diff --git a/.editorconfig b/.editorconfig index 146224e7330..cbde126ca6c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +max_line_length = 120 [*.go] indent_style = tab diff --git a/.gitignore b/.gitignore index 31c89aadf6b..72f6684ef20 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,8 @@ awsconfig /public_gen /public/vendor/npm /tmp -vendor/phantomjs/phantomjs -vendor/phantomjs/phantomjs.exe +tools/phantomjs/phantomjs +tools/phantomjs/phantomjs.exe profile.out coverage.txt @@ -51,9 +51,13 @@ debug.test /packaging/**/*.rpm /packaging/**/*.deb +# Ignore OSX indexing +.DS_Store + /vendor/**/*.py /vendor/**/*.xml /vendor/**/*.yml /vendor/**/*_test.go /vendor/**/.editorconfig /vendor/**/appengine* +*.orig \ No newline at end of file diff --git a/.jshintrc b/.jshintrc index 3fb6501c2f9..1d8fad63173 100644 --- a/.jshintrc +++ b/.jshintrc @@ -4,7 +4,7 @@ "bitwise":false, "curly": true, "eqnull": true, - "strict": true, + "strict": false, "devel": true, "eqeqeq": true, "forin": false, diff --git a/CHANGELOG.md b/CHANGELOG.md index b8b1dc8bdce..5916f960e7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,87 @@ -# 5.0.0 (unreleased) +# 5.0.0-stable (2018-03-01) -### WIP (in develop branch currently as its unstable or unfinished) -- Dashboard folders -- User groups -- Dashboard permissions (on folder & dashboard level), permissions can be assigned to groups or individual users -- UX changes to nav & side menu -- New dashboard grid layout system +### Fixes -# 4.7.0 (unreleased) +- **oauth** Fix Github OAuth not working with private Organizations [#11028](https://github.com/grafana/grafana/pull/11028) [@lostick](https://github.com/lostick) +- **kiosk** white area over bottom panels in kiosk mode [#11010](https://github.com/grafana/grafana/issues/11010) +- **alerting** Fix OK state doesn't show up in Microsoft Teams [#11032](https://github.com/grafana/grafana/pull/11032), thx [@manacker](https://github.com/manacker) + +# 5.0.0-beta5 (2018-02-26) + +### Fixes + +- **Orgs** Unable to switch org when too many orgs listed [#10774](https://github.com/grafana/grafana/issues/10774) +- **Folders** Make it easier/explicit to access/modify folders using the API [#10630](https://github.com/grafana/grafana/issues/10630) +- **Dashboard** Scrollbar works incorrectly in Grafana 5.0 Beta4 in some cases [#10982](https://github.com/grafana/grafana/issues/10982) +- **ElasticSearch** Custom aggregation sizes no longer allowed for Elasticsearch [#10124](https://github.com/grafana/grafana/issues/10124) +- **oauth** Github OAuth with allowed organizations fails to login [#10964](https://github.com/grafana/grafana/issues/10964) +- **heatmap** Heatmap panel has partially hidden legend [#10793](https://github.com/grafana/grafana/issues/10793) +- **snapshots** Expired snapshots not being cleaned up [#10996](https://github.com/grafana/grafana/pull/10996) + +# 5.0.0-beta4 (2018-02-19) + +### Fixes + +- **Dashboard** Fixed dashboard overwrite permission issue [#10814](https://github.com/grafana/grafana/issues/10814) +- **Keyboard shortcuts** Fixed Esc key when in panel edit/view mode [#10945](https://github.com/grafana/grafana/issues/10945) +- **Save dashboard** Fixed issue with time range & variable reset after saving [#10946](https://github.com/grafana/grafana/issues/10946) + +# 5.0.0-beta3 (2018-02-16) + +### Fixes + +- **MySQL** Fixed new migration issue with index length [#10931](https://github.com/grafana/grafana/issues/10931) +- **Modal** Escape key no closes modals everywhere, fixes [#10887](https://github.com/grafana/grafana/issues/10887) +- **Row repeats** Fix for repeating rows issue, fixes [#10932](https://github.com/grafana/grafana/issues/10932) +- **Docs** Team api documented, fixes [#10832](https://github.com/grafana/grafana/issues/10832) +- **Plugins** Plugin info page broken, fixes [#10943](https://github.com/grafana/grafana/issues/10943) + +# 5.0.0-beta2 (2018-02-15) + +### Fixes + +- **Permissions** Fixed search permissions issues [#10822](https://github.com/grafana/grafana/issues/10822) +- **Permissions** Fixed problem issues displaying permissions lists [#10864](https://github.com/grafana/grafana/issues/10864) +- **PNG-Rendering** Fixed problem rendering legend to the right [#10526](https://github.com/grafana/grafana/issues/10526) +- **Reset password** Fixed problem with reset password form [#10870](https://github.com/grafana/grafana/issues/10870) +- **Light theme** Fixed problem with light theme in safari, [#10869](https://github.com/grafana/grafana/issues/10869) +- **Provisioning** Now handles deletes when dashboard json files removed from disk [#10865](https://github.com/grafana/grafana/issues/10865) +- **MySQL** Fixed issue with schema migration on old mysql (index too long) [#10779](https://github.com/grafana/grafana/issues/10779) +- **Github OAuth** Fixed fetching github orgs from private github org [#10823](https://github.com/grafana/grafana/issues/10823) +- **Embedding** Fixed issues embedding panel [#10787](https://github.com/grafana/grafana/issues/10787) + +# 5.0.0-beta1 (2018-02-05) + +Grafana v5.0 is going to be the biggest and most foundational release Grafana has ever had, coming with a ton of UX improvements, a new dashboard grid engine, dashboard folders, user teams and permissions. Checkout out this [video preview](https://www.youtube.com/watch?v=Izr0IBgoTZQ) of Grafana v5. + +### New Major Features +- **Dashboards** Dashboard folders, [#1611](https://github.com/grafana/grafana/issues/1611) +- **Teams** User groups (teams) implemented. Can be used in folder & dashboard permission list. +- **Dashboard grid**: Panels are now layed out in a two dimensional grid (with x, y, w, h). [#9093](https://github.com/grafana/grafana/issues/9093). +- **Templating**: Vertical repeat direction for panel repeats. +- **UX**: Major update to page header and navigation +- **Dashboard settings**: Combine dashboard settings views into one with side menu, [#9750](https://github.com/grafana/grafana/issues/9750) +- **Persistent dashboard url's**: New url's for dashboards that allows renaming dashboards without breaking links. [#7883](https://github.com/grafana/grafana/issues/7883) ## Breaking changes -`[dashboard.json]` have been replaced with [dashboard provisioning](http://docs.grafana.org/administration/provisioning/). +* **[dashboard.json]** have been replaced with [dashboard provisioning](http://docs.grafana.org/administration/provisioning/). +Config files for provisioning datasources as configuration have changed from `/conf/datasources` to `/conf/provisioning/datasources`. +From `/etc/grafana/datasources` to `/etc/grafana/provisioning/datasources` when installed with deb/rpm packages. -Config files for provisioning datasources as configuration have changed from `/conf/datasources` to `/conf/provisioning/datasources`. -From `/etc/grafana/datasources` to `/etc/grafana/provisioning/datasources` when installed with deb/rpm packages. +* **Pagerduty** The notifier now defaults to not auto resolve incidents. More details at [#10222](https://github.com/grafana/grafana/issues/10222) + +* **HTTP API** + - `GET /api/alerts` property dashboardUri renamed to url and is now the full url (that is including app sub url). + +## New Dashboard Grid + +The new grid engine is a major upgrade for how you can position and move panels. It enables new layouts and a much easier dashboard building experience. The change is backward compatible. So you can upgrade your current version to 5.0 without breaking dashboards, but you cannot downgrade from 5.0 to previous versions. Grafana will automatically upgrade your dashboards to the new schema and position panels to match your existing layout. There might be minor differences in panel height. If you upgrade to 5.0 and for some reason want to rollback to the previous version you can restore dashboards to previous versions using dashboard history. But that should only be seen as an emergency solution. + +Dashboard panels and rows are positioned using a gridPos object `{x: 0, y: 0, w: 24, h: 5}`. Units are in grid dimensions (24 columns, 1 height unit 30px). Rows and Panels objects exist (together) in a flat array directly on the dashboard root object. Rows are not needed for layouts anymore and are mainly there for backward compatibility. Some panel plugins that do not respect their panel height might require an update. ## New Features +* **Alerting**: Add support for internal image store [#6922](https://github.com/grafana/grafana/issues/6922), thx [@FunkyM](https://github.com/FunkyM) * **Data Source Proxy**: Add support for whitelisting specified cookies that will be passed through to the data source when proxying data source requests [#5457](https://github.com/grafana/grafana/issues/5457), thanks [@robingustafsson](https://github.com/robingustafsson) * **Postgres/MySQL**: add __timeGroup macro for mysql [#9596](https://github.com/grafana/grafana/pull/9596), thanks [@svenklemm](https://github.com/svenklemm) * **Text**: Text panel are now edited in the ace editor. [#9698](https://github.com/grafana/grafana/pull/9698), thx [@mtanda](https://github.com/mtanda) @@ -25,30 +90,53 @@ From `/etc/grafana/datasources` to `/etc/grafana/provisioning/datasources` when * **Graphite**: Query editor updated to support new query by tag features [#9230](https://github.com/grafana/grafana/issues/9230) * **Dashboard history**: New config file option versions_to_keep sets how many versions per dashboard to store, [#9671](https://github.com/grafana/grafana/issues/9671) * **Dashboard as cfg**: Load dashboards from file into Grafana on startup/change [#9654](https://github.com/grafana/grafana/issues/9654) [#5269](https://github.com/grafana/grafana/issues/5269) +* **Prometheus**: Grafana can now send alerts to Prometheus Alertmanager while firing [#7481](https://github.com/grafana/grafana/issues/7481), thx [@Thib17](https://github.com/Thib17) and [@mtanda](https://github.com/mtanda) +* **Table**: Support multiple table formated queries in table panel [#9170](https://github.com/grafana/grafana/issues/9170), thx [@davkal](https://github.com/davkal) +* **Security**: Protect against brute force (frequent) login attempts [#7616](https://github.com/grafana/grafana/issues/7616) ## Minor +* **Graph**: Don't hide graph display options (Lines/Points) when draw mode is unchecked [#9770](https://github.com/grafana/grafana/issues/9770), thx [@Jonnymcc](https://github.com/Jonnymcc) +* **Prometheus**: Show label name in paren after by/without/on/ignoring/group_left/group_right [#9664](https://github.com/grafana/grafana/pull/9664), thx [@mtanda](https://github.com/mtanda) * **Alert panel**: Adds placeholder text when no alerts are within the time range [#9624](https://github.com/grafana/grafana/issues/9624), thx [@straend](https://github.com/straend) * **Mysql**: MySQL enable MaxOpenCon and MaxIdleCon regards how constring is configured. [#9784](https://github.com/grafana/grafana/issues/9784), thx [@dfredell](https://github.com/dfredell) * **Cloudwatch**: Fixes broken query inspector for cloudwatch [#9661](https://github.com/grafana/grafana/issues/9661), thx [@mtanda](https://github.com/mtanda) * **Dashboard**: Make it possible to start dashboards from search and dashboard list panel [#1871](https://github.com/grafana/grafana/issues/1871) * **Annotations**: Posting annotations now return the id of the annotation [#9798](https://github.com/grafana/grafana/issues/9798) * **Systemd**: Use systemd notification ready flag [#10024](https://github.com/grafana/grafana/issues/10024), thx [@jgrassler](https://github.com/jgrassler) -* **Github**: Use organizations_url provided from github to verify user belongs in org. [#10111](https://github.com/grafana/grafana/issues/10111), thx [@adiletmaratov](https://github.com/adiletmaratov) - -## Tech -* **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) - +* **Github**: Use organizations_url provided from github to verify user belongs in org. [#10111](https://github.com/grafana/grafana/issues/10111), thx +[@adiletmaratov](https://github.com/adiletmaratov) +* **Backend**: Fixed bug where Grafana exited before all sub routines where finished [#10131](https://github.com/grafana/grafana/issues/10131) +* **Azure**: Adds support for Azure blob storage as external image stor [#8955](https://github.com/grafana/grafana/issues/8955), thx [@saada](https://github.com/saada) +* **Telegram**: Add support for inline image uploads to telegram notifier plugin [#9967](https://github.com/grafana/grafana/pull/9967), thx [@rburchell](https://github.com/rburchell) ## Fixes * **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand) * **Singlestat**: suppress error when result contains no datapoints [#9636](https://github.com/grafana/grafana/issues/9636), thx [@utkarshcmu](https://github.com/utkarshcmu) * **Postgres/MySQL**: Control quoting in SQL-queries when using template variables [#9030](https://github.com/grafana/grafana/issues/9030), thanks [@svenklemm](https://github.com/svenklemm) +* **Pagerduty**: Pagerduty dont auto resolve incidents by default anymore. [#10222](https://github.com/grafana/grafana/issues/10222) +* **Cloudwatch**: Fix for multi-valued templated queries. [#9903](https://github.com/grafana/grafana/issues/9903) -# 4.6.3 (unreleased) +## Tech +* **RabbitMq**: Remove support for publishing events to RabbitMQ [#9645](https://github.com/grafana/grafana/issues/9645) + +## Deprecation notes + +### HTTP API +The following operations have been deprecated and will be removed in a future release: + - `GET /api/dashboards/db/:slug` -> Use `GET /api/dashboards/uid/:uid` instead + - `DELETE /api/dashboards/db/:slug` -> Use `DELETE /api/dashboards/uid/:uid` instead + +The following properties have been deprecated and will be removed in a future release: + - `uri` property in `GET /api/search` -> Use new `url` or `uid` property instead + - `meta.slug` property in `GET /api/dashboards/uid/:uid` and `GET /api/dashboards/db/:slug` -> Use new `meta.url` or `dashboard.uid` property instead + +# 4.6.3 (2017-12-14) ## Fixes * **Gzip**: Fixes bug gravatar images when gzip was enabled [#5952](https://github.com/grafana/grafana/issues/5952) * **Alert list**: Now shows alert state changes even after adding manual annotations on dashboard [#9951](https://github.com/grafana/grafana/issues/9951) +* **Alerting**: Fixes bug where rules evaluated as firing when all conditions was false and using OR operator. [#9318](https://github.com/grafana/grafana/issues/9318) +* **Cloudwatch**: CloudWatch no longer display metrics' default alias [#10151](https://github.com/grafana/grafana/issues/10151), thx [@mtanda](https://github.com/mtanda) # 4.6.2 (2017-11-16) diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 00000000000..8d82b29d622 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,636 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "cloud.google.com/go" + packages = ["compute/metadata"] + revision = "767c40d6a2e058483c25fa193e963a22da17236d" + version = "v0.18.0" + +[[projects]] + name = "github.com/BurntSushi/toml" + packages = ["."] + revision = "b26d9c308763d68093482582cea63d69be07a0f0" + version = "v0.3.0" + +[[projects]] + branch = "master" + name = "github.com/Unknwon/com" + packages = ["."] + revision = "7677a1d7c1137cd3dd5ba7a076d0c898a1ef4520" + +[[projects]] + name = "github.com/apache/thrift" + packages = ["lib/go/thrift"] + revision = "b2a4d4ae21c789b689dd162deb819665567f481c" + version = "0.10.0" + +[[projects]] + name = "github.com/aws/aws-sdk-go" + packages = [ + "aws", + "aws/awserr", + "aws/awsutil", + "aws/client", + "aws/client/metadata", + "aws/corehandlers", + "aws/credentials", + "aws/credentials/ec2rolecreds", + "aws/credentials/endpointcreds", + "aws/credentials/stscreds", + "aws/defaults", + "aws/ec2metadata", + "aws/endpoints", + "aws/request", + "aws/session", + "aws/signer/v4", + "internal/shareddefaults", + "private/protocol", + "private/protocol/ec2query", + "private/protocol/query", + "private/protocol/query/queryutil", + "private/protocol/rest", + "private/protocol/restxml", + "private/protocol/xml/xmlutil", + "service/cloudwatch", + "service/ec2", + "service/ec2/ec2iface", + "service/s3", + "service/sts" + ] + revision = "decd990ddc5dcdf2f73309cbcab90d06b996ca28" + version = "v1.12.67" + +[[projects]] + branch = "master" + name = "github.com/benbjohnson/clock" + packages = ["."] + revision = "7dc76406b6d3c05b5f71a86293cbcf3c4ea03b19" + +[[projects]] + branch = "master" + name = "github.com/beorn7/perks" + packages = ["quantile"] + revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9" + +[[projects]] + branch = "master" + name = "github.com/bmizerany/assert" + packages = ["."] + revision = "b7ed37b82869576c289d7d97fb2bbd8b64a0cb28" + +[[projects]] + branch = "master" + name = "github.com/bradfitz/gomemcache" + packages = ["memcache"] + revision = "1952afaa557dc08e8e0d89eafab110fb501c1a2b" + +[[projects]] + branch = "master" + name = "github.com/codahale/hdrhistogram" + packages = ["."] + revision = "3a0bb77429bd3a61596f5e8a3172445844342120" + +[[projects]] + name = "github.com/codegangsta/cli" + packages = ["."] + revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" + version = "v1.20.0" + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + name = "github.com/fatih/color" + packages = ["."] + revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260" + version = "v1.5.0" + +[[projects]] + name = "github.com/go-ini/ini" + packages = ["."] + revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a" + version = "v1.32.0" + +[[projects]] + name = "github.com/go-ldap/ldap" + packages = ["."] + revision = "bb7a9ca6e4fbc2129e3db588a34bc970ffe811a9" + version = "v2.5.1" + +[[projects]] + branch = "master" + name = "github.com/go-macaron/binding" + packages = ["."] + revision = "ac54ee249c27dca7e76fad851a4a04b73bd1b183" + +[[projects]] + branch = "master" + name = "github.com/go-macaron/gzip" + packages = ["."] + revision = "cad1c6580a07c56f5f6bc52d66002a05985c5854" + +[[projects]] + branch = "master" + name = "github.com/go-macaron/inject" + packages = ["."] + revision = "d8a0b8677191f4380287cfebd08e462217bac7ad" + +[[projects]] + branch = "master" + name = "github.com/go-macaron/session" + packages = [ + ".", + "memcache", + "mysql", + "postgres", + "redis" + ] + revision = "b8e286a0dba8f4999042d6b258daf51b31d08938" + +[[projects]] + name = "github.com/go-sql-driver/mysql" + packages = ["."] + revision = "2cc627ac8defc45d65066ae98f898166f580f9a4" + +[[projects]] + name = "github.com/go-stack/stack" + packages = ["."] + revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" + version = "v1.7.0" + +[[projects]] + branch = "master" + name = "github.com/go-xorm/builder" + packages = ["."] + revision = "488224409dd8aa2ce7a5baf8d10d55764a913738" + +[[projects]] + name = "github.com/go-xorm/core" + packages = ["."] + revision = "e8409d73255791843585964791443dbad877058c" + +[[projects]] + name = "github.com/go-xorm/xorm" + packages = ["."] + revision = "6687a2b4e824f4d87f2d65060ec5cb0d896dff1e" + +[[projects]] + branch = "master" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp" + ] + revision = "c65a0412e71e8b9b3bfd22925720d23c0f054237" + +[[projects]] + branch = "master" + name = "github.com/gopherjs/gopherjs" + packages = ["js"] + revision = "178c176a91fe05e3e6c58fa5c989bad19e6cdcb3" + +[[projects]] + name = "github.com/gorilla/websocket" + packages = ["."] + revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" + version = "v1.2.0" + +[[projects]] + name = "github.com/gosimple/slug" + packages = ["."] + revision = "e9f42fa127660e552d0ad2b589868d403a9be7c6" + version = "v1.1.1" + +[[projects]] + branch = "master" + name = "github.com/grafana/grafana_plugin_model" + packages = ["go/datasource"] + revision = "dfe5dc0a6ce05825ba7fe2d0323d92e631bffa89" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-hclog" + packages = ["."] + revision = "5bcb0f17e36442247290887cc914a6e507afa5c4" + +[[projects]] + name = "github.com/hashicorp/go-plugin" + packages = ["."] + revision = "3e6d191694b5a3a2b99755f31b47fa209e4bcd09" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/go-version" + packages = ["."] + revision = "4fe82ae3040f80a03d04d2cccb5606a626b8e1ee" + +[[projects]] + branch = "master" + name = "github.com/hashicorp/yamux" + packages = ["."] + revision = "683f49123a33db61abfb241b7ac5e4af4dc54d55" + +[[projects]] + name = "github.com/inconshreveable/log15" + packages = ["."] + revision = "0decfc6c20d9ca0ad143b0e89dcaa20f810b4fb3" + version = "v2.13" + +[[projects]] + name = "github.com/jmespath/go-jmespath" + packages = ["."] + revision = "0b12d6b5" + +[[projects]] + name = "github.com/jtolds/gls" + packages = ["."] + revision = "77f18212c9c7edc9bd6a33d383a7b545ce62f064" + version = "v4.2.1" + +[[projects]] + name = "github.com/klauspost/compress" + packages = [ + "flate", + "gzip" + ] + revision = "6c8db69c4b49dd4df1fff66996cf556176d0b9bf" + version = "v1.2.1" + +[[projects]] + name = "github.com/klauspost/cpuid" + packages = ["."] + revision = "ae7887de9fa5d2db4eaa8174a7eff2c1ac00f2da" + version = "v1.1" + +[[projects]] + name = "github.com/klauspost/crc32" + packages = ["."] + revision = "cb6bfca970f6908083f26f39a79009d608efd5cd" + version = "v1.1" + +[[projects]] + branch = "master" + name = "github.com/kr/pretty" + packages = ["."] + revision = "cfb55aafdaf3ec08f0db22699ab822c50091b1c4" + +[[projects]] + branch = "master" + name = "github.com/kr/text" + packages = ["."] + revision = "7cafcd837844e784b526369c9bce262804aebc60" + +[[projects]] + branch = "master" + name = "github.com/lib/pq" + packages = [ + ".", + "oid" + ] + revision = "61fe37aa2ee24fabcdbe5c4ac1d4ac566f88f345" + +[[projects]] + name = "github.com/mattn/go-colorable" + packages = ["."] + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + name = "github.com/mattn/go-sqlite3" + packages = ["."] + revision = "6c771bb9887719704b210e87e934f08be014bdb1" + version = "v1.6.0" + +[[projects]] + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/go-testing-interface" + packages = ["."] + revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28" + +[[projects]] + name = "github.com/opentracing/opentracing-go" + packages = [ + ".", + "ext", + "log" + ] + revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" + version = "v1.0.2" + +[[projects]] + name = "github.com/patrickmn/go-cache" + packages = ["."] + revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0" + version = "v2.1.0" + +[[projects]] + name = "github.com/prometheus/client_golang" + packages = [ + "api", + "api/prometheus/v1", + "prometheus", + "prometheus/promhttp" + ] + revision = "967789050ba94deca04a5e84cce8ad472ce313c1" + version = "v0.9.0-pre1" + +[[projects]] + branch = "master" + name = "github.com/prometheus/client_model" + packages = ["go"] + revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" + +[[projects]] + branch = "master" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] + revision = "89604d197083d4781071d3c65855d24ecfb0a563" + +[[projects]] + branch = "master" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfsd", + "xfs" + ] + revision = "85fadb6e89903ef7cca6f6a804474cd5ea85b6e1" + +[[projects]] + branch = "master" + name = "github.com/rainycape/unidecode" + packages = ["."] + revision = "cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c" + +[[projects]] + branch = "master" + name = "github.com/sergi/go-diff" + packages = ["diffmatchpatch"] + revision = "1744e2970ca51c86172c8190fadad617561ed6e7" + +[[projects]] + name = "github.com/smartystreets/assertions" + packages = [ + ".", + "internal/go-render/render", + "internal/oglematchers" + ] + revision = "0b37b35ec7434b77e77a4bb29b79677cced992ea" + version = "1.8.1" + +[[projects]] + name = "github.com/smartystreets/goconvey" + packages = [ + "convey", + "convey/gotest", + "convey/reporting" + ] + revision = "9e8dc3f972df6c8fcc0375ef492c24d0bb204857" + version = "1.6.3" + +[[projects]] + branch = "master" + name = "github.com/teris-io/shortid" + packages = ["."] + revision = "771a37caa5cf0c81f585d7b6df4dfc77e0615b5c" + +[[projects]] + name = "github.com/uber/jaeger-client-go" + packages = [ + ".", + "config", + "internal/baggage", + "internal/baggage/remote", + "internal/spanlog", + "log", + "rpcmetrics", + "thrift-gen/agent", + "thrift-gen/baggage", + "thrift-gen/jaeger", + "thrift-gen/sampling", + "thrift-gen/zipkincore", + "utils" + ] + revision = "3ac96c6e679cb60a74589b0d0aa7c70a906183f7" + version = "v2.11.2" + +[[projects]] + name = "github.com/uber/jaeger-lib" + packages = ["metrics"] + revision = "7f95f4f7e80028096410abddaae2556e4c61b59f" + version = "v1.3.1" + +[[projects]] + name = "github.com/yudai/gojsondiff" + packages = [ + ".", + "formatter" + ] + revision = "7b1b7adf999dab73a6eb02669c3d82dbb27a3dd6" + version = "1.0.0" + +[[projects]] + branch = "master" + name = "github.com/yudai/golcs" + packages = ["."] + revision = "ecda9a501e8220fae3b4b600c3db4b0ba22cfc68" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = ["pbkdf2"] + revision = "3d37316aaa6bd9929127ac9a527abf408178ea7b" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "lex/httplex", + "trace" + ] + revision = "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec" + +[[projects]] + branch = "master" + name = "golang.org/x/oauth2" + packages = [ + ".", + "google", + "internal", + "jws", + "jwt" + ] + revision = "b28fcf2b08a19742b43084fb40ab78ac6c3d8067" + +[[projects]] + branch = "master" + name = "golang.org/x/sync" + packages = ["errgroup"] + revision = "fd80eb99c8f653c847d294a001bdf2a3a6f768f5" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = ["unix"] + revision = "af50095a40f9041b3b38960738837185c26e9419" + +[[projects]] + branch = "master" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable" + ] + revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3" + +[[projects]] + name = "google.golang.org/appengine" + packages = [ + ".", + "cloudsql", + "internal", + "internal/app_identity", + "internal/base", + "internal/datastore", + "internal/log", + "internal/modules", + "internal/remote_api", + "internal/urlfetch", + "urlfetch" + ] + revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" + version = "v1.0.0" + +[[projects]] + branch = "master" + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + revision = "a8101f21cf983e773d0c1133ebc5424792003214" + +[[projects]] + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "codes", + "connectivity", + "credentials", + "encoding", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "health", + "health/grpc_health_v1", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport" + ] + revision = "6b51017f791ae1cfbec89c52efdf444b13b550ef" + version = "v1.9.2" + +[[projects]] + branch = "v3" + name = "gopkg.in/alexcesaro/quotedprintable.v3" + packages = ["."] + revision = "2caba252f4dc53eaf6b553000885530023f54623" + +[[projects]] + name = "gopkg.in/asn1-ber.v1" + packages = ["."] + revision = "379148ca0225df7a432012b8df0355c2a2063ac0" + version = "v1.2" + +[[projects]] + name = "gopkg.in/bufio.v1" + packages = ["."] + revision = "567b2bfa514e796916c4747494d6ff5132a1dfce" + version = "v1" + +[[projects]] + branch = "v2" + name = "gopkg.in/gomail.v2" + packages = ["."] + revision = "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1" + +[[projects]] + name = "gopkg.in/ini.v1" + packages = ["."] + revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a" + version = "v1.32.0" + +[[projects]] + name = "gopkg.in/macaron.v1" + packages = ["."] + revision = "75f2e9b42e99652f0d82b28ccb73648f44615faa" + version = "v1.2.4" + +[[projects]] + name = "gopkg.in/redis.v2" + packages = ["."] + revision = "e6179049628164864e6e84e973cfb56335748dea" + version = "v2.3.2" + +[[projects]] + branch = "v2" + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "4de68f1342ba98a637ec8ca7496aeeae2021bf9e4c7c80db7924e14709151a62" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 00000000000..22c56d29c71 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,199 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + +ignored = [ + "github.com/grafana/grafana/data/*", + "github.com/grafana/grafana/public/*", + "github.com/grafana/grafana/node_modules/*" + ] + +[[constraint]] + name = "github.com/BurntSushi/toml" + version = "0.3.0" + +[[constraint]] + branch = "master" + name = "github.com/Unknwon/com" + #version = "1.0.0" + +[[constraint]] + name = "github.com/aws/aws-sdk-go" + version = "1.12.65" + +[[constraint]] + branch = "master" + name = "github.com/benbjohnson/clock" + +[[constraint]] + branch = "master" + name = "github.com/bmizerany/assert" + +[[constraint]] + name = "github.com/codegangsta/cli" + version = "1.20.0" + +[[constraint]] + name = "github.com/davecgh/go-spew" + version = "1.1.0" + +[[constraint]] + name = "github.com/fatih/color" + version = "1.5.0" + +[[constraint]] + name = "github.com/go-ldap/ldap" + version = "2.5.1" + +[[constraint]] + branch = "master" + name = "github.com/go-macaron/binding" + +[[constraint]] + branch = "master" + name = "github.com/go-macaron/gzip" + +[[constraint]] + branch = "master" + name = "github.com/go-macaron/session" + +[[constraint]] + name = "github.com/go-sql-driver/mysql" + revision = "2cc627ac8defc45d65066ae98f898166f580f9a4" + #version = "1.3.0" //keeping this since we would rather depend on version then commit + +[[constraint]] + name = "github.com/go-stack/stack" + version = "1.7.0" + +[[constraint]] + name = "github.com/go-xorm/core" + revision = "e8409d73255791843585964791443dbad877058c" + #version = "0.5.7" //keeping this since we would rather depend on version then commit + +[[constraint]] + name = "github.com/go-xorm/xorm" + revision = "6687a2b4e824f4d87f2d65060ec5cb0d896dff1e" + #version = "0.6.4" //keeping this since we would rather depend on version then commit + +[[constraint]] + name = "github.com/gorilla/websocket" + version = "1.2.0" + +[[constraint]] + name = "github.com/gosimple/slug" + version = "1.1.1" + +[[constraint]] + branch = "master" + name = "github.com/grafana/grafana_plugin_model" + +[[constraint]] + branch = "master" + name = "github.com/hashicorp/go-hclog" + +[[constraint]] + branch = "master" + name = "github.com/hashicorp/go-version" + +[[constraint]] + name = "github.com/inconshreveable/log15" + version = "2.13.0" + +[[constraint]] + branch = "master" + name = "github.com/lib/pq" + +[[constraint]] + name = "github.com/mattn/go-isatty" + version = "0.0.3" + +[[constraint]] + name = "github.com/mattn/go-sqlite3" + version = "1.6.0" + +[[constraint]] + name = "github.com/opentracing/opentracing-go" + version = "1.0.2" + +[[constraint]] + name = "github.com/patrickmn/go-cache" + version = "2.1.0" + +[[constraint]] + name = "github.com/prometheus/client_golang" + version = "0.9.0-pre1" + +[[constraint]] + branch = "master" + name = "github.com/prometheus/client_model" + +[[constraint]] + branch = "master" + name = "github.com/prometheus/common" + +[[constraint]] + name = "github.com/smartystreets/goconvey" + version = "1.6.3" + +[[constraint]] + name = "github.com/uber/jaeger-client-go" + version = "2.11.2" + +[[constraint]] + name = "github.com/yudai/gojsondiff" + version = "1.0.0" + +[[constraint]] + branch = "master" + name = "golang.org/x/net" + +[[constraint]] + branch = "master" + name = "golang.org/x/oauth2" + +[[constraint]] + branch = "master" + name = "golang.org/x/sync" + +[[constraint]] + name = "gopkg.in/gomail.v2" + branch = "v2" + +[[constraint]] + name = "gopkg.in/ini.v1" + version = "1.32.0" + +[[constraint]] + name = "gopkg.in/macaron.v1" + version = "1.2.4" + +[[constraint]] + branch = "v2" + name = "gopkg.in/yaml.v2" + +[prune] + non-go = true + go-tests = true + unused-packages = true + +[[constraint]] + branch = "master" + name = "github.com/teris-io/shortid" diff --git a/Makefile b/Makefile index d003cda6dd4..d89718d200c 100644 --- a/Makefile +++ b/Makefile @@ -26,3 +26,6 @@ test: test-go test-js run: ./bin/grafana-server + +protoc: + protoc -I pkg/tsdb/models pkg/tsdb/models/*.proto --go_out=plugins=grpc:pkg/tsdb/models/. \ No newline at end of file diff --git a/README.md b/README.md index aefc0c0802b..81fb1f8d42b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ Graphite, Elasticsearch, OpenTSDB, Prometheus and InfluxDB. ![](http://docs.grafana.org/assets/img/features/dashboard_ex1.png) +## Grafana v5 Alpha Preview +Grafana master is now v5.0 alpha. This is going to be the biggest and most foundational release Grafana has ever had, coming with a ton of UX improvements, a new dashboard grid engine, dashboard folders, user teams and permissions. Checkout out this [video preview](https://www.youtube.com/watch?v=BC_YRNpqj5k) of Grafana v5. + ## Installation Head to [docs.grafana.org](http://docs.grafana.org/installation/) and [download](https://grafana.com/get) the latest release. @@ -19,7 +22,7 @@ If you have any problems please read the [troubleshooting guide](http://docs.gra Be sure to read the [getting started guide](http://docs.grafana.org/guides/gettingstarted/) and the other feature guides. ## Run from master -If you want to build a package yourself, or contribute. Here is a guide for how to do that. You can always find +If you want to build a package yourself, or contribute - Here is a guide for how to do that. You can always find the latest master builds [here](https://grafana.com/grafana/download) ### Dependencies @@ -42,23 +45,17 @@ For this you need nodejs (v.6+). ```bash npm install -g yarn yarn install --pure-lockfile -npm run build -``` - -To rebuild frontend assets (typescript, sass etc) as you change them start the watcher via. - -```bash npm run watch ``` -Run tests +Run tests ```bash -npm run test +npm run jest ``` -Run tests in watch mode +Run karma tests ```bash -npm run watch-test +npm run karma ``` ### Recompile backend on source change @@ -83,8 +80,11 @@ In your custom.ini uncomment (remove the leading `;`) sign. And set `app_mode = ### Running tests -- You can run backend Golang tests using "go test ./pkg/...". -- Execute all frontend tests with "npm run test" +#### Frontend +Execute all frontend tests +```bash +npm run test +``` Writing & watching frontend tests (we have two test runners) @@ -95,9 +95,21 @@ Writing & watching frontend tests (we have two test runners) - Start watcher: `npm run karma` - Karma+Mocha runs all files that end with the name "_specs.ts". +#### Backend +```bash +# Run Golang tests using sqlite3 as database (default) +go test ./pkg/... + +# Run Golang tests using mysql as database - convenient to use /docker/blocks/mysql_tests +GRAFANA_TEST_DB=mysql go test ./pkg/... + +# Run Golang tests using postgres as database - convenient to use /docker/blocks/postgres_tests +GRAFANA_TEST_DB=postgres go test ./pkg/... +``` + ## Contribute -If you have any idea for an improvement or found a bug do not hesitate to open an issue. +If you have any idea for an improvement or found a bug, do not hesitate to open an issue. And if you have time clone this repo and submit a pull request and help me make Grafana the kickass metrics & devops dashboard we all dream about! diff --git a/ROADMAP.md b/ROADMAP.md index 4273d8df6a9..c8dc3186c73 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,25 +1,28 @@ -# Roadmap (2017-10-31) +# Roadmap (2018-02-22) This roadmap is a tentative plan for the core development team. Things change constantly as PRs come in and priorities change. But it will give you an idea of our current vision and plan. -### Short term (1-4 months) +### Short term (1-2 months) - - Release Grafana v5 - - User groups - - Dashboard folders - - Dashboard & folder permissions (assigned to users or groups) - - New Dashboard layout engine - - New sidemenu & nav UX +- v5.1 + - Crossplatform builds & build speed improvements + - Enterprise LDAP + - New template interpolation syntax + - Provisioning workflow + - First login registration view + - IFQL Initial support + +### Mid term (2-4 months) + +- v5.2 + - Azure monitor backend rewrite - Elasticsearch alerting - - React migration foundation (core components) - - Graphite 1.1 Tags Support + - Backend plugins? (alert notifiers, auth) ### Long term (4 - 8 months) -- Backend plugins to support more Auth options, Alerting data sources & notifications - Alerting improvements (silence, per series tracking, etc) -- Dashboard as configuration and other automation / provisioning improvements - Progress on React migration - Change visualization (panel type) on the fly. - Multi stat panel (vertical version of singlestat with bars/graph mode with big number etc) diff --git a/build.go b/build.go index 1c61c72d5dc..d55244246ff 100644 --- a/build.go +++ b/build.go @@ -347,11 +347,11 @@ func ChangeWorkingDir(dir string) { } func grunt(params ...string) { - if runtime.GOOS == "windows" { - runPrint(`.\node_modules\.bin\grunt`, params...) - } else { - runPrint("./node_modules/.bin/grunt", params...) - } + if runtime.GOOS == "windows" { + runPrint(`.\node_modules\.bin\grunt`, params...) + } else { + runPrint("./node_modules/.bin/grunt", params...) + } } func gruntBuildArg(task string) []string { @@ -371,7 +371,7 @@ func gruntBuildArg(task string) []string { } func setup() { - runPrint("go", "get", "-v", "github.com/kardianos/govendor") + runPrint("go", "get", "-v", "github.com/golang/dep") runPrint("go", "install", "-v", "./pkg/cmd/grafana-server") } diff --git a/circle.yml b/circle.yml index 4eb600bfde3..bf013e3f5b1 100644 --- a/circle.yml +++ b/circle.yml @@ -9,7 +9,7 @@ machine: GOPATH: "/home/ubuntu/.go_workspace" ORG_PATH: "github.com/grafana" REPO_PATH: "${ORG_PATH}/grafana" - GODIST: "go1.9.2.linux-amd64.tar.gz" + GODIST: "go1.9.3.linux-amd64.tar.gz" post: - mkdir -p ~/download - mkdir -p ~/docker diff --git a/conf/defaults.ini b/conf/defaults.ini index 218c91608cc..4a2240f1924 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -174,6 +174,9 @@ disable_gravatar = false # data source proxy whitelist (ip_or_domain:port separated by spaces) data_source_proxy_whitelist = +# disable protection against brute force login attempts +disable_brute_force_login_protection = false + #################################### Snapshots ########################### [snapshots] # snapshot sharing options @@ -184,9 +187,6 @@ external_snapshot_name = Publish to snapshot.raintank.io # remove expired snapshot snapshot_remove_expired = true -# remove snapshots after 90 days -snapshot_TTL_days = 90 - #################################### Dashboards ################## [dashboards] @@ -221,6 +221,9 @@ external_manage_link_url = external_manage_link_name = external_manage_info = +# Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard. +viewers_can_edit = false + [auth] # Set to true to disable (hide) the login form, useful if you use OAuth disable_login_form = false @@ -245,7 +248,7 @@ enabled = false allow_sign_up = true client_id = some_id client_secret = some_secret -scopes = user:email +scopes = user:email,read:org auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token api_url = https://api.github.com/user @@ -321,7 +324,7 @@ allow_sign_up = true enabled = false host = localhost:25 user = -# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" password = cert_file = key_file = @@ -470,7 +473,7 @@ sampler_param = 1 #################################### External Image Storage ############## [external_image_storage] -# You can choose between (s3, webdav, gcs) +# You can choose between (s3, webdav, gcs, azure_blob, local) provider = [external_image_storage.s3] @@ -490,4 +493,12 @@ public_url = [external_image_storage.gcs] key_file = bucket = -path = \ No newline at end of file +path = + +[external_image_storage.azure_blob] +account_name = +account_key = +container_name = + +[external_image_storage.local] +# does not require any configuration diff --git a/conf/ldap.toml b/conf/ldap.toml index ae217106cb2..166d85eabb1 100644 --- a/conf/ldap.toml +++ b/conf/ldap.toml @@ -19,7 +19,7 @@ ssl_skip_verify = false # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" # Search user bind password -# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" bind_password = 'grafana' # User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" diff --git a/conf/provisioning/dashboards/sample.yaml b/conf/provisioning/dashboards/sample.yaml index 40992d1461e..d70bd425634 100644 --- a/conf/provisioning/dashboards/sample.yaml +++ b/conf/provisioning/dashboards/sample.yaml @@ -1,6 +1,10 @@ +# # config file version +apiVersion: 1 + +#providers: # - name: 'default' -# org_id: 1 +# orgId: 1 # folder: '' # type: file # options: -# folder: /var/lib/grafana/dashboards \ No newline at end of file +# path: /var/lib/grafana/dashboards diff --git a/conf/provisioning/datasources/sample.yaml b/conf/provisioning/datasources/sample.yaml index 1bb9cb53b45..877e229183d 100644 --- a/conf/provisioning/datasources/sample.yaml +++ b/conf/provisioning/datasources/sample.yaml @@ -1,10 +1,13 @@ +# # config file version +apiVersion: 1 + # # list of datasources that should be deleted from the database -#delete_datasources: +#deleteDatasources: # - name: Graphite -# org_id: 1 +# orgId: 1 # # list of datasources to insert/update depending -# # whats available in the datbase +# # on what's available in the datbase #datasources: # # name of the datasource. Required # - name: Graphite @@ -12,8 +15,8 @@ # type: graphite # # access mode. direct or proxy. Required # access: proxy -# # org id. will default to org_id 1 if not specified -# org_id: 1 +# # org id. will default to orgId 1 if not specified +# orgId: 1 # # url # url: http://localhost:8080 # # database password, if used @@ -23,22 +26,22 @@ # # database name, if used # database: # # enable/disable basic auth -# basic_auth: +# basicAuth: # # basic auth username -# basic_auth_user: +# basicAuthUser: # # basic auth password -# basic_auth_password: +# basicAuthPassword: # # enable/disable with credentials headers -# with_credentials: +# withCredentials: # # mark as default datasource. Max one per org -# is_default: +# isDefault: # # fields that will be converted to json and stored in json_data -# json_data: +# jsonData: # graphiteVersion: "1.1" # tlsAuth: true # tlsAuthWithCACert: true # # json object of data that will be encrypted. -# secure_json_data: +# secureJsonData: # tlsCACert: "..." # tlsClientCert: "..." # tlsClientKey: "..." diff --git a/conf/sample.ini b/conf/sample.ini index 7107f8354d6..3e45ac44d61 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -71,7 +71,7 @@ ;host = 127.0.0.1:3306 ;name = grafana ;user = root -# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" ;password = # Use either URL or the previous fields to configure the database @@ -162,6 +162,9 @@ log_queries = # data source proxy whitelist (ip_or_domain:port separated by spaces) ;data_source_proxy_whitelist = +# disable protection against brute force login attempts +;disable_brute_force_login_protection = false + #################################### Snapshots ########################### [snapshots] # snapshot sharing options @@ -172,9 +175,6 @@ log_queries = # remove expired snapshot ;snapshot_remove_expired = true -# remove snapshots after 90 days -;snapshot_TTL_days = 90 - #################################### Dashboards History ################## [dashboards] # Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1 @@ -205,6 +205,9 @@ log_queries = ;external_manage_link_name = ;external_manage_info = +# Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard. +;viewers_can_edit = false + [auth] # Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false ;disable_login_form = false @@ -414,7 +417,7 @@ log_queries = #################################### External image storage ########################## [external_image_storage] # Used for uploading images to public servers so they can be included in slack/email messages. -# you can choose between (s3, webdav, gcs) +# you can choose between (s3, webdav, gcs, azure_blob, local) ;provider = [external_image_storage.s3] @@ -433,4 +436,12 @@ log_queries = [external_image_storage.gcs] ;key_file = ;bucket = -;path = \ No newline at end of file +;path = + +[external_image_storage.azure_blob] +;account_name = +;account_key = +;container_name = + +[external_image_storage.local] +# does not require any configuration diff --git a/docker/blocks/apache_proxy/Dockerfile b/docker/blocks/apache_proxy/Dockerfile new file mode 100644 index 00000000000..37c2a4e493b --- /dev/null +++ b/docker/blocks/apache_proxy/Dockerfile @@ -0,0 +1,4 @@ +FROM jmferrer/apache2-reverse-proxy:latest + +COPY ports.conf /etc/apache2/sites-enabled +COPY proxy.conf /etc/apache2/sites-enabled \ No newline at end of file diff --git a/docker/blocks/apache_proxy/docker-compose.yaml b/docker/blocks/apache_proxy/docker-compose.yaml new file mode 100644 index 00000000000..2aec3d4bc4f --- /dev/null +++ b/docker/blocks/apache_proxy/docker-compose.yaml @@ -0,0 +1,9 @@ +# This will proxy all requests for http://localhost:10081/grafana/ to +# http://localhost:3000 (Grafana running locally) +# +# Please note that you'll need to change the root_url in the Grafana configuration: +# root_url = %(protocol)s://%(domain)s:/grafana/ + + apacheproxy: + build: blocks/apache_proxy + network_mode: host diff --git a/docker/blocks/apache_proxy/ports.conf b/docker/blocks/apache_proxy/ports.conf new file mode 100644 index 00000000000..e7a5f9712af --- /dev/null +++ b/docker/blocks/apache_proxy/ports.conf @@ -0,0 +1 @@ +Listen 10081 \ No newline at end of file diff --git a/docker/blocks/apache_proxy/proxy.conf b/docker/blocks/apache_proxy/proxy.conf new file mode 100644 index 00000000000..5eb35cbe8b9 --- /dev/null +++ b/docker/blocks/apache_proxy/proxy.conf @@ -0,0 +1,4 @@ + + ProxyPass /grafana/ http://localhost:3000/ + ProxyPassReverse /grafana/ http://localhost:3000/ + \ No newline at end of file diff --git a/docker/blocks/graphite/docker-compose.yaml b/docker/blocks/graphite/docker-compose.yaml index 2bd0dc322cc..606e28638f7 100644 --- a/docker/blocks/graphite/docker-compose.yaml +++ b/docker/blocks/graphite/docker-compose.yaml @@ -1,4 +1,4 @@ - graphite: + graphite09: build: blocks/graphite ports: - "8080:80" diff --git a/docker/blocks/mysql/dashboard.json b/docker/blocks/mysql/dashboard.json new file mode 100644 index 00000000000..e2b791f82e6 --- /dev/null +++ b/docker/blocks/mysql/dashboard.json @@ -0,0 +1,549 @@ +{ + "__inputs": [ + { + "name": "DS_MYSQL", + "label": "Mysql", + "description": "", + "type": "datasource", + "pluginId": "mysql", + "pluginName": "MySQL" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "mysql", + "name": "MySQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A dashboard visualizing data generated from grafana/fake-data-gen", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1518602729468, + "links": [], + "panels": [ + { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_MYSQL}", + "fill": 2, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "format": "time_series", + "hide": false, + "rawSql": "SELECT\n $__timeGroup(createdAt,'$summarize') as time_sec,\n avg(value) as value,\n hostname as metric\nFROM \n grafana_metric\nWHERE\n $__timeFilter(createdAt) AND\n measurement = 'logins.count' AND\n hostname IN($host)\nGROUP BY 1, 3\nORDER BY 1", + "refId": "A", + "target": "" + }, + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(createdAt,'$summarize') as time_sec,\n min(value) as value,\n 'total avg' as metric\nFROM \n grafana_metric\nWHERE\n $__timeFilter(createdAt) AND\n measurement = 'logins.count'\nGROUP BY 1\nORDER BY 1", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": "1h", + "title": "Average logins / $summarize", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_MYSQL}", + "fill": 2, + "gridPos": { + "h": 18, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(createdAt,'$summarize') as time_sec,\n avg(value) as value,\n 'started' as metric\nFROM \n grafana_metric\nWHERE\n $__timeFilter(createdAt) AND\n measurement = 'payment.started'\nGROUP BY 1, 3\nORDER BY 1", + "refId": "A", + "target": "" + }, + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(createdAt,'$summarize') as time_sec,\n avg(value) as value,\n 'ended' as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(createdAt) AND\n measurement = 'payment.ended'\nGROUP BY 1, 3\nORDER BY 1", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": "1h", + "title": "Average payments started/ended / $summarize", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_MYSQL}", + "fill": 2, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(createdAt,'$summarize') as time_sec,\n max(value) as value,\n hostname as metric\nFROM \n grafana_metric\nWHERE\n $__timeFilter(createdAt) AND\n measurement = 'cpu' AND\n hostname IN($host)\nGROUP BY 1, 3\nORDER BY 1", + "refId": "A", + "target": "" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": "1h", + "title": "Max CPU / $summarize", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "columns": [], + "datasource": "${DS_MYSQL}", + "fontSize": "100%", + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 6, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "alias": "", + "format": "table", + "rawSql": "SELECT createdAt as Time, source, datacenter, hostname, value FROM grafana_metric WHERE hostname in($host)", + "refId": "A", + "target": "" + } + ], + "timeShift": "1h", + "title": "Values", + "transform": "table", + "type": "table" + } + ], + "schemaVersion": 16, + "style": "dark", + "tags": [ + "fake-data-gen", + "mysql" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "${DS_MYSQL}", + "hide": 0, + "includeAll": false, + "label": "Datacenter", + "multi": false, + "name": "datacenter", + "options": [], + "query": "SELECT DISTINCT datacenter FROM grafana_metric", + "refresh": 1, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_MYSQL}", + "hide": 0, + "includeAll": true, + "label": "Hostname", + "multi": true, + "name": "host", + "options": [], + "query": "SELECT DISTINCT hostname FROM grafana_metric WHERE datacenter='$datacenter'", + "refresh": 1, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 5, + "auto_min": "10s", + "current": { + "selected": true, + "text": "1m", + "value": "1m" + }, + "hide": 0, + "label": "Summarize", + "name": "summarize", + "options": [ + { + "selected": false, + "text": "1s", + "value": "1s" + }, + { + "selected": false, + "text": "10s", + "value": "10s" + }, + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1s,10s,30s,1m,5m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Grafana Fake Data Gen - MySQL", + "uid": "DGsCac3kz", + "version": 6 +} \ No newline at end of file diff --git a/docker/blocks/mysql/docker-compose.yaml b/docker/blocks/mysql/docker-compose.yaml index 6eee158ac43..f7881e66539 100644 --- a/docker/blocks/mysql/docker-compose.yaml +++ b/docker/blocks/mysql/docker-compose.yaml @@ -12,3 +12,10 @@ - /etc/timezone:/etc/timezone:ro command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all] + fake-mysql-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: mysql + FD_PORT: 3306 + diff --git a/docker/blocks/mysql_tests/docker-compose.yaml b/docker/blocks/mysql_tests/docker-compose.yaml index c6c3097d463..3c59b66b5ac 100644 --- a/docker/blocks/mysql_tests/docker-compose.yaml +++ b/docker/blocks/mysql_tests/docker-compose.yaml @@ -7,4 +7,7 @@ MYSQL_PASSWORD: password ports: - "3306:3306" + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro tmpfs: /var/lib/mysql:rw diff --git a/docker/blocks/nginx_proxy/Dockerfile b/docker/blocks/nginx_proxy/Dockerfile new file mode 100644 index 00000000000..9ded20dfdda --- /dev/null +++ b/docker/blocks/nginx_proxy/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY nginx.conf /etc/nginx/nginx.conf \ No newline at end of file diff --git a/docker/blocks/nginx_proxy/docker-compose.yaml b/docker/blocks/nginx_proxy/docker-compose.yaml new file mode 100644 index 00000000000..7c3447ade5c --- /dev/null +++ b/docker/blocks/nginx_proxy/docker-compose.yaml @@ -0,0 +1,9 @@ +# This will proxy all requests for http://localhost:10080/grafana/ to +# http://localhost:3000 (Grafana running locally) +# +# Please note that you'll need to change the root_url in the Grafana configuration: +# root_url = %(protocol)s://%(domain)s:/grafana/ + + nginxproxy: + build: blocks/nginx_proxy + network_mode: host diff --git a/docker/blocks/nginx_proxy/nginx.conf b/docker/blocks/nginx_proxy/nginx.conf new file mode 100644 index 00000000000..18e27b3fb01 --- /dev/null +++ b/docker/blocks/nginx_proxy/nginx.conf @@ -0,0 +1,19 @@ +events { worker_connections 1024; } + +http { + sendfile on; + + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + + server { + listen 10080; + + location /grafana/ { + proxy_pass http://localhost:3000/; + } + } +} \ No newline at end of file diff --git a/docker/blocks/postgres/dashboard.json b/docker/blocks/postgres/dashboard.json new file mode 100644 index 00000000000..77b0ceac624 --- /dev/null +++ b/docker/blocks/postgres/dashboard.json @@ -0,0 +1,547 @@ +{ + "__inputs": [ + { + "name": "DS_POSTGRESQL", + "label": "PostgreSQL", + "description": "", + "type": "datasource", + "pluginId": "postgres", + "pluginName": "PostgreSQL" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A dashboard visualizing data generated from grafana/fake-data-gen", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1518601837383, + "links": [], + "panels": [ + { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_POSTGRESQL}", + "fill": 2, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "format": "time_series", + "hide": false, + "rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n avg(value) as \"value\",\n hostname as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'logins.count' AND\n hostname IN($host)\nGROUP BY time, metric\nORDER BY time", + "refId": "A", + "target": "" + }, + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n min(value) as \"value\",\n 'total avg' as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'logins.count'\nGROUP BY time", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Average logins / $summarize", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_POSTGRESQL}", + "fill": 2, + "gridPos": { + "h": 18, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n avg(value) as \"value\",\n 'started' as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'payment.started'\nGROUP BY time, metric\nORDER BY time", + "refId": "A", + "target": "" + }, + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n avg(value) as \"value\",\n 'ended' as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'payment.ended'\nGROUP BY time, metric\nORDER BY time", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Average payments started/ended / $summarize", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_POSTGRESQL}", + "fill": 2, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "format": "time_series", + "rawSql": "SELECT\n $__timeGroup(\"createdAt\",'$summarize'),\n max(value) as \"value\",\n hostname as \"metric\"\nFROM \n grafana_metric\nWHERE\n $__timeFilter(\"createdAt\") AND\n measurement = 'cpu' AND\n hostname IN($host)\nGROUP BY time, metric\nORDER BY time", + "refId": "A", + "target": "" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Max CPU / $summarize", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "columns": [], + "datasource": "${DS_POSTGRESQL}", + "fontSize": "100%", + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 6, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "alias": "", + "format": "table", + "rawSql": "SELECT \"createdAt\" as \"Time\", source, datacenter, hostname, value FROM grafana_metric WHERE hostname in($host)", + "refId": "A", + "target": "" + } + ], + "title": "Values", + "transform": "table", + "type": "table" + } + ], + "schemaVersion": 16, + "style": "dark", + "tags": [ + "fake-data-gen", + "postgres" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "${DS_POSTGRESQL}", + "hide": 0, + "includeAll": false, + "label": "Datacenter", + "multi": false, + "name": "datacenter", + "options": [], + "query": "SELECT DISTINCT datacenter FROM grafana_metric", + "refresh": 1, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_POSTGRESQL}", + "hide": 0, + "includeAll": true, + "label": "Hostname", + "multi": true, + "name": "host", + "options": [], + "query": "SELECT DISTINCT hostname FROM grafana_metric WHERE datacenter='$datacenter'", + "refresh": 1, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 5, + "auto_min": "10s", + "current": { + "text": "1m", + "value": "1m" + }, + "hide": 0, + "label": "Summarize", + "name": "summarize", + "options": [ + { + "selected": false, + "text": "1s", + "value": "1s" + }, + { + "selected": false, + "text": "10s", + "value": "10s" + }, + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1s,10s,30s,1m,5m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Grafana Fake Data Gen - PostgreSQL", + "uid": "JYola5qzz", + "version": 1 +} \ No newline at end of file diff --git a/docker/blocks/postgres/docker-compose.yaml b/docker/blocks/postgres/docker-compose.yaml index eced00aafeb..566df7b8877 100644 --- a/docker/blocks/postgres/docker-compose.yaml +++ b/docker/blocks/postgres/docker-compose.yaml @@ -7,3 +7,10 @@ ports: - "5432:5432" command: postgres -c log_connections=on -c logging_collector=on -c log_destination=stderr -c log_directory=/var/log/postgresql + + fake-postgres-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: postgres + FD_PORT: 5432 \ No newline at end of file diff --git a/docker/blocks/prometheus/Dockerfile b/docker/blocks/prometheus/Dockerfile index 1ad28f524ff..2098e6527d3 100644 --- a/docker/blocks/prometheus/Dockerfile +++ b/docker/blocks/prometheus/Dockerfile @@ -1,3 +1,3 @@ -FROM prom/prometheus +FROM prom/prometheus:v1.8.2 ADD prometheus.yml /etc/prometheus/ ADD alert.rules /etc/prometheus/ diff --git a/docker/blocks/prometheus2/docker-compose.yaml b/docker/blocks/prometheus2/docker-compose.yaml new file mode 100644 index 00000000000..7b133ed9000 --- /dev/null +++ b/docker/blocks/prometheus2/docker-compose.yaml @@ -0,0 +1,25 @@ + prometheus: + build: blocks/prometheus2 + network_mode: host + ports: + - "9090:9090" + + node_exporter: + image: prom/node-exporter + network_mode: host + ports: + - "9100:9100" + + fake-prometheus-data: + image: grafana/fake-data-gen + network_mode: host + ports: + - "9091:9091" + environment: + FD_DATASOURCE: prom + + alertmanager: + image: quay.io/prometheus/alertmanager + network_mode: host + ports: + - "9093:9093" diff --git a/docs/Dockerfile b/docs/Dockerfile index 7679f2b7e4b..faf90ea0ecd 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -9,5 +9,6 @@ FROM grafana/docs-base:latest COPY config.toml /site COPY awsconfig /site +COPY versions.json /site/static/js VOLUME ["/site/content"] diff --git a/docs/VERSION b/docs/VERSION index b570a0ac21b..5e0a0f1d665 100644 --- a/docs/VERSION +++ b/docs/VERSION @@ -1 +1 @@ -v4.3 +v5.0 diff --git a/docs/sources/administration/cli.md b/docs/sources/administration/cli.md index 2be1881cfab..3dc9b0cf3b4 100644 --- a/docs/sources/administration/cli.md +++ b/docs/sources/administration/cli.md @@ -10,17 +10,17 @@ weight = 8 # Grafana CLI -Grafana cli is a small executable that is bundled with grafana server and is suppose to be executed on the same machine as grafana runs. +Grafana cli is a small executable that is bundled with Grafana-server and is supposed to be executed on the same machine Grafana-server is running on. ## Plugins -The CLI helps you install, upgrade and manage your plugins on the same machine it CLI is running. -You can find more information about how to install and manage your plugins at the -[plugin page]({{< relref "plugins/installation.md" >}}). +The CLI allows you to install, upgrade and manage your plugins on the machine it is running on. +You can find more information about how to install and manage your plugins in the +[plugins page]({{< relref "plugins/installation.md" >}}). ## Admin -> This feature is only available in grafana 4.1 and above. +> This feature is only available in Grafana 4.1 and above. To show all admin commands: `grafana-cli admin` @@ -39,7 +39,7 @@ then there are two flags that can be used to set homepath and the config file pa `grafana-cli admin reset-admin-password --homepath "/usr/share/grafana" newpass` -If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API](http://docs.grafana.org/http_api/user/#change-password) can be used. Here is an example with curl using basic auth: +If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API](http://docs.grafana.org/http_api/user/#change-password) can be used. Here is an example using curl with basic auth: ```bash curl -X PUT -H "Content-Type: application/json" -d '{ diff --git a/docs/sources/administration/metrics.md b/docs/sources/administration/metrics.md index 56d0290bc82..5eed2b7ce15 100644 --- a/docs/sources/administration/metrics.md +++ b/docs/sources/administration/metrics.md @@ -10,6 +10,6 @@ weight = 8 # Internal metrics -Grafana collects some metrics about it self internally. Currently Grafana supports pushing metrics to graphite and exposing them to be scraped by Prometheus. +Grafana collects some metrics about itself internally. Currently, Grafana supports pushing metrics to Graphite or exposing them to be scraped by Prometheus. -To enabled internal metrics you have to enable it under the [metrics] section in your [grafana.ini](http://docs.grafana.org/installation/configuration/#enabled-6) config file.If you want to push metrics to graphite you have also have to configure the [metrics.graphite](http://docs.grafana.org/installation/configuration/#metrics-graphite) section. +To emit internal metrics you have to enable the option under the [metrics] section in your [grafana.ini](http://docs.grafana.org/installation/configuration/#enabled-6) config file. If you want to push metrics to Graphite, you must also configure the [metrics.graphite](http://docs.grafana.org/installation/configuration/#metrics-graphite) section. diff --git a/docs/sources/administration/permissions.md b/docs/sources/administration/permissions.md new file mode 100644 index 00000000000..e7b84a417c0 --- /dev/null +++ b/docs/sources/administration/permissions.md @@ -0,0 +1,118 @@ ++++ +title = "Permissions" +description = "Grafana user permissions" +keywords = ["grafana", "configuration", "documentation", "admin", "users", "permissions"] +type = "docs" +aliases = ["/reference/admin"] +[menu.docs] +name = "Permissions" +parent = "admin" +weight = 3 ++++ + +# Permissions + +Grafana users have permissions that are determined by their: + +- **Organization Role** (Admin, Editor, Viewer) +- Via **Team** memberships where the **Team** has been assigned specific permissions. +- Via permissions assigned directly to user (on folders or dashboards) +- The Grafana Admin (i.e. Super Admin) user flag. + +## Organization Roles + +Users can be belong to one or more organizations. A user's organization membership is tied to a role that defines what the user is allowed to do +in that organization. + +### Admin Role + +Can do everything scoped to the organization. For example: + +- Add & Edit data sources. +- Add & Edit organization users & teams. +- Configure App plugins & set org settings. + +### Editor Role + +- Can create and modify dashboards & alert rules. This can be disabled on specific folders and dashboards. +- **Cannot** create or edit data sources nor invite new users. + +### Viewer Role + +- View any dashboard. This can be disabled on specific folders and dashboards. +- **Cannot** create or edit dashboards nor data sources. + +This role can be tweaked via Grafana server setting [viewers_can_edit]({{< relref "installation/configuration.md#viewers-can-edit" >}}). If you set this to true users +with **Viewer** can also make transient dashboard edits, meaning they can modify panels & queries but not save the changes (nor create new dashboards). +Useful for public Grafana installations where you want anonymous users to be able to edit panels & queries but not save or create new dashboards. + +## Grafana Admin + +This admin flag makes a user a `Super Admin`. This means they can access the `Server Admin` views where all users and organizations can be administrated. + +### Dashboard & Folder Permissions + +> Introduced in Grafana v5.0 + +{{< docs-imagebox img="/img/docs/v50/folder_permissions.png" max-width="500px" class="docs-image--right" >}} + +For dashboards and dashboard folders there is a **Permissions** page that make it possible to +remove the default role based permssions for Editors and Viewers. It's here you can add and assign permissions to specific **Users** and **Teams**. + +You can assign & remove permissions for **Organization Roles**, **Users** and **Teams**. + +Permission levels: + +- **Admin**: Can edit & create dashboards and edit permissions. +- **Edit**: Can edit & create dashboards. **Cannot** edit folder/dashboard permissions. +- **View**: Can only view existing dashboards/folders. + +#### Restricting Access + +The highest permission always wins so if you for example want to hide a folder or dashboard from others you need to remove the **Organization Role** based permission from the Access Control List (ACL). + +- You cannot override permissions for users with the **Org Admin Role**. Admins always have access to everything. +- A more specific permission with a lower permission level will not have any effect if a more general rule exists with higher permission level. You need to remove or lower the permission level of the more general rule. + +#### How Grafana Resolves Multiple Permissions - Examples + +##### Example 1 (`user1` has the Editor Role) + +Permissions for a dashboard: + +- `Everyone with Editor Role Can Edit` +- `user1 Can View` + +Result: `user1` has Edit permission as the highest permission always wins. + +##### Example 2 (`user1` has the Viewer Role and is a member of `team1`) + +Permissions for a dashboard: + +- `Everyone with Viewer Role Can View` +- `user1 Can Edit` +- `team1 Can Admin` + +Result: `user1` has Admin permission as the highest permission always wins. + +##### Example 3 + +Permissions for a dashboard: + +- `user1 Can Admin (inherited from parent folder)` +- `user1 Can Edit` + +Result: You cannot override to a lower permission. `user1` has Admin permission as the highest permission always wins. + +- **View**: Can only view existing dashboars/folders. +- You cannot override permissions for users with **Org Admin Role** +- A more specific permission with lower permission level will not have any effect if a more general rule exists with higher permission level. For example if "Everyone with Editor Role Can Edit" exists in the ACL list then **John Doe** will still have Edit permission even after you have specifically added a permission for this user with the permission set to **View**. You need to remove or lower the permission level of the more general rule. + +### Data source permissions + +Permissions on dashboards and folders **do not** include permissions on data sources. A user with `Viewer` role +can still issue any possible query to a data source, not just those queries that exist on dashboards he/she has access to. +We hope to add permissions on data sources in a future release. Until then **do not** view dashboard permissions as a secure +way to restrict user data access. Dashboard permissions only limits what dashboards & folders a user can view & edit not which +data sources a user can access nor what queries a user can issue. + diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index 3dd5c5fd1d3..140053ec541 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -3,6 +3,7 @@ title = "Provisioning" description = "" keywords = ["grafana", "provisioning"] type = "docs" +aliases = ["/installation/provisioning"] [menu.docs] parent = "admin" weight = 8 @@ -12,7 +13,7 @@ weight = 8 ## Config file -Checkout the [configuration](/installation/configuration) page for more information about what you can configure in `grafana.ini` +Checkout the [configuration](/installation/configuration) page for more information on what you can configure in `grafana.ini` ### Config file locations @@ -35,7 +36,7 @@ GF__ ``` Where the section name is the text within the brackets. Everything -should be upper case, `.` should be replaced by `_`. For example, given these configuration settings: +should be upper case and `.` should be replaced by `_`. For example, given these configuration settings: ```bash # default section @@ -48,7 +49,7 @@ admin_user = admin client_secret = 0ldS3cretKey ``` -Then you can override them using: +Overriding will be done like so: ```bash export GF_DEFAULT_INSTANCE_NAME=my-instance @@ -60,34 +61,36 @@ export GF_AUTH_GOOGLE_CLIENT_SECRET=newS3cretKey ## Configuration management tools -Currently we do not provide any scripts/manifests for configuring Grafana. Rather then spending time learning and creating scripts/manifests for each tool, we think our time is better spent making Grafana easier to provision. Therefor, we heavily relay on the expertise of he community. +Currently we do not provide any scripts/manifests for configuring Grafana. Rather than spending time learning and creating scripts/manifests for each tool, we think our time is better spent making Grafana easier to provision. Therefore, we heavily relay on the expertise of the community. Tool | Project -----|------------ Puppet | [https://forge.puppet.com/puppet/grafana](https://forge.puppet.com/puppet/grafana) Ansible | [https://github.com/cloudalchemy/ansible-grafana](https://github.com/cloudalchemy/ansible-grafana) -Ansible | [https://github.com/picotrading/ansible-grafana](https://github.com/picotrading/ansible-grafana) Chef | [https://github.com/JonathanTron/chef-grafana](https://github.com/JonathanTron/chef-grafana) Saltstack | [https://github.com/salt-formulas/salt-formula-grafana](https://github.com/salt-formulas/salt-formula-grafana) -## Datasources +## Datasources > This feature is available from v5.0 It's possible to manage datasources in Grafana by adding one or more yaml config files in the [`provisioning/datasources`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `datasources` that will be added or updated during start up. If the datasource already exists, Grafana will update it to match the configuration file. The config file can also contain a list of datasources that should be deleted. That list is called `delete_datasources`. Grafana will delete datasources listed in `delete_datasources` before inserting/updating those in the `datasource` list. -### Running multiple grafana instances. -If you are running multiple instances of Grafana you might run into problems if they have different versions of the datasource.yaml configuration file. The best way to solve this problem is to add a version number to each datasource in the configuration and increase it when you update the config. Grafana will only update datasources with the same or lower version number than specified in the config. That way old configs cannot overwrite newer configs if they restart at the same time. +### Running multiple Grafana instances. +If you are running multiple instances of Grafana you might run into problems if they have different versions of the `datasource.yaml` configuration file. The best way to solve this problem is to add a version number to each datasource in the configuration and increase it when you update the config. Grafana will only update datasources with the same or lower version number than specified in the config. That way, old configs cannot overwrite newer configs if they restart at the same time. ### Example datasource config file ```yaml -# list of datasources that should be deleted from the database -delete_datasources: - - name: Graphite - org_id: 1 +# config file version +apiVersion: 1 -# list of datasources to insert/update depending -# whats available in the datbase +# list of datasources that should be deleted from the database +deleteDatasources: + - name: Graphite + orgId: 1 + +# list of datasources to insert/update depending +# whats available in the database datasources: # name of the datasource. Required - name: Graphite @@ -95,8 +98,8 @@ datasources: type: graphite # access mode. direct or proxy. Required access: proxy - # org id. will default to org_id 1 if not specified - org_id: 1 + # org id. will default to orgId 1 if not specified + orgId: 1 # url url: http://localhost:8080 # database password, if used @@ -106,22 +109,22 @@ datasources: # database name, if used database: # enable/disable basic auth - basic_auth: + basicAuth: # basic auth username - basic_auth_user: + basicAuthUser: # basic auth password - basic_auth_password: + basicAuthPassword: # enable/disable with credentials headers - with_credentials: + withCredentials: # mark as default datasource. Max one per org - is_default: + isDefault: # fields that will be converted to json and stored in json_data - json_data: + jsonData: graphiteVersion: "1.1" tlsAuth: true tlsAuthWithCACert: true # json object of data that will be encrypted. - secure_json_data: + secureJsonData: tlsCACert: "..." tlsClientCert: "..." tlsClientKey: "..." @@ -132,53 +135,72 @@ datasources: #### Json data -Since all datasources dont have the same configuration settings we only have the most common ones as fields. The rest should be stored as a json blob in the `json_data` field. Here are the most common settings that the core datasources use. +Since not all datasources have the same configuration settings we only have the most common ones as fields. The rest should be stored as a json blob in the `json_data` field. Here are the most common settings that the core datasources use. | Name | Type | Datasource |Description | | ----| ---- | ---- | --- | | tlsAuth | boolean | *All* | Enable TLS authentication using client cert configured in secure json data | | tlsAuthWithCACert | boolean | *All* | Enable TLS authtication using CA cert | +| tlsSkipVerify | boolean | *All* | Controls whether a client verifies the server's certificate chain and host name. | | graphiteVersion | string | Graphite | Graphite version | | timeInterval | string | Elastic, Influxdb & Prometheus | Lowest interval/step value that should be used for this data source | -| esVersion | string | Elastic | Elasticsearch version | -| timeField | string | Elastic | Which field that should be used as timestamp | +| esVersion | string | Elastic | Elasticsearch version | +| timeField | string | Elastic | Which field that should be used as timestamp | | interval | string | Elastic | Index date time format | | authType | string | Cloudwatch | Auth provider. keys/credentials/arn | -| assumeRoleArn | string | Cloudwatch | ARN of Assume Role | +| assumeRoleArn | string | Cloudwatch | ARN of Assume Role | | defaultRegion | string | Cloudwatch | AWS region | -| customMetricsNamespaces | string | Cloudwatch | Namespaces of Custom Metrics | +| customMetricsNamespaces | string | Cloudwatch | Namespaces of Custom Metrics | | tsdbVersion | string | OpenTsdb | Version | | tsdbResolution | string | OpenTsdb | Resolution | -| sslmode | string | Postgre | SSLmode. 'disable', 'require', 'verify-ca' or 'verify-full' | +| sslmode | string | Postgre | SSLmode. 'disable', 'require', 'verify-ca' or 'verify-full' | #### Secure Json data -{"authType":"keys","defaultRegion":"us-west-2","timeField":"@timestamp"} +`{"authType":"keys","defaultRegion":"us-west-2","timeField":"@timestamp"}` -Secure json data is a map of settings that will be encrypted with [secret key](/installation/configuration/#secret-key) from the grafana config. The purpose of this is only to hide content from the users of the application. This should be used for storing TLS Cert and password that Grafana will append to request on the server side. All these settings are optional. +Secure json data is a map of settings that will be encrypted with [secret key](/installation/configuration/#secret-key) from the Grafana config. The purpose of this is only to hide content from the users of the application. This should be used for storing TLS Cert and password that Grafana will append to the request on the server side. All of these settings are optional. | Name | Type | Datasource | Description | | ----| ---- | ---- | --- | | tlsCACert | string | *All* |CA cert for out going requests | | tlsClientCert | string | *All* |TLS Client cert for outgoing requests | | tlsClientKey | string | *All* |TLS Client key for outgoing requests | -| password | string | Postgre | password | -| user | string | Postgre | user | +| password | string | Postgre | password | +| user | string | Postgre | user | +| accessKey | string | Cloudwatch | Access key for connecting to Cloudwatch | +| secretKey | string | Cloudwatch | Secret key for connecting to Cloudwatch | ### Dashboards -It's possible to manage dashboards in Grafana by adding one or more yaml config files in the [`provisioning/dashboards`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `dashboards providers` that will load dashboards into grafana. Currently we only support reading dashboards from file but we will add more providers in the future. +It's possible to manage dashboards in Grafana by adding one or more yaml config files in the [`provisioning/dashboards`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `dashboards providers` that will load dashboards into Grafana from the local filesystem. -The dashboard provider config file looks like this +The dashboard provider config file looks somewhat like this: ```yaml +apiVersion: 1 + +providers: - name: 'default' - org_id: 1 + orgId: 1 folder: '' type: file + disableDeletion: false + editable: false options: - folder: /var/lib/grafana/dashboards + path: /var/lib/grafana/dashboards ``` -When grafana starts it will update/insert all dashboards available in the configured folders. If you modify the file the dashboard will also be updated. \ No newline at end of file +When Grafana starts, it will update/insert all dashboards available in the configured path. Then later on poll that path and look for updated json files and insert those update/insert those into the database. + +### Reuseable dashboard urls + +If the dashboard in the json file contains an [uid](/reference/dashboard/#json-fields), Grafana will force insert/update on that uid. This allows you to migrate dashboards betweens Grafana instances and provisioning Grafana from configuration without breaking the urls given since the new dashboard url uses the uid as identifer. +When Grafana starts, it will update/insert all dashboards available in the configured folders. If you modify the file, the dashboard will also be updated. +By default Grafana will delete dashboards in the database if the file is removed. You can disable this behavior using the `disableDeletion` setting. + +> **Note.** Provisioning allows you to overwrite existing dashboards +> which leads to problems if you re-use settings that are supposed to be unique. +> Be careful not to re-use the same `title` multiple times within a folder +> or `uid` within the same installation as this will cause weird behaviours. diff --git a/docs/sources/alerting/metrics.md b/docs/sources/alerting/metrics.md index 02fee6a718a..271e43f4ecf 100644 --- a/docs/sources/alerting/metrics.md +++ b/docs/sources/alerting/metrics.md @@ -13,7 +13,7 @@ weight = 2 > Alerting is only available in Grafana v4.0 and above. -The alert engine publishes some internal metrics about itself. You can read more about how Grafana published [internal metrics](/installation/configuration/#metrics). +The alert engine publishes some internal metrics about itself. You can read more about how Grafana publishes [internal metrics](/installation/configuration/#metrics). Description | Type | Metric name ---------- | ----------- | ---------- diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index 102134f34dd..453d169457b 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -14,23 +14,23 @@ weight = 2 > Alerting is only available in Grafana v4.0 and above. -When an alert changes state it sends out notifications. Each alert rule can have -multiple notifications. But in order to add a notification to an alert rule you first need -to add and configure a `notification` channel (can be email, Pagerduty or other integration). This is done from the Notification Channels page. +When an alert changes state, it sends out notifications. Each alert rule can have +multiple notifications. In order to add a notification to an alert rule you first need +to add and configure a `notification` channel (can be email, PagerDuty or other integration). This is done from the Notification Channels page. ## Notification Channel Setup -{{< imgbox max-width="40%" img="/img/docs/v43/alert_notifications_menu.png" caption="Alerting Notification Channels" >}} +{{< imgbox max-width="30%" img="/img/docs/v50/alerts_notifications_menu.png" caption="Alerting Notification Channels" >}} On the Notification Channels page hit the `New Channel` button to go the page where you can configure and setup a new Notification Channel. -You specify name and type, and type specific options. You can also test the notification to make -sure it's working and setup correctly. +You specify a name and a type, and type specific options. You can also test the notification to make +sure it's setup correctly. ### Send on all alerts -When checked this option will make this notification used for all alert rules, existing and new. +When checked, this option will nofity for all alert rules - existing and new. ## Supported Notification Types @@ -38,39 +38,39 @@ Grafana ships with the following set of notification types: ### Email -To enable email notification you have to setup [SMTP settings](/installation/configuration/#smtp) -in the Grafana config. Email notification will upload an image of the alert graph to an -external image destination if available or fallback to attaching the image in the email. +To enable email notifications you have to setup [SMTP settings](/installation/configuration/#smtp) +in the Grafana config. Email notifications will upload an image of the alert graph to an +external image destination if available or fallback to attaching the image to the email. ### Slack {{< imgbox max-width="40%" img="/img/docs/v4/slack_notification.png" caption="Alerting Slack Notification" >}} -To set up slack you need to configure an incoming webhook url at slack. You can follow their guide for how -to do that https://api.slack.com/incoming-webhooks If you want to include screenshots of the firing alerts -in the slack messages you have to configure either the [external image destination](#external-image-store) in Grafana, +To set up slack you need to configure an incoming webhook url at slack. You can follow their guide on how +to do that [here](https://api.slack.com/incoming-webhooks). If you want to include screenshots of the firing alerts +in the Slack messages you have to configure either the [external image destination](#external-image-store) in Grafana, or a bot integration via Slack Apps. Follow Slack's guide to set up a bot integration and use the token provided -https://api.slack.com/bot-users, which starts with "xoxb". +(https://api.slack.com/bot-users), which starts with "xoxb". Setting | Description ---------- | ----------- -Recipient | allows you to override the slack recipient. -Mention | make it possible to include a mention in the slack notification sent by Grafana. Ex @here or @channel +Recipient | allows you to override the Slack recipient. +Mention | make it possible to include a mention in the Slack notification sent by Grafana. Ex @here or @channel Token | If provided, Grafana will upload the generated image via Slack's file.upload API method, not the external image destination. ### PagerDuty -To set up PagerDuty, all you have to do is to provide an api key. +To set up PagerDuty, all you have to do is to provide an API key. Setting | Description ---------- | ----------- -Integration Key | Integration key for pagerduty. -Auto resolve incidents | Resolve incidents in pagerduty once the alert goes back to ok +Integration Key | Integration key for PagerDuty. +Auto resolve incidents | Resolve incidents in PagerDuty once the alert goes back to ok ### Webhook -The webhook notification is a simple way to send information about an state change over HTTP to a custom endpoint. -Using this notification you could integrate Grafana into any system you choose, by yourself. +The webhook notification is a simple way to send information about a state change over HTTP to a custom endpoint. +Using this notification you could integrate Grafana into a system of your choosing. Example json body: @@ -117,45 +117,48 @@ Dingtalk supports the following "message type": `text`, `link` and `markdown`. O ### Kafka -Notifications can be sent to a Kafka topic from Grafana using [Kafka REST Proxy](https://docs.confluent.io/1.0/kafka-rest/docs/index.html). -There are couple of configurations options which need to be set in Grafana UI under Kafka Settings: +Notifications can be sent to a Kafka topic from Grafana using the [Kafka REST Proxy](https://docs.confluent.io/1.0/kafka-rest/docs/index.html). +There are a couple of configuration options which need to be set up in Grafana UI under Kafka Settings: 1. Kafka REST Proxy endpoint. 2. Kafka Topic. -Once these two properties are set, you can send the alerts to Kafka for further processing or throttling them. +Once these two properties are set, you can send the alerts to Kafka for further processing or throttling. -### Other Supported Notification Channels +### All supported notifier -Grafana also supports the following Notification Channels: +Name | Type |Support images +-----|------------ | ------ +Slack | `slack` | yes +Pagerduty | `pagerduty` | yes +Email | `email` | yes +Webhook | `webhook` | link +Kafka | `kafka` | no +Hipchat | `hipchat` | yes +VictorOps | `victorops` | yes +Sensu | `sensu` | yes +OpsGenie | `opsgenie` | yes +Threema | `threema` | yes +Pushover | `pushover` | no +Telegram | `telegram` | no +Line | `line` | no +Prometheus Alertmanager | `prometheus-alertmanager` | no -- HipChat -- VictorOps - -- Sensu - -- OpsGenie - -- Threema - -- Pushover - -- Telegram - -- LINE # Enable images in notifications {#external-image-store} -Grafana can render the panel associated with the alert rule and include that in the notification. Most Notification Channels require that this image be publicly accessible (Slack and PagerDuty for example). In order to include images in alert notifications, Grafana can upload the image to an image store. It currently supports -Amazon S3 and Webdav for this. So to set that up you need to configure the [external image uploader](/installation/configuration/#external-image-storage) in your grafana-server ini config file. +Grafana can render the panel associated with the alert rule and include that in the notification. Most Notification Channels require that this image be publicly accessable (Slack and PagerDuty for example). In order to include images in alert notifications, Grafana can upload the image to an image store. It currently supports +Amazon S3, Webdav, Google Cloud Storage and Azure Blob Storage. So to set that up you need to configure the [external image uploader](/installation/configuration/#external-image-storage) in your grafana-server ini config file. + +Be aware that some notifiers requires public access to the image to be able to include it in the notification. So make sure to enable public access to the images. If your using local image uploader, your Grafana instance need to be accessible by the internet. Currently only the Email Channels attaches images if no external image store is specified. To include images in alert notifications for other channels then you need to set up an external image store. -This is an optional requirement, you can get Slack and email notifications without setting this up. +This is an optional requirement. You can get Slack and email notifications without setting this up. # Configure the link back to Grafana from alert notifications -All alert notifications contains a link back to the triggered alert in the Grafana instance. +All alert notifications contain a link back to the triggered alert in the Grafana instance. This url is based on the [domain](/installation/configuration/#domain) setting in Grafana. diff --git a/docs/sources/features/datasources/cloudwatch.md b/docs/sources/features/datasources/cloudwatch.md index bdf661dc4fc..e955dbb9569 100644 --- a/docs/sources/features/datasources/cloudwatch.md +++ b/docs/sources/features/datasources/cloudwatch.md @@ -13,7 +13,7 @@ weight = 10 # Using AWS CloudWatch in Grafana -Grafana ships with built in support for CloudWatch. You just have to add it as a data source and you will be ready to build dashboards for you CloudWatch metrics. +Grafana ships with built in support for CloudWatch. You just have to add it as a data source and you will be ready to build dashboards for your CloudWatch metrics. ## Adding the data source to Grafana @@ -78,11 +78,14 @@ CloudWatch Datasource Plugin provides the following queries you can specify in t edit view. They allow you to fill a variable's options list with things like `region`, `namespaces`, `metric names` and `dimension keys/values`. +In place of `region` you can specify `default` to use the default region configured in the datasource for the query, +e.g. `metrics(AWS/DynamoDB, default)` or `dimension_values(default, ..., ..., ...)`. + Name | Description ------- | -------- *regions()* | Returns a list of regions AWS provides their service. *namespaces()* | Returns a list of namespaces CloudWatch support. -*metrics(namespace, [region])* | Returns a list of metrics in the namespace. (specify region for custom metrics) +*metrics(namespace, [region])* | Returns a list of metrics in the namespace. (specify region or use "default" for custom metrics) *dimension_keys(namespace)* | Returns a list of dimension keys in the namespace. *dimension_values(region, namespace, metric, dimension_key)* | Returns a list of dimension values matching the specified `region`, `namespace`, `metric` and `dimension_key`. *ebs_volume_ids(region, instance_id)* | Returns a list of volume ids matching the specified `region`, `instance_id`. diff --git a/docs/sources/features/datasources/mysql.md b/docs/sources/features/datasources/mysql.md index d9f048e0371..7fae7441b6d 100644 --- a/docs/sources/features/datasources/mysql.md +++ b/docs/sources/features/datasources/mysql.md @@ -45,7 +45,14 @@ To simplify syntax and to allow for dynamic parts, like date range filters, the Macro example | Description ------------ | ------------- +*$__time(dateColumn)* | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, *UNIX_TIMESTAMP(dateColumn) as time_sec* *$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *dateColumn > FROM_UNIXTIME(1494410783) AND dateColumn < FROM_UNIXTIME(1494497183)* +*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *FROM_UNIXTIME(1494410783)* +*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *FROM_UNIXTIME(1494497183)* +*$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *cast(cast(UNIX_TIMESTAMP(dateColumn)/(300) as signed)*300 as signed) as time_sec,* +*$__unixEpochFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name with times represented as unix timestamp. For example, *dateColumn > 1494410783 AND dateColumn < 1494497183* +*$__unixEpochFrom()* | Will be replaced by the start of the currently active time selection as unix timestamp. For example, *1494410783* +*$__unixEpochTo()* | Will be replaced by the end of the currently active time selection as unix timestamp. For example, *1494497183* We plan to add many more macros. If you have suggestions for what macros you would like to see, please [open an issue](https://github.com/grafana/grafana) in our GitHub repo. @@ -99,6 +106,19 @@ GROUP BY metric1, UNIX_TIMESTAMP(time_date_time) DIV 300 ORDER BY time_sec asc ``` +Example with $__timeGroup macro: + +```sql +SELECT + $__timeGroup(time_date_time,'5m') as time_sec, + min(value_double) as value, + metric_name as metric +FROM test_data +WHERE $__timeFilter(time_date_time) +GROUP BY 1, metric_name +ORDER BY 1 +``` + Currently, there is no support for a dynamic group by time based on time range & panel width. This is something we plan to add. diff --git a/docs/sources/features/index.md b/docs/sources/features/index.md index 1352e9f0576..d7fae41682b 100644 --- a/docs/sources/features/index.md +++ b/docs/sources/features/index.md @@ -5,7 +5,7 @@ type = "docs" [menu.docs] name = "Features" identifier = "features" -weight = 3 +weight = 4 +++ diff --git a/docs/sources/features/panels/singlestat.md b/docs/sources/features/panels/singlestat.md index 5e2cb36600b..510642337ff 100644 --- a/docs/sources/features/panels/singlestat.md +++ b/docs/sources/features/panels/singlestat.md @@ -47,7 +47,7 @@ The coloring options of the Singlestat Panel config allow you to dynamically cha 2. **Thresholds**: Change the background and value colors dynamically within the panel, depending on the Singlestat value. The threshold field accepts **2 comma-separated** values which represent 3 ranges that correspond to the three colors directly to the right. For example: if the thresholds are 70, 90 then the first color represents < 70, the second color represents between 70 and 90 and the third color represents > 90. 3. **Colors**: Select a color and opacity 4. **Value**: This checkbox applies the configured thresholds and colors to the summary stat. -5. **Invert order**: This link toggles the threshold color order.
For example: Green, Orange, Red () will become Red, Orange, Green (). +5. **Invert order**: This link toggles the threshold color order.
For example: Green, Orange, Red () will become Red, Orange, Green (). ### Spark Lines diff --git a/docs/sources/features/shortcuts.md b/docs/sources/features/shortcuts.md index caad521446e..cbcf3670c83 100644 --- a/docs/sources/features/shortcuts.md +++ b/docs/sources/features/shortcuts.md @@ -8,7 +8,7 @@ weight = 7 # Keyboard shortcuts -{{< docs-imagebox img="/img/docs/v4/shortcuts.png" max-width="20rem" class="docs-image--right" >}} +{{< docs-imagebox img="/img/docs/v50/shortcuts.png" max-width="20rem" class="docs-image--right" >}} Grafana v4 introduces a number of really powerful keyboard shortcuts. You can now focus a panel by hovering over it with your mouse. With a panel focused you can simple hit `e` to toggle panel @@ -34,6 +34,8 @@ Hit `?` on your keyboard to open the shortcuts help modal. - `d` `s` Dashboard settings - `d` `v` Toggle in-active / view mode - `d` `k` Toggle kiosk mode (hides top nav) +- `d` `E` Expand all rows +- `d` `C` Collapse all rows - `mod+o` Toggle shared graph crosshair ### Focused Panel @@ -42,12 +44,9 @@ Hit `?` on your keyboard to open the shortcuts help modal. - `p` `s` Open Panel Share Modal - `p` `r` Remove Panel -### Focused Row -- `r` `c` Collapse Row -- `r` `r` Remove Row - ### Time Range - `t` `z` Zoom out time range - `t` Move time range back - `t` Move time range forward +mod = CTRL on windows or linux and CMD key on Mac diff --git a/docs/sources/guides/basic_concepts.md b/docs/sources/guides/basic_concepts.md index cb64b105349..b710a227a79 100644 --- a/docs/sources/guides/basic_concepts.md +++ b/docs/sources/guides/basic_concepts.md @@ -7,6 +7,7 @@ type = "docs" name = "Basic Concepts" identifier = "basic_concepts" parent = "guides" +weight = 2 +++ # Basic Concepts diff --git a/docs/sources/guides/getting_started.md b/docs/sources/guides/getting_started.md index 5c02042481f..f724504156f 100644 --- a/docs/sources/guides/getting_started.md +++ b/docs/sources/guides/getting_started.md @@ -8,6 +8,7 @@ aliases = ["/guides/gettingstarted"] name = "Getting Started" identifier = "getting_started_guide" parent = "guides" +weight = 1 +++ # Getting started @@ -24,38 +25,38 @@ Read the [Basic Concepts](/guides/basic_concepts) document to get a crash course ### Top header -Let's start with creating a new Dashboard. You can find the new Dashboard link on the right side of the Dashboard picker. You now have a blank Dashboard. +Let's start with creating a new Dashboard. You can find the new Dashboard link on the right side of the Dashboard picker. You now have a blank Dashboard. - + The image above shows you the top header for a Dashboard. 1. Side menubar toggle: This toggles the side menu, allowing you to focus on the data presented in the dashboard. The side menu provides access to features unrelated to a Dashboard such as Users, Organizations, and Data Sources. -2. Dashboard dropdown: This dropdown shows you which Dashboard you are currently viewing, and allows you to easily switch to a new Dashboard. From here you can also create a new Dashboard, Import existing Dashboards, and manage Dashboard playlists. -3. Star Dashboard: Star (or unstar) the current Dashboard. Starred Dashboards will show up on your own Home Dashboard by default, and are a convenient way to mark Dashboards that you're interested in. -4. Share Dashboard: Share the current dashboard by creating a link or create a static Snapshot of it. Make sure the Dashboard is saved before sharing. -5. Save dashboard: The current Dashboard will be saved with the current Dashboard name. -6. Settings: Manage Dashboard settings and features such as Templating and Annotations. +2. Dashboard dropdown: This dropdown shows you which Dashboard you are currently viewing, and allows you to easily switch to a new Dashboard. From here you can also create a new Dashboard or folder, Import existing Dashboards, and manage Dashboard playlists. +3. Add Panel: Adds a new panel to the current Dashboard +4. Star Dashboard: Star (or unstar) the current Dashboard. Starred Dashboards will show up on your own Home Dashboard by default, and are a convenient way to mark Dashboards that you're interested in. +5. Share Dashboard: Share the current dashboard by creating a link or create a static Snapshot of it. Make sure the Dashboard is saved before sharing. +6. Save dashboard: The current Dashboard will be saved with the current Dashboard name. +7. Settings: Manage Dashboard settings and features such as Templating and Annotations. -## Dashboards, Panels, Rows, the building blocks of Grafana... +## Dashboards, Panels, the building blocks of Grafana... -Dashboards are at the core of what Grafana is all about. Dashboards are composed of individual Panels arranged on a number of Rows. Grafana ships with a variety of Panels. Grafana makes it easy to construct the right queries, and customize the display properties so that you can create the perfect Dashboard for your need. Each Panel can interact with data from any configured Grafana Data Source (currently InfluxDB, Graphite, OpenTSDB, Prometheus and Cloudwatch). The [Basic Concepts](/guides/basic_concepts) guide explores these key ideas in detail. +Dashboards are at the core of what Grafana is all about. Dashboards are composed of individual Panels arranged on a grid. Grafana ships with a variety of Panels. Grafana makes it easy to construct the right queries, and customize the display properties so that you can create the perfect Dashboard for your need. Each Panel can interact with data from any configured Grafana Data Source (currently InfluxDB, Graphite, OpenTSDB, Prometheus and Cloudwatch). The [Basic Concepts](/guides/basic_concepts) guide explores these key ideas in detail. - + 1. Zoom out time range 2. Time picker dropdown. Here you can access relative time range options, auto refresh options and set custom absolute time ranges. 3. Manual refresh button. Will cause all panels to refresh (fetch new data). -4. Row controls menu. Via this menu you can add panels to the row, set row height and more. -5. Dashboard panel. You edit panels by clicking the panel title. -6. Graph legend. You can change series colors, y-axis and series visibility directly from the legend. +4. Dashboard panel. You edit panels by clicking the panel title. +5. Graph legend. You can change series colors, y-axis and series visibility directly from the legend. ## Adding & Editing Graphs and Panels ![](/img/docs/v45/metrics_tab.png) -1. You add panels via row menu. The row menu is the icon to the left of each row. +1. You add panels by clicking the Add panel icon on the top menu. 2. To edit the graph you click on the graph title to open the panel menu, then `Edit`. 3. This should take you to the `Metrics` tab. In this tab you should see the editor for your default data source. @@ -63,7 +64,7 @@ When you click the `Metrics` tab, you are presented with a Query Editor that is ## Drag-and-Drop panels -You can Drag-and-Drop Panels within and between Rows. Click and hold the Panel title, and drag it to its new location. You can also easily resize panels by clicking the (-) and (+) icons. +You can Drag-and-Drop Panels by simply clicking and holding the Panel title, and drag it to its new location. You can also easily resize panels by clicking the (-) and (+) icons. ![](/img/docs/animated_gifs/drag_drop.gif) diff --git a/docs/sources/guides/index.md b/docs/sources/guides/index.md index c80dd624624..2ea09142880 100644 --- a/docs/sources/guides/index.md +++ b/docs/sources/guides/index.md @@ -4,6 +4,6 @@ type = "docs" [menu.docs] name = "Getting Started" identifier = "guides" -weight = 2 +weight = 3 +++ diff --git a/docs/sources/guides/whats-new-in-v2-1.md b/docs/sources/guides/whats-new-in-v2-1.md index 68da4f60226..2ad0e3356f0 100644 --- a/docs/sources/guides/whats-new-in-v2-1.md +++ b/docs/sources/guides/whats-new-in-v2-1.md @@ -3,11 +3,6 @@ title = "What's New in Grafana v2.1" description = "Feature & improvement highlights for Grafana v2.1" keywords = ["grafana", "new", "documentation", "2.1"] type = "docs" -[menu.docs] -name = "Version 2.1" -identifier = "v2.1" -parent = "whatsnew" -weight = 10 +++ # What's new in Grafana v2.1 diff --git a/docs/sources/guides/whats-new-in-v2-5.md b/docs/sources/guides/whats-new-in-v2-5.md index ff80ec1f4f4..90270ea1121 100644 --- a/docs/sources/guides/whats-new-in-v2-5.md +++ b/docs/sources/guides/whats-new-in-v2-5.md @@ -3,11 +3,6 @@ title = "What's New in Grafana v2.5" description = "Feature & improvement highlights for Grafana v2.5" keywords = ["grafana", "new", "documentation", "2.5"] type = "docs" -[menu.docs] -name = "Version 2.5" -identifier = "v2.5" -parent = "whatsnew" -weight = 9 +++ # What's new in Grafana v2.5 diff --git a/docs/sources/guides/whats-new-in-v2-6.md b/docs/sources/guides/whats-new-in-v2-6.md index 0b1e6688e60..b8996680ce6 100644 --- a/docs/sources/guides/whats-new-in-v2-6.md +++ b/docs/sources/guides/whats-new-in-v2-6.md @@ -3,11 +3,6 @@ title = "What's New in Grafana v2.6" description = "Feature & improvement highlights for Grafana v2.6" keywords = ["grafana", "new", "documentation", "2.6"] type = "docs" -[menu.docs] -name = "Version 2.6" -identifier = "v2.6" -parent = "whatsnew" -weight = 7 +++ # What's new in Grafana v2.6 diff --git a/docs/sources/guides/whats-new-in-v2.md b/docs/sources/guides/whats-new-in-v2.md index bd92128a12e..499849c8d83 100644 --- a/docs/sources/guides/whats-new-in-v2.md +++ b/docs/sources/guides/whats-new-in-v2.md @@ -3,11 +3,6 @@ title = "What's New in Grafana v2.0" description = "Feature & improvement highlights for Grafana v2.0" keywords = ["grafana", "new", "documentation", "2.0"] type = "docs" -[menu.docs] -name = "Version 2.0" -identifier = "v2.0" -parent = "whatsnew" -weight = 11 +++ # What's New in Grafana v2.0 diff --git a/docs/sources/guides/whats-new-in-v4.md b/docs/sources/guides/whats-new-in-v4.md index 68a40ed7a1e..7b0d2259580 100644 --- a/docs/sources/guides/whats-new-in-v4.md +++ b/docs/sources/guides/whats-new-in-v4.md @@ -55,7 +55,7 @@ of another alert in your conditions, and `Time Of Day`. Alerting would not be very useful if there was no way to send notifications when rules trigger and change state. You can setup notifications of different types. We currently have `Slack`, `PagerDuty`, `Email` and `Webhook` with more in the pipe that will be added during beta period. The notifications can then be added to your alert rules. -If you have configured an external image store in the grafana.ini config file (s3 and webdav options available) +If you have configured an external image store in the grafana.ini config file (s3, webdav, and azure_blob options available) you can get very rich notifications with an image of the graph and the metric values all included in the notification. diff --git a/docs/sources/guides/whats-new-in-v5.md b/docs/sources/guides/whats-new-in-v5.md new file mode 100644 index 00000000000..fdc3c515a79 --- /dev/null +++ b/docs/sources/guides/whats-new-in-v5.md @@ -0,0 +1,154 @@ ++++ +title = "What's New in Grafana v5.0" +description = "Feature & improvement highlights for Grafana v5.0" +keywords = ["grafana", "new", "documentation", "5.0"] +type = "docs" +[menu.docs] +name = "Version 5.0" +identifier = "v5.0" +parent = "whatsnew" +weight = -6 ++++ + +# What's New in Grafana v5.0 + +> Out in beta: [Download now!](https://grafana.com/grafana/download/beta) + +This is the most substantial update that Grafana has ever seen. This article will detail the major new features and enhancements. + +- [New Dashboard Layout Engine]({{< relref "#new-dashboard-layout-engine" >}}) enables a much easier drag, drop and resize experience and new types of layouts. +- [New UX]({{< relref "#new-ux-layout-engine" >}}). The UI has big improvements in both look and function. +- [New Light Theme]({{< relref "#new-light-theme" >}}) is now looking really nice. +- [Dashboard Folders]({{< relref "#dashboard-folders" >}}) helps you keep your dashboards organized. +- [Permissions]({{< relref "#dashboard-folders" >}}) on folders and dashboards helps manage larger Grafana installations. +- [Group users into teams]({{< relref "#teams" >}}) and use them in the new permission system. +- [Datasource provisioning]({{< relref "#data-sources" >}}) makes it possible to setup datasources via config files. +- [Dashboard provisioning]({{< relref "#dashboards" >}}) makes it possible to setup dashboards via config files. +- [Persistent dashboard url's]({{< relref "#dashboard-model-persistent-url-s-and-api-changes" >}}) makes it possible to rename dashboards without breaking links. +- [Graphite Tags & Integrated Function Docs]({{< relref "#graphite-tags-integrated-function-docs" >}}). + +### Video showing new features + + +
+ +## New Dashboard Layout Engine + +{{< docs-imagebox img="/img/docs/v50/new_grid.png" max-width="1000px" class="docs-image--right">}} + +The new dashboard layout engine allows for much easier movement and sizing of panels, as other panels now move out of the way in +a very intuitive way. Panels are sized independently, so rows are no longer necessary to create layouts. This opens +up many new types of layouts where panels of different heights can be aligned easily. Checkout the new grid in the video +above or on the [play site](http://play.grafana.org). All your existing dashboards will automatically migrate to the +new position system and look close to identical. The new panel position makes dashboards saved in v5.0 incompatible +with older versions of Grafana. + +
+ +## New UX + +{{< docs-imagebox img="/img/docs/v50/new_ux_nav.png" max-width="1000px" class="docs-image--right" >}} + +Almost every page has seen significant UX improvements. All pages (except dashboard pages) have a new tab-based layout that improves navigation between pages. The side menu has also changed quite a bit. You can still hide the side menu completely if you click on the Grafana logo. + +
+ +## Dashboard Settings + +{{< docs-imagebox img="/img/docs/v50/dashboard_settings.png" max-width="1000px" class="docs-image--right" >}} +Dashboard pages have a new header toolbar where buttons and actions are now all moved to the right. All the dashboard +settings views have been combined with a side nav which allows you to easily move between different setting categories. + +
+ +## New Light Theme + +{{< docs-imagebox img="/img/docs/v50/new_white_theme.png" max-width="1000px" class="docs-image--right" >}} + +This theme has not seen a lot of love in recent years and we felt it was time to give it a major overhaul. We are very happy with the result. + +
+ +## Dashboard Folders + +{{< docs-imagebox img="/img/docs/v50/new_search.png" max-width="1000px" class="docs-image--right" >}} + +The big new feature that comes with Grafana v5.0 is dashboard folders. Now you can organize your dashboards in folders, +which is very useful if you have a lot of dashboards or multiple teams. + +- New search design adds expandable sections for each folder, starred and recently viewed dashboards. +- New manage dashboard pages enable batch actions and views for folder settings and permissions. +- Set permissions on folders and have dashboards inherit the permissions. + +## Teams + +A team is a new concept in Grafana v5. They are simply a group of users that can be used in the new permission system for dashboards and folders. Only an admin can create teams. +We hope to do more with teams in future releases like integration with LDAP and a team landing page. + +## Permissions + +{{< docs-imagebox img="/img/docs/v50/folder_permissions.png" max-width="1000px" class="docs-image--right" >}} + +You can assign permissions to folders and dashboards. The default user role-based permissions can be removed and +replaced with specific teams or users enabling more control over what a user can see and edit. + +Dashboard permissions only limits what dashboards & folders a user can view & edit not which +data sources a user can access nor what queries a user can issue. + +
+ +## Provisioning from configuration + +In previous versions of Grafana, you could only use the API for provisioning data sources and dashboards. +But that required the service to be running before you started creating dashboards and you also needed to +set up credentials for the HTTP API. In v5.0 we decided to improve this experience by adding a new active +provisioning system that uses config files. This will make GitOps more natural as data sources and dashboards can +be defined via files that can be version controlled. We hope to extend this system to later add support for users, orgs +and alerts as well. + +### Data sources + +Data sources can now be setup using config files. These data sources are by default not editable from the Grafana GUI. +It's also possible to update and delete data sources from the config file. More info in the [data source provisioning docs](/administration/provisioning/#datasources). + +### Dashboards + +We also deprecated the `[dashboard.json]` in favor of our new dashboard provisioner that keeps dashboards on disk +in sync with dashboards in Grafana's database. The dashboard provisioner has multiple advantages over the old +`[dashboard.json]` feature. Instead of storing the dashboard in memory we now insert the dashboard into the database, +which makes it possible to star them, use one as the home dashboard, set permissions and other features in Grafana that +expects the dashboards to exist in the database. More info in the [dashboard provisioning docs](/administration/provisioning/#dashboards) + + +## Graphite Tags & Integrated Function Docs + +{{< docs-imagebox img="/img/docs/v50/graphite_tags.png" max-width="1000px" class="docs-image--right" >}} + +The Graphite query editor has been updated to support the latest Graphite version (v1.2) that adds +many new functions and support for querying by tags. You can now also view function documentation right in the query editor! + +Read more on [Graphite Tag Support](http://graphite.readthedocs.io/en/latest/tags.html?highlight=tags). + +
+ +## Dashboard model, persistent url's and API changes + +We are introducing a new unique identifier (`uid`) in the dashboard JSON model. It's automatically +generated if not provided when creating a dashboard and will have a length of 9-12 characters. + +The unique identifier allows having persistent URL's for accessing dashboards, sharing them +between instances and when using [dashboard provisioning](#dashboards). This means that dashboard can +be renamed without breaking any links. We're changing the url format for dashboards +from `/dashboard/db/:slug` to `/d/:uid/:slug`. We'll keep supporting the old slug-based url's for dashboards +and redirects to the new one for backward compatibility. Please note that the old slug-based url's +have been deprecated and will be removed in a future release. + +Sharing dashboards between instances becomes much easier since the `uid` is unique (unique enough). +This might seem like a small change, but we are incredibly excited about it since it will make it +much easier to manage, collaborate and navigate between dashboards. + +### API changes +New uid-based routes in the dashboard API have been introduced to retrieve and delete dashboards. +The corresponding slug-based routes have been deprecated and will be removed in a future release. + + diff --git a/docs/sources/http_api/admin.md b/docs/sources/http_api/admin.md index 716246102bc..0194c69caac 100644 --- a/docs/sources/http_api/admin.md +++ b/docs/sources/http_api/admin.md @@ -61,7 +61,7 @@ Content-Type: application/json "client_id":"some_id", "client_secret":"************", "enabled":"false", - "scopes":"user:email", + "scopes":"user:email,read:org", "team_ids":"", "token_url":"https://github.com/login/oauth/access_token" }, diff --git a/docs/sources/http_api/alerting.md b/docs/sources/http_api/alerting.md index e66218bb066..3860ae490b1 100644 --- a/docs/sources/http_api/alerting.md +++ b/docs/sources/http_api/alerting.md @@ -62,7 +62,7 @@ Content-Type: application/json } "newStateDate": "2016-12-25", "executionError": "", - "dashboardUri": "http://grafana.com/dashboard/db/sensors" + "url": "http://grafana.com/dashboard/db/sensors" } ] ``` @@ -94,7 +94,7 @@ Content-Type: application/json "state": "alerting", "newStateDate": "2016-12-25", "executionError": "", - "dashboardUri": "http://grafana.com/dashboard/db/sensors" + "url": "http://grafana.com/dashboard/db/sensors" } ``` @@ -196,6 +196,8 @@ Content-Type: application/json ## Create alert notification +You can find the full list of [supported notifers](/alerting/notifications/#all-supported-notifier) at the alert notifiers page. + `POST /api/alert-notifications` **Example Request**: @@ -292,4 +294,4 @@ Content-Type: application/json { "message": "Notification deleted" } -``` \ No newline at end of file +``` diff --git a/docs/sources/http_api/auth.md b/docs/sources/http_api/auth.md index b526031fdeb..166a5a4fdb9 100644 --- a/docs/sources/http_api/auth.md +++ b/docs/sources/http_api/auth.md @@ -100,7 +100,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk JSON Body schema: - **name** – The key name -- **role** – Sets the access level/Grafana Role for the key. Can be one of the following values: `Viewer`, `Editor`, `Read Only Editor` or `Admin`. +- **role** – Sets the access level/Grafana Role for the key. Can be one of the following values: `Viewer`, `Editor` or `Admin`. **Example Response**: diff --git a/docs/sources/http_api/dashboard.md b/docs/sources/http_api/dashboard.md index 0538754bd96..a6ed0c81f4b 100644 --- a/docs/sources/http_api/dashboard.md +++ b/docs/sources/http_api/dashboard.md @@ -11,6 +11,17 @@ parent = "http_api" # Dashboard API +## Identifier (id) vs unique identifier (uid) + +The identifier (id) of a dashboard is an auto-incrementing numeric value and is only unique per Grafana install. + +The unique identifier (uid) of a dashboard can be used for uniquely identify a dashboard between multiple Grafana installs. +It's automatically generated if not provided when creating a dashboard. The uid allows having consistent URL's for accessing +dashboards and when syncing dashboards between multiple Grafana installs, see [dashboard provisioning](/administration/provisioning/#dashboards) +for more information. This means that changing the title of a dashboard will not break any bookmarked links to that dashboard. + +The uid can have a maximum length of 40 characters. + ## Create / Update dashboard `POST /api/dashboards/db` @@ -28,6 +39,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk { "dashboard": { "id": null, + "uid": null, "title": "Production Overview", "tags": [ "templated" ], "timezone": "browser", @@ -38,14 +50,18 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk "schemaVersion": 6, "version": 0 }, + "folderId": 0, "overwrite": false } ``` JSON Body schema: -- **dashboard** – The complete dashboard model, id = null to create a new dashboard -- **overwrite** – Set to true if you want to overwrite existing dashboard with newer version or with same dashboard title. +- **dashboard** – The complete dashboard model, id = null to create a new dashboard. +- **dashboard.id** – id = null to create a new dashboard. +- **dashboard.uid** – Optional [unique identifier](/http_api/dashboard/#identifier-id-vs-unique-identifier-uid) when creating a dashboard. uid = null will generate a new uid. +- **folderId** – The id of the folder to save the dashboard in. +- **overwrite** – Set to true if you want to overwrite existing dashboard with newer version, same dashboard title in folder or same dashboard uid. - **message** - Set a commit message for the version history. **Example Response**: @@ -56,9 +72,12 @@ Content-Type: application/json; charset=UTF-8 Content-Length: 78 { - "slug": "production-overview", - "status": "success", - "version": 1 + "id": 1, + "uid": "cIBgcSjkk", + "url": "/d/cIBgcSjkk/production-overview", + "status": "success", + "version": 1, + "slug": "production-overview" //deprecated in Grafana v5.0 } ``` @@ -67,10 +86,18 @@ Status Codes: - **200** – Created - **400** – Errors (invalid json, missing or invalid fields, etc) - **401** – Unauthorized +- **403** – Access denied - **412** – Precondition failed -The **412** status code is used when a newer dashboard already exists (newer, its version is greater than the version that was sent). The -same status code is also used if another dashboard exists with the same title. The response body will look like this: +The **412** status code is used for explaing that you cannot create the dashboard and why. +There can be different reasons for this: + +- The dashboard has been changed by someone else, `status=version-mismatch` +- A dashboard with the same name in the folder already exists, `status=name-exists` +- A dashboard with the same uid already exists, `status=name-exists` +- The dashboard belongs to plugin ``, `status=plugin-dashboard` + + The response body will have the following properties: ```http HTTP/1.1 412 Precondition Failed @@ -83,18 +110,18 @@ Content-Length: 97 } ``` -In in case of title already exists the `status` property will be `name-exists`. +In case of title already exists the `status` property will be `name-exists`. -## Get dashboard +## Get dashboard by uid -`GET /api/dashboards/db/:slug` +`GET /api/dashboards/uid/:uid` -Will return the dashboard given the dashboard slug. Slug is the url friendly version of the dashboard title. +Will return the dashboard given the dashboard unique identifier (uid). **Example Request**: ```http -GET /api/dashboards/db/production-overview HTTP/1.1 +GET /api/dashboards/uid/cIBgcSjkk HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk @@ -107,12 +134,9 @@ HTTP/1.1 200 Content-Type: application/json { - "meta": { - "isStarred": false, - "slug": "production-overview" - }, "dashboard": { - "id": null, + "id": 1, + "uid": "cIBgcSjkk", "title": "Production Overview", "tags": [ "templated" ], "timezone": "browser", @@ -122,20 +146,32 @@ Content-Type: application/json ], "schemaVersion": 6, "version": 0 + }, + "meta": { + "isStarred": false, + "url": "/d/cIBgcSjkk/production-overview", + "slug": "production-overview" //deprecated in Grafana v5.0 } } ``` -## Delete dashboard +Status Codes: -`DELETE /api/dashboards/db/:slug` +- **200** – Found +- **401** – Unauthorized +- **403** – Access denied +- **404** – Not found -The above will delete the dashboard with the specified slug. The slug is the url friendly (unique) version of the dashboard title. +## Delete dashboard by uid + +`DELETE /api/dashboards/uid/:uid` + +Will delete the dashboard given the specified unique identifier (uid). **Example Request**: ```http -DELETE /api/dashboards/db/test HTTP/1.1 +DELETE /api/dashboards/uid/cIBgcSjkk HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk @@ -147,9 +183,16 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk HTTP/1.1 200 Content-Type: application/json -{"title": "Test"} +{"title": "Production Overview"} ``` +Status Codes: + +- **200** – Deleted +- **401** – Unauthorized +- **403** – Access denied +- **404** – Not found + ## Gets the home dashboard `GET /api/dashboards/home` @@ -172,15 +215,6 @@ HTTP/1.1 200 Content-Type: application/json { - "meta": { - "isHome":true, - "canSave":false, - "canEdit":false, - "canStar":false, - "slug":"", - "expires":"0001-01-01T00:00:00Z", - "created":"0001-01-01T00:00:00Z" - }, "dashboard": { "editable":false, "hideControls":true, @@ -206,13 +240,21 @@ Content-Type: application/json "timezone":"browser", "title":"Home", "version":5 + }, + "meta": { + "isHome":true, + "canSave":false, + "canEdit":false, + "canStar":false, + "url":"", + "expires":"0001-01-01T00:00:00Z", + "created":"0001-01-01T00:00:00Z" } } ``` ## Tags for Dashboard - `GET /api/dashboards/tags` Get all tags of dashboards @@ -244,21 +286,24 @@ Content-Type: application/json ] ``` -## Search Dashboards +## Dashboard Search +See [Folder/Dashboard Search API](/http_api/folder_dashboard_search). -`GET /api/search/` +## Deprecated resources +Please note that these resource have been deprecated and will be removed in a future release. -Query parameters: +### Get dashboard by slug +**Deprecated starting from Grafana v5.0. Please update to use the new *Get dashboard by uid* resource instead** -- **query** – Search Query -- **tag** – Tag to use -- **starred** – Flag indicating if only starred Dashboards should be returned -- **tagcloud** - Flag indicating if a tagcloud should be returned +`GET /api/dashboards/db/:slug` + +Will return the dashboard given the dashboard slug. Slug is the url friendly version of the dashboard title. +If there exists multiple dashboards with the same slug, one of them will be returned in the response. **Example Request**: ```http -GET /api/search?query=Production%20Overview&starred=true&tag=prod HTTP/1.1 +GET /api/dashboards/db/production-overview HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk @@ -270,14 +315,78 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk HTTP/1.1 200 Content-Type: application/json -[ - { - "id":1, - "title":"Production Overview", - "uri":"db/production-overview", - "type":"dash-db", - "tags":[prod], - "isStarred":true +{ + "dashboard": { + "id": 1, + "uid": "cIBgcSjkk", + "title": "Production Overview", + "tags": [ "templated" ], + "timezone": "browser", + "rows": [ + { + } + ], + "schemaVersion": 6, + "version": 0 + }, + "meta": { + "isStarred": false, + "url": "/d/cIBgcSjkk/production-overview", + "slug": "production-overview" // deprecated in Grafana v5.0 } -] +} +``` + +Status Codes: + +- **200** – Found +- **401** – Unauthorized +- **403** – Access denied +- **404** – Not found + +### Delete dashboard by slug +**Deprecated starting from Grafana v5.0. Please update to use the *Delete dashboard by uid* resource instead.** + +`DELETE /api/dashboards/db/:slug` + +Will delete the dashboard given the specified slug. Slug is the url friendly version of the dashboard title. + +**Example Request**: + +```http +DELETE /api/dashboards/db/test HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{"title": "Production Overview"} +``` + +Status Codes: + +- **200** – Deleted +- **401** – Unauthorized +- **403** – Access denied +- **404** – Not found +- **412** – Precondition failed + +The **412** status code is used when there exists multiple dashboards with the same slug. +The response body will look like this: + +```http +HTTP/1.1 412 Precondition Failed +Content-Type: application/json; charset=UTF-8 +Content-Length: 97 + +{ + "message": "Multiple dashboards with the same slug exists", + "status": "multiple-slugs-exists" +} ``` diff --git a/docs/sources/http_api/dashboard_permissions.md b/docs/sources/http_api/dashboard_permissions.md new file mode 100644 index 00000000000..26aa1550d7c --- /dev/null +++ b/docs/sources/http_api/dashboard_permissions.md @@ -0,0 +1,149 @@ ++++ +title = "Dashboard Permissions HTTP API " +description = "Grafana Dashboard Permissions HTTP API" +keywords = ["grafana", "http", "documentation", "api", "dashboard", "permission", "permissions", "acl"] +aliases = ["/http_api/dashboardpermissions/"] +type = "docs" +[menu.docs] +name = "Dashboard Permissions" +parent = "http_api" ++++ + +# Dashboard Permissions API + +This API can be used to update/get the permissions for a dashboard. + +Permissions with `dashboardId=-1` are the default permissions for users with the Viewer and Editor roles. Permissions can be set for a user, a team or a role (Viewer or Editor). Permissions cannot be set for Admins - they always have access to everything. + +The permission levels for the permission field: + +- 1 = View +- 2 = Edit +- 4 = Admin + +## Get permissions for a dashboard + +`GET /api/dashboards/id/:dashboardId/permissions` + +Gets all existing permissions for the dashboard with the given `dashboardId`. + +**Example request**: + +```http +GET /api/dashboards/id/1/permissions HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example Response** + +```http +HTTP/1.1 200 OK +Content-Type: application/json; charset=UTF-8 +Content-Length: 551 + +[ + { + "id": 1, + "dashboardId": -1, + "created": "2017-06-20T02:00:00+02:00", + "updated": "2017-06-20T02:00:00+02:00", + "userId": 0, + "userLogin": "", + "userEmail": "", + "teamId": 0, + "team": "", + "role": "Viewer", + "permission": 1, + "permissionName": "View", + "uid": "", + "title": "", + "slug": "", + "isFolder": false, + "url": "" + }, + { + "id": 2, + "dashboardId": -1, + "created": "2017-06-20T02:00:00+02:00", + "updated": "2017-06-20T02:00:00+02:00", + "userId": 0, + "userLogin": "", + "userEmail": "", + "teamId": 0, + "team": "", + "role": "Editor", + "permission": 2, + "permissionName": "Edit", + "uid": "", + "title": "", + "slug": "", + "isFolder": false, + "url": "" + } +] +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Access denied +- **404** - Dashboard not found + +## Update permissions for a dashboard + +`POST /api/dashboards/id/:dashboardId/permissions` + +Updates permissions for a dashboard. This operation will remove existing permissions if they're not included in the request. + +**Example request**: + +```http +POST /api/dashboards/id/1/permissions +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + + "items": [ + { + "role": "Viewer", + "permission": 1 + }, + { + "role": "Editor", + "permission": 2 + }, + { + "teamId": 1, + "permission": 1 + }, + { + "userId": 11, + "permission": 4 + } + ] +} +``` + +JSON body schema: + +- **items** - The permission items to add/update. Items that are omitted from the list will be removed. + +**Example response**: + +```http +HTTP/1.1 200 OK +Content-Type: application/json; charset=UTF-8 +Content-Length: 35 + +{"message":"Dashboard permissions updated"} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Access denied +- **404** - Dashboard not found diff --git a/docs/sources/http_api/folder.md b/docs/sources/http_api/folder.md new file mode 100644 index 00000000000..7ee1f737799 --- /dev/null +++ b/docs/sources/http_api/folder.md @@ -0,0 +1,317 @@ ++++ +title = "Folder HTTP API " +description = "Grafana Folder HTTP API" +keywords = ["grafana", "http", "documentation", "api", "folder"] +aliases = ["/http_api/folder/"] +type = "docs" +[menu.docs] +name = "Folder" +parent = "http_api" ++++ + +# Folder API + +## Identifier (id) vs unique identifier (uid) + +The identifier (id) of a folder is an auto-incrementing numeric value and is only unique per Grafana install. + +The unique identifier (uid) of a folder can be used for uniquely identify folders between multiple Grafana installs. It's automatically generated if not provided when creating a folder. The uid allows having consistent URL's for accessing folders and when syncing folders between multiple Grafana installs. This means that changing the title of a folder will not break any bookmarked links to that folder. + +The uid can have a maximum length of 40 characters. + + +## Get all folders + +`GET /api/folders` + +Returns all folders that the authenticated user has permission to view. + +**Example Request**: + +```http +GET /api/folders?limit=10 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +[ + { + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 + } +] +``` + +## Get folder by uid + +`GET /api/folders/:uid` + +Will return the folder given the folder uid. + +**Example Request**: + +```http +GET /api/folders/nErXDvCkzzh HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +``` + +Status Codes: + +- **200** – Found +- **401** – Unauthorized +- **403** – Access Denied +- **404** – Folder not found + +## Create folder + +`POST /api/folders` + +Creates a new folder. + +**Example Request**: + +```http +POST /api/folders HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +{ + "uid": "nErXDvCkzz", + "title": "Department ABC" +} +``` + +JSON Body schema: + +- **uid** – Optional [unique identifier](/http_api/folder/#identifier-id-vs-unique-identifier-uid). +- **title** – The title of the folder. + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +``` + +Status Codes: + +- **200** – Created +- **400** – Errors (invalid json, missing or invalid fields, etc) +- **401** – Unauthorized +- **403** – Access Denied + +## Update folder + +`PUT /api/folders/:uid` + +Updates an existing folder identified by uid. + +**Example Request**: + +```http +PUT /api/folders/nErXDvCkzz HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +{ + "title":"Department DEF", + "version": 1 +} +``` + +JSON Body schema: + +- **uid** – Provide another [unique identifier](/http_api/folder/#identifier-id-vs-unique-identifier-uid) than stored to change the unique identifier. +- **title** – The title of the folder. +- **version** – Provide the current version to be able to update the folder. Not needed if `overwrite=true`. +- **overwrite** – Set to true if you want to overwrite existing folder with newer version. + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet DEF", + "url": "/dashboards/f/nErXDvCkzz/department-def", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +``` + +Status Codes: + +- **200** – Updated +- **400** – Errors (invalid json, missing or invalid fields, etc) +- **401** – Unauthorized +- **403** – Access Denied +- **404** – Folder not found +- **412** – Precondition failed + +The **412** status code is used for explaing that you cannot update the folder and why. +There can be different reasons for this: + +- The folder has been changed by someone else, `status=version-mismatch` + + The response body will have the following properties: + +```http +HTTP/1.1 412 Precondition Failed +Content-Type: application/json; charset=UTF-8 +Content-Length: 97 + +{ + "message": "The folder has been changed by someone else", + "status": "version-mismatch" +} +``` + +## Delete folder + +`DELETE /api/folders/:uid` + +Deletes an existing folder identified by uid together with all dashboards stored in the folder, if any. This operation cannot be reverted. + +**Example Request**: + +```http +DELETE /api/folders/nErXDvCkzz HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "message":"Folder deleted" +} +``` + +Status Codes: + +- **200** – Deleted +- **401** – Unauthorized +- **403** – Access Denied +- **404** – Folder not found + +## Get folder by id + +`GET /api/folders/:id` + +Will return the folder identified by id. + +**Example Request**: + +```http +GET /api/folders/1 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +``` + +Status Codes: + +- **200** – Found +- **401** – Unauthorized +- **403** – Access Denied +- **404** – Folder not found diff --git a/docs/sources/http_api/folder_dashboard_search.md b/docs/sources/http_api/folder_dashboard_search.md new file mode 100644 index 00000000000..73b5dd90b87 --- /dev/null +++ b/docs/sources/http_api/folder_dashboard_search.md @@ -0,0 +1,98 @@ ++++ +title = "Folder/Dashboard Search HTTP API " +description = "Grafana Folder/Dashboard Search HTTP API" +keywords = ["grafana", "http", "documentation", "api", "search", "folder", "dashboard"] +aliases = ["/http_api/folder_dashboard_search/"] +type = "docs" +[menu.docs] +name = "Folder/dashboard search" +parent = "http_api" ++++ + +# Folder/Dashboard Search API + +## Search folders and dashboards + +`GET /api/search/` + +Query parameters: + +- **query** – Search Query +- **tag** – List of tags to search for +- **type** – Type to search for, `dash-folder` or `dash-db` +- **dashboardIds** – List of dashboard id's to search for +- **folderIds** – List of folder id's to search in for dashboards +- **starred** – Flag indicating if only starred Dashboards should be returned +- **limit** – Limit the number of returned results + +**Example request for retrieving folders and dashboards of the general folder**: + +```http +GET /api/search?folderIds=0&query=&starred=false HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example response for retrieving folders and dashboards of the general folder**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +[ + { + "id": 163, + "uid": "000000163", + "title": "Folder", + "url": "/dashboards/f/000000163/folder", + "type": "dash-folder", + "tags": [], + "isStarred": false, + "uri":"db/folder" // deprecated in Grafana v5.0 + }, + { + "id":1, + "uid": "cIBgcSjkk", + "title":"Production Overview", + "url": "/d/cIBgcSjkk/production-overview", + "type":"dash-db", + "tags":[prod], + "isStarred":true, + "uri":"db/production-overview" // deprecated in Grafana v5.0 + } +] +``` + +**Example request searching for dashboards**: + +```http +GET /api/search?query=Production%20Overview&starred=true&tag=prod HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example response searching for dashboards**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +[ + { + "id":1, + "uid": "cIBgcSjkk", + "title":"Production Overview", + "url": "/d/cIBgcSjkk/production-overview", + "type":"dash-db", + "tags":[prod], + "isStarred":true, + "folderId": 2, + "folderUid": "000000163", + "folderTitle": "Folder", + "folderUrl": "/dashboards/f/000000163/folder", + "uri":"db/production-overview" // deprecated in Grafana v5.0 + } +] +``` \ No newline at end of file diff --git a/docs/sources/http_api/folder_permissions.md b/docs/sources/http_api/folder_permissions.md new file mode 100644 index 00000000000..284ab70866f --- /dev/null +++ b/docs/sources/http_api/folder_permissions.md @@ -0,0 +1,149 @@ ++++ +title = "Folder Permissions HTTP API " +description = "Grafana Folder Permissions HTTP API" +keywords = ["grafana", "http", "documentation", "api", "folder", "permission", "permissions", "acl"] +aliases = ["/http_api/dashboardpermissions/"] +type = "docs" +[menu.docs] +name = "Folder Permissions" +parent = "http_api" ++++ + +# Folder Permissions API + +This API can be used to update/get the permissions for a folder. + +Permissions with `folderId=-1` are the default permissions for users with the Viewer and Editor roles. Permissions can be set for a user, a team or a role (Viewer or Editor). Permissions cannot be set for Admins - they always have access to everything. + +The permission levels for the permission field: + +- 1 = View +- 2 = Edit +- 4 = Admin + +## Get permissions for a folder + +`GET /api/folders/:uid/permissions` + +Gets all existing permissions for the folder with the given `uid`. + +**Example request**: + +```http +GET /api/folders/nErXDvCkzz/permissions HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example Response** + +```http +HTTP/1.1 200 OK +Content-Type: application/json; charset=UTF-8 +Content-Length: 551 + +[ + { + "id": 1, + "folderId": -1, + "created": "2017-06-20T02:00:00+02:00", + "updated": "2017-06-20T02:00:00+02:00", + "userId": 0, + "userLogin": "", + "userEmail": "", + "teamId": 0, + "team": "", + "role": "Viewer", + "permission": 1, + "permissionName": "View", + "uid": "nErXDvCkzz", + "title": "", + "slug": "", + "isFolder": false, + "url": "" + }, + { + "id": 2, + "dashboardId": -1, + "created": "2017-06-20T02:00:00+02:00", + "updated": "2017-06-20T02:00:00+02:00", + "userId": 0, + "userLogin": "", + "userEmail": "", + "teamId": 0, + "team": "", + "role": "Editor", + "permission": 2, + "permissionName": "Edit", + "uid": "", + "title": "", + "slug": "", + "isFolder": false, + "url": "" + } +] +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Access denied +- **404** - Folder not found + +## Update permissions for a folder + +`POST /api/folders/:uid/permissions` + +Updates permissions for a folder. This operation will remove existing permissions if they're not included in the request. + +**Example request**: + +```http +POST /api/folders/nErXDvCkzz/permissions +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + + "items": [ + { + "role": "Viewer", + "permission": 1 + }, + { + "role": "Editor", + "permission": 2 + }, + { + "teamId": 1, + "permission": 1 + }, + { + "userId": 11, + "permission": 4 + } + ] +} +``` + +JSON body schema: + +- **items** - The permission items to add/update. Items that are omitted from the list will be removed. + +**Example response**: + +```http +HTTP/1.1 200 OK +Content-Type: application/json; charset=UTF-8 +Content-Length: 35 + +{"message":"Folder permissions updated"} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Access denied +- **404** - Dashboard not found diff --git a/docs/sources/http_api/index.md b/docs/sources/http_api/index.md index 9c5d0e7d49a..81b3c907c7a 100644 --- a/docs/sources/http_api/index.md +++ b/docs/sources/http_api/index.md @@ -18,12 +18,19 @@ dashboards, creating users and updating data sources. ## Supported HTTP APIs: -* [Authentication API]({{< relref "auth.md" >}}) -* [Dashboard API]({{< relref "dashboard.md" >}}) -* [Data Source API]({{< relref "data_source.md" >}}) -* [Organisation API]({{< relref "org.md" >}}) -* [User API]({{< relref "user.md" >}}) -* [Admin API]({{< relref "admin.md" >}}) -* [Snapshot API]({{< relref "snapshot.md" >}}) -* [Preferences API]({{< relref "preferences.md" >}}) -* [Other API]({{< relref "other.md" >}}) +* [Authentication API]({{< relref "/http_api/auth.md" >}}) +* [Dashboard API]({{< relref "/http_api/dashboard.md" >}}) +* [Dashboard Versions API]({{< relref "http_api/dashboard_versions.md" >}}) +* [Dashboard Permissions API]({{< relref "http_api/dashboard_permissions.md" >}}) +* [Folder API]({{< relref "/http_api/folder.md" >}}) +* [Folder Permissions API]({{< relref "http_api/folder_permissions.md" >}}) +* [Folder/dashboard search API]({{< relref "/http_api/folder_dashboard_search.md" >}}) +* [Data Source API]({{< relref "http_api/data_source.md" >}}) +* [Organisation API]({{< relref "http_api/org.md" >}}) +* [Snapshot API]({{< relref "http_api/snapshot.md" >}}) +* [Annotations API]({{< relref "http_api/annotations.md" >}}) +* [Alerting API]({{< relref "http_api/alerting.md" >}}) +* [User API]({{< relref "http_api/user.md" >}}) +* [Admin API]({{< relref "http_api/admin.md" >}}) +* [Preferences API]({{< relref "http_api/preferences.md" >}}) +* [Other API]({{< relref "http_api/other.md" >}}) diff --git a/docs/sources/http_api/team.md b/docs/sources/http_api/team.md new file mode 100644 index 00000000000..94ea4108481 --- /dev/null +++ b/docs/sources/http_api/team.md @@ -0,0 +1,316 @@ ++++ +title = "Team HTTP API " +description = "Grafana Team HTTP API" +keywords = ["grafana", "http", "documentation", "api", "team", "teams", "group"] +aliases = ["/http_api/team/"] +type = "docs" +[menu.docs] +name = "Teams" +parent = "http_api" ++++ + +# Team API + +This API can be used to create/update/delete Teams and to add/remove users to Teams. All actions require that the user has the Admin role for the organization. + +## Team Search With Paging + +`GET /api/teams/search?perpage=50&page=1&query=mytea` + +or + +`GET /api/teams/search?name=myteam` + +```http +GET /api/teams/search?perpage=10&page=1&query=myteam HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= +``` + +### Using the query parameter + +Default value for the `perpage` parameter is `1000` and for the `page` parameter is `1`. + +The `totalCount` field in the response can be used for pagination of the teams list E.g. if `totalCount` is equal to 100 teams and the `perpage` parameter is set to 10 then there are 10 pages of teams. + +The `query` parameter is optional and it will return results where the query value is contained in the `name` field. Query values with spaces need to be url encoded e.g. `query=my%20team`. + +### Using the name parameter + +The `name` parameter returns a single team if the parameter matches the `name` field. + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + + "totalCount": 1, + "teams": [ + { + "id": 1, + "orgId": 1, + "name": "MyTestTeam", + "email": "", + "avatarUrl": "\/avatar\/3f49c15916554246daa714b9bd0ee398", + "memberCount": 1 + } + ], + "page": 1, + "perPage": 1000 +} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied +- **404** - Team not found (if searching by name) + +## Get Team By Id + +`GET /api/teams/:id` + +**Example Request**: + +```http +GET /api/teams/1 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "id": 1, + "orgId": 1, + "name": "MyTestTeam", + "email": "", + "created": "2017-12-15T10:40:45+01:00", + "updated": "2017-12-15T10:40:45+01:00" +} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied +- **404** - Team not found + +## Add Team + +The Team `name` needs to be unique. `name` is required and `email` is optional. + +`POST /api/teams` + +**Example Request**: + +```http +POST /api/teams HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= + +{ + "name": "MyTestTeam", + "email": "email@test.com" +} +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{"message":"Team created","teamId":2} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied +- **409** - Team name is taken + +## Update Team + +There are two fields that can be updated for a team: `name` and `email`. + +`PUT /api/teams/:id` + +**Example Request**: + +```http +PUT /api/teams/2 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= + +{ + "name": "MyTestTeam", + "email": "email@test.com" +} +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{"message":"Team updated"} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied +- **404** - Team not found +- **409** - Team name is taken + +## Delete Team By Id + +`DELETE /api/teams/:id` + +**Example Request**: + +```http +DELETE /api/teams/2 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{"message":"Team deleted"} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied +- **404** - Failed to delete Team. ID not found + +## Get Team Members + +`GET /api/teams/:teamId/members` + +**Example Request**: + +```http +GET /api/teams/1/members HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +[ + { + "orgId": 1, + "teamId": 1, + "userId": 3, + "email": "user1@email.com", + "login": "user1", + "avatarUrl": "\/avatar\/1b3c32f6386b0185c40d359cdc733a79" + }, + { + "orgId": 1, + "teamId": 1, + "userId": 2, + "email": "user2@email.com", + "login": "user2", + "avatarUrl": "\/avatar\/cad3c68da76e45d10269e8ef02f8e73e" + } +] +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied + +## Add Team Member + +`POST /api/teams/:teamId/members` + +**Example Request**: + +```http +POST /api/teams/1/members HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= + +{ + "userId": 2 +} +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{"message":"Member added to Team"} +``` + +Status Codes: + +- **200** - Ok +- **400** - User is already added to this team +- **401** - Unauthorized +- **403** - Permission denied +- **404** - Team not found + +## Remove Member From Team + +`DELETE /api/teams/:teamId/members/:userId` + +**Example Request**: + +```http +DELETE /api/teams/2/members/3 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Basic YWRtaW46YWRtaW4= +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{"message":"Team Member removed"} +``` + +Status Codes: + +- **200** - Ok +- **401** - Unauthorized +- **403** - Permission denied +- **404** - Team not found/Team member not found diff --git a/docs/sources/http_api/user.md b/docs/sources/http_api/user.md index ba8afd4db22..134c1842851 100644 --- a/docs/sources/http_api/user.md +++ b/docs/sources/http_api/user.md @@ -156,7 +156,7 @@ HTTP/1.1 200 Content-Type: application/json { - "email": "user@mygraf.com" + "email": "user@mygraf.com", "name": "admin", "login": "admin", "theme": "light", @@ -409,4 +409,4 @@ HTTP/1.1 200 Content-Type: application/json {"message":"Dashboard unstarred"} -``` \ No newline at end of file +``` diff --git a/docs/sources/index.md b/docs/sources/index.md index 7a431e29692..3c59b9baba0 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -1,53 +1,107 @@ +++ -title = "Docs Home" -description = "Install guide for Grafana" +title = "Grafana documentation" +description = "Guides, Installation & Feature Documentation" keywords = ["grafana", "installation", "documentation"] type = "docs" aliases = ["v1.1", "guides/reference/admin"] -[menu.docs] -name = "Welcome to the Docs" -identifier = "root" -weight = -1 +++ -# Welcome to the Grafana Documentation +# Grafana Documentation -Grafana is an open source metric analytics & visualization suite. It is most commonly used for -visualizing time series data for infrastructure and application analytics but many use it in -other domains including industrial sensors, home automation, weather, and process control. +

Installing Grafana

+ -## Installing Grafana -- [Installing on Debian / Ubuntu](installation/debian) -- [Installing on RPM-based Linux (CentOS, Fedora, OpenSuse, RedHat)](installation/rpm) -- [Installing on Mac OS X](installation/mac) -- [Installing on Windows](installation/windows) -- [Installing on Docker](installation/docker) -- [Installing using Provisioning (Chef, Puppet, Salt, Ansible, etc)](installation/provisioning) -- [Nightly Builds](https://grafana.com/grafana/download) +

Guides

-For other platforms Read the [build from source]({{< relref "project/building_from_source.md" >}}) -instructions for more information. + -## Configuring Grafana - -The back-end web server has a number of configuration options. Go the -[Configuration]({{< relref "installation/configuration.md" >}}) page for details on all -those options. - - -## Getting Started - -- [Getting Started]({{< relref "guides/getting_started.md" >}}) -- [Basic Concepts]({{< relref "guides/basic_concepts.md" >}}) -- [Screencasts]({{< relref "tutorials/screencasts.md" >}}) - -## Data Source Guides - -- [Graphite]({{< relref "features/datasources/graphite.md" >}}) -- [Elasticsearch]({{< relref "features/datasources/elasticsearch.md" >}}) -- [InfluxDB]({{< relref "features/datasources/influxdb.md" >}}) -- [Prometheus]({{< relref "features/datasources/prometheus.md" >}}) -- [OpenTSDB]({{< relref "features/datasources/opentsdb.md" >}}) -- [MySQL]({{< relref "features/datasources/mysql.md" >}}) -- [Postgres]({{< relref "features/datasources/postgres.md" >}}) -- [Cloudwatch]({{< relref "features/datasources/cloudwatch.md" >}}) +

Data Source Guides

+ diff --git a/docs/sources/installation/behind_proxy.md b/docs/sources/installation/behind_proxy.md index 3d89d8b3c2c..f1a00a5b1cc 100644 --- a/docs/sources/installation/behind_proxy.md +++ b/docs/sources/installation/behind_proxy.md @@ -69,4 +69,57 @@ server { } ``` +#### HAProxy configuration with sub path +```bash +frontend http-in + bind *:80 + use_backend grafana_backend if { path /grafana } or { path_beg /grafana/ } +backend grafana_backend + # Requires haproxy >= 1.6 + http-request set-path %[path,regsub(^/grafana/?,/)] + + # Works for haproxy < 1.6 + # reqrep ^([^\ ]*\ /)grafana[/]?(.*) \1\2 + + server grafana localhost:3000 +``` + +### IIS URL Rewrite Rule (Windows) with Subpath + +IIS requires that the URL Rewrite module is installed. + +Given: + +- subpath `grafana` +- Grafana installed on `http://localhost:3000` +- server config: + + ```bash + [server] + domain = localhost:8080 + root_url = %(protocol)s://%(domain)s:/grafana + ``` + +Create an Inbound Rule for the parent website (localhost:8080 in this example) in IIS Manager with the following settings: + +- pattern: `grafana(/)?(.*)` +- check the `Ignore case` checkbox +- rewrite url set to `http://localhost:3000/{R:2}` +- check the `Append query string` checkbox +- check the `Stop processing of subsequent rules` checkbox + +This is the rewrite rule that is generated in the `web.config`: + +```xml + + + + + + + + +``` + +See the [tutorial on IIS Url Rewrites](http://docs.grafana.org/tutorials/iis/) for more in-depth instructions. diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 1333c8c191d..66072a98f84 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -205,7 +205,7 @@ The database user (not applicable for `sqlite3`). ### password -The database user's password (not applicable for `sqlite3`). If the password contains `#` or `;` you have to wrap it with trippel quotes. Ex `"""#password;"""` +The database user's password (not applicable for `sqlite3`). If the password contains `#` or `;` you have to wrap it with triple quotes. Ex `"""#password;"""` ### ssl_mode @@ -214,19 +214,19 @@ For MySQL, use either `true`, `false`, or `skip-verify`. ### ca_cert_path -(MySQL only) The path to the CA certificate to use. On many linux systems, certs can be found in `/etc/ssl/certs`. +The path to the CA certificate to use. On many linux systems, certs can be found in `/etc/ssl/certs`. ### client_key_path -(MySQL only) The path to the client key. Only if server requires client authentication. +The path to the client key. Only if server requires client authentication. ### client_cert_path -(MySQL only) The path to the client cert. Only if server requires client authentication. +The path to the client cert. Only if server requires client authentication. ### server_cert_name -(MySQL only) The common name field of the certificate used by the `mysql` server. Not necessary if `ssl_mode` is set to `skip-verify`. +The common name field of the certificate used by the `mysql` or `postgres` server. Not necessary if `ssl_mode` is set to `skip-verify`. ### max_idle_conn The maximum number of connections in the idle connection pool. @@ -292,10 +292,14 @@ organization to be created for that new user. The role new users will be assigned for the main organization (if the above setting is set to true). Defaults to `Viewer`, other valid -options are `Admin` and `Editor` and `Read Only Editor`. e.g. : +options are `Admin` and `Editor`. e.g. : -`auto_assign_org_role = Read Only Editor` +`auto_assign_org_role = Viewer` +### viewers_can_edit + +Viewers can edit/inspect dashboard settings in the browser. But not save the dashboard. +Defaults to `false`.
@@ -350,7 +354,7 @@ enabled = true allow_sign_up = true client_id = YOUR_GITHUB_APP_CLIENT_ID client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email +scopes = user:email,read:org auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token api_url = https://api.github.com/user @@ -383,6 +387,7 @@ scopes = user:email,read:org team_ids = 150,300 auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user allow_sign_up = true ``` @@ -401,6 +406,7 @@ client_secret = YOUR_GITHUB_APP_CLIENT_SECRET scopes = user:email,read:org auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user allow_sign_up = true # space-delimited organization names allowed_organizations = github google @@ -492,7 +498,7 @@ name = BitBucket enabled = true allow_sign_up = true client_id = -client_secret = +client_secret = scopes = account email auth_url = https://bitbucket.org/site/oauth2/authorize token_url = https://bitbucket.org/site/oauth2/access_token @@ -501,6 +507,105 @@ team_ids = allowed_organizations = ``` +### Set up oauth2 with OneLogin + +1. Create a new Custom Connector with the following settings: + - Name: Grafana + - Sign On Method: OpenID Connect + - Redirect URI: `https:///login/generic_oauth` + - Signing Algorithm: RS256 + - Login URL: `https:///login/generic_oauth` + + then: +2. Add an App to the Grafana Connector: + - Display Name: Grafana + + then: +3. Under the SSO tab on the Grafana App details page you'll find the Client ID and Client Secret. + + Your OneLogin Domain will match the url you use to access OneLogin. + + Configure Grafana as follows: + + ```bash + [auth.generic_oauth] + name = OneLogin + enabled = true + allow_sign_up = true + client_id = + client_secret = + scopes = openid email name + auth_url = https://.onelogin.com/oidc/auth + token_url = https://.onelogin.com/oidc/token + api_url = https://.onelogin.com/oidc/me + team_ids = + allowed_organizations = + ``` + +### Set up oauth2 with Auth0 + +1. Create a new Client in Auth0 + - Name: Grafana + - Type: Regular Web Application + +2. Go to the Settings tab and set: + - Allowed Callback URLs: `https:///login/generic_oauth` + +3. Click Save Changes, then use the values at the top of the page to configure Grafana: + + ```bash + [auth.generic_oauth] + enabled = true + allow_sign_up = true + team_ids = + allowed_organizations = + name = Auth0 + client_id = + client_secret = + scopes = openid profile email + auth_url = https:///authorize + token_url = https:///oauth/token + api_url = https:///userinfo + ``` + +### Set up oauth2 with Azure Active Directory + +1. Log in to portal.azure.com and click "Azure Active Directory" in the side menu, then click the "Properties" sub-menu item. + +2. Copy the "Directory ID", this is needed for setting URLs later + +3. Click "App Registrations" and add a new application registration: + - Name: Grafana + - Application type: Web app / API + - Sign-on URL: `https:///login/generic_oauth` + +4. Click the name of the new application to open the application details page. + +5. Note down the "Application ID", this will be the OAuth client id. + +6. Click "Settings", then click "Keys" and add a new entry under Passwords + - Key Description: Grafana OAuth + - Duration: Never Expires + +7. Click Save then copy the key value, this will be the OAuth client secret. + +8. Configure Grafana as follows: + + ```bash + [auth.generic_oauth] + name = Azure AD + enabled = true + allow_sign_up = true + client_id = + client_secret = + scopes = openid email name + auth_url = https://login.microsoftonline.com//oauth2/authorize + token_url = https://login.microsoftonline.com//oauth2/token + api_url = + team_ids = + allowed_organizations = + ``` +
## [auth.basic] @@ -568,31 +673,6 @@ session provider you have configured. - **memcache:** ex: 127.0.0.1:11211 - **redis:** ex: `addr=127.0.0.1:6379,pool_size=100,prefix=grafana` -If you use MySQL or Postgres as the session store you need to create the -session table manually. - -Mysql Example: - -```bash -CREATE TABLE `session` ( - `key` CHAR(16) NOT NULL, - `data` BLOB, - `expiry` INT(11) UNSIGNED NOT NULL, - PRIMARY KEY (`key`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; -``` - -Postgres Example: - -```bash -CREATE TABLE session ( - key CHAR(16) NOT NULL, - data BYTEA, - expiry INTEGER NOT NULL, - PRIMARY KEY (key) -); -``` - Postgres valid `sslmode` are `disable`, `require`, `verify-ca`, and `verify-full` (default). ### cookie_name @@ -717,17 +797,14 @@ Set root url to a Grafana instance where you want to publish external snapshots ### external_snapshot_name Set name for external snapshot button. Defaults to `Publish to snapshot.raintank.io` -### remove expired snapshot +### snapshot_remove_expired Enabled to automatically remove expired snapshots -### remove snapshots after 90 days -Time to live for snapshots. - ## [external_image_storage] These options control how images should be made public so they can be shared on services like slack. ### provider -You can choose between (s3, webdav, gcs). If left empty Grafana will ignore the upload action. +You can choose between (s3, webdav, gcs, azure_blob, local). If left empty Grafana will ignore the upload action. ## [external_image_storage.s3] @@ -782,6 +859,17 @@ Bucket Name on Google Cloud Storage. ### path Optional extra path inside bucket +## [external_image_storage.azure_blob] + +### account_name +Storage account name + +### account_key +Storage account key + +### container_name +Container name where to store "Blob" images with random names. Creating the blob container beforehand is required. Only public containers are supported. + ## [alerting] ### enabled @@ -789,6 +877,4 @@ Defaults to true. Set to false to disable alerting engine and hide Alerting from ### execute_alerts -### execute_alerts = true - Makes it possible to turn off alert rule execution. diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index d832ea7a8ed..515a598d3cd 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -15,9 +15,7 @@ weight = 1 Description | Download ------------ | ------------- -Stable for Debian-based Linux | [grafana_4.6.2_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.2_amd64.deb) - - +Stable for Debian-based Linux | [grafana_5.0.0_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0_amd64.deb) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. @@ -26,21 +24,11 @@ installation. ```bash -wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_4.6.2_amd64.deb +wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.0_amd64.deb sudo apt-get install -y adduser libfontconfig -sudo dpkg -i grafana_4.6.2_amd64.deb +sudo dpkg -i grafana_5.0.0_amd64.deb ``` - - ## APT Repository Add the following line to your `/etc/apt/sources.list` file. diff --git a/docs/sources/installation/index.md b/docs/sources/installation/index.md index 47d52817b64..a86f426dc13 100644 --- a/docs/sources/installation/index.md +++ b/docs/sources/installation/index.md @@ -7,6 +7,7 @@ aliases = ["installation/installation/", "v2.1/installation/install/"] [menu.docs] name = "Installation" identifier = "installation" +weight = 1 +++ ## Installing Grafana diff --git a/docs/sources/installation/ldap.md b/docs/sources/installation/ldap.md index 8f6be6e1d8c..85501e51d85 100644 --- a/docs/sources/installation/ldap.md +++ b/docs/sources/installation/ldap.md @@ -43,7 +43,7 @@ ssl_skip_verify = false # Search user bind dn bind_dn = "cn=admin,dc=grafana,dc=org" # Search user bind password -# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" bind_password = 'grafana' # User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index fa2bd71ed07..4ed59093903 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -15,9 +15,8 @@ weight = 2 Description | Download ------------ | ------------- -Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [4.6.2 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.2-1.x86_64.rpm) +Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.0 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-1.x86_64.rpm) - Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. @@ -27,7 +26,7 @@ installation. You can install Grafana using Yum directly. ```bash -$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.2-1.x86_64.rpm +$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-1.x86_64.rpm ``` Or install manually using `rpm`. @@ -35,15 +34,15 @@ Or install manually using `rpm`. #### On CentOS / Fedora / Redhat: ```bash -$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.2-1.x86_64.rpm +$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-1.x86_64.rpm $ sudo yum install initscripts fontconfig -$ sudo rpm -Uvh grafana-4.6.2-1.x86_64.rpm +$ sudo rpm -Uvh grafana-5.0.0-1.x86_64.rpm ``` #### On OpenSuse: ```bash -$ sudo rpm -i --nodeps grafana-4.6.2-1.x86_64.rpm +$ sudo rpm -i --nodeps grafana-5.0.0-1.x86_64.rpm ``` ## Install via YUM Repository diff --git a/docs/sources/installation/upgrading.md b/docs/sources/installation/upgrading.md index 6a4b4e8f047..5b00fd92924 100644 --- a/docs/sources/installation/upgrading.md +++ b/docs/sources/installation/upgrading.md @@ -101,3 +101,11 @@ as this will make upgrades easier without risking losing your config changes. ## Upgrading from 2.x We are not aware of any issues upgrading directly from 2.x to 4.x but to be on the safe side go via 3.x => 4.x. + +## Upgrading to v5.0 + +The dashboard grid layout engine has changed. All dashboards will be automatically upgraded to new +positioning system when you load them in v5. Dashboards saved in v5 will not work in older versions of Grafana. Some +external panel plugins might need to be updated to work properly. + +For more details on the new panel positioning system, [click here]({{< relref "reference/dashboard.md#panel-size-position" >}}) diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 9cfd689fb43..d4c233df996 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -13,7 +13,7 @@ weight = 3 Description | Download ------------ | ------------- -Latest stable package for Windows | [grafana.4.6.2.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.6.2.windows-x64.zip) +Latest stable package for Windows | [grafana-5.0.0.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0.windows-x64.zip) Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing installation. @@ -30,9 +30,9 @@ on windows. Edit `custom.ini` and uncomment the `http_port` configuration option (`;` is the comment character in ini files) and change it to something like `8080` or similar. That port should not require extra Windows privileges. -Start Grafana by executing `grafana-server.exe`, preferably from the +Start Grafana by executing `grafana-server.exe`, located in the `bin` directory, preferably from the command line. If you want to run Grafana as windows service, download -[NSSM](https://nssm.cc/). It is very easy add Grafana as a Windows +[NSSM](https://nssm.cc/). It is very easy to add Grafana as a Windows service using that tool. Read more about the [configuration options]({{< relref "configuration.md" >}}). @@ -42,7 +42,3 @@ Read more about the [configuration options]({{< relref "configuration.md" >}}). The Grafana backend includes Sqlite3 which requires GCC to compile. So in order to compile Grafana on Windows you need to install GCC. We recommend [TDM-GCC](http://tdm-gcc.tdragon.net/download). - -Copy `conf/sample.ini` to a file named `conf/custom.ini` and change the -web server port to something like 8080. The default Grafana port, 3000, -requires special privileges on Windows. diff --git a/docs/sources/plugins/developing/datasources.md b/docs/sources/plugins/developing/datasources.md index 0149f06e1aa..09a005ba714 100644 --- a/docs/sources/plugins/developing/datasources.md +++ b/docs/sources/plugins/developing/datasources.md @@ -84,15 +84,15 @@ An array of: { "target":"upper_75", "datapoints":[ - [622,1450754160000], - [365,1450754220000] + [622, 1450754160000], + [365, 1450754220000] ] }, { "target":"upper_90", "datapoints":[ - [861,1450754160000], - [767,1450754220000] + [861, 1450754160000], + [767, 1450754220000] ] } ] diff --git a/docs/sources/project/building_from_source.md b/docs/sources/project/building_from_source.md index dba04164d00..13d71e8dcf4 100644 --- a/docs/sources/project/building_from_source.md +++ b/docs/sources/project/building_from_source.md @@ -57,7 +57,7 @@ For this you need nodejs (v.6+). ```bash npm install -g yarn yarn install --pure-lockfile -npm run build +npm run watch ``` ## Running Grafana Locally diff --git a/docs/sources/reference/admin.md b/docs/sources/reference/admin.md deleted file mode 100644 index a6863b4ea71..00000000000 --- a/docs/sources/reference/admin.md +++ /dev/null @@ -1,42 +0,0 @@ -+++ -title = "Admin Roles" -description = "Users & Organization permission and administration" -keywords = ["grafana", "configuration", "documentation", "admin", "users", "permissions"] -type = "docs" -[menu.docs] -name = "Admin Roles" -parent = "admin" -weight = 3 -+++ - -# Administration - -Grafana has two levels of administrators: - -* Organizational administrators: These admins can manage users within specific organizations in a particular Grafana installation -* Grafana administrators: These super admins can manage users across all organizations in a Grafana installation. They can also change and access system-wide settings. - -## Organizational Administrators - -As an Organizational administrator, you can add `Data Sources`, add Users to your Organization and -modify Organization details and options. - -> *Note*: If Grafana is configured with `users.allow_org_create = true`, any User of any Organization will be able to -> start their own Organization and become the administrator of that Organization. - - -## Grafana Administrators - - -As a Grafana Administrator, you have complete access to any Organization or User in that instance of Grafana. -When performing actions as a Grafana admin, the sidebar will change it's appearance as below to indicate you are performing global server administration. - -From the Grafana Server Admin page, you can access the System Info page which summarizes all of the backend configuration settings of the Grafana server. - -## Why would I have multiple Organizations? - -Organizations in Grafana are best suited for a **multi-tenant deployment**. In a multi-tenant deployment, -Organizations can be used to provide a full Grafana experience to different sets of users from a single Grafana instance, -at the convenience of the Grafana Administrator. - -In most cases, a Grafana installation will only have **one** Organization. Since dashboards, data sources and other configuration items are not shared between organizations, there's no need to create multiple Organizations if you want all your users to have access to the same set of dashboards and data. diff --git a/docs/sources/reference/annotations.md b/docs/sources/reference/annotations.md index de118f37d46..bfc104ef522 100644 --- a/docs/sources/reference/annotations.md +++ b/docs/sources/reference/annotations.md @@ -54,7 +54,8 @@ Annotation events are fetched via annotation queries. To add a new annotation qu open the dashboard settings menu, then select `Annotations`. This will open the dashboard annotations settings view. To create a new annotation query hit the `New` button. -![](/img/docs/annotations/new_query.png) + +{{< docs-imagebox img="/img/docs/v50/annotation_new_query.png" max-width="600px" >}} Specify a name for the annotation query. This name is given to the toggle (checkbox) that will allow you to enable/disable showing annotation events from this query. For example you might have two diff --git a/docs/sources/reference/dashboard.md b/docs/sources/reference/dashboard.md index d2da621a5a3..dbc3ed8635c 100644 --- a/docs/sources/reference/dashboard.md +++ b/docs/sources/reference/dashboard.md @@ -10,7 +10,7 @@ weight = 100 # Dashboard JSON -A dashboard in Grafana is represented by a JSON object, which stores metadata of its dashboard. Dashboard metadata includes dashboard properties, metadata from rows, panels, template variables, panel queries, etc. +A dashboard in Grafana is represented by a JSON object, which stores metadata of its dashboard. Dashboard metadata includes dashboard properties, metadata from panels, template variables, panel queries, etc. To view the JSON of a dashboard, follow the steps mentioned below: @@ -27,6 +27,7 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized ```json { "id": null, + "uid": "cLV5GDCkz", "title": "New dashboard", "tags": [], "style": "dark", @@ -34,7 +35,7 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized "editable": true, "hideControls": false, "graphTooltip": 1, - "rows": [], + "panels": [], "time": { "from": "now-6h", "to": "now" @@ -49,7 +50,7 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized "annotations": { "list": [] }, - "schemaVersion": 7, + "schemaVersion": 16, "version": 0, "links": [] } @@ -58,224 +59,56 @@ Each field in the dashboard JSON is explained below with its usage: | Name | Usage | | ---- | ----- | -| **id** | unique dashboard id, an integer | +| **id** | unique numeric identifier for the dashboard. (generated by the db) | +| **uid** | unique dashboard identifier that can be generated by anyone. string (8-40) | | **title** | current title of dashboard | | **tags** | tags associated with dashboard, an array of strings | | **style** | theme of dashboard, i.e. `dark` or `light` | | **timezone** | timezone of dashboard, i.e. `utc` or `browser` | | **editable** | whether a dashboard is editable or not | -| **hideControls** | whether row controls on the left in green are hidden or not | | **graphTooltip** | 0 for no shared crosshair or tooltip (default), 1 for shared crosshair, 2 for shared crosshair AND shared tooltip | -| **rows** | row metadata, see [rows section](#rows) for details | | **time** | time range for dashboard, i.e. last 6 hours, last 7 days, etc | | **timepicker** | timepicker metadata, see [timepicker section](#timepicker) for details | | **templating** | templating metadata, see [templating section](#templating) for details | | **annotations** | annotations metadata, see [annotations section](#annotations) for details | -| **schemaVersion** | TODO | -| **version** | TODO | -| **links** | TODO | +| **schemaVersion** | version of the JSON schema (integer), incremented each time a Grafana update brings changes to the said schema | +| **version** | version of the dashboard (integer), incremented each time the dashboard is updated | +| **panels** | panels array, see below for detail. | -### rows +## Panels -`rows` field consists of an array of JSON object representing each row in a dashboard, such as shown below: - -```json - "rows": [ - { - "collapse": false, - "editable": true, - "height": "200px", - "panels": [], - "title": "New row" - }, - { - "collapse": true, - "editable": true, - "height": "300px", - "panels": [], - "title": "New row" - } - ] -``` - -Usage of the fields is explained below: - -| Name | Usage | -| ---- | ----- | -| **collapse** | whether row is collapsed or not | -| **editable** | whether a row is editable or not | -| **height** | height of the row in pixels | -| **panels** | panels metadata, see [panels section](#panels) for details | -| **title** | title of row | - -#### panels - -Panels are the building blocks a dashboard. It consists of datasource queries, type of graphs, aliases, etc. Panel JSON consists of an array of JSON objects, each representing a different panel in a row. Most of the fields are common for all panels but some fields depends on the panel type. Following is an example of panel JSON representing a `graph` panel type: +Panels are the building blocks a dashboard. It consists of datasource queries, type of graphs, aliases, etc. Panel JSON consists of an array of JSON objects, each representing a different panel. Most of the fields are common for all panels but some fields depends on the panel type. Following is an example of panel JSON of a text panel. ```json "panels": [ - { - "aliasColors": {}, - "bars": false, - "datasource": null, - "editable": true, - "error": false, - "fill": 0, - "grid": { - "leftLogBase": 1, - "leftMax": null, - "leftMin": null, - "rightLogBase": 1, - "rightMax": null, - "rightMin": null, - "threshold1": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2": null, - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "id": 1, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "aggregator": "max", - "alias": "$tag_instance_id", - "currentTagKey": "", - "currentTagValue": "", - "downsampleAggregator": "avg", - "downsampleInterval": "", - "errors": {}, - "metric": "memory.percent-used", - "refId": "A", - "shouldComputeRate": false, - "tags": { - "app": "$app", - "env": "stage", - "instance_id": "*" - } - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Memory Utilization", - "tooltip": { - "shared": true, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "percent", - "short" - ] - }, - { - "aliasColors": {}, - "bars": false, - "datasource": null, - "editable": true, - "error": false, - "fill": 0, - "grid": { - "leftLogBase": 1, - "leftMax": null, - "leftMin": null, - "rightLogBase": 1, - "rightMax": null, - "rightMin": null, - "threshold1": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2": null, - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 4, - "stack": false, - "steppedLine": false, - "targets": [ - { - "aggregator": "avg", - "alias": "$tag_instance_id", - "currentTagKey": "", - "currentTagValue": "", - "downsampleAggregator": "avg", - "downsampleInterval": "", - "errors": {}, - "metric": "memory.percent-cached", - "refId": "A", - "shouldComputeRate": false, - "tags": { - "app": "$app", - "env": "prod", - "instance_id": "*" - } - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Memory Cached", - "tooltip": { - "shared": true, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "short", - "short" - ] - }, + { + "type": "text", + "title": "Panel Title", + "gridPos": { + "x": 0, + "y": 0, + "w": 12, + "h": 9 + }, + "id": 4, + "mode": "markdown", + "content": "# title" + } ``` -Usage of each field is explained below: +### Panel size & position -| Name | Usage | -| ---- | ----- | -| TODO | TODO | +The gridPos property describes the panel size and position in grid coordinates. + +- `w` 1-24 (the width of the dashboard is divided into 24 columns) +- `h` In grid height units, each represents 30 pixels. +- `x` The x position, in same unit as `w`. +- `y` The y position, in same unit as `h`. + +The grid has a negative gravity that moves panels up if there i empty space above a panel. ### timepicker -Description: TODO - ```json "timepicker": { "collapse": false, @@ -416,7 +249,3 @@ Usage of the above mentioned fields in the templating section is explained below | **refresh** | TODO | | **regex** | TODO | | **type** | type of variable, i.e. `custom`, `query` or `interval` | - -### annotations - -TODO diff --git a/docs/sources/reference/dashboard_folders.md b/docs/sources/reference/dashboard_folders.md new file mode 100644 index 00000000000..2c287c6891b --- /dev/null +++ b/docs/sources/reference/dashboard_folders.md @@ -0,0 +1,52 @@ ++++ +title = "Dashboard Folders" +keywords = ["grafana", "dashboard", "dashboard folders", "folder", "folders", "documentation", "guide"] +type = "docs" +[menu.docs] +name = "Folders" +parent = "dashboard_features" +weight = 3 ++++ + +# Dashboard Folders + +Folders are a way to organize and group dashboards - very useful if you have a lot of dashboards or multiple teams using the same Grafana instance. + +## How To Create A Folder + +- Create a folder by using the Create Folder link in the side menu (under the create menu (+ icon)) +- Use the create Folder button on the Manage Dashboards page. +- When saving a dashboard, you can either choose a folder for the dashboard to be saved in or create a new folder + +On the Create Folder page, fill in a unique name for the folder and press Create. + +## Manage Dashboards + +{{< docs-imagebox img="/img/docs/v50/manage_dashboard_menu.png" max-width="300px" class="docs-image--right" >}} + +There is a new Manage Dashboards page where you can carry out a variety of tasks: + +- create a folder +- create a dashboard +- move dashboards into folders +- delete multiple dashboards +- navigate to a folder page (where you can set permissions for a folder and/or its dashboards) + +## Dashboard Folder Page + +You reach the dashboard folder page by clicking on the cog icon that appears when you hover +over a folder in the dashboard list in the search result or on the Manage dashboards page. + +The Dashboard Folder Page is similar to the Manage Dashboards page and is where you can carry out the following tasks: + +- Allows you to move or delete dashboards in a folder. +- Rename a folder (under the Settings tab). +- Set permissions for the folder (inherited by dashboards in the folder). + +## Permissions + +Permissions can assigned to a folder and inherited by the containing dashboards. An Access Control List (ACL) is used where +**Organization Role**, **Team** and Individual **User** can be assigned permissions. Read the + [Dashboard & Folder Permissions]({{< relref "administration/permissions.md#dashboard-folder-permissions" >}}) docs for more detail + on the permission system. + diff --git a/docs/sources/reference/export_import.md b/docs/sources/reference/export_import.md index 4c2d5faa3d3..31f32d890f6 100644 --- a/docs/sources/reference/export_import.md +++ b/docs/sources/reference/export_import.md @@ -15,9 +15,9 @@ Grafana Dashboards can easily be exported and imported, either from the UI or fr Dashboards are exported in Grafana JSON format, and contain everything you need (layout, variables, styles, data sources, queries, etc)to import the dashboard at a later time. -The export feature is accessed from the share menu. +The export feature is accessed in the share window which you open by clicking the share button in the dashboard menu. - +{{< docs-imagebox img="/img/docs/v50/export_modal.png" max-width="700px" >}} ### Making a dashboard portable @@ -31,12 +31,12 @@ the dashboard, and will also be added as an required input when the dashboard is To import a dashboard open dashboard search and then hit the import button. - +{{< docs-imagebox img="/img/docs/v50/import_step1.png" max-width="700px" >}} From here you can upload a dashboard json file, paste a [Grafana.com](https://grafana.com) dashboard url or paste dashboard json text directly into the text area. - +{{< docs-imagebox img="/img/docs/v50/import_step2.png" max-width="700px" >}} In step 2 of the import process Grafana will let you change the name of the dashboard, pick what data source you want the dashboard to use and specify any metric prefixes (if the dashboard use any). @@ -45,7 +45,7 @@ data source you want the dashboard to use and specify any metric prefixes (if th Find dashboards for common server applications at [Grafana.com/dashboards](https://grafana.com/dashboards). - +{{< docs-imagebox img="/img/docs/v50/gcom_dashboard_list.png" max-width="700px" >}} ## Import & Sharing with Grafana 2.x or 3.0 diff --git a/docs/sources/reference/playlist.md b/docs/sources/reference/playlist.md index f509ae4dc0d..5a6bf921334 100644 --- a/docs/sources/reference/playlist.md +++ b/docs/sources/reference/playlist.md @@ -16,7 +16,7 @@ Since Grafana automatically scales Dashboards to any resolution they're perfect ## Creating a Playlist -{{< docs-imagebox img="/img/docs/v3/playlist.png" max-width="25rem" class="docs-image--right">}} +{{< docs-imagebox img="/img/docs/v50/playlist.png" max-width="25rem" class="docs-image--right">}} The Playlist feature can be accessed from Grafana's sidemenu, in the Dashboard submenu. diff --git a/docs/sources/reference/search.md b/docs/sources/reference/search.md index 9fc4d47893c..1bf6fd53e52 100644 --- a/docs/sources/reference/search.md +++ b/docs/sources/reference/search.md @@ -10,22 +10,22 @@ weight = 5 # Dashboard Search -Dashboards can be searched by the dashboard name, filtered by one (or many) tags or filtered by starred status. The dashboard search is accessed through the dashboard picker, available in the dashboard top nav area. +Dashboards can be searched by the dashboard name, filtered by one (or many) tags or filtered by starred status. The dashboard search is accessed through the dashboard picker, available in the dashboard top nav area. The dashboard search can also be opened by using the shortcut `F`. - + -1. `Dashboard Picker`: The Dashboard Picker is your primary navigation tool to move between dashboards. It is present on all dashboards, and open the Dashboard Search. The dashboard picker also doubles as the title of the current dashboard. -2. `Search Bar`: The search bar allows you to enter any string and search both database and file based dashboards in real-time. -3. `Starred`: The starred link allows you to filter the list to display only starred dashboards. -4. `Tags`: The tags filter allows you to filter the list by dashboard tags. +1. `Search Bar`: The search bar allows you to enter any string and search both database and file based dashboards in real-time. +2. `Starred`: Here you find all your starred dashboards. +3. `Recent`: Here you find the latest created dashboards. +4. `Folders`: The tags filter allows you to filter the list by dashboard tags. +5. `Root`: The root contains all dashboards that are not placed in a folder. +6. `Tags`: The tags filter allows you to filter the list by dashboard tags. When using only a keyboard, you can use your keyboard arrow keys to navigate the results, hit enter to open the selected dashboard. ## Find by dashboard name - - -To search and load dashboards click the open folder icon in the header or use the shortcut `CTRL`+`F`. Begin typing any part of the desired dashboard names. Search will return results for for any partial string match in real-time, as you type. +Begin typing any part of the desired dashboard names in the search bar. Search will return results for for any partial string match in real-time, as you type. Dashboard search is: - Real-time @@ -38,21 +38,8 @@ Tags are a great way to organize your dashboards, especially as the number of da To filter the dashboard list by tag, click on any tag appearing in the right column. The list may be further filtered by clicking on additional tags: - - -Alternately, to see a list of all available tags, click the tags link in the search bar. All tags will be shown, and when a tag is selected, the dashboard search will be instantly filtered: - - +Alternately, to see a list of all available tags, click the tags dropdown menu. All tags will be shown, and when a tag is selected, the dashboard search will be instantly filtered: When using only a keyboard: `tab` to focus on the *tags* link, `▼` down arrow key to find a tag and select with the `Enter` key. -**Note**: When multiple tags are selected, Grafana will show dashboards that include **all**. - - -## Filter by Starred - -Starring is a great way to organize and find commonly used dashboards. To show only starred dashboards in the list, click the *starred* link in the search bar: - - - -When using only a keyboard: `tab` to focus on the *stars* link, `▼` down arrow key to find a tag and select with the `Enter` key. +**Note**: When multiple tags are selected, Grafana will show dashboards that include **all**. \ No newline at end of file diff --git a/docs/sources/reference/sharing.md b/docs/sources/reference/sharing.md index badd3b5712a..59c2e0345ea 100644 --- a/docs/sources/reference/sharing.md +++ b/docs/sources/reference/sharing.md @@ -24,7 +24,7 @@ A dashboard snapshot is an instant way to share an interactive dashboard publicl (metric, template and annotation) and panel links, leaving only the visible metric data and series names embedded into your dashboard. Dashboard snapshots can be accessed by anyone who has the link and can reach the URL. -![](/img/docs/v4/share_panel_modal.png) +{{< docs-imagebox img="/img/docs/v50/share_panel_modal.png" max-width="700px" >}} ### Publish snapshots @@ -39,7 +39,7 @@ Click a panel title to open the panel menu, then click share in the panel menu t ### Direct Link Rendered Image -You also get a link to service side rendered PNG of the panel. Useful if you want to share an image of the panel. Please note that for OSX and Windows, you will need to ensure that a `phantomjs` binary is available under `vendor/phantomjs/phantomjs`. For Linux, a `phantomjs` binary is included - however, you should ensure that any requisite libraries (e.g. libfontconfig) are available. +You also get a link to service side rendered PNG of the panel. Useful if you want to share an image of the panel. Please note that for OSX and Windows, you will need to ensure that a `phantomjs` binary is available under `tools/phantomjs/phantomjs`. For Linux, a `phantomjs` binary is included - however, you should ensure that any requisite libraries (e.g. libfontconfig) are available. Example of a link to a server-side rendered PNG: @@ -70,9 +70,9 @@ Below there should be an interactive Grafana graph embedded in an iframe: ### Export Panel Data -![](/img/docs/v4/export_panel_data.png) +{{< docs-imagebox img="/img/docs/v50/export_panel_data.png" max-width="500px" >}} -The submenu for a panel can be found by clicking on the title of a panel and then on the hamburger (three horizontal lines) submenu on the left of the context menu. +The submenu for a panel can be found by clicking on the title of a panel and then on the More submenu. This menu contains two options for exporting data: diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index 36308adf52f..3a15b4ed7d1 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -1,20 +1,20 @@ +++ -title = "Templating" +title = "Variables" keywords = ["grafana", "templating", "documentation", "guide"] type = "docs" [menu.docs] -name = "Templating" +name = "Variables" parent = "dashboard_features" weight = 1 +++ -# Templating +# Variables -Templating allows for more interactive and dynamic dashboards. Instead of hard-coding things like server, application +Variables allows for more interactive and dynamic dashboards. Instead of hard-coding things like server, application and sensor name in you metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard. - +{{< docs-imagebox img="/img/docs/v50/variables_dashboard.png" >}} ## What is a variable? @@ -43,7 +43,7 @@ is the set of values you can choose from. ## Adding a variable - +{{< docs-imagebox img="/img/docs/v50/variables_var_list.png" max-width="800px" >}} You add variables via Dashboard cogs menu > Templating. This opens up a list of variables and a `New` button to create a new variable. @@ -133,7 +133,7 @@ Option | Description *Tags query* | Data source query that should return a list of tags *Tag values query* | Data source query that should return a list of values for a specified tag key. Use `$tag` in the query to refer the currently selected tag. -![](/img/docs/v4/variable_dropdown_tags.png) +{{< docs-imagebox img="/img/docs/v50/variable_dropdown_tags.png" max-width="300px" >}} ### Interval variables diff --git a/docs/sources/reference/timerange.md b/docs/sources/reference/timerange.md index a4d6fc62336..4121ed87931 100644 --- a/docs/sources/reference/timerange.md +++ b/docs/sources/reference/timerange.md @@ -13,7 +13,7 @@ weight = 7 Grafana provides numerous ways to manage the time ranges of the data being visualized, both at the Dashboard-level and the Panel-level. - + In the top right, you have the master Dashboard time picker (it's in between the 'Zoom out' and the 'Refresh' links). @@ -39,11 +39,11 @@ Week to date | `now/w` | `now` Previous Month | `now-1M/M` | `now-1M/M` -## Dashboard-Level Time Picker Settings +## Dashboard Time Options -There are two settings available from the Dashboard Settings area, allowing customization of the auto-refresh intervals and the definition of `now`. +There are two settings available in the Dashboard Settings General tab, allowing customization of the auto-refresh intervals and the definition of `now`. - + ### Auto-Refresh Options @@ -59,11 +59,11 @@ Users often ask, [when will then be now](https://www.youtube.com/watch?v=VeZ9HhH You can override the relative time range for individual panels, causing them to be different than what is selected in the Dashboard time picker in the upper right. This allows you to show metrics from different time periods or days at the same time. - +{{< docs-imagebox img="/img/docs/v50/panel_time_override.png" max-width="500px" >}} You control these overrides in panel editor mode and the tab `Time Range`. - +{{< docs-imagebox img="/img/docs/v50/time_range_tab.png" max-width="500px" >}} When you zoom or change the Dashboard time to a custom absolute time range, all panel overrides will be disabled. The panel relative time override is only active when the dashboard time is also relative. The panel timeshift override is always active, even when the dashboard time is absolute. diff --git a/docs/sources/tutorials/iis.md b/docs/sources/tutorials/iis.md new file mode 100644 index 00000000000..63a41d67c16 --- /dev/null +++ b/docs/sources/tutorials/iis.md @@ -0,0 +1,89 @@ ++++ +title = "Grafana with IIS Reverse Proxy on Windows" +type = "docs" +keywords = ["grafana", "tutorials", "proxy", "IIS", "windows"] +[menu.docs] +parent = "tutorials" +weight = 10 ++++ + +# How to Use IIS with URL Rewrite as a Reverse Proxy for Grafana on Windows + +If you want Grafana to be a subpath or subfolder under a website in IIS then the URL Rewrite module for ISS can be used to support this. + +Example: + +- Parent site: http://localhost:8080 +- Grafana: http://localhost:3000 + +Grafana as a subpath: http://localhost:8080/grafana + +## Setup + +If you have not already done it, then a requirement is to install URL Rewrite module for IIS. + +Download and install the URL Rewrite module for IIS: https://www.iis.net/downloads/microsoft/url-rewrite + +## Grafana Config + +The Grafana config can be set by creating a file named `custom.ini` in the `conf` subdirectory of your Grafana installation. See the [installation instructions](http://docs.grafana.org/installation/windows/#configure) for more details. + +Given that the subpath should be `grafana` and the parent site is `localhost:8080` then add this to the `custom.ini` config file: + + ```bash +[server] +domain = localhost:8080 +root_url = %(protocol)s://%(domain)s:/grafana +``` + +Restart the Grafana server after changing the config file. + +## IIS Config + +1. Open the IIS Manager and click on the parent website +2. In the admin console for this website, double click on the Url Rewrite option: + {{< docs-imagebox img="/img/docs/tutorials/IIS_admin_console.png" max-width= "800px" >}} + +3. Click on the `Add Rule(s)...` action +4. Choose the Blank Rule template for an Inbound Rule + {{< docs-imagebox img="/img/docs/tutorials/IIS_add_inbound_rule.png" max-width= "800px" >}} + +5. Create an Inbound Rule for the parent website (localhost:8080 in this example) with the following settings: + - pattern: `grafana(/)?(.*)` + - check the `Ignore case` checkbox + - rewrite url set to `http://localhost:3000/{R:2}` + - check the `Append query string` checkbox + - check the `Stop processing of subsequent rules` checkbox + + {{< docs-imagebox img="/img/docs/tutorials/IIS_url_rewrite.png" max-width= "800px" >}} + +Finally, navigate to `http://localhost:8080/grafana` (replace `http://localhost:8080` with your parent domain) and you should come to the Grafana login page. + +## Troubleshooting + +### 404 error + +When navigating to the grafana url (`http://localhost:8080/grafana` in the example above) and a `HTTP Error 404.0 - Not Found` error is returned then either: + +- the pattern for the Inbound Rule is incorrect. Edit the rule, click on the `Test pattern...` button, test the part of the url after `http://localhost:8080/` and make sure it matches. For `grafana/login` the test should return 3 capture groups: {R:0}: `grafana` {R:1}: `/` and {R:2}: `login`. +- The `root_url` setting in the Grafana config file does not match the parent url with subpath. + +### Grafana Website only shows text with no images or css + +{{< docs-imagebox img="/img/docs/tutorials/IIS_proxy_error.png" max-width= "800px" >}} + +1. The `root_url` setting in the Grafana config file does not match the parent url with subpath. This could happen if the root_url is commented out by mistake (`;` is used for commenting out a line in .ini files): + + `; root_url = %(protocol)s://%(domain)s:/grafana` + +2. or if the subpath in the `root_url` setting does not match the subpath used in the pattern in the Inbound Rule in IIS: + + `root_url = %(protocol)s://%(domain)s:/grafana` + + pattern in Inbound Rule: `wrongsubpath(/)?(.*)` + +3. or if the Rewrite Url in the Inbound Rule is incorrect. + + The Rewrite Url should not include the subpath. + + The Rewrite Url should contain the capture group from the pattern matching that returns the part of the url after the subpath. The pattern used above returns 3 capture groups and the third one {R:2} returns the part of the url after `http://localhost:8080/grafana/`. diff --git a/docs/sources/features/whatsnew/index.md b/docs/sources/whatsnew/index.md similarity index 90% rename from docs/sources/features/whatsnew/index.md rename to docs/sources/whatsnew/index.md index 30357af4668..df472f07093 100644 --- a/docs/sources/features/whatsnew/index.md +++ b/docs/sources/whatsnew/index.md @@ -3,7 +3,7 @@ title = "What's New in Grafana" [menu.docs] name = "What's New In Grafana" identifier = "whatsnew" -weight = 2 +weight = 3 +++ diff --git a/docs/versions.json b/docs/versions.json new file mode 100644 index 00000000000..4685360cc29 --- /dev/null +++ b/docs/versions.json @@ -0,0 +1,9 @@ +[ + { "version": "v5.0", "path": "/", "archived": false, "current": true }, + { "version": "v4.6", "path": "/v4.6", "archived": true }, + { "version": "v4.5", "path": "/v4.5", "archived": true }, + { "version": "v4.4", "path": "/v4.4", "archived": true }, + { "version": "v4.3", "path": "/v4.3", "archived": true }, + { "version": "v4.1", "path": "/v4.1", "archived": true }, + { "version": "v3.1", "path": "/v3.1", "archived": true } +] diff --git a/jest.config.js b/jest.config.js index cbe77c4e30f..606465c9840 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ module.exports = { - verbose: true, + verbose: false, "globals": { "ts-jest": { "tsConfigFile": "tsconfig.json" @@ -24,5 +24,6 @@ module.exports = { "setupFiles": [ "./public/test/jest-shim.ts", "./public/test/jest-setup.ts" - ] + ], + "snapshotSerializers": ["enzyme-to-json/serializer"], }; diff --git a/latest.json b/latest.json index a746e92c3b3..b476f44a00a 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "stable": "4.6.2", - "testing": "4.6.2" + "stable": "5.0.0", + "testing": "5.0.0" } diff --git a/package.json b/package.json index 9a6edfb8be9..df4359ef5c1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Grafana Labs" }, "name": "grafana", - "version": "4.7.0-pre1", + "version": "5.0.1-pre1", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git" @@ -14,17 +14,19 @@ "@types/enzyme": "^2.8.9", "@types/jest": "^21.1.4", "@types/node": "^8.0.31", - "@types/react": "^16.0.5", - "@types/react-dom": "^15.5.4", + "@types/react": "^16.0.25", + "@types/react-dom": "^16.0.3", "angular-mocks": "^1.6.6", "autoprefixer": "^6.4.0", "awesome-typescript-loader": "^3.2.3", + "axios": "^0.17.1", "babel-core": "^6.26.0", "babel-loader": "^7.1.2", "babel-preset-es2015": "^6.24.1", "css-loader": "^0.28.7", "enzyme": "^3.1.0", "enzyme-adapter-react-16": "^1.0.1", + "enzyme-to-json": "^3.3.0", "es6-promise": "^3.0.2", "es6-shim": "^0.35.3", "expect.js": "~0.2.0", @@ -54,7 +56,7 @@ "html-loader": "^0.5.1", "html-webpack-plugin": "^2.30.1", "husky": "^0.14.3", - "jest": "^21.2.1", + "jest": "^22.0.4", "jshint-stylish": "~2.2.1", "json-loader": "^0.5.7", "karma": "1.7.0", @@ -65,8 +67,9 @@ "karma-sinon": "^1.0.5", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^2.0.4", - "lint-staged": "^4.2.3", + "lint-staged": "^6.0.0", "load-grunt-tasks": "3.5.2", + "mobx-react-devtools": "^4.2.15", "mocha": "^4.0.1", "ng-annotate-loader": "^0.6.1", "ng-annotate-webpack-plugin": "^0.2.1-pre", @@ -76,19 +79,19 @@ "postcss-browser-reporter": "^0.5.0", "postcss-loader": "^2.0.6", "postcss-reporter": "^5.0.0", - "prettier": "1.7.3", + "prettier": "1.9.2", "react-test-renderer": "^16.0.0", "sass-lint": "^1.10.2", "sass-loader": "^6.0.6", "sinon": "1.17.6", "systemjs": "0.20.19", "systemjs-plugin-css": "^0.1.36", - "ts-jest": "^21.1.3", - "ts-loader": "^2.3.7", - "tslint": "^5.7.0", + "ts-jest": "^22.0.0", + "ts-loader": "^3.2.0", + "tslint": "^5.8.0", "tslint-loader": "^3.5.3", - "typescript": "^2.5.2", - "webpack": "^3.6.0", + "typescript": "^2.6.2", + "webpack": "^3.10.0", "webpack-bundle-analyzer": "^2.9.0", "webpack-cleanup-plugin": "^0.5.1", "webpack-merge": "^4.1.0", @@ -103,34 +106,66 @@ "lint": "tslint -c tslint.json --project tsconfig.json --type-check", "karma": "node ./node_modules/grunt-cli/bin/grunt karma:dev", "jest": "node ./node_modules/jest-cli/bin/jest.js --notify --watch", - "precommit": "node ./node_modules/grunt-cli/bin/grunt precommit" + "api-tests": "node ./node_modules/jest-cli/bin/jest.js --notify --watch --config=tests/api/jest.js", + "precommit": "lint-staged && node ./node_modules/grunt-cli/bin/grunt precommit" + }, + "lint-staged": { + "*.{ts,tsx}": [ + "prettier --write", + "git add" + ], + "*.scss": [ + "prettier --write", + "git add" + ], + "*.go": [ + "gofmt -w -s", + "git add" + ] + }, + "prettier": { + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 120 }, "license": "Apache-2.0", "dependencies": { "angular": "^1.6.6", "angular-bindonce": "^0.3.1", - "angular-mocks": "^1.6.6", "angular-native-dragdrop": "^1.2.2", "angular-route": "^1.6.6", "angular-sanitize": "^1.6.6", "babel-polyfill": "^6.26.0", "brace": "^0.10.0", + "classnames": "^2.2.5", "clipboard": "^1.7.1", + "d3": "^4.11.0", + "d3-scale-chromatic": "^1.1.1", "eventemitter3": "^2.0.3", "file-saver": "^1.3.3", "jquery": "^3.2.1", "lodash": "^4.17.4", + "mobx": "^3.4.1", + "mobx-react": "^4.3.5", + "mobx-state-tree": "^1.3.1", "moment": "^2.18.1", "mousetrap": "^1.6.0", - "ngreact": "^0.4.1", - "react": "^16.0.0", - "react-dom": "^16.0.0", + "mousetrap-global-bind": "^1.1.0", + "perfect-scrollbar": "^1.2.0", + "prop-types": "^15.6.0", + "react": "^16.2.0", + "react-dom": "^16.2.0", + "react-grid-layout-grafana": "0.16.0", + "react-highlight-words": "^0.10.0", + "react-popper": "^0.7.5", + "react-select": "^1.1.0", + "react-sizeme": "^2.3.6", + "react-transition-group": "^2.2.1", "remarkable": "^1.7.1", + "rst2html": "github:thoward/rst2html#990cb89", "rxjs": "^5.4.3", "tether": "^1.4.0", - "tether-drop": "https://github.com/torkelo/drop", - "tinycolor2": "^1.4.1", - "d3": "^4.11.0", - "d3-scale-chromatic": "^1.1.1" + "tether-drop": "https://github.com/torkelo/drop/tarball/master", + "tinycolor2": "^1.4.1" } } diff --git a/packaging/publish/publish_both.sh b/packaging/publish/publish_both.sh index 6c4f5a5c29a..9736cbddd6c 100755 --- a/packaging/publish/publish_both.sh +++ b/packaging/publish/publish_both.sh @@ -1,5 +1,5 @@ #! /usr/bin/env bash -version=4.6.2 +version=4.6.3 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${version}_amd64.deb diff --git a/packaging/publish/publish_testing.sh b/packaging/publish/publish_testing.sh index 276193ad63f..08ba2a89dd9 100755 --- a/packaging/publish/publish_testing.sh +++ b/packaging/publish/publish_testing.sh @@ -1,6 +1,6 @@ #! /usr/bin/env bash -deb_ver=4.6.0-beta1 -rpm_ver=4.6.0-beta1 +deb_ver=5.0.0-beta5 +rpm_ver=5.0.0-beta5 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 58ea56cc8a7..08edf54748b 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/services/guardian" ) func ValidateOrgAlert(c *middleware.Context) { @@ -51,6 +52,7 @@ func GetAlerts(c *middleware.Context) Response { DashboardId: c.QueryInt64("dashboardId"), PanelId: c.QueryInt64("panelId"), Limit: c.QueryInt64("limit"), + User: c.SignedInUser, } states := c.QueryStrings("state") @@ -62,43 +64,11 @@ func GetAlerts(c *middleware.Context) Response { return ApiError(500, "List alerts failed", err) } - dashboardIds := make([]int64, 0) - alertDTOs := make([]*dtos.AlertRule, 0) for _, alert := range query.Result { - dashboardIds = append(dashboardIds, alert.DashboardId) - alertDTOs = append(alertDTOs, &dtos.AlertRule{ - Id: alert.Id, - DashboardId: alert.DashboardId, - PanelId: alert.PanelId, - Name: alert.Name, - Message: alert.Message, - State: alert.State, - NewStateDate: alert.NewStateDate, - ExecutionError: alert.ExecutionError, - EvalData: alert.EvalData, - }) + alert.Url = models.GetDashboardUrl(alert.DashboardUid, alert.DashboardSlug) } - dashboardsQuery := models.GetDashboardsQuery{ - DashboardIds: dashboardIds, - } - - if len(alertDTOs) > 0 { - if err := bus.Dispatch(&dashboardsQuery); err != nil { - return ApiError(500, "List alerts failed", err) - } - } - - //TODO: should be possible to speed this up with lookup table - for _, alert := range alertDTOs { - for _, dash := range dashboardsQuery.Result { - if alert.DashboardId == dash.Id { - alert.DashbboardUri = "db/" + dash.Slug - } - } - } - - return Json(200, alertDTOs) + return Json(200, query.Result) } // POST /api/alerts/test @@ -155,24 +125,6 @@ func GetAlert(c *middleware.Context) Response { return Json(200, &query.Result) } -// DEL /api/alerts/:id -func DelAlert(c *middleware.Context) Response { - alertId := c.ParamsInt64(":alertId") - - if alertId == 0 { - return ApiError(401, "Failed to parse alertid", nil) - } - - cmd := models.DeleteAlertCommand{AlertId: alertId} - - if err := bus.Dispatch(&cmd); err != nil { - return ApiError(500, "Failed to delete alert", err) - } - - var resp = map[string]interface{}{"alertId": alertId} - return Json(200, resp) -} - func GetAlertNotifiers(c *middleware.Context) Response { return Json(200, alerting.GetNotifiers()) } @@ -267,6 +219,22 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R //POST /api/alerts/:alertId/pause func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response { alertId := c.ParamsInt64("alertId") + + query := models.GetAlertByIdQuery{Id: alertId} + + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "Get Alert failed", err) + } + + guardian := guardian.New(query.Result.DashboardId, c.OrgId, c.SignedInUser) + if canEdit, err := guardian.CanEdit(); err != nil || !canEdit { + if err != nil { + return ApiError(500, "Error while checking permissions for Alert", err) + } + + return ApiError(403, "Access denied to this dashboard and alert", nil) + } + cmd := models.PauseAlertCommand{ OrgId: c.OrgId, AlertIds: []int64{alertId}, @@ -278,7 +246,7 @@ func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response { } var response models.AlertStateType = models.AlertStatePending - pausedState := "un paused" + pausedState := "un-paused" if cmd.Paused { response = models.AlertStatePaused pausedState = "paused" @@ -287,7 +255,7 @@ func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response { result := map[string]interface{}{ "alertId": alertId, "state": response, - "message": "alert " + pausedState, + "message": "Alert " + pausedState, } return Json(200, result) diff --git a/pkg/api/alerting_test.go b/pkg/api/alerting_test.go new file mode 100644 index 00000000000..6b030053e22 --- /dev/null +++ b/pkg/api/alerting_test.go @@ -0,0 +1,97 @@ +package api + +import ( + "testing" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertingApiEndpoint(t *testing.T) { + Convey("Given an alert in a dashboard with an acl", t, func() { + + singleAlert := &m.Alert{Id: 1, DashboardId: 1, Name: "singlealert"} + + bus.AddHandler("test", func(query *m.GetAlertByIdQuery) error { + query.Result = singleAlert + return nil + }) + + viewerRole := m.ROLE_VIEWER + editorRole := m.ROLE_EDITOR + + aclMockResp := []*m.DashboardAclInfoDTO{} + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = aclMockResp + return nil + }) + + bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error { + query.Result = []*m.Team{} + return nil + }) + + Convey("When user is editor and not in the ACL", func() { + Convey("Should not be able to pause the alert", func() { + cmd := dtos.PauseAlertCommand{ + AlertId: 1, + Paused: true, + } + postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", m.ROLE_EDITOR, cmd, func(sc *scenarioContext) { + CallPauseAlert(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + }) + + Convey("When user is editor and dashboard has default ACL", func() { + aclMockResp = []*m.DashboardAclInfoDTO{ + {Role: &viewerRole, Permission: m.PERMISSION_VIEW}, + {Role: &editorRole, Permission: m.PERMISSION_EDIT}, + } + + Convey("Should be able to pause the alert", func() { + cmd := dtos.PauseAlertCommand{ + AlertId: 1, + Paused: true, + } + postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", m.ROLE_EDITOR, cmd, func(sc *scenarioContext) { + CallPauseAlert(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + }) + }) +} + +func CallPauseAlert(sc *scenarioContext) { + bus.AddHandler("test", func(cmd *m.PauseAlertCommand) error { + return nil + }) + + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() +} + +func postAlertScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PauseAlertCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.UserId = TestUserID + sc.context.OrgId = TestOrgID + sc.context.OrgRole = role + + return PauseAlert(c, cmd) + }) + + sc.m.Post(routePattern, sc.defaultHandler) + + fn(sc) + }) +} diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index 0bf95557abc..cb1a15e69eb 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -7,7 +7,9 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/annotations" + "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/util" ) @@ -51,6 +53,10 @@ func (e *CreateAnnotationError) Error() string { } func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response { + if canSave, err := canSaveByDashboardId(c, cmd.DashboardId); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + repo := annotations.GetRepository() if cmd.Text == "" { @@ -178,6 +184,10 @@ func UpdateAnnotation(c *middleware.Context, cmd dtos.UpdateAnnotationsCmd) Resp repo := annotations.GetRepository() + if resp := canSave(c, repo, annotationId); resp != nil { + return resp + } + item := annotations.Item{ OrgId: c.OrgId, UserId: c.UserId, @@ -228,6 +238,10 @@ func DeleteAnnotationById(c *middleware.Context) Response { repo := annotations.GetRepository() annotationId := c.ParamsInt64(":annotationId") + if resp := canSave(c, repo, annotationId); resp != nil { + return resp + } + err := repo.Delete(&annotations.DeleteParams{ Id: annotationId, }) @@ -243,6 +257,10 @@ func DeleteAnnotationRegion(c *middleware.Context) Response { repo := annotations.GetRepository() regionId := c.ParamsInt64(":regionId") + if resp := canSave(c, repo, regionId); resp != nil { + return resp + } + err := repo.Delete(&annotations.DeleteParams{ RegionId: regionId, }) @@ -253,3 +271,50 @@ func DeleteAnnotationRegion(c *middleware.Context) Response { return ApiSuccess("Annotation region deleted") } + +func canSaveByDashboardId(c *middleware.Context, dashboardId int64) (bool, error) { + if dashboardId == 0 && !c.SignedInUser.HasRole(m.ROLE_EDITOR) { + return false, nil + } + + if dashboardId > 0 { + guardian := guardian.New(dashboardId, c.OrgId, c.SignedInUser) + if canEdit, err := guardian.CanEdit(); err != nil || !canEdit { + return false, err + } + } + + return true, nil +} + +func canSave(c *middleware.Context, repo annotations.Repository, annotationId int64) Response { + items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationId, OrgId: c.OrgId}) + + if err != nil || len(items) == 0 { + return ApiError(500, "Could not find annotation to update", err) + } + + dashboardId := items[0].DashboardId + + if canSave, err := canSaveByDashboardId(c, dashboardId); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + + return nil +} + +func canSaveByRegionId(c *middleware.Context, repo annotations.Repository, regionId int64) Response { + items, err := repo.Find(&annotations.ItemQuery{RegionId: regionId, OrgId: c.OrgId}) + + if err != nil || len(items) == 0 { + return ApiError(500, "Could not find annotation to update", err) + } + + dashboardId := items[0].DashboardId + + if canSave, err := canSaveByDashboardId(c, dashboardId); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + + return nil +} diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go new file mode 100644 index 00000000000..480962d8826 --- /dev/null +++ b/pkg/api/annotations_test.go @@ -0,0 +1,242 @@ +package api + +import ( + "testing" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/annotations" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestAnnotationsApiEndpoint(t *testing.T) { + Convey("Given an annotation without a dashboard id", t, func() { + cmd := dtos.PostAnnotationsCmd{ + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, + } + + updateCmd := dtos.UpdateAnnotationsCmd{ + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, + } + + Convey("When user is an Org Viewer", func() { + role := m.ROLE_VIEWER + Convey("Should not be allowed to save an annotation", func() { + postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + + putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationById + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationRegion + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + }) + + Convey("When user is an Org Editor", func() { + role := m.ROLE_EDITOR + Convey("Should be able to save an annotation", func() { + postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationById + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationRegion + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + }) + }) + + Convey("Given an annotation with a dashboard id and the dashboard does not have an acl", t, func() { + cmd := dtos.PostAnnotationsCmd{ + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, + DashboardId: 1, + PanelId: 1, + } + + updateCmd := dtos.UpdateAnnotationsCmd{ + Time: 1000, + Text: "annotation text", + Tags: []string{"tag1", "tag2"}, + IsRegion: false, + Id: 1, + } + + viewerRole := m.ROLE_VIEWER + editorRole := m.ROLE_EDITOR + + aclMockResp := []*m.DashboardAclInfoDTO{ + {Role: &viewerRole, Permission: m.PERMISSION_VIEW}, + {Role: &editorRole, Permission: m.PERMISSION_EDIT}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = aclMockResp + return nil + }) + + bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error { + query.Result = []*m.Team{} + return nil + }) + + Convey("When user is an Org Viewer", func() { + role := m.ROLE_VIEWER + Convey("Should not be allowed to save an annotation", func() { + postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + + putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationById + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationRegion + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + }) + + Convey("When user is an Org Editor", func() { + role := m.ROLE_EDITOR + Convey("Should be able to save an annotation", func() { + postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) { + sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationById + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/region/1", "/api/annotations/region/:regionId", role, func(sc *scenarioContext) { + sc.handlerFunc = DeleteAnnotationRegion + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + }) + }) +} + +type fakeAnnotationsRepo struct { +} + +func (repo *fakeAnnotationsRepo) Delete(params *annotations.DeleteParams) error { + return nil +} +func (repo *fakeAnnotationsRepo) Save(item *annotations.Item) error { + item.Id = 1 + return nil +} +func (repo *fakeAnnotationsRepo) Update(item *annotations.Item) error { + return nil +} +func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) { + annotations := []*annotations.ItemDTO{{Id: 1}} + return annotations, nil +} + +var fakeAnnoRepo *fakeAnnotationsRepo + +func postAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PostAnnotationsCmd, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.UserId = TestUserID + sc.context.OrgId = TestOrgID + sc.context.OrgRole = role + + return PostAnnotation(c, cmd) + }) + + fakeAnnoRepo = &fakeAnnotationsRepo{} + annotations.SetRepository(fakeAnnoRepo) + + sc.m.Post(routePattern, sc.defaultHandler) + + fn(sc) + }) +} + +func putAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.UserId = TestUserID + sc.context.OrgId = TestOrgID + sc.context.OrgRole = role + + return UpdateAnnotation(c, cmd) + }) + + fakeAnnoRepo = &fakeAnnotationsRepo{} + annotations.SetRepository(fakeAnnoRepo) + + sc.m.Put(routePattern, sc.defaultHandler) + + fn(sc) + }) +} diff --git a/pkg/api/api.go b/pkg/api/api.go index 3810f87dbb8..1b7e30e34ad 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -15,6 +15,8 @@ func (hs *HttpServer) registerRoutes() { reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true}) reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN) reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN) + redirectFromLegacyDashboardUrl := middleware.RedirectFromLegacyDashboardUrl() + redirectFromLegacyDashboardSoloUrl := middleware.RedirectFromLegacyDashboardSoloUrl() quota := middleware.Quota bind := binding.Bind @@ -40,9 +42,14 @@ func (hs *HttpServer) registerRoutes() { r.Get("/datasources/", reqSignedIn, Index) r.Get("/datasources/new", reqSignedIn, Index) r.Get("/datasources/edit/*", reqSignedIn, Index) - r.Get("/org/users/", reqSignedIn, Index) + r.Get("/org/users", reqSignedIn, Index) + r.Get("/org/users/new", reqSignedIn, Index) + r.Get("/org/users/invite", reqSignedIn, Index) + r.Get("/org/teams", reqSignedIn, Index) + r.Get("/org/teams/*", reqSignedIn, Index) r.Get("/org/apikeys/", reqSignedIn, Index) r.Get("/dashboard/import/", reqSignedIn, Index) + r.Get("/configuration", reqGrafanaAdmin, Index) r.Get("/admin", reqGrafanaAdmin, Index) r.Get("/admin/settings", reqGrafanaAdmin, Index) r.Get("/admin/users", reqGrafanaAdmin, Index) @@ -58,10 +65,15 @@ func (hs *HttpServer) registerRoutes() { r.Get("/plugins/:id/edit", reqSignedIn, Index) r.Get("/plugins/:id/page/:page", reqSignedIn, Index) - r.Get("/dashboard/*", reqSignedIn, Index) + r.Get("/d/:uid/:slug", reqSignedIn, Index) + r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardUrl, Index) + r.Get("/dashboard/script/*", reqSignedIn, Index) r.Get("/dashboard-solo/snapshot/*", Index) - r.Get("/dashboard-solo/*", reqSignedIn, Index) + r.Get("/d-solo/:uid/:slug", reqSignedIn, Index) + r.Get("/dashboard-solo/db/:slug", reqSignedIn, redirectFromLegacyDashboardSoloUrl, Index) + r.Get("/dashboard-solo/script/*", reqSignedIn, Index) r.Get("/import/dashboard", reqSignedIn, Index) + r.Get("/dashboards/", reqSignedIn, Index) r.Get("/dashboards/*", reqSignedIn, Index) r.Get("/playlists/", reqSignedIn, Index) @@ -94,7 +106,7 @@ func (hs *HttpServer) registerRoutes() { r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot) r.Get("/api/snapshot/shared-options/", GetSharingOptions) r.Get("/api/snapshots/:key", GetDashboardSnapshot) - r.Get("/api/snapshots-delete/:key", reqEditorRole, DeleteDashboardSnapshot) + r.Get("/api/snapshots-delete/:key", reqEditorRole, wrap(DeleteDashboardSnapshot)) // api renew session based on remember cookie r.Get("/api/login/ping", quota("session"), LoginApiPing) @@ -134,6 +146,18 @@ func (hs *HttpServer) registerRoutes() { usersRoute.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg)) }, reqGrafanaAdmin) + // team (admin permission required) + apiRoute.Group("/teams", func(teamsRoute RouteRegister) { + teamsRoute.Get("/:teamId", wrap(GetTeamById)) + teamsRoute.Get("/search", wrap(SearchTeams)) + teamsRoute.Post("/", quota("teams"), bind(m.CreateTeamCommand{}), wrap(CreateTeam)) + teamsRoute.Put("/:teamId", bind(m.UpdateTeamCommand{}), wrap(UpdateTeam)) + teamsRoute.Delete("/:teamId", wrap(DeleteTeamById)) + teamsRoute.Get("/:teamId/members", wrap(GetTeamMembers)) + teamsRoute.Post("/:teamId/members", quota("teams"), bind(m.AddTeamMemberCommand{}), wrap(AddTeamMember)) + teamsRoute.Delete("/:teamId/members/:userId", wrap(RemoveTeamMember)) + }, reqOrgAdmin) + // org information available to all users. apiRoute.Group("/org", func(orgRoute RouteRegister) { orgRoute.Get("/", wrap(GetOrgCurrent)) @@ -222,21 +246,49 @@ func (hs *HttpServer) registerRoutes() { apiRoute.Any("/datasources/proxy/:id/*", reqSignedIn, hs.ProxyDataSourceRequest) apiRoute.Any("/datasources/proxy/:id", reqSignedIn, hs.ProxyDataSourceRequest) + // Folders + apiRoute.Group("/folders", func(folderRoute RouteRegister) { + folderRoute.Get("/", wrap(GetFolders)) + folderRoute.Get("/id/:id", wrap(GetFolderById)) + folderRoute.Post("/", bind(m.CreateFolderCommand{}), wrap(CreateFolder)) + + folderRoute.Group("/:uid", func(folderUidRoute RouteRegister) { + folderUidRoute.Get("/", wrap(GetFolderByUid)) + folderUidRoute.Put("/", bind(m.UpdateFolderCommand{}), wrap(UpdateFolder)) + folderUidRoute.Delete("/", wrap(DeleteFolder)) + + folderUidRoute.Group("/permissions", func(folderPermissionRoute RouteRegister) { + folderPermissionRoute.Get("/", wrap(GetFolderPermissionList)) + folderPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), wrap(UpdateFolderPermissions)) + }) + }) + }) + // Dashboard apiRoute.Group("/dashboards", func(dashboardRoute RouteRegister) { - dashboardRoute.Get("/db/:slug", GetDashboard) - dashboardRoute.Delete("/db/:slug", reqEditorRole, DeleteDashboard) + dashboardRoute.Get("/uid/:uid", wrap(GetDashboard)) + dashboardRoute.Delete("/uid/:uid", wrap(DeleteDashboardByUid)) - dashboardRoute.Get("/id/:dashboardId/versions", wrap(GetDashboardVersions)) - dashboardRoute.Get("/id/:dashboardId/versions/:id", wrap(GetDashboardVersion)) - dashboardRoute.Post("/id/:dashboardId/restore", reqEditorRole, bind(dtos.RestoreDashboardVersionCommand{}), wrap(RestoreDashboardVersion)) + dashboardRoute.Get("/db/:slug", wrap(GetDashboard)) + dashboardRoute.Delete("/db/:slug", wrap(DeleteDashboard)) dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), wrap(CalculateDashboardDiff)) - dashboardRoute.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), wrap(PostDashboard)) + dashboardRoute.Post("/db", bind(m.SaveDashboardCommand{}), wrap(PostDashboard)) dashboardRoute.Get("/home", wrap(GetHomeDashboard)) dashboardRoute.Get("/tags", GetDashboardTags) dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard)) + + dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) { + dashIdRoute.Get("/versions", wrap(GetDashboardVersions)) + dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion)) + dashIdRoute.Post("/restore", bind(dtos.RestoreDashboardVersionCommand{}), wrap(RestoreDashboardVersion)) + + dashIdRoute.Group("/permissions", func(dashboardPermissionRoute RouteRegister) { + dashboardPermissionRoute.Get("/", wrap(GetDashboardPermissionList)) + dashboardPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), wrap(UpdateDashboardPermissions)) + }) + }) }) // Dashboard snapshots @@ -291,8 +343,8 @@ func (hs *HttpServer) registerRoutes() { annotationsRoute.Delete("/:annotationId", wrap(DeleteAnnotationById)) annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), wrap(UpdateAnnotation)) annotationsRoute.Delete("/region/:regionId", wrap(DeleteAnnotationRegion)) - annotationsRoute.Post("/graphite", bind(dtos.PostGraphiteAnnotationsCmd{}), wrap(PostGraphiteAnnotation)) - }, reqEditorRole) + annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), wrap(PostGraphiteAnnotation)) + }) // error test r.Get("/metrics/error", wrap(GenerateError)) diff --git a/pkg/api/avatar/avatar.go b/pkg/api/avatar/avatar.go index fdf93d06b5d..ce9da1e8790 100644 --- a/pkg/api/avatar/avatar.go +++ b/pkg/api/avatar/avatar.go @@ -25,6 +25,8 @@ import ( "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/setting" "gopkg.in/macaron.v1" + + gocache "github.com/patrickmn/go-cache" ) var gravatarSource string @@ -92,7 +94,7 @@ func (this *Avatar) Update() (err error) { type CacheServer struct { notFound *Avatar - cache map[string]*Avatar + cache *gocache.Cache } func (this *CacheServer) mustInt(r *http.Request, defaultValue int, keys ...string) (v int) { @@ -110,7 +112,9 @@ func (this *CacheServer) Handler(ctx *macaron.Context) { var avatar *Avatar - if avatar, _ = this.cache[hash]; avatar == nil { + if obj, exist := this.cache.Get(hash); exist { + avatar = obj.(*Avatar) + } else { avatar = New(hash) } @@ -124,7 +128,7 @@ func (this *CacheServer) Handler(ctx *macaron.Context) { if avatar.notFound { avatar = this.notFound } else { - this.cache[hash] = avatar + this.cache.Add(hash, avatar, gocache.DefaultExpiration) } ctx.Resp.Header().Add("Content-Type", "image/jpeg") @@ -146,18 +150,18 @@ func NewCacheServer() *CacheServer { return &CacheServer{ notFound: newNotFound(), - cache: make(map[string]*Avatar), + cache: gocache.New(time.Hour, time.Hour*2), } } func newNotFound() *Avatar { avatar := &Avatar{notFound: true} - // load transparent png into buffer - path := filepath.Join(setting.StaticRootPath, "img", "transparent.png") + // load user_profile png into buffer + path := filepath.Join(setting.StaticRootPath, "img", "user_profile.png") if data, err := ioutil.ReadFile(path); err != nil { - log.Error(3, "Failed to read transparent.png, %v", path) + log.Error(3, "Failed to read user_profile.png, %v", path) } else { avatar.data = bytes.NewBuffer(data) } diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go new file mode 100644 index 00000000000..33fc1688603 --- /dev/null +++ b/pkg/api/common_test.go @@ -0,0 +1,105 @@ +package api + +import ( + "net/http" + "net/http/httptest" + "path/filepath" + + "github.com/go-macaron/session" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/models" + macaron "gopkg.in/macaron.v1" + + . "github.com/smartystreets/goconvey/convey" +) + +func loggedInUserScenario(desc string, url string, fn scenarioFunc) { + loggedInUserScenarioWithRole(desc, "GET", url, url, models.ROLE_EDITOR, fn) +} + +func loggedInUserScenarioWithRole(desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.UserId = TestUserID + sc.context.OrgId = TestOrgID + sc.context.OrgRole = role + if sc.handlerFunc != nil { + return sc.handlerFunc(sc.context) + } + + return nil + }) + + switch method { + case "GET": + sc.m.Get(routePattern, sc.defaultHandler) + case "DELETE": + sc.m.Delete(routePattern, sc.defaultHandler) + } + + fn(sc) + }) +} + +func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext { + sc.resp = httptest.NewRecorder() + req, err := http.NewRequest(method, url, nil) + So(err, ShouldBeNil) + sc.req = req + + return sc +} + +func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext { + sc.resp = httptest.NewRecorder() + req, err := http.NewRequest(method, url, nil) + q := req.URL.Query() + for k, v := range queryParams { + q.Add(k, v) + } + req.URL.RawQuery = q.Encode() + So(err, ShouldBeNil) + sc.req = req + + return sc +} + +type scenarioContext struct { + m *macaron.Macaron + context *middleware.Context + resp *httptest.ResponseRecorder + handlerFunc handlerFunc + defaultHandler macaron.Handler + req *http.Request + url string +} + +func (sc *scenarioContext) exec() { + sc.m.ServeHTTP(sc.resp, sc.req) +} + +type scenarioFunc func(c *scenarioContext) +type handlerFunc func(c *middleware.Context) Response + +func setupScenarioContext(url string) *scenarioContext { + sc := &scenarioContext{ + url: url, + } + viewsPath, _ := filepath.Abs("../../public/views") + + sc.m = macaron.New() + sc.m.Use(macaron.Renderer(macaron.RenderOptions{ + Directory: viewsPath, + Delims: macaron.Delims{Left: "[[", Right: "]]"}, + })) + + sc.m.Use(middleware.GetContextHandler()) + sc.m.Use(middleware.Sessioner(&session.Options{})) + + return sc +} diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 92d4a13d39e..53174075c25 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "path" - "strings" "github.com/grafana/grafana/pkg/services/dashboards" @@ -18,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -35,23 +35,33 @@ func isDashboardStarredByUser(c *middleware.Context, dashId int64) (bool, error) return query.Result, nil } -func GetDashboard(c *middleware.Context) { - slug := strings.ToLower(c.Params(":slug")) - - query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId} - err := bus.Dispatch(&query) +func dashboardGuardianResponse(err error) Response { if err != nil { - c.JsonApiErr(404, "Dashboard not found", nil) - return + return ApiError(500, "Error while checking dashboard permissions", err) } - isStarred, err := isDashboardStarredByUser(c, query.Result.Id) - if err != nil { - c.JsonApiErr(500, "Error while checking if dashboard was starred by user", err) - return + return ApiError(403, "Access denied to this dashboard", nil) +} + +func GetDashboard(c *middleware.Context) Response { + dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, c.Params(":uid")) + if rsp != nil { + return rsp } - dash := query.Result + guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) + if canView, err := guardian.CanView(); err != nil || !canView { + return dashboardGuardianResponse(err) + } + + canEdit, _ := guardian.CanEdit() + canSave, _ := guardian.CanSave() + canAdmin, _ := guardian.CanAdmin() + + isStarred, err := isDashboardStarredByUser(c, dash.Id) + if err != nil { + return ApiError(500, "Error while checking if dashboard was starred by user", err) + } // Finding creator and last updater of the dashboard updater, creator := "Anonymous", "Anonymous" @@ -62,29 +72,46 @@ func GetDashboard(c *middleware.Context) { creator = getUserLogin(dash.CreatedBy) } + meta := dtos.DashboardMeta{ + IsStarred: isStarred, + Slug: dash.Slug, + Type: m.DashTypeDB, + CanStar: c.IsSignedIn, + CanSave: canSave, + CanEdit: canEdit, + CanAdmin: canAdmin, + Created: dash.Created, + Updated: dash.Updated, + UpdatedBy: updater, + CreatedBy: creator, + Version: dash.Version, + HasAcl: dash.HasAcl, + IsFolder: dash.IsFolder, + FolderId: dash.FolderId, + Url: dash.GetUrl(), + FolderTitle: "General", + } + + // lookup folder title + if dash.FolderId > 0 { + query := m.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId} + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "Dashboard folder could not be read", err) + } + meta.FolderTitle = query.Result.Title + meta.FolderUrl = query.Result.GetUrl() + } + // make sure db version is in sync with json model version dash.Data.Set("version", dash.Version) dto := dtos.DashboardFullWithMeta{ Dashboard: dash.Data, - Meta: dtos.DashboardMeta{ - IsStarred: isStarred, - Slug: slug, - Type: m.DashTypeDB, - CanStar: c.IsSignedIn, - CanSave: c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR, - CanEdit: canEditDashboard(c.OrgRole), - Created: dash.Created, - Updated: dash.Updated, - UpdatedBy: updater, - CreatedBy: creator, - Version: dash.Version, - }, + Meta: meta, } - // TODO(ben): copy this performance metrics logic for the new API endpoints added c.TimeRequest(metrics.M_Api_Dashboard_Get) - c.JSON(200, dto) + return Json(200, dto) } func getUserLogin(userId int64) string { @@ -98,24 +125,74 @@ func getUserLogin(userId int64) string { } } -func DeleteDashboard(c *middleware.Context) { - slug := c.Params(":slug") +func getDashboardHelper(orgId int64, slug string, id int64, uid string) (*m.Dashboard, Response) { + var query m.GetDashboardQuery + + if len(uid) > 0 { + query = m.GetDashboardQuery{Uid: uid, Id: id, OrgId: orgId} + } else { + query = m.GetDashboardQuery{Slug: slug, Id: id, OrgId: orgId} + } - query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { - c.JsonApiErr(404, "Dashboard not found", nil) - return + return nil, ApiError(404, "Dashboard not found", err) } - cmd := m.DeleteDashboardCommand{Slug: slug, OrgId: c.OrgId} + return query.Result, nil +} + +func DeleteDashboard(c *middleware.Context) Response { + query := m.GetDashboardsBySlugQuery{OrgId: c.OrgId, Slug: c.Params(":slug")} + + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "Failed to retrieve dashboards by slug", err) + } + + if len(query.Result) > 1 { + return Json(412, util.DynMap{"status": "multiple-slugs-exists", "message": m.ErrDashboardsWithSameSlugExists.Error()}) + } + + dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, "") + if rsp != nil { + return rsp + } + + guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) + if canSave, err := guardian.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + + cmd := m.DeleteDashboardCommand{OrgId: c.OrgId, Id: dash.Id} if err := bus.Dispatch(&cmd); err != nil { - c.JsonApiErr(500, "Failed to delete dashboard", err) - return + return ApiError(500, "Failed to delete dashboard", err) } - var resp = map[string]interface{}{"title": query.Result.Title} + return Json(200, util.DynMap{ + "title": dash.Title, + "message": fmt.Sprintf("Dashboard %s deleted", dash.Title), + }) +} - c.JSON(200, resp) +func DeleteDashboardByUid(c *middleware.Context) Response { + dash, rsp := getDashboardHelper(c.OrgId, "", 0, c.Params(":uid")) + if rsp != nil { + return rsp + } + + guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) + if canSave, err := guardian.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + + cmd := m.DeleteDashboardCommand{OrgId: c.OrgId, Id: dash.Id} + if err := bus.Dispatch(&cmd); err != nil { + return ApiError(500, "Failed to delete dashboard", err) + } + + return Json(200, util.DynMap{ + "title": dash.Title, + "message": fmt.Sprintf("Dashboard %s deleted", dash.Title), + }) } func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response { @@ -124,7 +201,7 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response { dash := cmd.GetDashboardModel() - if dash.Id == 0 { + if dash.Id == 0 && dash.Uid == "" { limitReached, err := middleware.QuotaReached(c, "dashboard") if err != nil { return ApiError(500, "failed to get quota", err) @@ -134,17 +211,31 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response { } } - dashItem := &dashboards.SaveDashboardItem{ + dashItem := &dashboards.SaveDashboardDTO{ Dashboard: dash, Message: cmd.Message, OrgId: c.OrgId, - UserId: c.UserId, + User: c.SignedInUser, + Overwrite: cmd.Overwrite, } - dashboard, err := dashboards.GetRepository().SaveDashboard(dashItem) + dashboard, err := dashboards.NewService().SaveDashboard(dashItem) - if err == m.ErrDashboardTitleEmpty { - return ApiError(400, m.ErrDashboardTitleEmpty.Error(), nil) + if err == m.ErrDashboardTitleEmpty || + err == m.ErrDashboardWithSameNameAsFolder || + err == m.ErrDashboardFolderWithSameNameAsDashboard || + err == m.ErrDashboardTypeMismatch || + err == m.ErrDashboardInvalidUid || + err == m.ErrDashboardUidToLong || + err == m.ErrDashboardWithSameUIDExists || + err == m.ErrFolderNotFound || + err == m.ErrDashboardFolderCannotHaveParent || + err == m.ErrDashboardFolderNameExists { + return ApiError(400, err.Error(), nil) + } + + if err == m.ErrDashboardUpdateAccessDenied { + return ApiError(403, err.Error(), err) } if err == m.ErrDashboardContainsInvalidAlertData { @@ -152,7 +243,7 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response { } if err != nil { - if err == m.ErrDashboardWithSameNameExists { + if err == m.ErrDashboardWithSameNameInFolderExists { return Json(412, util.DynMap{"status": "name-exists", "message": err.Error()}) } if err == m.ErrDashboardVersionMismatch { @@ -177,11 +268,14 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response { } c.TimeRequest(metrics.M_Api_Dashboard_Save) - return Json(200, util.DynMap{"status": "success", "slug": dashboard.Slug, "version": dashboard.Version}) -} - -func canEditDashboard(role m.RoleType) bool { - return role == m.ROLE_ADMIN || role == m.ROLE_EDITOR || role == m.ROLE_READ_ONLY_EDITOR + return Json(200, util.DynMap{ + "status": "success", + "slug": dashboard.Slug, + "version": dashboard.Version, + "id": dashboard.Id, + "uid": dashboard.Uid, + "url": dashboard.GetUrl(), + }) } func GetHomeDashboard(c *middleware.Context) Response { @@ -191,10 +285,11 @@ func GetHomeDashboard(c *middleware.Context) Response { } if prefsQuery.Result.HomeDashboardId != 0 { - slugQuery := m.GetDashboardSlugByIdQuery{Id: prefsQuery.Result.HomeDashboardId} + slugQuery := m.GetDashboardRefByIdQuery{Id: prefsQuery.Result.HomeDashboardId} err := bus.Dispatch(&slugQuery) if err == nil { - dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + slugQuery.Result} + url := m.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug) + dashRedirect := dtos.DashboardRedirect{RedirectUri: url} return Json(200, &dashRedirect) } else { log.Warn("Failed to get slug from database, %s", err.Error()) @@ -209,7 +304,9 @@ func GetHomeDashboard(c *middleware.Context) Response { dash := dtos.DashboardFullWithMeta{} dash.Meta.IsHome = true - dash.Meta.CanEdit = canEditDashboard(c.OrgRole) + dash.Meta.CanEdit = c.SignedInUser.HasRole(m.ROLE_EDITOR) + dash.Meta.FolderTitle = "General" + jsonParser := json.NewDecoder(file) if err := jsonParser.Decode(&dash.Dashboard); err != nil { return ApiError(500, "Failed to load home dashboard", err) @@ -223,39 +320,41 @@ func GetHomeDashboard(c *middleware.Context) Response { } func addGettingStartedPanelToHomeDashboard(dash *simplejson.Json) { - rows := dash.Get("rows").MustArray() - row := simplejson.NewFromAny(rows[0]) + panels := dash.Get("panels").MustArray() newpanel := simplejson.NewFromAny(map[string]interface{}{ "type": "gettingstarted", "id": 123123, - "span": 12, + "gridPos": map[string]interface{}{ + "x": 0, + "y": 3, + "w": 24, + "h": 4, + }, }) - panels := row.Get("panels").MustArray() panels = append(panels, newpanel) - row.Set("panels", panels) + dash.Set("panels", panels) } // GetDashboardVersions returns all dashboard versions as JSON func GetDashboardVersions(c *middleware.Context) Response { - dashboardId := c.ParamsInt64(":dashboardId") - limit := c.QueryInt("limit") - start := c.QueryInt("start") + dashId := c.ParamsInt64(":dashboardId") - if limit == 0 { - limit = 1000 + guardian := guardian.New(dashId, c.OrgId, c.SignedInUser) + if canSave, err := guardian.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) } query := m.GetDashboardVersionsQuery{ OrgId: c.OrgId, - DashboardId: dashboardId, - Limit: limit, - Start: start, + DashboardId: dashId, + Limit: c.QueryInt("limit"), + Start: c.QueryInt("start"), } if err := bus.Dispatch(&query); err != nil { - return ApiError(404, fmt.Sprintf("No versions found for dashboardId %d", dashboardId), err) + return ApiError(404, fmt.Sprintf("No versions found for dashboardId %d", dashId), err) } for _, version := range query.Result { @@ -279,17 +378,21 @@ func GetDashboardVersions(c *middleware.Context) Response { // GetDashboardVersion returns the dashboard version with the given ID. func GetDashboardVersion(c *middleware.Context) Response { - dashboardId := c.ParamsInt64(":dashboardId") - version := c.ParamsInt(":id") + dashId := c.ParamsInt64(":dashboardId") + + guardian := guardian.New(dashId, c.OrgId, c.SignedInUser) + if canSave, err := guardian.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) + } query := m.GetDashboardVersionQuery{ OrgId: c.OrgId, - DashboardId: dashboardId, - Version: version, + DashboardId: dashId, + Version: c.ParamsInt(":id"), } if err := bus.Dispatch(&query); err != nil { - return ApiError(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", version, dashboardId), err) + return ApiError(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashId), err) } creator := "Anonymous" @@ -308,6 +411,18 @@ func GetDashboardVersion(c *middleware.Context) Response { // POST /api/dashboards/calculate-diff performs diffs on two dashboards func CalculateDashboardDiff(c *middleware.Context, apiOptions dtos.CalculateDiffOptions) Response { + guardianBase := guardian.New(apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser) + if canSave, err := guardianBase.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + + if apiOptions.Base.DashboardId != apiOptions.New.DashboardId { + guardianNew := guardian.New(apiOptions.New.DashboardId, c.OrgId, c.SignedInUser) + if canSave, err := guardianNew.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + } + options := dashdiffs.Options{ OrgId: c.OrgId, DiffType: dashdiffs.ParseDiffType(apiOptions.DiffType), @@ -333,26 +448,28 @@ func CalculateDashboardDiff(c *middleware.Context, apiOptions dtos.CalculateDiff if options.DiffType == dashdiffs.DiffDelta { return Respond(200, result.Delta).Header("Content-Type", "application/json") - } else { - return Respond(200, result.Delta).Header("Content-Type", "text/html") } + + return Respond(200, result.Delta).Header("Content-Type", "text/html") } // RestoreDashboardVersion restores a dashboard to the given version. func RestoreDashboardVersion(c *middleware.Context, apiCmd dtos.RestoreDashboardVersionCommand) Response { - dashboardId := c.ParamsInt64(":dashboardId") - - dashQuery := m.GetDashboardQuery{Id: dashboardId, OrgId: c.OrgId} - if err := bus.Dispatch(&dashQuery); err != nil { - return ApiError(404, "Dashboard not found", nil) + dash, rsp := getDashboardHelper(c.OrgId, "", c.ParamsInt64(":dashboardId"), "") + if rsp != nil { + return rsp } - versionQuery := m.GetDashboardVersionQuery{DashboardId: dashboardId, Version: apiCmd.Version, OrgId: c.OrgId} + guardian := guardian.New(dash.Id, c.OrgId, c.SignedInUser) + if canSave, err := guardian.CanSave(); err != nil || !canSave { + return dashboardGuardianResponse(err) + } + + versionQuery := m.GetDashboardVersionQuery{DashboardId: dash.Id, Version: apiCmd.Version, OrgId: c.OrgId} if err := bus.Dispatch(&versionQuery); err != nil { return ApiError(404, "Dashboard version not found", nil) } - dashboard := dashQuery.Result version := versionQuery.Result saveCmd := m.SaveDashboardCommand{} @@ -360,7 +477,8 @@ func RestoreDashboardVersion(c *middleware.Context, apiCmd dtos.RestoreDashboard saveCmd.OrgId = c.OrgId saveCmd.UserId = c.UserId saveCmd.Dashboard = version.Data - saveCmd.Dashboard.Set("version", dashboard.Version) + saveCmd.Dashboard.Set("version", dash.Version) + saveCmd.Dashboard.Set("uid", dash.Uid) saveCmd.Message = fmt.Sprintf("Restored from version %d", version.Version) return PostDashboard(c, saveCmd) diff --git a/pkg/api/dashboard_permission.go b/pkg/api/dashboard_permission.go new file mode 100644 index 00000000000..419825644c8 --- /dev/null +++ b/pkg/api/dashboard_permission.go @@ -0,0 +1,91 @@ +package api + +import ( + "time" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/guardian" +) + +func GetDashboardPermissionList(c *middleware.Context) Response { + dashId := c.ParamsInt64(":dashboardId") + + _, rsp := getDashboardHelper(c.OrgId, "", dashId, "") + if rsp != nil { + return rsp + } + + g := guardian.New(dashId, c.OrgId, c.SignedInUser) + + if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin { + return dashboardGuardianResponse(err) + } + + acl, err := g.GetAcl() + if err != nil { + return ApiError(500, "Failed to get dashboard permissions", err) + } + + for _, perm := range acl { + if perm.Slug != "" { + perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug) + } + } + + return Json(200, acl) +} + +func UpdateDashboardPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCommand) Response { + dashId := c.ParamsInt64(":dashboardId") + + _, rsp := getDashboardHelper(c.OrgId, "", dashId, "") + if rsp != nil { + return rsp + } + + g := guardian.New(dashId, c.OrgId, c.SignedInUser) + if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin { + return dashboardGuardianResponse(err) + } + + cmd := m.UpdateDashboardAclCommand{} + cmd.DashboardId = dashId + + for _, item := range apiCmd.Items { + cmd.Items = append(cmd.Items, &m.DashboardAcl{ + OrgId: c.OrgId, + DashboardId: dashId, + UserId: item.UserId, + TeamId: item.TeamId, + Role: item.Role, + Permission: item.Permission, + Created: time.Now(), + Updated: time.Now(), + }) + } + + if okToUpdate, err := g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate { + if err != nil { + if err == guardian.ErrGuardianPermissionExists || + err == guardian.ErrGuardianOverride { + return ApiError(400, err.Error(), err) + } + + return ApiError(500, "Error while checking dashboard permissions", err) + } + + return ApiError(403, "Cannot remove own admin permission for a folder", nil) + } + + if err := bus.Dispatch(&cmd); err != nil { + if err == m.ErrDashboardAclInfoMissing || err == m.ErrDashboardPermissionDashboardEmpty { + return ApiError(409, err.Error(), err) + } + return ApiError(500, "Failed to create permission", err) + } + + return ApiSuccess("Dashboard permissions updated") +} diff --git a/pkg/api/dashboard_permission_test.go b/pkg/api/dashboard_permission_test.go new file mode 100644 index 00000000000..03231338268 --- /dev/null +++ b/pkg/api/dashboard_permission_test.go @@ -0,0 +1,210 @@ +package api + +import ( + "testing" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/guardian" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestDashboardPermissionApiEndpoint(t *testing.T) { + Convey("Dashboard permissions test", t, func() { + Convey("Given dashboard not exists", func() { + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + return m.ErrDashboardNotFound + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) { + callGetDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 404) + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) { + callUpdateDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 404) + }) + }) + + Convey("Given user has no admin permissions", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false}) + + getDashboardQueryResult := m.NewDashboard("Dash") + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = getDashboardQueryResult + return nil + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) { + callGetDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) { + callUpdateDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + + Convey("Given user has admin permissions and permissions to update", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ + CanAdminValue: true, + CheckPermissionBeforeUpdateValue: true, + GetAclValue: []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT}, + {OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN}, + {OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, TeamId: 2, Permission: m.PERMISSION_ADMIN}, + }, + }) + + getDashboardQueryResult := m.NewDashboard("Dash") + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = getDashboardQueryResult + return nil + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) { + callGetDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 200) + respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes()) + So(err, ShouldBeNil) + So(len(respJSON.MustArray()), ShouldEqual, 5) + So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2) + So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, m.PERMISSION_VIEW) + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) { + callUpdateDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + + Convey("When trying to update permissions with duplicate permissions", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ + CanAdminValue: true, + CheckPermissionBeforeUpdateValue: false, + CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists, + }) + + getDashboardQueryResult := m.NewDashboard("Dash") + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = getDashboardQueryResult + return nil + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) { + callUpdateDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 400) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + + Convey("When trying to override inherited permissions with lower presedence", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ + CanAdminValue: true, + CheckPermissionBeforeUpdateValue: false, + CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride}, + ) + + getDashboardQueryResult := m.NewDashboard("Dash") + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = getDashboardQueryResult + return nil + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) { + callUpdateDashboardPermissions(sc) + So(sc.resp.Code, ShouldEqual, 400) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + }) +} + +func callGetDashboardPermissions(sc *scenarioContext) { + sc.handlerFunc = GetDashboardPermissionList + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() +} + +func callUpdateDashboardPermissions(sc *scenarioContext) { + bus.AddHandler("test", func(cmd *m.UpdateDashboardAclCommand) error { + return nil + }) + + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() +} + +func updateDashboardPermissionScenario(desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.OrgId = TestOrgID + sc.context.UserId = TestUserID + + return UpdateDashboardPermissions(c, cmd) + }) + + sc.m.Post(routePattern, sc.defaultHandler) + + fn(sc) + }) +} diff --git a/pkg/api/dashboard_snapshot.go b/pkg/api/dashboard_snapshot.go index a834bd4717d..c10302faf32 100644 --- a/pkg/api/dashboard_snapshot.go +++ b/pkg/api/dashboard_snapshot.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -56,6 +57,7 @@ func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapsho }) } +// GET /api/snapshots/:key func GetDashboardSnapshot(c *middleware.Context) { key := c.Params(":key") query := &m.GetDashboardSnapshotQuery{Key: key} @@ -90,18 +92,43 @@ func GetDashboardSnapshot(c *middleware.Context) { c.JSON(200, dto) } -func DeleteDashboardSnapshot(c *middleware.Context) { +// GET /api/snapshots-delete/:key +func DeleteDashboardSnapshot(c *middleware.Context) Response { key := c.Params(":key") + + query := &m.GetDashboardSnapshotQuery{DeleteKey: key} + + err := bus.Dispatch(query) + if err != nil { + return ApiError(500, "Failed to get dashboard snapshot", err) + } + + if query.Result == nil { + return ApiError(404, "Failed to get dashboard snapshot", nil) + } + dashboard := query.Result.Dashboard + dashboardId := dashboard.Get("id").MustInt64() + + guardian := guardian.New(dashboardId, c.OrgId, c.SignedInUser) + canEdit, err := guardian.CanEdit() + if err != nil { + return ApiError(500, "Error while checking permissions for snapshot", err) + } + + if !canEdit && query.Result.UserId != c.SignedInUser.UserId { + return ApiError(403, "Access denied to this snapshot", nil) + } + cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: key} if err := bus.Dispatch(cmd); err != nil { - c.JsonApiErr(500, "Failed to delete dashboard snapshot", err) - return + return ApiError(500, "Failed to delete dashboard snapshot", err) } - c.JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from a CDN cache."}) + return Json(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from a CDN cache."}) } +// GET /api/dashboard/snapshots func SearchDashboardSnapshots(c *middleware.Context) Response { query := c.Query("query") limit := c.QueryInt("limit") @@ -111,9 +138,10 @@ func SearchDashboardSnapshots(c *middleware.Context) Response { } searchQuery := m.GetDashboardSnapshotsQuery{ - Name: query, - Limit: limit, - OrgId: c.OrgId, + Name: query, + Limit: limit, + OrgId: c.OrgId, + SignedInUser: c.SignedInUser, } err := bus.Dispatch(&searchQuery) diff --git a/pkg/api/dashboard_snapshot_test.go b/pkg/api/dashboard_snapshot_test.go new file mode 100644 index 00000000000..87c2b9e99d4 --- /dev/null +++ b/pkg/api/dashboard_snapshot_test.go @@ -0,0 +1,97 @@ +package api + +import ( + "testing" + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestDashboardSnapshotApiEndpoint(t *testing.T) { + Convey("Given a single snapshot", t, func() { + jsonModel, _ := simplejson.NewJson([]byte(`{"id":100}`)) + + mockSnapshotResult := &m.DashboardSnapshot{ + Id: 1, + Dashboard: jsonModel, + Expires: time.Now().Add(time.Duration(1000) * time.Second), + UserId: 999999, + } + + bus.AddHandler("test", func(query *m.GetDashboardSnapshotQuery) error { + query.Result = mockSnapshotResult + return nil + }) + + bus.AddHandler("test", func(cmd *m.DeleteDashboardSnapshotCommand) error { + return nil + }) + + viewerRole := m.ROLE_VIEWER + editorRole := m.ROLE_EDITOR + aclMockResp := []*m.DashboardAclInfoDTO{} + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = aclMockResp + return nil + }) + + teamResp := []*m.Team{} + bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error { + query.Result = teamResp + return nil + }) + + Convey("When user has editor role and is not in the ACL", func() { + Convey("Should not be able to delete snapshot", func() { + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:key", m.ROLE_EDITOR, func(sc *scenarioContext) { + sc.handlerFunc = DeleteDashboardSnapshot + sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec() + + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + }) + + Convey("When user is editor and dashboard has default ACL", func() { + aclMockResp = []*m.DashboardAclInfoDTO{ + {Role: &viewerRole, Permission: m.PERMISSION_VIEW}, + {Role: &editorRole, Permission: m.PERMISSION_EDIT}, + } + + Convey("Should be able to delete a snapshot", func() { + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:key", m.ROLE_EDITOR, func(sc *scenarioContext) { + sc.handlerFunc = DeleteDashboardSnapshot + sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec() + + So(sc.resp.Code, ShouldEqual, 200) + respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes()) + So(err, ShouldBeNil) + + So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted") + }) + }) + }) + + Convey("When user is editor and is the creator of the snapshot", func() { + aclMockResp = []*m.DashboardAclInfoDTO{} + mockSnapshotResult.UserId = TestUserID + + Convey("Should be able to delete a snapshot", func() { + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:key", m.ROLE_EDITOR, func(sc *scenarioContext) { + sc.handlerFunc = DeleteDashboardSnapshot + sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec() + + So(sc.resp.Code, ShouldEqual, 200) + respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes()) + So(err, ShouldBeNil) + + So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted") + }) + }) + }) + }) +} diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go new file mode 100644 index 00000000000..3857fa0b9e1 --- /dev/null +++ b/pkg/api/dashboard_test.go @@ -0,0 +1,912 @@ +package api + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/setting" + + . "github.com/smartystreets/goconvey/convey" +) + +// This tests three main scenarios. +// If a user has access to execute an action on a dashboard: +// 1. and the dashboard is in a folder which does not have an acl +// 2. and the dashboard is in a folder which does have an acl +// 3. Post dashboard response tests + +func TestDashboardApiEndpoint(t *testing.T) { + Convey("Given a dashboard with a parent folder which does not have an acl", t, func() { + fakeDash := m.NewDashboard("Child dash") + fakeDash.Id = 1 + fakeDash.FolderId = 1 + fakeDash.HasAcl = false + + bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error { + dashboards := []*m.Dashboard{fakeDash} + query.Result = dashboards + return nil + }) + + var getDashboardQueries []*m.GetDashboardQuery + + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = fakeDash + getDashboardQueries = append(getDashboardQueries, query) + return nil + }) + + viewerRole := m.ROLE_VIEWER + editorRole := m.ROLE_EDITOR + + aclMockResp := []*m.DashboardAclInfoDTO{ + {Role: &viewerRole, Permission: m.PERMISSION_VIEW}, + {Role: &editorRole, Permission: m.PERMISSION_EDIT}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = aclMockResp + return nil + }) + + bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error { + query.Result = []*m.Team{} + return nil + }) + + // This tests two scenarios: + // 1. user is an org viewer + // 2. user is an org editor + + Convey("When user is an Org Viewer", func() { + role := m.ROLE_VIEWER + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should not be able to edit or save dashboard", func() { + So(dash.Meta.CanEdit, ShouldBeFalse) + So(dash.Meta.CanSave, ShouldBeFalse) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should not be able to edit or save dashboard", func() { + So(dash.Meta.CanEdit, ShouldBeFalse) + So(dash.Meta.CanSave, ShouldBeFalse) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + Convey("When user is an Org Editor", func() { + role := m.ROLE_EDITOR + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should be able to edit or save dashboard", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeTrue) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should be able to edit or save dashboard", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeTrue) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 200) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 200) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + }) + + Convey("Given a dashboard with a parent folder which has an acl", t, func() { + fakeDash := m.NewDashboard("Child dash") + fakeDash.Id = 1 + fakeDash.FolderId = 1 + fakeDash.HasAcl = true + setting.ViewersCanEdit = false + + bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error { + dashboards := []*m.Dashboard{fakeDash} + query.Result = dashboards + return nil + }) + + aclMockResp := []*m.DashboardAclInfoDTO{ + { + DashboardId: 1, + Permission: m.PERMISSION_EDIT, + UserId: 200, + }, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = aclMockResp + return nil + }) + + var getDashboardQueries []*m.GetDashboardQuery + + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = fakeDash + getDashboardQueries = append(getDashboardQueries, query) + return nil + }) + + bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error { + query.Result = []*m.Team{} + return nil + }) + + // This tests six scenarios: + // 1. user is an org viewer AND has no permissions for this dashboard + // 2. user is an org editor AND has no permissions for this dashboard + // 3. user is an org viewer AND has been granted edit permission for the dashboard + // 4. user is an org viewer AND all viewers have edit permission for this dashboard + // 5. user is an org viewer AND has been granted an admin permission + // 6. user is an org editor AND has been granted a view permission + + Convey("When user is an Org Viewer and has no permissions for this dashboard", func() { + role := m.ROLE_VIEWER + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + sc.handlerFunc = GetDashboard + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should be denied access", func() { + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + sc.handlerFunc = GetDashboard + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should be denied access", func() { + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + Convey("When user is an Org Editor and has no permissions for this dashboard", func() { + role := m.ROLE_EDITOR + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + sc.handlerFunc = GetDashboard + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should be denied access", func() { + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + sc.handlerFunc = GetDashboard + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should be denied access", func() { + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + Convey("When user is an Org Viewer but has an edit permission", func() { + role := m.ROLE_VIEWER + + mockResult := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_EDIT}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = mockResult + return nil + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should be able to get dashboard with edit rights", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeTrue) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should be able to get dashboard with edit rights", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeTrue) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 200) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 200) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + + Convey("When user is an Org Viewer and viewers can edit", func() { + role := m.ROLE_VIEWER + setting.ViewersCanEdit = true + + mockResult := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = mockResult + return nil + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should be able to get dashboard with edit rights but can save should be false", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeFalse) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should be able to get dashboard with edit rights but can save should be false", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeFalse) + So(dash.Meta.CanAdmin, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + }) + + Convey("When user is an Org Viewer but has an admin permission", func() { + role := m.ROLE_VIEWER + + mockResult := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = mockResult + return nil + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should be able to get dashboard with edit rights", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeTrue) + So(dash.Meta.CanAdmin, ShouldBeTrue) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should be able to get dashboard with edit rights", func() { + So(dash.Meta.CanEdit, ShouldBeTrue) + So(dash.Meta.CanSave, ShouldBeTrue) + So(dash.Meta.CanAdmin, ShouldBeTrue) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 200) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 200) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + + Convey("When user is an Org Editor but has a view permission", func() { + role := m.ROLE_EDITOR + + mockResult := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = mockResult + return nil + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + + Convey("Should not be able to edit or save dashboard", func() { + So(dash.Meta.CanEdit, ShouldBeFalse) + So(dash.Meta.CanSave, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + dash := GetDashboardShouldReturn200(sc) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + + Convey("Should not be able to edit or save dashboard", func() { + So(dash.Meta.CanEdit, ShouldBeFalse) + So(dash.Meta.CanSave, ShouldBeFalse) + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/child-dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by slug", func() { + So(getDashboardQueries[0].Slug, ShouldEqual, "child-dash") + }) + }) + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { + CallDeleteDashboardByUid(sc) + So(sc.resp.Code, ShouldEqual, 403) + + Convey("Should lookup dashboard by uid", func() { + So(getDashboardQueries[0].Uid, ShouldEqual, "abcdefghi") + }) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { + CallGetDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { + CallGetDashboardVersions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + }) + + Convey("Given two dashboards with the same title in different folders", t, func() { + dashOne := m.NewDashboard("dash") + dashOne.Id = 2 + dashOne.FolderId = 1 + dashOne.HasAcl = false + + dashTwo := m.NewDashboard("dash") + dashTwo.Id = 4 + dashTwo.FolderId = 3 + dashTwo.HasAcl = false + + bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error { + dashboards := []*m.Dashboard{dashOne, dashTwo} + query.Result = dashboards + return nil + }) + + role := m.ROLE_EDITOR + + loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/db/dash", "/api/dashboards/db/:slug", role, func(sc *scenarioContext) { + CallDeleteDashboard(sc) + + Convey("Should result in 412 Precondition failed", func() { + So(sc.resp.Code, ShouldEqual, 412) + result := sc.ToJson() + So(result.Get("status").MustString(), ShouldEqual, "multiple-slugs-exists") + So(result.Get("message").MustString(), ShouldEqual, m.ErrDashboardsWithSameSlugExists.Error()) + }) + }) + }) + + Convey("Post dashboard response tests", t, func() { + + // This tests that a valid request returns correct response + + Convey("Given a correct request for creating a dashboard", func() { + cmd := m.SaveDashboardCommand{ + OrgId: 1, + UserId: 5, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash", + }), + Overwrite: true, + FolderId: 3, + IsFolder: false, + Message: "msg", + } + + mock := &dashboards.FakeDashboardService{ + SaveDashboardResult: &m.Dashboard{ + Id: 2, + Uid: "uid", + Title: "Dash", + Slug: "dash", + Version: 2, + }, + } + + postDashboardScenario("When calling POST on", "/api/dashboards", "/api/dashboards", mock, cmd, func(sc *scenarioContext) { + CallPostDashboardShouldReturnSuccess(sc) + + Convey("It should call dashboard service with correct data", func() { + dto := mock.SavedDashboards[0] + So(dto.OrgId, ShouldEqual, cmd.OrgId) + So(dto.User.UserId, ShouldEqual, cmd.UserId) + So(dto.Dashboard.FolderId, ShouldEqual, 3) + So(dto.Dashboard.Title, ShouldEqual, "Dash") + So(dto.Overwrite, ShouldBeTrue) + So(dto.Message, ShouldEqual, "msg") + }) + + Convey("It should return correct response data", func() { + result := sc.ToJson() + So(result.Get("status").MustString(), ShouldEqual, "success") + So(result.Get("id").MustInt64(), ShouldEqual, 2) + So(result.Get("uid").MustString(), ShouldEqual, "uid") + So(result.Get("slug").MustString(), ShouldEqual, "dash") + So(result.Get("url").MustString(), ShouldEqual, "/d/uid/dash") + }) + }) + }) + + // This tests that invalid requests returns expected error responses + + Convey("Given incorrect requests for creating a dashboard", func() { + testCases := []struct { + SaveError error + ExpectedStatusCode int + }{ + {SaveError: m.ErrDashboardNotFound, ExpectedStatusCode: 404}, + {SaveError: m.ErrFolderNotFound, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardWithSameUIDExists, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: 412}, + {SaveError: m.ErrDashboardVersionMismatch, ExpectedStatusCode: 412}, + {SaveError: m.ErrDashboardTitleEmpty, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardContainsInvalidAlertData, ExpectedStatusCode: 500}, + {SaveError: m.ErrDashboardFailedToUpdateAlertData, ExpectedStatusCode: 500}, + {SaveError: m.ErrDashboardFailedGenerateUniqueUid, ExpectedStatusCode: 500}, + {SaveError: m.ErrDashboardTypeMismatch, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardFolderNameExists, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403}, + {SaveError: m.ErrDashboardInvalidUid, ExpectedStatusCode: 400}, + {SaveError: m.ErrDashboardUidToLong, ExpectedStatusCode: 400}, + {SaveError: m.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412}, + } + + cmd := m.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "", + }), + } + + for _, tc := range testCases { + mock := &dashboards.FakeDashboardService{ + SaveDashboardError: tc.SaveError, + } + + postDashboardScenario(fmt.Sprintf("Expect '%s' error when calling POST on", tc.SaveError.Error()), "/api/dashboards", "/api/dashboards", mock, cmd, func(sc *scenarioContext) { + CallPostDashboard(sc) + So(sc.resp.Code, ShouldEqual, tc.ExpectedStatusCode) + }) + } + }) + }) + + Convey("Given two dashboards being compared", t, func() { + mockResult := []*m.DashboardAclInfoDTO{} + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = mockResult + return nil + }) + + bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error { + query.Result = &m.DashboardVersion{ + Data: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash" + string(query.DashboardId), + }), + } + return nil + }) + + cmd := dtos.CalculateDiffOptions{ + Base: dtos.CalculateDiffTarget{ + DashboardId: 1, + Version: 1, + }, + New: dtos.CalculateDiffTarget{ + DashboardId: 2, + Version: 2, + }, + DiffType: "basic", + } + + Convey("when user does not have permission", func() { + role := m.ROLE_VIEWER + + postDiffScenario("When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) { + CallPostDashboard(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + }) + + Convey("when user does have permission", func() { + role := m.ROLE_ADMIN + + postDiffScenario("When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) { + CallPostDashboard(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + }) + }) +} + +func GetDashboardShouldReturn200(sc *scenarioContext) dtos.DashboardFullWithMeta { + CallGetDashboard(sc) + + So(sc.resp.Code, ShouldEqual, 200) + + dash := dtos.DashboardFullWithMeta{} + err := json.NewDecoder(sc.resp.Body).Decode(&dash) + So(err, ShouldBeNil) + + return dash +} + +func CallGetDashboard(sc *scenarioContext) { + sc.handlerFunc = GetDashboard + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() +} + +func CallGetDashboardVersion(sc *scenarioContext) { + bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error { + query.Result = &m.DashboardVersion{} + return nil + }) + + sc.handlerFunc = GetDashboardVersion + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() +} + +func CallGetDashboardVersions(sc *scenarioContext) { + bus.AddHandler("test", func(query *m.GetDashboardVersionsQuery) error { + query.Result = []*m.DashboardVersionDTO{} + return nil + }) + + sc.handlerFunc = GetDashboardVersions + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() +} + +func CallDeleteDashboard(sc *scenarioContext) { + bus.AddHandler("test", func(cmd *m.DeleteDashboardCommand) error { + return nil + }) + + sc.handlerFunc = DeleteDashboard + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() +} + +func CallDeleteDashboardByUid(sc *scenarioContext) { + bus.AddHandler("test", func(cmd *m.DeleteDashboardCommand) error { + return nil + }) + + sc.handlerFunc = DeleteDashboardByUid + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() +} + +func CallPostDashboard(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() +} + +func CallPostDashboardShouldReturnSuccess(sc *scenarioContext) { + CallPostDashboard(sc) + + So(sc.resp.Code, ShouldEqual, 200) +} + +func postDashboardScenario(desc string, url string, routePattern string, mock *dashboards.FakeDashboardService, cmd m.SaveDashboardCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.SignedInUser = &m.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId} + + return PostDashboard(c, cmd) + }) + + origNewDashboardService := dashboards.NewService + dashboards.MockDashboardService(mock) + + sc.m.Post(routePattern, sc.defaultHandler) + + defer func() { + dashboards.NewService = origNewDashboardService + }() + + fn(sc) + }) +} + +func postDiffScenario(desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions, role m.RoleType, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.SignedInUser = &m.SignedInUser{ + OrgId: TestOrgID, + UserId: TestUserID, + } + sc.context.OrgRole = role + + return CalculateDashboardDiff(c, cmd) + }) + + sc.m.Post(routePattern, sc.defaultHandler) + + fn(sc) + }) +} + +func (sc *scenarioContext) ToJson() *simplejson.Json { + var result *simplejson.Json + err := json.NewDecoder(sc.resp.Body).Decode(&result) + So(err, ShouldBeNil) + return result +} diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go index 5ae752bea91..490393727d6 100644 --- a/pkg/api/datasources_test.go +++ b/pkg/api/datasources_test.go @@ -2,17 +2,11 @@ package api import ( "encoding/json" - "net/http" - "net/http/httptest" - "path/filepath" "testing" "github.com/grafana/grafana/pkg/models" - macaron "gopkg.in/macaron.v1" - "github.com/go-macaron/session" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/middleware" . "github.com/smartystreets/goconvey/convey" ) @@ -54,79 +48,3 @@ func TestDataSourcesProxy(t *testing.T) { }) }) } - -func loggedInUserScenario(desc string, url string, fn scenarioFunc) { - Convey(desc+" "+url, func() { - defer bus.ClearBusHandlers() - - sc := &scenarioContext{ - url: url, - } - viewsPath, _ := filepath.Abs("../../public/views") - - sc.m = macaron.New() - sc.m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: viewsPath, - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) - - sc.m.Use(middleware.GetContextHandler()) - sc.m.Use(middleware.Sessioner(&session.Options{})) - - sc.defaultHandler = wrap(func(c *middleware.Context) Response { - sc.context = c - sc.context.UserId = TestUserID - sc.context.OrgId = TestOrgID - sc.context.OrgRole = models.ROLE_EDITOR - if sc.handlerFunc != nil { - return sc.handlerFunc(sc.context) - } - - return nil - }) - - sc.m.Get(url, sc.defaultHandler) - - fn(sc) - }) -} - -func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext { - sc.resp = httptest.NewRecorder() - req, err := http.NewRequest(method, url, nil) - So(err, ShouldBeNil) - sc.req = req - - return sc -} - -func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext { - sc.resp = httptest.NewRecorder() - req, err := http.NewRequest(method, url, nil) - q := req.URL.Query() - for k, v := range queryParams { - q.Add(k, v) - } - req.URL.RawQuery = q.Encode() - So(err, ShouldBeNil) - sc.req = req - - return sc -} - -type scenarioContext struct { - m *macaron.Macaron - context *middleware.Context - resp *httptest.ResponseRecorder - handlerFunc handlerFunc - defaultHandler macaron.Handler - req *http.Request - url string -} - -func (sc *scenarioContext) exec() { - sc.m.ServeHTTP(sc.resp, sc.req) -} - -type scenarioFunc func(c *scenarioContext) -type handlerFunc func(c *middleware.Context) Response diff --git a/pkg/api/dtos/acl.go b/pkg/api/dtos/acl.go new file mode 100644 index 00000000000..6c74e68ce0d --- /dev/null +++ b/pkg/api/dtos/acl.go @@ -0,0 +1,16 @@ +package dtos + +import ( + m "github.com/grafana/grafana/pkg/models" +) + +type UpdateDashboardAclCommand struct { + Items []DashboardAclUpdateItem `json:"items"` +} + +type DashboardAclUpdateItem struct { + UserId int64 `json:"userId"` + TeamId int64 `json:"teamId"` + Role *m.RoleType `json:"role,omitempty"` + Permission m.PermissionType `json:"permission"` +} diff --git a/pkg/api/dtos/alerting.go b/pkg/api/dtos/alerting.go index 4285ebc89cc..d30f2697f3f 100644 --- a/pkg/api/dtos/alerting.go +++ b/pkg/api/dtos/alerting.go @@ -19,7 +19,8 @@ type AlertRule struct { EvalDate time.Time `json:"evalDate"` EvalData *simplejson.Json `json:"evalData"` ExecutionError string `json:"executionError"` - DashbboardUri string `json:"dashboardUri"` + Url string `json:"url"` + CanEdit bool `json:"canEdit"` } type AlertNotification struct { diff --git a/pkg/api/dtos/dashboard.go b/pkg/api/dtos/dashboard.go index 9ef9a96edc4..e4c66aebbda 100644 --- a/pkg/api/dtos/dashboard.go +++ b/pkg/api/dtos/dashboard.go @@ -7,20 +7,27 @@ import ( ) type DashboardMeta struct { - IsStarred bool `json:"isStarred,omitempty"` - IsHome bool `json:"isHome,omitempty"` - IsSnapshot bool `json:"isSnapshot,omitempty"` - Type string `json:"type,omitempty"` - CanSave bool `json:"canSave"` - CanEdit bool `json:"canEdit"` - CanStar bool `json:"canStar"` - Slug string `json:"slug"` - Expires time.Time `json:"expires"` - Created time.Time `json:"created"` - Updated time.Time `json:"updated"` - UpdatedBy string `json:"updatedBy"` - CreatedBy string `json:"createdBy"` - Version int `json:"version"` + IsStarred bool `json:"isStarred,omitempty"` + IsHome bool `json:"isHome,omitempty"` + IsSnapshot bool `json:"isSnapshot,omitempty"` + Type string `json:"type,omitempty"` + CanSave bool `json:"canSave"` + CanEdit bool `json:"canEdit"` + CanAdmin bool `json:"canAdmin"` + CanStar bool `json:"canStar"` + Slug string `json:"slug"` + Url string `json:"url"` + Expires time.Time `json:"expires"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` + UpdatedBy string `json:"updatedBy"` + CreatedBy string `json:"createdBy"` + Version int `json:"version"` + HasAcl bool `json:"hasAcl"` + IsFolder bool `json:"isFolder"` + FolderId int64 `json:"folderId"` + FolderTitle string `json:"folderTitle"` + FolderUrl string `json:"folderUrl"` } type DashboardFullWithMeta struct { diff --git a/pkg/api/dtos/folder.go b/pkg/api/dtos/folder.go new file mode 100644 index 00000000000..469656c6f8f --- /dev/null +++ b/pkg/api/dtos/folder.go @@ -0,0 +1,25 @@ +package dtos + +import "time" + +type Folder struct { + Id int64 `json:"id"` + Uid string `json:"uid"` + Title string `json:"title"` + Url string `json:"url"` + HasAcl bool `json:"hasAcl"` + CanSave bool `json:"canSave"` + CanEdit bool `json:"canEdit"` + CanAdmin bool `json:"canAdmin"` + CreatedBy string `json:"createdBy"` + Created time.Time `json:"created"` + UpdatedBy string `json:"updatedBy"` + Updated time.Time `json:"updated"` + Version int `json:"version"` +} + +type FolderSearchHit struct { + Id int64 `json:"id"` + Uid string `json:"uid"` + Title string `json:"title"` +} diff --git a/pkg/api/dtos/index.go b/pkg/api/dtos/index.go index b813c78f2bb..8c7f505277d 100644 --- a/pkg/api/dtos/index.go +++ b/pkg/api/dtos/index.go @@ -7,9 +7,10 @@ type IndexViewData struct { AppSubUrl string GoogleAnalyticsId string GoogleTagManagerId string - MainNavLinks []*NavLink + NavTree []*NavLink BuildVersion string BuildCommit string + Theme string NewGrafanaVersionExists bool NewGrafanaVersion string } @@ -20,10 +21,16 @@ type PluginCss struct { } type NavLink struct { - Text string `json:"text,omitempty"` - Icon string `json:"icon,omitempty"` - Img string `json:"img,omitempty"` - Url string `json:"url,omitempty"` - Divider bool `json:"divider,omitempty"` - Children []*NavLink `json:"children,omitempty"` + Id string `json:"id,omitempty"` + Text string `json:"text,omitempty"` + Description string `json:"description,omitempty"` + SubTitle string `json:"subTitle,omitempty"` + Icon string `json:"icon,omitempty"` + Img string `json:"img,omitempty"` + Url string `json:"url,omitempty"` + Target string `json:"target,omitempty"` + Divider bool `json:"divider,omitempty"` + HideFromMenu bool `json:"hideFromMenu,omitempty"` + HideFromTabs bool `json:"hideFromTabs,omitempty"` + Children []*NavLink `json:"children,omitempty"` } diff --git a/pkg/api/dtos/invite.go b/pkg/api/dtos/invite.go index 3f002a8b157..09d53f576b4 100644 --- a/pkg/api/dtos/invite.go +++ b/pkg/api/dtos/invite.go @@ -6,7 +6,7 @@ type AddInviteForm struct { LoginOrEmail string `json:"loginOrEmail" binding:"Required"` Name string `json:"name"` Role m.RoleType `json:"role" binding:"Required"` - SkipEmails bool `json:"skipEmails"` + SendEmail bool `json:"sendEmail"` } type InviteInfo struct { diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index e2aa12249aa..a702b06fad5 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -3,6 +3,7 @@ package dtos import ( "crypto/md5" "fmt" + "regexp" "strings" "github.com/grafana/grafana/pkg/components/simplejson" @@ -27,6 +28,7 @@ type CurrentUser struct { Email string `json:"email"` Name string `json:"name"` LightTheme bool `json:"lightTheme"` + OrgCount int `json:"orgCount"` OrgId int64 `json:"orgId"` OrgName string `json:"orgName"` OrgRole m.RoleType `json:"orgRole"` @@ -56,3 +58,19 @@ func GetGravatarUrl(text string) string { hasher.Write([]byte(strings.ToLower(text))) return fmt.Sprintf(setting.AppSubUrl+"/avatar/%x", hasher.Sum(nil)) } + +func GetGravatarUrlWithDefault(text string, defaultText string) string { + if text != "" { + return GetGravatarUrl(text) + } + + reg, err := regexp.Compile("[^a-zA-Z0-9]+") + + if err != nil { + return "" + } + + text = reg.ReplaceAllString(defaultText, "") + "@localhost" + + return GetGravatarUrl(text) +} diff --git a/pkg/api/folder.go b/pkg/api/folder.go new file mode 100644 index 00000000000..e3c4f127569 --- /dev/null +++ b/pkg/api/folder.go @@ -0,0 +1,147 @@ +package api + +import ( + "fmt" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/guardian" + "github.com/grafana/grafana/pkg/util" +) + +func GetFolders(c *middleware.Context) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folders, err := s.GetFolders(c.QueryInt("limit")) + + if err != nil { + return toFolderError(err) + } + + result := make([]dtos.FolderSearchHit, 0) + + for _, f := range folders { + result = append(result, dtos.FolderSearchHit{ + Id: f.Id, + Uid: f.Uid, + Title: f.Title, + }) + } + + return Json(200, result) +} + +func GetFolderByUid(c *middleware.Context) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folder, err := s.GetFolderByUid(c.Params(":uid")) + + if err != nil { + return toFolderError(err) + } + + g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) + return Json(200, toFolderDto(g, folder)) +} + +func GetFolderById(c *middleware.Context) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folder, err := s.GetFolderById(c.ParamsInt64(":id")) + if err != nil { + return toFolderError(err) + } + + g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) + return Json(200, toFolderDto(g, folder)) +} + +func CreateFolder(c *middleware.Context, cmd m.CreateFolderCommand) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + err := s.CreateFolder(&cmd) + if err != nil { + return toFolderError(err) + } + + g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser) + return Json(200, toFolderDto(g, cmd.Result)) +} + +func UpdateFolder(c *middleware.Context, cmd m.UpdateFolderCommand) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + err := s.UpdateFolder(c.Params(":uid"), &cmd) + if err != nil { + return toFolderError(err) + } + + g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser) + return Json(200, toFolderDto(g, cmd.Result)) +} + +func DeleteFolder(c *middleware.Context) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + f, err := s.DeleteFolder(c.Params(":uid")) + if err != nil { + return toFolderError(err) + } + + return Json(200, util.DynMap{ + "title": f.Title, + "message": fmt.Sprintf("Folder %s deleted", f.Title), + }) +} + +func toFolderDto(g guardian.DashboardGuardian, folder *m.Folder) dtos.Folder { + canEdit, _ := g.CanEdit() + canSave, _ := g.CanSave() + canAdmin, _ := g.CanAdmin() + + // Finding creator and last updater of the folder + updater, creator := "Anonymous", "Anonymous" + if folder.CreatedBy > 0 { + creator = getUserLogin(folder.CreatedBy) + } + if folder.UpdatedBy > 0 { + updater = getUserLogin(folder.UpdatedBy) + } + + return dtos.Folder{ + Id: folder.Id, + Uid: folder.Uid, + Title: folder.Title, + Url: folder.Url, + HasAcl: folder.HasAcl, + CanSave: canSave, + CanEdit: canEdit, + CanAdmin: canAdmin, + CreatedBy: creator, + Created: folder.Created, + UpdatedBy: updater, + Updated: folder.Updated, + Version: folder.Version, + } +} + +func toFolderError(err error) Response { + if err == m.ErrFolderTitleEmpty || + err == m.ErrFolderSameNameExists || + err == m.ErrFolderWithSameUIDExists || + err == m.ErrDashboardTypeMismatch || + err == m.ErrDashboardInvalidUid || + err == m.ErrDashboardUidToLong { + return ApiError(400, err.Error(), nil) + } + + if err == m.ErrFolderAccessDenied { + return ApiError(403, "Access denied", err) + } + + if err == m.ErrFolderNotFound { + return Json(404, util.DynMap{"status": "not-found", "message": m.ErrFolderNotFound.Error()}) + } + + if err == m.ErrFolderVersionMismatch { + return Json(412, util.DynMap{"status": "version-mismatch", "message": m.ErrFolderVersionMismatch.Error()}) + } + + return ApiError(500, "Folder API error", err) +} diff --git a/pkg/api/folder_permission.go b/pkg/api/folder_permission.go new file mode 100644 index 00000000000..7c8aba87337 --- /dev/null +++ b/pkg/api/folder_permission.go @@ -0,0 +1,108 @@ +package api + +import ( + "time" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/guardian" +) + +func GetFolderPermissionList(c *middleware.Context) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folder, err := s.GetFolderByUid(c.Params(":uid")) + + if err != nil { + return toFolderError(err) + } + + g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) + + if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin { + return toFolderError(m.ErrFolderAccessDenied) + } + + acl, err := g.GetAcl() + if err != nil { + return ApiError(500, "Failed to get folder permissions", err) + } + + for _, perm := range acl { + perm.FolderId = folder.Id + perm.DashboardId = 0 + + if perm.Slug != "" { + perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug) + } + } + + return Json(200, acl) +} + +func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCommand) Response { + s := dashboards.NewFolderService(c.OrgId, c.SignedInUser) + folder, err := s.GetFolderByUid(c.Params(":uid")) + + if err != nil { + return toFolderError(err) + } + + g := guardian.New(folder.Id, c.OrgId, c.SignedInUser) + canAdmin, err := g.CanAdmin() + if err != nil { + return toFolderError(err) + } + + if !canAdmin { + return toFolderError(m.ErrFolderAccessDenied) + } + + cmd := m.UpdateDashboardAclCommand{} + cmd.DashboardId = folder.Id + + for _, item := range apiCmd.Items { + cmd.Items = append(cmd.Items, &m.DashboardAcl{ + OrgId: c.OrgId, + DashboardId: folder.Id, + UserId: item.UserId, + TeamId: item.TeamId, + Role: item.Role, + Permission: item.Permission, + Created: time.Now(), + Updated: time.Now(), + }) + } + + if okToUpdate, err := g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, cmd.Items); err != nil || !okToUpdate { + if err != nil { + if err == guardian.ErrGuardianPermissionExists || + err == guardian.ErrGuardianOverride { + return ApiError(400, err.Error(), err) + } + + return ApiError(500, "Error while checking folder permissions", err) + } + + return ApiError(403, "Cannot remove own admin permission for a folder", nil) + } + + if err := bus.Dispatch(&cmd); err != nil { + if err == m.ErrDashboardAclInfoMissing { + err = m.ErrFolderAclInfoMissing + } + if err == m.ErrDashboardPermissionDashboardEmpty { + err = m.ErrFolderPermissionFolderEmpty + } + + if err == m.ErrFolderAclInfoMissing || err == m.ErrFolderPermissionFolderEmpty { + return ApiError(409, err.Error(), err) + } + + return ApiError(500, "Failed to create permission", err) + } + + return ApiSuccess("Folder permissions updated") +} diff --git a/pkg/api/folder_permission_test.go b/pkg/api/folder_permission_test.go new file mode 100644 index 00000000000..552577963b4 --- /dev/null +++ b/pkg/api/folder_permission_test.go @@ -0,0 +1,242 @@ +package api + +import ( + "testing" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/guardian" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestFolderPermissionApiEndpoint(t *testing.T) { + Convey("Folder permissions test", t, func() { + Convey("Given folder not exists", func() { + mock := &fakeFolderService{ + GetFolderByUidError: m.ErrFolderNotFound, + } + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) { + callGetFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 404) + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) { + callUpdateFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 404) + }) + + Reset(func() { + dashboards.NewFolderService = origNewFolderService + }) + }) + + Convey("Given user has no admin permissions", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false}) + + mock := &fakeFolderService{ + GetFolderByUidResult: &m.Folder{ + Id: 1, + Uid: "uid", + Title: "Folder", + }, + } + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", m.ROLE_EDITOR, func(sc *scenarioContext) { + callGetFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) { + callUpdateFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 403) + }) + + Reset(func() { + guardian.New = origNewGuardian + dashboards.NewFolderService = origNewFolderService + }) + }) + + Convey("Given user has admin permissions and permissions to update", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ + CanAdminValue: true, + CheckPermissionBeforeUpdateValue: true, + GetAclValue: []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT}, + {OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN}, + {OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, TeamId: 2, Permission: m.PERMISSION_ADMIN}, + }, + }) + + mock := &fakeFolderService{ + GetFolderByUidResult: &m.Folder{ + Id: 1, + Uid: "uid", + Title: "Folder", + }, + } + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", m.ROLE_ADMIN, func(sc *scenarioContext) { + callGetFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 200) + respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes()) + So(err, ShouldBeNil) + So(len(respJSON.MustArray()), ShouldEqual, 5) + So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2) + So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, m.PERMISSION_VIEW) + }) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) { + callUpdateFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 200) + }) + + Reset(func() { + guardian.New = origNewGuardian + dashboards.NewFolderService = origNewFolderService + }) + }) + + Convey("When trying to update permissions with duplicate permissions", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ + CanAdminValue: true, + CheckPermissionBeforeUpdateValue: false, + CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists, + }) + + mock := &fakeFolderService{ + GetFolderByUidResult: &m.Folder{ + Id: 1, + Uid: "uid", + Title: "Folder", + }, + } + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) { + callUpdateFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 400) + }) + + Reset(func() { + guardian.New = origNewGuardian + dashboards.NewFolderService = origNewFolderService + }) + }) + + Convey("When trying to override inherited permissions with lower presedence", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ + CanAdminValue: true, + CheckPermissionBeforeUpdateValue: false, + CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride}, + ) + + mock := &fakeFolderService{ + GetFolderByUidResult: &m.Folder{ + Id: 1, + Uid: "uid", + Title: "Folder", + }, + } + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + cmd := dtos.UpdateDashboardAclCommand{ + Items: []dtos.DashboardAclUpdateItem{ + {UserId: 1000, Permission: m.PERMISSION_ADMIN}, + }, + } + + updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) { + callUpdateFolderPermissions(sc) + So(sc.resp.Code, ShouldEqual, 400) + }) + + Reset(func() { + guardian.New = origNewGuardian + dashboards.NewFolderService = origNewFolderService + }) + }) + }) +} + +func callGetFolderPermissions(sc *scenarioContext) { + sc.handlerFunc = GetFolderPermissionList + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() +} + +func callUpdateFolderPermissions(sc *scenarioContext) { + bus.AddHandler("test", func(cmd *m.UpdateDashboardAclCommand) error { + return nil + }) + + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() +} + +func updateFolderPermissionScenario(desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.OrgId = TestOrgID + sc.context.UserId = TestUserID + + return UpdateFolderPermissions(c, cmd) + }) + + sc.m.Post(routePattern, sc.defaultHandler) + + fn(sc) + }) +} diff --git a/pkg/api/folder_test.go b/pkg/api/folder_test.go new file mode 100644 index 00000000000..0ab3cc7d7c9 --- /dev/null +++ b/pkg/api/folder_test.go @@ -0,0 +1,254 @@ +package api + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + + m "github.com/grafana/grafana/pkg/models" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestFoldersApiEndpoint(t *testing.T) { + Convey("Create/update folder response tests", t, func() { + Convey("Given a correct request for creating a folder", func() { + cmd := m.CreateFolderCommand{ + Uid: "uid", + Title: "Folder", + } + + mock := &fakeFolderService{ + CreateFolderResult: &m.Folder{Id: 1, Uid: "uid", Title: "Folder"}, + } + + createFolderScenario("When calling POST on", "/api/folders", "/api/folders", mock, cmd, func(sc *scenarioContext) { + callCreateFolder(sc) + + Convey("It should return correct response data", func() { + folder := dtos.Folder{} + err := json.NewDecoder(sc.resp.Body).Decode(&folder) + So(err, ShouldBeNil) + So(folder.Id, ShouldEqual, 1) + So(folder.Uid, ShouldEqual, "uid") + So(folder.Title, ShouldEqual, "Folder") + }) + }) + }) + + Convey("Given incorrect requests for creating a folder", func() { + testCases := []struct { + Error error + ExpectedStatusCode int + }{ + {Error: m.ErrFolderWithSameUIDExists, ExpectedStatusCode: 400}, + {Error: m.ErrFolderTitleEmpty, ExpectedStatusCode: 400}, + {Error: m.ErrFolderSameNameExists, ExpectedStatusCode: 400}, + {Error: m.ErrDashboardInvalidUid, ExpectedStatusCode: 400}, + {Error: m.ErrDashboardUidToLong, ExpectedStatusCode: 400}, + {Error: m.ErrFolderAccessDenied, ExpectedStatusCode: 403}, + {Error: m.ErrFolderNotFound, ExpectedStatusCode: 404}, + {Error: m.ErrFolderVersionMismatch, ExpectedStatusCode: 412}, + {Error: m.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500}, + } + + cmd := m.CreateFolderCommand{ + Uid: "uid", + Title: "Folder", + } + + for _, tc := range testCases { + mock := &fakeFolderService{ + CreateFolderError: tc.Error, + } + + createFolderScenario(fmt.Sprintf("Expect '%s' error when calling POST on", tc.Error.Error()), "/api/folders", "/api/folders", mock, cmd, func(sc *scenarioContext) { + callCreateFolder(sc) + if sc.resp.Code != tc.ExpectedStatusCode { + t.Errorf("For error '%s' expected status code %d, actual %d", tc.Error, tc.ExpectedStatusCode, sc.resp.Code) + } + }) + } + }) + + Convey("Given a correct request for updating a folder", func() { + cmd := m.UpdateFolderCommand{ + Title: "Folder upd", + } + + mock := &fakeFolderService{ + UpdateFolderResult: &m.Folder{Id: 1, Uid: "uid", Title: "Folder upd"}, + } + + updateFolderScenario("When calling PUT on", "/api/folders/uid", "/api/folders/:uid", mock, cmd, func(sc *scenarioContext) { + callUpdateFolder(sc) + + Convey("It should return correct response data", func() { + folder := dtos.Folder{} + err := json.NewDecoder(sc.resp.Body).Decode(&folder) + So(err, ShouldBeNil) + So(folder.Id, ShouldEqual, 1) + So(folder.Uid, ShouldEqual, "uid") + So(folder.Title, ShouldEqual, "Folder upd") + }) + }) + }) + + Convey("Given incorrect requests for updating a folder", func() { + testCases := []struct { + Error error + ExpectedStatusCode int + }{ + {Error: m.ErrFolderWithSameUIDExists, ExpectedStatusCode: 400}, + {Error: m.ErrFolderTitleEmpty, ExpectedStatusCode: 400}, + {Error: m.ErrFolderSameNameExists, ExpectedStatusCode: 400}, + {Error: m.ErrDashboardInvalidUid, ExpectedStatusCode: 400}, + {Error: m.ErrDashboardUidToLong, ExpectedStatusCode: 400}, + {Error: m.ErrFolderAccessDenied, ExpectedStatusCode: 403}, + {Error: m.ErrFolderNotFound, ExpectedStatusCode: 404}, + {Error: m.ErrFolderVersionMismatch, ExpectedStatusCode: 412}, + {Error: m.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500}, + } + + cmd := m.UpdateFolderCommand{ + Title: "Folder upd", + } + + for _, tc := range testCases { + mock := &fakeFolderService{ + UpdateFolderError: tc.Error, + } + + updateFolderScenario(fmt.Sprintf("Expect '%s' error when calling PUT on", tc.Error.Error()), "/api/folders/uid", "/api/folders/:uid", mock, cmd, func(sc *scenarioContext) { + callUpdateFolder(sc) + if sc.resp.Code != tc.ExpectedStatusCode { + t.Errorf("For error '%s' expected status code %d, actual %d", tc.Error, tc.ExpectedStatusCode, sc.resp.Code) + } + }) + } + }) + }) +} + +func callGetFolderByUid(sc *scenarioContext) { + sc.handlerFunc = GetFolderByUid + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() +} + +func callDeleteFolder(sc *scenarioContext) { + sc.handlerFunc = DeleteFolder + sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() +} + +func callCreateFolder(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() +} + +func createFolderScenario(desc string, url string, routePattern string, mock *fakeFolderService, cmd m.CreateFolderCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.SignedInUser = &m.SignedInUser{OrgId: TestOrgID, UserId: TestUserID} + + return CreateFolder(c, cmd) + }) + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + sc.m.Post(routePattern, sc.defaultHandler) + + defer func() { + dashboards.NewFolderService = origNewFolderService + }() + + fn(sc) + }) +} + +func callUpdateFolder(sc *scenarioContext) { + sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec() +} + +func updateFolderScenario(desc string, url string, routePattern string, mock *fakeFolderService, cmd m.UpdateFolderCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + sc := setupScenarioContext(url) + sc.defaultHandler = wrap(func(c *middleware.Context) Response { + sc.context = c + sc.context.SignedInUser = &m.SignedInUser{OrgId: TestOrgID, UserId: TestUserID} + + return UpdateFolder(c, cmd) + }) + + origNewFolderService := dashboards.NewFolderService + mockFolderService(mock) + + sc.m.Put(routePattern, sc.defaultHandler) + + defer func() { + dashboards.NewFolderService = origNewFolderService + }() + + fn(sc) + }) +} + +type fakeFolderService struct { + GetFoldersResult []*models.Folder + GetFoldersError error + GetFolderByUidResult *models.Folder + GetFolderByUidError error + GetFolderByIdResult *models.Folder + GetFolderByIdError error + CreateFolderResult *models.Folder + CreateFolderError error + UpdateFolderResult *models.Folder + UpdateFolderError error + DeleteFolderResult *models.Folder + DeleteFolderError error + DeletedFolderUids []string +} + +func (s *fakeFolderService) GetFolders(limit int) ([]*models.Folder, error) { + return s.GetFoldersResult, s.GetFoldersError +} + +func (s *fakeFolderService) GetFolderById(id int64) (*models.Folder, error) { + return s.GetFolderByIdResult, s.GetFolderByIdError +} + +func (s *fakeFolderService) GetFolderByUid(uid string) (*models.Folder, error) { + return s.GetFolderByUidResult, s.GetFolderByUidError +} + +func (s *fakeFolderService) CreateFolder(cmd *models.CreateFolderCommand) error { + cmd.Result = s.CreateFolderResult + return s.CreateFolderError +} + +func (s *fakeFolderService) UpdateFolder(existingUid string, cmd *models.UpdateFolderCommand) error { + cmd.Result = s.UpdateFolderResult + return s.UpdateFolderError +} + +func (s *fakeFolderService) DeleteFolder(uid string) (*models.Folder, error) { + s.DeletedFolderUids = append(s.DeletedFolderUids, uid) + return s.DeleteFolderResult, s.DeleteFolderError +} + +func mockFolderService(mock *fakeFolderService) { + dashboards.NewFolderService = func(orgId int64, user *models.SignedInUser) dashboards.FolderService { + return mock + } +} diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 563f940904e..591dcc62344 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -143,7 +143,6 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro "alertingEnabled": setting.AlertingEnabled, "googleAnalyticsId": setting.GoogleAnalyticsId, "disableLoginForm": setting.DisableLoginForm, - "disableSignoutMenu": setting.DisableSignoutMenu, "externalUserMngInfo": setting.ExternalUserMngInfo, "externalUserMngLinkUrl": setting.ExternalUserMngLinkUrl, "externalUserMngLinkName": setting.ExternalUserMngLinkName, diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 89456d20d8c..b911780913d 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -95,7 +95,7 @@ func (hs *HttpServer) Start(ctx context.Context) error { func (hs *HttpServer) Shutdown(ctx context.Context) error { err := hs.httpSrv.Shutdown(ctx) - hs.log.Info("stopped http server") + hs.log.Info("Stopped HTTP server") return err } @@ -162,6 +162,10 @@ func (hs *HttpServer) newMacaron() *macaron.Macaron { hs.mapStatic(m, setting.StaticRootPath, "", "public") hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt") + if setting.ImageUploadProvider == "local" { + hs.mapStatic(m, setting.ImagesDir, "", "/public/img/attachments") + } + m.Use(macaron.Renderer(macaron.RenderOptions{ Directory: path.Join(setting.StaticRootPath, "views"), IndentJSON: macaron.Env != macaron.PROD, diff --git a/pkg/api/index.go b/pkg/api/index.go index bf7a9fc1759..5beecefab88 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -50,6 +50,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Login: c.Login, Email: c.Email, Name: c.Name, + OrgCount: c.OrgCount, OrgId: c.OrgId, OrgName: c.OrgName, OrgRole: c.OrgRole, @@ -61,6 +62,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { HelpFlags1: c.HelpFlags1, }, Settings: settings, + Theme: prefs.Theme, AppUrl: appUrl, AppSubUrl: appSubUrl, GoogleAnalyticsId: setting.GoogleAnalyticsId, @@ -82,52 +84,77 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { themeUrlParam := c.Query("theme") if themeUrlParam == "light" { data.User.LightTheme = true - } - - dashboardChildNavs := []*dtos.NavLink{ - {Text: "Home", Url: setting.AppSubUrl + "/"}, - {Text: "Playlists", Url: setting.AppSubUrl + "/playlists"}, - {Text: "Snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots"}, + data.Theme = "light" } if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR { - dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{Divider: true}) - dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{Text: "New", Icon: "fa fa-plus", Url: setting.AppSubUrl + "/dashboard/new"}) - dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{Text: "Import", Icon: "fa fa-download", Url: setting.AppSubUrl + "/dashboard/new/?editview=import"}) + data.NavTree = append(data.NavTree, &dtos.NavLink{ + Text: "Create", + Id: "create", + Icon: "fa fa-fw fa-plus", + Url: setting.AppSubUrl + "/dashboard/new", + Children: []*dtos.NavLink{ + {Text: "Dashboard", Icon: "gicon gicon-dashboard-new", Url: setting.AppSubUrl + "/dashboard/new"}, + {Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboards/folder/new"}, + {Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"}, + }, + }) } - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ + dashboardChildNavs := []*dtos.NavLink{ + {Text: "Home", Id: "home", Url: setting.AppSubUrl + "/", Icon: "gicon gicon-home", HideFromTabs: true}, + {Text: "Divider", Divider: true, Id: "divider", HideFromTabs: true}, + {Text: "Manage", Id: "manage-dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "gicon gicon-manage"}, + {Text: "Playlists", Id: "playlists", Url: setting.AppSubUrl + "/playlists", Icon: "gicon gicon-playlists"}, + {Text: "Snapshots", Id: "snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots", Icon: "gicon gicon-snapshots"}, + } + + data.NavTree = append(data.NavTree, &dtos.NavLink{ Text: "Dashboards", - Icon: "icon-gf icon-gf-dashboard", + Id: "dashboards", + SubTitle: "Manage dashboards & folders", + Icon: "gicon gicon-dashboard", Url: setting.AppSubUrl + "/", Children: dashboardChildNavs, }) - if setting.AlertingEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) { - alertChildNavs := []*dtos.NavLink{ - {Text: "Alert List", Url: setting.AppSubUrl + "/alerting/list"}, - {Text: "Notification channels", Url: setting.AppSubUrl + "/alerting/notifications"}, + if c.IsSignedIn { + profileNode := &dtos.NavLink{ + Text: c.SignedInUser.NameOrFallback(), + SubTitle: c.SignedInUser.Login, + Id: "profile", + Img: data.User.GravatarUrl, + Url: setting.AppSubUrl + "/profile", + HideFromMenu: true, + Children: []*dtos.NavLink{ + {Text: "Preferences", Id: "profile-settings", Url: setting.AppSubUrl + "/profile", Icon: "gicon gicon-preferences"}, + {Text: "Change Password", Id: "change-password", Url: setting.AppSubUrl + "/profile/password", Icon: "fa fa-fw fa-lock", HideFromMenu: true}, + }, } - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ - Text: "Alerting", - Icon: "icon-gf icon-gf-alert", - Url: setting.AppSubUrl + "/alerting/list", - Children: alertChildNavs, - }) + if !setting.DisableSignoutMenu { + // add sign out first + profileNode.Children = append(profileNode.Children, &dtos.NavLink{ + Text: "Sign out", Id: "sign-out", Url: setting.AppSubUrl + "/logout", Icon: "fa fa-fw fa-sign-out", Target: "_self", + }) + } + + data.NavTree = append(data.NavTree, profileNode) } - if c.OrgRole == m.ROLE_ADMIN { - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ - Text: "Data Sources", - Icon: "icon-gf icon-gf-datasources", - Url: setting.AppSubUrl + "/datasources", - }) + if setting.AlertingEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) { + alertChildNavs := []*dtos.NavLink{ + {Text: "Alert Rules", Id: "alert-list", Url: setting.AppSubUrl + "/alerting/list", Icon: "gicon gicon-alert-rules"}, + {Text: "Notification channels", Id: "channels", Url: setting.AppSubUrl + "/alerting/notifications", Icon: "gicon gicon-alert-notification-channel"}, + } - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ - Text: "Plugins", - Icon: "icon-gf icon-gf-apps", - Url: setting.AppSubUrl + "/plugins", + data.NavTree = append(data.NavTree, &dtos.NavLink{ + Text: "Alerting", + SubTitle: "Alert rules & notifications", + Id: "alerting", + Icon: "gicon gicon-alert", + Url: setting.AppSubUrl + "/alerting/list", + Children: alertChildNavs, }) } @@ -140,6 +167,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { if plugin.Pinned { appLink := &dtos.NavLink{ Text: plugin.Name, + Id: "plugin-page-" + plugin.Id, Url: plugin.DefaultNavUrl, Img: plugin.Info.Logos.Small, } @@ -168,29 +196,106 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { if len(appLink.Children) > 0 && c.OrgRole == m.ROLE_ADMIN { appLink.Children = append(appLink.Children, &dtos.NavLink{Divider: true}) - appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "fa fa-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/edit"}) + appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "gicon gicon-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/edit"}) } if len(appLink.Children) > 0 { - data.MainNavLinks = append(data.MainNavLinks, appLink) + data.NavTree = append(data.NavTree, appLink) } } } - if c.IsGrafanaAdmin { - data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{ - Text: "Admin", - Icon: "fa fa-fw fa-cogs", - Url: setting.AppSubUrl + "/admin", + if c.OrgRole == m.ROLE_ADMIN { + cfgNode := &dtos.NavLink{ + Id: "cfg", + Text: "Configuration", + SubTitle: "Organization: " + c.OrgName, + Icon: "gicon gicon-cog", + Url: setting.AppSubUrl + "/datasources", Children: []*dtos.NavLink{ - {Text: "Global Users", Url: setting.AppSubUrl + "/admin/users"}, - {Text: "Global Orgs", Url: setting.AppSubUrl + "/admin/orgs"}, - {Text: "Server Settings", Url: setting.AppSubUrl + "/admin/settings"}, - {Text: "Server Stats", Url: setting.AppSubUrl + "/admin/stats"}, + { + Text: "Data Sources", + Icon: "gicon gicon-datasources", + Description: "Add and configure data sources", + Id: "datasources", + Url: setting.AppSubUrl + "/datasources", + }, + { + Text: "Users", + Id: "users", + Description: "Manage org members", + Icon: "gicon gicon-user", + Url: setting.AppSubUrl + "/org/users", + }, + { + Text: "Teams", + Id: "teams", + Description: "Manage org groups", + Icon: "gicon gicon-team", + Url: setting.AppSubUrl + "/org/teams", + }, + { + Text: "Plugins", + Id: "plugins", + Description: "View and configure plugins", + Icon: "gicon gicon-plugins", + Url: setting.AppSubUrl + "/plugins", + }, + { + Text: "Preferences", + Id: "org-settings", + Description: "Organization preferences", + Icon: "gicon gicon-preferences", + Url: setting.AppSubUrl + "/org", + }, + + { + Text: "API Keys", + Id: "apikeys", + Description: "Create & manage API keys", + Icon: "gicon gicon-apikeys", + Url: setting.AppSubUrl + "/org/apikeys", + }, }, - }) + } + + if c.IsGrafanaAdmin { + cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{ + Divider: true, HideFromTabs: true, Id: "admin-divider", Text: "Text", + }) + cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{ + Text: "Server Admin", + HideFromTabs: true, + SubTitle: "Manage all users & orgs", + Id: "admin", + Icon: "gicon gicon-shield", + Url: setting.AppSubUrl + "/admin/users", + Children: []*dtos.NavLink{ + {Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"}, + {Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"}, + {Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"}, + {Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"}, + {Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"}, + }, + }) + } + + data.NavTree = append(data.NavTree, cfgNode) } + data.NavTree = append(data.NavTree, &dtos.NavLink{ + Text: "Help", + Id: "help", + Url: "#", + Icon: "gicon gicon-question", + HideFromMenu: true, + Children: []*dtos.NavLink{ + {Text: "Keyboard shortcuts", Url: "/shortcuts", Icon: "fa fa-fw fa-keyboard-o", Target: "_self"}, + {Text: "Community site", Url: "http://community.grafana.com", Icon: "fa fa-fw fa-comment", Target: "_blank"}, + {Text: "Documentation", Url: "http://docs.grafana.org", Icon: "fa fa-fw fa-file", Target: "_blank"}, + }, + }) + return &data, nil } diff --git a/pkg/api/login.go b/pkg/api/login.go index ebfe672f825..b6855af7baf 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -102,12 +102,13 @@ func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) Response { } authQuery := login.LoginUserQuery{ - Username: cmd.User, - Password: cmd.Password, + Username: cmd.User, + Password: cmd.Password, + IpAddress: c.Req.RemoteAddr, } if err := bus.Dispatch(&authQuery); err != nil { - if err == login.ErrInvalidCredentials { + if err == login.ErrInvalidCredentials || err == login.ErrTooManyLoginAttempts { return ApiError(401, "Invalid username or password", err) } diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 847f09f0eb8..341ff212f10 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -1,6 +1,7 @@ package api import ( + "context" "crypto/rand" "crypto/tls" "crypto/x509" @@ -11,7 +12,6 @@ import ( "net/http" "net/url" - "golang.org/x/net/context" "golang.org/x/oauth2" "github.com/grafana/grafana/pkg/bus" @@ -29,25 +29,25 @@ var ( ErrSignUpNotAllowed = errors.New("Signup is not allowed for this adapter") ErrUsersQuotaReached = errors.New("Users quota reached") ErrNoEmail = errors.New("Login provider didn't return an email address") - oauthLogger = log.New("oauth.login") + oauthLogger = log.New("oauth") ) func GenStateString() string { rnd := make([]byte, 32) rand.Read(rnd) - return base64.StdEncoding.EncodeToString(rnd) + return base64.URLEncoding.EncodeToString(rnd) } func OAuthLogin(ctx *middleware.Context) { if setting.OAuthService == nil { - ctx.Handle(404, "login.OAuthLogin(oauth service not enabled)", nil) + ctx.Handle(404, "OAuth not enabled", nil) return } name := ctx.Params(":name") connect, ok := social.SocialMap[name] if !ok { - ctx.Handle(404, "login.OAuthLogin(social login not enabled)", errors.New(name)) + ctx.Handle(404, fmt.Sprintf("No OAuth with name %s configured", name), nil) return } @@ -96,7 +96,9 @@ func OAuthLogin(ctx *middleware.Context) { if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" || setting.OAuthService.OAuthInfos[name].TlsClientKey != "" { cert, err := tls.LoadX509KeyPair(setting.OAuthService.OAuthInfos[name].TlsClientCert, setting.OAuthService.OAuthInfos[name].TlsClientKey) if err != nil { - log.Fatal(1, "Failed to setup TlsClientCert", "oauth provider", name, "error", err) + ctx.Logger.Error("Failed to setup TlsClientCert", "oauth", name, "error", err) + ctx.Handle(500, "login.OAuthLogin(Failed to setup TlsClientCert)", nil) + return } tr.TLSClientConfig.Certificates = append(tr.TLSClientConfig.Certificates, cert) @@ -105,7 +107,9 @@ func OAuthLogin(ctx *middleware.Context) { if setting.OAuthService.OAuthInfos[name].TlsClientCa != "" { caCert, err := ioutil.ReadFile(setting.OAuthService.OAuthInfos[name].TlsClientCa) if err != nil { - log.Fatal(1, "Failed to setup TlsClientCa", "oauth provider", name, "error", err) + ctx.Logger.Error("Failed to setup TlsClientCa", "oauth", name, "error", err) + ctx.Handle(500, "login.OAuthLogin(Failed to setup TlsClientCa)", nil) + return } caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) @@ -124,13 +128,13 @@ func OAuthLogin(ctx *middleware.Context) { // token.TokenType was defaulting to "bearer", which is out of spec, so we explicitly set to "Bearer" token.TokenType = "Bearer" - ctx.Logger.Debug("OAuthLogin Got token") + oauthLogger.Debug("OAuthLogin Got token", "token", token) // set up oauth2 client client := connect.Client(oauthCtx, token) // get user info - userInfo, err := connect.UserInfo(client) + userInfo, err := connect.UserInfo(client, token) if err != nil { if sErr, ok := err.(*social.Error); ok { redirectWithError(ctx, sErr) @@ -140,7 +144,7 @@ func OAuthLogin(ctx *middleware.Context) { return } - ctx.Logger.Debug("OAuthLogin got user info", "userInfo", userInfo) + oauthLogger.Debug("OAuthLogin got user info", "userInfo", userInfo) // validate that we got at least an email address if userInfo.Email == "" { @@ -205,8 +209,7 @@ func OAuthLogin(ctx *middleware.Context) { } func redirectWithError(ctx *middleware.Context, err error, v ...interface{}) { - ctx.Logger.Info(err.Error(), v...) - // TODO: we can use the flash storage here once it's implemented + ctx.Logger.Error(err.Error(), v...) ctx.Session.Set("loginError", err.Error()) ctx.Redirect(setting.AppSubUrl + "/login") } diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index 864e464133d..57d9913d2eb 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -61,7 +61,7 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response } // send invite email - if !inviteDto.SkipEmails && util.IsEmail(inviteDto.LoginOrEmail) { + if inviteDto.SendEmail && util.IsEmail(inviteDto.LoginOrEmail) { emailCmd := m.SendEmailCommand{ To: []string{inviteDto.LoginOrEmail}, Template: "new_user_invite.html", @@ -99,7 +99,7 @@ func inviteExistingUserToOrg(c *middleware.Context, user *m.User, inviteDto *dto return ApiError(500, "Error while trying to create org user", err) } else { - if !inviteDto.SkipEmails && util.IsEmail(user.Email) { + if inviteDto.SendEmail && util.IsEmail(user.Email) { emailCmd := m.SendEmailCommand{ To: []string{user.Email}, Template: "invited_to_org.html", diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index 02c376eed30..433b9f2bd66 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -1,6 +1,7 @@ package api import ( + "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" @@ -31,10 +32,6 @@ func addOrgUserHelper(cmd m.AddOrgUserCommand) Response { userToAdd := userQuery.Result - // if userToAdd.Id == c.UserId { - // return ApiError(400, "Cannot add yourself as user", nil) - // } - cmd.UserId = userToAdd.Id if err := bus.Dispatch(&cmd); err != nil { @@ -49,22 +46,30 @@ func addOrgUserHelper(cmd m.AddOrgUserCommand) Response { // GET /api/org/users func GetOrgUsersForCurrentOrg(c *middleware.Context) Response { - return getOrgUsersHelper(c.OrgId) + return getOrgUsersHelper(c.OrgId, c.Params("query"), c.ParamsInt("limit")) } // GET /api/orgs/:orgId/users func GetOrgUsers(c *middleware.Context) Response { - return getOrgUsersHelper(c.ParamsInt64(":orgId")) + return getOrgUsersHelper(c.ParamsInt64(":orgId"), "", 0) } -func getOrgUsersHelper(orgId int64) Response { - query := m.GetOrgUsersQuery{OrgId: orgId} +func getOrgUsersHelper(orgId int64, query string, limit int) Response { + q := m.GetOrgUsersQuery{ + OrgId: orgId, + Query: query, + Limit: limit, + } - if err := bus.Dispatch(&query); err != nil { + if err := bus.Dispatch(&q); err != nil { return ApiError(500, "Failed to get account user", err) } - return Json(200, query.Result) + for _, user := range q.Result { + user.AvatarUrl = dtos.GetGravatarUrl(user.Email) + } + + return Json(200, q.Result) } // PATCH /api/org/users/:userId diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index a6c2da26dd8..040aef0474e 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -130,7 +130,7 @@ func GetPlaylistItems(c *middleware.Context) Response { func GetPlaylistDashboards(c *middleware.Context) Response { playlistId := c.ParamsInt64(":id") - playlists, err := LoadPlaylistDashboards(c.OrgId, c.UserId, playlistId) + playlists, err := LoadPlaylistDashboards(c.OrgId, c.SignedInUser, playlistId) if err != nil { return ApiError(500, "Could not load dashboards", err) } diff --git a/pkg/api/playlist_play.go b/pkg/api/playlist_play.go index 29a806ce23d..1d059e06be5 100644 --- a/pkg/api/playlist_play.go +++ b/pkg/api/playlist_play.go @@ -34,18 +34,18 @@ func populateDashboardsById(dashboardByIds []int64, dashboardIdOrder map[int64]i return result, nil } -func populateDashboardsByTag(orgId, userId int64, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice { +func populateDashboardsByTag(orgId int64, signedInUser *m.SignedInUser, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice { result := make(dtos.PlaylistDashboardsSlice, 0) if len(dashboardByTag) > 0 { for _, tag := range dashboardByTag { searchQuery := search.Query{ - Title: "", - Tags: []string{tag}, - UserId: userId, - Limit: 100, - IsStarred: false, - OrgId: orgId, + Title: "", + Tags: []string{tag}, + SignedInUser: signedInUser, + Limit: 100, + IsStarred: false, + OrgId: orgId, } if err := bus.Dispatch(&searchQuery); err == nil { @@ -64,7 +64,7 @@ func populateDashboardsByTag(orgId, userId int64, dashboardByTag []string, dashb return result } -func LoadPlaylistDashboards(orgId, userId, playlistId int64) (dtos.PlaylistDashboardsSlice, error) { +func LoadPlaylistDashboards(orgId int64, signedInUser *m.SignedInUser, playlistId int64) (dtos.PlaylistDashboardsSlice, error) { playlistItems, _ := LoadPlaylistItems(playlistId) dashboardByIds := make([]int64, 0) @@ -89,7 +89,7 @@ func LoadPlaylistDashboards(orgId, userId, playlistId int64) (dtos.PlaylistDashb var k, _ = populateDashboardsById(dashboardByIds, dashboardIdOrder) result = append(result, k...) - result = append(result, populateDashboardsByTag(orgId, userId, dashboardByTag, dashboardTagOrder)...) + result = append(result, populateDashboardsByTag(orgId, signedInUser, dashboardByTag, dashboardTagOrder)...) sort.Sort(result) return result, nil diff --git a/pkg/api/pluginproxy/ds_proxy.go b/pkg/api/pluginproxy/ds_proxy.go index faac8c03c62..5f4ec632c4d 100644 --- a/pkg/api/pluginproxy/ds_proxy.go +++ b/pkg/api/pluginproxy/ds_proxy.go @@ -135,9 +135,24 @@ func (proxy *DataSourceProxy) getDirector() func(req *http.Request) { req.Header.Add("Authorization", dsAuth) } - // clear cookie headers + // clear cookie header, except for whitelisted cookies + var keptCookies []*http.Cookie + if proxy.ds.JsonData != nil { + if keepCookies := proxy.ds.JsonData.Get("keepCookies"); keepCookies != nil { + keepCookieNames := keepCookies.MustStringArray() + for _, c := range req.Cookies() { + for _, v := range keepCookieNames { + if c.Name == v { + keptCookies = append(keptCookies, c) + } + } + } + } + } req.Header.Del("Cookie") - req.Header.Del("Set-Cookie") + for _, c := range keptCookies { + req.AddCookie(c) + } // clear X-Forwarded Host/Port/Proto headers req.Header.Del("X-Forwarded-Host") diff --git a/pkg/api/pluginproxy/ds_proxy_test.go b/pkg/api/pluginproxy/ds_proxy_test.go index 0a900ad3a6d..a7a869b2a9f 100644 --- a/pkg/api/pluginproxy/ds_proxy_test.go +++ b/pkg/api/pluginproxy/ds_proxy_test.go @@ -149,6 +149,58 @@ func TestDSRouteRule(t *testing.T) { }) }) + Convey("When proxying a data source with no keepCookies specified", func() { + plugin := &plugins.DataSourcePlugin{} + + json, _ := simplejson.NewJson([]byte(`{"keepCookies": []}`)) + + ds := &m.DataSource{ + Type: m.DS_GRAPHITE, + Url: "http://graphite:8086", + JsonData: json, + } + + ctx := &middleware.Context{} + proxy := NewDataSourceProxy(ds, plugin, ctx, "") + + requestUrl, _ := url.Parse("http://grafana.com/sub") + req := http.Request{URL: requestUrl, Header: make(http.Header)} + cookies := "grafana_user=admin; grafana_remember=99; grafana_sess=11; JSESSION_ID=test" + req.Header.Set("Cookie", cookies) + + proxy.getDirector()(&req) + + Convey("Should clear all cookies", func() { + So(req.Header.Get("Cookie"), ShouldEqual, "") + }) + }) + + Convey("When proxying a data source with keep cookies specified", func() { + plugin := &plugins.DataSourcePlugin{} + + json, _ := simplejson.NewJson([]byte(`{"keepCookies": ["JSESSION_ID"]}`)) + + ds := &m.DataSource{ + Type: m.DS_GRAPHITE, + Url: "http://graphite:8086", + JsonData: json, + } + + ctx := &middleware.Context{} + proxy := NewDataSourceProxy(ds, plugin, ctx, "") + + requestUrl, _ := url.Parse("http://grafana.com/sub") + req := http.Request{URL: requestUrl, Header: make(http.Header)} + cookies := "grafana_user=admin; grafana_remember=99; grafana_sess=11; JSESSION_ID=test" + req.Header.Set("Cookie", cookies) + + proxy.getDirector()(&req) + + Convey("Should keep named cookies", func() { + So(req.Header.Get("Cookie"), ShouldEqual, "JSESSION_ID=test") + }) + }) + Convey("When interpolating string", func() { data := templateData{ SecureJsonData: map[string]string{ diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 0483b624a30..e8c21541339 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -168,7 +168,7 @@ func ImportDashboard(c *middleware.Context, apiCmd dtos.ImportDashboardCommand) cmd := plugins.ImportDashboardCommand{ OrgId: c.OrgId, - UserId: c.UserId, + User: c.SignedInUser, PluginId: apiCmd.PluginId, Path: apiCmd.Path, Inputs: apiCmd.Inputs, diff --git a/pkg/api/render.go b/pkg/api/render.go index cab9c81505d..65733cfab15 100644 --- a/pkg/api/render.go +++ b/pkg/api/render.go @@ -21,18 +21,22 @@ func RenderToPng(c *middleware.Context) { Path: c.Params("*") + queryParams, Width: queryReader.Get("width", "800"), Height: queryReader.Get("height", "400"), - OrgId: c.OrgId, Timeout: queryReader.Get("timeout", "60"), + OrgId: c.OrgId, + UserId: c.UserId, + OrgRole: c.OrgRole, Timezone: queryReader.Get("tz", ""), + Encoding: queryReader.Get("encoding", ""), } pngPath, err := renderer.RenderToPng(renderOpts) - if err != nil { - if err == renderer.ErrTimeout { - c.Handle(500, err.Error(), err) - } + if err != nil && err == renderer.ErrTimeout { + c.Handle(500, err.Error(), err) + return + } + if err != nil { c.Handle(500, "Rendering failed.", err) return } diff --git a/pkg/api/search.go b/pkg/api/search.go index c68dc51e986..f79385d83f8 100644 --- a/pkg/api/search.go +++ b/pkg/api/search.go @@ -6,6 +6,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" ) @@ -14,27 +15,44 @@ func Search(c *middleware.Context) { tags := c.QueryStrings("tag") starred := c.Query("starred") limit := c.QueryInt("limit") + dashboardType := c.Query("type") + permission := models.PERMISSION_VIEW if limit == 0 { limit = 1000 } - dbids := make([]int, 0) + if c.Query("permission") == "Edit" { + permission = models.PERMISSION_EDIT + } + + dbids := make([]int64, 0) for _, id := range c.QueryStrings("dashboardIds") { - dashboardId, err := strconv.Atoi(id) + dashboardId, err := strconv.ParseInt(id, 10, 64) if err == nil { dbids = append(dbids, dashboardId) } } + folderIds := make([]int64, 0) + for _, id := range c.QueryStrings("folderIds") { + folderId, err := strconv.ParseInt(id, 10, 64) + if err == nil { + folderIds = append(folderIds, folderId) + } + } + searchQuery := search.Query{ Title: query, Tags: tags, - UserId: c.UserId, + SignedInUser: c.SignedInUser, Limit: limit, IsStarred: starred == "true", OrgId: c.OrgId, DashboardIds: dbids, + Type: dashboardType, + FolderIds: folderIds, + Permission: permission, } err := bus.Dispatch(&searchQuery) diff --git a/pkg/api/team.go b/pkg/api/team.go new file mode 100644 index 00000000000..f11eca68b91 --- /dev/null +++ b/pkg/api/team.go @@ -0,0 +1,98 @@ +package api + +import ( + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/util" +) + +// POST /api/teams +func CreateTeam(c *middleware.Context, cmd m.CreateTeamCommand) Response { + cmd.OrgId = c.OrgId + if err := bus.Dispatch(&cmd); err != nil { + if err == m.ErrTeamNameTaken { + return ApiError(409, "Team name taken", err) + } + return ApiError(500, "Failed to create Team", err) + } + + return Json(200, &util.DynMap{ + "teamId": cmd.Result.Id, + "message": "Team created", + }) +} + +// PUT /api/teams/:teamId +func UpdateTeam(c *middleware.Context, cmd m.UpdateTeamCommand) Response { + cmd.OrgId = c.OrgId + cmd.Id = c.ParamsInt64(":teamId") + if err := bus.Dispatch(&cmd); err != nil { + if err == m.ErrTeamNameTaken { + return ApiError(400, "Team name taken", err) + } + return ApiError(500, "Failed to update Team", err) + } + + return ApiSuccess("Team updated") +} + +// DELETE /api/teams/:teamId +func DeleteTeamById(c *middleware.Context) Response { + if err := bus.Dispatch(&m.DeleteTeamCommand{OrgId: c.OrgId, Id: c.ParamsInt64(":teamId")}); err != nil { + if err == m.ErrTeamNotFound { + return ApiError(404, "Failed to delete Team. ID not found", nil) + } + return ApiError(500, "Failed to update Team", err) + } + return ApiSuccess("Team deleted") +} + +// GET /api/teams/search +func SearchTeams(c *middleware.Context) Response { + perPage := c.QueryInt("perpage") + if perPage <= 0 { + perPage = 1000 + } + page := c.QueryInt("page") + if page < 1 { + page = 1 + } + + query := m.SearchTeamsQuery{ + OrgId: c.OrgId, + Query: c.Query("query"), + Name: c.Query("name"), + Page: page, + Limit: perPage, + } + + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "Failed to search Teams", err) + } + + for _, team := range query.Result.Teams { + team.AvatarUrl = dtos.GetGravatarUrlWithDefault(team.Email, team.Name) + } + + query.Result.Page = page + query.Result.PerPage = perPage + + return Json(200, query.Result) +} + +// GET /api/teams/:teamId +func GetTeamById(c *middleware.Context) Response { + query := m.GetTeamByIdQuery{OrgId: c.OrgId, Id: c.ParamsInt64(":teamId")} + + if err := bus.Dispatch(&query); err != nil { + if err == m.ErrTeamNotFound { + return ApiError(404, "Team not found", err) + } + + return ApiError(500, "Failed to get Team", err) + } + + return Json(200, &query.Result) +} diff --git a/pkg/api/team_members.go b/pkg/api/team_members.go new file mode 100644 index 00000000000..8586ac04fdb --- /dev/null +++ b/pkg/api/team_members.go @@ -0,0 +1,62 @@ +package api + +import ( + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/middleware" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/util" +) + +// GET /api/teams/:teamId/members +func GetTeamMembers(c *middleware.Context) Response { + query := m.GetTeamMembersQuery{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId")} + + if err := bus.Dispatch(&query); err != nil { + return ApiError(500, "Failed to get Team Members", err) + } + + for _, member := range query.Result { + member.AvatarUrl = dtos.GetGravatarUrl(member.Email) + } + + return Json(200, query.Result) +} + +// POST /api/teams/:teamId/members +func AddTeamMember(c *middleware.Context, cmd m.AddTeamMemberCommand) Response { + cmd.TeamId = c.ParamsInt64(":teamId") + cmd.OrgId = c.OrgId + + if err := bus.Dispatch(&cmd); err != nil { + if err == m.ErrTeamNotFound { + return ApiError(404, "Team not found", nil) + } + + if err == m.ErrTeamMemberAlreadyAdded { + return ApiError(400, "User is already added to this team", nil) + } + + return ApiError(500, "Failed to add Member to Team", err) + } + + return Json(200, &util.DynMap{ + "message": "Member added to Team", + }) +} + +// DELETE /api/teams/:teamId/members/:userId +func RemoveTeamMember(c *middleware.Context) Response { + if err := bus.Dispatch(&m.RemoveTeamMemberCommand{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId"), UserId: c.ParamsInt64(":userId")}); err != nil { + if err == m.ErrTeamNotFound { + return ApiError(404, "Team not found", nil) + } + + if err == m.ErrTeamMemberNotFound { + return ApiError(404, "Team member not found", nil) + } + + return ApiError(500, "Failed to remove Member from Team", err) + } + return ApiSuccess("Team Member removed") +} diff --git a/pkg/api/team_test.go b/pkg/api/team_test.go new file mode 100644 index 00000000000..0bf06d723c8 --- /dev/null +++ b/pkg/api/team_test.go @@ -0,0 +1,71 @@ +package api + +import ( + "testing" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestTeamApiEndpoint(t *testing.T) { + Convey("Given two teams", t, func() { + mockResult := models.SearchTeamQueryResult{ + Teams: []*models.SearchTeamDto{ + {Name: "team1"}, + {Name: "team2"}, + }, + TotalCount: 2, + } + + Convey("When searching with no parameters", func() { + loggedInUserScenario("When calling GET on", "/api/teams/search", func(sc *scenarioContext) { + var sentLimit int + var sendPage int + bus.AddHandler("test", func(query *models.SearchTeamsQuery) error { + query.Result = mockResult + + sentLimit = query.Limit + sendPage = query.Page + + return nil + }) + + sc.handlerFunc = SearchTeams + sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() + + So(sentLimit, ShouldEqual, 1000) + So(sendPage, ShouldEqual, 1) + + respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes()) + So(err, ShouldBeNil) + + So(respJSON.Get("totalCount").MustInt(), ShouldEqual, 2) + So(len(respJSON.Get("teams").MustArray()), ShouldEqual, 2) + }) + }) + + Convey("When searching with page and perpage parameters", func() { + loggedInUserScenario("When calling GET on", "/api/teams/search", func(sc *scenarioContext) { + var sentLimit int + var sendPage int + bus.AddHandler("test", func(query *models.SearchTeamsQuery) error { + query.Result = mockResult + + sentLimit = query.Limit + sendPage = query.Page + + return nil + }) + + sc.handlerFunc = SearchTeams + sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec() + + So(sentLimit, ShouldEqual, 10) + So(sendPage, ShouldEqual, 2) + }) + }) + }) +} diff --git a/pkg/api/user.go b/pkg/api/user.go index 7e8bad91ab0..9a041d30272 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -1,6 +1,7 @@ package api import ( + "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" @@ -219,7 +220,7 @@ func SearchUsers(c *middleware.Context) Response { return Json(200, query.Result.Users) } -// GET /api/search +// GET /api/users/search func SearchUsersWithPaging(c *middleware.Context) Response { query, err := searchUser(c) if err != nil { @@ -247,6 +248,10 @@ func searchUser(c *middleware.Context) (*m.SearchUsersQuery, error) { return nil, err } + for _, user := range query.Result.Users { + user.AvatarUrl = dtos.GetGravatarUrl(user.Email) + } + query.Result.Page = page query.Result.PerPage = perPage diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index a1b249d9c81..f40bc9c081b 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -94,7 +94,7 @@ func InstallPlugin(pluginName, version string, c CommandLine) error { res, _ := s.ReadPlugin(pluginFolder, pluginName) for _, v := range res.Dependencies.Plugins { - InstallPlugin(v.Id, version, c) + InstallPlugin(v.Id, "", c) logger.Infof("Installed dependency: %v ✔\n", v.Id) } diff --git a/pkg/cmd/grafana-server/main.go b/pkg/cmd/grafana-server/main.go index 183e4b047cd..ab0e12f2d9f 100644 --- a/pkg/cmd/grafana-server/main.go +++ b/pkg/cmd/grafana-server/main.go @@ -14,8 +14,8 @@ import ( "net/http" _ "net/http/pprof" + "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/metrics" - "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" _ "github.com/grafana/grafana/pkg/services/alerting/conditions" @@ -30,7 +30,7 @@ import ( _ "github.com/grafana/grafana/pkg/tsdb/testdata" ) -var version = "4.6.0" +var version = "5.0.0" var commit = "NA" var buildstamp string var build_date string @@ -40,9 +40,6 @@ var homePath = flag.String("homepath", "", "path to grafana install/home path, d var pidFile = flag.String("pidfile", "", "path to pid file") var exitChan = make(chan int) -func init() { -} - func main() { v := flag.Bool("v", false, "prints current version and exits") profile := flag.Bool("profile", false, "Turn on pprof profiling") @@ -82,12 +79,28 @@ func main() { setting.BuildStamp = buildstampInt64 metrics.M_Grafana_Version.WithLabelValues(version).Set(1) - + shutdownCompleted := make(chan int) server := NewGrafanaServer() - server.Start() + + go listenToSystemSignals(server, shutdownCompleted) + + go func() { + code := 0 + if err := server.Start(); err != nil { + log.Error2("Startup failed", "error", err) + code = 1 + } + + exitChan <- code + }() + + code := <-shutdownCompleted + log.Info2("Grafana shutdown completed.", "code", code) + log.Close() + os.Exit(code) } -func listenToSystemSignals(server models.GrafanaServer) { +func listenToSystemSignals(server *GrafanaServerImpl, shutdownCompleted chan int) { signalChan := make(chan os.Signal, 1) ignoreChan := make(chan os.Signal, 1) code := 0 @@ -97,10 +110,12 @@ func listenToSystemSignals(server models.GrafanaServer) { select { case sig := <-signalChan: - // Stops trace if profiling has been enabled - trace.Stop() + trace.Stop() // Stops trace if profiling has been enabled server.Shutdown(0, fmt.Sprintf("system signal: %s", sig)) + shutdownCompleted <- 0 case code = <-exitChan: + trace.Stop() // Stops trace if profiling has been enabled server.Shutdown(code, "startup error") + shutdownCompleted <- code } } diff --git a/pkg/cmd/grafana-server/server.go b/pkg/cmd/grafana-server/server.go index 820295a9b88..8ed3196e4ad 100644 --- a/pkg/cmd/grafana-server/server.go +++ b/pkg/cmd/grafana-server/server.go @@ -11,7 +11,6 @@ import ( "strconv" "time" - "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" "github.com/grafana/grafana/pkg/services/provisioning" "golang.org/x/sync/errgroup" @@ -20,7 +19,6 @@ import ( "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/login" "github.com/grafana/grafana/pkg/metrics" - "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/cleanup" @@ -33,7 +31,7 @@ import ( "github.com/grafana/grafana/pkg/tracing" ) -func NewGrafanaServer() models.GrafanaServer { +func NewGrafanaServer() *GrafanaServerImpl { rootCtx, shutdownFn := context.WithCancel(context.Background()) childRoutines, childCtx := errgroup.WithContext(rootCtx) @@ -54,9 +52,7 @@ type GrafanaServerImpl struct { httpServer *api.HttpServer } -func (g *GrafanaServerImpl) Start() { - go listenToSystemSignals(g) - +func (g *GrafanaServerImpl) Start() error { g.initLogging() g.writePIDFile() @@ -66,21 +62,22 @@ func (g *GrafanaServerImpl) Start() { search.Init() login.Init() social.NewOAuthService() - plugins.Init() + + pluginManager, err := plugins.NewPluginManager(g.context) + if err != nil { + return fmt.Errorf("Failed to start plugins. error: %v", err) + } + g.childRoutines.Go(func() error { return pluginManager.Run(g.context) }) if err := provisioning.Init(g.context, setting.HomePath, setting.Cfg); err != nil { - logger.Error("Failed to provision Grafana from config", "error", err) - g.Shutdown(1, "Startup failed") - return + return fmt.Errorf("Failed to provision Grafana from config. error: %v", err) } - closer, err := tracing.Init(setting.Cfg) + tracingCloser, err := tracing.Init(setting.Cfg) if err != nil { - g.log.Error("Tracing settings is not valid", "error", err) - g.Shutdown(1, "Startup failed") - return + return fmt.Errorf("Tracing settings is not valid. error: %v", err) } - defer closer.Close() + defer tracingCloser.Close() // init alerting if setting.AlertingEnabled && setting.ExecuteAlerts { @@ -93,13 +90,12 @@ func (g *GrafanaServerImpl) Start() { g.childRoutines.Go(func() error { return cleanUpService.Run(g.context) }) if err = notifications.Init(); err != nil { - g.log.Error("Notification service failed to initialize", "error", err) - g.Shutdown(1, "Startup failed") - return + return fmt.Errorf("Notification service failed to initialize. error: %v", err) } - SendSystemdNotification("READY=1") - g.startHttpServer() + sendSystemdNotification("READY=1") + + return g.startHttpServer() } func initSql() { @@ -123,16 +119,16 @@ func (g *GrafanaServerImpl) initLogging() { setting.LogConfigurationInfo() } -func (g *GrafanaServerImpl) startHttpServer() { +func (g *GrafanaServerImpl) startHttpServer() error { g.httpServer = api.NewHttpServer() err := g.httpServer.Start(g.context) if err != nil { - g.log.Error("Fail to start server", "error", err) - g.Shutdown(1, "Startup failed") - return + return fmt.Errorf("Fail to start server. error: %v", err) } + + return nil } func (g *GrafanaServerImpl) Shutdown(code int, reason string) { @@ -145,10 +141,9 @@ func (g *GrafanaServerImpl) Shutdown(code int, reason string) { g.shutdownFn() err = g.childRoutines.Wait() - - g.log.Info("Shutdown completed", "reason", err) - log.Close() - os.Exit(code) + if err != nil && err != context.Canceled { + g.log.Error("Server shutdown completed with an error", "error", err) + } } func (g *GrafanaServerImpl) writePIDFile() { @@ -173,7 +168,7 @@ func (g *GrafanaServerImpl) writePIDFile() { g.log.Info("Writing PID file", "path", *pidFile, "pid", pid) } -func SendSystemdNotification(state string) error { +func sendSystemdNotification(state string) error { notifySocket := os.Getenv("NOTIFY_SOCKET") if notifySocket == "" { diff --git a/pkg/components/imguploader/azureblobuploader.go b/pkg/components/imguploader/azureblobuploader.go new file mode 100644 index 00000000000..40d2de836be --- /dev/null +++ b/pkg/components/imguploader/azureblobuploader.go @@ -0,0 +1,320 @@ +package imguploader + +import ( + "bytes" + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "mime" + "net/http" + "net/url" + "os" + "path" + "sort" + "strconv" + "strings" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/util" +) + +type AzureBlobUploader struct { + account_name string + account_key string + container_name string + log log.Logger +} + +func NewAzureBlobUploader(account_name string, account_key string, container_name string) *AzureBlobUploader { + return &AzureBlobUploader{ + account_name: account_name, + account_key: account_key, + container_name: container_name, + log: log.New("azureBlobUploader"), + } +} + +// Receive path of image on disk and return azure blob url +func (az *AzureBlobUploader) Upload(ctx context.Context, imageDiskPath string) (string, error) { + // setup client + blob := NewStorageClient(az.account_name, az.account_key) + + file, err := os.Open(imageDiskPath) + + if err != nil { + return "", err + } + randomFileName := util.GetRandomString(30) + ".png" + // upload image + az.log.Debug("Uploading image to azure_blob", "conatiner_name", az.container_name, "blob_name", randomFileName) + resp, err := blob.FileUpload(az.container_name, randomFileName, file) + if err != nil { + return "", err + } + + if resp.StatusCode > 400 && resp.StatusCode < 600 { + body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + aerr := &Error{ + Code: resp.StatusCode, + Status: resp.Status, + Body: body, + Header: resp.Header, + } + aerr.parseXML() + resp.Body.Close() + return "", aerr + } + + if err != nil { + return "", err + } + + url := fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", az.account_name, az.container_name, randomFileName) + return url, nil +} + +// --- AZURE LIBRARY +type Blobs struct { + XMLName xml.Name `xml:"EnumerationResults"` + Items []Blob `xml:"Blobs>Blob"` +} + +type Blob struct { + Name string `xml:"Name"` + Property Property `xml:"Properties"` +} + +type Property struct { + LastModified string `xml:"Last-Modified"` + Etag string `xml:"Etag"` + ContentLength int `xml:"Content-Length"` + ContentType string `xml:"Content-Type"` + BlobType string `xml:"BlobType"` + LeaseStatus string `xml:"LeaseStatus"` +} + +type Error struct { + Code int + Status string + Body []byte + Header http.Header + + AzureCode string +} + +func (e *Error) Error() string { + return fmt.Sprintf("status %d: %s", e.Code, e.Body) +} + +func (e *Error) parseXML() { + var xe xmlError + _ = xml.NewDecoder(bytes.NewReader(e.Body)).Decode(&xe) + e.AzureCode = xe.Code +} + +type xmlError struct { + XMLName xml.Name `xml:"Error"` + Code string + Message string +} + +const ms_date_layout = "Mon, 02 Jan 2006 15:04:05 GMT" +const version = "2017-04-17" + +var client = &http.Client{} + +type StorageClient struct { + Auth *Auth + Transport http.RoundTripper +} + +func (c *StorageClient) transport() http.RoundTripper { + if c.Transport != nil { + return c.Transport + } + return http.DefaultTransport +} + +func NewStorageClient(account, accessKey string) *StorageClient { + return &StorageClient{ + Auth: &Auth{ + account, + accessKey, + }, + Transport: nil, + } +} + +func (c *StorageClient) absUrl(format string, a ...interface{}) string { + part := fmt.Sprintf(format, a...) + return fmt.Sprintf("https://%s.blob.core.windows.net/%s", c.Auth.Account, part) +} + +func copyHeadersToRequest(req *http.Request, headers map[string]string) { + for k, v := range headers { + req.Header[k] = []string{v} + } +} + +func (c *StorageClient) FileUpload(container, blobName string, body io.Reader) (*http.Response, error) { + blobName = escape(blobName) + extension := strings.ToLower(path.Ext(blobName)) + contentType := mime.TypeByExtension(extension) + buf := new(bytes.Buffer) + buf.ReadFrom(body) + req, err := http.NewRequest( + "PUT", + c.absUrl("%s/%s", container, blobName), + buf, + ) + if err != nil { + return nil, err + } + + copyHeadersToRequest(req, map[string]string{ + "x-ms-blob-type": "BlockBlob", + "x-ms-date": time.Now().UTC().Format(ms_date_layout), + "x-ms-version": version, + "Accept-Charset": "UTF-8", + "Content-Type": contentType, + "Content-Length": strconv.Itoa(buf.Len()), + }) + + c.Auth.SignRequest(req) + + return c.transport().RoundTrip(req) +} + +func escape(content string) string { + content = url.QueryEscape(content) + // the Azure's behavior uses %20 to represent whitespace instead of + (plus) + content = strings.Replace(content, "+", "%20", -1) + // the Azure's behavior uses slash instead of + %2F + content = strings.Replace(content, "%2F", "/", -1) + + return content +} + +type Auth struct { + Account string + Key string +} + +func (a *Auth) SignRequest(req *http.Request) { + strToSign := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", + strings.ToUpper(req.Method), + tryget(req.Header, "Content-Encoding"), + tryget(req.Header, "Content-Language"), + tryget(req.Header, "Content-Length"), + tryget(req.Header, "Content-MD5"), + tryget(req.Header, "Content-Type"), + tryget(req.Header, "Date"), + tryget(req.Header, "If-Modified-Since"), + tryget(req.Header, "If-Match"), + tryget(req.Header, "If-None-Match"), + tryget(req.Header, "If-Unmodified-Since"), + tryget(req.Header, "Range"), + a.canonicalizedHeaders(req), + a.canonicalizedResource(req), + ) + decodedKey, _ := base64.StdEncoding.DecodeString(a.Key) + + sha256 := hmac.New(sha256.New, []byte(decodedKey)) + sha256.Write([]byte(strToSign)) + + signature := base64.StdEncoding.EncodeToString(sha256.Sum(nil)) + + copyHeadersToRequest(req, map[string]string{ + "Authorization": fmt.Sprintf("SharedKey %s:%s", a.Account, signature), + }) +} + +func tryget(headers map[string][]string, key string) string { + // We default to empty string for "0" values to match server side behavior when generating signatures. + if len(headers[key]) > 0 { // && headers[key][0] != "0" { //&& key != "Content-Length" { + return headers[key][0] + } + return "" +} + +// +// The following is copied ~95% verbatim from: +// http://github.com/loldesign/azure/ -> core/core.go +// + +/* +Based on Azure docs: + Link: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element + + 1) Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header. + 2) Convert each HTTP header name to lowercase. + 3) Sort the headers lexicographically by header name, in ascending order. Note that each header may appear only once in the string. + 4) Unfold the string by replacing any breaking white space with a single space. + 5) Trim any white space around the colon in the header. + 6) Finally, append a new line character to each canonicalized header in the resulting list. Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string. +*/ +func (a *Auth) canonicalizedHeaders(req *http.Request) string { + var buffer bytes.Buffer + + for key, value := range req.Header { + lowerKey := strings.ToLower(key) + + if strings.HasPrefix(lowerKey, "x-ms-") { + if buffer.Len() == 0 { + buffer.WriteString(fmt.Sprintf("%s:%s", lowerKey, value[0])) + } else { + buffer.WriteString(fmt.Sprintf("\n%s:%s", lowerKey, value[0])) + } + } + } + + splitted := strings.Split(buffer.String(), "\n") + sort.Strings(splitted) + + return strings.Join(splitted, "\n") +} + +/* +Based on Azure docs + Link: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element + +1) Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns the resource being accessed. +2) Append the resource's encoded URI path, without any query parameters. +3) Retrieve all query parameters on the resource URI, including the comp parameter if it exists. +4) Convert all parameter names to lowercase. +5) Sort the query parameters lexicographically by parameter name, in ascending order. +6) URL-decode each query parameter name and value. +7) Append each query parameter name and value to the string in the following format, making sure to include the colon (:) between the name and the value: + parameter-name:parameter-value + +8) If a query parameter has more than one value, sort all values lexicographically, then include them in a comma-separated list: + parameter-name:parameter-value-1,parameter-value-2,parameter-value-n + +9) Append a new line character (\n) after each name-value pair. + +Rules: + 1) Avoid using the new line character (\n) in values for query parameters. If it must be used, ensure that it does not affect the format of the canonicalized resource string. + 2) Avoid using commas in query parameter values. +*/ +func (a *Auth) canonicalizedResource(req *http.Request) string { + var buffer bytes.Buffer + + buffer.WriteString(fmt.Sprintf("/%s%s", a.Account, req.URL.Path)) + queries := req.URL.Query() + + for key, values := range queries { + sort.Strings(values) + buffer.WriteString(fmt.Sprintf("\n%s:%s", key, strings.Join(values, ","))) + } + + splitted := strings.Split(buffer.String(), "\n") + sort.Strings(splitted) + + return strings.Join(splitted, "\n") +} diff --git a/pkg/components/imguploader/azureblobuploader_test.go b/pkg/components/imguploader/azureblobuploader_test.go new file mode 100644 index 00000000000..570e105b321 --- /dev/null +++ b/pkg/components/imguploader/azureblobuploader_test.go @@ -0,0 +1,24 @@ +package imguploader + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/setting" + . "github.com/smartystreets/goconvey/convey" +) + +func TestUploadToAzureBlob(t *testing.T) { + SkipConvey("[Integration test] for external_image_store.azure_blob", t, func() { + err := setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + uploader, _ := NewImageUploader() + + path, err := uploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png") + + So(err, ShouldBeNil) + So(path, ShouldNotEqual, "") + }) +} diff --git a/pkg/components/imguploader/imguploader.go b/pkg/components/imguploader/imguploader.go index fd14b5d6739..52a31f9f606 100644 --- a/pkg/components/imguploader/imguploader.go +++ b/pkg/components/imguploader/imguploader.go @@ -3,6 +3,7 @@ package imguploader import ( "context" "fmt" + "github.com/grafana/grafana/pkg/log" "regexp" "github.com/grafana/grafana/pkg/setting" @@ -76,6 +77,23 @@ func NewImageUploader() (ImageUploader, error) { path := gcssec.Key("path").MustString("") return NewGCSUploader(keyFile, bucketName, path), nil + case "azure_blob": + azureBlobSec, err := setting.Cfg.GetSection("external_image_storage.azure_blob") + if err != nil { + return nil, err + } + + account_name := azureBlobSec.Key("account_name").MustString("") + account_key := azureBlobSec.Key("account_key").MustString("") + container_name := azureBlobSec.Key("container_name").MustString("") + + return NewAzureBlobUploader(account_name, account_key, container_name), nil + case "local": + return NewLocalImageUploader() + } + + if setting.ImageUploadProvider != "" { + log.Error2("The external image storage configuration is invalid", "unsupported provider", setting.ImageUploadProvider) } return NopImageUploader{}, nil diff --git a/pkg/components/imguploader/imguploader_test.go b/pkg/components/imguploader/imguploader_test.go index 44b4c090008..b0311dac975 100644 --- a/pkg/components/imguploader/imguploader_test.go +++ b/pkg/components/imguploader/imguploader_test.go @@ -119,5 +119,47 @@ func TestImageUploaderFactory(t *testing.T) { So(original.keyFile, ShouldEqual, "/etc/secrets/project-79a52befa3f6.json") So(original.bucket, ShouldEqual, "project-grafana-east") }) + + Convey("AzureBlobUploader config", func() { + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + setting.ImageUploadProvider = "azure_blob" + + Convey("with container name", func() { + azureBlobSec, err := setting.Cfg.GetSection("external_image_storage.azure_blob") + azureBlobSec.NewKey("account_name", "account_name") + azureBlobSec.NewKey("account_key", "account_key") + azureBlobSec.NewKey("container_name", "container_name") + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + original, ok := uploader.(*AzureBlobUploader) + + So(ok, ShouldBeTrue) + So(original.account_name, ShouldEqual, "account_name") + So(original.account_key, ShouldEqual, "account_key") + So(original.container_name, ShouldEqual, "container_name") + }) + }) + + Convey("Local uploader", func() { + var err error + + setting.NewConfigContext(&setting.CommandLineArgs{ + HomePath: "../../../", + }) + + setting.ImageUploadProvider = "local" + + uploader, err := NewImageUploader() + + So(err, ShouldBeNil) + original, ok := uploader.(*LocalUploader) + + So(ok, ShouldBeTrue) + So(original, ShouldNotBeNil) + }) }) } diff --git a/pkg/components/imguploader/localuploader.go b/pkg/components/imguploader/localuploader.go new file mode 100644 index 00000000000..022d67122a7 --- /dev/null +++ b/pkg/components/imguploader/localuploader.go @@ -0,0 +1,22 @@ +package imguploader + +import ( + "context" + "path" + "path/filepath" + + "github.com/grafana/grafana/pkg/setting" +) + +type LocalUploader struct { +} + +func (u *LocalUploader) Upload(ctx context.Context, imageOnDiskPath string) (string, error) { + filename := filepath.Base(imageOnDiskPath) + image_url := setting.ToAbsUrl(path.Join("public/img/attachments", filename)) + return image_url, nil +} + +func NewLocalImageUploader() (*LocalUploader, error) { + return &LocalUploader{}, nil +} diff --git a/pkg/components/imguploader/localuploader_test.go b/pkg/components/imguploader/localuploader_test.go new file mode 100644 index 00000000000..0d8c0df0e57 --- /dev/null +++ b/pkg/components/imguploader/localuploader_test.go @@ -0,0 +1,18 @@ +package imguploader + +import ( + "context" + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestUploadToLocal(t *testing.T) { + Convey("[Integration test] for external_image_store.local", t, func() { + localUploader, _ := NewLocalImageUploader() + path, err := localUploader.Upload(context.Background(), "../../../public/img/logo_transparent_400x.png") + + So(err, ShouldBeNil) + So(path, ShouldContainSubstring, "/public/img/attachments") + }) +} diff --git a/pkg/components/renderer/renderer.go b/pkg/components/renderer/renderer.go index d5980231f0e..313f7892707 100644 --- a/pkg/components/renderer/renderer.go +++ b/pkg/components/renderer/renderer.go @@ -16,17 +16,22 @@ import ( "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) type RenderOpts struct { - Path string - Width string - Height string - Timeout string - OrgId int64 - Timezone string + Path string + Width string + Height string + Timeout string + OrgId int64 + UserId int64 + OrgRole models.RoleType + Timezone string + IsAlertContext bool + Encoding string } var ErrTimeout = errors.New("Timeout error. You can set timeout in seconds with &timeout url parameter") @@ -74,7 +79,11 @@ func RenderToPng(params *RenderOpts) (string, error) { pngPath, _ := filepath.Abs(filepath.Join(setting.ImagesDir, util.GetRandomString(20))) pngPath = pngPath + ".png" - renderKey := middleware.AddRenderAuthKey(params.OrgId) + orgRole := params.OrgRole + if params.IsAlertContext { + orgRole = models.ROLE_ADMIN + } + renderKey := middleware.AddRenderAuthKey(params.OrgId, params.UserId, orgRole) defer middleware.RemoveRenderAuthKey(renderKey) timeout, err := strconv.Atoi(params.Timeout) @@ -82,9 +91,15 @@ func RenderToPng(params *RenderOpts) (string, error) { timeout = 15 } + phantomDebugArg := "--debug=false" + if log.GetLogLevelFor("png-renderer") >= log.LvlDebug { + phantomDebugArg = "--debug=true" + } + cmdArgs := []string{ "--ignore-ssl-errors=true", "--web-security=false", + phantomDebugArg, scriptPath, "url=" + url, "width=" + params.Width, @@ -95,16 +110,18 @@ func RenderToPng(params *RenderOpts) (string, error) { "renderKey=" + renderKey, } + if params.Encoding != "" { + cmdArgs = append([]string{fmt.Sprintf("--output-encoding=%s", params.Encoding)}, cmdArgs...) + } + cmd := exec.Command(binPath, cmdArgs...) - stdout, err := cmd.StdoutPipe() + output, err := cmd.StdoutPipe() if err != nil { + rendererLog.Error("Could not acquire stdout pipe", err) return "", err } - stderr, err := cmd.StderrPipe() - if err != nil { - return "", err - } + cmd.Stderr = cmd.Stdout if params.Timezone != "" { baseEnviron := os.Environ() @@ -113,11 +130,12 @@ func RenderToPng(params *RenderOpts) (string, error) { err = cmd.Start() if err != nil { + rendererLog.Error("Could not start command", err) return "", err } - go io.Copy(os.Stdout, stdout) - go io.Copy(os.Stdout, stderr) + logWriter := log.NewLogWriter(rendererLog, log.LvlDebug, "[phantom] ") + go io.Copy(logWriter, output) done := make(chan error) go func() { diff --git a/pkg/log/log.go b/pkg/log/log.go index 9b3f8b27071..0e6874e1b4b 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -21,6 +21,7 @@ import ( var Root log15.Logger var loggersToClose []DisposableHandler +var filters map[string]log15.Lvl func init() { loggersToClose = make([]DisposableHandler, 0) @@ -114,6 +115,25 @@ func Close() { loggersToClose = make([]DisposableHandler, 0) } +func GetLogLevelFor(name string) Lvl { + if level, ok := filters[name]; ok { + switch level { + case log15.LvlWarn: + return LvlWarn + case log15.LvlInfo: + return LvlInfo + case log15.LvlError: + return LvlError + case log15.LvlCrit: + return LvlCrit + default: + return LvlDebug + } + } + + return LvlInfo +} + var logLevels = map[string]log15.Lvl{ "trace": log15.LvlDebug, "debug": log15.LvlDebug, @@ -187,7 +207,7 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) { // Log level. _, level := getLogLevelFromConfig("log."+mode, defaultLevelName, cfg) - modeFilters := getFilters(util.SplitString(sec.Key("filters").String())) + filters := getFilters(util.SplitString(sec.Key("filters").String())) format := getLogFormat(sec.Key("format").MustString("")) var handler log15.Handler @@ -219,12 +239,12 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) { } for key, value := range defaultFilters { - if _, exist := modeFilters[key]; !exist { - modeFilters[key] = value + if _, exist := filters[key]; !exist { + filters[key] = value } } - handler = LogFilterHandler(level, modeFilters, handler) + handler = LogFilterHandler(level, filters, handler) handlers = append(handlers, handler) } @@ -236,8 +256,8 @@ func LogFilterHandler(maxLevel log15.Lvl, filters map[string]log15.Lvl, h log15. if len(filters) > 0 { for i := 0; i < len(r.Ctx); i += 2 { - key := r.Ctx[i].(string) - if key == "logger" { + key, ok := r.Ctx[i].(string) + if ok && key == "logger" { loggerName, strOk := r.Ctx[i+1].(string) if strOk { if filterLevel, ok := filters[loggerName]; ok { diff --git a/pkg/log/log_writer.go b/pkg/log/log_writer.go new file mode 100644 index 00000000000..2ff401a7f0a --- /dev/null +++ b/pkg/log/log_writer.go @@ -0,0 +1,39 @@ +package log + +import ( + "io" + "strings" +) + +type logWriterImpl struct { + log Logger + level Lvl + prefix string +} + +func NewLogWriter(log Logger, level Lvl, prefix string) io.Writer { + return &logWriterImpl{ + log: log, + level: level, + prefix: prefix, + } +} + +func (l *logWriterImpl) Write(p []byte) (n int, err error) { + message := l.prefix + strings.TrimSpace(string(p)) + + switch l.level { + case LvlCrit: + l.log.Crit(message) + case LvlError: + l.log.Error(message) + case LvlWarn: + l.log.Warn(message) + case LvlInfo: + l.log.Info(message) + default: + l.log.Debug(message) + } + + return len(p), nil +} diff --git a/pkg/log/log_writer_test.go b/pkg/log/log_writer_test.go new file mode 100644 index 00000000000..4537b4d6100 --- /dev/null +++ b/pkg/log/log_writer_test.go @@ -0,0 +1,116 @@ +package log + +import ( + "testing" + + "github.com/inconshreveable/log15" + . "github.com/smartystreets/goconvey/convey" +) + +type FakeLogger struct { + debug string + info string + warn string + err string + crit string +} + +func (f *FakeLogger) New(ctx ...interface{}) log15.Logger { + return nil +} + +func (f *FakeLogger) Debug(msg string, ctx ...interface{}) { + f.debug = msg +} + +func (f *FakeLogger) Info(msg string, ctx ...interface{}) { + f.info = msg +} + +func (f *FakeLogger) Warn(msg string, ctx ...interface{}) { + f.warn = msg +} + +func (f *FakeLogger) Error(msg string, ctx ...interface{}) { + f.err = msg +} + +func (f *FakeLogger) Crit(msg string, ctx ...interface{}) { + f.crit = msg +} + +func (f *FakeLogger) GetHandler() log15.Handler { + return nil +} + +func (f *FakeLogger) SetHandler(l log15.Handler) {} + +func TestLogWriter(t *testing.T) { + Convey("When writing to a LogWriter", t, func() { + Convey("Should write using the correct level [crit]", func() { + fake := &FakeLogger{} + + crit := NewLogWriter(fake, LvlCrit, "") + n, err := crit.Write([]byte("crit")) + + So(n, ShouldEqual, 4) + So(err, ShouldBeNil) + So(fake.crit, ShouldEqual, "crit") + }) + + Convey("Should write using the correct level [error]", func() { + fake := &FakeLogger{} + + crit := NewLogWriter(fake, LvlError, "") + n, err := crit.Write([]byte("error")) + + So(n, ShouldEqual, 5) + So(err, ShouldBeNil) + So(fake.err, ShouldEqual, "error") + }) + + Convey("Should write using the correct level [warn]", func() { + fake := &FakeLogger{} + + crit := NewLogWriter(fake, LvlWarn, "") + n, err := crit.Write([]byte("warn")) + + So(n, ShouldEqual, 4) + So(err, ShouldBeNil) + So(fake.warn, ShouldEqual, "warn") + }) + + Convey("Should write using the correct level [info]", func() { + fake := &FakeLogger{} + + crit := NewLogWriter(fake, LvlInfo, "") + n, err := crit.Write([]byte("info")) + + So(n, ShouldEqual, 4) + So(err, ShouldBeNil) + So(fake.info, ShouldEqual, "info") + }) + + Convey("Should write using the correct level [debug]", func() { + fake := &FakeLogger{} + + crit := NewLogWriter(fake, LvlDebug, "") + n, err := crit.Write([]byte("debug")) + + So(n, ShouldEqual, 5) + So(err, ShouldBeNil) + So(fake.debug, ShouldEqual, "debug") + }) + + Convey("Should prefix the output with the prefix", func() { + fake := &FakeLogger{} + + crit := NewLogWriter(fake, LvlDebug, "prefix") + n, err := crit.Write([]byte("debug")) + + So(n, ShouldEqual, 5) // n is how much of input consumed + So(err, ShouldBeNil) + So(fake.debug, ShouldEqual, "prefixdebug") + }) + }) +} diff --git a/pkg/login/auth.go b/pkg/login/auth.go index 45561783e43..5527c7271d6 100644 --- a/pkg/login/auth.go +++ b/pkg/login/auth.go @@ -3,21 +3,20 @@ package login import ( "errors" - "crypto/subtle" "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/util" ) var ( - ErrInvalidCredentials = errors.New("Invalid Username or Password") + ErrInvalidCredentials = errors.New("Invalid Username or Password") + ErrTooManyLoginAttempts = errors.New("Too many consecutive incorrect login attempts for user. Login for user temporarily blocked") ) type LoginUserQuery struct { - Username string - Password string - User *m.User + Username string + Password string + User *m.User + IpAddress string } func Init() { @@ -26,41 +25,31 @@ func Init() { } func AuthenticateUser(query *LoginUserQuery) error { - err := loginUsingGrafanaDB(query) - if err == nil || err != ErrInvalidCredentials { + if err := validateLoginAttempts(query.Username); err != nil { return err } - if setting.LdapEnabled { - for _, server := range LdapCfg.Servers { - author := NewLdapAuthenticator(server) - err = author.Login(query) - if err == nil || err != ErrInvalidCredentials { - return err - } + err := loginUsingGrafanaDB(query) + if err == nil || (err != m.ErrUserNotFound && err != ErrInvalidCredentials) { + return err + } + + ldapEnabled, ldapErr := loginUsingLdap(query) + if ldapEnabled { + if ldapErr == nil || ldapErr != ErrInvalidCredentials { + return ldapErr } + + err = ldapErr + } + + if err == ErrInvalidCredentials { + saveInvalidLoginAttempt(query) + } + + if err == m.ErrUserNotFound { + return ErrInvalidCredentials } return err } - -func loginUsingGrafanaDB(query *LoginUserQuery) error { - userQuery := m.GetUserByLoginQuery{LoginOrEmail: query.Username} - - if err := bus.Dispatch(&userQuery); err != nil { - if err == m.ErrUserNotFound { - return ErrInvalidCredentials - } - return err - } - - user := userQuery.Result - - passwordHashed := util.EncodePassword(query.Password, user.Salt) - if subtle.ConstantTimeCompare([]byte(passwordHashed), []byte(user.Password)) != 1 { - return ErrInvalidCredentials - } - - query.User = user - return nil -} diff --git a/pkg/login/auth_test.go b/pkg/login/auth_test.go new file mode 100644 index 00000000000..59d3c8f2b33 --- /dev/null +++ b/pkg/login/auth_test.go @@ -0,0 +1,214 @@ +package login + +import ( + "errors" + "testing" + + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAuthenticateUser(t *testing.T) { + Convey("Authenticate user", t, func() { + authScenario("When a user authenticates having too many login attempts", func(sc *authScenarioContext) { + mockLoginAttemptValidation(ErrTooManyLoginAttempts, sc) + mockLoginUsingGrafanaDB(nil, sc) + mockLoginUsingLdap(true, nil, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, ErrTooManyLoginAttempts) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeFalse) + So(sc.ldapLoginWasCalled, ShouldBeFalse) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse) + }) + }) + + authScenario("When grafana user authenticate with valid credentials", func(sc *authScenarioContext) { + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(nil, sc) + mockLoginUsingLdap(true, ErrInvalidCredentials, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, nil) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeFalse) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse) + }) + }) + + authScenario("When grafana user authenticate and unexpected error occurs", func(sc *authScenarioContext) { + customErr := errors.New("custom") + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(customErr, sc) + mockLoginUsingLdap(true, ErrInvalidCredentials, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, customErr) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeFalse) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse) + }) + }) + + authScenario("When a non-existing grafana user authenticate and ldap disabled", func(sc *authScenarioContext) { + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc) + mockLoginUsingLdap(false, nil, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, ErrInvalidCredentials) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeTrue) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse) + }) + }) + + authScenario("When a non-existing grafana user authenticate and invalid ldap credentials", func(sc *authScenarioContext) { + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc) + mockLoginUsingLdap(true, ErrInvalidCredentials, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, ErrInvalidCredentials) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeTrue) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeTrue) + }) + }) + + authScenario("When a non-existing grafana user authenticate and valid ldap credentials", func(sc *authScenarioContext) { + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc) + mockLoginUsingLdap(true, nil, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldBeNil) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeTrue) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse) + }) + }) + + authScenario("When a non-existing grafana user authenticate and ldap returns unexpected error", func(sc *authScenarioContext) { + customErr := errors.New("custom") + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc) + mockLoginUsingLdap(true, customErr, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, customErr) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeTrue) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse) + }) + }) + + authScenario("When grafana user authenticate with invalid credentials and invalid ldap credentials", func(sc *authScenarioContext) { + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(ErrInvalidCredentials, sc) + mockLoginUsingLdap(true, ErrInvalidCredentials, sc) + mockSaveInvalidLoginAttempt(sc) + + err := AuthenticateUser(sc.loginUserQuery) + + Convey("it should result in", func() { + So(err, ShouldEqual, ErrInvalidCredentials) + So(sc.loginAttemptValidationWasCalled, ShouldBeTrue) + So(sc.grafanaLoginWasCalled, ShouldBeTrue) + So(sc.ldapLoginWasCalled, ShouldBeTrue) + So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeTrue) + }) + }) + }) +} + +type authScenarioContext struct { + loginUserQuery *LoginUserQuery + grafanaLoginWasCalled bool + ldapLoginWasCalled bool + loginAttemptValidationWasCalled bool + saveInvalidLoginAttemptWasCalled bool +} + +type authScenarioFunc func(sc *authScenarioContext) + +func mockLoginUsingGrafanaDB(err error, sc *authScenarioContext) { + loginUsingGrafanaDB = func(query *LoginUserQuery) error { + sc.grafanaLoginWasCalled = true + return err + } +} + +func mockLoginUsingLdap(enabled bool, err error, sc *authScenarioContext) { + loginUsingLdap = func(query *LoginUserQuery) (bool, error) { + sc.ldapLoginWasCalled = true + return enabled, err + } +} + +func mockLoginAttemptValidation(err error, sc *authScenarioContext) { + validateLoginAttempts = func(username string) error { + sc.loginAttemptValidationWasCalled = true + return err + } +} + +func mockSaveInvalidLoginAttempt(sc *authScenarioContext) { + saveInvalidLoginAttempt = func(query *LoginUserQuery) { + sc.saveInvalidLoginAttemptWasCalled = true + } +} + +func authScenario(desc string, fn authScenarioFunc) { + Convey(desc, func() { + origLoginUsingGrafanaDB := loginUsingGrafanaDB + origLoginUsingLdap := loginUsingLdap + origValidateLoginAttempts := validateLoginAttempts + origSaveInvalidLoginAttempt := saveInvalidLoginAttempt + + sc := &authScenarioContext{ + loginUserQuery: &LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + }, + } + + defer func() { + loginUsingGrafanaDB = origLoginUsingGrafanaDB + loginUsingLdap = origLoginUsingLdap + validateLoginAttempts = origValidateLoginAttempts + saveInvalidLoginAttempt = origSaveInvalidLoginAttempt + }() + + fn(sc) + }) +} diff --git a/pkg/login/brute_force_login_protection.go b/pkg/login/brute_force_login_protection.go new file mode 100644 index 00000000000..2ea93979c7a --- /dev/null +++ b/pkg/login/brute_force_login_protection.go @@ -0,0 +1,48 @@ +package login + +import ( + "time" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" +) + +var ( + maxInvalidLoginAttempts int64 = 5 + loginAttemptsWindow time.Duration = time.Minute * 5 +) + +var validateLoginAttempts = func(username string) error { + if setting.DisableBruteForceLoginProtection { + return nil + } + + loginAttemptCountQuery := m.GetUserLoginAttemptCountQuery{ + Username: username, + Since: time.Now().Add(-loginAttemptsWindow), + } + + if err := bus.Dispatch(&loginAttemptCountQuery); err != nil { + return err + } + + if loginAttemptCountQuery.Result >= maxInvalidLoginAttempts { + return ErrTooManyLoginAttempts + } + + return nil +} + +var saveInvalidLoginAttempt = func(query *LoginUserQuery) { + if setting.DisableBruteForceLoginProtection { + return + } + + loginAttemptCommand := m.CreateLoginAttemptCommand{ + Username: query.Username, + IpAddress: query.IpAddress, + } + + bus.Dispatch(&loginAttemptCommand) +} diff --git a/pkg/login/brute_force_login_protection_test.go b/pkg/login/brute_force_login_protection_test.go new file mode 100644 index 00000000000..5375134ba88 --- /dev/null +++ b/pkg/login/brute_force_login_protection_test.go @@ -0,0 +1,125 @@ +package login + +import ( + "testing" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" + . "github.com/smartystreets/goconvey/convey" +) + +func TestLoginAttemptsValidation(t *testing.T) { + Convey("Validate login attempts", t, func() { + Convey("Given brute force login protection enabled", func() { + setting.DisableBruteForceLoginProtection = false + + Convey("When user login attempt count equals max-1 ", func() { + withLoginAttempts(maxInvalidLoginAttempts - 1) + err := validateLoginAttempts("user") + + Convey("it should not result in error", func() { + So(err, ShouldBeNil) + }) + }) + + Convey("When user login attempt count equals max ", func() { + withLoginAttempts(maxInvalidLoginAttempts) + err := validateLoginAttempts("user") + + Convey("it should result in too many login attempts error", func() { + So(err, ShouldEqual, ErrTooManyLoginAttempts) + }) + }) + + Convey("When user login attempt count is greater than max ", func() { + withLoginAttempts(maxInvalidLoginAttempts + 5) + err := validateLoginAttempts("user") + + Convey("it should result in too many login attempts error", func() { + So(err, ShouldEqual, ErrTooManyLoginAttempts) + }) + }) + + Convey("When saving invalid login attempt", func() { + defer bus.ClearBusHandlers() + createLoginAttemptCmd := &m.CreateLoginAttemptCommand{} + + bus.AddHandler("test", func(cmd *m.CreateLoginAttemptCommand) error { + createLoginAttemptCmd = cmd + return nil + }) + + saveInvalidLoginAttempt(&LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + }) + + Convey("it should dispatch command", func() { + So(createLoginAttemptCmd, ShouldNotBeNil) + So(createLoginAttemptCmd.Username, ShouldEqual, "user") + So(createLoginAttemptCmd.IpAddress, ShouldEqual, "192.168.1.1:56433") + }) + }) + }) + + Convey("Given brute force login protection disabled", func() { + setting.DisableBruteForceLoginProtection = true + + Convey("When user login attempt count equals max-1 ", func() { + withLoginAttempts(maxInvalidLoginAttempts - 1) + err := validateLoginAttempts("user") + + Convey("it should not result in error", func() { + So(err, ShouldBeNil) + }) + }) + + Convey("When user login attempt count equals max ", func() { + withLoginAttempts(maxInvalidLoginAttempts) + err := validateLoginAttempts("user") + + Convey("it should not result in error", func() { + So(err, ShouldBeNil) + }) + }) + + Convey("When user login attempt count is greater than max ", func() { + withLoginAttempts(maxInvalidLoginAttempts + 5) + err := validateLoginAttempts("user") + + Convey("it should not result in error", func() { + So(err, ShouldBeNil) + }) + }) + + Convey("When saving invalid login attempt", func() { + defer bus.ClearBusHandlers() + createLoginAttemptCmd := (*m.CreateLoginAttemptCommand)(nil) + + bus.AddHandler("test", func(cmd *m.CreateLoginAttemptCommand) error { + createLoginAttemptCmd = cmd + return nil + }) + + saveInvalidLoginAttempt(&LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + }) + + Convey("it should not dispatch command", func() { + So(createLoginAttemptCmd, ShouldBeNil) + }) + }) + }) + }) +} + +func withLoginAttempts(loginAttempts int64) { + bus.AddHandler("test", func(query *m.GetUserLoginAttemptCountQuery) error { + query.Result = loginAttempts + return nil + }) +} diff --git a/pkg/login/grafana_login.go b/pkg/login/grafana_login.go new file mode 100644 index 00000000000..677ba776e4f --- /dev/null +++ b/pkg/login/grafana_login.go @@ -0,0 +1,35 @@ +package login + +import ( + "crypto/subtle" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/util" +) + +var validatePassword = func(providedPassword string, userPassword string, userSalt string) error { + passwordHashed := util.EncodePassword(providedPassword, userSalt) + if subtle.ConstantTimeCompare([]byte(passwordHashed), []byte(userPassword)) != 1 { + return ErrInvalidCredentials + } + + return nil +} + +var loginUsingGrafanaDB = func(query *LoginUserQuery) error { + userQuery := m.GetUserByLoginQuery{LoginOrEmail: query.Username} + + if err := bus.Dispatch(&userQuery); err != nil { + return err + } + + user := userQuery.Result + + if err := validatePassword(query.Password, user.Password, user.Salt); err != nil { + return err + } + + query.User = user + return nil +} diff --git a/pkg/login/grafana_login_test.go b/pkg/login/grafana_login_test.go new file mode 100644 index 00000000000..88e52224113 --- /dev/null +++ b/pkg/login/grafana_login_test.go @@ -0,0 +1,139 @@ +package login + +import ( + "testing" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestGrafanaLogin(t *testing.T) { + Convey("Login using Grafana DB", t, func() { + grafanaLoginScenario("When login with non-existing user", func(sc *grafanaLoginScenarioContext) { + sc.withNonExistingUser() + err := loginUsingGrafanaDB(sc.loginUserQuery) + + Convey("it should result in user not found error", func() { + So(err, ShouldEqual, m.ErrUserNotFound) + }) + + Convey("it should not call password validation", func() { + So(sc.validatePasswordCalled, ShouldBeFalse) + }) + + Convey("it should not pupulate user object", func() { + So(sc.loginUserQuery.User, ShouldBeNil) + }) + }) + + grafanaLoginScenario("When login with invalid credentials", func(sc *grafanaLoginScenarioContext) { + sc.withInvalidPassword() + err := loginUsingGrafanaDB(sc.loginUserQuery) + + Convey("it should result in invalid credentials error", func() { + So(err, ShouldEqual, ErrInvalidCredentials) + }) + + Convey("it should call password validation", func() { + So(sc.validatePasswordCalled, ShouldBeTrue) + }) + + Convey("it should not pupulate user object", func() { + So(sc.loginUserQuery.User, ShouldBeNil) + }) + }) + + grafanaLoginScenario("When login with valid credentials", func(sc *grafanaLoginScenarioContext) { + sc.withValidCredentials() + err := loginUsingGrafanaDB(sc.loginUserQuery) + + Convey("it should not result in error", func() { + So(err, ShouldBeNil) + }) + + Convey("it should call password validation", func() { + So(sc.validatePasswordCalled, ShouldBeTrue) + }) + + Convey("it should pupulate user object", func() { + So(sc.loginUserQuery.User, ShouldNotBeNil) + So(sc.loginUserQuery.User.Login, ShouldEqual, sc.loginUserQuery.Username) + So(sc.loginUserQuery.User.Password, ShouldEqual, sc.loginUserQuery.Password) + }) + }) + }) +} + +type grafanaLoginScenarioContext struct { + loginUserQuery *LoginUserQuery + validatePasswordCalled bool +} + +type grafanaLoginScenarioFunc func(c *grafanaLoginScenarioContext) + +func grafanaLoginScenario(desc string, fn grafanaLoginScenarioFunc) { + Convey(desc, func() { + origValidatePassword := validatePassword + + sc := &grafanaLoginScenarioContext{ + loginUserQuery: &LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + }, + validatePasswordCalled: false, + } + + defer func() { + validatePassword = origValidatePassword + }() + + fn(sc) + }) +} + +func mockPasswordValidation(valid bool, sc *grafanaLoginScenarioContext) { + validatePassword = func(providedPassword string, userPassword string, userSalt string) error { + sc.validatePasswordCalled = true + + if !valid { + return ErrInvalidCredentials + } + + return nil + } +} + +func (sc *grafanaLoginScenarioContext) getUserByLoginQueryReturns(user *m.User) { + bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error { + if user == nil { + return m.ErrUserNotFound + } + + query.Result = user + return nil + }) +} + +func (sc *grafanaLoginScenarioContext) withValidCredentials() { + sc.getUserByLoginQueryReturns(&m.User{ + Id: 1, + Login: sc.loginUserQuery.Username, + Password: sc.loginUserQuery.Password, + Salt: "salt", + }) + mockPasswordValidation(true, sc) +} + +func (sc *grafanaLoginScenarioContext) withNonExistingUser() { + sc.getUserByLoginQueryReturns(nil) +} + +func (sc *grafanaLoginScenarioContext) withInvalidPassword() { + sc.getUserByLoginQueryReturns(&m.User{ + Password: sc.loginUserQuery.Password, + Salt: "salt", + }) + mockPasswordValidation(false, sc) +} diff --git a/pkg/login/ldap_login.go b/pkg/login/ldap_login.go new file mode 100644 index 00000000000..b74b69db036 --- /dev/null +++ b/pkg/login/ldap_login.go @@ -0,0 +1,21 @@ +package login + +import ( + "github.com/grafana/grafana/pkg/setting" +) + +var loginUsingLdap = func(query *LoginUserQuery) (bool, error) { + if !setting.LdapEnabled { + return false, nil + } + + for _, server := range LdapCfg.Servers { + author := NewLdapAuthenticator(server) + err := author.Login(query) + if err == nil || err != ErrInvalidCredentials { + return true, err + } + } + + return true, ErrInvalidCredentials +} diff --git a/pkg/login/ldap_login_test.go b/pkg/login/ldap_login_test.go new file mode 100644 index 00000000000..6af125566e8 --- /dev/null +++ b/pkg/login/ldap_login_test.go @@ -0,0 +1,172 @@ +package login + +import ( + "testing" + + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" + . "github.com/smartystreets/goconvey/convey" +) + +func TestLdapLogin(t *testing.T) { + Convey("Login using ldap", t, func() { + Convey("Given ldap enabled and a server configured", func() { + setting.LdapEnabled = true + LdapCfg.Servers = append(LdapCfg.Servers, + &LdapServerConf{ + Host: "", + }) + + ldapLoginScenario("When login with invalid credentials", func(sc *ldapLoginScenarioContext) { + sc.withLoginResult(false) + enabled, err := loginUsingLdap(sc.loginUserQuery) + + Convey("it should return true", func() { + So(enabled, ShouldBeTrue) + }) + + Convey("it should return invalid credentials error", func() { + So(err, ShouldEqual, ErrInvalidCredentials) + }) + + Convey("it should call ldap login", func() { + So(sc.ldapAuthenticatorMock.loginCalled, ShouldBeTrue) + }) + }) + + ldapLoginScenario("When login with valid credentials", func(sc *ldapLoginScenarioContext) { + sc.withLoginResult(true) + enabled, err := loginUsingLdap(sc.loginUserQuery) + + Convey("it should return true", func() { + So(enabled, ShouldBeTrue) + }) + + Convey("it should not return error", func() { + So(err, ShouldBeNil) + }) + + Convey("it should call ldap login", func() { + So(sc.ldapAuthenticatorMock.loginCalled, ShouldBeTrue) + }) + }) + }) + + Convey("Given ldap enabled and no server configured", func() { + setting.LdapEnabled = true + LdapCfg.Servers = make([]*LdapServerConf, 0) + + ldapLoginScenario("When login", func(sc *ldapLoginScenarioContext) { + sc.withLoginResult(true) + enabled, err := loginUsingLdap(sc.loginUserQuery) + + Convey("it should return true", func() { + So(enabled, ShouldBeTrue) + }) + + Convey("it should return invalid credentials error", func() { + So(err, ShouldEqual, ErrInvalidCredentials) + }) + + Convey("it should not call ldap login", func() { + So(sc.ldapAuthenticatorMock.loginCalled, ShouldBeFalse) + }) + }) + }) + + Convey("Given ldap disabled", func() { + setting.LdapEnabled = false + + ldapLoginScenario("When login", func(sc *ldapLoginScenarioContext) { + sc.withLoginResult(false) + enabled, err := loginUsingLdap(&LoginUserQuery{ + Username: "user", + Password: "pwd", + }) + + Convey("it should return false", func() { + So(enabled, ShouldBeFalse) + }) + + Convey("it should not return error", func() { + So(err, ShouldBeNil) + }) + + Convey("it should not call ldap login", func() { + So(sc.ldapAuthenticatorMock.loginCalled, ShouldBeFalse) + }) + }) + }) + }) +} + +func mockLdapAuthenticator(valid bool) *mockLdapAuther { + mock := &mockLdapAuther{ + validLogin: valid, + } + + NewLdapAuthenticator = func(server *LdapServerConf) ILdapAuther { + return mock + } + + return mock +} + +type mockLdapAuther struct { + validLogin bool + loginCalled bool +} + +func (a *mockLdapAuther) Login(query *LoginUserQuery) error { + a.loginCalled = true + + if !a.validLogin { + return ErrInvalidCredentials + } + + return nil +} + +func (a *mockLdapAuther) SyncSignedInUser(signedInUser *m.SignedInUser) error { + return nil +} + +func (a *mockLdapAuther) GetGrafanaUserFor(ldapUser *LdapUserInfo) (*m.User, error) { + return nil, nil +} + +func (a *mockLdapAuther) SyncOrgRoles(user *m.User, ldapUser *LdapUserInfo) error { + return nil +} + +type ldapLoginScenarioContext struct { + loginUserQuery *LoginUserQuery + ldapAuthenticatorMock *mockLdapAuther +} + +type ldapLoginScenarioFunc func(c *ldapLoginScenarioContext) + +func ldapLoginScenario(desc string, fn ldapLoginScenarioFunc) { + Convey(desc, func() { + origNewLdapAuthenticator := NewLdapAuthenticator + + sc := &ldapLoginScenarioContext{ + loginUserQuery: &LoginUserQuery{ + Username: "user", + Password: "pwd", + IpAddress: "192.168.1.1:56433", + }, + ldapAuthenticatorMock: &mockLdapAuther{}, + } + + defer func() { + NewLdapAuthenticator = origNewLdapAuthenticator + }() + + fn(sc) + }) +} + +func (sc *ldapLoginScenarioContext) withLoginResult(valid bool) { + sc.ldapAuthenticatorMock = mockLdapAuthenticator(valid) +} diff --git a/pkg/login/settings.go b/pkg/login/ldap_settings.go similarity index 100% rename from pkg/login/settings.go rename to pkg/login/ldap_settings.go diff --git a/pkg/metrics/graphitebridge/graphite.go b/pkg/metrics/graphitebridge/graphite.go index 8504a908d9a..68fb544fc7c 100644 --- a/pkg/metrics/graphitebridge/graphite.go +++ b/pkg/metrics/graphitebridge/graphite.go @@ -26,9 +26,10 @@ import ( "strings" "time" + "context" + "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" - "golang.org/x/net/context" dto "github.com/prometheus/client_model/go" diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 4d7de98f2ea..4d4a11d0faa 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -379,6 +379,7 @@ func sendUsageStats() { metrics["stats.alerts.count"] = statsQuery.Result.Alerts metrics["stats.active_users.count"] = statsQuery.Result.ActiveUsers metrics["stats.datasources.count"] = statsQuery.Result.Datasources + metrics["stats.stars.count"] = statsQuery.Result.Stars dsStats := models.GetDataSourceStatsQuery{} if err := bus.Dispatch(&dsStats); err != nil { diff --git a/pkg/middleware/auth.go b/pkg/middleware/auth.go index be3415d990b..65697a616ea 100644 --- a/pkg/middleware/auth.go +++ b/pkg/middleware/auth.go @@ -42,8 +42,7 @@ func accessForbidden(c *Context) { return } - c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, setting.AppSubUrl+"/") - c.Redirect(setting.AppSubUrl + "/login") + c.Redirect(setting.AppSubUrl + "/") } func notAuthorized(c *Context) { @@ -52,7 +51,8 @@ func notAuthorized(c *Context) { return } - c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, setting.AppSubUrl+"/") + c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, setting.AppSubUrl+"/", nil, false, true) + c.Redirect(setting.AppSubUrl + "/login") } diff --git a/pkg/middleware/dashboard_redirect.go b/pkg/middleware/dashboard_redirect.go new file mode 100644 index 00000000000..4a3812fb8a2 --- /dev/null +++ b/pkg/middleware/dashboard_redirect.go @@ -0,0 +1,49 @@ +package middleware + +import ( + "fmt" + "strings" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + "gopkg.in/macaron.v1" +) + +func getDashboardUrlBySlug(orgId int64, slug string) (string, error) { + query := m.GetDashboardQuery{Slug: slug, OrgId: orgId} + + if err := bus.Dispatch(&query); err != nil { + return "", m.ErrDashboardNotFound + } + + return m.GetDashboardUrl(query.Result.Uid, query.Result.Slug), nil +} + +func RedirectFromLegacyDashboardUrl() macaron.Handler { + return func(c *Context) { + slug := c.Params("slug") + + if slug != "" { + if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil { + url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery) + c.Redirect(url, 301) + return + } + } + } +} + +func RedirectFromLegacyDashboardSoloUrl() macaron.Handler { + return func(c *Context) { + slug := c.Params("slug") + + if slug != "" { + if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil { + url = strings.Replace(url, "/d/", "/d-solo/", 1) + url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery) + c.Redirect(url, 301) + return + } + } + } +} diff --git a/pkg/middleware/dashboard_redirect_test.go b/pkg/middleware/dashboard_redirect_test.go new file mode 100644 index 00000000000..0af06347ed0 --- /dev/null +++ b/pkg/middleware/dashboard_redirect_test.go @@ -0,0 +1,58 @@ +package middleware + +import ( + "strings" + "testing" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/util" + . "github.com/smartystreets/goconvey/convey" +) + +func TestMiddlewareDashboardRedirect(t *testing.T) { + Convey("Given the dashboard redirect middleware", t, func() { + bus.ClearBusHandlers() + redirectFromLegacyDashboardUrl := RedirectFromLegacyDashboardUrl() + redirectFromLegacyDashboardSoloUrl := RedirectFromLegacyDashboardSoloUrl() + + fakeDash := m.NewDashboard("Child dash") + fakeDash.Id = 1 + fakeDash.FolderId = 1 + fakeDash.HasAcl = false + fakeDash.Uid = util.GenerateShortUid() + + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = fakeDash + return nil + }) + + middlewareScenario("GET dashboard by legacy url", func(sc *scenarioContext) { + sc.m.Get("/dashboard/db/:slug", redirectFromLegacyDashboardUrl, sc.defaultHandler) + + sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec() + + Convey("Should redirect to new dashboard url with a 301 Moved Permanently", func() { + So(sc.resp.Code, ShouldEqual, 301) + redirectUrl, _ := sc.resp.Result().Location() + So(redirectUrl.Path, ShouldEqual, m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)) + So(len(redirectUrl.Query()), ShouldEqual, 2) + }) + }) + + middlewareScenario("GET dashboard solo by legacy url", func(sc *scenarioContext) { + sc.m.Get("/dashboard-solo/db/:slug", redirectFromLegacyDashboardSoloUrl, sc.defaultHandler) + + sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec() + + Convey("Should redirect to new dashboard url with a 301 Moved Permanently", func() { + So(sc.resp.Code, ShouldEqual, 301) + redirectUrl, _ := sc.resp.Result().Location() + expectedUrl := m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug) + expectedUrl = strings.Replace(expectedUrl, "/d/", "/d-solo/", 1) + So(redirectUrl.Path, ShouldEqual, expectedUrl) + So(len(redirectUrl.Query()), ShouldEqual, 2) + }) + }) + }) +} diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 946ebae6b87..f0c952811cd 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -87,7 +87,7 @@ func initContextWithAnonymousUser(ctx *Context) bool { ctx.IsSignedIn = false ctx.AllowAnonymous = true - ctx.SignedInUser = &m.SignedInUser{} + ctx.SignedInUser = &m.SignedInUser{IsAnonymous: true} ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole) ctx.OrgId = orgQuery.Result.Id ctx.OrgName = orgQuery.Result.Name @@ -206,7 +206,9 @@ func (ctx *Context) Handle(status int, title string, err error) { ctx.Data["Title"] = title ctx.Data["AppSubUrl"] = setting.AppSubUrl - ctx.HTML(status, strconv.Itoa(status)) + ctx.Data["Theme"] = "dark" + + ctx.HTML(status, "error") } func (ctx *Context) JsonOK(message string) { diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 0d9e0e5b973..ffd8e8a0af0 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -399,6 +399,20 @@ func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext { return sc } +func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext { + sc.resp = httptest.NewRecorder() + req, err := http.NewRequest(method, url, nil) + q := req.URL.Query() + for k, v := range queryParams { + q.Add(k, v) + } + req.URL.RawQuery = q.Encode() + So(err, ShouldBeNil) + sc.req = req + + return sc +} + func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext { sc.handlerFunc = fn return sc diff --git a/pkg/middleware/org_redirect.go b/pkg/middleware/org_redirect.go index a5f90d60e47..9dd764be1bb 100644 --- a/pkg/middleware/org_redirect.go +++ b/pkg/middleware/org_redirect.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "strconv" + "strings" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/models" @@ -41,7 +42,7 @@ func OrgRedirect() macaron.Handler { return } - newUrl := setting.ToAbsUrl(fmt.Sprintf("%s?%s", c.Req.URL.Path, c.Req.URL.Query().Encode())) - c.Redirect(newUrl, 302) + newURL := setting.ToAbsUrl(fmt.Sprintf("%s?%s", strings.TrimPrefix(c.Req.URL.Path, "/"), c.Req.URL.Query().Encode())) + c.Redirect(newURL, 302) } } diff --git a/pkg/middleware/recovery.go b/pkg/middleware/recovery.go index 0c9dc4670e2..a8bdf809637 100644 --- a/pkg/middleware/recovery.go +++ b/pkg/middleware/recovery.go @@ -115,11 +115,11 @@ func Recovery() macaron.Handler { c.Data["Title"] = "Server Error" c.Data["AppSubUrl"] = setting.AppSubUrl - if theErr, ok := err.(error); ok { - c.Data["Title"] = theErr.Error() - } - if setting.Env == setting.DEV { + if theErr, ok := err.(error); ok { + c.Data["Title"] = theErr.Error() + } + c.Data["ErrorMsg"] = string(stack) } @@ -137,7 +137,7 @@ func Recovery() macaron.Handler { c.JSON(500, resp) } else { - c.HTML(500, "500") + c.HTML(500, "error") } } }() diff --git a/pkg/middleware/render_auth.go b/pkg/middleware/render_auth.go index 3a57660c9bf..d2f9c1b2b1a 100644 --- a/pkg/middleware/render_auth.go +++ b/pkg/middleware/render_auth.go @@ -33,14 +33,15 @@ func initContextWithRenderAuth(ctx *Context) bool { type renderContextFunc func(key string) (string, error) -func AddRenderAuthKey(orgId int64) string { +func AddRenderAuthKey(orgId int64, userId int64, orgRole m.RoleType) string { renderKeysLock.Lock() key := util.GetRandomString(32) renderKeys[key] = &m.SignedInUser{ OrgId: orgId, - OrgRole: m.ROLE_VIEWER, + OrgRole: orgRole, + UserId: userId, } renderKeysLock.Unlock() diff --git a/pkg/models/alert.go b/pkg/models/alert.go index fa3f4b466a8..88b49350b97 100644 --- a/pkg/models/alert.go +++ b/pkg/models/alert.go @@ -159,10 +159,6 @@ type SetAlertStateCommand struct { Timestamp time.Time } -type DeleteAlertCommand struct { - AlertId int64 -} - //Queries type GetAlertsQuery struct { OrgId int64 @@ -170,8 +166,9 @@ type GetAlertsQuery struct { DashboardId int64 PanelId int64 Limit int64 + User *SignedInUser - Result []*Alert + Result []*AlertListItemDTO } type GetAllAlertsQuery struct { @@ -191,6 +188,21 @@ type GetAlertStatesForDashboardQuery struct { Result []*AlertStateInfoDTO } +type AlertListItemDTO struct { + Id int64 `json:"id"` + DashboardId int64 `json:"dashboardId"` + DashboardUid string `json:"dashboardUid"` + DashboardSlug string `json:"dashboardSlug"` + PanelId int64 `json:"panelId"` + Name string `json:"name"` + State AlertStateType `json:"state"` + NewStateDate time.Time `json:"newStateDate"` + EvalDate time.Time `json:"evalDate"` + EvalData *simplejson.Json `json:"evalData"` + ExecutionError string `json:"executionError"` + Url string `json:"url"` +} + type AlertStateInfoDTO struct { Id int64 `json:"id"` DashboardId int64 `json:"dashboardId"` @@ -198,3 +210,17 @@ type AlertStateInfoDTO struct { State AlertStateType `json:"state"` NewStateDate time.Time `json:"newStateDate"` } + +// "Internal" commands + +type UpdateDashboardAlertsCommand struct { + UserId int64 + OrgId int64 + Dashboard *Dashboard +} + +type ValidateDashboardAlertsCommand struct { + UserId int64 + OrgId int64 + Dashboard *Dashboard +} diff --git a/pkg/models/dashboard_acl.go b/pkg/models/dashboard_acl.go new file mode 100644 index 00000000000..5b91b2a70b4 --- /dev/null +++ b/pkg/models/dashboard_acl.go @@ -0,0 +1,108 @@ +package models + +import ( + "errors" + "time" +) + +type PermissionType int + +const ( + PERMISSION_VIEW PermissionType = 1 << iota + PERMISSION_EDIT + PERMISSION_ADMIN +) + +func (p PermissionType) String() string { + names := map[int]string{ + int(PERMISSION_VIEW): "View", + int(PERMISSION_EDIT): "Edit", + int(PERMISSION_ADMIN): "Admin", + } + return names[int(p)] +} + +// Typed errors +var ( + ErrDashboardAclInfoMissing = errors.New("User id and team id cannot both be empty for a dashboard permission.") + ErrDashboardPermissionDashboardEmpty = errors.New("Dashboard Id must be greater than zero for a dashboard permission.") + ErrFolderAclInfoMissing = errors.New("User id and team id cannot both be empty for a folder permission.") + ErrFolderPermissionFolderEmpty = errors.New("Folder Id must be greater than zero for a folder permission.") +) + +// Dashboard ACL model +type DashboardAcl struct { + Id int64 + OrgId int64 + DashboardId int64 + + UserId int64 + TeamId int64 + Role *RoleType // pointer to be nullable + Permission PermissionType + + Created time.Time + Updated time.Time +} + +type DashboardAclInfoDTO struct { + OrgId int64 `json:"-"` + DashboardId int64 `json:"dashboardId,omitempty"` + FolderId int64 `json:"folderId,omitempty"` + + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` + + UserId int64 `json:"userId"` + UserLogin string `json:"userLogin"` + UserEmail string `json:"userEmail"` + TeamId int64 `json:"teamId"` + Team string `json:"team"` + Role *RoleType `json:"role,omitempty"` + Permission PermissionType `json:"permission"` + PermissionName string `json:"permissionName"` + Uid string `json:"uid"` + Title string `json:"title"` + Slug string `json:"slug"` + IsFolder bool `json:"isFolder"` + Url string `json:"url"` +} + +func (dto *DashboardAclInfoDTO) hasSameRoleAs(other *DashboardAclInfoDTO) bool { + if dto.Role == nil || other.Role == nil { + return false + } + + return dto.UserId <= 0 && dto.TeamId <= 0 && dto.UserId == other.UserId && dto.TeamId == other.TeamId && *dto.Role == *other.Role +} + +func (dto *DashboardAclInfoDTO) hasSameUserAs(other *DashboardAclInfoDTO) bool { + return dto.UserId > 0 && dto.UserId == other.UserId +} + +func (dto *DashboardAclInfoDTO) hasSameTeamAs(other *DashboardAclInfoDTO) bool { + return dto.TeamId > 0 && dto.TeamId == other.TeamId +} + +// IsDuplicateOf returns true if other item has same role, same user or same team +func (dto *DashboardAclInfoDTO) IsDuplicateOf(other *DashboardAclInfoDTO) bool { + return dto.hasSameRoleAs(other) || dto.hasSameUserAs(other) || dto.hasSameTeamAs(other) +} + +// +// COMMANDS +// + +type UpdateDashboardAclCommand struct { + DashboardId int64 + Items []*DashboardAcl +} + +// +// QUERIES +// +type GetDashboardAclInfoListQuery struct { + DashboardId int64 + OrgId int64 + Result []*DashboardAclInfoDTO +} diff --git a/pkg/models/dashboard_acl_test.go b/pkg/models/dashboard_acl_test.go new file mode 100644 index 00000000000..35357ff1cc9 --- /dev/null +++ b/pkg/models/dashboard_acl_test.go @@ -0,0 +1,21 @@ +package models + +import ( + "testing" + + "fmt" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestDashboardAclModel(t *testing.T) { + + Convey("When printing a PermissionType", t, func() { + view := PERMISSION_VIEW + printed := fmt.Sprint(view) + + Convey("Should output a friendly name", func() { + So(printed, ShouldEqual, "View") + }) + }) +} diff --git a/pkg/models/dashboard_snapshot.go b/pkg/models/dashboard_snapshot.go index 9273b88f291..ec8b19f3c18 100644 --- a/pkg/models/dashboard_snapshot.go +++ b/pkg/models/dashboard_snapshot.go @@ -64,10 +64,12 @@ type DeleteDashboardSnapshotCommand struct { } type DeleteExpiredSnapshotsCommand struct { + DeletedRows int64 } type GetDashboardSnapshotQuery struct { - Key string + Key string + DeleteKey string Result *DashboardSnapshot } @@ -76,9 +78,10 @@ type DashboardSnapshots []*DashboardSnapshot type DashboardSnapshotsList []*DashboardSnapshotDTO type GetDashboardSnapshotsQuery struct { - Name string - Limit int - OrgId int64 + Name string + Limit int + OrgId int64 + SignedInUser *SignedInUser Result DashboardSnapshotsList } diff --git a/pkg/models/dashboard_version.go b/pkg/models/dashboard_version.go index 4acb4282a58..9f5f18cb263 100644 --- a/pkg/models/dashboard_version.go +++ b/pkg/models/dashboard_version.go @@ -75,4 +75,5 @@ type GetDashboardVersionsQuery struct { // type DeleteExpiredVersionsCommand struct { + DeletedRows int64 } diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index aab6d78db3f..4b771038df6 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -2,22 +2,37 @@ package models import ( "errors" + "fmt" "strings" "time" "github.com/gosimple/slug" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/setting" ) // Typed errors var ( - ErrDashboardNotFound = errors.New("Dashboard not found") - ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found") - ErrDashboardWithSameNameExists = errors.New("A dashboard with the same name already exists") - ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else") - ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty") - ErrDashboardContainsInvalidAlertData = errors.New("Invalid alert data. Cannot save dashboard") - ErrDashboardFailedToUpdateAlertData = errors.New("Failed to save alert data") + ErrDashboardNotFound = errors.New("Dashboard not found") + ErrDashboardFolderNotFound = errors.New("Folder not found") + ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found") + ErrDashboardWithSameUIDExists = errors.New("A dashboard with the same uid already exists") + ErrDashboardWithSameNameInFolderExists = errors.New("A dashboard with the same name in the folder already exists") + ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else") + ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty") + ErrDashboardFolderCannotHaveParent = errors.New("A Dashboard Folder cannot be added to another folder") + ErrDashboardContainsInvalidAlertData = errors.New("Invalid alert data. Cannot save dashboard") + ErrDashboardFailedToUpdateAlertData = errors.New("Failed to save alert data") + ErrDashboardsWithSameSlugExists = errors.New("Multiple dashboards with the same slug exists") + ErrDashboardFailedGenerateUniqueUid = errors.New("Failed to generate unique dashboard id") + ErrDashboardTypeMismatch = errors.New("Dashboard cannot be changed to a folder") + ErrDashboardFolderWithSameNameAsDashboard = errors.New("Folder name cannot be the same as one of its dashboards") + ErrDashboardWithSameNameAsFolder = errors.New("Dashboard name cannot be the same as folder") + ErrDashboardFolderNameExists = errors.New("A folder with that name already exists") + ErrDashboardUpdateAccessDenied = errors.New("Access denied to save dashboard") + ErrDashboardInvalidUid = errors.New("uid contains illegal characters") + ErrDashboardUidToLong = errors.New("uid to long. max 40 characters") + RootFolderName = "General" ) type UpdatePluginDashboardError struct { @@ -38,6 +53,7 @@ var ( // Dashboard model type Dashboard struct { Id int64 + Uid string Slug string OrgId int64 GnetId int64 @@ -49,11 +65,38 @@ type Dashboard struct { UpdatedBy int64 CreatedBy int64 + FolderId int64 + IsFolder bool + HasAcl bool Title string Data *simplejson.Json } +func (d *Dashboard) SetId(id int64) { + d.Id = id + d.Data.Set("id", id) +} + +func (d *Dashboard) SetUid(uid string) { + d.Uid = uid + d.Data.Set("uid", uid) +} + +func (d *Dashboard) SetVersion(version int) { + d.Version = version + d.Data.Set("version", version) +} + +// GetDashboardIdForSavePermissionCheck return the dashboard id to be used for checking permission of dashboard +func (d *Dashboard) GetDashboardIdForSavePermissionCheck() int64 { + if d.Id == 0 { + return d.FolderId + } + + return d.Id +} + // NewDashboard creates a new dashboard func NewDashboard(title string) *Dashboard { dash := &Dashboard{} @@ -66,6 +109,16 @@ func NewDashboard(title string) *Dashboard { return dash } +// NewDashboardFolder creates a new dashboard folder +func NewDashboardFolder(title string) *Dashboard { + folder := NewDashboard(title) + folder.IsFolder = true + folder.Data.Set("schemaVersion", 16) + folder.Data.Set("version", 0) + folder.IsFolder = true + return folder +} + // GetTags turns the tags in data json into go string array func (dash *Dashboard) GetTags() []string { return dash.Data.Get("tags").MustStringArray() @@ -76,14 +129,21 @@ func NewDashboardFromJson(data *simplejson.Json) *Dashboard { dash.Data = data dash.Title = dash.Data.Get("title").MustString() dash.UpdateSlug() + update := false if id, err := dash.Data.Get("id").Float64(); err == nil { dash.Id = int64(id) + update = true + } - if version, err := dash.Data.Get("version").Float64(); err == nil { - dash.Version = int(version) - dash.Updated = time.Now() - } + if uid, err := dash.Data.Get("uid").String(); err == nil { + dash.Uid = uid + update = true + } + + if version, err := dash.Data.Get("version").Float64(); err == nil && update { + dash.Version = int(version) + dash.Updated = time.Now() } else { dash.Data.Set("version", 0) dash.Created = time.Now() @@ -106,13 +166,11 @@ func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard { userId = -1 } - if dash.Data.Get("version").MustInt(0) == 0 { - dash.CreatedBy = userId - } - dash.UpdatedBy = userId dash.OrgId = cmd.OrgId dash.PluginId = cmd.PluginId + dash.IsFolder = cmd.IsFolder + dash.FolderId = cmd.FolderId dash.UpdateSlug() return dash } @@ -124,8 +182,46 @@ func (dash *Dashboard) GetString(prop string, defaultValue string) string { // UpdateSlug updates the slug func (dash *Dashboard) UpdateSlug() { - title := strings.ToLower(dash.Data.Get("title").MustString()) - dash.Slug = slug.Make(title) + title := dash.Data.Get("title").MustString() + dash.Slug = SlugifyTitle(title) +} + +func SlugifyTitle(title string) string { + return slug.Make(strings.ToLower(title)) +} + +// GetUrl return the html url for a folder if it's folder, otherwise for a dashboard +func (dash *Dashboard) GetUrl() string { + return GetDashboardFolderUrl(dash.IsFolder, dash.Uid, dash.Slug) +} + +// Return the html url for a dashboard +func (dash *Dashboard) GenerateUrl() string { + return GetDashboardUrl(dash.Uid, dash.Slug) +} + +// GetDashboardFolderUrl return the html url for a folder if it's folder, otherwise for a dashboard +func GetDashboardFolderUrl(isFolder bool, uid string, slug string) string { + if isFolder { + return GetFolderUrl(uid, slug) + } + + return GetDashboardUrl(uid, slug) +} + +// Return the html url for a dashboard +func GetDashboardUrl(uid string, slug string) string { + return fmt.Sprintf("%s/d/%s/%s", setting.AppSubUrl, uid, slug) +} + +// Return the full url for a dashboard +func GetFullDashboardUrl(uid string, slug string) string { + return fmt.Sprintf("%s%s", setting.AppUrl, GetDashboardUrl(uid, slug)) +} + +// GetFolderUrl return the html url for a folder +func GetFolderUrl(folderUid string, slug string) string { + return fmt.Sprintf("%s/dashboards/f/%s/%s", setting.AppSubUrl, folderUid, slug) } // @@ -140,24 +236,48 @@ type SaveDashboardCommand struct { OrgId int64 `json:"-"` RestoredFrom int `json:"-"` PluginId string `json:"-"` + FolderId int64 `json:"folderId"` + IsFolder bool `json:"isFolder"` UpdatedAt time.Time Result *Dashboard } +type DashboardProvisioning struct { + Id int64 + DashboardId int64 + Name string + ExternalId string + Updated int64 +} + +type SaveProvisionedDashboardCommand struct { + DashboardCmd *SaveDashboardCommand + DashboardProvisioning *DashboardProvisioning + + Result *Dashboard +} + type DeleteDashboardCommand struct { - Slug string + Id int64 OrgId int64 } +type ValidateDashboardBeforeSaveCommand struct { + OrgId int64 + Dashboard *Dashboard + Overwrite bool +} + // // QUERIES // type GetDashboardQuery struct { - Slug string // required if no Id is specified + Slug string // required if no Id or Uid is specified Id int64 // optional if slug is set + Uid string // optional if slug is set OrgId int64 Result *Dashboard @@ -178,6 +298,14 @@ type GetDashboardsQuery struct { Result []*Dashboard } +type GetDashboardPermissionsForUserQuery struct { + DashboardIds []int64 + OrgId int64 + UserId int64 + OrgRole RoleType + Result []*DashboardPermissionForUser +} + type GetDashboardsByPluginIdQuery struct { OrgId int64 PluginId string @@ -188,3 +316,32 @@ type GetDashboardSlugByIdQuery struct { Id int64 Result string } + +type GetProvisionedDashboardDataQuery struct { + Name string + + Result []*DashboardProvisioning +} + +type GetDashboardsBySlugQuery struct { + OrgId int64 + Slug string + + Result []*Dashboard +} + +type DashboardPermissionForUser struct { + DashboardId int64 `json:"dashboardId"` + Permission PermissionType `json:"permission"` + PermissionName string `json:"permissionName"` +} + +type DashboardRef struct { + Uid string + Slug string +} + +type GetDashboardRefByIdQuery struct { + Id int64 + Result *DashboardRef +} diff --git a/pkg/models/dashboards_test.go b/pkg/models/dashboards_test.go index ee16508dc8a..ad865b575bb 100644 --- a/pkg/models/dashboards_test.go +++ b/pkg/models/dashboards_test.go @@ -16,6 +16,12 @@ func TestDashboardModel(t *testing.T) { So(dashboard.Slug, ShouldEqual, "grafana-play-home") }) + Convey("Can slugify title", t, func() { + slug := SlugifyTitle("Grafana Play Home") + + So(slug, ShouldEqual, "grafana-play-home") + }) + Convey("Given a dashboard json", t, func() { json := simplejson.New() json.Set("title", "test dash") @@ -28,4 +34,27 @@ func TestDashboardModel(t *testing.T) { }) }) + Convey("Given a new dashboard folder", t, func() { + json := simplejson.New() + json.Set("title", "test dash") + + cmd := &SaveDashboardCommand{Dashboard: json, IsFolder: true} + dash := cmd.GetDashboardModel() + + Convey("Should set IsFolder to true", func() { + So(dash.IsFolder, ShouldBeTrue) + }) + }) + + Convey("Given a child dashboard", t, func() { + json := simplejson.New() + json.Set("title", "test dash") + + cmd := &SaveDashboardCommand{Dashboard: json, FolderId: 1} + dash := cmd.GetDashboardModel() + + Convey("Should set FolderId", func() { + So(dash.FolderId, ShouldEqual, 1) + }) + }) } diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index 9c1cb6fe9e2..d2b93c5c1d6 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -58,21 +58,22 @@ type DataSource struct { } var knownDatasourcePlugins map[string]bool = map[string]bool{ - DS_ES: true, - DS_GRAPHITE: true, - DS_INFLUXDB: true, - DS_INFLUXDB_08: true, - DS_KAIROSDB: true, - DS_CLOUDWATCH: true, - DS_PROMETHEUS: true, - DS_OPENTSDB: true, - DS_POSTGRES: true, - DS_MYSQL: true, - "opennms": true, - "druid": true, - "dalmatinerdb": true, - "gnocci": true, - "zabbix": true, + DS_ES: true, + DS_GRAPHITE: true, + DS_INFLUXDB: true, + DS_INFLUXDB_08: true, + DS_KAIROSDB: true, + DS_CLOUDWATCH: true, + DS_PROMETHEUS: true, + DS_OPENTSDB: true, + DS_POSTGRES: true, + DS_MYSQL: true, + "opennms": true, + "abhisant-druid-datasource": true, + "dalmatinerdb-datasource": true, + "gnocci": true, + "zabbix": true, + "alexanderzobnin-zabbix-datasource": true, "newrelic-app": true, "grafana-datadog-datasource": true, "grafana-simple-json": true, diff --git a/pkg/models/folders.go b/pkg/models/folders.go new file mode 100644 index 00000000000..c61620a11fc --- /dev/null +++ b/pkg/models/folders.go @@ -0,0 +1,91 @@ +package models + +import ( + "errors" + "strings" + "time" +) + +// Typed errors +var ( + ErrFolderNotFound = errors.New("Folder not found") + ErrFolderVersionMismatch = errors.New("The folder has been changed by someone else") + ErrFolderTitleEmpty = errors.New("Folder title cannot be empty") + ErrFolderWithSameUIDExists = errors.New("A folder/dashboard with the same uid already exists") + ErrFolderSameNameExists = errors.New("A folder or dashboard in the general folder with the same name already exists") + ErrFolderFailedGenerateUniqueUid = errors.New("Failed to generate unique folder id") + ErrFolderAccessDenied = errors.New("Access denied to folder") +) + +type Folder struct { + Id int64 + Uid string + Title string + Url string + Version int + + Created time.Time + Updated time.Time + + UpdatedBy int64 + CreatedBy int64 + HasAcl bool +} + +// GetDashboardModel turns the command into the savable model +func (cmd *CreateFolderCommand) GetDashboardModel(orgId int64, userId int64) *Dashboard { + dashFolder := NewDashboardFolder(strings.TrimSpace(cmd.Title)) + dashFolder.OrgId = orgId + dashFolder.SetUid(strings.TrimSpace(cmd.Uid)) + + if userId == 0 { + userId = -1 + } + + dashFolder.CreatedBy = userId + dashFolder.UpdatedBy = userId + dashFolder.UpdateSlug() + + return dashFolder +} + +// UpdateDashboardModel updates an existing model from command into model for update +func (cmd *UpdateFolderCommand) UpdateDashboardModel(dashFolder *Dashboard, orgId int64, userId int64) { + dashFolder.OrgId = orgId + dashFolder.Title = strings.TrimSpace(cmd.Title) + dashFolder.Data.Set("title", dashFolder.Title) + + if cmd.Uid != "" { + dashFolder.SetUid(cmd.Uid) + } + + dashFolder.SetVersion(cmd.Version) + dashFolder.IsFolder = true + + if userId == 0 { + userId = -1 + } + + dashFolder.UpdatedBy = userId + dashFolder.UpdateSlug() +} + +// +// COMMANDS +// + +type CreateFolderCommand struct { + Uid string `json:"uid"` + Title string `json:"title"` + + Result *Folder +} + +type UpdateFolderCommand struct { + Uid string `json:"uid"` + Title string `json:"title"` + Version int `json:"version"` + Overwrite bool `json:"overwrite"` + + Result *Folder +} diff --git a/pkg/models/login_attempt.go b/pkg/models/login_attempt.go new file mode 100644 index 00000000000..6e0976bc506 --- /dev/null +++ b/pkg/models/login_attempt.go @@ -0,0 +1,36 @@ +package models + +import ( + "time" +) + +type LoginAttempt struct { + Id int64 + Username string + IpAddress string + Created int64 +} + +// --------------------- +// COMMANDS + +type CreateLoginAttemptCommand struct { + Username string + IpAddress string + + Result LoginAttempt +} + +type DeleteOldLoginAttemptsCommand struct { + OlderThan time.Time + DeletedRows int64 +} + +// --------------------- +// QUERIES + +type GetUserLoginAttemptCountQuery struct { + Username string + Since time.Time + Result int64 +} diff --git a/pkg/models/org_user.go b/pkg/models/org_user.go index 67b081fd1ce..ca32cc50060 100644 --- a/pkg/models/org_user.go +++ b/pkg/models/org_user.go @@ -18,25 +18,25 @@ var ( type RoleType string const ( - ROLE_VIEWER RoleType = "Viewer" - ROLE_EDITOR RoleType = "Editor" - ROLE_READ_ONLY_EDITOR RoleType = "Read Only Editor" - ROLE_ADMIN RoleType = "Admin" + ROLE_VIEWER RoleType = "Viewer" + ROLE_EDITOR RoleType = "Editor" + ROLE_ADMIN RoleType = "Admin" ) func (r RoleType) IsValid() bool { - return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR + return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR } func (r RoleType) Includes(other RoleType) bool { if r == ROLE_ADMIN { return true } - if r == ROLE_EDITOR || r == ROLE_READ_ONLY_EDITOR { + + if r == ROLE_EDITOR { return other != ROLE_ADMIN } - return r == other + return false } func (r *RoleType) UnmarshalJSON(data []byte) error { @@ -95,7 +95,10 @@ type UpdateOrgUserCommand struct { // QUERIES type GetOrgUsersQuery struct { - OrgId int64 + OrgId int64 + Query string + Limit int + Result []*OrgUserDTO } @@ -106,6 +109,7 @@ type OrgUserDTO struct { OrgId int64 `json:"orgId"` UserId int64 `json:"userId"` Email string `json:"email"` + AvatarUrl string `json:"avatarUrl"` Login string `json:"login"` Role string `json:"role"` LastSeenAt time.Time `json:"lastSeenAt"` diff --git a/pkg/models/server.go b/pkg/models/server.go deleted file mode 100644 index 4d683835256..00000000000 --- a/pkg/models/server.go +++ /dev/null @@ -1,6 +0,0 @@ -package models - -type GrafanaServer interface { - Start() - Shutdown(code int, reason string) -} diff --git a/pkg/models/stats.go b/pkg/models/stats.go index 0d982c3f4bd..e132d88c030 100644 --- a/pkg/models/stats.go +++ b/pkg/models/stats.go @@ -8,6 +8,7 @@ type SystemStats struct { Orgs int64 Playlists int64 Alerts int64 + Stars int64 } type DataSourceStats struct { diff --git a/pkg/models/team.go b/pkg/models/team.go new file mode 100644 index 00000000000..9c679a13394 --- /dev/null +++ b/pkg/models/team.go @@ -0,0 +1,85 @@ +package models + +import ( + "errors" + "time" +) + +// Typed errors +var ( + ErrTeamNotFound = errors.New("Team not found") + ErrTeamNameTaken = errors.New("Team name is taken") + ErrTeamMemberNotFound = errors.New("Team member not found") +) + +// Team model +type Team struct { + Id int64 `json:"id"` + OrgId int64 `json:"orgId"` + Name string `json:"name"` + Email string `json:"email"` + + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` +} + +// --------------------- +// COMMANDS + +type CreateTeamCommand struct { + Name string `json:"name" binding:"Required"` + Email string `json:"email"` + OrgId int64 `json:"-"` + + Result Team `json:"-"` +} + +type UpdateTeamCommand struct { + Id int64 + Name string + Email string + OrgId int64 `json:"-"` +} + +type DeleteTeamCommand struct { + OrgId int64 + Id int64 +} + +type GetTeamByIdQuery struct { + OrgId int64 + Id int64 + Result *Team +} + +type GetTeamsByUserQuery struct { + OrgId int64 + UserId int64 `json:"userId"` + Result []*Team `json:"teams"` +} + +type SearchTeamsQuery struct { + Query string + Name string + Limit int + Page int + OrgId int64 + + Result SearchTeamQueryResult +} + +type SearchTeamDto struct { + Id int64 `json:"id"` + OrgId int64 `json:"orgId"` + Name string `json:"name"` + Email string `json:"email"` + AvatarUrl string `json:"avatarUrl"` + MemberCount int64 `json:"memberCount"` +} + +type SearchTeamQueryResult struct { + TotalCount int64 `json:"totalCount"` + Teams []*SearchTeamDto `json:"teams"` + Page int `json:"page"` + PerPage int `json:"perPage"` +} diff --git a/pkg/models/team_member.go b/pkg/models/team_member.go new file mode 100644 index 00000000000..19cf657292d --- /dev/null +++ b/pkg/models/team_member.go @@ -0,0 +1,58 @@ +package models + +import ( + "errors" + "time" +) + +// Typed errors +var ( + ErrTeamMemberAlreadyAdded = errors.New("User is already added to this team") +) + +// TeamMember model +type TeamMember struct { + Id int64 + OrgId int64 + TeamId int64 + UserId int64 + + Created time.Time + Updated time.Time +} + +// --------------------- +// COMMANDS + +type AddTeamMemberCommand struct { + UserId int64 `json:"userId" binding:"Required"` + OrgId int64 `json:"-"` + TeamId int64 `json:"-"` +} + +type RemoveTeamMemberCommand struct { + OrgId int64 `json:"-"` + UserId int64 + TeamId int64 +} + +// ---------------------- +// QUERIES + +type GetTeamMembersQuery struct { + OrgId int64 + TeamId int64 + Result []*TeamMemberDTO +} + +// ---------------------- +// Projections and DTOs + +type TeamMemberDTO struct { + OrgId int64 `json:"orgId"` + TeamId int64 `json:"teamId"` + UserId int64 `json:"userId"` + Email string `json:"email"` + Login string `json:"login"` + AvatarUrl string `json:"avatarUrl"` +} diff --git a/pkg/models/user.go b/pkg/models/user.go index 77938b63a0b..d5b912e0a9c 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -160,7 +160,9 @@ type SignedInUser struct { Name string Email string ApiKeyId int64 + OrgCount int IsGrafanaAdmin bool + IsAnonymous bool HelpFlags1 HelpFlags1 LastSeenAt time.Time } @@ -169,10 +171,28 @@ func (u *SignedInUser) ShouldUpdateLastSeenAt() bool { return u.UserId > 0 && time.Since(u.LastSeenAt) > time.Minute*5 } +func (u *SignedInUser) NameOrFallback() string { + if u.Name != "" { + return u.Name + } else if u.Login != "" { + return u.Login + } else { + return u.Email + } +} + type UpdateUserLastSeenAtCommand struct { UserId int64 } +func (user *SignedInUser) HasRole(role RoleType) bool { + if user.IsGrafanaAdmin { + return true + } + + return user.OrgRole.Includes(role) +} + type UserProfileDTO struct { Id int64 `json:"id"` Email string `json:"email"` @@ -188,6 +208,7 @@ type UserSearchHitDTO struct { Name string `json:"name"` Login string `json:"login"` Email string `json:"email"` + AvatarUrl string `json:"avatarUrl"` IsAdmin bool `json:"isAdmin"` LastSeenAt time.Time `json:"lastSeenAt"` LastSeenAtAge string `json:"lastSeenAtAge"` diff --git a/pkg/plugins/dashboard_importer.go b/pkg/plugins/dashboard_importer.go index 1b3e4bac182..53012f3e817 100644 --- a/pkg/plugins/dashboard_importer.go +++ b/pkg/plugins/dashboard_importer.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" ) type ImportDashboardCommand struct { @@ -17,7 +18,7 @@ type ImportDashboardCommand struct { Overwrite bool OrgId int64 - UserId int64 + User *m.SignedInUser PluginId string Result *PluginDashboardInfoDTO } @@ -34,7 +35,7 @@ type DashboardInputMissingError struct { } func (e DashboardInputMissingError) Error() string { - return fmt.Sprintf("Dashbord input variable: %v missing from import command", e.VariableName) + return fmt.Sprintf("Dashboard input variable: %v missing from import command", e.VariableName) } func init() { @@ -66,21 +67,32 @@ func ImportDashboard(cmd *ImportDashboardCommand) error { saveCmd := m.SaveDashboardCommand{ Dashboard: generatedDash, OrgId: cmd.OrgId, - UserId: cmd.UserId, + UserId: cmd.User.UserId, Overwrite: cmd.Overwrite, PluginId: cmd.PluginId, + FolderId: dashboard.FolderId, } - if err := bus.Dispatch(&saveCmd); err != nil { + dto := &dashboards.SaveDashboardDTO{ + OrgId: cmd.OrgId, + Dashboard: saveCmd.GetDashboardModel(), + Overwrite: saveCmd.Overwrite, + User: cmd.User, + } + + savedDash, err := dashboards.NewService().SaveDashboard(dto) + + if err != nil { return err } cmd.Result = &PluginDashboardInfoDTO{ PluginId: cmd.PluginId, - Title: dashboard.Title, + Title: savedDash.Title, Path: cmd.Path, - Revision: dashboard.Data.Get("revision").MustInt64(1), - ImportedUri: "db/" + saveCmd.Result.Slug, + Revision: savedDash.Data.Get("revision").MustInt64(1), + ImportedUri: "db/" + savedDash.Slug, + ImportedUrl: savedDash.GetUrl(), ImportedRevision: dashboard.Data.Get("revision").MustInt64(1), Imported: true, } diff --git a/pkg/plugins/dashboard_importer_test.go b/pkg/plugins/dashboard_importer_test.go index d2897fad1cd..549b3bb4cf9 100644 --- a/pkg/plugins/dashboard_importer_test.go +++ b/pkg/plugins/dashboard_importer_test.go @@ -1,74 +1,68 @@ package plugins import ( + "context" "io/ioutil" "testing" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/setting" . "github.com/smartystreets/goconvey/convey" "gopkg.in/ini.v1" ) func TestDashboardImport(t *testing.T) { - - Convey("When importing plugin dashboard", t, func() { - setting.Cfg = ini.Empty() - sec, _ := setting.Cfg.NewSection("plugin.test-app") - sec.NewKey("path", "../../tests/test-app") - err := Init() - - So(err, ShouldBeNil) - - var importedDash *m.Dashboard - bus.AddHandler("test", func(cmd *m.SaveDashboardCommand) error { - importedDash = cmd.GetDashboardModel() - cmd.Result = importedDash - return nil - }) + pluginScenario("When importing a plugin dashboard", t, func() { + origNewDashboardService := dashboards.NewService + mock := &dashboards.FakeDashboardService{} + dashboards.MockDashboardService(mock) cmd := ImportDashboardCommand{ PluginId: "test-app", Path: "dashboards/connections.json", OrgId: 1, - UserId: 1, + User: &m.SignedInUser{UserId: 1, OrgRole: m.ROLE_ADMIN}, Inputs: []ImportDashboardInput{ {Name: "*", Type: "datasource", Value: "graphite"}, }, } - err = ImportDashboard(&cmd) + err := ImportDashboard(&cmd) So(err, ShouldBeNil) Convey("should install dashboard", func() { - So(importedDash, ShouldNotBeNil) + So(cmd.Result, ShouldNotBeNil) - resultStr, _ := importedDash.Data.EncodePretty() + resultStr, _ := mock.SavedDashboards[0].Dashboard.Data.EncodePretty() expectedBytes, _ := ioutil.ReadFile("../../tests/test-app/dashboards/connections_result.json") expectedJson, _ := simplejson.NewJson(expectedBytes) expectedStr, _ := expectedJson.EncodePretty() So(string(resultStr), ShouldEqual, string(expectedStr)) - panel := importedDash.Data.Get("rows").GetIndex(0).Get("panels").GetIndex(0) + panel := mock.SavedDashboards[0].Dashboard.Data.Get("rows").GetIndex(0).Get("panels").GetIndex(0) So(panel.Get("datasource").MustString(), ShouldEqual, "graphite") }) + + Reset(func() { + dashboards.NewService = origNewDashboardService + }) }) Convey("When evaling dashboard template", t, func() { template, _ := simplejson.NewJson([]byte(`{ - "__inputs": [ - { - "name": "DS_NAME", - "type": "datasource" - } - ], - "test": { - "prop": "${DS_NAME}" - } - }`)) + "__inputs": [ + { + "name": "DS_NAME", + "type": "datasource" + } + ], + "test": { + "prop": "${DS_NAME}" + } + }`)) evaluator := &DashTemplateEvaluator{ template: template, @@ -90,5 +84,17 @@ func TestDashboardImport(t *testing.T) { }) }) +} +func pluginScenario(desc string, t *testing.T, fn func()) { + Convey("Given a plugin", t, func() { + setting.Cfg = ini.Empty() + sec, _ := setting.Cfg.NewSection("plugin.test-app") + sec.NewKey("path", "../../tests/test-app") + err := initPlugins(context.Background()) + + So(err, ShouldBeNil) + + Convey(desc, fn) + }) } diff --git a/pkg/plugins/dashboards.go b/pkg/plugins/dashboards.go index 5d26766b8e5..d15bcdd6db5 100644 --- a/pkg/plugins/dashboards.go +++ b/pkg/plugins/dashboards.go @@ -14,7 +14,9 @@ type PluginDashboardInfoDTO struct { Title string `json:"title"` Imported bool `json:"imported"` ImportedUri string `json:"importedUri"` + ImportedUrl string `json:"importedUrl"` Slug string `json:"slug"` + DashboardId int64 `json:"dashboardId"` ImportedRevision int64 `json:"importedRevision"` Revision int64 `json:"revision"` Description string `json:"description"` @@ -60,8 +62,10 @@ func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDT // find existing dashboard for _, existingDash := range query.Result { if existingDash.Slug == dashboard.Slug { + res.DashboardId = existingDash.Id res.Imported = true res.ImportedUri = "db/" + existingDash.Slug + res.ImportedUrl = existingDash.GetUrl() res.ImportedRevision = existingDash.Data.Get("revision").MustInt64(1) existingMatches[existingDash.Id] = true } @@ -74,8 +78,9 @@ func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDT for _, dash := range query.Result { if _, exists := existingMatches[dash.Id]; !exists { result = append(result, &PluginDashboardInfoDTO{ - Slug: dash.Slug, - Removed: true, + Slug: dash.Slug, + DashboardId: dash.Id, + Removed: true, }) } } diff --git a/pkg/plugins/dashboards_test.go b/pkg/plugins/dashboards_test.go index 980d7bb91bd..8573d452409 100644 --- a/pkg/plugins/dashboards_test.go +++ b/pkg/plugins/dashboards_test.go @@ -1,6 +1,7 @@ package plugins import ( + "context" "testing" "github.com/grafana/grafana/pkg/bus" @@ -17,7 +18,7 @@ func TestPluginDashboards(t *testing.T) { setting.Cfg = ini.Empty() sec, _ := setting.Cfg.NewSection("plugin.test-app") sec.NewKey("path", "../../tests/test-app") - err := Init() + err := initPlugins(context.Background()) So(err, ShouldBeNil) diff --git a/pkg/plugins/dashboards_updater.go b/pkg/plugins/dashboards_updater.go index 52a623e73dd..835e8873810 100644 --- a/pkg/plugins/dashboards_updater.go +++ b/pkg/plugins/dashboards_updater.go @@ -47,7 +47,7 @@ func autoUpdateAppDashboard(pluginDashInfo *PluginDashboardInfoDTO, orgId int64) PluginId: pluginDashInfo.PluginId, Overwrite: true, Dashboard: dash.Data, - UserId: 0, + User: &m.SignedInUser{UserId: 0, OrgRole: m.ROLE_ADMIN}, Path: pluginDashInfo.Path, } @@ -75,7 +75,7 @@ func syncPluginDashboards(pluginDef *PluginBase, orgId int64) { if dash.Removed { plog.Info("Deleting plugin dashboard", "pluginId", pluginDef.Id, "dashboard", dash.Slug) - deleteCmd := m.DeleteDashboardCommand{OrgId: orgId, Slug: dash.Slug} + deleteCmd := m.DeleteDashboardCommand{OrgId: orgId, Id: dash.DashboardId} if err := bus.Dispatch(&deleteCmd); err != nil { plog.Error("Failed to auto update app dashboard", "pluginId", pluginDef.Id, "error", err) return @@ -124,7 +124,7 @@ func handlePluginStateChanged(event *m.PluginStateChangedEvent) error { return err } else { for _, dash := range query.Result { - deleteCmd := m.DeleteDashboardCommand{OrgId: dash.OrgId, Slug: dash.Slug} + deleteCmd := m.DeleteDashboardCommand{OrgId: dash.OrgId, Id: dash.Id} plog.Info("Deleting plugin dashboard", "pluginId", event.PluginId, "dashboard", dash.Slug) diff --git a/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go new file mode 100644 index 00000000000..170e187b282 --- /dev/null +++ b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go @@ -0,0 +1,161 @@ +package wrapper + +import ( + "context" + "errors" + "fmt" + + "github.com/grafana/grafana/pkg/components/null" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana_plugin_model/go/datasource" +) + +func NewDatasourcePluginWrapper(log log.Logger, plugin datasource.DatasourcePlugin) *DatasourcePluginWrapper { + return &DatasourcePluginWrapper{DatasourcePlugin: plugin, logger: log} +} + +type DatasourcePluginWrapper struct { + datasource.DatasourcePlugin + logger log.Logger +} + +func (tw *DatasourcePluginWrapper) Query(ctx context.Context, ds *models.DataSource, query *tsdb.TsdbQuery) (*tsdb.Response, error) { + jsonData, err := ds.JsonData.MarshalJSON() + if err != nil { + return nil, err + } + + pbQuery := &datasource.DatasourceRequest{ + Datasource: &datasource.DatasourceInfo{ + Name: ds.Name, + Type: ds.Type, + Url: ds.Url, + Id: ds.Id, + OrgId: ds.OrgId, + JsonData: string(jsonData), + DecryptedSecureJsonData: ds.SecureJsonData.Decrypt(), + }, + TimeRange: &datasource.TimeRange{ + FromRaw: query.TimeRange.From, + ToRaw: query.TimeRange.To, + ToEpochMs: query.TimeRange.GetToAsMsEpoch(), + FromEpochMs: query.TimeRange.GetFromAsMsEpoch(), + }, + Queries: []*datasource.Query{}, + } + + for _, q := range query.Queries { + modelJson, _ := q.Model.MarshalJSON() + + pbQuery.Queries = append(pbQuery.Queries, &datasource.Query{ + ModelJson: string(modelJson), + IntervalMs: q.IntervalMs, + RefId: q.RefId, + MaxDataPoints: q.MaxDataPoints, + }) + } + + pbres, err := tw.DatasourcePlugin.Query(ctx, pbQuery) + + if err != nil { + return nil, err + } + + res := &tsdb.Response{ + Results: map[string]*tsdb.QueryResult{}, + } + + for _, r := range pbres.Results { + qr := &tsdb.QueryResult{ + RefId: r.RefId, + Series: []*tsdb.TimeSeries{}, + Tables: []*tsdb.Table{}, + } + + if r.Error != "" { + qr.Error = errors.New(r.Error) + qr.ErrorString = r.Error + } + + for _, s := range r.GetSeries() { + points := tsdb.TimeSeriesPoints{} + + for _, p := range s.Points { + po := tsdb.NewTimePoint(null.FloatFrom(p.Value), float64(p.Timestamp)) + points = append(points, po) + } + + qr.Series = append(qr.Series, &tsdb.TimeSeries{ + Name: s.Name, + Tags: s.Tags, + Points: points, + }) + } + + mappedTables, err := tw.mapTables(r) + if err != nil { + return nil, err + } + qr.Tables = mappedTables + + res.Results[r.RefId] = qr + } + + return res, nil +} +func (tw *DatasourcePluginWrapper) mapTables(r *datasource.QueryResult) ([]*tsdb.Table, error) { + var tables []*tsdb.Table + for _, t := range r.GetTables() { + mappedTable, err := tw.mapTable(t) + if err != nil { + return nil, err + } + tables = append(tables, mappedTable) + } + return tables, nil +} + +func (tw *DatasourcePluginWrapper) mapTable(t *datasource.Table) (*tsdb.Table, error) { + table := &tsdb.Table{} + for _, c := range t.GetColumns() { + table.Columns = append(table.Columns, tsdb.TableColumn{ + Text: c.Name, + }) + } + + table.Rows = make([]tsdb.RowValues, 0) + for _, r := range t.GetRows() { + row := tsdb.RowValues{} + for _, rv := range r.Values { + mappedRw, err := tw.mapRowValue(rv) + if err != nil { + return nil, err + } + + row = append(row, mappedRw) + } + table.Rows = append(table.Rows, row) + } + + return table, nil +} +func (tw *DatasourcePluginWrapper) mapRowValue(rv *datasource.RowValue) (interface{}, error) { + switch rv.Kind { + case datasource.RowValue_TYPE_NULL: + return nil, nil + case datasource.RowValue_TYPE_INT64: + return rv.Int64Value, nil + case datasource.RowValue_TYPE_BOOL: + return rv.BoolValue, nil + case datasource.RowValue_TYPE_STRING: + return rv.StringValue, nil + case datasource.RowValue_TYPE_DOUBLE: + return rv.DoubleValue, nil + case datasource.RowValue_TYPE_BYTES: + return rv.BytesValue, nil + default: + return nil, fmt.Errorf("Unsupported row value %v from plugin", rv.Kind) + } +} diff --git a/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go new file mode 100644 index 00000000000..834e8238e3a --- /dev/null +++ b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go @@ -0,0 +1,109 @@ +package wrapper + +import ( + "testing" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana_plugin_model/go/datasource" +) + +func TestMapTables(t *testing.T) { + dpw := NewDatasourcePluginWrapper(log.New("test-logger"), nil) + var qr = &datasource.QueryResult{} + qr.Tables = append(qr.Tables, &datasource.Table{ + Columns: []*datasource.TableColumn{}, + Rows: nil, + }) + want := []*tsdb.Table{{}} + + have, err := dpw.mapTables(qr) + if err != nil { + t.Errorf("failed to map tables. error: %v", err) + } + if len(want) != len(have) { + t.Errorf("could not map all tables") + } +} + +func TestMapTable(t *testing.T) { + dpw := NewDatasourcePluginWrapper(log.New("test-logger"), nil) + + source := &datasource.Table{ + Columns: []*datasource.TableColumn{{Name: "column1"}, {Name: "column2"}}, + Rows: []*datasource.TableRow{{ + Values: []*datasource.RowValue{ + { + Kind: datasource.RowValue_TYPE_BOOL, + BoolValue: true, + }, + { + Kind: datasource.RowValue_TYPE_INT64, + Int64Value: 42, + }, + }, + }}, + } + + want := &tsdb.Table{ + Columns: []tsdb.TableColumn{{Text: "column1"}, {Text: "column2"}}, + } + have, err := dpw.mapTable(source) + if err != nil { + t.Fatalf("failed to map table. error: %v", err) + } + + for i := range have.Columns { + if want.Columns[i] != have.Columns[i] { + t.Fatalf("have column: %s, want %s", have, want) + } + } + + if len(have.Rows) != 1 { + t.Fatalf("Expects one row but got %d", len(have.Rows)) + } + + rowValuesCount := len(have.Rows[0]) + if rowValuesCount != 2 { + t.Fatalf("Expects two row values, got %d", rowValuesCount) + } +} + +func TestMappingRowValue(t *testing.T) { + dpw := NewDatasourcePluginWrapper(log.New("test-logger"), nil) + + boolRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_BOOL, BoolValue: true}) + haveBool, ok := boolRowValue.(bool) + if !ok || haveBool != true { + t.Fatalf("Expected true, was %v", haveBool) + } + + intRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_INT64, Int64Value: 42}) + haveInt, ok := intRowValue.(int64) + if !ok || haveInt != 42 { + t.Fatalf("Expected %d, was %d", 42, haveInt) + } + + stringRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_STRING, StringValue: "grafana"}) + haveString, ok := stringRowValue.(string) + if !ok || haveString != "grafana" { + t.Fatalf("Expected %s, was %s", "grafana", haveString) + } + + doubleRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_DOUBLE, DoubleValue: 1.5}) + haveDouble, ok := doubleRowValue.(float64) + if !ok || haveDouble != 1.5 { + t.Fatalf("Expected %v, was %v", 1.5, haveDouble) + } + + bytesRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_BYTES, BytesValue: []byte{66}}) + haveBytes, ok := bytesRowValue.([]byte) + if !ok || len(haveBytes) != 1 || haveBytes[0] != 66 { + t.Fatalf("Expected %v, was %v", []byte{66}, haveBytes) + } + + haveNil, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_NULL}) + if haveNil != nil { + t.Fatalf("Expected %v, was %v", nil, haveNil) + } +} diff --git a/pkg/plugins/datasource_plugin.go b/pkg/plugins/datasource_plugin.go index b36d7081dfe..37ce175efe4 100644 --- a/pkg/plugins/datasource_plugin.go +++ b/pkg/plugins/datasource_plugin.go @@ -1,9 +1,23 @@ package plugins import ( + "context" "encoding/json" + "fmt" "os" + "os/exec" + "path" "path/filepath" + "runtime" + "strings" + "time" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/plugins/datasource/wrapper" + "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana_plugin_model/go/datasource" + plugin "github.com/hashicorp/go-plugin" ) type DataSourcePlugin struct { @@ -16,6 +30,12 @@ type DataSourcePlugin struct { Mixed bool `json:"mixed,omitempty"` HasQueryHelp bool `json:"hasQueryHelp,omitempty"` Routes []*AppPluginRoute `json:"routes"` + + Backend bool `json:"backend,omitempty"` + Executable string `json:"executable,omitempty"` + + log log.Logger + client *plugin.Client } func (p *DataSourcePlugin) Load(decoder *json.Decoder, pluginDir string) error { @@ -39,3 +59,87 @@ func (p *DataSourcePlugin) Load(decoder *json.Decoder, pluginDir string) error { DataSources[p.Id] = p return nil } + +var handshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "grafana_plugin_type", + MagicCookieValue: "datasource", +} + +func composeBinaryName(executable, os, arch string) string { + var extension string + os = strings.ToLower(os) + if os == "windows" { + extension = ".exe" + } + + return fmt.Sprintf("%s_%s_%s%s", executable, os, strings.ToLower(arch), extension) +} + +func (p *DataSourcePlugin) initBackendPlugin(ctx context.Context, log log.Logger) error { + p.log = log.New("plugin-id", p.Id) + + err := p.spawnSubProcess() + if err == nil { + go p.restartKilledProcess(ctx) + } + + return err +} + +func (p *DataSourcePlugin) spawnSubProcess() error { + cmd := composeBinaryName(p.Executable, runtime.GOOS, runtime.GOARCH) + fullpath := path.Join(p.PluginDir, cmd) + + p.client = plugin.NewClient(&plugin.ClientConfig{ + HandshakeConfig: handshakeConfig, + Plugins: map[string]plugin.Plugin{p.Id: &datasource.DatasourcePluginImpl{}}, + Cmd: exec.Command(fullpath), + AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, + Logger: LogWrapper{Logger: p.log}, + }) + + rpcClient, err := p.client.Client() + if err != nil { + return err + } + + raw, err := rpcClient.Dispense(p.Id) + if err != nil { + return err + } + + plugin := raw.(datasource.DatasourcePlugin) + + tsdb.RegisterTsdbQueryEndpoint(p.Id, func(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) { + return wrapper.NewDatasourcePluginWrapper(p.log, plugin), nil + }) + + return nil +} + +func (p *DataSourcePlugin) restartKilledProcess(ctx context.Context) error { + ticker := time.NewTicker(time.Second * 1) + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + if p.client.Exited() { + err := p.spawnSubProcess() + p.log.Debug("Spawning new sub process", "name", p.Name, "id", p.Id) + if err != nil { + p.log.Error("Failed to spawn subprocess") + } + } + } + } +} + +func (p *DataSourcePlugin) Kill() { + if p.client != nil { + p.log.Debug("Killing subprocess ", "name", p.Name) + p.client.Kill() + } +} diff --git a/pkg/plugins/datasource_plugin_test.go b/pkg/plugins/datasource_plugin_test.go new file mode 100644 index 00000000000..147f0310f5c --- /dev/null +++ b/pkg/plugins/datasource_plugin_test.go @@ -0,0 +1,35 @@ +package plugins + +import ( + "testing" +) + +func TestComposeBinaryName(t *testing.T) { + tests := []struct { + name string + os string + arch string + + expectedPath string + }{ + { + name: "simple-json", + os: "linux", + arch: "amd64", + expectedPath: `simple-json_linux_amd64`, + }, + { + name: "simple-json", + os: "windows", + arch: "amd64", + expectedPath: `simple-json_windows_amd64.exe`, + }, + } + + for _, v := range tests { + have := composeBinaryName(v.name, v.os, v.arch) + if have != v.expectedPath { + t.Errorf("expected %s got %s", v.expectedPath, have) + } + } +} diff --git a/pkg/plugins/frontend_plugin.go b/pkg/plugins/frontend_plugin.go index 90c18d90044..04af4060169 100644 --- a/pkg/plugins/frontend_plugin.go +++ b/pkg/plugins/frontend_plugin.go @@ -40,7 +40,7 @@ func getPluginLogoUrl(pluginType, path, baseUrl string) string { } func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin) { - appSubPath := strings.Replace(strings.Replace(fp.PluginDir, app.PluginDir, "", 1), "\\", "/", 1) + appSubPath := strings.Replace(strings.Replace(fp.PluginDir, app.PluginDir, "", 1), "\\", "/", -1) fp.IncludedInAppId = app.Id fp.BaseUrl = app.BaseUrl diff --git a/pkg/plugins/frontend_plugin_test.go b/pkg/plugins/frontend_plugin_test.go index 304cd38deae..311f9fcc510 100644 --- a/pkg/plugins/frontend_plugin_test.go +++ b/pkg/plugins/frontend_plugin_test.go @@ -14,7 +14,7 @@ func TestFrontendPlugin(t *testing.T) { fp := &FrontendPluginBase{ PluginBase: PluginBase{ - PluginDir: "c:\\grafana\\public\\app\\plugins\\app\\testdata\\datasource", + PluginDir: "c:\\grafana\\public\\app\\plugins\\app\\testdata\\datasources\\datasource", BaseUrl: "fpbase", }, } @@ -29,6 +29,6 @@ func TestFrontendPlugin(t *testing.T) { } fp.setPathsBasedOnApp(app) - So(fp.Module, ShouldEqual, "app/plugins/app/testdata/datasource/module") + So(fp.Module, ShouldEqual, "app/plugins/app/testdata/datasources/datasource/module") }) } diff --git a/pkg/plugins/hclog-wrapper.go b/pkg/plugins/hclog-wrapper.go new file mode 100644 index 00000000000..cab7fc1a373 --- /dev/null +++ b/pkg/plugins/hclog-wrapper.go @@ -0,0 +1,49 @@ +package plugins + +import ( + "log" + + glog "github.com/grafana/grafana/pkg/log" + hclog "github.com/hashicorp/go-hclog" +) + +type LogWrapper struct { + Logger glog.Logger +} + +func (lw LogWrapper) Trace(msg string, args ...interface{}) { + lw.Logger.Debug(msg, args...) +} +func (lw LogWrapper) Debug(msg string, args ...interface{}) { + lw.Logger.Debug(msg, args...) +} +func (lw LogWrapper) Info(msg string, args ...interface{}) { + lw.Logger.Info(msg, args...) +} +func (lw LogWrapper) Warn(msg string, args ...interface{}) { + lw.Logger.Warn(msg, args...) +} +func (lw LogWrapper) Error(msg string, args ...interface{}) { + lw.Logger.Error(msg, args...) +} + +func (lw LogWrapper) IsTrace() bool { return true } +func (lw LogWrapper) IsDebug() bool { return true } +func (lw LogWrapper) IsInfo() bool { return true } +func (lw LogWrapper) IsWarn() bool { return true } +func (lw LogWrapper) IsError() bool { return true } + +func (lw LogWrapper) With(args ...interface{}) hclog.Logger { + return LogWrapper{Logger: lw.Logger.New(args...)} +} +func (lw LogWrapper) Named(name string) hclog.Logger { + return LogWrapper{Logger: lw.Logger.New()} +} + +func (lw LogWrapper) ResetNamed(name string) hclog.Logger { + return LogWrapper{Logger: lw.Logger.New()} +} + +func (lw LogWrapper) StandardLogger(ops *hclog.StandardLoggerOptions) *log.Logger { + return nil +} diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 885bd5c9e03..417f565dd0c 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -1,6 +1,7 @@ package plugins import ( + "context" "encoding/json" "errors" "fmt" @@ -34,14 +35,41 @@ type PluginScanner struct { errors []error } -func Init() error { +type PluginManager struct { + log log.Logger +} + +func NewPluginManager(ctx context.Context) (*PluginManager, error) { + err := initPlugins(ctx) + + if err != nil { + return nil, err + } + + return &PluginManager{ + log: log.New("plugins"), + }, nil +} + +func (p *PluginManager) Run(ctx context.Context) error { + <-ctx.Done() + + for _, p := range DataSources { + p.Kill() + } + + p.log.Info("Stopped Plugins", "error", ctx.Err()) + return ctx.Err() +} + +func initPlugins(ctx context.Context) error { plog = log.New("plugins") - DataSources = make(map[string]*DataSourcePlugin) - StaticRoutes = make([]*PluginStaticRoute, 0) - Panels = make(map[string]*PanelPlugin) - Apps = make(map[string]*AppPlugin) - Plugins = make(map[string]*PluginBase) + DataSources = map[string]*DataSourcePlugin{} + StaticRoutes = []*PluginStaticRoute{} + Panels = map[string]*PanelPlugin{} + Apps = map[string]*AppPlugin{} + Plugins = map[string]*PluginBase{} PluginTypes = map[string]interface{}{ "panel": PanelPlugin{}, "datasource": DataSourcePlugin{}, @@ -53,9 +81,8 @@ func Init() error { // check if plugins dir exists if _, err := os.Stat(setting.PluginsPath); os.IsNotExist(err) { - plog.Warn("Plugin dir does not exist", "dir", setting.PluginsPath) if err = os.MkdirAll(setting.PluginsPath, os.ModePerm); err != nil { - plog.Warn("Failed to create plugin dir", "dir", setting.PluginsPath, "error", err) + plog.Error("Failed to create plugin dir", "dir", setting.PluginsPath, "error", err) } else { plog.Info("Plugin dir created", "dir", setting.PluginsPath) scan(setting.PluginsPath) @@ -70,9 +97,18 @@ func Init() error { for _, panel := range Panels { panel.initFrontendPlugin() } - for _, panel := range DataSources { - panel.initFrontendPlugin() + + for _, ds := range DataSources { + if ds.Backend { + err := ds.initBackendPlugin(ctx, plog) + if err != nil { + plog.Error("Failed to init plugin.", "error", err, "plugin", ds.Id) + } + } + + ds.initFrontendPlugin() } + for _, app := range Apps { app.initApp() } diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index f2dbc1e2e82..4d3ccb4502b 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -1,6 +1,7 @@ package plugins import ( + "context" "path/filepath" "testing" @@ -14,7 +15,7 @@ func TestPluginScans(t *testing.T) { Convey("When scaning for plugins", t, func() { setting.StaticRootPath, _ = filepath.Abs("../../public/") setting.Cfg = ini.Empty() - err := Init() + err := initPlugins(context.Background()) So(err, ShouldBeNil) So(len(DataSources), ShouldBeGreaterThan, 1) @@ -29,7 +30,7 @@ func TestPluginScans(t *testing.T) { setting.Cfg = ini.Empty() sec, _ := setting.Cfg.NewSection("plugin.nginx-app") sec.NewKey("path", "../../tests/test-app") - err := Init() + err := initPlugins(context.Background()) So(err, ShouldBeNil) So(len(Apps), ShouldBeGreaterThan, 0) diff --git a/pkg/services/alerting/commands.go b/pkg/services/alerting/commands.go index 62671a559fa..2c145614751 100644 --- a/pkg/services/alerting/commands.go +++ b/pkg/services/alerting/commands.go @@ -5,24 +5,12 @@ import ( m "github.com/grafana/grafana/pkg/models" ) -type UpdateDashboardAlertsCommand struct { - UserId int64 - OrgId int64 - Dashboard *m.Dashboard -} - -type ValidateDashboardAlertsCommand struct { - UserId int64 - OrgId int64 - Dashboard *m.Dashboard -} - func init() { bus.AddHandler("alerting", updateDashboardAlerts) bus.AddHandler("alerting", validateDashboardAlerts) } -func validateDashboardAlerts(cmd *ValidateDashboardAlertsCommand) error { +func validateDashboardAlerts(cmd *m.ValidateDashboardAlertsCommand) error { extractor := NewDashAlertExtractor(cmd.Dashboard, cmd.OrgId) if _, err := extractor.GetAlerts(); err != nil { @@ -32,7 +20,7 @@ func validateDashboardAlerts(cmd *ValidateDashboardAlertsCommand) error { return nil } -func updateDashboardAlerts(cmd *UpdateDashboardAlertsCommand) error { +func updateDashboardAlerts(cmd *m.UpdateDashboardAlertsCommand) error { saveAlerts := m.SaveAlertsCommand{ OrgId: cmd.OrgId, UserId: cmd.UserId, diff --git a/pkg/services/alerting/eval_context.go b/pkg/services/alerting/eval_context.go index e92edd2af12..d598203d675 100644 --- a/pkg/services/alerting/eval_context.go +++ b/pkg/services/alerting/eval_context.go @@ -12,17 +12,19 @@ import ( ) type EvalContext struct { - Firing bool - IsTestRun bool - EvalMatches []*EvalMatch - Logs []*ResultLogEntry - Error error - ConditionEvals string - StartTime time.Time - EndTime time.Time - Rule *Rule - log log.Logger - dashboardSlug string + Firing bool + IsTestRun bool + EvalMatches []*EvalMatch + Logs []*ResultLogEntry + Error error + ConditionEvals string + StartTime time.Time + EndTime time.Time + Rule *Rule + log log.Logger + + dashboardRef *m.DashboardRef + ImagePublicUrl string ImageOnDiskPath string NoDataFound bool @@ -75,14 +77,6 @@ func (c *EvalContext) ShouldUpdateAlertState() bool { return c.Rule.State != c.PrevAlertState } -func (c *EvalContext) ShouldSendNotification() bool { - if (c.PrevAlertState == m.AlertStatePending) && (c.Rule.State == m.AlertStateOK) { - return false - } - - return true -} - func (a *EvalContext) GetDurationMs() float64 { return float64(a.EndTime.Nanosecond()-a.StartTime.Nanosecond()) / float64(1000000) } @@ -91,29 +85,30 @@ func (c *EvalContext) GetNotificationTitle() string { return "[" + c.GetStateModel().Text + "] " + c.Rule.Name } -func (c *EvalContext) GetDashboardSlug() (string, error) { - if c.dashboardSlug != "" { - return c.dashboardSlug, nil +func (c *EvalContext) GetDashboardUID() (*m.DashboardRef, error) { + if c.dashboardRef != nil { + return c.dashboardRef, nil } - slugQuery := &m.GetDashboardSlugByIdQuery{Id: c.Rule.DashboardId} - if err := bus.Dispatch(slugQuery); err != nil { - return "", err + uidQuery := &m.GetDashboardRefByIdQuery{Id: c.Rule.DashboardId} + if err := bus.Dispatch(uidQuery); err != nil { + return nil, err } - c.dashboardSlug = slugQuery.Result - return c.dashboardSlug, nil + c.dashboardRef = uidQuery.Result + return c.dashboardRef, nil } +const urlFormat = "%s?fullscreen=true&edit=true&tab=alert&panelId=%d&orgId=%d" + func (c *EvalContext) GetRuleUrl() (string, error) { if c.IsTestRun { return setting.AppUrl, nil } - if slug, err := c.GetDashboardSlug(); err != nil { + if ref, err := c.GetDashboardUID(); err != nil { return "", err } else { - ruleUrl := fmt.Sprintf("%sdashboard/db/%s?fullscreen&edit&tab=alert&panelId=%d&orgId=%d", setting.AppUrl, slug, c.Rule.PanelId, c.Rule.OrgId) - return ruleUrl, nil + return fmt.Sprintf(urlFormat, m.GetFullDashboardUrl(ref.Uid, ref.Slug), c.Rule.PanelId, c.Rule.OrgId), nil } } diff --git a/pkg/services/alerting/eval_context_test.go b/pkg/services/alerting/eval_context_test.go index 5cff2996ca6..019ca1ed01f 100644 --- a/pkg/services/alerting/eval_context_test.go +++ b/pkg/services/alerting/eval_context_test.go @@ -28,21 +28,5 @@ func TestAlertingEvalContext(t *testing.T) { So(ctx.ShouldUpdateAlertState(), ShouldBeFalse) }) }) - - Convey("Should send notifications", func() { - Convey("pending -> ok", func() { - ctx.PrevAlertState = models.AlertStatePending - ctx.Rule.State = models.AlertStateOK - - So(ctx.ShouldSendNotification(), ShouldBeFalse) - }) - - Convey("ok -> alerting", func() { - ctx.PrevAlertState = models.AlertStateOK - ctx.Rule.State = models.AlertStateAlerting - - So(ctx.ShouldSendNotification(), ShouldBeTrue) - }) - }) }) } diff --git a/pkg/services/alerting/eval_handler.go b/pkg/services/alerting/eval_handler.go index 79b2f231b41..457e02000fa 100644 --- a/pkg/services/alerting/eval_handler.go +++ b/pkg/services/alerting/eval_handler.go @@ -39,6 +39,11 @@ func (e *DefaultEvalHandler) Eval(context *EvalContext) { break } + if i == 0 { + firing = cr.Firing + noDataFound = cr.NoDataFound + } + // calculating Firing based on operator if cr.Operator == "or" { firing = firing || cr.Firing diff --git a/pkg/services/alerting/eval_handler_test.go b/pkg/services/alerting/eval_handler_test.go index cf6422a5250..c942e24818f 100644 --- a/pkg/services/alerting/eval_handler_test.go +++ b/pkg/services/alerting/eval_handler_test.go @@ -36,6 +36,16 @@ func TestAlertingEvaluationHandler(t *testing.T) { So(context.ConditionEvals, ShouldEqual, "true = true") }) + Convey("Show return triggered with single passing condition2", func() { + context := NewEvalContext(context.TODO(), &Rule{ + Conditions: []Condition{&conditionStub{firing: true, operator: "and"}}, + }) + + handler.Eval(context) + So(context.Firing, ShouldEqual, true) + So(context.ConditionEvals, ShouldEqual, "true = true") + }) + Convey("Show return false with not passing asdf", func() { context := NewEvalContext(context.TODO(), &Rule{ Conditions: []Condition{ @@ -131,6 +141,33 @@ func TestAlertingEvaluationHandler(t *testing.T) { So(context.ConditionEvals, ShouldEqual, "[[true OR false] OR true] = true") }) + Convey("Should return false if no condition is firing using OR operator", func() { + context := NewEvalContext(context.TODO(), &Rule{ + Conditions: []Condition{ + &conditionStub{firing: false, operator: "or"}, + &conditionStub{firing: false, operator: "or"}, + &conditionStub{firing: false, operator: "or"}, + }, + }) + + handler.Eval(context) + So(context.Firing, ShouldEqual, false) + So(context.ConditionEvals, ShouldEqual, "[[false OR false] OR false] = false") + }) + + Convey("Should retuasdfrn no data if one condition has nodata", func() { + context := NewEvalContext(context.TODO(), &Rule{ + Conditions: []Condition{ + &conditionStub{operator: "or", noData: false}, + &conditionStub{operator: "or", noData: false}, + &conditionStub{operator: "or", noData: false}, + }, + }) + + handler.Eval(context) + So(context.NoDataFound, ShouldBeFalse) + }) + Convey("Should return no data if one condition has nodata", func() { context := NewEvalContext(context.TODO(), &Rule{ Conditions: []Condition{ diff --git a/pkg/services/alerting/extractor.go b/pkg/services/alerting/extractor.go index b8579ffdc6a..a609824cbc8 100644 --- a/pkg/services/alerting/extractor.go +++ b/pkg/services/alerting/extractor.go @@ -69,6 +69,90 @@ func copyJson(in *simplejson.Json) (*simplejson.Json, error) { return simplejson.NewJson(rawJson) } +func (e *DashAlertExtractor) GetAlertFromPanels(jsonWithPanels *simplejson.Json) ([]*m.Alert, error) { + alerts := make([]*m.Alert, 0) + + for _, panelObj := range jsonWithPanels.Get("panels").MustArray() { + panel := simplejson.NewFromAny(panelObj) + jsonAlert, hasAlert := panel.CheckGet("alert") + + if !hasAlert { + continue + } + + panelId, err := panel.Get("id").Int64() + if err != nil { + return nil, fmt.Errorf("panel id is required. err %v", err) + } + + // backward compatibility check, can be removed later + enabled, hasEnabled := jsonAlert.CheckGet("enabled") + if hasEnabled && enabled.MustBool() == false { + continue + } + + frequency, err := getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString()) + if err != nil { + return nil, ValidationError{Reason: "Could not parse frequency"} + } + + alert := &m.Alert{ + DashboardId: e.Dash.Id, + OrgId: e.OrgId, + PanelId: panelId, + Id: jsonAlert.Get("id").MustInt64(), + Name: jsonAlert.Get("name").MustString(), + Handler: jsonAlert.Get("handler").MustInt64(), + Message: jsonAlert.Get("message").MustString(), + Frequency: frequency, + } + + for _, condition := range jsonAlert.Get("conditions").MustArray() { + jsonCondition := simplejson.NewFromAny(condition) + + jsonQuery := jsonCondition.Get("query") + queryRefId := jsonQuery.Get("params").MustArray()[0].(string) + panelQuery := findPanelQueryByRefId(panel, queryRefId) + + if panelQuery == nil { + reason := fmt.Sprintf("Alert on PanelId: %v refers to query(%s) that cannot be found", alert.PanelId, queryRefId) + return nil, ValidationError{Reason: reason} + } + + dsName := "" + if panelQuery.Get("datasource").MustString() != "" { + dsName = panelQuery.Get("datasource").MustString() + } else if panel.Get("datasource").MustString() != "" { + dsName = panel.Get("datasource").MustString() + } + + if datasource, err := e.lookupDatasourceId(dsName); err != nil { + return nil, err + } else { + jsonQuery.SetPath([]string{"datasourceId"}, datasource.Id) + } + + if interval, err := panel.Get("interval").String(); err == nil { + panelQuery.Set("interval", interval) + } + + jsonQuery.Set("model", panelQuery.Interface()) + } + + alert.Settings = jsonAlert + + // validate + _, err = NewRuleFromDBAlert(alert) + if err == nil && alert.ValidToSave() { + alerts = append(alerts, alert) + } else { + return nil, err + } + } + + return alerts, nil +} + func (e *DashAlertExtractor) GetAlerts() ([]*m.Alert, error) { e.log.Debug("GetAlerts") @@ -78,86 +162,27 @@ func (e *DashAlertExtractor) GetAlerts() ([]*m.Alert, error) { } alerts := make([]*m.Alert, 0) - for _, rowObj := range dashboardJson.Get("rows").MustArray() { - row := simplejson.NewFromAny(rowObj) - for _, panelObj := range row.Get("panels").MustArray() { - panel := simplejson.NewFromAny(panelObj) - jsonAlert, hasAlert := panel.CheckGet("alert") - - if !hasAlert { - continue - } - - panelId, err := panel.Get("id").Int64() + // We extract alerts from rows to be backwards compatible + // with the old dashboard json model. + rows := dashboardJson.Get("rows").MustArray() + if len(rows) > 0 { + for _, rowObj := range rows { + row := simplejson.NewFromAny(rowObj) + a, err := e.GetAlertFromPanels(row) if err != nil { - return nil, fmt.Errorf("panel id is required. err %v", err) - } - - // backward compatibility check, can be removed later - enabled, hasEnabled := jsonAlert.CheckGet("enabled") - if hasEnabled && enabled.MustBool() == false { - continue - } - - frequency, err := getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString()) - if err != nil { - return nil, ValidationError{Reason: "Could not parse frequency"} - } - - alert := &m.Alert{ - DashboardId: e.Dash.Id, - OrgId: e.OrgId, - PanelId: panelId, - Id: jsonAlert.Get("id").MustInt64(), - Name: jsonAlert.Get("name").MustString(), - Handler: jsonAlert.Get("handler").MustInt64(), - Message: jsonAlert.Get("message").MustString(), - Frequency: frequency, - } - - for _, condition := range jsonAlert.Get("conditions").MustArray() { - jsonCondition := simplejson.NewFromAny(condition) - - jsonQuery := jsonCondition.Get("query") - queryRefId := jsonQuery.Get("params").MustArray()[0].(string) - panelQuery := findPanelQueryByRefId(panel, queryRefId) - - if panelQuery == nil { - reason := fmt.Sprintf("Alert on PanelId: %v refers to query(%s) that cannot be found", alert.PanelId, queryRefId) - return nil, ValidationError{Reason: reason} - } - - dsName := "" - if panelQuery.Get("datasource").MustString() != "" { - dsName = panelQuery.Get("datasource").MustString() - } else if panel.Get("datasource").MustString() != "" { - dsName = panel.Get("datasource").MustString() - } - - if datasource, err := e.lookupDatasourceId(dsName); err != nil { - return nil, err - } else { - jsonQuery.SetPath([]string{"datasourceId"}, datasource.Id) - } - - if interval, err := panel.Get("interval").String(); err == nil { - panelQuery.Set("interval", interval) - } - - jsonQuery.Set("model", panelQuery.Interface()) - } - - alert.Settings = jsonAlert - - // validate - _, err = NewRuleFromDBAlert(alert) - if err == nil && alert.ValidToSave() { - alerts = append(alerts, alert) - } else { return nil, err } + + alerts = append(alerts, a...) } + } else { + a, err := e.GetAlertFromPanels(dashboardJson) + if err != nil { + return nil, err + } + + alerts = append(alerts, a...) } e.log.Debug("Extracted alerts from dashboard", "alertCount", len(alerts)) diff --git a/pkg/services/alerting/extractor_test.go b/pkg/services/alerting/extractor_test.go index 68054fab5ef..71f3026025d 100644 --- a/pkg/services/alerting/extractor_test.go +++ b/pkg/services/alerting/extractor_test.go @@ -1,12 +1,12 @@ package alerting import ( + "io/ioutil" "testing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/setting" . "github.com/smartystreets/goconvey/convey" ) @@ -18,10 +18,6 @@ func TestAlertRuleExtraction(t *testing.T) { return &FakeCondition{}, nil }) - setting.NewConfigContext(&setting.CommandLineArgs{ - HomePath: "../../../", - }) - // mock data defaultDs := &m.DataSource{Id: 12, OrgId: 1, Name: "I am default", IsDefault: true} graphite2Ds := &m.DataSource{Id: 15, OrgId: 1, Name: "graphite2"} @@ -45,70 +41,8 @@ func TestAlertRuleExtraction(t *testing.T) { return nil }) - json := ` - { - "id": 57, - "title": "Graphite 4", - "originalTitle": "Graphite 4", - "tags": ["graphite"], - "rows": [ - { - "panels": [ - { - "title": "Active desktop users", - "editable": true, - "type": "graph", - "id": 3, - "targets": [ - { - "refId": "A", - "target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)" - } - ], - "datasource": null, - "alert": { - "name": "name1", - "message": "desc1", - "handler": 1, - "frequency": "60s", - "conditions": [ - { - "type": "query", - "query": {"params": ["A", "5m", "now"]}, - "reducer": {"type": "avg", "params": []}, - "evaluator": {"type": ">", "params": [100]} - } - ] - } - }, - { - "title": "Active mobile users", - "id": 4, - "targets": [ - {"refId": "A", "target": ""}, - {"refId": "B", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} - ], - "datasource": "graphite2", - "alert": { - "name": "name2", - "message": "desc2", - "handler": 0, - "frequency": "60s", - "severity": "warning", - "conditions": [ - { - "type": "query", - "query": {"params": ["B", "5m", "now"]}, - "reducer": {"type": "avg", "params": []}, - "evaluator": {"type": ">", "params": [100]} - } - ] - } - } - ] - } - ] - }` + json, err := ioutil.ReadFile("./test-data/graphite-alert.json") + So(err, ShouldBeNil) Convey("Extractor should not modify the original json", func() { dashJson, err := simplejson.NewJson([]byte(json)) @@ -201,69 +135,8 @@ func TestAlertRuleExtraction(t *testing.T) { }) Convey("Panels missing id should return error", func() { - panelWithoutId := ` - { - "id": 57, - "title": "Graphite 4", - "originalTitle": "Graphite 4", - "tags": ["graphite"], - "rows": [ - { - "panels": [ - { - "title": "Active desktop users", - "editable": true, - "type": "graph", - "targets": [ - { - "refId": "A", - "target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)" - } - ], - "datasource": null, - "alert": { - "name": "name1", - "message": "desc1", - "handler": 1, - "frequency": "60s", - "conditions": [ - { - "type": "query", - "query": {"params": ["A", "5m", "now"]}, - "reducer": {"type": "avg", "params": []}, - "evaluator": {"type": ">", "params": [100]} - } - ] - } - }, - { - "title": "Active mobile users", - "id": 4, - "targets": [ - {"refId": "A", "target": ""}, - {"refId": "B", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} - ], - "datasource": "graphite2", - "alert": { - "name": "name2", - "message": "desc2", - "handler": 0, - "frequency": "60s", - "severity": "warning", - "conditions": [ - { - "type": "query", - "query": {"params": ["B", "5m", "now"]}, - "reducer": {"type": "avg", "params": []}, - "evaluator": {"type": ">", "params": [100]} - } - ] - } - } - ] - } - ] - }` + panelWithoutId, err := ioutil.ReadFile("./test-data/panels-missing-id.json") + So(err, ShouldBeNil) dashJson, err := simplejson.NewJson([]byte(panelWithoutId)) So(err, ShouldBeNil) @@ -277,292 +150,31 @@ func TestAlertRuleExtraction(t *testing.T) { }) }) + Convey("Parse alerts from dashboard without rows", func() { + json, err := ioutil.ReadFile("./test-data/v5-dashboard.json") + So(err, ShouldBeNil) + + dashJson, err := simplejson.NewJson(json) + So(err, ShouldBeNil) + dash := m.NewDashboardFromJson(dashJson) + extractor := NewDashAlertExtractor(dash, 1) + + alerts, err := extractor.GetAlerts() + + Convey("Get rules without error", func() { + So(err, ShouldBeNil) + }) + + Convey("Should have 2 alert rule", func() { + So(len(alerts), ShouldEqual, 2) + }) + }) + Convey("Parse and validate dashboard containing influxdb alert", func() { + json, err := ioutil.ReadFile("./test-data/influxdb-alert.json") + So(err, ShouldBeNil) - json2 := `{ - "id": 4, - "title": "Influxdb", - "tags": [ - "apa" - ], - "style": "dark", - "timezone": "browser", - "editable": true, - "hideControls": false, - "sharedCrosshair": false, - "rows": [ - { - "collapse": false, - "editable": true, - "height": "450px", - "panels": [ - { - "alert": { - "conditions": [ - { - "evaluator": { - "params": [ - 10 - ], - "type": "gt" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "avg" - }, - "type": "query" - } - ], - "frequency": "3s", - "handler": 1, - "name": "Influxdb", - "noDataState": "no_data", - "notifications": [ - { - "id": 6 - } - ] - }, - "alerting": {}, - "aliasColors": { - "logins.count.count": "#890F02" - }, - "bars": false, - "datasource": "InfluxDB", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 1, - "interval": ">10s", - "isNew": true, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "datacenter" - ], - "type": "tag" - }, - { - "params": [ - "none" - ], - "type": "fill" - } - ], - "hide": false, - "measurement": "logins.count", - "policy": "default", - "query": "SELECT 8 * count(\"value\") FROM \"logins.count\" WHERE $timeFilter GROUP BY time($interval), \"datacenter\" fill(none)", - "rawQuery": true, - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "count" - } - ] - ], - "tags": [] - }, - { - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "hide": true, - "measurement": "cpu", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ], - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 10 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Panel Title", - "tooltip": { - "msResolution": false, - "ordering": "alphabetical", - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "editable": true, - "error": false, - "id": 2, - "isNew": true, - "limit": 10, - "links": [], - "show": "current", - "span": 2, - "stateFilter": [ - "alerting" - ], - "title": "Alert status", - "type": "alertlist" - } - ], - "title": "Row" - } - ], - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": { - "now": true, - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "templating": { - "list": [] - }, - "annotations": { - "list": [] - }, - "schemaVersion": 13, - "version": 120, - "links": [], - "gnetId": null - }` - - dashJson, err := simplejson.NewJson([]byte(json2)) + dashJson, err := simplejson.NewJson(json) So(err, ShouldBeNil) dash := m.NewDashboardFromJson(dashJson) extractor := NewDashAlertExtractor(dash, 1) diff --git a/pkg/services/alerting/interfaces.go b/pkg/services/alerting/interfaces.go index 0955155575c..18f969ba1b9 100644 --- a/pkg/services/alerting/interfaces.go +++ b/pkg/services/alerting/interfaces.go @@ -15,7 +15,7 @@ type Notifier interface { Notify(evalContext *EvalContext) error GetType() string NeedsImage() bool - PassesFilter(rule *Rule) bool + ShouldNotify(evalContext *EvalContext) bool GetNotifierId() int64 GetIsDefault() bool diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index be74d41cc6c..af9ba52a52a 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -24,7 +24,7 @@ type NotifierPlugin struct { } type NotificationService interface { - Send(context *EvalContext) error + SendIfNeeded(context *EvalContext) error } func NewNotificationService() NotificationService { @@ -41,14 +41,12 @@ func newNotificationService() *notificationService { } } -func (n *notificationService) Send(context *EvalContext) error { - notifiers, err := n.getNotifiers(context.Rule.OrgId, context.Rule.Notifications, context) +func (n *notificationService) SendIfNeeded(context *EvalContext) error { + notifiers, err := n.getNeededNotifiers(context.Rule.OrgId, context.Rule.Notifications, context) if err != nil { return err } - n.log.Info("Sending notifications for", "ruleId", context.Rule.Id, "sent count", len(notifiers)) - if len(notifiers) == 0 { return nil } @@ -67,7 +65,7 @@ func (n *notificationService) sendNotifications(context *EvalContext, notifiers for _, notifier := range notifiers { not := notifier //avoid updating scope variable in go routine - n.log.Info("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault()) + n.log.Debug("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault()) metrics.M_Alerting_Notification_Sent.WithLabelValues(not.GetType()).Inc() g.Go(func() error { return not.Notify(context) }) } @@ -82,16 +80,17 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) { } renderOpts := &renderer.RenderOpts{ - Width: "800", - Height: "400", - Timeout: "30", - OrgId: context.Rule.OrgId, + Width: "800", + Height: "400", + Timeout: "30", + OrgId: context.Rule.OrgId, + IsAlertContext: true, } - if slug, err := context.GetDashboardSlug(); err != nil { + if ref, err := context.GetDashboardUID(); err != nil { return err } else { - renderOpts.Path = fmt.Sprintf("dashboard-solo/db/%s?&panelId=%d", slug, context.Rule.PanelId) + renderOpts.Path = fmt.Sprintf("d-solo/%s/%s?panelId=%d", ref.Uid, ref.Slug, context.Rule.PanelId) } if imagePath, err := renderer.RenderToPng(renderOpts); err != nil { @@ -109,7 +108,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) { return nil } -func (n *notificationService) getNotifiers(orgId int64, notificationIds []int64, context *EvalContext) (NotifierSlice, error) { +func (n *notificationService) getNeededNotifiers(orgId int64, notificationIds []int64, context *EvalContext) (NotifierSlice, error) { query := &m.GetAlertNotificationsToSendQuery{OrgId: orgId, Ids: notificationIds} if err := bus.Dispatch(query); err != nil { @@ -121,7 +120,7 @@ func (n *notificationService) getNotifiers(orgId int64, notificationIds []int64, if not, err := n.createNotifierFor(notification); err != nil { return nil, err } else { - if shouldUseNotification(not, context) { + if not.ShouldNotify(context) { result = append(result, not) } } @@ -139,18 +138,6 @@ func (n *notificationService) createNotifierFor(model *m.AlertNotification) (Not return notifierPlugin.Factory(model) } -func shouldUseNotification(notifier Notifier, context *EvalContext) bool { - if !context.Firing { - return true - } - - if context.Error != nil { - return true - } - - return notifier.PassesFilter(context.Rule) -} - type NotifierFactory func(notification *m.AlertNotification) (Notifier, error) var notifierFactories map[string]*NotifierPlugin = make(map[string]*NotifierPlugin) diff --git a/pkg/services/alerting/notifier_test.go b/pkg/services/alerting/notifier_test.go deleted file mode 100644 index 5e378dec890..00000000000 --- a/pkg/services/alerting/notifier_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package alerting - -import ( - "testing" - - "fmt" - - "github.com/grafana/grafana/pkg/models" - m "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" -) - -type FakeNotifier struct { - FakeMatchResult bool -} - -func (fn *FakeNotifier) GetType() string { - return "FakeNotifier" -} - -func (fn *FakeNotifier) NeedsImage() bool { - return true -} - -func (n *FakeNotifier) GetNotifierId() int64 { - return 0 -} - -func (n *FakeNotifier) GetIsDefault() bool { - return false -} - -func (fn *FakeNotifier) Notify(alertResult *EvalContext) error { return nil } - -func (fn *FakeNotifier) PassesFilter(rule *Rule) bool { - return fn.FakeMatchResult -} - -func TestAlertNotificationExtraction(t *testing.T) { - - Convey("Notifier tests", t, func() { - Convey("none firing alerts", func() { - ctx := &EvalContext{ - Firing: false, - Rule: &Rule{ - State: m.AlertStateAlerting, - }, - } - notifier := &FakeNotifier{FakeMatchResult: false} - - So(shouldUseNotification(notifier, ctx), ShouldBeTrue) - }) - - Convey("execution error cannot be ignored", func() { - ctx := &EvalContext{ - Firing: true, - Error: fmt.Errorf("I used to be a programmer just like you"), - Rule: &Rule{ - State: m.AlertStateOK, - }, - } - notifier := &FakeNotifier{FakeMatchResult: false} - - So(shouldUseNotification(notifier, ctx), ShouldBeTrue) - }) - - Convey("firing alert that match", func() { - ctx := &EvalContext{ - Firing: true, - Rule: &Rule{ - State: models.AlertStateAlerting, - }, - } - notifier := &FakeNotifier{FakeMatchResult: true} - - So(shouldUseNotification(notifier, ctx), ShouldBeTrue) - }) - - Convey("firing alert that dont match", func() { - ctx := &EvalContext{ - Firing: true, - Rule: &Rule{State: m.AlertStateOK}, - } - notifier := &FakeNotifier{FakeMatchResult: false} - - So(shouldUseNotification(notifier, ctx), ShouldBeFalse) - }) - }) -} diff --git a/pkg/services/alerting/notifiers/alertmanager.go b/pkg/services/alerting/notifiers/alertmanager.go new file mode 100644 index 00000000000..08f8e8be29c --- /dev/null +++ b/pkg/services/alerting/notifiers/alertmanager.go @@ -0,0 +1,96 @@ +package notifiers + +import ( + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" +) + +func init() { + alerting.RegisterNotifier(&alerting.NotifierPlugin{ + Type: "prometheus-alertmanager", + Name: "Prometheus Alertmanager", + Description: "Sends alert to Prometheus Alertmanager", + Factory: NewAlertmanagerNotifier, + OptionsTemplate: ` +

Alertmanager settings

+
+ Url + +
+ `, + }) +} + +func NewAlertmanagerNotifier(model *m.AlertNotification) (alerting.Notifier, error) { + url := model.Settings.Get("url").MustString() + if url == "" { + return nil, alerting.ValidationError{Reason: "Could not find url property in settings"} + } + + return &AlertmanagerNotifier{ + NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings), + Url: url, + log: log.New("alerting.notifier.prometheus-alertmanager"), + }, nil +} + +type AlertmanagerNotifier struct { + NotifierBase + Url string + log log.Logger +} + +func (this *AlertmanagerNotifier) ShouldNotify(evalContext *alerting.EvalContext) bool { + return evalContext.Rule.State == m.AlertStateAlerting +} + +func (this *AlertmanagerNotifier) Notify(evalContext *alerting.EvalContext) error { + + alerts := make([]interface{}, 0) + for _, match := range evalContext.EvalMatches { + alertJSON := simplejson.New() + alertJSON.Set("startsAt", evalContext.StartTime.UTC().Format(time.RFC3339)) + + if ruleUrl, err := evalContext.GetRuleUrl(); err == nil { + alertJSON.Set("generatorURL", ruleUrl) + } + + if evalContext.Rule.Message != "" { + alertJSON.SetPath([]string{"annotations", "description"}, evalContext.Rule.Message) + } + + tags := make(map[string]string) + if len(match.Tags) == 0 { + tags["metric"] = match.Metric + } else { + for k, v := range match.Tags { + tags[k] = v + } + } + tags["alertname"] = evalContext.Rule.Name + alertJSON.Set("labels", tags) + + alerts = append(alerts, alertJSON) + } + + bodyJSON := simplejson.NewFromAny(alerts) + body, _ := bodyJSON.MarshalJSON() + + cmd := &m.SendWebhookSync{ + Url: this.Url + "/api/v1/alerts", + HttpMethod: "POST", + Body: string(body), + } + + if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { + this.log.Error("Failed to send alertmanager", "error", err, "alertmanager", this.Name) + return err + } + + return nil +} diff --git a/pkg/services/alerting/notifiers/alertmanager_test.go b/pkg/services/alerting/notifiers/alertmanager_test.go new file mode 100644 index 00000000000..3549b536e48 --- /dev/null +++ b/pkg/services/alerting/notifiers/alertmanager_test.go @@ -0,0 +1,47 @@ +package notifiers + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestAlertmanagerNotifier(t *testing.T) { + Convey("Alertmanager notifier tests", t, func() { + + Convey("Parsing alert notification from settings", func() { + Convey("empty settings should return error", func() { + json := `{ }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "alertmanager", + Type: "alertmanager", + Settings: settingsJSON, + } + + _, err := NewAlertmanagerNotifier(model) + So(err, ShouldNotBeNil) + }) + + Convey("from settings", func() { + json := `{ "url": "http://127.0.0.1:9093/" }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "alertmanager", + Type: "alertmanager", + Settings: settingsJSON, + } + + not, err := NewAlertmanagerNotifier(model) + alertmanagerNotifier := not.(*AlertmanagerNotifier) + + So(err, ShouldBeNil) + So(alertmanagerNotifier.Url, ShouldEqual, "http://127.0.0.1:9093/") + }) + }) + }) +} diff --git a/pkg/services/alerting/notifiers/base.go b/pkg/services/alerting/notifiers/base.go index dc22e1acaa0..601f8fc24b1 100644 --- a/pkg/services/alerting/notifiers/base.go +++ b/pkg/services/alerting/notifiers/base.go @@ -2,6 +2,7 @@ package notifiers import ( "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" ) @@ -14,7 +15,7 @@ type NotifierBase struct { } func NewNotifierBase(id int64, isDefault bool, name, notifierType string, model *simplejson.Json) NotifierBase { - uploadImage := model.Get("uploadImage").MustBool(true) + uploadImage := model.Get("uploadImage").MustBool(false) return NotifierBase{ Id: id, @@ -25,7 +26,13 @@ func NewNotifierBase(id int64, isDefault bool, name, notifierType string, model } } -func (n *NotifierBase) PassesFilter(rule *alerting.Rule) bool { +func defaultShouldNotify(context *alerting.EvalContext) bool { + if context.PrevAlertState == context.Rule.State { + return false + } + if (context.PrevAlertState == m.AlertStatePending) && (context.Rule.State == m.AlertStateOK) { + return false + } return true } diff --git a/pkg/services/alerting/notifiers/base_test.go b/pkg/services/alerting/notifiers/base_test.go new file mode 100644 index 00000000000..4225e203a3d --- /dev/null +++ b/pkg/services/alerting/notifiers/base_test.go @@ -0,0 +1,32 @@ +package notifiers + +import ( + "context" + "testing" + + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" + . "github.com/smartystreets/goconvey/convey" +) + +func TestBaseNotifier(t *testing.T) { + Convey("Base notifier tests", t, func() { + Convey("should notify", func() { + Convey("pending -> ok", func() { + context := alerting.NewEvalContext(context.TODO(), &alerting.Rule{ + State: m.AlertStatePending, + }) + context.Rule.State = m.AlertStateOK + So(defaultShouldNotify(context), ShouldBeFalse) + }) + + Convey("ok -> alerting", func() { + context := alerting.NewEvalContext(context.TODO(), &alerting.Rule{ + State: m.AlertStateOK, + }) + context.Rule.State = m.AlertStateAlerting + So(defaultShouldNotify(context), ShouldBeTrue) + }) + }) + }) +} diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go index e32b9d34f91..c2029b1173c 100644 --- a/pkg/services/alerting/notifiers/dingding.go +++ b/pkg/services/alerting/notifiers/dingding.go @@ -38,6 +38,10 @@ func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error) }, nil } +func (this *DingDingNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + type DingDingNotifier struct { NotifierBase Url string diff --git a/pkg/services/alerting/notifiers/dingding_test.go b/pkg/services/alerting/notifiers/dingding_test.go index 3ca267dbf5b..f89bf6382ce 100644 --- a/pkg/services/alerting/notifiers/dingding_test.go +++ b/pkg/services/alerting/notifiers/dingding_test.go @@ -9,7 +9,7 @@ import ( ) func TestDingDingNotifier(t *testing.T) { - Convey("Line notifier tests", t, func() { + Convey("Dingding notifier tests", t, func() { Convey("empty settings should return error", func() { json := `{ }` @@ -25,10 +25,8 @@ func TestDingDingNotifier(t *testing.T) { }) Convey("settings should trigger incident", func() { - json := ` - { - "url": "https://www.google.com" - }` + json := `{ "url": "https://www.google.com" }` + settingsJSON, _ := simplejson.NewJson([]byte(json)) model := &m.AlertNotification{ Name: "dingding_testing", diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go index 7e8c4b33c0c..095f7c7156a 100644 --- a/pkg/services/alerting/notifiers/email.go +++ b/pkg/services/alerting/notifiers/email.go @@ -20,7 +20,7 @@ func init() { OptionsTemplate: `

Email addresses

- +
You can enter multiple email addresses using a ";" separator @@ -58,6 +58,10 @@ func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) { }, nil } +func (this *EmailNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *EmailNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Sending alert notification to", "addresses", this.Addresses) diff --git a/pkg/services/alerting/notifiers/hipchat.go b/pkg/services/alerting/notifiers/hipchat.go index f1f63d42a04..b65f25b1422 100644 --- a/pkg/services/alerting/notifiers/hipchat.go +++ b/pkg/services/alerting/notifiers/hipchat.go @@ -75,6 +75,10 @@ type HipChatNotifier struct { log log.Logger } +func (this *HipChatNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *HipChatNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Executing hipchat notification", "ruleId", evalContext.Rule.Id, "notification", this.Name) diff --git a/pkg/services/alerting/notifiers/kafka.go b/pkg/services/alerting/notifiers/kafka.go index 92f6489106b..e885d44405d 100644 --- a/pkg/services/alerting/notifiers/kafka.go +++ b/pkg/services/alerting/notifiers/kafka.go @@ -57,6 +57,10 @@ type KafkaNotifier struct { log log.Logger } +func (this *KafkaNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error { state := evalContext.Rule.State diff --git a/pkg/services/alerting/notifiers/line.go b/pkg/services/alerting/notifiers/line.go index 4fbaa2d543e..bc0b0c984a4 100644 --- a/pkg/services/alerting/notifiers/line.go +++ b/pkg/services/alerting/notifiers/line.go @@ -51,6 +51,10 @@ type LineNotifier struct { log log.Logger } +func (this *LineNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *LineNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Executing line notification", "ruleId", evalContext.Rule.Id, "notification", this.Name) diff --git a/pkg/services/alerting/notifiers/opsgenie.go b/pkg/services/alerting/notifiers/opsgenie.go index aea02465177..82be9d1df4e 100644 --- a/pkg/services/alerting/notifiers/opsgenie.go +++ b/pkg/services/alerting/notifiers/opsgenie.go @@ -23,6 +23,10 @@ func init() { API Key
+
+ Alert API Url + +
%s: %v", evt.Metric, evt.Value) @@ -142,6 +147,9 @@ func (this *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error { if evalContext.ImagePublicUrl != "" { message += fmt.Sprintf("\nShow graph image", evalContext.ImagePublicUrl) } + if message == "" { + message = "Notification message missing (Set a notification message to replace this text.)" + } q := url.Values{} q.Add("user", this.UserKey) diff --git a/pkg/services/alerting/notifiers/sensu.go b/pkg/services/alerting/notifiers/sensu.go index 9f77801d458..7a34d51b493 100644 --- a/pkg/services/alerting/notifiers/sensu.go +++ b/pkg/services/alerting/notifiers/sensu.go @@ -71,6 +71,10 @@ type SensuNotifier struct { log log.Logger } +func (this *SensuNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *SensuNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Sending sensu result") diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go index e051a71740a..c5bb9344e30 100644 --- a/pkg/services/alerting/notifiers/slack.go +++ b/pkg/services/alerting/notifiers/slack.go @@ -98,6 +98,10 @@ type SlackNotifier struct { log log.Logger } +func (this *SlackNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *SlackNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Executing slack notification", "ruleId", evalContext.Rule.Id, "notification", this.Name) diff --git a/pkg/services/alerting/notifiers/slack_test.go b/pkg/services/alerting/notifiers/slack_test.go index 13f8c7b48b7..dd82973bc95 100644 --- a/pkg/services/alerting/notifiers/slack_test.go +++ b/pkg/services/alerting/notifiers/slack_test.go @@ -78,7 +78,6 @@ func TestSlackNotifier(t *testing.T) { So(slackNotifier.Mention, ShouldEqual, "@carl") So(slackNotifier.Token, ShouldEqual, "xoxb-XXXXXXXX-XXXXXXXX-XXXXXXXXXX") }) - }) }) } diff --git a/pkg/services/alerting/notifiers/teams.go b/pkg/services/alerting/notifiers/teams.go index 200a8594428..851e5a01c75 100644 --- a/pkg/services/alerting/notifiers/teams.go +++ b/pkg/services/alerting/notifiers/teams.go @@ -47,6 +47,10 @@ type TeamsNotifier struct { log log.Logger } +func (this *TeamsNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Executing teams notification", "ruleId", evalContext.Rule.Id, "notification", this.Name) @@ -78,6 +82,8 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error { message := this.Mention if evalContext.Rule.State != m.AlertStateOK { //dont add message when going back to alert state ok. message += " " + evalContext.Rule.Message + } else { + message += " " // summary must not be empty } body := map[string]interface{}{ diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go index 7fb029e57c8..0ca1ad3dfe0 100644 --- a/pkg/services/alerting/notifiers/telegram.go +++ b/pkg/services/alerting/notifiers/telegram.go @@ -1,17 +1,19 @@ package notifiers import ( + "bytes" "fmt" - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" + "io" + "mime/multipart" + "os" ) var ( - telegeramApiUrl string = "https://api.telegram.org/bot%s/%s" + telegramApiUrl string = "https://api.telegram.org/bot%s/%s" ) func init() { @@ -47,9 +49,10 @@ func init() { type TelegramNotifier struct { NotifierBase - BotToken string - ChatID string - log log.Logger + BotToken string + ChatID string + UploadImage bool + log log.Logger } func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error) { @@ -59,6 +62,7 @@ func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error) botToken := model.Settings.Get("bottoken").MustString() chatId := model.Settings.Get("chatid").MustString() + uploadImage := model.Settings.Get("uploadImage").MustBool() if botToken == "" { return nil, alerting.ValidationError{Reason: "Could not find Bot Token in settings"} @@ -72,27 +76,42 @@ func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error) NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings), BotToken: botToken, ChatID: chatId, + UploadImage: uploadImage, log: log.New("alerting.notifier.telegram"), }, nil } -func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error { - this.log.Info("Sending alert notification to", "bot_token", this.BotToken) - this.log.Info("Sending alert notification to", "chat_id", this.ChatID) +func (this *TelegramNotifier) buildMessage(evalContext *alerting.EvalContext, sendImageInline bool) *m.SendWebhookSync { + var imageFile *os.File + var err error - bodyJSON := simplejson.New() + if sendImageInline { + imageFile, err = os.Open(evalContext.ImageOnDiskPath) + defer imageFile.Close() + if err != nil { + sendImageInline = false // fall back to text message + } + } - bodyJSON.Set("chat_id", this.ChatID) - bodyJSON.Set("parse_mode", "html") + message := "" - message := fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message) + if sendImageInline { + // Telegram's API does not allow HTML formatting for image captions. + message = fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message) + } else { + message = fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message) + } ruleUrl, err := evalContext.GetRuleUrl() if err == nil { message = message + fmt.Sprintf("URL: %s\n", ruleUrl) } - if evalContext.ImagePublicUrl != "" { - message = message + fmt.Sprintf("Image: %s\n", evalContext.ImagePublicUrl) + + if !sendImageInline { + // only attach this if we are not sending it inline. + if evalContext.ImagePublicUrl != "" { + message = message + fmt.Sprintf("Image: %s\n", evalContext.ImagePublicUrl) + } } metrics := "" @@ -103,19 +122,69 @@ func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error { break } } + if metrics != "" { - message = message + fmt.Sprintf("\nMetrics:%s", metrics) + if sendImageInline { + // Telegram's API does not allow HTML formatting for image captions. + message = message + fmt.Sprintf("\nMetrics:%s", metrics) + } else { + message = message + fmt.Sprintf("\nMetrics:%s", metrics) + } } - bodyJSON.Set("text", message) + var body bytes.Buffer - url := fmt.Sprintf(telegeramApiUrl, this.BotToken, "sendMessage") - body, _ := bodyJSON.MarshalJSON() + w := multipart.NewWriter(&body) + fw, _ := w.CreateFormField("chat_id") + fw.Write([]byte(this.ChatID)) + if sendImageInline { + fw, _ = w.CreateFormField("caption") + fw.Write([]byte(message)) + + fw, _ = w.CreateFormFile("photo", evalContext.ImageOnDiskPath) + io.Copy(fw, imageFile) + } else { + fw, _ = w.CreateFormField("text") + fw.Write([]byte(message)) + + fw, _ = w.CreateFormField("parse_mode") + fw.Write([]byte("html")) + } + + w.Close() + + apiMethod := "" + if sendImageInline { + this.log.Info("Sending telegram image notification", "photo", evalContext.ImageOnDiskPath, "chat_id", this.ChatID, "bot_token", this.BotToken) + apiMethod = "sendPhoto" + } else { + this.log.Info("Sending telegram text notification", "chat_id", this.ChatID, "bot_token", this.BotToken) + apiMethod = "sendMessage" + } + + url := fmt.Sprintf(telegramApiUrl, this.BotToken, apiMethod) cmd := &m.SendWebhookSync{ Url: url, - Body: string(body), + Body: body.String(), HttpMethod: "POST", + HttpHeader: map[string]string{ + "Content-Type": w.FormDataContentType(), + }, + } + return cmd +} + +func (this *TelegramNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + +func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error { + var cmd *m.SendWebhookSync + if evalContext.ImagePublicUrl == "" && this.UploadImage == true { + cmd = this.buildMessage(evalContext, true) + } else { + cmd = this.buildMessage(evalContext, false) } if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { diff --git a/pkg/services/alerting/notifiers/threema.go b/pkg/services/alerting/notifiers/threema.go index e4ffffc9108..b8455dcfbfd 100644 --- a/pkg/services/alerting/notifiers/threema.go +++ b/pkg/services/alerting/notifiers/threema.go @@ -114,6 +114,10 @@ func NewThreemaNotifier(model *m.AlertNotification) (alerting.Notifier, error) { }, nil } +func (this *ThreemaNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (notifier *ThreemaNotifier) Notify(evalContext *alerting.EvalContext) error { notifier.log.Info("Sending alert notification from", "threema_id", notifier.GatewayID) notifier.log.Info("Sending alert notification to", "threema_id", notifier.RecipientID) diff --git a/pkg/services/alerting/notifiers/victorops.go b/pkg/services/alerting/notifiers/victorops.go index 4b4db553cde..a2b770dfd02 100644 --- a/pkg/services/alerting/notifiers/victorops.go +++ b/pkg/services/alerting/notifiers/victorops.go @@ -68,6 +68,10 @@ type VictoropsNotifier struct { log log.Logger } +func (this *VictoropsNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + // Notify sends notification to Victorops via POST to URL endpoint func (this *VictoropsNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Executing victorops notification", "ruleId", evalContext.Rule.Id, "notification", this.Name) diff --git a/pkg/services/alerting/notifiers/webhook.go b/pkg/services/alerting/notifiers/webhook.go index 4c97ed2b75e..d2d6ec636b7 100644 --- a/pkg/services/alerting/notifiers/webhook.go +++ b/pkg/services/alerting/notifiers/webhook.go @@ -65,6 +65,10 @@ type WebhookNotifier struct { log log.Logger } +func (this *WebhookNotifier) ShouldNotify(context *alerting.EvalContext) bool { + return defaultShouldNotify(context) +} + func (this *WebhookNotifier) Notify(evalContext *alerting.EvalContext) error { this.log.Info("Sending webhook") diff --git a/pkg/services/alerting/notifiers/webhook_test.go b/pkg/services/alerting/notifiers/webhook_test.go index eb25130e4e1..b2d944eb6e9 100644 --- a/pkg/services/alerting/notifiers/webhook_test.go +++ b/pkg/services/alerting/notifiers/webhook_test.go @@ -18,7 +18,7 @@ func TestWebhookNotifier(t *testing.T) { settingsJSON, _ := simplejson.NewJson([]byte(json)) model := &m.AlertNotification{ Name: "ops", - Type: "email", + Type: "webhook", Settings: settingsJSON, } @@ -35,7 +35,7 @@ func TestWebhookNotifier(t *testing.T) { settingsJSON, _ := simplejson.NewJson([]byte(json)) model := &m.AlertNotification{ Name: "ops", - Type: "email", + Type: "webhook", Settings: settingsJSON, } @@ -44,7 +44,7 @@ func TestWebhookNotifier(t *testing.T) { So(err, ShouldBeNil) So(webhookNotifier.Name, ShouldEqual, "ops") - So(webhookNotifier.Type, ShouldEqual, "email") + So(webhookNotifier.Type, ShouldEqual, "webhook") So(webhookNotifier.Url, ShouldEqual, "http://google.com") }) }) diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 448b4ace5bb..8f9deb758a6 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -85,11 +85,9 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error { if err := annotationRepo.Save(&item); err != nil { handler.log.Error("Failed to save annotation for new alert state", "error", err) } - - if evalContext.ShouldSendNotification() { - handler.notifier.Send(evalContext) - } } + handler.notifier.SendIfNeeded(evalContext) + return nil } diff --git a/pkg/services/alerting/test-data/graphite-alert.json b/pkg/services/alerting/test-data/graphite-alert.json new file mode 100644 index 00000000000..5f23e224f9a --- /dev/null +++ b/pkg/services/alerting/test-data/graphite-alert.json @@ -0,0 +1,63 @@ +{ + "id": 57, + "title": "Graphite 4", + "originalTitle": "Graphite 4", + "tags": ["graphite"], + "rows": [ + { + "panels": [ + { + "title": "Active desktop users", + "editable": true, + "type": "graph", + "id": 3, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)" + } + ], + "datasource": null, + "alert": { + "name": "name1", + "message": "desc1", + "handler": 1, + "frequency": "60s", + "conditions": [ + { + "type": "query", + "query": {"params": ["A", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + }, + { + "title": "Active mobile users", + "id": 4, + "targets": [ + {"refId": "A", "target": ""}, + {"refId": "B", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} + ], + "datasource": "graphite2", + "alert": { + "name": "name2", + "message": "desc2", + "handler": 0, + "frequency": "60s", + "severity": "warning", + "conditions": [ + { + "type": "query", + "query": {"params": ["B", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + } + ] + } + ] + } \ No newline at end of file diff --git a/pkg/services/alerting/test-data/influxdb-alert.json b/pkg/services/alerting/test-data/influxdb-alert.json new file mode 100644 index 00000000000..79ca355c5a1 --- /dev/null +++ b/pkg/services/alerting/test-data/influxdb-alert.json @@ -0,0 +1,282 @@ +{ + "id": 4, + "title": "Influxdb", + "tags": [ + "apa" + ], + "style": "dark", + "timezone": "browser", + "editable": true, + "hideControls": false, + "sharedCrosshair": false, + "rows": [ + { + "collapse": false, + "editable": true, + "height": "450px", + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "frequency": "3s", + "handler": 1, + "name": "Influxdb", + "noDataState": "no_data", + "notifications": [ + { + "id": 6 + } + ] + }, + "alerting": {}, + "aliasColors": { + "logins.count.count": "#890F02" + }, + "bars": false, + "datasource": "InfluxDB", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 1, + "interval": ">10s", + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "datacenter" + ], + "type": "tag" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "logins.count", + "policy": "default", + "query": "SELECT 8 * count(\"value\") FROM \"logins.count\" WHERE $timeFilter GROUP BY time($interval), \"datacenter\" fill(none)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + } + ] + ], + "tags": [] + }, + { + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "cpu", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ], + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Panel Title", + "tooltip": { + "msResolution": false, + "ordering": "alphabetical", + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "editable": true, + "error": false, + "id": 2, + "isNew": true, + "limit": 10, + "links": [], + "show": "current", + "span": 2, + "stateFilter": [ + "alerting" + ], + "title": "Alert status", + "type": "alertlist" + } + ], + "title": "Row" + } + ], + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [] + }, + "annotations": { + "list": [] + }, + "schemaVersion": 13, + "version": 120, + "links": [], + "gnetId": null + } \ No newline at end of file diff --git a/pkg/services/alerting/test-data/panels-missing-id.json b/pkg/services/alerting/test-data/panels-missing-id.json new file mode 100644 index 00000000000..dad96a18dc1 --- /dev/null +++ b/pkg/services/alerting/test-data/panels-missing-id.json @@ -0,0 +1,62 @@ +{ + "id": 57, + "title": "Graphite 4", + "originalTitle": "Graphite 4", + "tags": ["graphite"], + "rows": [ + { + "panels": [ + { + "title": "Active desktop users", + "editable": true, + "type": "graph", + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)" + } + ], + "datasource": null, + "alert": { + "name": "name1", + "message": "desc1", + "handler": 1, + "frequency": "60s", + "conditions": [ + { + "type": "query", + "query": {"params": ["A", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + }, + { + "title": "Active mobile users", + "id": 4, + "targets": [ + {"refId": "A", "target": ""}, + {"refId": "B", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} + ], + "datasource": "graphite2", + "alert": { + "name": "name2", + "message": "desc2", + "handler": 0, + "frequency": "60s", + "severity": "warning", + "conditions": [ + { + "type": "query", + "query": {"params": ["B", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + } + ] + } + ] + } \ No newline at end of file diff --git a/pkg/services/alerting/test-data/v5-dashboard.json b/pkg/services/alerting/test-data/v5-dashboard.json new file mode 100644 index 00000000000..da7bbd8d048 --- /dev/null +++ b/pkg/services/alerting/test-data/v5-dashboard.json @@ -0,0 +1,60 @@ +{ + "id": 57, + "title": "Graphite 4", + "originalTitle": "Graphite 4", + "tags": ["graphite"], + "panels": [ + { + "title": "Active desktop users", + "editable": true, + "type": "graph", + "id": 3, + "targets": [ + { + "refId": "A", + "target": "aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)" + } + ], + "datasource": null, + "alert": { + "name": "name1", + "message": "desc1", + "handler": 1, + "frequency": "60s", + "conditions": [ + { + "type": "query", + "query": {"params": ["A", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + }, + { + "title": "Active mobile users", + "id": 4, + "targets": [ + {"refId": "A", "target": ""}, + {"refId": "B", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"} + ], + "datasource": "graphite2", + "alert": { + "name": "name2", + "message": "desc2", + "handler": 0, + "frequency": "60s", + "severity": "warning", + "conditions": [ + { + "type": "query", + "query": {"params": ["B", "5m", "now"]}, + "reducer": {"type": "avg", "params": []}, + "evaluator": {"type": ">", "params": [100]} + } + ] + } + + } + ] + } \ No newline at end of file diff --git a/pkg/services/alerting/ticker_test.go b/pkg/services/alerting/ticker_test.go index d4a5b958cdb..6670ee960a5 100644 --- a/pkg/services/alerting/ticker_test.go +++ b/pkg/services/alerting/ticker_test.go @@ -1,121 +1,121 @@ package alerting -import ( - "testing" - "time" - - "github.com/benbjohnson/clock" -) - -func inspectTick(tick time.Time, last time.Time, offset time.Duration, t *testing.T) { - if !tick.Equal(last.Add(time.Duration(1) * time.Second)) { - t.Fatalf("expected a tick 1 second more than prev, %s. got: %s", last, tick) - } -} - -// returns the new last tick seen -func assertAdvanceUntil(ticker *Ticker, last, desiredLast time.Time, offset, wait time.Duration, t *testing.T) time.Time { - for { - select { - case tick := <-ticker.C: - inspectTick(tick, last, offset, t) - last = tick - case <-time.NewTimer(wait).C: - if last.Before(desiredLast) { - t.Fatalf("waited %s for ticker to advance to %s, but only went up to %s", wait, desiredLast, last) - } - if last.After(desiredLast) { - t.Fatalf("timer advanced too far. should only have gone up to %s, but it went up to %s", desiredLast, last) - } - return last - } - } -} - -func assertNoAdvance(ticker *Ticker, desiredLast time.Time, wait time.Duration, t *testing.T) { - for { - select { - case tick := <-ticker.C: - t.Fatalf("timer should have stayed at %s, instead it advanced to %s", desiredLast, tick) - case <-time.NewTimer(wait).C: - return - } - } -} - -func TestTickerRetro1Hour(t *testing.T) { - offset := time.Duration(10) * time.Second - last := time.Unix(0, 0) - mock := clock.NewMock() - mock.Add(time.Duration(1) * time.Hour) - desiredLast := mock.Now().Add(-offset) - ticker := NewTicker(last, offset, mock) - - last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) - assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) - -} - -func TestAdvanceWithUpdateOffset(t *testing.T) { - offset := time.Duration(10) * time.Second - last := time.Unix(0, 0) - mock := clock.NewMock() - mock.Add(time.Duration(1) * time.Hour) - desiredLast := mock.Now().Add(-offset) - ticker := NewTicker(last, offset, mock) - - last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) - assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) - - // lowering offset should see a few more ticks - offset = time.Duration(5) * time.Second - ticker.updateOffset(offset) - desiredLast = mock.Now().Add(-offset) - last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t) - assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) - - // advancing clock should see even more ticks - mock.Add(time.Duration(1) * time.Hour) - desiredLast = mock.Now().Add(-offset) - last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t) - assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) - -} - -func getCase(lastSeconds, offsetSeconds int) (time.Time, time.Duration) { - last := time.Unix(int64(lastSeconds), 0) - offset := time.Duration(offsetSeconds) * time.Second - return last, offset -} - -func TestTickerNoAdvance(t *testing.T) { - - // it's 00:01:00 now. what are some cases where we don't want the ticker to advance? - mock := clock.NewMock() - mock.Add(time.Duration(60) * time.Second) - - type Case struct { - last int - offset int - } - - // note that some cases add up to now, others go into the future - cases := []Case{ - {50, 10}, - {50, 30}, - {59, 1}, - {59, 10}, - {59, 30}, - {60, 1}, - {60, 10}, - {60, 30}, - {90, 1}, - {90, 10}, - {90, 30}, - } - for _, c := range cases { - last, offset := getCase(c.last, c.offset) - ticker := NewTicker(last, offset, mock) - assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) - } -} +//import ( +// "testing" +// "time" +// +// "github.com/benbjohnson/clock" +//) +// +//func inspectTick(tick time.Time, last time.Time, offset time.Duration, t *testing.T) { +// if !tick.Equal(last.Add(time.Duration(1) * time.Second)) { +// t.Fatalf("expected a tick 1 second more than prev, %s. got: %s", last, tick) +// } +//} +// +//// returns the new last tick seen +//func assertAdvanceUntil(ticker *Ticker, last, desiredLast time.Time, offset, wait time.Duration, t *testing.T) time.Time { +// for { +// select { +// case tick := <-ticker.C: +// inspectTick(tick, last, offset, t) +// last = tick +// case <-time.NewTimer(wait).C: +// if last.Before(desiredLast) { +// t.Fatalf("waited %s for ticker to advance to %s, but only went up to %s", wait, desiredLast, last) +// } +// if last.After(desiredLast) { +// t.Fatalf("timer advanced too far. should only have gone up to %s, but it went up to %s", desiredLast, last) +// } +// return last +// } +// } +//} +// +//func assertNoAdvance(ticker *Ticker, desiredLast time.Time, wait time.Duration, t *testing.T) { +// for { +// select { +// case tick := <-ticker.C: +// t.Fatalf("timer should have stayed at %s, instead it advanced to %s", desiredLast, tick) +// case <-time.NewTimer(wait).C: +// return +// } +// } +//} +// +//func TestTickerRetro1Hour(t *testing.T) { +// offset := time.Duration(10) * time.Second +// last := time.Unix(0, 0) +// mock := clock.NewMock() +// mock.Add(time.Duration(1) * time.Hour) +// desiredLast := mock.Now().Add(-offset) +// ticker := NewTicker(last, offset, mock) +// +// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) +// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) +// +//} +// +//func TestAdvanceWithUpdateOffset(t *testing.T) { +// offset := time.Duration(10) * time.Second +// last := time.Unix(0, 0) +// mock := clock.NewMock() +// mock.Add(time.Duration(1) * time.Hour) +// desiredLast := mock.Now().Add(-offset) +// ticker := NewTicker(last, offset, mock) +// +// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) +// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) +// +// // lowering offset should see a few more ticks +// offset = time.Duration(5) * time.Second +// ticker.updateOffset(offset) +// desiredLast = mock.Now().Add(-offset) +// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t) +// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) +// +// // advancing clock should see even more ticks +// mock.Add(time.Duration(1) * time.Hour) +// desiredLast = mock.Now().Add(-offset) +// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t) +// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) +// +//} +// +//func getCase(lastSeconds, offsetSeconds int) (time.Time, time.Duration) { +// last := time.Unix(int64(lastSeconds), 0) +// offset := time.Duration(offsetSeconds) * time.Second +// return last, offset +//} +// +//func TestTickerNoAdvance(t *testing.T) { +// +// // it's 00:01:00 now. what are some cases where we don't want the ticker to advance? +// mock := clock.NewMock() +// mock.Add(time.Duration(60) * time.Second) +// +// type Case struct { +// last int +// offset int +// } +// +// // note that some cases add up to now, others go into the future +// cases := []Case{ +// {50, 10}, +// {50, 30}, +// {59, 1}, +// {59, 10}, +// {59, 30}, +// {60, 1}, +// {60, 10}, +// {60, 30}, +// {90, 1}, +// {90, 10}, +// {90, 30}, +// } +// for _, c := range cases { +// last, offset := getCase(c.last, c.offset) +// ticker := NewTicker(last, offset, mock) +// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) +// } +//} diff --git a/pkg/services/annotations/annotations.go b/pkg/services/annotations/annotations.go index 02f927a76ba..a6cd7a33318 100644 --- a/pkg/services/annotations/annotations.go +++ b/pkg/services/annotations/annotations.go @@ -10,14 +10,16 @@ type Repository interface { } type ItemQuery struct { - OrgId int64 `json:"orgId"` - From int64 `json:"from"` - To int64 `json:"to"` - AlertId int64 `json:"alertId"` - DashboardId int64 `json:"dashboardId"` - PanelId int64 `json:"panelId"` - Tags []string `json:"tags"` - Type string `json:"type"` + OrgId int64 `json:"orgId"` + From int64 `json:"from"` + To int64 `json:"to"` + AlertId int64 `json:"alertId"` + DashboardId int64 `json:"dashboardId"` + PanelId int64 `json:"panelId"` + AnnotationId int64 `json:"annotationId"` + RegionId int64 `json:"regionId"` + Tags []string `json:"tags"` + Type string `json:"type"` Limit int64 `json:"limit"` } diff --git a/pkg/services/cleanup/cleanup.go b/pkg/services/cleanup/cleanup.go index 6e5e7684100..5e9efeea3b0 100644 --- a/pkg/services/cleanup/cleanup.go +++ b/pkg/services/cleanup/cleanup.go @@ -46,6 +46,7 @@ func (service *CleanUpService) start(ctx context.Context) error { service.cleanUpTmpFiles() service.deleteExpiredSnapshots() service.deleteExpiredDashboardVersions() + service.deleteOldLoginAttempts() case <-ctx.Done(): return ctx.Err() } @@ -82,9 +83,34 @@ func (service *CleanUpService) cleanUpTmpFiles() { } func (service *CleanUpService) deleteExpiredSnapshots() { - bus.Dispatch(&m.DeleteExpiredSnapshotsCommand{}) + cmd := m.DeleteExpiredSnapshotsCommand{} + if err := bus.Dispatch(&cmd); err != nil { + service.log.Error("Failed to delete expired snapshots", "error", err.Error()) + } else { + service.log.Debug("Deleted expired snapshots", "rows affected", cmd.DeletedRows) + } } func (service *CleanUpService) deleteExpiredDashboardVersions() { - bus.Dispatch(&m.DeleteExpiredVersionsCommand{}) + cmd := m.DeleteExpiredVersionsCommand{} + if err := bus.Dispatch(&cmd); err != nil { + service.log.Error("Failed to delete expired dashboard versions", "error", err.Error()) + } else { + service.log.Debug("Deleted old/expired dashboard versions", "rows affected", cmd.DeletedRows) + } +} + +func (service *CleanUpService) deleteOldLoginAttempts() { + if setting.DisableBruteForceLoginProtection { + return + } + + cmd := m.DeleteOldLoginAttemptsCommand{ + OlderThan: time.Now().Add(time.Minute * -10), + } + if err := bus.Dispatch(&cmd); err != nil { + service.log.Error("Problem deleting expired login attempts", "error", err.Error()) + } else { + service.log.Debug("Deleted expired login attempts", "rows affected", cmd.DeletedRows) + } } diff --git a/pkg/services/dashboards/dashboard_service.go b/pkg/services/dashboards/dashboard_service.go new file mode 100644 index 00000000000..1f39394d757 --- /dev/null +++ b/pkg/services/dashboards/dashboard_service.go @@ -0,0 +1,237 @@ +package dashboards + +import ( + "strings" + "time" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/guardian" + "github.com/grafana/grafana/pkg/util" +) + +// DashboardService service for operating on dashboards +type DashboardService interface { + SaveDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) +} + +// DashboardProvisioningService service for operating on provisioned dashboards +type DashboardProvisioningService interface { + SaveProvisionedDashboard(dto *SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) + SaveFolderForProvisionedDashboards(*SaveDashboardDTO) (*models.Dashboard, error) + GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error) +} + +// NewService factory for creating a new dashboard service +var NewService = func() DashboardService { + return &dashboardServiceImpl{} +} + +// NewProvisioningService factory for creating a new dashboard provisioning service +var NewProvisioningService = func() DashboardProvisioningService { + return &dashboardServiceImpl{} +} + +type SaveDashboardDTO struct { + OrgId int64 + UpdatedAt time.Time + User *models.SignedInUser + Message string + Overwrite bool + Dashboard *models.Dashboard +} + +type dashboardServiceImpl struct { + orgId int64 + user *models.SignedInUser +} + +func (dr *dashboardServiceImpl) GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error) { + cmd := &models.GetProvisionedDashboardDataQuery{Name: name} + err := bus.Dispatch(cmd) + if err != nil { + return nil, err + } + + return cmd.Result, nil +} + +func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO, validateAlerts bool) (*models.SaveDashboardCommand, error) { + dash := dto.Dashboard + + dash.Title = strings.TrimSpace(dash.Title) + dash.Data.Set("title", dash.Title) + dash.SetUid(strings.TrimSpace(dash.Uid)) + + if dash.Title == "" { + return nil, models.ErrDashboardTitleEmpty + } + + if dash.IsFolder && dash.FolderId > 0 { + return nil, models.ErrDashboardFolderCannotHaveParent + } + + if dash.IsFolder && strings.ToLower(dash.Title) == strings.ToLower(models.RootFolderName) { + return nil, models.ErrDashboardFolderNameExists + } + + if !util.IsValidShortUid(dash.Uid) { + return nil, models.ErrDashboardInvalidUid + } else if len(dash.Uid) > 40 { + return nil, models.ErrDashboardUidToLong + } + + if validateAlerts { + validateAlertsCmd := models.ValidateDashboardAlertsCommand{ + OrgId: dto.OrgId, + Dashboard: dash, + } + + if err := bus.Dispatch(&validateAlertsCmd); err != nil { + return nil, models.ErrDashboardContainsInvalidAlertData + } + } + + validateBeforeSaveCmd := models.ValidateDashboardBeforeSaveCommand{ + OrgId: dto.OrgId, + Dashboard: dash, + Overwrite: dto.Overwrite, + } + + if err := bus.Dispatch(&validateBeforeSaveCmd); err != nil { + return nil, err + } + + guard := guardian.New(dash.GetDashboardIdForSavePermissionCheck(), dto.OrgId, dto.User) + if canSave, err := guard.CanSave(); err != nil || !canSave { + if err != nil { + return nil, err + } + return nil, models.ErrDashboardUpdateAccessDenied + } + + cmd := &models.SaveDashboardCommand{ + Dashboard: dash.Data, + Message: dto.Message, + OrgId: dto.OrgId, + Overwrite: dto.Overwrite, + UserId: dto.User.UserId, + FolderId: dash.FolderId, + IsFolder: dash.IsFolder, + PluginId: dash.PluginId, + } + + if !dto.UpdatedAt.IsZero() { + cmd.UpdatedAt = dto.UpdatedAt + } + + return cmd, nil +} + +func (dr *dashboardServiceImpl) updateAlerting(cmd *models.SaveDashboardCommand, dto *SaveDashboardDTO) error { + alertCmd := models.UpdateDashboardAlertsCommand{ + OrgId: dto.OrgId, + UserId: dto.User.UserId, + Dashboard: cmd.Result, + } + + if err := bus.Dispatch(&alertCmd); err != nil { + return models.ErrDashboardFailedToUpdateAlertData + } + + return nil +} + +func (dr *dashboardServiceImpl) SaveProvisionedDashboard(dto *SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) { + dto.User = &models.SignedInUser{ + UserId: 0, + OrgRole: models.ROLE_ADMIN, + } + cmd, err := dr.buildSaveDashboardCommand(dto, true) + if err != nil { + return nil, err + } + + saveCmd := &models.SaveProvisionedDashboardCommand{ + DashboardCmd: cmd, + DashboardProvisioning: provisioning, + } + + // dashboard + err = bus.Dispatch(saveCmd) + if err != nil { + return nil, err + } + + //alerts + err = dr.updateAlerting(cmd, dto) + if err != nil { + return nil, err + } + + return cmd.Result, nil +} + +func (dr *dashboardServiceImpl) SaveFolderForProvisionedDashboards(dto *SaveDashboardDTO) (*models.Dashboard, error) { + dto.User = &models.SignedInUser{ + UserId: 0, + OrgRole: models.ROLE_ADMIN, + } + cmd, err := dr.buildSaveDashboardCommand(dto, false) + if err != nil { + return nil, err + } + + err = bus.Dispatch(cmd) + if err != nil { + return nil, err + } + + err = dr.updateAlerting(cmd, dto) + if err != nil { + return nil, err + } + + return cmd.Result, nil +} + +func (dr *dashboardServiceImpl) SaveDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) { + cmd, err := dr.buildSaveDashboardCommand(dto, true) + if err != nil { + return nil, err + } + + err = bus.Dispatch(cmd) + if err != nil { + return nil, err + } + + err = dr.updateAlerting(cmd, dto) + if err != nil { + return nil, err + } + + return cmd.Result, nil +} + +type FakeDashboardService struct { + SaveDashboardResult *models.Dashboard + SaveDashboardError error + SavedDashboards []*SaveDashboardDTO +} + +func (s *FakeDashboardService) SaveDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) { + s.SavedDashboards = append(s.SavedDashboards, dto) + + if s.SaveDashboardResult == nil && s.SaveDashboardError == nil { + s.SaveDashboardResult = dto.Dashboard + } + + return s.SaveDashboardResult, s.SaveDashboardError +} + +func MockDashboardService(mock *FakeDashboardService) { + NewService = func() DashboardService { + return mock + } +} diff --git a/pkg/services/dashboards/dashboard_service_test.go b/pkg/services/dashboards/dashboard_service_test.go new file mode 100644 index 00000000000..965b10655b3 --- /dev/null +++ b/pkg/services/dashboards/dashboard_service_test.go @@ -0,0 +1,95 @@ +package dashboards + +import ( + "errors" + "testing" + + "github.com/grafana/grafana/pkg/services/guardian" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/models" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestDashboardService(t *testing.T) { + Convey("Dashboard service tests", t, func() { + service := dashboardServiceImpl{} + + origNewDashboardGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) + + Convey("Save dashboard validation", func() { + dto := &SaveDashboardDTO{} + + Convey("When saving a dashboard with empty title it should return error", func() { + titles := []string{"", " ", " \t "} + + for _, title := range titles { + dto.Dashboard = models.NewDashboard(title) + _, err := service.SaveDashboard(dto) + So(err, ShouldEqual, models.ErrDashboardTitleEmpty) + } + }) + + Convey("Should return validation error if it's a folder and have a folder id", func() { + dto.Dashboard = models.NewDashboardFolder("Folder") + dto.Dashboard.FolderId = 1 + _, err := service.SaveDashboard(dto) + So(err, ShouldEqual, models.ErrDashboardFolderCannotHaveParent) + }) + + Convey("Should return validation error if folder is named General", func() { + dto.Dashboard = models.NewDashboardFolder("General") + _, err := service.SaveDashboard(dto) + So(err, ShouldEqual, models.ErrDashboardFolderNameExists) + }) + + Convey("When saving a dashboard should validate uid", func() { + bus.AddHandler("test", func(cmd *models.ValidateDashboardAlertsCommand) error { + return nil + }) + + bus.AddHandler("test", func(cmd *models.ValidateDashboardBeforeSaveCommand) error { + return nil + }) + + testCases := []struct { + Uid string + Error error + }{ + {Uid: "", Error: nil}, + {Uid: " ", Error: nil}, + {Uid: " \t ", Error: nil}, + {Uid: "asdf90_-", Error: nil}, + {Uid: "asdf/90", Error: models.ErrDashboardInvalidUid}, + {Uid: " asdfghjklqwertyuiopzxcvbnmasdfghjklqwer ", Error: nil}, + {Uid: "asdfghjklqwertyuiopzxcvbnmasdfghjklqwertyuiopzxcvbnmasdfghjklqwertyuiopzxcvbnm", Error: models.ErrDashboardUidToLong}, + } + + for _, tc := range testCases { + dto.Dashboard = models.NewDashboard("title") + dto.Dashboard.SetUid(tc.Uid) + dto.User = &models.SignedInUser{} + + _, err := service.buildSaveDashboardCommand(dto, true) + So(err, ShouldEqual, tc.Error) + } + }) + + Convey("Should return validation error if alert data is invalid", func() { + bus.AddHandler("test", func(cmd *models.ValidateDashboardAlertsCommand) error { + return errors.New("error") + }) + + dto.Dashboard = models.NewDashboard("Dash") + _, err := service.SaveDashboard(dto) + So(err, ShouldEqual, models.ErrDashboardContainsInvalidAlertData) + }) + }) + + Reset(func() { + guardian.New = origNewDashboardGuardian + }) + }) +} diff --git a/pkg/services/dashboards/dashboards.go b/pkg/services/dashboards/dashboards.go deleted file mode 100644 index 24e9f240fd8..00000000000 --- a/pkg/services/dashboards/dashboards.go +++ /dev/null @@ -1,82 +0,0 @@ -package dashboards - -import ( - "time" - - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/alerting" -) - -type Repository interface { - SaveDashboard(*SaveDashboardItem) (*models.Dashboard, error) -} - -var repositoryInstance Repository - -func GetRepository() Repository { - return repositoryInstance -} - -func SetRepository(rep Repository) { - repositoryInstance = rep -} - -type SaveDashboardItem struct { - TitleLower string - OrgId int64 - Folder string - UpdatedAt time.Time - UserId int64 - Message string - Overwrite bool - Dashboard *models.Dashboard -} - -type DashboardRepository struct{} - -func (dr *DashboardRepository) SaveDashboard(json *SaveDashboardItem) (*models.Dashboard, error) { - dashboard := json.Dashboard - - if dashboard.Title == "" { - return nil, models.ErrDashboardTitleEmpty - } - - validateAlertsCmd := alerting.ValidateDashboardAlertsCommand{ - OrgId: json.OrgId, - Dashboard: dashboard, - } - - if err := bus.Dispatch(&validateAlertsCmd); err != nil { - return nil, models.ErrDashboardContainsInvalidAlertData - } - - cmd := models.SaveDashboardCommand{ - Dashboard: dashboard.Data, - Message: json.Message, - OrgId: json.OrgId, - Overwrite: json.Overwrite, - UserId: json.UserId, - } - - if !json.UpdatedAt.IsZero() { - cmd.UpdatedAt = json.UpdatedAt - } - - err := bus.Dispatch(&cmd) - if err != nil { - return nil, err - } - - alertCmd := alerting.UpdateDashboardAlertsCommand{ - OrgId: json.OrgId, - UserId: json.UserId, - Dashboard: cmd.Result, - } - - if err := bus.Dispatch(&alertCmd); err != nil { - return nil, models.ErrDashboardFailedToUpdateAlertData - } - - return cmd.Result, nil -} diff --git a/pkg/services/dashboards/folder_service.go b/pkg/services/dashboards/folder_service.go new file mode 100644 index 00000000000..66afa6306fb --- /dev/null +++ b/pkg/services/dashboards/folder_service.go @@ -0,0 +1,245 @@ +package dashboards + +import ( + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/guardian" + "github.com/grafana/grafana/pkg/services/search" +) + +// FolderService service for operating on folders +type FolderService interface { + GetFolders(limit int) ([]*models.Folder, error) + GetFolderById(id int64) (*models.Folder, error) + GetFolderByUid(uid string) (*models.Folder, error) + CreateFolder(cmd *models.CreateFolderCommand) error + UpdateFolder(uid string, cmd *models.UpdateFolderCommand) error + DeleteFolder(uid string) (*models.Folder, error) +} + +// NewFolderService factory for creating a new folder service +var NewFolderService = func(orgId int64, user *models.SignedInUser) FolderService { + return &dashboardServiceImpl{ + orgId: orgId, + user: user, + } +} + +func (dr *dashboardServiceImpl) GetFolders(limit int) ([]*models.Folder, error) { + if limit == 0 { + limit = 1000 + } + + searchQuery := search.Query{ + SignedInUser: dr.user, + DashboardIds: make([]int64, 0), + FolderIds: make([]int64, 0), + Limit: limit, + OrgId: dr.orgId, + Type: "dash-folder", + Permission: models.PERMISSION_VIEW, + } + + if err := bus.Dispatch(&searchQuery); err != nil { + return nil, err + } + + folders := make([]*models.Folder, 0) + + for _, hit := range searchQuery.Result { + folders = append(folders, &models.Folder{ + Id: hit.Id, + Uid: hit.Uid, + Title: hit.Title, + }) + } + + return folders, nil +} + +func (dr *dashboardServiceImpl) GetFolderById(id int64) (*models.Folder, error) { + query := models.GetDashboardQuery{OrgId: dr.orgId, Id: id} + dashFolder, err := getFolder(query) + + if err != nil { + return nil, toFolderError(err) + } + + g := guardian.New(dashFolder.Id, dr.orgId, dr.user) + if canView, err := g.CanView(); err != nil || !canView { + if err != nil { + return nil, toFolderError(err) + } + return nil, models.ErrFolderAccessDenied + } + + return dashToFolder(dashFolder), nil +} + +func (dr *dashboardServiceImpl) GetFolderByUid(uid string) (*models.Folder, error) { + query := models.GetDashboardQuery{OrgId: dr.orgId, Uid: uid} + dashFolder, err := getFolder(query) + + if err != nil { + return nil, toFolderError(err) + } + + g := guardian.New(dashFolder.Id, dr.orgId, dr.user) + if canView, err := g.CanView(); err != nil || !canView { + if err != nil { + return nil, toFolderError(err) + } + return nil, models.ErrFolderAccessDenied + } + + return dashToFolder(dashFolder), nil +} + +func (dr *dashboardServiceImpl) CreateFolder(cmd *models.CreateFolderCommand) error { + dashFolder := cmd.GetDashboardModel(dr.orgId, dr.user.UserId) + + dto := &SaveDashboardDTO{ + Dashboard: dashFolder, + OrgId: dr.orgId, + User: dr.user, + } + + saveDashboardCmd, err := dr.buildSaveDashboardCommand(dto, false) + if err != nil { + return toFolderError(err) + } + + err = bus.Dispatch(saveDashboardCmd) + if err != nil { + return toFolderError(err) + } + + query := models.GetDashboardQuery{OrgId: dr.orgId, Id: saveDashboardCmd.Result.Id} + dashFolder, err = getFolder(query) + if err != nil { + return toFolderError(err) + } + + cmd.Result = dashToFolder(dashFolder) + + return nil +} + +func (dr *dashboardServiceImpl) UpdateFolder(existingUid string, cmd *models.UpdateFolderCommand) error { + query := models.GetDashboardQuery{OrgId: dr.orgId, Uid: existingUid} + dashFolder, err := getFolder(query) + if err != nil { + return toFolderError(err) + } + + cmd.UpdateDashboardModel(dashFolder, dr.orgId, dr.user.UserId) + + dto := &SaveDashboardDTO{ + Dashboard: dashFolder, + OrgId: dr.orgId, + User: dr.user, + Overwrite: cmd.Overwrite, + } + + saveDashboardCmd, err := dr.buildSaveDashboardCommand(dto, false) + if err != nil { + return toFolderError(err) + } + + err = bus.Dispatch(saveDashboardCmd) + if err != nil { + return toFolderError(err) + } + + query = models.GetDashboardQuery{OrgId: dr.orgId, Id: saveDashboardCmd.Result.Id} + dashFolder, err = getFolder(query) + if err != nil { + return toFolderError(err) + } + + cmd.Result = dashToFolder(dashFolder) + + return nil +} + +func (dr *dashboardServiceImpl) DeleteFolder(uid string) (*models.Folder, error) { + query := models.GetDashboardQuery{OrgId: dr.orgId, Uid: uid} + dashFolder, err := getFolder(query) + if err != nil { + return nil, toFolderError(err) + } + + guardian := guardian.New(dashFolder.Id, dr.orgId, dr.user) + if canSave, err := guardian.CanSave(); err != nil || !canSave { + if err != nil { + return nil, toFolderError(err) + } + return nil, models.ErrFolderAccessDenied + } + + deleteCmd := models.DeleteDashboardCommand{OrgId: dr.orgId, Id: dashFolder.Id} + if err := bus.Dispatch(&deleteCmd); err != nil { + return nil, toFolderError(err) + } + + return dashToFolder(dashFolder), nil +} + +func getFolder(query models.GetDashboardQuery) (*models.Dashboard, error) { + if err := bus.Dispatch(&query); err != nil { + return nil, toFolderError(err) + } + + if !query.Result.IsFolder { + return nil, models.ErrFolderNotFound + } + + return query.Result, nil +} + +func dashToFolder(dash *models.Dashboard) *models.Folder { + return &models.Folder{ + Id: dash.Id, + Uid: dash.Uid, + Title: dash.Title, + HasAcl: dash.HasAcl, + Url: dash.GetUrl(), + Version: dash.Version, + Created: dash.Created, + CreatedBy: dash.CreatedBy, + Updated: dash.Updated, + UpdatedBy: dash.UpdatedBy, + } +} + +func toFolderError(err error) error { + if err == models.ErrDashboardTitleEmpty { + return models.ErrFolderTitleEmpty + } + + if err == models.ErrDashboardUpdateAccessDenied { + return models.ErrFolderAccessDenied + } + + if err == models.ErrDashboardWithSameNameInFolderExists { + return models.ErrFolderSameNameExists + } + + if err == models.ErrDashboardWithSameUIDExists { + return models.ErrFolderWithSameUIDExists + } + + if err == models.ErrDashboardVersionMismatch { + return models.ErrFolderVersionMismatch + } + + if err == models.ErrDashboardNotFound { + return models.ErrFolderNotFound + } + + if err == models.ErrDashboardFailedGenerateUniqueUid { + err = models.ErrFolderFailedGenerateUniqueUid + } + + return err +} diff --git a/pkg/services/dashboards/folder_service_test.go b/pkg/services/dashboards/folder_service_test.go new file mode 100644 index 00000000000..6357e84805a --- /dev/null +++ b/pkg/services/dashboards/folder_service_test.go @@ -0,0 +1,191 @@ +package dashboards + +import ( + "testing" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/models" + + "github.com/grafana/grafana/pkg/services/guardian" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestFolderService(t *testing.T) { + Convey("Folder service tests", t, func() { + service := dashboardServiceImpl{ + orgId: 1, + user: &models.SignedInUser{UserId: 1}, + } + + Convey("Given user has no permissions", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{}) + + bus.AddHandler("test", func(query *models.GetDashboardQuery) error { + query.Result = models.NewDashboardFolder("Folder") + return nil + }) + + bus.AddHandler("test", func(cmd *models.ValidateDashboardAlertsCommand) error { + return nil + }) + + bus.AddHandler("test", func(cmd *models.ValidateDashboardBeforeSaveCommand) error { + return models.ErrDashboardUpdateAccessDenied + }) + + Convey("When get folder by id should return access denied error", func() { + _, err := service.GetFolderById(1) + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrFolderAccessDenied) + }) + + Convey("When get folder by uid should return access denied error", func() { + _, err := service.GetFolderByUid("uid") + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrFolderAccessDenied) + }) + + Convey("When creating folder should return access denied error", func() { + err := service.CreateFolder(&models.CreateFolderCommand{ + Title: "Folder", + }) + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrFolderAccessDenied) + }) + + Convey("When updating folder should return access denied error", func() { + err := service.UpdateFolder("uid", &models.UpdateFolderCommand{ + Uid: "uid", + Title: "Folder", + }) + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrFolderAccessDenied) + }) + + Convey("When deleting folder by uid should return access denied error", func() { + _, err := service.DeleteFolder("uid") + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrFolderAccessDenied) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + + Convey("Given user has permission to save", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) + + dash := models.NewDashboardFolder("Folder") + dash.Id = 1 + + bus.AddHandler("test", func(query *models.GetDashboardQuery) error { + query.Result = dash + return nil + }) + + bus.AddHandler("test", func(cmd *models.ValidateDashboardAlertsCommand) error { + return nil + }) + + bus.AddHandler("test", func(cmd *models.ValidateDashboardBeforeSaveCommand) error { + return nil + }) + + bus.AddHandler("test", func(cmd *models.UpdateDashboardAlertsCommand) error { + return nil + }) + + bus.AddHandler("test", func(cmd *models.SaveDashboardCommand) error { + cmd.Result = dash + return nil + }) + + bus.AddHandler("test", func(cmd *models.DeleteDashboardCommand) error { + return nil + }) + + Convey("When creating folder should not return access denied error", func() { + err := service.CreateFolder(&models.CreateFolderCommand{ + Title: "Folder", + }) + So(err, ShouldBeNil) + }) + + Convey("When updating folder should not return access denied error", func() { + err := service.UpdateFolder("uid", &models.UpdateFolderCommand{ + Uid: "uid", + Title: "Folder", + }) + So(err, ShouldBeNil) + }) + + Convey("When deleting folder by uid should not return access denied error", func() { + _, err := service.DeleteFolder("uid") + So(err, ShouldBeNil) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + + Convey("Given user has permission to view", func() { + origNewGuardian := guardian.New + guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true}) + + dashFolder := models.NewDashboardFolder("Folder") + dashFolder.Id = 1 + dashFolder.Uid = "uid-abc" + + bus.AddHandler("test", func(query *models.GetDashboardQuery) error { + query.Result = dashFolder + return nil + }) + + Convey("When get folder by id should return folder", func() { + f, _ := service.GetFolderById(1) + So(f.Id, ShouldEqual, dashFolder.Id) + So(f.Uid, ShouldEqual, dashFolder.Uid) + So(f.Title, ShouldEqual, dashFolder.Title) + }) + + Convey("When get folder by uid should return folder", func() { + f, _ := service.GetFolderByUid("uid") + So(f.Id, ShouldEqual, dashFolder.Id) + So(f.Uid, ShouldEqual, dashFolder.Uid) + So(f.Title, ShouldEqual, dashFolder.Title) + }) + + Reset(func() { + guardian.New = origNewGuardian + }) + }) + + Convey("Should map errors correct", func() { + testCases := []struct { + ActualError error + ExpectedError error + }{ + {ActualError: models.ErrDashboardTitleEmpty, ExpectedError: models.ErrFolderTitleEmpty}, + {ActualError: models.ErrDashboardUpdateAccessDenied, ExpectedError: models.ErrFolderAccessDenied}, + {ActualError: models.ErrDashboardWithSameNameInFolderExists, ExpectedError: models.ErrFolderSameNameExists}, + {ActualError: models.ErrDashboardWithSameUIDExists, ExpectedError: models.ErrFolderWithSameUIDExists}, + {ActualError: models.ErrDashboardVersionMismatch, ExpectedError: models.ErrFolderVersionMismatch}, + {ActualError: models.ErrDashboardNotFound, ExpectedError: models.ErrFolderNotFound}, + {ActualError: models.ErrDashboardFailedGenerateUniqueUid, ExpectedError: models.ErrFolderFailedGenerateUniqueUid}, + {ActualError: models.ErrDashboardInvalidUid, ExpectedError: models.ErrDashboardInvalidUid}, + } + + for _, tc := range testCases { + actualError := toFolderError(tc.ActualError) + if actualError != tc.ExpectedError { + t.Errorf("For error '%s' expected error '%s', actual '%s'", tc.ActualError, tc.ExpectedError, actualError) + } + } + }) + }) +} diff --git a/pkg/services/guardian/guardian.go b/pkg/services/guardian/guardian.go new file mode 100644 index 00000000000..811b38cac86 --- /dev/null +++ b/pkg/services/guardian/guardian.go @@ -0,0 +1,262 @@ +package guardian + +import ( + "errors" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" +) + +var ( + ErrGuardianPermissionExists = errors.New("Permission already exists") + ErrGuardianOverride = errors.New("You can only override a permission to be higher") +) + +// DashboardGuardian to be used for guard against operations without access on dashboard and acl +type DashboardGuardian interface { + CanSave() (bool, error) + CanEdit() (bool, error) + CanView() (bool, error) + CanAdmin() (bool, error) + HasPermission(permission m.PermissionType) (bool, error) + CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) + GetAcl() ([]*m.DashboardAclInfoDTO, error) +} + +type dashboardGuardianImpl struct { + user *m.SignedInUser + dashId int64 + orgId int64 + acl []*m.DashboardAclInfoDTO + groups []*m.Team + log log.Logger +} + +// New factory for creating a new dashboard guardian instance +var New = func(dashId int64, orgId int64, user *m.SignedInUser) DashboardGuardian { + return &dashboardGuardianImpl{ + user: user, + dashId: dashId, + orgId: orgId, + log: log.New("guardians.dashboard"), + } +} + +func (g *dashboardGuardianImpl) CanSave() (bool, error) { + return g.HasPermission(m.PERMISSION_EDIT) +} + +func (g *dashboardGuardianImpl) CanEdit() (bool, error) { + if setting.ViewersCanEdit { + return g.HasPermission(m.PERMISSION_VIEW) + } + + return g.HasPermission(m.PERMISSION_EDIT) +} + +func (g *dashboardGuardianImpl) CanView() (bool, error) { + return g.HasPermission(m.PERMISSION_VIEW) +} + +func (g *dashboardGuardianImpl) CanAdmin() (bool, error) { + return g.HasPermission(m.PERMISSION_ADMIN) +} + +func (g *dashboardGuardianImpl) HasPermission(permission m.PermissionType) (bool, error) { + if g.user.OrgRole == m.ROLE_ADMIN { + return true, nil + } + + acl, err := g.GetAcl() + if err != nil { + return false, err + } + + return g.checkAcl(permission, acl) +} + +func (g *dashboardGuardianImpl) checkAcl(permission m.PermissionType, acl []*m.DashboardAclInfoDTO) (bool, error) { + orgRole := g.user.OrgRole + teamAclItems := []*m.DashboardAclInfoDTO{} + + for _, p := range acl { + // user match + if !g.user.IsAnonymous { + if p.UserId == g.user.UserId && p.Permission >= permission { + return true, nil + } + } + + // role match + if p.Role != nil { + if *p.Role == orgRole && p.Permission >= permission { + return true, nil + } + } + + // remember this rule for later + if p.TeamId > 0 { + teamAclItems = append(teamAclItems, p) + } + } + + // do we have team rules? + if len(teamAclItems) == 0 { + return false, nil + } + + // load teams + teams, err := g.getTeams() + if err != nil { + return false, err + } + + // evalute team rules + for _, p := range acl { + for _, ug := range teams { + if ug.Id == p.TeamId && p.Permission >= permission { + return true, nil + } + } + } + + return false, nil +} + +func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) { + acl := []*m.DashboardAclInfoDTO{} + adminRole := m.ROLE_ADMIN + everyoneWithAdminRole := &m.DashboardAclInfoDTO{DashboardId: g.dashId, UserId: 0, TeamId: 0, Role: &adminRole, Permission: m.PERMISSION_ADMIN} + + // validate that duplicate permissions don't exists + for _, p := range updatePermissions { + aclItem := &m.DashboardAclInfoDTO{DashboardId: p.DashboardId, UserId: p.UserId, TeamId: p.TeamId, Role: p.Role, Permission: p.Permission} + if aclItem.IsDuplicateOf(everyoneWithAdminRole) { + return false, ErrGuardianPermissionExists + } + + for _, a := range acl { + if a.IsDuplicateOf(aclItem) { + return false, ErrGuardianPermissionExists + } + } + + acl = append(acl, aclItem) + } + + existingPermissions, err := g.GetAcl() + if err != nil { + return false, err + } + + // validate overridden permissions to be higher + for _, a := range acl { + for _, existingPerm := range existingPermissions { + // handle default permissions + if existingPerm.DashboardId == -1 { + existingPerm.DashboardId = g.dashId + } + + if a.DashboardId == existingPerm.DashboardId { + continue + } + + if a.IsDuplicateOf(existingPerm) && a.Permission <= existingPerm.Permission { + return false, ErrGuardianOverride + } + } + } + + if g.user.OrgRole == m.ROLE_ADMIN { + return true, nil + } + + return g.checkAcl(permission, acl) +} + +// GetAcl returns dashboard acl +func (g *dashboardGuardianImpl) GetAcl() ([]*m.DashboardAclInfoDTO, error) { + if g.acl != nil { + return g.acl, nil + } + + query := m.GetDashboardAclInfoListQuery{DashboardId: g.dashId, OrgId: g.orgId} + if err := bus.Dispatch(&query); err != nil { + return nil, err + } + + for _, a := range query.Result { + // handle default permissions + if a.DashboardId == -1 { + a.DashboardId = g.dashId + } + } + + g.acl = query.Result + return g.acl, nil +} + +func (g *dashboardGuardianImpl) getTeams() ([]*m.Team, error) { + if g.groups != nil { + return g.groups, nil + } + + query := m.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId} + err := bus.Dispatch(&query) + + g.groups = query.Result + return query.Result, err +} + +type FakeDashboardGuardian struct { + DashId int64 + OrgId int64 + User *m.SignedInUser + CanSaveValue bool + CanEditValue bool + CanViewValue bool + CanAdminValue bool + HasPermissionValue bool + CheckPermissionBeforeUpdateValue bool + CheckPermissionBeforeUpdateError error + GetAclValue []*m.DashboardAclInfoDTO +} + +func (g *FakeDashboardGuardian) CanSave() (bool, error) { + return g.CanSaveValue, nil +} + +func (g *FakeDashboardGuardian) CanEdit() (bool, error) { + return g.CanEditValue, nil +} + +func (g *FakeDashboardGuardian) CanView() (bool, error) { + return g.CanViewValue, nil +} + +func (g *FakeDashboardGuardian) CanAdmin() (bool, error) { + return g.CanAdminValue, nil +} + +func (g *FakeDashboardGuardian) HasPermission(permission m.PermissionType) (bool, error) { + return g.HasPermissionValue, nil +} + +func (g *FakeDashboardGuardian) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) { + return g.CheckPermissionBeforeUpdateValue, g.CheckPermissionBeforeUpdateError +} + +func (g *FakeDashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) { + return g.GetAclValue, nil +} + +func MockDashboardGuardian(mock *FakeDashboardGuardian) { + New = func(dashId int64, orgId int64, user *m.SignedInUser) DashboardGuardian { + mock.OrgId = orgId + mock.DashId = dashId + mock.User = user + return mock + } +} diff --git a/pkg/services/guardian/guardian_test.go b/pkg/services/guardian/guardian_test.go new file mode 100644 index 00000000000..bb7e6bd1a72 --- /dev/null +++ b/pkg/services/guardian/guardian_test.go @@ -0,0 +1,711 @@ +package guardian + +import ( + "fmt" + "testing" + + "github.com/grafana/grafana/pkg/bus" + + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestGuardian(t *testing.T) { + Convey("Guardian permission tests", t, func() { + orgRoleScenario("Given user has admin org role", m.ROLE_ADMIN, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeTrue) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + + Convey("When trying to update permissions", func() { + Convey("With duplicate user permissions should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianPermissionExists) + }) + + Convey("With duplicate team permissions should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianPermissionExists) + }) + + Convey("With duplicate everyone with editor role permission should return error", func() { + r := m.ROLE_EDITOR + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianPermissionExists) + }) + + Convey("With duplicate everyone with viewer role permission should return error", func() { + r := m.ROLE_VIEWER + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianPermissionExists) + }) + + Convey("With everyone with admin role permission should return error", func() { + r := m.ROLE_ADMIN + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianPermissionExists) + }) + }) + + Convey("Given default permissions", func() { + editor := m.ROLE_EDITOR + viewer := m.ROLE_VIEWER + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: -1, Role: &editor, Permission: m.PERMISSION_EDIT}, + {OrgId: 1, DashboardId: -1, Role: &viewer, Permission: m.PERMISSION_VIEW}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions without everyone with role editor can edit should be allowed", func() { + r := m.ROLE_VIEWER + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_VIEW}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions without everyone with role viewer can view should be allowed", func() { + r := m.ROLE_EDITOR + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, Role: &r, Permission: m.PERMISSION_EDIT}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + }) + + Convey("Given parent folder has user admin permission", func() { + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with admin user permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with edit user permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with view user permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has user edit permission", func() { + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_EDIT}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with admin user permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with edit user permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with view user permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has user view permission", func() { + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, UserId: 1, Permission: m.PERMISSION_VIEW}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with admin user permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with edit user permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_EDIT}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with view user permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, UserId: 1, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has team admin permission", func() { + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_ADMIN}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with admin team permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with edit team permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with view team permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has team edit permission", func() { + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_EDIT}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with admin team permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with edit team permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with view team permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has team view permission", func() { + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, TeamId: 1, Permission: m.PERMISSION_VIEW}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with admin team permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with edit team permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_EDIT}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with view team permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, TeamId: 1, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has editor role with edit permission", func() { + r := m.ROLE_EDITOR + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, Role: &r, Permission: m.PERMISSION_EDIT}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with everyone with editor role can admin permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with everyone with editor role can edit permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_EDIT}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + + Convey("When trying to update dashboard permissions with everyone with editor role can view permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + + Convey("Given parent folder has editor role with view permission", func() { + r := m.ROLE_EDITOR + existingPermissions := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 2, Role: &r, Permission: m.PERMISSION_VIEW}, + } + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = existingPermissions + return nil + }) + + Convey("When trying to update dashboard permissions with everyone with viewer role can admin permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with everyone with viewer role can edit permission should be allowed", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_EDIT}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeTrue) + }) + + Convey("When trying to update dashboard permissions with everyone with viewer role can view permission should return error", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 3, Role: &r, Permission: m.PERMISSION_VIEW}, + } + _, err := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(err, ShouldEqual, ErrGuardianOverride) + }) + }) + }) + + orgRoleScenario("Given user has editor org role", m.ROLE_EDITOR, func(sc *scenarioContext) { + everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeTrue) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeTrue) + }) + + everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeFalse) + }) + + everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeFalse) + }) + + everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeFalse) + }) + + userWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeTrue) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + userWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + userWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeTrue) + }) + + teamWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeTrue) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + teamWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + teamWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeTrue) + }) + + Convey("When trying to update permissions should return false", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeFalse) + }) + }) + + orgRoleScenario("Given user has viewer org role", m.ROLE_VIEWER, func(sc *scenarioContext) { + everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeFalse) + }) + + everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeFalse) + }) + + everyoneWithRoleScenario(m.ROLE_EDITOR, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeFalse) + }) + + everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeTrue) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + everyoneWithRoleScenario(m.ROLE_VIEWER, m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeTrue) + }) + + userWithPermissionScenario(m.PERMISSION_ADMIN, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeTrue) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + userWithPermissionScenario(m.PERMISSION_EDIT, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeTrue) + So(canSave, ShouldBeTrue) + So(canView, ShouldBeTrue) + }) + + userWithPermissionScenario(m.PERMISSION_VIEW, sc, func(sc *scenarioContext) { + canAdmin, _ := sc.g.CanAdmin() + canEdit, _ := sc.g.CanEdit() + canSave, _ := sc.g.CanSave() + canView, _ := sc.g.CanView() + So(canAdmin, ShouldBeFalse) + So(canEdit, ShouldBeFalse) + So(canSave, ShouldBeFalse) + So(canView, ShouldBeTrue) + }) + + Convey("When trying to update permissions should return false", func() { + p := []*m.DashboardAcl{ + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_VIEW}, + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: m.PERMISSION_ADMIN}, + } + ok, _ := sc.g.CheckPermissionBeforeUpdate(m.PERMISSION_ADMIN, p) + So(ok, ShouldBeFalse) + }) + }) + }) +} + +type scenarioContext struct { + g DashboardGuardian +} + +type scenarioFunc func(c *scenarioContext) + +func orgRoleScenario(desc string, role m.RoleType, fn scenarioFunc) { + user := &m.SignedInUser{ + UserId: 1, + OrgId: 1, + OrgRole: role, + } + guard := New(1, 1, user) + sc := &scenarioContext{ + g: guard, + } + + Convey(desc, func() { + fn(sc) + }) +} + +func permissionScenario(desc string, sc *scenarioContext, permissions []*m.DashboardAclInfoDTO, fn scenarioFunc) { + bus.ClearBusHandlers() + + bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error { + query.Result = permissions + return nil + }) + + teams := []*m.Team{} + + for _, p := range permissions { + if p.TeamId > 0 { + teams = append(teams, &m.Team{Id: p.TeamId}) + } + } + + bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error { + query.Result = teams + return nil + }) + + Convey(desc, func() { + fn(sc) + }) +} + +func userWithPermissionScenario(permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) { + p := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 1, UserId: 1, Permission: permission}, + } + permissionScenario(fmt.Sprintf("and user has permission to %s item", permission), sc, p, fn) +} + +func teamWithPermissionScenario(permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) { + p := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 1, TeamId: 1, Permission: permission}, + } + permissionScenario(fmt.Sprintf("and team has permission to %s item", permission), sc, p, fn) +} + +func everyoneWithRoleScenario(role m.RoleType, permission m.PermissionType, sc *scenarioContext, fn scenarioFunc) { + p := []*m.DashboardAclInfoDTO{ + {OrgId: 1, DashboardId: 1, UserId: -1, Role: &role, Permission: permission}, + } + permissionScenario(fmt.Sprintf("and everyone with %s role can %s item", role, permission), sc, p, fn) +} diff --git a/pkg/services/provisioning/dashboards/config_reader.go b/pkg/services/provisioning/dashboards/config_reader.go index a602ca71df3..9030ba609b9 100644 --- a/pkg/services/provisioning/dashboards/config_reader.go +++ b/pkg/services/provisioning/dashboards/config_reader.go @@ -2,41 +2,79 @@ package dashboards import ( "io/ioutil" + "os" "path/filepath" "strings" + "github.com/grafana/grafana/pkg/log" yaml "gopkg.in/yaml.v2" ) type configReader struct { path string + log log.Logger } -func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) { - files, err := ioutil.ReadDir(cr.path) +func (cr *configReader) parseConfigs(file os.FileInfo) ([]*DashboardsAsConfig, error) { + filename, _ := filepath.Abs(filepath.Join(cr.path, file.Name())) + yamlFile, err := ioutil.ReadFile(filename) if err != nil { return nil, err } + apiVersion := &ConfigVersion{ApiVersion: 0} + yaml.Unmarshal(yamlFile, &apiVersion) + + if apiVersion.ApiVersion > 0 { + + v1 := &DashboardAsConfigV1{} + err := yaml.Unmarshal(yamlFile, &v1) + if err != nil { + return nil, err + } + + if v1 != nil { + return v1.mapToDashboardAsConfig(), nil + } + + } else { + var v0 []*DashboardsAsConfigV0 + err := yaml.Unmarshal(yamlFile, &v0) + if err != nil { + return nil, err + } + + if v0 != nil { + cr.log.Warn("[Deprecated] the dashboard provisioning config is outdated. please upgrade", "filename", filename) + return mapV0ToDashboardAsConfig(v0), nil + } + } + + return []*DashboardsAsConfig{}, nil +} + +func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) { var dashboards []*DashboardsAsConfig + + files, err := ioutil.ReadDir(cr.path) + if err != nil { + cr.log.Error("cant read dashboard provisioning files from directory", "path", cr.path) + return dashboards, nil + } + for _, file := range files { if !strings.HasSuffix(file.Name(), ".yaml") && !strings.HasSuffix(file.Name(), ".yml") { continue } - filename, _ := filepath.Abs(filepath.Join(cr.path, file.Name())) - yamlFile, err := ioutil.ReadFile(filename) + parsedDashboards, err := cr.parseConfigs(file) if err != nil { - return nil, err + } - var datasource []*DashboardsAsConfig - err = yaml.Unmarshal(yamlFile, &datasource) - if err != nil { - return nil, err + if len(parsedDashboards) > 0 { + dashboards = append(dashboards, parsedDashboards...) } - - dashboards = append(dashboards, datasource...) } for i := range dashboards { diff --git a/pkg/services/provisioning/dashboards/config_reader_test.go b/pkg/services/provisioning/dashboards/config_reader_test.go index 56c5a5fcf3d..ecbf6435c36 100644 --- a/pkg/services/provisioning/dashboards/config_reader_test.go +++ b/pkg/services/provisioning/dashboards/config_reader_test.go @@ -3,60 +3,79 @@ package dashboards import ( "testing" + "github.com/grafana/grafana/pkg/log" . "github.com/smartystreets/goconvey/convey" ) var ( simpleDashboardConfig string = "./test-configs/dashboards-from-disk" + oldVersion string = "./test-configs/version-0" brokenConfigs string = "./test-configs/broken-configs" ) func TestDashboardsAsConfig(t *testing.T) { Convey("Dashboards as configuration", t, func() { + logger := log.New("test-logger") - Convey("Can read config file", func() { + Convey("Can read config file version 1 format", func() { + cfgProvider := configReader{path: simpleDashboardConfig, log: logger} + cfg, err := cfgProvider.readConfig() + So(err, ShouldBeNil) - cfgProvifer := configReader{path: simpleDashboardConfig} - cfg, err := cfgProvifer.readConfig() - if err != nil { - t.Fatalf("readConfig return an error %v", err) - } - - So(len(cfg), ShouldEqual, 2) - - ds := cfg[0] - - So(ds.Name, ShouldEqual, "general dashboards") - So(ds.Type, ShouldEqual, "file") - So(ds.OrgId, ShouldEqual, 2) - So(ds.Folder, ShouldEqual, "developers") - So(ds.Editable, ShouldBeTrue) - - So(len(ds.Options), ShouldEqual, 1) - So(ds.Options["folder"], ShouldEqual, "/var/lib/grafana/dashboards") - - ds2 := cfg[1] - - So(ds2.Name, ShouldEqual, "default") - So(ds2.Type, ShouldEqual, "file") - So(ds2.OrgId, ShouldEqual, 1) - So(ds2.Folder, ShouldEqual, "") - So(ds2.Editable, ShouldBeFalse) - - So(len(ds2.Options), ShouldEqual, 1) - So(ds2.Options["folder"], ShouldEqual, "/var/lib/grafana/dashboards") + validateDashboardAsConfig(cfg) }) - Convey("Should skip broken config files", func() { + Convey("Can read config file in version 0 format", func() { + cfgProvider := configReader{path: oldVersion, log: logger} + cfg, err := cfgProvider.readConfig() + So(err, ShouldBeNil) - cfgProvifer := configReader{path: brokenConfigs} - cfg, err := cfgProvifer.readConfig() + validateDashboardAsConfig(cfg) + }) + + Convey("Should skip invalid path", func() { + + cfgProvider := configReader{path: "/invalid-directory", log: logger} + cfg, err := cfgProvider.readConfig() if err != nil { t.Fatalf("readConfig return an error %v", err) } So(len(cfg), ShouldEqual, 0) + }) + Convey("Should skip broken config files", func() { + + cfgProvider := configReader{path: brokenConfigs, log: logger} + cfg, err := cfgProvider.readConfig() + if err != nil { + t.Fatalf("readConfig return an error %v", err) + } + + So(len(cfg), ShouldEqual, 0) }) }) } +func validateDashboardAsConfig(cfg []*DashboardsAsConfig) { + So(len(cfg), ShouldEqual, 2) + + ds := cfg[0] + So(ds.Name, ShouldEqual, "general dashboards") + So(ds.Type, ShouldEqual, "file") + So(ds.OrgId, ShouldEqual, 2) + So(ds.Folder, ShouldEqual, "developers") + So(ds.Editable, ShouldBeTrue) + So(len(ds.Options), ShouldEqual, 1) + So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards") + So(ds.DisableDeletion, ShouldBeTrue) + + ds2 := cfg[1] + So(ds2.Name, ShouldEqual, "default") + So(ds2.Type, ShouldEqual, "file") + So(ds2.OrgId, ShouldEqual, 1) + So(ds2.Folder, ShouldEqual, "") + So(ds2.Editable, ShouldBeFalse) + So(len(ds2.Options), ShouldEqual, 1) + So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards") + So(ds2.DisableDeletion, ShouldBeFalse) +} diff --git a/pkg/services/provisioning/dashboards/dashboard.go b/pkg/services/provisioning/dashboards/dashboard.go index 1ee0f78497d..a5349517bbe 100644 --- a/pkg/services/provisioning/dashboards/dashboard.go +++ b/pkg/services/provisioning/dashboards/dashboard.go @@ -14,9 +14,10 @@ type DashboardProvisioner struct { } func Provision(ctx context.Context, configDirectory string) (*DashboardProvisioner, error) { + log := log.New("provisioning.dashboard") d := &DashboardProvisioner{ - cfgReader: &configReader{path: configDirectory}, - log: log.New("provisioning.dashboard"), + cfgReader: &configReader{path: configDirectory, log: log}, + log: log, ctx: ctx, } diff --git a/pkg/services/provisioning/dashboards/file_reader.go b/pkg/services/provisioning/dashboards/file_reader.go index 42f232bca82..d3e9892c8f5 100644 --- a/pkg/services/provisioning/dashboards/file_reader.go +++ b/pkg/services/provisioning/dashboards/file_reader.go @@ -2,6 +2,7 @@ package dashboards import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -15,21 +16,31 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/models" - gocache "github.com/patrickmn/go-cache" +) + +var ( + checkDiskForChangesInterval time.Duration = time.Second * 3 + + ErrFolderNameMissing error = errors.New("Folder name missing") ) type fileReader struct { - Cfg *DashboardsAsConfig - Path string - log log.Logger - dashboardRepo dashboards.Repository - cache *gocache.Cache + Cfg *DashboardsAsConfig + Path string + log log.Logger + dashboardService dashboards.DashboardProvisioningService } func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReader, error) { - path, ok := cfg.Options["folder"].(string) + var path string + path, ok := cfg.Options["path"].(string) if !ok { - return nil, fmt.Errorf("Failed to load dashboards. folder param is not a string") + path, ok = cfg.Options["folder"].(string) + if !ok { + return nil, fmt.Errorf("Failed to load dashboards. path param is not a string") + } + + log.Warn("[Deprecated] The folder property is deprecated. Please use path instead.") } if _, err := os.Stat(path); os.IsNotExist(err) { @@ -37,48 +48,31 @@ func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReade } return &fileReader{ - Cfg: cfg, - Path: path, - log: log, - dashboardRepo: dashboards.GetRepository(), - cache: gocache.New(5*time.Minute, 30*time.Minute), + Cfg: cfg, + Path: path, + log: log, + dashboardService: dashboards.NewProvisioningService(), }, nil } -func (fr *fileReader) addCache(key string, json *dashboards.SaveDashboardItem) { - fr.cache.Add(key, json, time.Minute*10) -} - -func (fr *fileReader) getCache(key string) (*dashboards.SaveDashboardItem, bool) { - obj, exist := fr.cache.Get(key) - if !exist { - return nil, exist - } - - dash, ok := obj.(*dashboards.SaveDashboardItem) - if !ok { - return nil, ok - } - - return dash, ok -} - func (fr *fileReader) ReadAndListen(ctx context.Context) error { - ticker := time.NewTicker(time.Second * 3) - - if err := fr.walkFolder(); err != nil { + if err := fr.startWalkingDisk(); err != nil { fr.log.Error("failed to search for dashboards", "error", err) } + ticker := time.NewTicker(checkDiskForChangesInterval) + running := false for { select { case <-ticker.C: - if !running { // avoid walking the filesystem in parallel. incase fs is very slow. + if !running { // avoid walking the filesystem in parallel. in-case fs is very slow. running = true go func() { - fr.walkFolder() + if err := fr.startWalkingDisk(); err != nil { + fr.log.Error("failed to search for dashboards", "error", err) + } running = false }() } @@ -88,66 +82,203 @@ func (fr *fileReader) ReadAndListen(ctx context.Context) error { } } -func (fr *fileReader) walkFolder() error { +func (fr *fileReader) startWalkingDisk() error { if _, err := os.Stat(fr.Path); err != nil { if os.IsNotExist(err) { return err } } - return filepath.Walk(fr.Path, func(path string, fileInfo os.FileInfo, err error) error { - if err != nil { - return err - } - if fileInfo.IsDir() { - if strings.HasPrefix(fileInfo.Name(), ".") { - return filepath.SkipDir - } - return nil - } - - if !strings.HasSuffix(fileInfo.Name(), ".json") { - return nil - } - - cachedDashboard, exist := fr.getCache(path) - if exist && cachedDashboard.UpdatedAt == fileInfo.ModTime() { - return nil - } - - dash, err := fr.readDashboardFromFile(path) - if err != nil { - fr.log.Error("failed to load dashboard from ", "file", path, "error", err) - return nil - } - - cmd := &models.GetDashboardQuery{Slug: dash.Dashboard.Slug} - err = bus.Dispatch(cmd) - - // if we dont have the dashboard in the db, save it! - if err == models.ErrDashboardNotFound { - fr.log.Debug("saving new dashboard", "file", path) - _, err = fr.dashboardRepo.SaveDashboard(dash) - return err - } - - if err != nil { - fr.log.Error("failed to query for dashboard", "slug", dash.Dashboard.Slug, "error", err) - return nil - } - - // break if db version is newer then fil version - if cmd.Result.Updated.Unix() >= fileInfo.ModTime().Unix() { - return nil - } - - fr.log.Debug("loading dashboard from disk into database.", "file", path) - _, err = fr.dashboardRepo.SaveDashboard(dash) + folderId, err := getOrCreateFolderId(fr.Cfg, fr.dashboardService) + if err != nil && err != ErrFolderNameMissing { return err - }) + } + + provisionedDashboardRefs, err := getProvisionedDashboardByPath(fr.dashboardService, fr.Cfg.Name) + if err != nil { + return err + } + + filesFoundOnDisk := map[string]os.FileInfo{} + err = filepath.Walk(fr.Path, createWalkFn(filesFoundOnDisk)) + if err != nil { + return err + } + + fr.deleteDashboardIfFileIsMissing(provisionedDashboardRefs, filesFoundOnDisk) + + sanityChecker := newProvisioningSanityChecker(fr.Cfg.Name) + + // save dashboards based on json files + for path, fileInfo := range filesFoundOnDisk { + provisioningMetadata, err := fr.saveDashboard(path, folderId, fileInfo, provisionedDashboardRefs) + sanityChecker.track(provisioningMetadata) + if err != nil { + fr.log.Error("failed to save dashboard", "error", err) + } + } + sanityChecker.logWarnings(fr.log) + + return nil +} +func (fr *fileReader) deleteDashboardIfFileIsMissing(provisionedDashboardRefs map[string]*models.DashboardProvisioning, filesFoundOnDisk map[string]os.FileInfo) { + if fr.Cfg.DisableDeletion { + return + } + + // find dashboards to delete since json file is missing + var dashboardToDelete []int64 + for path, provisioningData := range provisionedDashboardRefs { + _, existsOnDisk := filesFoundOnDisk[path] + if !existsOnDisk { + dashboardToDelete = append(dashboardToDelete, provisioningData.DashboardId) + } + } + // delete dashboard that are missing json file + for _, dashboardId := range dashboardToDelete { + fr.log.Debug("deleting provisioned dashboard. missing on disk", "id", dashboardId) + cmd := &models.DeleteDashboardCommand{OrgId: fr.Cfg.OrgId, Id: dashboardId} + err := bus.Dispatch(cmd) + if err != nil { + fr.log.Error("failed to delete dashboard", "id", cmd.Id) + } + } } -func (fr *fileReader) readDashboardFromFile(path string) (*dashboards.SaveDashboardItem, error) { +func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.FileInfo, provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) { + provisioningMetadata := provisioningMetadata{} + resolvedFileInfo, err := resolveSymlink(fileInfo, path) + if err != nil { + return provisioningMetadata, err + } + + provisionedData, alreadyProvisioned := provisionedDashboardRefs[path] + upToDate := alreadyProvisioned && provisionedData.Updated == resolvedFileInfo.ModTime().Unix() + + dash, err := fr.readDashboardFromFile(path, resolvedFileInfo.ModTime(), folderId) + if err != nil { + fr.log.Error("failed to load dashboard from ", "file", path, "error", err) + return provisioningMetadata, nil + } + + // keeps track of what uid's and title's we have already provisioned + provisioningMetadata.uid = dash.Dashboard.Uid + provisioningMetadata.title = dash.Dashboard.Title + + if upToDate { + return provisioningMetadata, nil + } + + if dash.Dashboard.Id != 0 { + fr.log.Error("provisioned dashboard json files cannot contain id") + return provisioningMetadata, nil + } + + if alreadyProvisioned { + dash.Dashboard.SetId(provisionedData.DashboardId) + } + + fr.log.Debug("saving new dashboard", "file", path) + dp := &models.DashboardProvisioning{ExternalId: path, Name: fr.Cfg.Name, Updated: resolvedFileInfo.ModTime().Unix()} + _, err = fr.dashboardService.SaveProvisionedDashboard(dash, dp) + return provisioningMetadata, err +} + +func getProvisionedDashboardByPath(service dashboards.DashboardProvisioningService, name string) (map[string]*models.DashboardProvisioning, error) { + arr, err := service.GetProvisionedDashboardData(name) + if err != nil { + return nil, err + } + + byPath := map[string]*models.DashboardProvisioning{} + for _, pd := range arr { + byPath[pd.ExternalId] = pd + } + + return byPath, nil +} + +func getOrCreateFolderId(cfg *DashboardsAsConfig, service dashboards.DashboardProvisioningService) (int64, error) { + if cfg.Folder == "" { + return 0, ErrFolderNameMissing + } + + cmd := &models.GetDashboardQuery{Slug: models.SlugifyTitle(cfg.Folder), OrgId: cfg.OrgId} + err := bus.Dispatch(cmd) + + if err != nil && err != models.ErrDashboardNotFound { + return 0, err + } + + // dashboard folder not found. create one. + if err == models.ErrDashboardNotFound { + dash := &dashboards.SaveDashboardDTO{} + dash.Dashboard = models.NewDashboardFolder(cfg.Folder) + dash.Dashboard.IsFolder = true + dash.Overwrite = true + dash.OrgId = cfg.OrgId + dbDash, err := service.SaveFolderForProvisionedDashboards(dash) + if err != nil { + return 0, err + } + + return dbDash.Id, nil + } + + if !cmd.Result.IsFolder { + return 0, fmt.Errorf("got invalid response. expected folder, found dashboard") + } + + return cmd.Result.Id, nil +} + +func resolveSymlink(fileinfo os.FileInfo, path string) (os.FileInfo, error) { + checkFilepath, err := filepath.EvalSymlinks(path) + if path != checkFilepath { + path = checkFilepath + fi, err := os.Lstat(checkFilepath) + if err != nil { + return nil, err + } + + return fi, nil + } + + return fileinfo, err +} + +func createWalkFn(filesOnDisk map[string]os.FileInfo) filepath.WalkFunc { + return func(path string, fileInfo os.FileInfo, err error) error { + if err != nil { + return err + } + + isValid, err := validateWalkablePath(fileInfo) + if !isValid { + return err + } + + filesOnDisk[path] = fileInfo + return nil + } +} + +func validateWalkablePath(fileInfo os.FileInfo) (bool, error) { + if fileInfo.IsDir() { + if strings.HasPrefix(fileInfo.Name(), ".") { + return false, filepath.SkipDir + } + return false, nil + } + + if !strings.HasSuffix(fileInfo.Name(), ".json") { + return false, nil + } + + return true, nil +} + +func (fr *fileReader) readDashboardFromFile(path string, lastModified time.Time, folderId int64) (*dashboards.SaveDashboardDTO, error) { reader, err := os.Open(path) if err != nil { return nil, err @@ -159,17 +290,53 @@ func (fr *fileReader) readDashboardFromFile(path string) (*dashboards.SaveDashbo return nil, err } - stat, err := os.Stat(path) + dash, err := createDashboardJson(data, lastModified, fr.Cfg, folderId) if err != nil { return nil, err } - dash, err := createDashboardJson(data, stat.ModTime(), fr.Cfg) - if err != nil { - return nil, err - } - - fr.addCache(path, dash) - return dash, nil } + +type provisioningMetadata struct { + uid string + title string +} + +func newProvisioningSanityChecker(provisioningProvider string) provisioningSanityChecker { + return provisioningSanityChecker{ + provisioningProvider: provisioningProvider, + uidUsage: map[string]uint8{}, + titleUsage: map[string]uint8{}} +} + +type provisioningSanityChecker struct { + provisioningProvider string + uidUsage map[string]uint8 + titleUsage map[string]uint8 +} + +func (checker provisioningSanityChecker) track(pm provisioningMetadata) { + if len(pm.uid) > 0 { + checker.uidUsage[pm.uid] += 1 + } + if len(pm.title) > 0 { + checker.titleUsage[pm.title] += 1 + } + +} + +func (checker provisioningSanityChecker) logWarnings(log log.Logger) { + for uid, times := range checker.uidUsage { + if times > 1 { + log.Error("the same 'uid' is used more than once", "uid", uid, "provider", checker.provisioningProvider) + } + } + + for title, times := range checker.titleUsage { + if times > 1 { + log.Error("the same 'title' is used more than once", "title", title, "provider", checker.provisioningProvider) + } + } + +} diff --git a/pkg/services/provisioning/dashboards/file_reader_test.go b/pkg/services/provisioning/dashboards/file_reader_test.go index e91f278322a..cd5e3456734 100644 --- a/pkg/services/provisioning/dashboards/file_reader_test.go +++ b/pkg/services/provisioning/dashboards/file_reader_test.go @@ -2,6 +2,7 @@ package dashboards import ( "os" + "path/filepath" "testing" "time" @@ -18,115 +19,234 @@ var ( brokenDashboards string = "./test-dashboards/broken-dashboards" oneDashboard string = "./test-dashboards/one-dashboard" - fakeRepo *fakeDashboardRepo + fakeService *fakeDashboardProvisioningService ) func TestDashboardFileReader(t *testing.T) { - Convey("Reading dashboards from disk", t, func() { + Convey("Dashboard file reader", t, func() { bus.ClearBusHandlers() - fakeRepo = &fakeDashboardRepo{} + origNewDashboardProvisioningService := dashboards.NewProvisioningService + fakeService = mockDashboardProvisioningService() bus.AddHandler("test", mockGetDashboardQuery) - dashboards.SetRepository(fakeRepo) logger := log.New("test.logger") - cfg := &DashboardsAsConfig{ - Name: "Default", - Type: "file", - OrgId: 1, - Folder: "", - Options: map[string]interface{}{}, - } + Convey("Reading dashboards from disk", func() { - Convey("Can read default dashboard", func() { - cfg.Options["folder"] = defaultDashboards - - reader, err := NewDashboardFileReader(cfg, logger) - So(err, ShouldBeNil) - - err = reader.walkFolder() - So(err, ShouldBeNil) - - So(len(fakeRepo.inserted), ShouldEqual, 2) - }) - - Convey("Should not update dashboards when db is newer", func() { - cfg.Options["folder"] = oneDashboard - - fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{ - Updated: time.Now().Add(time.Hour), - Slug: "grafana", - }) - - reader, err := NewDashboardFileReader(cfg, logger) - So(err, ShouldBeNil) - - err = reader.walkFolder() - So(err, ShouldBeNil) - - So(len(fakeRepo.inserted), ShouldEqual, 0) - }) - - Convey("Can read default dashboard and replace old version in database", func() { - cfg.Options["folder"] = oneDashboard - - stat, _ := os.Stat(oneDashboard + "/dashboard1.json") - - fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{ - Updated: stat.ModTime().AddDate(0, 0, -1), - Slug: "grafana", - }) - - reader, err := NewDashboardFileReader(cfg, logger) - So(err, ShouldBeNil) - - err = reader.walkFolder() - So(err, ShouldBeNil) - - So(len(fakeRepo.inserted), ShouldEqual, 1) - }) - - Convey("Invalid configuration should return error", func() { cfg := &DashboardsAsConfig{ - Name: "Default", - Type: "file", - OrgId: 1, - Folder: "", + Name: "Default", + Type: "file", + OrgId: 1, + Folder: "", + Options: map[string]interface{}{}, } - _, err := NewDashboardFileReader(cfg, logger) - So(err, ShouldNotBeNil) + Convey("Can read default dashboard", func() { + cfg.Options["path"] = defaultDashboards + cfg.Folder = "Team A" + + reader, err := NewDashboardFileReader(cfg, logger) + So(err, ShouldBeNil) + + err = reader.startWalkingDisk() + So(err, ShouldBeNil) + + folders := 0 + dashboards := 0 + + for _, i := range fakeService.inserted { + if i.Dashboard.IsFolder { + folders++ + } else { + dashboards++ + } + } + + So(folders, ShouldEqual, 1) + So(dashboards, ShouldEqual, 2) + }) + + Convey("Can read default dashboard and replace old version in database", func() { + cfg.Options["path"] = oneDashboard + + stat, _ := os.Stat(oneDashboard + "/dashboard1.json") + + fakeService.getDashboard = append(fakeService.getDashboard, &models.Dashboard{ + Updated: stat.ModTime().AddDate(0, 0, -1), + Slug: "grafana", + }) + + reader, err := NewDashboardFileReader(cfg, logger) + So(err, ShouldBeNil) + + err = reader.startWalkingDisk() + So(err, ShouldBeNil) + + So(len(fakeService.inserted), ShouldEqual, 1) + }) + + Convey("Invalid configuration should return error", func() { + cfg := &DashboardsAsConfig{ + Name: "Default", + Type: "file", + OrgId: 1, + Folder: "", + } + + _, err := NewDashboardFileReader(cfg, logger) + So(err, ShouldNotBeNil) + }) + + Convey("Broken dashboards should not cause error", func() { + cfg.Options["path"] = brokenDashboards + + _, err := NewDashboardFileReader(cfg, logger) + So(err, ShouldBeNil) + }) }) - Convey("Broken dashboards should not cause error", func() { + Convey("Should not create new folder if folder name is missing", func() { cfg := &DashboardsAsConfig{ Name: "Default", Type: "file", OrgId: 1, Folder: "", Options: map[string]interface{}{ - "folder": brokenDashboards, + "folder": defaultDashboards, }, } - _, err := NewDashboardFileReader(cfg, logger) + _, err := getOrCreateFolderId(cfg, fakeService) + So(err, ShouldEqual, ErrFolderNameMissing) + }) + + Convey("can get or Create dashboard folder", func() { + cfg := &DashboardsAsConfig{ + Name: "Default", + Type: "file", + OrgId: 1, + Folder: "TEAM A", + Options: map[string]interface{}{ + "folder": defaultDashboards, + }, + } + + folderId, err := getOrCreateFolderId(cfg, fakeService) So(err, ShouldBeNil) + inserted := false + for _, d := range fakeService.inserted { + if d.Dashboard.IsFolder && d.Dashboard.Id == folderId { + inserted = true + } + } + So(len(fakeService.inserted), ShouldEqual, 1) + So(inserted, ShouldBeTrue) + }) + + Convey("Walking the folder with dashboards", func() { + noFiles := map[string]os.FileInfo{} + + Convey("should skip dirs that starts with .", func() { + shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: ".folder"}, nil) + So(shouldSkip, ShouldEqual, filepath.SkipDir) + }) + + Convey("should keep walking if file is not .json", func() { + shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: "folder"}, nil) + So(shouldSkip, ShouldBeNil) + }) + }) + + Convey("Can use bpth path and folder as dashboard path", func() { + cfg := &DashboardsAsConfig{ + Name: "Default", + Type: "file", + OrgId: 1, + Folder: "", + Options: map[string]interface{}{}, + } + + Convey("using path parameter", func() { + cfg.Options["path"] = defaultDashboards + reader, err := NewDashboardFileReader(cfg, log.New("test-logger")) + So(err, ShouldBeNil) + So(reader.Path, ShouldEqual, defaultDashboards) + }) + + Convey("using folder as options", func() { + cfg.Options["folder"] = defaultDashboards + reader, err := NewDashboardFileReader(cfg, log.New("test-logger")) + So(err, ShouldBeNil) + So(reader.Path, ShouldEqual, defaultDashboards) + }) + }) + + Reset(func() { + dashboards.NewProvisioningService = origNewDashboardProvisioningService }) }) } -type fakeDashboardRepo struct { - inserted []*dashboards.SaveDashboardItem +type FakeFileInfo struct { + isDirectory bool + name string +} + +func (ffi *FakeFileInfo) IsDir() bool { + return ffi.isDirectory +} + +func (ffi FakeFileInfo) Size() int64 { + return 1 +} + +func (ffi FakeFileInfo) Mode() os.FileMode { + return 0777 +} + +func (ffi FakeFileInfo) Name() string { + return ffi.name +} + +func (ffi FakeFileInfo) ModTime() time.Time { + return time.Time{} +} + +func (ffi FakeFileInfo) Sys() interface{} { + return nil +} + +func mockDashboardProvisioningService() *fakeDashboardProvisioningService { + mock := fakeDashboardProvisioningService{} + dashboards.NewProvisioningService = func() dashboards.DashboardProvisioningService { + return &mock + } + return &mock +} + +type fakeDashboardProvisioningService struct { + inserted []*dashboards.SaveDashboardDTO + provisioned []*models.DashboardProvisioning getDashboard []*models.Dashboard } -func (repo *fakeDashboardRepo) SaveDashboard(json *dashboards.SaveDashboardItem) (*models.Dashboard, error) { - repo.inserted = append(repo.inserted, json) - return json.Dashboard, nil +func (s *fakeDashboardProvisioningService) GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error) { + return s.provisioned, nil +} + +func (s *fakeDashboardProvisioningService) SaveProvisionedDashboard(dto *dashboards.SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) { + s.inserted = append(s.inserted, dto) + s.provisioned = append(s.provisioned, provisioning) + return dto.Dashboard, nil +} + +func (s *fakeDashboardProvisioningService) SaveFolderForProvisionedDashboards(dto *dashboards.SaveDashboardDTO) (*models.Dashboard, error) { + s.inserted = append(s.inserted, dto) + return dto.Dashboard, nil } func mockGetDashboardQuery(cmd *models.GetDashboardQuery) error { - for _, d := range fakeRepo.getDashboard { + for _, d := range fakeService.getDashboard { if d.Slug == cmd.Slug { cmd.Result = d return nil diff --git a/pkg/services/provisioning/dashboards/test-configs/broken-configs/commented.yaml b/pkg/services/provisioning/dashboards/test-configs/broken-configs/commented.yaml index e40612af508..f0dcca9b47a 100644 --- a/pkg/services/provisioning/dashboards/test-configs/broken-configs/commented.yaml +++ b/pkg/services/provisioning/dashboards/test-configs/broken-configs/commented.yaml @@ -3,4 +3,4 @@ # folder: '' # type: file # options: -# folder: /var/lib/grafana/dashboards +# path: /var/lib/grafana/dashboards diff --git a/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/dev-dashboards.yaml b/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/dev-dashboards.yaml index a7c4a812092..e9776d69010 100644 --- a/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/dev-dashboards.yaml +++ b/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/dev-dashboards.yaml @@ -1,12 +1,16 @@ +apiVersion: 1 + +providers: - name: 'general dashboards' - org_id: 2 + orgId: 2 folder: 'developers' editable: true + disableDeletion: true type: file options: - folder: /var/lib/grafana/dashboards + path: /var/lib/grafana/dashboards - name: 'default' type: file options: - folder: /var/lib/grafana/dashboards + path: /var/lib/grafana/dashboards diff --git a/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/sample.yaml b/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/sample.yaml new file mode 100644 index 00000000000..5b73632b1ff --- /dev/null +++ b/pkg/services/provisioning/dashboards/test-configs/dashboards-from-disk/sample.yaml @@ -0,0 +1,10 @@ +apiVersion: 1 + +#providers: +#- name: 'gasdf' +# orgId: 2 +# folder: 'developers' +# editable: true +# type: file +# options: +# path: /var/lib/grafana/dashboards diff --git a/pkg/services/provisioning/dashboards/test-configs/version-0/version-0.yaml b/pkg/services/provisioning/dashboards/test-configs/version-0/version-0.yaml new file mode 100644 index 00000000000..979e762d4d4 --- /dev/null +++ b/pkg/services/provisioning/dashboards/test-configs/version-0/version-0.yaml @@ -0,0 +1,13 @@ +- name: 'general dashboards' + org_id: 2 + folder: 'developers' + editable: true + disableDeletion: true + type: file + options: + path: /var/lib/grafana/dashboards + +- name: 'default' + type: file + options: + path: /var/lib/grafana/dashboards diff --git a/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard1.json b/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard1.json index 5b6765a4ed6..febb98be0e8 100644 --- a/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard1.json +++ b/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard1.json @@ -1,5 +1,5 @@ { - "title": "Grafana", + "title": "Grafana1", "tags": [], "style": "dark", "timezone": "browser", @@ -170,4 +170,3 @@ }, "version": 5 } - \ No newline at end of file diff --git a/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard2.json b/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard2.json index 5b6765a4ed6..9291f16d9e7 100644 --- a/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard2.json +++ b/pkg/services/provisioning/dashboards/test-dashboards/folder-one/dashboard2.json @@ -1,5 +1,5 @@ { - "title": "Grafana", + "title": "Grafana2", "tags": [], "style": "dark", "timezone": "browser", @@ -170,4 +170,3 @@ }, "version": 5 } - \ No newline at end of file diff --git a/pkg/services/provisioning/dashboards/types.go b/pkg/services/provisioning/dashboards/types.go index 002a56b5f3c..f742b321552 100644 --- a/pkg/services/provisioning/dashboards/types.go +++ b/pkg/services/provisioning/dashboards/types.go @@ -1,7 +1,6 @@ package dashboards import ( - "strings" "time" "github.com/grafana/grafana/pkg/components/simplejson" @@ -11,24 +10,54 @@ import ( ) type DashboardsAsConfig struct { - Name string `json:"name" yaml:"name"` - Type string `json:"type" yaml:"type"` - OrgId int64 `json:"org_id" yaml:"org_id"` - Folder string `json:"folder" yaml:"folder"` - Editable bool `json:"editable" yaml:"editable"` - Options map[string]interface{} `json:"options" yaml:"options"` + Name string + Type string + OrgId int64 + Folder string + Editable bool + Options map[string]interface{} + DisableDeletion bool } -func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *DashboardsAsConfig) (*dashboards.SaveDashboardItem, error) { +type DashboardsAsConfigV0 struct { + Name string `json:"name" yaml:"name"` + Type string `json:"type" yaml:"type"` + OrgId int64 `json:"org_id" yaml:"org_id"` + Folder string `json:"folder" yaml:"folder"` + Editable bool `json:"editable" yaml:"editable"` + Options map[string]interface{} `json:"options" yaml:"options"` + DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"` +} - dash := &dashboards.SaveDashboardItem{} +type ConfigVersion struct { + ApiVersion int64 `json:"apiVersion" yaml:"apiVersion"` +} + +type DashboardAsConfigV1 struct { + Providers []*DashboardProviderConfigs `json:"providers" yaml:"providers"` +} + +type DashboardProviderConfigs struct { + Name string `json:"name" yaml:"name"` + Type string `json:"type" yaml:"type"` + OrgId int64 `json:"orgId" yaml:"orgId"` + Folder string `json:"folder" yaml:"folder"` + Editable bool `json:"editable" yaml:"editable"` + Options map[string]interface{} `json:"options" yaml:"options"` + DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"` +} + +func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *DashboardsAsConfig, folderId int64) (*dashboards.SaveDashboardDTO, error) { + dash := &dashboards.SaveDashboardDTO{} dash.Dashboard = models.NewDashboardFromJson(data) - dash.TitleLower = strings.ToLower(dash.Dashboard.Title) dash.UpdatedAt = lastModified dash.Overwrite = true dash.OrgId = cfg.OrgId - dash.Folder = cfg.Folder - dash.Dashboard.Data.Set("editable", cfg.Editable) + dash.Dashboard.OrgId = cfg.OrgId + dash.Dashboard.FolderId = folderId + if !cfg.Editable { + dash.Dashboard.Data.Set("editable", cfg.Editable) + } if dash.Dashboard.Title == "" { return nil, models.ErrDashboardTitleEmpty @@ -36,3 +65,39 @@ func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *Das return dash, nil } + +func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig { + var r []*DashboardsAsConfig + + for _, v := range v0 { + r = append(r, &DashboardsAsConfig{ + Name: v.Name, + Type: v.Type, + OrgId: v.OrgId, + Folder: v.Folder, + Editable: v.Editable, + Options: v.Options, + DisableDeletion: v.DisableDeletion, + }) + } + + return r +} + +func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig { + var r []*DashboardsAsConfig + + for _, v := range dc.Providers { + r = append(r, &DashboardsAsConfig{ + Name: v.Name, + Type: v.Type, + OrgId: v.OrgId, + Folder: v.Folder, + Editable: v.Editable, + Options: v.Options, + DisableDeletion: v.DisableDeletion, + }) + } + + return r +} diff --git a/pkg/services/provisioning/datasources/config_reader.go b/pkg/services/provisioning/datasources/config_reader.go new file mode 100644 index 00000000000..58ed5472a6b --- /dev/null +++ b/pkg/services/provisioning/datasources/config_reader.go @@ -0,0 +1,113 @@ +package datasources + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/grafana/grafana/pkg/log" + "gopkg.in/yaml.v2" +) + +type configReader struct { + log log.Logger +} + +func (cr *configReader) readConfig(path string) ([]*DatasourcesAsConfig, error) { + var datasources []*DatasourcesAsConfig + + files, err := ioutil.ReadDir(path) + if err != nil { + cr.log.Error("cant read datasource provisioning files from directory", "path", path) + return datasources, nil + } + + for _, file := range files { + if strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml") { + datasource, err := cr.parseDatasourceConfig(path, file) + if err != nil { + return nil, err + } + + if datasource != nil { + datasources = append(datasources, datasource) + } + } + } + + err = validateDefaultUniqueness(datasources) + if err != nil { + return nil, err + } + + return datasources, nil +} + +func (cr *configReader) parseDatasourceConfig(path string, file os.FileInfo) (*DatasourcesAsConfig, error) { + filename, _ := filepath.Abs(filepath.Join(path, file.Name())) + yamlFile, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + var apiVersion *ConfigVersion + err = yaml.Unmarshal(yamlFile, &apiVersion) + if err != nil { + return nil, err + } + + if apiVersion == nil { + apiVersion = &ConfigVersion{ApiVersion: 0} + } + + if apiVersion.ApiVersion > 0 { + var v1 *DatasourcesAsConfigV1 + err = yaml.Unmarshal(yamlFile, &v1) + if err != nil { + return nil, err + } + + return v1.mapToDatasourceFromConfig(apiVersion.ApiVersion), nil + } + + var v0 *DatasourcesAsConfigV0 + err = yaml.Unmarshal(yamlFile, &v0) + if err != nil { + return nil, err + } + + cr.log.Warn("[Deprecated] the datasource provisioning config is outdated. please upgrade", "filename", filename) + + return v0.mapToDatasourceFromConfig(apiVersion.ApiVersion), nil +} + +func validateDefaultUniqueness(datasources []*DatasourcesAsConfig) error { + defaultCount := 0 + for i := range datasources { + if datasources[i].Datasources == nil { + continue + } + + for _, ds := range datasources[i].Datasources { + if ds.OrgId == 0 { + ds.OrgId = 1 + } + + if ds.IsDefault { + defaultCount++ + if defaultCount > 1 { + return ErrInvalidConfigToManyDefault + } + } + } + + for _, ds := range datasources[i].DeleteDatasources { + if ds.OrgId == 0 { + ds.OrgId = 1 + } + } + } + + return nil +} diff --git a/pkg/services/provisioning/datasources/datasources_test.go b/pkg/services/provisioning/datasources/config_reader_test.go similarity index 62% rename from pkg/services/provisioning/datasources/datasources_test.go rename to pkg/services/provisioning/datasources/config_reader_test.go index f3252c28d9d..3198329e0ae 100644 --- a/pkg/services/provisioning/datasources/datasources_test.go +++ b/pkg/services/provisioning/datasources/config_reader_test.go @@ -11,12 +11,13 @@ import ( ) var ( - logger log.Logger = log.New("fake.logger") + logger log.Logger = log.New("fake.log") oneDatasourcesConfig string = "" twoDatasourcesConfig string = "./test-configs/two-datasources" twoDatasourcesConfigPurgeOthers string = "./test-configs/insert-two-delete-two" doubleDatasourcesConfig string = "./test-configs/double-default" allProperties string = "./test-configs/all-properties" + versionZero string = "./test-configs/version-0" brokenYaml string = "./test-configs/broken-yaml" fakeRepo *fakeRepository @@ -115,52 +116,101 @@ func TestDatasourceAsConfig(t *testing.T) { }) Convey("broken yaml should return error", func() { - _, err := configReader{}.readConfig(brokenYaml) + reader := &configReader{} + _, err := reader.readConfig(brokenYaml) So(err, ShouldNotBeNil) }) - Convey("can read all properties", func() { - cfgProvifer := configReader{} + Convey("skip invalid directory", func() { + cfgProvifer := &configReader{log: log.New("test logger")} + cfg, err := cfgProvifer.readConfig("./invalid-directory") + if err != nil { + t.Fatalf("readConfig return an error %v", err) + } + + So(len(cfg), ShouldEqual, 0) + }) + + Convey("can read all properties from version 1", func() { + cfgProvifer := &configReader{log: log.New("test logger")} cfg, err := cfgProvifer.readConfig(allProperties) if err != nil { t.Fatalf("readConfig return an error %v", err) } - So(len(cfg), ShouldEqual, 2) + So(len(cfg), ShouldEqual, 3) dsCfg := cfg[0] - ds := dsCfg.Datasources[0] - So(ds.Name, ShouldEqual, "name") - So(ds.Type, ShouldEqual, "type") - So(ds.Access, ShouldEqual, models.DS_ACCESS_PROXY) - So(ds.OrgId, ShouldEqual, 2) - So(ds.Url, ShouldEqual, "url") - So(ds.User, ShouldEqual, "user") - So(ds.Password, ShouldEqual, "password") - So(ds.Database, ShouldEqual, "database") - So(ds.BasicAuth, ShouldBeTrue) - So(ds.BasicAuthUser, ShouldEqual, "basic_auth_user") - So(ds.BasicAuthPassword, ShouldEqual, "basic_auth_password") - So(ds.WithCredentials, ShouldBeTrue) - So(ds.IsDefault, ShouldBeTrue) - So(ds.Editable, ShouldBeTrue) + So(dsCfg.ApiVersion, ShouldEqual, 1) - So(len(ds.JsonData), ShouldBeGreaterThan, 2) - So(ds.JsonData["graphiteVersion"], ShouldEqual, "1.1") - So(ds.JsonData["tlsAuth"], ShouldEqual, true) - So(ds.JsonData["tlsAuthWithCACert"], ShouldEqual, true) + validateDatasource(dsCfg) + validateDeleteDatasources(dsCfg) - So(len(ds.SecureJsonData), ShouldBeGreaterThan, 2) - So(ds.SecureJsonData["tlsCACert"], ShouldEqual, "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==") - So(ds.SecureJsonData["tlsClientCert"], ShouldEqual, "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==") - So(ds.SecureJsonData["tlsClientKey"], ShouldEqual, "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==") + dsCount := 0 + delDsCount := 0 - dstwo := cfg[1].Datasources[0] - So(dstwo.Name, ShouldEqual, "name2") + for _, c := range cfg { + dsCount += len(c.Datasources) + delDsCount += len(c.DeleteDatasources) + } + + So(dsCount, ShouldEqual, 2) + So(delDsCount, ShouldEqual, 1) + }) + + Convey("can read all properties from version 0", func() { + cfgProvifer := &configReader{log: log.New("test logger")} + cfg, err := cfgProvifer.readConfig(versionZero) + if err != nil { + t.Fatalf("readConfig return an error %v", err) + } + + So(len(cfg), ShouldEqual, 1) + + dsCfg := cfg[0] + + So(dsCfg.ApiVersion, ShouldEqual, 0) + + validateDatasource(dsCfg) + validateDeleteDatasources(dsCfg) }) }) } +func validateDeleteDatasources(dsCfg *DatasourcesAsConfig) { + So(len(dsCfg.DeleteDatasources), ShouldEqual, 1) + deleteDs := dsCfg.DeleteDatasources[0] + So(deleteDs.Name, ShouldEqual, "old-graphite3") + So(deleteDs.OrgId, ShouldEqual, 2) +} +func validateDatasource(dsCfg *DatasourcesAsConfig) { + ds := dsCfg.Datasources[0] + So(ds.Name, ShouldEqual, "name") + So(ds.Type, ShouldEqual, "type") + So(ds.Access, ShouldEqual, models.DS_ACCESS_PROXY) + So(ds.OrgId, ShouldEqual, 2) + So(ds.Url, ShouldEqual, "url") + So(ds.User, ShouldEqual, "user") + So(ds.Password, ShouldEqual, "password") + So(ds.Database, ShouldEqual, "database") + So(ds.BasicAuth, ShouldBeTrue) + So(ds.BasicAuthUser, ShouldEqual, "basic_auth_user") + So(ds.BasicAuthPassword, ShouldEqual, "basic_auth_password") + So(ds.WithCredentials, ShouldBeTrue) + So(ds.IsDefault, ShouldBeTrue) + So(ds.Editable, ShouldBeTrue) + So(ds.Version, ShouldEqual, 10) + + So(len(ds.JsonData), ShouldBeGreaterThan, 2) + So(ds.JsonData["graphiteVersion"], ShouldEqual, "1.1") + So(ds.JsonData["tlsAuth"], ShouldEqual, true) + So(ds.JsonData["tlsAuthWithCACert"], ShouldEqual, true) + + So(len(ds.SecureJsonData), ShouldBeGreaterThan, 2) + So(ds.SecureJsonData["tlsCACert"], ShouldEqual, "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==") + So(ds.SecureJsonData["tlsClientCert"], ShouldEqual, "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==") + So(ds.SecureJsonData["tlsClientKey"], ShouldEqual, "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==") +} type fakeRepository struct { inserted []*models.AddDataSourceCommand diff --git a/pkg/services/provisioning/datasources/datasources.go b/pkg/services/provisioning/datasources/datasources.go index ce631c565d4..1fa0a3b3173 100644 --- a/pkg/services/provisioning/datasources/datasources.go +++ b/pkg/services/provisioning/datasources/datasources.go @@ -2,16 +2,12 @@ package datasources import ( "errors" - "io/ioutil" - "path/filepath" - "strings" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/models" - yaml "gopkg.in/yaml.v2" ) var ( @@ -25,13 +21,13 @@ func Provision(configDirectory string) error { type DatasourceProvisioner struct { log log.Logger - cfgProvider configReader + cfgProvider *configReader } func newDatasourceProvisioner(log log.Logger) DatasourceProvisioner { return DatasourceProvisioner{ log: log, - cfgProvider: configReader{}, + cfgProvider: &configReader{log: log}, } } @@ -94,61 +90,3 @@ func (dc *DatasourceProvisioner) deleteDatasources(dsToDelete []*DeleteDatasourc return nil } - -type configReader struct{} - -func (configReader) readConfig(path string) ([]*DatasourcesAsConfig, error) { - files, err := ioutil.ReadDir(path) - if err != nil { - return nil, err - } - - var datasources []*DatasourcesAsConfig - for _, file := range files { - if strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml") { - filename, _ := filepath.Abs(filepath.Join(path, file.Name())) - yamlFile, err := ioutil.ReadFile(filename) - - if err != nil { - return nil, err - } - var datasource *DatasourcesAsConfig - err = yaml.Unmarshal(yamlFile, &datasource) - if err != nil { - return nil, err - } - - if datasource != nil { - datasources = append(datasources, datasource) - } - } - } - - defaultCount := 0 - for i := range datasources { - if datasources[i].Datasources == nil { - continue - } - - for _, ds := range datasources[i].Datasources { - if ds.OrgId == 0 { - ds.OrgId = 1 - } - - if ds.IsDefault { - defaultCount++ - if defaultCount > 1 { - return nil, ErrInvalidConfigToManyDefault - } - } - } - - for _, ds := range datasources[i].DeleteDatasources { - if ds.OrgId == 0 { - ds.OrgId = 1 - } - } - } - - return datasources, nil -} diff --git a/pkg/services/provisioning/datasources/test-configs/all-properties/all-properties.yaml b/pkg/services/provisioning/datasources/test-configs/all-properties/all-properties.yaml index af0d3009a4c..b92b81f7079 100644 --- a/pkg/services/provisioning/datasources/test-configs/all-properties/all-properties.yaml +++ b/pkg/services/provisioning/datasources/test-configs/all-properties/all-properties.yaml @@ -1,23 +1,30 @@ +apiVersion: 1 + datasources: - name: name type: type access: proxy - org_id: 2 + orgId: 2 url: url password: password user: user database: database - basic_auth: true - basic_auth_user: basic_auth_user - basic_auth_password: basic_auth_password - with_credentials: true - is_default: true - json_data: + basicAuth: true + basicAuthUser: basic_auth_user + basicAuthPassword: basic_auth_password + withCredentials: true + isDefault: true + jsonData: graphiteVersion: "1.1" tlsAuth: true tlsAuthWithCACert: true - secure_json_data: + secureJsonData: tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==" tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==" tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==" editable: true + version: 10 + +deleteDatasources: + - name: old-graphite3 + orgId: 2 diff --git a/pkg/services/provisioning/datasources/test-configs/all-properties/sample.yaml b/pkg/services/provisioning/datasources/test-configs/all-properties/sample.yaml new file mode 100644 index 00000000000..2187eabdc46 --- /dev/null +++ b/pkg/services/provisioning/datasources/test-configs/all-properties/sample.yaml @@ -0,0 +1,32 @@ +# Should not be included + + +apiVersion: 1 + +#datasources: +# - name: name +# type: type +# access: proxy +# orgId: 2 +# url: url +# password: password +# user: user +# database: database +# basicAuth: true +# basicAuthUser: basic_auth_user +# basicAuthPassword: basic_auth_password +# withCredentials: true +# jsonData: +# graphiteVersion: "1.1" +# tlsAuth: true +# tlsAuthWithCACert: true +# secureJsonData: +# tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==" +# tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==" +# tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==" +# editable: true +# version: 10 +# +#deleteDatasources: +# - name: old-graphite3 +# orgId: 2 diff --git a/pkg/services/provisioning/datasources/test-configs/all-properties/second.yaml b/pkg/services/provisioning/datasources/test-configs/all-properties/second.yaml index 43c41ee9b3b..9f27a8d07ee 100644 --- a/pkg/services/provisioning/datasources/test-configs/all-properties/second.yaml +++ b/pkg/services/provisioning/datasources/test-configs/all-properties/second.yaml @@ -3,5 +3,5 @@ datasources: - name: name2 type: type2 access: proxy - org_id: 2 + orgId: 2 url: url2 diff --git a/pkg/services/provisioning/datasources/test-configs/version-0/version-0.yaml b/pkg/services/provisioning/datasources/test-configs/version-0/version-0.yaml new file mode 100644 index 00000000000..fcd4ddd6b01 --- /dev/null +++ b/pkg/services/provisioning/datasources/test-configs/version-0/version-0.yaml @@ -0,0 +1,28 @@ +datasources: + - name: name + type: type + access: proxy + org_id: 2 + url: url + password: password + user: user + database: database + basic_auth: true + basic_auth_user: basic_auth_user + basic_auth_password: basic_auth_password + with_credentials: true + is_default: true + json_data: + graphiteVersion: "1.1" + tlsAuth: true + tlsAuthWithCACert: true + secure_json_data: + tlsCACert: "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==" + tlsClientCert: "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==" + tlsClientKey: "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==" + editable: true + version: 10 + +delete_datasources: + - name: old-graphite3 + org_id: 2 diff --git a/pkg/services/provisioning/datasources/types.go b/pkg/services/provisioning/datasources/types.go index ee2175d6a90..8e2443a0169 100644 --- a/pkg/services/provisioning/datasources/types.go +++ b/pkg/services/provisioning/datasources/types.go @@ -1,22 +1,74 @@ package datasources -import "github.com/grafana/grafana/pkg/models" +import ( + "github.com/grafana/grafana/pkg/models" +) import "github.com/grafana/grafana/pkg/components/simplejson" +type ConfigVersion struct { + ApiVersion int64 `json:"apiVersion" yaml:"apiVersion"` +} + type DatasourcesAsConfig struct { - Datasources []*DataSourceFromConfig `json:"datasources" yaml:"datasources"` - DeleteDatasources []*DeleteDatasourceConfig `json:"delete_datasources" yaml:"delete_datasources"` + ApiVersion int64 + + Datasources []*DataSourceFromConfig + DeleteDatasources []*DeleteDatasourceConfig } type DeleteDatasourceConfig struct { + OrgId int64 + Name string +} + +type DataSourceFromConfig struct { + OrgId int64 + Version int + + Name string + Type string + Access string + Url string + Password string + User string + Database string + BasicAuth bool + BasicAuthUser string + BasicAuthPassword string + WithCredentials bool + IsDefault bool + JsonData map[string]interface{} + SecureJsonData map[string]string + Editable bool +} + +type DatasourcesAsConfigV0 struct { + ConfigVersion + + Datasources []*DataSourceFromConfigV0 `json:"datasources" yaml:"datasources"` + DeleteDatasources []*DeleteDatasourceConfigV0 `json:"delete_datasources" yaml:"delete_datasources"` +} + +type DatasourcesAsConfigV1 struct { + ConfigVersion + + Datasources []*DataSourceFromConfigV1 `json:"datasources" yaml:"datasources"` + DeleteDatasources []*DeleteDatasourceConfigV1 `json:"deleteDatasources" yaml:"deleteDatasources"` +} + +type DeleteDatasourceConfigV0 struct { OrgId int64 `json:"org_id" yaml:"org_id"` Name string `json:"name" yaml:"name"` } -type DataSourceFromConfig struct { - OrgId int64 `json:"org_id" yaml:"org_id"` - Version int `json:"version" yaml:"version"` +type DeleteDatasourceConfigV1 struct { + OrgId int64 `json:"orgId" yaml:"orgId"` + Name string `json:"name" yaml:"name"` +} +type DataSourceFromConfigV0 struct { + OrgId int64 `json:"org_id" yaml:"org_id"` + Version int `json:"version" yaml:"version"` Name string `json:"name" yaml:"name"` Type string `json:"type" yaml:"type"` Access string `json:"access" yaml:"access"` @@ -34,6 +86,108 @@ type DataSourceFromConfig struct { Editable bool `json:"editable" yaml:"editable"` } +type DataSourceFromConfigV1 struct { + OrgId int64 `json:"orgId" yaml:"orgId"` + Version int `json:"version" yaml:"version"` + Name string `json:"name" yaml:"name"` + Type string `json:"type" yaml:"type"` + Access string `json:"access" yaml:"access"` + Url string `json:"url" yaml:"url"` + Password string `json:"password" yaml:"password"` + User string `json:"user" yaml:"user"` + Database string `json:"database" yaml:"database"` + BasicAuth bool `json:"basicAuth" yaml:"basicAuth"` + BasicAuthUser string `json:"basicAuthUser" yaml:"basicAuthUser"` + BasicAuthPassword string `json:"basicAuthPassword" yaml:"basicAuthPassword"` + WithCredentials bool `json:"withCredentials" yaml:"withCredentials"` + IsDefault bool `json:"isDefault" yaml:"isDefault"` + JsonData map[string]interface{} `json:"jsonData" yaml:"jsonData"` + SecureJsonData map[string]string `json:"secureJsonData" yaml:"secureJsonData"` + Editable bool `json:"editable" yaml:"editable"` +} + +func (cfg *DatasourcesAsConfigV1) mapToDatasourceFromConfig(apiVersion int64) *DatasourcesAsConfig { + r := &DatasourcesAsConfig{} + + r.ApiVersion = apiVersion + + if cfg == nil { + return r + } + + for _, ds := range cfg.Datasources { + r.Datasources = append(r.Datasources, &DataSourceFromConfig{ + OrgId: ds.OrgId, + Name: ds.Name, + Type: ds.Type, + Access: ds.Access, + Url: ds.Url, + Password: ds.Password, + User: ds.User, + Database: ds.Database, + BasicAuth: ds.BasicAuth, + BasicAuthUser: ds.BasicAuthUser, + BasicAuthPassword: ds.BasicAuthPassword, + WithCredentials: ds.WithCredentials, + IsDefault: ds.IsDefault, + JsonData: ds.JsonData, + SecureJsonData: ds.SecureJsonData, + Editable: ds.Editable, + Version: ds.Version, + }) + } + + for _, ds := range cfg.DeleteDatasources { + r.DeleteDatasources = append(r.DeleteDatasources, &DeleteDatasourceConfig{ + OrgId: ds.OrgId, + Name: ds.Name, + }) + } + + return r +} + +func (cfg *DatasourcesAsConfigV0) mapToDatasourceFromConfig(apiVersion int64) *DatasourcesAsConfig { + r := &DatasourcesAsConfig{} + + r.ApiVersion = apiVersion + + if cfg == nil { + return r + } + + for _, ds := range cfg.Datasources { + r.Datasources = append(r.Datasources, &DataSourceFromConfig{ + OrgId: ds.OrgId, + Name: ds.Name, + Type: ds.Type, + Access: ds.Access, + Url: ds.Url, + Password: ds.Password, + User: ds.User, + Database: ds.Database, + BasicAuth: ds.BasicAuth, + BasicAuthUser: ds.BasicAuthUser, + BasicAuthPassword: ds.BasicAuthPassword, + WithCredentials: ds.WithCredentials, + IsDefault: ds.IsDefault, + JsonData: ds.JsonData, + SecureJsonData: ds.SecureJsonData, + Editable: ds.Editable, + Version: ds.Version, + }) + } + + for _, ds := range cfg.DeleteDatasources { + r.DeleteDatasources = append(r.DeleteDatasources, &DeleteDatasourceConfig{ + OrgId: ds.OrgId, + Name: ds.Name, + }) + } + + return r +} + func createInsertCommand(ds *DataSourceFromConfig) *models.AddDataSourceCommand { jsonData := simplejson.New() if len(ds.JsonData) > 0 { diff --git a/pkg/services/search/handlers.go b/pkg/services/search/handlers.go index 3a200389d69..cf194c320bb 100644 --- a/pkg/services/search/handlers.go +++ b/pkg/services/search/handlers.go @@ -12,33 +12,25 @@ func Init() { } func searchHandler(query *Query) error { - hits := make(HitList, 0) - dashQuery := FindPersistedDashboardsQuery{ Title: query.Title, - UserId: query.UserId, + SignedInUser: query.SignedInUser, IsStarred: query.IsStarred, - OrgId: query.OrgId, DashboardIds: query.DashboardIds, + Type: query.Type, + FolderIds: query.FolderIds, + Tags: query.Tags, + Limit: query.Limit, + Permission: query.Permission, } if err := bus.Dispatch(&dashQuery); err != nil { return err } + hits := make(HitList, 0) hits = append(hits, dashQuery.Result...) - // filter out results with tag filter - if len(query.Tags) > 0 { - filtered := HitList{} - for _, hit := range hits { - if hasRequiredTags(query.Tags, hit.Tags) { - filtered = append(filtered, hit) - } - } - hits = filtered - } - // sort main result array sort.Sort(hits) @@ -52,7 +44,7 @@ func searchHandler(query *Query) error { } // add isStarred info - if err := setIsStarredFlagOnSearchResults(query.UserId, hits); err != nil { + if err := setIsStarredFlagOnSearchResults(query.SignedInUser.UserId, hits); err != nil { return err } @@ -60,25 +52,6 @@ func searchHandler(query *Query) error { return nil } -func stringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - -func hasRequiredTags(queryTags, hitTags []string) bool { - for _, queryTag := range queryTags { - if !stringInSlice(queryTag, hitTags) { - return false - } - } - - return true -} - func setIsStarredFlagOnSearchResults(userId int64, hits []*Hit) error { query := m.GetUserStarsQuery{UserId: userId} if err := bus.Dispatch(&query); err != nil { diff --git a/pkg/services/search/handlers_test.go b/pkg/services/search/handlers_test.go index c0ac09f9cd0..fc223b2ef4b 100644 --- a/pkg/services/search/handlers_test.go +++ b/pkg/services/search/handlers_test.go @@ -11,13 +11,15 @@ import ( func TestSearch(t *testing.T) { Convey("Given search query", t, func() { - query := Query{Limit: 2000} + query := Query{Limit: 2000, SignedInUser: &m.SignedInUser{IsGrafanaAdmin: true}} bus.AddHandler("test", func(query *FindPersistedDashboardsQuery) error { query.Result = HitList{ - &Hit{Id: 16, Title: "CCAA", Tags: []string{"BB", "AA"}}, - &Hit{Id: 10, Title: "AABB", Tags: []string{"CC", "AA"}}, - &Hit{Id: 15, Title: "BBAA", Tags: []string{"EE", "AA", "BB"}}, + &Hit{Id: 16, Title: "CCAA", Type: "dash-db", Tags: []string{"BB", "AA"}}, + &Hit{Id: 10, Title: "AABB", Type: "dash-db", Tags: []string{"CC", "AA"}}, + &Hit{Id: 15, Title: "BBAA", Type: "dash-db", Tags: []string{"EE", "AA", "BB"}}, + &Hit{Id: 25, Title: "bbAAa", Type: "dash-db", Tags: []string{"EE", "AA", "BB"}}, + &Hit{Id: 17, Title: "FOLDER", Type: "dash-folder"}, } return nil }) @@ -27,34 +29,29 @@ func TestSearch(t *testing.T) { return nil }) + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{IsGrafanaAdmin: true} + return nil + }) + Convey("That is empty", func() { err := searchHandler(&query) So(err, ShouldBeNil) Convey("should return sorted results", func() { - So(query.Result[0].Title, ShouldEqual, "AABB") - So(query.Result[1].Title, ShouldEqual, "BBAA") - So(query.Result[2].Title, ShouldEqual, "CCAA") + So(query.Result[0].Title, ShouldEqual, "FOLDER") + So(query.Result[1].Title, ShouldEqual, "AABB") + So(query.Result[2].Title, ShouldEqual, "BBAA") + So(query.Result[3].Title, ShouldEqual, "bbAAa") + So(query.Result[4].Title, ShouldEqual, "CCAA") }) Convey("should return sorted tags", func() { - So(query.Result[1].Tags[0], ShouldEqual, "AA") - So(query.Result[1].Tags[1], ShouldEqual, "BB") - So(query.Result[1].Tags[2], ShouldEqual, "EE") + So(query.Result[3].Tags[0], ShouldEqual, "AA") + So(query.Result[3].Tags[1], ShouldEqual, "BB") + So(query.Result[3].Tags[2], ShouldEqual, "EE") }) }) - Convey("That filters by tag", func() { - query.Tags = []string{"BB", "AA"} - err := searchHandler(&query) - So(err, ShouldBeNil) - - Convey("should return correct results", func() { - So(len(query.Result), ShouldEqual, 2) - So(query.Result[0].Title, ShouldEqual, "BBAA") - So(query.Result[1].Title, ShouldEqual, "CCAA") - }) - - }) }) } diff --git a/pkg/services/search/models.go b/pkg/services/search/models.go index 159637013f5..2da09672f13 100644 --- a/pkg/services/search/models.go +++ b/pkg/services/search/models.go @@ -1,37 +1,58 @@ package search +import "strings" +import "github.com/grafana/grafana/pkg/models" + type HitType string const ( - DashHitDB HitType = "dash-db" - DashHitHome HitType = "dash-home" - DashHitJson HitType = "dash-json" - DashHitScripted HitType = "dash-scripted" + DashHitDB HitType = "dash-db" + DashHitHome HitType = "dash-home" + DashHitFolder HitType = "dash-folder" ) type Hit struct { - Id int64 `json:"id"` - Title string `json:"title"` - Uri string `json:"uri"` - Type HitType `json:"type"` - Tags []string `json:"tags"` - IsStarred bool `json:"isStarred"` + Id int64 `json:"id"` + Uid string `json:"uid"` + Title string `json:"title"` + Uri string `json:"uri"` + Url string `json:"url"` + Type HitType `json:"type"` + Tags []string `json:"tags"` + IsStarred bool `json:"isStarred"` + FolderId int64 `json:"folderId,omitempty"` + FolderUid string `json:"folderUid,omitempty"` + FolderTitle string `json:"folderTitle,omitempty"` + FolderUrl string `json:"folderUrl,omitempty"` } type HitList []*Hit -func (s HitList) Len() int { return len(s) } -func (s HitList) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s HitList) Less(i, j int) bool { return s[i].Title < s[j].Title } +func (s HitList) Len() int { return len(s) } +func (s HitList) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s HitList) Less(i, j int) bool { + if s[i].Type == "dash-folder" && s[j].Type == "dash-db" { + return true + } + + if s[i].Type == "dash-db" && s[j].Type == "dash-folder" { + return false + } + + return strings.ToLower(s[i].Title) < strings.ToLower(s[j].Title) +} type Query struct { Title string Tags []string OrgId int64 - UserId int64 + SignedInUser *models.SignedInUser Limit int IsStarred bool - DashboardIds []int + Type string + DashboardIds []int64 + FolderIds []int64 + Permission models.PermissionType Result HitList } @@ -39,9 +60,14 @@ type Query struct { type FindPersistedDashboardsQuery struct { Title string OrgId int64 - UserId int64 + SignedInUser *models.SignedInUser IsStarred bool - DashboardIds []int + DashboardIds []int64 + Type string + FolderIds []int64 + Tags []string + Limit int + Permission models.PermissionType Result HitList } diff --git a/pkg/services/sqlstore/alert.go b/pkg/services/sqlstore/alert.go index 73be7d774fd..8c751f0cada 100644 --- a/pkg/services/sqlstore/alert.go +++ b/pkg/services/sqlstore/alert.go @@ -14,7 +14,6 @@ func init() { bus.AddHandler("sql", SaveAlerts) bus.AddHandler("sql", HandleAlertsQuery) bus.AddHandler("sql", GetAlertById) - bus.AddHandler("sql", DeleteAlertById) bus.AddHandler("sql", GetAllAlertQueryHandler) bus.AddHandler("sql", SetAlertState) bus.AddHandler("sql", GetAlertStatesForDashboard) @@ -24,7 +23,7 @@ func init() { func GetAlertById(query *m.GetAlertByIdQuery) error { alert := m.Alert{} - has, err := x.Id(query.Id).Get(&alert) + has, err := x.ID(query.Id).Get(&alert) if !has { return fmt.Errorf("could not find alert") } @@ -61,59 +60,62 @@ func deleteAlertByIdInternal(alertId int64, reason string, sess *DBSession) erro return nil } -func DeleteAlertById(cmd *m.DeleteAlertCommand) error { - return inTransaction(func(sess *DBSession) error { - return deleteAlertByIdInternal(cmd.AlertId, "DeleteAlertCommand", sess) - }) -} - func HandleAlertsQuery(query *m.GetAlertsQuery) error { - var sql bytes.Buffer - params := make([]interface{}, 0) + builder := SqlBuilder{} - sql.WriteString(`SELECT * - from alert - `) + builder.Write(`SELECT + alert.id, + alert.dashboard_id, + alert.panel_id, + alert.name, + alert.state, + alert.new_state_date, + alert.eval_date, + alert.execution_error, + dashboard.uid as dashboard_uid, + dashboard.slug as dashboard_slug + FROM alert + INNER JOIN dashboard on dashboard.id = alert.dashboard_id `) - sql.WriteString(`WHERE org_id = ?`) - params = append(params, query.OrgId) + builder.Write(`WHERE alert.org_id = ?`, query.OrgId) if query.DashboardId != 0 { - sql.WriteString(` AND dashboard_id = ?`) - params = append(params, query.DashboardId) + builder.Write(` AND alert.dashboard_id = ?`, query.DashboardId) } if query.PanelId != 0 { - sql.WriteString(` AND panel_id = ?`) - params = append(params, query.PanelId) + builder.Write(` AND alert.panel_id = ?`, query.PanelId) } - if len(query.State) > 0 && query.State[0] != "ALL" { - sql.WriteString(` AND (`) + if len(query.State) > 0 && query.State[0] != "all" { + builder.Write(` AND (`) for i, v := range query.State { if i > 0 { - sql.WriteString(" OR ") + builder.Write(" OR ") } if strings.HasPrefix(v, "not_") { - sql.WriteString("state <> ? ") + builder.Write("state <> ? ") v = strings.TrimPrefix(v, "not_") } else { - sql.WriteString("state = ? ") + builder.Write("state = ? ") } - params = append(params, v) + builder.AddParams(v) } - sql.WriteString(")") + builder.Write(")") } - sql.WriteString(" ORDER BY name ASC") + if query.User.OrgRole != m.ROLE_ADMIN { + builder.writeDashboardPermissionFilter(query.User, m.PERMISSION_EDIT) + } + + builder.Write(" ORDER BY name ASC") if query.Limit != 0 { - sql.WriteString(" LIMIT ?") - params = append(params, query.Limit) + builder.Write(" LIMIT ?", query.Limit) } - alerts := make([]*m.Alert, 0) - if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil { + alerts := make([]*m.AlertListItemDTO, 0) + if err := x.SQL(builder.GetSqlString(), builder.params...).Find(&alerts); err != nil { return err } @@ -260,7 +262,7 @@ func SetAlertState(cmd *m.SetAlertStateCommand) error { alert.ExecutionError = cmd.Error } - sess.Id(alert.Id).Update(&alert) + sess.ID(alert.Id).Update(&alert) return nil }) } @@ -324,7 +326,7 @@ func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error WHERE org_id = ? AND dashboard_id = ?` query.Result = make([]*m.AlertStateInfoDTO, 0) - err := x.Sql(rawSql, query.OrgId, query.DashboardId).Find(&query.Result) + err := x.SQL(rawSql, query.OrgId, query.DashboardId).Find(&query.Result) return err } diff --git a/pkg/services/sqlstore/alert_notification.go b/pkg/services/sqlstore/alert_notification.go index 5e66627f194..ae691c7166c 100644 --- a/pkg/services/sqlstore/alert_notification.go +++ b/pkg/services/sqlstore/alert_notification.go @@ -76,7 +76,7 @@ func GetAlertNotificationsToSend(query *m.GetAlertNotificationsToSendQuery) erro sql.WriteString(`)`) results := make([]*m.AlertNotification, 0) - if err := x.Sql(sql.String(), params...).Find(&results); err != nil { + if err := x.SQL(sql.String(), params...).Find(&results); err != nil { return err } @@ -165,7 +165,7 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error { return inTransaction(func(sess *DBSession) (err error) { current := m.AlertNotification{} - if _, err = sess.Id(cmd.Id).Get(¤t); err != nil { + if _, err = sess.ID(cmd.Id).Get(¤t); err != nil { return err } @@ -187,7 +187,7 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error { sess.UseBool("is_default") - if affected, err := sess.Id(cmd.Id).Update(current); err != nil { + if affected, err := sess.ID(cmd.Id).Update(current); err != nil { return err } else if affected == 0 { return fmt.Errorf("Could not find alert notification") diff --git a/pkg/services/sqlstore/alert_test.go b/pkg/services/sqlstore/alert_test.go index daf4f774717..de86ae87a4f 100644 --- a/pkg/services/sqlstore/alert_test.go +++ b/pkg/services/sqlstore/alert_test.go @@ -12,7 +12,7 @@ func TestAlertingDataAccess(t *testing.T) { Convey("Testing Alerting data access", t, func() { InitTestDB(t) - testDash := insertTestDashboard("dashboard with alerts", 1, "alert") + testDash := insertTestDashboard("dashboard with alerts", 1, 0, false, "alert") items := []*m.Alert{ { @@ -71,15 +71,21 @@ func TestAlertingDataAccess(t *testing.T) { }) Convey("Can read properties", func() { - alertQuery := m.GetAlertsQuery{DashboardId: testDash.Id, PanelId: 1, OrgId: 1} + alertQuery := m.GetAlertsQuery{DashboardId: testDash.Id, PanelId: 1, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}} err2 := HandleAlertsQuery(&alertQuery) alert := alertQuery.Result[0] So(err2, ShouldBeNil) So(alert.Name, ShouldEqual, "Alerting title") - So(alert.Message, ShouldEqual, "Alerting message") So(alert.State, ShouldEqual, "pending") - So(alert.Frequency, ShouldEqual, 1) + }) + + Convey("Viewer cannot read alerts", func() { + alertQuery := m.GetAlertsQuery{DashboardId: testDash.Id, PanelId: 1, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_VIEWER}} + err2 := HandleAlertsQuery(&alertQuery) + + So(err2, ShouldBeNil) + So(alertQuery.Result, ShouldHaveLength, 0) }) Convey("Alerts with same dashboard id and panel id should update", func() { @@ -100,7 +106,7 @@ func TestAlertingDataAccess(t *testing.T) { }) Convey("Alerts should be updated", func() { - query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}} err2 := HandleAlertsQuery(&query) So(err2, ShouldBeNil) @@ -149,7 +155,7 @@ func TestAlertingDataAccess(t *testing.T) { Convey("Should save 3 dashboards", func() { So(err, ShouldBeNil) - queryForDashboard := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + queryForDashboard := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}} err2 := HandleAlertsQuery(&queryForDashboard) So(err2, ShouldBeNil) @@ -163,7 +169,7 @@ func TestAlertingDataAccess(t *testing.T) { err = SaveAlerts(&cmd) Convey("should delete the missing alert", func() { - query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}} err2 := HandleAlertsQuery(&query) So(err2, ShouldBeNil) So(len(query.Result), ShouldEqual, 2) @@ -192,13 +198,13 @@ func TestAlertingDataAccess(t *testing.T) { err = DeleteDashboard(&m.DeleteDashboardCommand{ OrgId: 1, - Slug: testDash.Slug, + Id: testDash.Id, }) So(err, ShouldBeNil) Convey("Alerts should be removed", func() { - query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1} + query := m.GetAlertsQuery{DashboardId: testDash.Id, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}} err2 := HandleAlertsQuery(&query) So(testDash.Id, ShouldEqual, 1) diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index effffb8bab4..76f1819a18c 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -138,6 +138,17 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I sql.WriteString(`WHERE annotation.org_id = ?`) params = append(params, query.OrgId) + if query.AnnotationId != 0 { + fmt.Print("annotation query") + sql.WriteString(` AND annotation.id = ?`) + params = append(params, query.AnnotationId) + } + + if query.RegionId != 0 { + sql.WriteString(` AND annotation.region_id = ?`) + params = append(params, query.RegionId) + } + if query.AlertId != 0 { sql.WriteString(` AND annotation.alert_id = ?`) params = append(params, query.AlertId) @@ -197,6 +208,7 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I sql.WriteString(fmt.Sprintf(" ORDER BY epoch DESC LIMIT %v", query.Limit)) items := make([]*annotations.ItemDTO, 0) + if err := x.Sql(sql.String(), params...).Find(&items); err != nil { return nil, err } diff --git a/pkg/services/sqlstore/annotation_test.go b/pkg/services/sqlstore/annotation_test.go index 2afd4479b66..d5cee110b9a 100644 --- a/pkg/services/sqlstore/annotation_test.go +++ b/pkg/services/sqlstore/annotation_test.go @@ -51,6 +51,20 @@ func TestAnnotations(t *testing.T) { So(err, ShouldBeNil) So(annotation.Id, ShouldBeGreaterThan, 0) + annotation2 := &annotations.Item{ + OrgId: 1, + UserId: 1, + DashboardId: 2, + Text: "hello", + Type: "alert", + Epoch: 20, + Tags: []string{"outage", "error", "type:outage", "server:server-1"}, + RegionId: 1, + } + err = repo.Save(annotation2) + So(err, ShouldBeNil) + So(annotation2.Id, ShouldBeGreaterThan, 0) + Convey("Can query for annotation", func() { items, err := repo.Find(&annotations.ItemQuery{ OrgId: 1, @@ -67,6 +81,28 @@ func TestAnnotations(t *testing.T) { }) }) + Convey("Can query for annotation by id", func() { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + AnnotationId: annotation2.Id, + }) + + So(err, ShouldBeNil) + So(items, ShouldHaveLength, 1) + So(items[0].Id, ShouldEqual, annotation2.Id) + }) + + Convey("Can query for annotation by region id", func() { + items, err := repo.Find(&annotations.ItemQuery{ + OrgId: 1, + RegionId: annotation2.RegionId, + }) + + So(err, ShouldBeNil) + So(items, ShouldHaveLength, 1) + So(items[0].Id, ShouldEqual, annotation2.Id) + }) + Convey("Should not find any when item is outside time range", func() { items, err := repo.Find(&annotations.ItemQuery{ OrgId: 1, diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index cdf9d4eb3c7..5ee34183628 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -1,14 +1,14 @@ package sqlstore import ( - "bytes" - "fmt" + "strings" "time" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/metrics" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" + "github.com/grafana/grafana/pkg/util" ) func init() { @@ -19,126 +19,155 @@ func init() { bus.AddHandler("sql", SearchDashboards) bus.AddHandler("sql", GetDashboardTags) bus.AddHandler("sql", GetDashboardSlugById) + bus.AddHandler("sql", GetDashboardUIDById) bus.AddHandler("sql", GetDashboardsByPluginId) + bus.AddHandler("sql", GetDashboardPermissionsForUser) + bus.AddHandler("sql", GetDashboardsBySlug) + bus.AddHandler("sql", ValidateDashboardBeforeSave) } +var generateNewUid func() string = util.GenerateShortUid + func SaveDashboard(cmd *m.SaveDashboardCommand) error { return inTransaction(func(sess *DBSession) error { - dash := cmd.GetDashboardModel() - - // try get existing dashboard - var existing, sameTitle m.Dashboard - - if dash.Id > 0 { - dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing) - if err != nil { - return err - } - if !dashWithIdExists { - return m.ErrDashboardNotFound - } - - // check for is someone else has written in between - if dash.Version != existing.Version { - if cmd.Overwrite { - dash.Version = existing.Version - } else { - return m.ErrDashboardVersionMismatch - } - } - - // do not allow plugin dashboard updates without overwrite flag - if existing.PluginId != "" && cmd.Overwrite == false { - return m.UpdatePluginDashboardError{PluginId: existing.PluginId} - } - } - - sameTitleExists, err := sess.Where("org_id=? AND slug=?", dash.OrgId, dash.Slug).Get(&sameTitle) - if err != nil { - return err - } - - if sameTitleExists { - // another dashboard with same name - if dash.Id != sameTitle.Id { - if cmd.Overwrite { - dash.Id = sameTitle.Id - dash.Version = sameTitle.Version - } else { - return m.ErrDashboardWithSameNameExists - } - } - } - - parentVersion := dash.Version - affectedRows := int64(0) - - if dash.Id == 0 { - dash.Version = 1 - metrics.M_Api_Dashboard_Insert.Inc() - dash.Data.Set("version", dash.Version) - affectedRows, err = sess.Insert(dash) - } else { - dash.Version += 1 - dash.Data.Set("version", dash.Version) - - if !cmd.UpdatedAt.IsZero() { - dash.Updated = cmd.UpdatedAt - } - - affectedRows, err = sess.Id(dash.Id).Update(dash) - } - - if err != nil { - return err - } - - if affectedRows == 0 { - return m.ErrDashboardNotFound - } - - dashVersion := &m.DashboardVersion{ - DashboardId: dash.Id, - ParentVersion: parentVersion, - RestoredFrom: cmd.RestoredFrom, - Version: dash.Version, - Created: time.Now(), - CreatedBy: dash.UpdatedBy, - Message: cmd.Message, - Data: dash.Data, - } - - // insert version entry - if affectedRows, err = sess.Insert(dashVersion); err != nil { - return err - } else if affectedRows == 0 { - return m.ErrDashboardNotFound - } - - // delete existing tabs - _, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id) - if err != nil { - return err - } - - // insert new tags - tags := dash.GetTags() - if len(tags) > 0 { - for _, tag := range tags { - if _, err := sess.Insert(&DashboardTag{DashboardId: dash.Id, Term: tag}); err != nil { - return err - } - } - } - - cmd.Result = dash - - return err + return saveDashboard(sess, cmd) }) } +func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error { + dash := cmd.GetDashboardModel() + + userId := cmd.UserId + + if userId == 0 { + userId = -1 + } + + if dash.Id > 0 { + var existing m.Dashboard + dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing) + if err != nil { + return err + } + if !dashWithIdExists { + return m.ErrDashboardNotFound + } + + // check for is someone else has written in between + if dash.Version != existing.Version { + if cmd.Overwrite { + dash.SetVersion(existing.Version) + } else { + return m.ErrDashboardVersionMismatch + } + } + + // do not allow plugin dashboard updates without overwrite flag + if existing.PluginId != "" && cmd.Overwrite == false { + return m.UpdatePluginDashboardError{PluginId: existing.PluginId} + } + } + + if dash.Uid == "" { + uid, err := generateNewDashboardUid(sess, dash.OrgId) + if err != nil { + return err + } + dash.SetUid(uid) + } + + parentVersion := dash.Version + affectedRows := int64(0) + var err error + + if dash.Id == 0 { + dash.SetVersion(1) + dash.Created = time.Now() + dash.CreatedBy = userId + dash.Updated = time.Now() + dash.UpdatedBy = userId + metrics.M_Api_Dashboard_Insert.Inc() + affectedRows, err = sess.Insert(dash) + } else { + dash.SetVersion(dash.Version + 1) + + if !cmd.UpdatedAt.IsZero() { + dash.Updated = cmd.UpdatedAt + } else { + dash.Updated = time.Now() + } + + dash.UpdatedBy = userId + + affectedRows, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash) + } + + if err != nil { + return err + } + + if affectedRows == 0 { + return m.ErrDashboardNotFound + } + + dashVersion := &m.DashboardVersion{ + DashboardId: dash.Id, + ParentVersion: parentVersion, + RestoredFrom: cmd.RestoredFrom, + Version: dash.Version, + Created: time.Now(), + CreatedBy: dash.UpdatedBy, + Message: cmd.Message, + Data: dash.Data, + } + + // insert version entry + if affectedRows, err = sess.Insert(dashVersion); err != nil { + return err + } else if affectedRows == 0 { + return m.ErrDashboardNotFound + } + + // delete existing tags + _, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id) + if err != nil { + return err + } + + // insert new tags + tags := dash.GetTags() + if len(tags) > 0 { + for _, tag := range tags { + if _, err := sess.Insert(&DashboardTag{DashboardId: dash.Id, Term: tag}); err != nil { + return err + } + } + } + + cmd.Result = dash + + return err +} + +func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) { + for i := 0; i < 3; i++ { + uid := generateNewUid() + + exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&m.Dashboard{}) + if err != nil { + return "", err + } + + if !exists { + return uid, nil + } + } + + return "", m.ErrDashboardFailedGenerateUniqueUid +} + func GetDashboard(query *m.GetDashboardQuery) error { - dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id} + dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid} has, err := x.Get(&dashboard) if err != nil { @@ -147,70 +176,85 @@ func GetDashboard(query *m.GetDashboardQuery) error { return m.ErrDashboardNotFound } - dashboard.Data.Set("id", dashboard.Id) + dashboard.SetId(dashboard.Id) + dashboard.SetUid(dashboard.Uid) query.Result = &dashboard return nil } type DashboardSearchProjection struct { - Id int64 - Title string - Slug string - Term string + Id int64 + Uid string + Title string + Slug string + Term string + IsFolder bool + FolderId int64 + FolderUid string + FolderSlug string + FolderTitle string } -func SearchDashboards(query *search.FindPersistedDashboardsQuery) error { - var sql bytes.Buffer - params := make([]interface{}, 0) - - sql.WriteString(`SELECT - dashboard.id, - dashboard.title, - dashboard.slug, - dashboard_tag.term - FROM dashboard - LEFT OUTER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id`) - - if query.IsStarred { - sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id") +func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) { + limit := query.Limit + if limit == 0 { + limit = 1000 } - sql.WriteString(` WHERE dashboard.org_id=?`) - - params = append(params, query.OrgId) + sb := NewSearchBuilder(query.SignedInUser, limit, query.Permission). + WithTags(query.Tags). + WithDashboardIdsIn(query.DashboardIds) if query.IsStarred { - sql.WriteString(` AND star.user_id=?`) - params = append(params, query.UserId) - } - - if len(query.DashboardIds) > 0 { - sql.WriteString(" AND (") - for i, dashboardId := range query.DashboardIds { - if i != 0 { - sql.WriteString(" OR") - } - - sql.WriteString(" dashboard.id = ?") - params = append(params, dashboardId) - } - sql.WriteString(")") + sb.IsStarred() } if len(query.Title) > 0 { - sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?") - params = append(params, "%"+query.Title+"%") + sb.WithTitle(query.Title) } - sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT 1000")) + if len(query.Type) > 0 { + sb.WithType(query.Type) + } + + if len(query.FolderIds) > 0 { + sb.WithFolderIds(query.FolderIds) + } var res []DashboardSearchProjection - err := x.Sql(sql.String(), params...).Find(&res) + sql, params := sb.ToSql() + err := x.Sql(sql, params...).Find(&res) + if err != nil { + return nil, err + } + + return res, nil +} + +func SearchDashboards(query *search.FindPersistedDashboardsQuery) error { + res, err := findDashboards(query) if err != nil { return err } + makeQueryResult(query, res) + + return nil +} + +func getHitType(item DashboardSearchProjection) search.HitType { + var hitType search.HitType + if item.IsFolder { + hitType = search.DashHitFolder + } else { + hitType = search.DashHitDB + } + + return hitType +} + +func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []DashboardSearchProjection) { query.Result = make([]*search.Hit, 0) hits := make(map[int64]*search.Hit) @@ -218,12 +262,22 @@ func SearchDashboards(query *search.FindPersistedDashboardsQuery) error { hit, exists := hits[item.Id] if !exists { hit = &search.Hit{ - Id: item.Id, - Title: item.Title, - Uri: "db/" + item.Slug, - Type: search.DashHitDB, - Tags: []string{}, + Id: item.Id, + Uid: item.Uid, + Title: item.Title, + Uri: "db/" + item.Slug, + Url: m.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug), + Type: getHitType(item), + FolderId: item.FolderId, + FolderUid: item.FolderUid, + FolderTitle: item.FolderTitle, + Tags: []string{}, } + + if item.FolderId > 0 { + hit.FolderUrl = m.GetFolderUrl(item.FolderUid, item.FolderSlug) + } + query.Result = append(query.Result, hit) hits[item.Id] = hit } @@ -231,8 +285,6 @@ func SearchDashboards(query *search.FindPersistedDashboardsQuery) error { hit.Tags = append(hit.Tags, item.Term) } } - - return err } func GetDashboardTags(query *m.GetDashboardTagsQuery) error { @@ -252,7 +304,7 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error { func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { return inTransaction(func(sess *DBSession) error { - dashboard := m.Dashboard{Slug: cmd.Slug, OrgId: cmd.OrgId} + dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId} has, err := sess.Get(&dashboard) if err != nil { return err @@ -266,7 +318,9 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error { "DELETE FROM dashboard WHERE id = ?", "DELETE FROM playlist_item WHERE type = 'dashboard_by_id' AND value = ?", "DELETE FROM dashboard_version WHERE dashboard_id = ?", + "DELETE FROM dashboard WHERE folder_id = ?", "DELETE FROM annotation WHERE dashboard_id = ?", + "DELETE FROM dashboard_provisioning WHERE dashboard_id = ?", } for _, sql := range deletes { @@ -301,10 +355,81 @@ func GetDashboards(query *m.GetDashboardsQuery) error { return nil } +// GetDashboardPermissionsForUser returns the maximum permission the specified user has for a dashboard(s) +// The function takes in a list of dashboard ids and the user id and role +func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery) error { + if len(query.DashboardIds) == 0 { + return m.ErrCommandValidationFailed + } + + if query.OrgRole == m.ROLE_ADMIN { + var permissions = make([]*m.DashboardPermissionForUser, 0) + for _, d := range query.DashboardIds { + permissions = append(permissions, &m.DashboardPermissionForUser{ + DashboardId: d, + Permission: m.PERMISSION_ADMIN, + PermissionName: m.PERMISSION_ADMIN.String(), + }) + } + query.Result = permissions + + return nil + } + + params := make([]interface{}, 0) + + // check dashboards that have ACLs via user id, team id or role + sql := `SELECT d.id AS dashboard_id, MAX(COALESCE(da.permission, pt.permission)) AS permission + FROM dashboard AS d + LEFT JOIN dashboard_acl as da on d.folder_id = da.dashboard_id or d.id = da.dashboard_id + LEFT JOIN team_member as ugm on ugm.team_id = da.team_id + LEFT JOIN org_user ou ON ou.role = da.role AND ou.user_id = ? + ` + params = append(params, query.UserId) + + //check the user's role for dashboards that do not have hasAcl set + sql += `LEFT JOIN org_user ouRole ON ouRole.user_id = ? AND ouRole.org_id = ?` + params = append(params, query.UserId) + params = append(params, query.OrgId) + + sql += ` + LEFT JOIN (SELECT 1 AS permission, 'Viewer' AS role + UNION SELECT 2 AS permission, 'Editor' AS role + UNION SELECT 4 AS permission, 'Admin' AS role) pt ON ouRole.role = pt.role + WHERE + d.Id IN (?` + strings.Repeat(",?", len(query.DashboardIds)-1) + `) ` + for _, id := range query.DashboardIds { + params = append(params, id) + } + + sql += ` AND + d.org_id = ? AND + ( + (d.has_acl = ? AND (da.user_id = ? OR ugm.user_id = ? OR ou.id IS NOT NULL)) + OR (d.has_acl = ? AND ouRole.id IS NOT NULL) + ) + group by d.id + order by d.id asc` + params = append(params, query.OrgId) + params = append(params, dialect.BooleanStr(true)) + params = append(params, query.UserId) + params = append(params, query.UserId) + params = append(params, dialect.BooleanStr(false)) + + err := x.Sql(sql, params...).Find(&query.Result) + + for _, p := range query.Result { + p.PermissionName = p.Permission.String() + } + + return err +} + func GetDashboardsByPluginId(query *m.GetDashboardsByPluginIdQuery) error { var dashboards = make([]*m.Dashboard, 0) + whereExpr := "org_id=? AND plugin_id=? AND is_folder=" + dialect.BooleanStr(false) - err := x.Where("org_id=? AND plugin_id=?", query.OrgId, query.PluginId).Find(&dashboards) + err := x.Where(whereExpr, query.OrgId, query.PluginId).Find(&dashboards) query.Result = dashboards if err != nil { @@ -322,7 +447,7 @@ func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error { var rawSql = `SELECT slug from dashboard WHERE Id=?` var slug = DashboardSlugDTO{} - exists, err := x.Sql(rawSql, query.Id).Get(&slug) + exists, err := x.SQL(rawSql, query.Id).Get(&slug) if err != nil { return err @@ -333,3 +458,156 @@ func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error { query.Result = slug.Slug return nil } + +func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error { + var dashboards []*m.Dashboard + + if err := x.Where("org_id=? AND slug=?", query.OrgId, query.Slug).Find(&dashboards); err != nil { + return err + } + + query.Result = dashboards + return nil +} + +func GetDashboardUIDById(query *m.GetDashboardRefByIdQuery) error { + var rawSql = `SELECT uid, slug from dashboard WHERE Id=?` + + us := &m.DashboardRef{} + + exists, err := x.SQL(rawSql, query.Id).Get(us) + + if err != nil { + return err + } else if exists == false { + return m.ErrDashboardNotFound + } + + query.Result = us + return nil +} + +func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) (err error) { + dash := cmd.Dashboard + + dashWithIdExists := false + var existingById m.Dashboard + + if dash.Id > 0 { + dashWithIdExists, err = sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existingById) + if err != nil { + return err + } + + if !dashWithIdExists { + return m.ErrDashboardNotFound + } + + if dash.Uid == "" { + dash.SetUid(existingById.Uid) + } + } + + dashWithUidExists := false + var existingByUid m.Dashboard + + if dash.Uid != "" { + dashWithUidExists, err = sess.Where("org_id=? AND uid=?", dash.OrgId, dash.Uid).Get(&existingByUid) + if err != nil { + return err + } + } + + if dash.FolderId > 0 { + var existingFolder m.Dashboard + folderExists, folderErr := sess.Where("org_id=? AND id=? AND is_folder=?", dash.OrgId, dash.FolderId, dialect.BooleanStr(true)).Get(&existingFolder) + if folderErr != nil { + return folderErr + } + + if !folderExists { + return m.ErrDashboardFolderNotFound + } + } + + if !dashWithIdExists && !dashWithUidExists { + return nil + } + + if dashWithIdExists && dashWithUidExists && existingById.Id != existingByUid.Id { + return m.ErrDashboardWithSameUIDExists + } + + existing := existingById + + if !dashWithIdExists && dashWithUidExists { + dash.SetId(existingByUid.Id) + dash.SetUid(existingByUid.Uid) + existing = existingByUid + } + + if (existing.IsFolder && !dash.IsFolder) || + (!existing.IsFolder && dash.IsFolder) { + return m.ErrDashboardTypeMismatch + } + + // check for is someone else has written in between + if dash.Version != existing.Version { + if cmd.Overwrite { + dash.SetVersion(existing.Version) + } else { + return m.ErrDashboardVersionMismatch + } + } + + // do not allow plugin dashboard updates without overwrite flag + if existing.PluginId != "" && cmd.Overwrite == false { + return m.UpdatePluginDashboardError{PluginId: existing.PluginId} + } + + return nil +} + +func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) error { + dash := cmd.Dashboard + var existing m.Dashboard + + exists, err := sess.Where("org_id=? AND slug=? AND (is_folder=? OR folder_id=?)", dash.OrgId, dash.Slug, dialect.BooleanStr(true), dash.FolderId).Get(&existing) + if err != nil { + return err + } + + if exists && dash.Id != existing.Id { + if existing.IsFolder && !dash.IsFolder { + return m.ErrDashboardWithSameNameAsFolder + } + + if !existing.IsFolder && dash.IsFolder { + return m.ErrDashboardFolderWithSameNameAsDashboard + } + + if cmd.Overwrite { + dash.SetId(existing.Id) + dash.SetUid(existing.Uid) + dash.SetVersion(existing.Version) + } else { + return m.ErrDashboardWithSameNameInFolderExists + } + } + + return nil +} + +func ValidateDashboardBeforeSave(cmd *m.ValidateDashboardBeforeSaveCommand) (err error) { + return inTransaction(func(sess *DBSession) error { + if err = getExistingDashboardByIdOrUidForUpdate(sess, cmd); err != nil { + return err + } + + if err = getExistingDashboardByTitleAndFolder(sess, cmd); err != nil { + return err + } + + return nil + }) +} diff --git a/pkg/services/sqlstore/dashboard_acl.go b/pkg/services/sqlstore/dashboard_acl.go new file mode 100644 index 00000000000..ae91d1d41f3 --- /dev/null +++ b/pkg/services/sqlstore/dashboard_acl.go @@ -0,0 +1,126 @@ +package sqlstore + +import ( + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +func init() { + bus.AddHandler("sql", UpdateDashboardAcl) + bus.AddHandler("sql", GetDashboardAclInfoList) +} + +func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error { + return inTransaction(func(sess *DBSession) error { + // delete existing items + _, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", cmd.DashboardId) + if err != nil { + return err + } + + for _, item := range cmd.Items { + if item.UserId == 0 && item.TeamId == 0 && (item.Role == nil || !item.Role.IsValid()) { + return m.ErrDashboardAclInfoMissing + } + + if item.DashboardId == 0 { + return m.ErrDashboardPermissionDashboardEmpty + } + + sess.Nullable("user_id", "team_id") + if _, err := sess.Insert(item); err != nil { + return err + } + } + + // Update dashboard HasAcl flag + dashboard := m.Dashboard{HasAcl: true} + if _, err := sess.Cols("has_acl").Where("id=?", cmd.DashboardId).Update(&dashboard); err != nil { + return err + } + return nil + }) +} + +// GetDashboardAclInfoList returns a list of permissions for a dashboard. They can be fetched from three +// different places. +// 1) Permissions for the dashboard +// 2) permissions for its parent folder +// 3) if no specific permissions have been set for the dashboard or its parent folder then get the default permissions +func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { + var err error + + falseStr := dialect.BooleanStr(false) + + if query.DashboardId == 0 { + sql := `SELECT + da.id, + da.org_id, + da.dashboard_id, + da.user_id, + da.team_id, + da.permission, + da.role, + da.created, + da.updated, + '' as user_login, + '' as user_email, + '' as team, + '' as title, + '' as slug, + '' as uid,` + + falseStr + ` AS is_folder + FROM dashboard_acl as da + WHERE da.dashboard_id = -1` + query.Result = make([]*m.DashboardAclInfoDTO, 0) + err = x.SQL(sql).Find(&query.Result) + + } else { + + rawSQL := ` + -- get permissions for the dashboard and its parent folder + SELECT + da.id, + da.org_id, + da.dashboard_id, + da.user_id, + da.team_id, + da.permission, + da.role, + da.created, + da.updated, + u.login AS user_login, + u.email AS user_email, + ug.name AS team, + d.title, + d.slug, + d.uid, + d.is_folder + FROM dashboard as d + LEFT JOIN dashboard folder on folder.id = d.folder_id + LEFT JOIN dashboard_acl AS da ON + da.dashboard_id = d.id OR + da.dashboard_id = d.folder_id OR + ( + -- include default permissions --> + da.org_id = -1 AND ( + (folder.id IS NOT NULL AND folder.has_acl = ` + falseStr + `) OR + (folder.id IS NULL AND d.has_acl = ` + falseStr + `) + ) + ) + LEFT JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id + LEFT JOIN team ug on ug.id = da.team_id + WHERE d.org_id = ? AND d.id = ? AND da.id IS NOT NULL + ORDER BY 1 ASC + ` + + query.Result = make([]*m.DashboardAclInfoDTO, 0) + err = x.SQL(rawSQL, query.OrgId, query.DashboardId).Find(&query.Result) + } + + for _, p := range query.Result { + p.PermissionName = p.Permission.String() + } + + return err +} diff --git a/pkg/services/sqlstore/dashboard_acl_test.go b/pkg/services/sqlstore/dashboard_acl_test.go new file mode 100644 index 00000000000..8fbb9c0d813 --- /dev/null +++ b/pkg/services/sqlstore/dashboard_acl_test.go @@ -0,0 +1,217 @@ +package sqlstore + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" + + m "github.com/grafana/grafana/pkg/models" +) + +func TestDashboardAclDataAccess(t *testing.T) { + Convey("Testing DB", t, func() { + InitTestDB(t) + Convey("Given a dashboard folder and a user", func() { + currentUser := createUser("viewer", "Viewer", false) + savedFolder := insertTestDashboard("1 test dash folder", 1, 0, true, "prod", "webapp") + childDash := insertTestDashboard("2 test dash", 1, savedFolder.Id, false, "prod", "webapp") + + Convey("When adding dashboard permission with userId and teamId set to 0", func() { + err := testHelperUpdateDashboardAcl(savedFolder.Id, m.DashboardAcl{ + OrgId: 1, + DashboardId: savedFolder.Id, + Permission: m.PERMISSION_EDIT, + }) + So(err, ShouldEqual, m.ErrDashboardAclInfoMissing) + }) + + Convey("Given dashboard folder with default permissions", func() { + Convey("When reading dashboard acl should include acl for parent folder", func() { + query := m.GetDashboardAclInfoListQuery{DashboardId: childDash.Id, OrgId: 1} + + err := GetDashboardAclInfoList(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + defaultPermissionsId := -1 + So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) + So(*query.Result[0].Role, ShouldEqual, m.ROLE_VIEWER) + So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) + So(*query.Result[1].Role, ShouldEqual, m.ROLE_EDITOR) + }) + }) + + Convey("Given dashboard folder with removed default permissions", func() { + err := UpdateDashboardAcl(&m.UpdateDashboardAclCommand{ + DashboardId: savedFolder.Id, + Items: []*m.DashboardAcl{}, + }) + So(err, ShouldBeNil) + + Convey("When reading dashboard acl should return no acl items", func() { + query := m.GetDashboardAclInfoListQuery{DashboardId: childDash.Id, OrgId: 1} + + err := GetDashboardAclInfoList(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 0) + }) + }) + + Convey("Given dashboard folder permission", func() { + err := testHelperUpdateDashboardAcl(savedFolder.Id, m.DashboardAcl{ + OrgId: 1, + UserId: currentUser.Id, + DashboardId: savedFolder.Id, + Permission: m.PERMISSION_EDIT, + }) + So(err, ShouldBeNil) + + Convey("When reading dashboard acl should include acl for parent folder", func() { + query := m.GetDashboardAclInfoListQuery{DashboardId: childDash.Id, OrgId: 1} + + err := GetDashboardAclInfoList(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].DashboardId, ShouldEqual, savedFolder.Id) + }) + + Convey("Given child dashboard permission", func() { + err := testHelperUpdateDashboardAcl(childDash.Id, m.DashboardAcl{ + OrgId: 1, + UserId: currentUser.Id, + DashboardId: childDash.Id, + Permission: m.PERMISSION_EDIT, + }) + So(err, ShouldBeNil) + + Convey("When reading dashboard acl should include acl for parent folder and child", func() { + query := m.GetDashboardAclInfoListQuery{OrgId: 1, DashboardId: childDash.Id} + + err := GetDashboardAclInfoList(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].DashboardId, ShouldEqual, savedFolder.Id) + So(query.Result[1].DashboardId, ShouldEqual, childDash.Id) + }) + }) + }) + + Convey("Given child dashboard permission in folder with no permissions", func() { + err := testHelperUpdateDashboardAcl(childDash.Id, m.DashboardAcl{ + OrgId: 1, + UserId: currentUser.Id, + DashboardId: childDash.Id, + Permission: m.PERMISSION_EDIT, + }) + So(err, ShouldBeNil) + + Convey("When reading dashboard acl should include default acl for parent folder and the child acl", func() { + query := m.GetDashboardAclInfoListQuery{OrgId: 1, DashboardId: childDash.Id} + + err := GetDashboardAclInfoList(&query) + So(err, ShouldBeNil) + + defaultPermissionsId := -1 + So(len(query.Result), ShouldEqual, 3) + So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) + So(*query.Result[0].Role, ShouldEqual, m.ROLE_VIEWER) + So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) + So(*query.Result[1].Role, ShouldEqual, m.ROLE_EDITOR) + So(query.Result[2].DashboardId, ShouldEqual, childDash.Id) + }) + }) + + Convey("Should be able to add dashboard permission", func() { + err := testHelperUpdateDashboardAcl(savedFolder.Id, m.DashboardAcl{ + OrgId: 1, + UserId: currentUser.Id, + DashboardId: savedFolder.Id, + Permission: m.PERMISSION_EDIT, + }) + + q1 := &m.GetDashboardAclInfoListQuery{DashboardId: savedFolder.Id, OrgId: 1} + err = GetDashboardAclInfoList(q1) + So(err, ShouldBeNil) + + So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) + So(q1.Result[0].Permission, ShouldEqual, m.PERMISSION_EDIT) + So(q1.Result[0].PermissionName, ShouldEqual, "Edit") + So(q1.Result[0].UserId, ShouldEqual, currentUser.Id) + So(q1.Result[0].UserLogin, ShouldEqual, currentUser.Login) + So(q1.Result[0].UserEmail, ShouldEqual, currentUser.Email) + + Convey("Should be able to delete an existing permission", func() { + err := testHelperUpdateDashboardAcl(savedFolder.Id) + So(err, ShouldBeNil) + + q3 := &m.GetDashboardAclInfoListQuery{DashboardId: savedFolder.Id, OrgId: 1} + err = GetDashboardAclInfoList(q3) + So(err, ShouldBeNil) + So(len(q3.Result), ShouldEqual, 0) + }) + }) + + Convey("Given a team", func() { + group1 := m.CreateTeamCommand{Name: "group1 name", OrgId: 1} + err := CreateTeam(&group1) + So(err, ShouldBeNil) + + Convey("Should be able to add a user permission for a team", func() { + err := testHelperUpdateDashboardAcl(savedFolder.Id, m.DashboardAcl{ + OrgId: 1, + TeamId: group1.Result.Id, + DashboardId: savedFolder.Id, + Permission: m.PERMISSION_EDIT, + }) + So(err, ShouldBeNil) + + q1 := &m.GetDashboardAclInfoListQuery{DashboardId: savedFolder.Id, OrgId: 1} + err = GetDashboardAclInfoList(q1) + So(err, ShouldBeNil) + So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) + So(q1.Result[0].Permission, ShouldEqual, m.PERMISSION_EDIT) + So(q1.Result[0].TeamId, ShouldEqual, group1.Result.Id) + }) + + Convey("Should be able to update an existing permission for a team", func() { + err := testHelperUpdateDashboardAcl(savedFolder.Id, m.DashboardAcl{ + OrgId: 1, + TeamId: group1.Result.Id, + DashboardId: savedFolder.Id, + Permission: m.PERMISSION_ADMIN, + }) + So(err, ShouldBeNil) + + q3 := &m.GetDashboardAclInfoListQuery{DashboardId: savedFolder.Id, OrgId: 1} + err = GetDashboardAclInfoList(q3) + So(err, ShouldBeNil) + So(len(q3.Result), ShouldEqual, 1) + So(q3.Result[0].DashboardId, ShouldEqual, savedFolder.Id) + So(q3.Result[0].Permission, ShouldEqual, m.PERMISSION_ADMIN) + So(q3.Result[0].TeamId, ShouldEqual, group1.Result.Id) + }) + }) + }) + + Convey("Given a root folder", func() { + var rootFolderId int64 = 0 + + Convey("When reading dashboard acl should return default permissions", func() { + query := m.GetDashboardAclInfoListQuery{DashboardId: rootFolderId, OrgId: 1} + + err := GetDashboardAclInfoList(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + defaultPermissionsId := -1 + So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) + So(*query.Result[0].Role, ShouldEqual, m.ROLE_VIEWER) + So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) + So(*query.Result[1].Role, ShouldEqual, m.ROLE_EDITOR) + }) + }) + }) +} diff --git a/pkg/services/sqlstore/dashboard_folder_test.go b/pkg/services/sqlstore/dashboard_folder_test.go new file mode 100644 index 00000000000..40d6cf5bcb2 --- /dev/null +++ b/pkg/services/sqlstore/dashboard_folder_test.go @@ -0,0 +1,361 @@ +package sqlstore + +import ( + "testing" + + "github.com/go-xorm/xorm" + . "github.com/smartystreets/goconvey/convey" + + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/search" +) + +func TestDashboardFolderDataAccess(t *testing.T) { + var x *xorm.Engine + + Convey("Testing DB", t, func() { + x = InitTestDB(t) + + Convey("Given one dashboard folder with two dashboards and one dashboard in the root folder", func() { + folder := insertTestDashboard("1 test dash folder", 1, 0, true, "prod", "webapp") + dashInRoot := insertTestDashboard("test dash 67", 1, 0, false, "prod", "webapp") + childDash := insertTestDashboard("test dash 23", 1, folder.Id, false, "prod", "webapp") + insertTestDashboard("test dash 45", 1, folder.Id, false, "prod") + + currentUser := createUser("viewer", "Viewer", false) + + Convey("and no acls are set", func() { + Convey("should return all dashboards", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, + OrgId: 1, + DashboardIds: []int64{folder.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].Id, ShouldEqual, folder.Id) + So(query.Result[1].Id, ShouldEqual, dashInRoot.Id) + }) + }) + + Convey("and acl is set for dashboard folder", func() { + var otherUser int64 = 999 + testHelperUpdateDashboardAcl(folder.Id, m.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT}) + + Convey("should not return folder", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, + OrgId: 1, DashboardIds: []int64{folder.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Id, ShouldEqual, dashInRoot.Id) + }) + + Convey("when the user is given permission", func() { + testHelperUpdateDashboardAcl(folder.Id, m.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: currentUser.Id, Permission: m.PERMISSION_EDIT}) + + Convey("should be able to access folder", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, + OrgId: 1, + DashboardIds: []int64{folder.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].Id, ShouldEqual, folder.Id) + So(query.Result[1].Id, ShouldEqual, dashInRoot.Id) + }) + }) + + Convey("when the user is an admin", func() { + Convey("should be able to access folder", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{ + UserId: currentUser.Id, + OrgId: 1, + OrgRole: m.ROLE_ADMIN, + }, + OrgId: 1, + DashboardIds: []int64{folder.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].Id, ShouldEqual, folder.Id) + So(query.Result[1].Id, ShouldEqual, dashInRoot.Id) + }) + }) + }) + + Convey("and acl is set for dashboard child and folder has all permissions removed", func() { + var otherUser int64 = 999 + testHelperUpdateDashboardAcl(folder.Id) + testHelperUpdateDashboardAcl(childDash.Id, m.DashboardAcl{DashboardId: folder.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT}) + + Convey("should not return folder or child", func() { + query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}} + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Id, ShouldEqual, dashInRoot.Id) + }) + + Convey("when the user is given permission to child", func() { + testHelperUpdateDashboardAcl(childDash.Id, m.DashboardAcl{DashboardId: childDash.Id, OrgId: 1, UserId: currentUser.Id, Permission: m.PERMISSION_EDIT}) + + Convey("should be able to search for child dashboard but not folder", func() { + query := &search.FindPersistedDashboardsQuery{SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1, DashboardIds: []int64{folder.Id, childDash.Id, dashInRoot.Id}} + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].Id, ShouldEqual, childDash.Id) + So(query.Result[1].Id, ShouldEqual, dashInRoot.Id) + }) + }) + + Convey("when the user is an admin", func() { + Convey("should be able to search for child dash and folder", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{ + UserId: currentUser.Id, + OrgId: 1, + OrgRole: m.ROLE_ADMIN, + }, + OrgId: 1, + DashboardIds: []int64{folder.Id, dashInRoot.Id, childDash.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 3) + So(query.Result[0].Id, ShouldEqual, folder.Id) + So(query.Result[1].Id, ShouldEqual, childDash.Id) + So(query.Result[2].Id, ShouldEqual, dashInRoot.Id) + }) + }) + }) + }) + + Convey("Given two dashboard folders with one dashboard each and one dashboard in the root folder", func() { + folder1 := insertTestDashboard("1 test dash folder", 1, 0, true, "prod") + folder2 := insertTestDashboard("2 test dash folder", 1, 0, true, "prod") + dashInRoot := insertTestDashboard("test dash 67", 1, 0, false, "prod") + childDash1 := insertTestDashboard("child dash 1", 1, folder1.Id, false, "prod") + childDash2 := insertTestDashboard("child dash 2", 1, folder2.Id, false, "prod") + + currentUser := createUser("viewer", "Viewer", false) + var rootFolderId int64 = 0 + + Convey("and one folder is expanded, the other collapsed", func() { + Convey("should return dashboards in root and expanded folder", func() { + query := &search.FindPersistedDashboardsQuery{FolderIds: []int64{rootFolderId, folder1.Id}, SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, OrgId: 1} + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 4) + So(query.Result[0].Id, ShouldEqual, folder1.Id) + So(query.Result[1].Id, ShouldEqual, folder2.Id) + So(query.Result[2].Id, ShouldEqual, childDash1.Id) + So(query.Result[3].Id, ShouldEqual, dashInRoot.Id) + }) + }) + + Convey("and acl is set for one dashboard folder", func() { + var otherUser int64 = 999 + testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT}) + + Convey("and a dashboard is moved from folder without acl to the folder with an acl", func() { + moveDashboard(1, childDash2.Data, folder1.Id) + + Convey("should not return folder with acl or its children", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, + OrgId: 1, + DashboardIds: []int64{folder1.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Id, ShouldEqual, dashInRoot.Id) + }) + }) + Convey("and a dashboard is moved from folder with acl to the folder without an acl", func() { + moveDashboard(1, childDash1.Data, folder2.Id) + + Convey("should return folder without acl and its children", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, + OrgId: 1, + DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 4) + So(query.Result[0].Id, ShouldEqual, folder2.Id) + So(query.Result[1].Id, ShouldEqual, childDash1.Id) + So(query.Result[2].Id, ShouldEqual, childDash2.Id) + So(query.Result[3].Id, ShouldEqual, dashInRoot.Id) + }) + }) + + Convey("and a dashboard with an acl is moved to the folder without an acl", func() { + testHelperUpdateDashboardAcl(childDash1.Id, m.DashboardAcl{DashboardId: childDash1.Id, OrgId: 1, UserId: otherUser, Permission: m.PERMISSION_EDIT}) + moveDashboard(1, childDash1.Data, folder2.Id) + + Convey("should return folder without acl but not the dashboard with acl", func() { + query := &search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: currentUser.Id, OrgId: 1, OrgRole: m.ROLE_VIEWER}, + OrgId: 1, + DashboardIds: []int64{folder2.Id, childDash1.Id, childDash2.Id, dashInRoot.Id}, + } + err := SearchDashboards(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 4) + So(query.Result[0].Id, ShouldEqual, folder2.Id) + So(query.Result[1].Id, ShouldEqual, childDash1.Id) + So(query.Result[2].Id, ShouldEqual, childDash2.Id) + So(query.Result[3].Id, ShouldEqual, dashInRoot.Id) + }) + }) + }) + }) + + Convey("Given two dashboard folders", func() { + + folder1 := insertTestDashboard("1 test dash folder", 1, 0, true, "prod") + folder2 := insertTestDashboard("2 test dash folder", 1, 0, true, "prod") + insertTestDashboard("folder in another org", 2, 0, true, "prod") + + adminUser := createUser("admin", "Admin", true) + editorUser := createUser("editor", "Editor", false) + viewerUser := createUser("viewer", "Viewer", false) + + Convey("Admin users", func() { + Convey("Should have write access to all dashboard folders in their org", func() { + query := search.FindPersistedDashboardsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{UserId: adminUser.Id, OrgRole: m.ROLE_ADMIN, OrgId: 1}, + Permission: m.PERMISSION_VIEW, + Type: "dash-folder", + } + + err := SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].Id, ShouldEqual, folder1.Id) + So(query.Result[1].Id, ShouldEqual, folder2.Id) + }) + + Convey("should have write access to all folders and dashboards", func() { + query := m.GetDashboardPermissionsForUserQuery{ + DashboardIds: []int64{folder1.Id, folder2.Id}, + OrgId: 1, + UserId: adminUser.Id, + OrgRole: m.ROLE_ADMIN, + } + + err := GetDashboardPermissionsForUser(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].DashboardId, ShouldEqual, folder1.Id) + So(query.Result[0].Permission, ShouldEqual, m.PERMISSION_ADMIN) + So(query.Result[1].DashboardId, ShouldEqual, folder2.Id) + So(query.Result[1].Permission, ShouldEqual, m.PERMISSION_ADMIN) + }) + }) + + Convey("Editor users", func() { + query := search.FindPersistedDashboardsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{UserId: editorUser.Id, OrgRole: m.ROLE_EDITOR, OrgId: 1}, + Permission: m.PERMISSION_EDIT, + } + + Convey("Should have write access to all dashboard folders with default ACL", func() { + err := SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].Id, ShouldEqual, folder1.Id) + So(query.Result[1].Id, ShouldEqual, folder2.Id) + }) + + Convey("should have edit access to folders with default ACL", func() { + query := m.GetDashboardPermissionsForUserQuery{ + DashboardIds: []int64{folder1.Id, folder2.Id}, + OrgId: 1, + UserId: editorUser.Id, + OrgRole: m.ROLE_EDITOR, + } + + err := GetDashboardPermissionsForUser(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].DashboardId, ShouldEqual, folder1.Id) + So(query.Result[0].Permission, ShouldEqual, m.PERMISSION_EDIT) + So(query.Result[1].DashboardId, ShouldEqual, folder2.Id) + So(query.Result[1].Permission, ShouldEqual, m.PERMISSION_EDIT) + }) + + Convey("Should have write access to one dashboard folder if default role changed to view for one folder", func() { + testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: editorUser.Id, Permission: m.PERMISSION_VIEW}) + + err := SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Id, ShouldEqual, folder2.Id) + }) + + }) + + Convey("Viewer users", func() { + query := search.FindPersistedDashboardsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{UserId: viewerUser.Id, OrgRole: m.ROLE_VIEWER, OrgId: 1}, + Permission: m.PERMISSION_EDIT, + } + + Convey("Should have no write access to any dashboard folders with default ACL", func() { + err := SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 0) + }) + + Convey("should have view access to folders with default ACL", func() { + query := m.GetDashboardPermissionsForUserQuery{ + DashboardIds: []int64{folder1.Id, folder2.Id}, + OrgId: 1, + UserId: viewerUser.Id, + OrgRole: m.ROLE_VIEWER, + } + + err := GetDashboardPermissionsForUser(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + So(query.Result[0].DashboardId, ShouldEqual, folder1.Id) + So(query.Result[0].Permission, ShouldEqual, m.PERMISSION_VIEW) + So(query.Result[1].DashboardId, ShouldEqual, folder2.Id) + So(query.Result[1].Permission, ShouldEqual, m.PERMISSION_VIEW) + }) + + Convey("Should be able to get one dashboard folder if default role changed to edit for one folder", func() { + testHelperUpdateDashboardAcl(folder1.Id, m.DashboardAcl{DashboardId: folder1.Id, OrgId: 1, UserId: viewerUser.Id, Permission: m.PERMISSION_EDIT}) + + err := SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Id, ShouldEqual, folder1.Id) + }) + }) + }) + }) +} diff --git a/pkg/services/sqlstore/dashboard_provisioning.go b/pkg/services/sqlstore/dashboard_provisioning.go new file mode 100644 index 00000000000..69409c3b873 --- /dev/null +++ b/pkg/services/sqlstore/dashboard_provisioning.go @@ -0,0 +1,66 @@ +package sqlstore + +import ( + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/models" +) + +func init() { + bus.AddHandler("sql", GetProvisionedDashboardDataQuery) + bus.AddHandler("sql", SaveProvisionedDashboard) +} + +type DashboardExtras struct { + Id int64 + DashboardId int64 + Key string + Value string +} + +func SaveProvisionedDashboard(cmd *models.SaveProvisionedDashboardCommand) error { + return inTransaction(func(sess *DBSession) error { + err := saveDashboard(sess, cmd.DashboardCmd) + + if err != nil { + return err + } + + cmd.Result = cmd.DashboardCmd.Result + if cmd.DashboardProvisioning.Updated == 0 { + cmd.DashboardProvisioning.Updated = cmd.Result.Updated.Unix() + } + + return saveProvionedData(sess, cmd.DashboardProvisioning, cmd.Result) + }) +} + +func saveProvionedData(sess *DBSession, cmd *models.DashboardProvisioning, dashboard *models.Dashboard) error { + result := &models.DashboardProvisioning{} + + exist, err := sess.Where("dashboard_id=?", dashboard.Id).Get(result) + if err != nil { + return err + } + + cmd.Id = result.Id + cmd.DashboardId = dashboard.Id + + if exist { + _, err = sess.ID(result.Id).Update(cmd) + } else { + _, err = sess.Insert(cmd) + } + + return err +} + +func GetProvisionedDashboardDataQuery(cmd *models.GetProvisionedDashboardDataQuery) error { + var result []*models.DashboardProvisioning + + if err := x.Where("name = ?", cmd.Name).Find(&result); err != nil { + return err + } + + cmd.Result = result + return nil +} diff --git a/pkg/services/sqlstore/dashboard_provisioning_test.go b/pkg/services/sqlstore/dashboard_provisioning_test.go new file mode 100644 index 00000000000..b752173b67d --- /dev/null +++ b/pkg/services/sqlstore/dashboard_provisioning_test.go @@ -0,0 +1,55 @@ +package sqlstore + +import ( + "testing" + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestDashboardProvisioningTest(t *testing.T) { + Convey("Testing Dashboard provisioning", t, func() { + InitTestDB(t) + + saveDashboardCmd := &models.SaveDashboardCommand{ + OrgId: 1, + FolderId: 0, + IsFolder: false, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": "test dashboard", + }), + } + + Convey("Saving dashboards with extras", func() { + now := time.Now() + + cmd := &models.SaveProvisionedDashboardCommand{ + DashboardCmd: saveDashboardCmd, + DashboardProvisioning: &models.DashboardProvisioning{ + Name: "default", + ExternalId: "/var/grafana.json", + Updated: now.Unix(), + }, + } + + err := SaveProvisionedDashboard(cmd) + So(err, ShouldBeNil) + So(cmd.Result, ShouldNotBeNil) + So(cmd.Result.Id, ShouldNotEqual, 0) + dashId := cmd.Result.Id + + Convey("Can query for provisioned dashboards", func() { + query := &models.GetProvisionedDashboardDataQuery{Name: "default"} + err := GetProvisionedDashboardDataQuery(query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].DashboardId, ShouldEqual, dashId) + So(query.Result[0].Updated, ShouldEqual, now.Unix()) + }) + }) + }) +} diff --git a/pkg/services/sqlstore/dashboard_service_integration_test.go b/pkg/services/sqlstore/dashboard_service_integration_test.go new file mode 100644 index 00000000000..d005270c33c --- /dev/null +++ b/pkg/services/sqlstore/dashboard_service_integration_test.go @@ -0,0 +1,932 @@ +package sqlstore + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/guardian" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/models" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestIntegratedDashboardService(t *testing.T) { + Convey("Dashboard service integration tests", t, func() { + InitTestDB(t) + var testOrgId int64 = 1 + + Convey("Given saved folders and dashboards in organization A", func() { + + bus.AddHandler("test", func(cmd *models.ValidateDashboardAlertsCommand) error { + return nil + }) + + bus.AddHandler("test", func(cmd *models.UpdateDashboardAlertsCommand) error { + return nil + }) + + savedFolder := saveTestFolder("Saved folder", testOrgId) + savedDashInFolder := saveTestDashboard("Saved dash in folder", testOrgId, savedFolder.Id) + saveTestDashboard("Other saved dash in folder", testOrgId, savedFolder.Id) + savedDashInGeneralFolder := saveTestDashboard("Saved dashboard in general folder", testOrgId, 0) + otherSavedFolder := saveTestFolder("Other saved folder", testOrgId) + + Convey("Should return dashboard model", func() { + So(savedFolder.Title, ShouldEqual, "Saved folder") + So(savedFolder.Slug, ShouldEqual, "saved-folder") + So(savedFolder.Id, ShouldNotEqual, 0) + So(savedFolder.IsFolder, ShouldBeTrue) + So(savedFolder.FolderId, ShouldEqual, 0) + So(len(savedFolder.Uid), ShouldBeGreaterThan, 0) + + So(savedDashInFolder.Title, ShouldEqual, "Saved dash in folder") + So(savedDashInFolder.Slug, ShouldEqual, "saved-dash-in-folder") + So(savedDashInFolder.Id, ShouldNotEqual, 0) + So(savedDashInFolder.IsFolder, ShouldBeFalse) + So(savedDashInFolder.FolderId, ShouldEqual, savedFolder.Id) + So(len(savedDashInFolder.Uid), ShouldBeGreaterThan, 0) + }) + + // Basic validation tests + + Convey("When saving a dashboard with non-existing id", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": float64(123412321), + "title": "Expect error", + }), + } + + err := callSaveWithError(cmd) + + Convey("It should result in not found error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardNotFound) + }) + }) + + // Given other organization + + Convey("Given organization B", func() { + var otherOrgId int64 = 2 + + Convey("When saving a dashboard with id that are saved in organization A", func() { + cmd := models.SaveDashboardCommand{ + OrgId: otherOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInFolder.Id, + "title": "Expect error", + }), + Overwrite: false, + } + + err := callSaveWithError(cmd) + + Convey("It should result in not found error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardNotFound) + }) + }) + + permissionScenario("Given user has permission to save", true, func(sc *dashboardPermissionScenarioContext) { + Convey("When saving a dashboard with uid that are saved in organization A", func() { + var otherOrgId int64 = 2 + cmd := models.SaveDashboardCommand{ + OrgId: otherOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "uid": savedDashInFolder.Uid, + "title": "Dash with existing uid in other org", + }), + Overwrite: false, + } + + res := callSaveWithResult(cmd) + + Convey("It should create dashboard in other organization", func() { + So(res, ShouldNotBeNil) + + query := models.GetDashboardQuery{OrgId: otherOrgId, Uid: savedDashInFolder.Uid} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Id, ShouldNotEqual, savedDashInFolder.Id) + So(query.Result.Id, ShouldEqual, res.Id) + So(query.Result.OrgId, ShouldEqual, otherOrgId) + So(query.Result.Uid, ShouldEqual, savedDashInFolder.Uid) + }) + }) + }) + }) + + // Given user has no permission to save + + permissionScenario("Given user has no permission to save", false, func(sc *dashboardPermissionScenarioContext) { + + Convey("When trying to create a new dashboard in the General folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash", + }), + UserId: 10000, + Overwrite: true, + } + + err := callSaveWithError(cmd) + + Convey("It should call dashboard guardian with correct arguments and result in access denied error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardUpdateAccessDenied) + + So(sc.dashboardGuardianMock.DashId, ShouldEqual, 0) + So(sc.dashboardGuardianMock.OrgId, ShouldEqual, cmd.OrgId) + So(sc.dashboardGuardianMock.User.UserId, ShouldEqual, cmd.UserId) + }) + }) + + Convey("When trying to create a new dashboard in other folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash", + }), + FolderId: otherSavedFolder.Id, + UserId: 10000, + Overwrite: true, + } + + err := callSaveWithError(cmd) + + Convey("It should call dashboard guardian with correct arguments and rsult in access denied error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardUpdateAccessDenied) + + So(sc.dashboardGuardianMock.DashId, ShouldEqual, otherSavedFolder.Id) + So(sc.dashboardGuardianMock.OrgId, ShouldEqual, cmd.OrgId) + So(sc.dashboardGuardianMock.User.UserId, ShouldEqual, cmd.UserId) + }) + }) + + Convey("When trying to update a dashboard by existing id in the General folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInGeneralFolder.Id, + "title": "Dash", + }), + FolderId: savedDashInGeneralFolder.FolderId, + UserId: 10000, + Overwrite: true, + } + + err := callSaveWithError(cmd) + + Convey("It should call dashboard guardian with correct arguments and result in access denied error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardUpdateAccessDenied) + + So(sc.dashboardGuardianMock.DashId, ShouldEqual, savedDashInGeneralFolder.Id) + So(sc.dashboardGuardianMock.OrgId, ShouldEqual, cmd.OrgId) + So(sc.dashboardGuardianMock.User.UserId, ShouldEqual, cmd.UserId) + }) + }) + + Convey("When trying to update a dashboard by existing id in other folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInFolder.Id, + "title": "Dash", + }), + FolderId: savedDashInFolder.FolderId, + UserId: 10000, + Overwrite: true, + } + + err := callSaveWithError(cmd) + + Convey("It should call dashboard guardian with correct arguments and result in access denied error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardUpdateAccessDenied) + + So(sc.dashboardGuardianMock.DashId, ShouldEqual, savedDashInFolder.Id) + So(sc.dashboardGuardianMock.OrgId, ShouldEqual, cmd.OrgId) + So(sc.dashboardGuardianMock.User.UserId, ShouldEqual, cmd.UserId) + }) + }) + }) + + // Given user has permission to save + + permissionScenario("Given user has permission to save", true, func(sc *dashboardPermissionScenarioContext) { + + Convey("and overwrite flag is set to false", func() { + shouldOverwrite := false + + Convey("When creating a dashboard in General folder with same name as dashboard in other folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInFolder.Title, + }), + FolderId: 0, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should create a new dashboard", func() { + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Id, ShouldEqual, res.Id) + So(query.Result.FolderId, ShouldEqual, 0) + }) + }) + + Convey("When creating a dashboard in other folder with same name as dashboard in General folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInGeneralFolder.Title, + }), + FolderId: savedFolder.Id, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should create a new dashboard", func() { + So(res.Id, ShouldNotEqual, savedDashInGeneralFolder.Id) + + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.FolderId, ShouldEqual, savedFolder.Id) + }) + }) + + Convey("When creating a folder with same name as dashboard in other folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInFolder.Title, + }), + IsFolder: true, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should create a new folder", func() { + So(res.Id, ShouldNotEqual, savedDashInGeneralFolder.Id) + So(res.IsFolder, ShouldBeTrue) + + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.FolderId, ShouldEqual, 0) + So(query.Result.IsFolder, ShouldBeTrue) + }) + }) + + Convey("When saving a dashboard without id and uid and unique title in folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash without id and uid", + }), + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should create a new dashboard", func() { + So(res.Id, ShouldBeGreaterThan, 0) + So(len(res.Uid), ShouldBeGreaterThan, 0) + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Id, ShouldEqual, res.Id) + So(query.Result.Uid, ShouldEqual, res.Uid) + }) + }) + + Convey("When saving a dashboard when dashboard id is zero ", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": 0, + "title": "Dash with zero id", + }), + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should create a new dashboard", func() { + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Id, ShouldEqual, res.Id) + }) + }) + + Convey("When saving a dashboard in non-existing folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "Expect error", + }), + FolderId: 123412321, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in folder not found error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardFolderNotFound) + }) + }) + + Convey("When updating an existing dashboard by id without current version", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInGeneralFolder.Id, + "title": "test dash 23", + }), + FolderId: savedFolder.Id, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in version mismatch error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardVersionMismatch) + }) + }) + + Convey("When updating an existing dashboard by id with current version", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInGeneralFolder.Id, + "title": "Updated title", + "version": savedDashInGeneralFolder.Version, + }), + FolderId: savedFolder.Id, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should update dashboard", func() { + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: savedDashInGeneralFolder.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Title, ShouldEqual, "Updated title") + So(query.Result.FolderId, ShouldEqual, savedFolder.Id) + So(query.Result.Version, ShouldBeGreaterThan, savedDashInGeneralFolder.Version) + }) + }) + + Convey("When updating an existing dashboard by uid without current version", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "uid": savedDashInFolder.Uid, + "title": "test dash 23", + }), + FolderId: 0, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in version mismatch error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardVersionMismatch) + }) + }) + + Convey("When updating an existing dashboard by uid with current version", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "uid": savedDashInFolder.Uid, + "title": "Updated title", + "version": savedDashInFolder.Version, + }), + FolderId: 0, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should update dashboard", func() { + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: savedDashInFolder.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Title, ShouldEqual, "Updated title") + So(query.Result.FolderId, ShouldEqual, 0) + So(query.Result.Version, ShouldBeGreaterThan, savedDashInFolder.Version) + }) + }) + + Convey("When creating a dashboard with same name as dashboard in other folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInFolder.Title, + }), + FolderId: savedDashInFolder.FolderId, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in dashboard with same name in folder error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardWithSameNameInFolderExists) + }) + }) + + Convey("When creating a dashboard with same name as dashboard in General folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInGeneralFolder.Title, + }), + FolderId: savedDashInGeneralFolder.FolderId, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in dashboard with same name in folder error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardWithSameNameInFolderExists) + }) + }) + + Convey("When creating a folder with same name as existing folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedFolder.Title, + }), + IsFolder: true, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in dashboard with same name in folder error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardWithSameNameInFolderExists) + }) + }) + }) + + Convey("and overwrite flag is set to true", func() { + shouldOverwrite := true + + Convey("When updating an existing dashboard by id without current version", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInGeneralFolder.Id, + "title": "Updated title", + }), + FolderId: savedFolder.Id, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should update dashboard", func() { + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: savedDashInGeneralFolder.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Title, ShouldEqual, "Updated title") + So(query.Result.FolderId, ShouldEqual, savedFolder.Id) + So(query.Result.Version, ShouldBeGreaterThan, savedDashInGeneralFolder.Version) + }) + }) + + Convey("When updating an existing dashboard by uid without current version", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "uid": savedDashInFolder.Uid, + "title": "Updated title", + }), + FolderId: 0, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + So(res, ShouldNotBeNil) + + Convey("It should update dashboard", func() { + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: savedDashInFolder.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Title, ShouldEqual, "Updated title") + So(query.Result.FolderId, ShouldEqual, 0) + So(query.Result.Version, ShouldBeGreaterThan, savedDashInFolder.Version) + }) + }) + + Convey("When updating uid for existing dashboard using id", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInFolder.Id, + "uid": "new-uid", + "title": savedDashInFolder.Title, + }), + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + + Convey("It should update dashboard", func() { + So(res, ShouldNotBeNil) + So(res.Id, ShouldEqual, savedDashInFolder.Id) + So(res.Uid, ShouldEqual, "new-uid") + + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: savedDashInFolder.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Uid, ShouldEqual, "new-uid") + So(query.Result.Version, ShouldBeGreaterThan, savedDashInFolder.Version) + }) + }) + + Convey("When updating uid to an existing uid for existing dashboard using id", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInFolder.Id, + "uid": savedDashInGeneralFolder.Uid, + "title": savedDashInFolder.Title, + }), + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in same uid exists error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardWithSameUIDExists) + }) + }) + + Convey("When creating a dashboard with same name as dashboard in other folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInFolder.Title, + }), + FolderId: savedDashInFolder.FolderId, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + + Convey("It should overwrite existing dashboard", func() { + So(res, ShouldNotBeNil) + So(res.Id, ShouldEqual, savedDashInFolder.Id) + So(res.Uid, ShouldEqual, savedDashInFolder.Uid) + + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Id, ShouldEqual, res.Id) + So(query.Result.Uid, ShouldEqual, res.Uid) + }) + }) + + Convey("When creating a dashboard with same name as dashboard in General folder", func() { + cmd := models.SaveDashboardCommand{ + OrgId: testOrgId, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": savedDashInGeneralFolder.Title, + }), + FolderId: savedDashInGeneralFolder.FolderId, + Overwrite: shouldOverwrite, + } + + res := callSaveWithResult(cmd) + + Convey("It should overwrite existing dashboard", func() { + So(res, ShouldNotBeNil) + So(res.Id, ShouldEqual, savedDashInGeneralFolder.Id) + So(res.Uid, ShouldEqual, savedDashInGeneralFolder.Uid) + + query := models.GetDashboardQuery{OrgId: cmd.OrgId, Id: res.Id} + + err := bus.Dispatch(&query) + So(err, ShouldBeNil) + So(query.Result.Id, ShouldEqual, res.Id) + So(query.Result.Uid, ShouldEqual, res.Uid) + }) + }) + + Convey("When trying to update existing folder to a dashboard using id", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedFolder.Id, + "title": "new title", + }), + IsFolder: false, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in type mismatch error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardTypeMismatch) + }) + }) + + Convey("When trying to update existing dashboard to a folder using id", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDashInFolder.Id, + "title": "new folder title", + }), + IsFolder: true, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in type mismatch error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardTypeMismatch) + }) + }) + + Convey("When trying to update existing folder to a dashboard using uid", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "uid": savedFolder.Uid, + "title": "new title", + }), + IsFolder: false, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in type mismatch error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardTypeMismatch) + }) + }) + + Convey("When trying to update existing dashboard to a folder using uid", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "uid": savedDashInFolder.Uid, + "title": "new folder title", + }), + IsFolder: true, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in type mismatch error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardTypeMismatch) + }) + }) + + Convey("When trying to update existing folder to a dashboard using title", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": savedFolder.Title, + }), + IsFolder: false, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in dashboard with same name as folder error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardWithSameNameAsFolder) + }) + }) + + Convey("When trying to update existing dashboard to a folder using title", func() { + cmd := models.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": savedDashInGeneralFolder.Title, + }), + IsFolder: true, + Overwrite: shouldOverwrite, + } + + err := callSaveWithError(cmd) + + Convey("It should result in folder with same name as dashboard error", func() { + So(err, ShouldNotBeNil) + So(err, ShouldEqual, models.ErrDashboardFolderWithSameNameAsDashboard) + }) + }) + }) + }) + }) + }) +} + +type scenarioContext struct { + dashboardGuardianMock *guardian.FakeDashboardGuardian +} + +type scenarioFunc func(c *scenarioContext) + +func dashboardGuardianScenario(desc string, mock *guardian.FakeDashboardGuardian, fn scenarioFunc) { + Convey(desc, func() { + origNewDashboardGuardian := guardian.New + guardian.MockDashboardGuardian(mock) + + sc := &scenarioContext{ + dashboardGuardianMock: mock, + } + + defer func() { + guardian.New = origNewDashboardGuardian + }() + + fn(sc) + }) +} + +type dashboardPermissionScenarioContext struct { + dashboardGuardianMock *guardian.FakeDashboardGuardian +} + +type dashboardPermissionScenarioFunc func(sc *dashboardPermissionScenarioContext) + +func dashboardPermissionScenario(desc string, mock *guardian.FakeDashboardGuardian, fn dashboardPermissionScenarioFunc) { + Convey(desc, func() { + origNewDashboardGuardian := guardian.New + guardian.MockDashboardGuardian(mock) + + sc := &dashboardPermissionScenarioContext{ + dashboardGuardianMock: mock, + } + + defer func() { + guardian.New = origNewDashboardGuardian + }() + + fn(sc) + }) +} + +func permissionScenario(desc string, canSave bool, fn dashboardPermissionScenarioFunc) { + mock := &guardian.FakeDashboardGuardian{ + CanSaveValue: canSave, + } + dashboardPermissionScenario(desc, mock, fn) +} + +func callSaveWithResult(cmd models.SaveDashboardCommand) *models.Dashboard { + dto := toSaveDashboardDto(cmd) + res, _ := dashboards.NewService().SaveDashboard(&dto) + return res +} + +func callSaveWithError(cmd models.SaveDashboardCommand) error { + dto := toSaveDashboardDto(cmd) + _, err := dashboards.NewService().SaveDashboard(&dto) + return err +} + +func dashboardServiceScenario(desc string, mock *guardian.FakeDashboardGuardian, fn scenarioFunc) { + Convey(desc, func() { + origNewDashboardGuardian := guardian.New + guardian.MockDashboardGuardian(mock) + + sc := &scenarioContext{ + dashboardGuardianMock: mock, + } + + defer func() { + guardian.New = origNewDashboardGuardian + }() + + fn(sc) + }) +} + +func saveTestDashboard(title string, orgId int64, folderId int64) *models.Dashboard { + cmd := models.SaveDashboardCommand{ + OrgId: orgId, + FolderId: folderId, + IsFolder: false, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + }), + } + + dto := dashboards.SaveDashboardDTO{ + OrgId: orgId, + Dashboard: cmd.GetDashboardModel(), + User: &models.SignedInUser{ + UserId: 1, + OrgRole: models.ROLE_ADMIN, + }, + } + + res, err := dashboards.NewService().SaveDashboard(&dto) + So(err, ShouldBeNil) + + return res +} + +func saveTestFolder(title string, orgId int64) *models.Dashboard { + cmd := models.SaveDashboardCommand{ + OrgId: orgId, + FolderId: 0, + IsFolder: true, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + }), + } + + dto := dashboards.SaveDashboardDTO{ + OrgId: orgId, + Dashboard: cmd.GetDashboardModel(), + User: &models.SignedInUser{ + UserId: 1, + OrgRole: models.ROLE_ADMIN, + }, + } + + res, err := dashboards.NewService().SaveDashboard(&dto) + So(err, ShouldBeNil) + + return res +} + +func toSaveDashboardDto(cmd models.SaveDashboardCommand) dashboards.SaveDashboardDTO { + dash := (&cmd).GetDashboardModel() + + return dashboards.SaveDashboardDTO{ + Dashboard: dash, + Message: cmd.Message, + OrgId: cmd.OrgId, + User: &models.SignedInUser{UserId: cmd.UserId}, + Overwrite: cmd.Overwrite, + } +} diff --git a/pkg/services/sqlstore/dashboard_snapshot.go b/pkg/services/sqlstore/dashboard_snapshot.go index 0ef7f99da67..9e82bbb2c83 100644 --- a/pkg/services/sqlstore/dashboard_snapshot.go +++ b/pkg/services/sqlstore/dashboard_snapshot.go @@ -16,20 +16,23 @@ func init() { bus.AddHandler("sql", DeleteExpiredSnapshots) } +// DeleteExpiredSnapshots removes snapshots with old expiry dates. +// SnapShotRemoveExpired is deprecated and should be removed in the future. +// Snapshot expiry is decided by the user when they share the snapshot. func DeleteExpiredSnapshots(cmd *m.DeleteExpiredSnapshotsCommand) error { return inTransaction(func(sess *DBSession) error { - var expiredCount int64 = 0 - - if setting.SnapShotRemoveExpired { - deleteExpiredSql := "DELETE FROM dashboard_snapshot WHERE expires < ?" - expiredResponse, err := x.Exec(deleteExpiredSql, time.Now) - if err != nil { - return err - } - expiredCount, _ = expiredResponse.RowsAffected() + if !setting.SnapShotRemoveExpired { + sqlog.Warn("[Deprecated] The snapshot_remove_expired setting is outdated. Please remove from your config.") + return nil } - sqlog.Debug("Deleted old/expired snaphots", "expired", expiredCount) + deleteExpiredSql := "DELETE FROM dashboard_snapshot WHERE expires < ?" + expiredResponse, err := sess.Exec(deleteExpiredSql, time.Now()) + if err != nil { + return err + } + cmd.DeletedRows, _ = expiredResponse.RowsAffected() + return nil }) } @@ -72,7 +75,7 @@ func DeleteDashboardSnapshot(cmd *m.DeleteDashboardSnapshotCommand) error { } func GetDashboardSnapshot(query *m.GetDashboardSnapshotQuery) error { - snapshot := m.DashboardSnapshot{Key: query.Key} + snapshot := m.DashboardSnapshot{Key: query.Key, DeleteKey: query.DeleteKey} has, err := x.Get(&snapshot) if err != nil { @@ -85,6 +88,8 @@ func GetDashboardSnapshot(query *m.GetDashboardSnapshotQuery) error { return nil } +// SearchDashboardSnapshots returns a list of all snapshots for admins +// for other roles, it returns snapshots created by the user func SearchDashboardSnapshots(query *m.GetDashboardSnapshotsQuery) error { var snapshots = make(m.DashboardSnapshotsList, 0) @@ -95,7 +100,16 @@ func SearchDashboardSnapshots(query *m.GetDashboardSnapshotsQuery) error { sess.Where("name LIKE ?", query.Name) } - sess.Where("org_id = ?", query.OrgId) + // admins can see all snapshots, everyone else can only see their own snapshots + if query.SignedInUser.OrgRole == m.ROLE_ADMIN { + sess.Where("org_id = ?", query.OrgId) + } else if !query.SignedInUser.IsAnonymous { + sess.Where("org_id = ? AND user_id = ?", query.OrgId, query.SignedInUser.UserId) + } else { + query.Result = snapshots + return nil + } + err := sess.Find(&snapshots) query.Result = snapshots return err diff --git a/pkg/services/sqlstore/dashboard_snapshot_test.go b/pkg/services/sqlstore/dashboard_snapshot_test.go index 50375088b4b..2081cbf6194 100644 --- a/pkg/services/sqlstore/dashboard_snapshot_test.go +++ b/pkg/services/sqlstore/dashboard_snapshot_test.go @@ -2,11 +2,14 @@ package sqlstore import ( "testing" + "time" + "github.com/go-xorm/xorm" . "github.com/smartystreets/goconvey/convey" "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" ) func TestDashboardSnapshotDBAccess(t *testing.T) { @@ -14,17 +17,19 @@ func TestDashboardSnapshotDBAccess(t *testing.T) { Convey("Testing DashboardSnapshot data access", t, func() { InitTestDB(t) - Convey("Given saved snaphot", func() { + Convey("Given saved snapshot", func() { cmd := m.CreateDashboardSnapshotCommand{ Key: "hej", Dashboard: simplejson.NewFromAny(map[string]interface{}{ "hello": "mupp", }), + UserId: 1000, + OrgId: 1, } err := CreateDashboardSnapshot(&cmd) So(err, ShouldBeNil) - Convey("Should be able to get snaphot by key", func() { + Convey("Should be able to get snapshot by key", func() { query := m.GetDashboardSnapshotQuery{Key: "hej"} err = GetDashboardSnapshot(&query) So(err, ShouldBeNil) @@ -33,6 +38,135 @@ func TestDashboardSnapshotDBAccess(t *testing.T) { So(query.Result.Dashboard.Get("hello").MustString(), ShouldEqual, "mupp") }) + Convey("And the user has the admin role", func() { + Convey("Should return all the snapshots", func() { + query := m.GetDashboardSnapshotsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}, + } + err := SearchDashboardSnapshots(&query) + So(err, ShouldBeNil) + + So(query.Result, ShouldNotBeNil) + So(len(query.Result), ShouldEqual, 1) + }) + }) + + Convey("And the user has the editor role and has created a snapshot", func() { + Convey("Should return all the snapshots", func() { + query := m.GetDashboardSnapshotsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_EDITOR, UserId: 1000}, + } + err := SearchDashboardSnapshots(&query) + So(err, ShouldBeNil) + + So(query.Result, ShouldNotBeNil) + So(len(query.Result), ShouldEqual, 1) + }) + }) + + Convey("And the user has the editor role and has not created any snapshot", func() { + Convey("Should not return any snapshots", func() { + query := m.GetDashboardSnapshotsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_EDITOR, UserId: 2}, + } + err := SearchDashboardSnapshots(&query) + So(err, ShouldBeNil) + + So(query.Result, ShouldNotBeNil) + So(len(query.Result), ShouldEqual, 0) + }) + }) + + Convey("And the user is anonymous", func() { + cmd := m.CreateDashboardSnapshotCommand{ + Key: "strangesnapshotwithuserid0", + DeleteKey: "adeletekey", + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "hello": "mupp", + }), + UserId: 0, + OrgId: 1, + } + err := CreateDashboardSnapshot(&cmd) + So(err, ShouldBeNil) + + Convey("Should not return any snapshots", func() { + query := m.GetDashboardSnapshotsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_EDITOR, IsAnonymous: true, UserId: 0}, + } + err := SearchDashboardSnapshots(&query) + So(err, ShouldBeNil) + + So(query.Result, ShouldNotBeNil) + So(len(query.Result), ShouldEqual, 0) + }) + }) }) }) } + +func TestDeleteExpiredSnapshots(t *testing.T) { + Convey("Testing dashboard snapshots clean up", t, func() { + x := InitTestDB(t) + + setting.SnapShotRemoveExpired = true + + notExpiredsnapshot := createTestSnapshot(x, "key1", 1000) + createTestSnapshot(x, "key2", -1000) + createTestSnapshot(x, "key3", -1000) + + Convey("Clean up old dashboard snapshots", func() { + err := DeleteExpiredSnapshots(&m.DeleteExpiredSnapshotsCommand{}) + So(err, ShouldBeNil) + + query := m.GetDashboardSnapshotsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}, + } + err = SearchDashboardSnapshots(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Key, ShouldEqual, notExpiredsnapshot.Key) + }) + + Convey("Don't delete anything if there are no expired snapshots", func() { + err := DeleteExpiredSnapshots(&m.DeleteExpiredSnapshotsCommand{}) + So(err, ShouldBeNil) + + query := m.GetDashboardSnapshotsQuery{ + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_ADMIN}, + } + SearchDashboardSnapshots(&query) + + So(len(query.Result), ShouldEqual, 1) + }) + }) +} + +func createTestSnapshot(x *xorm.Engine, key string, expires int64) *m.DashboardSnapshot { + cmd := m.CreateDashboardSnapshotCommand{ + Key: key, + DeleteKey: "delete" + key, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "hello": "mupp", + }), + UserId: 1000, + OrgId: 1, + Expires: expires, + } + err := CreateDashboardSnapshot(&cmd) + So(err, ShouldBeNil) + + // Set expiry date manually - to be able to create expired snapshots + expireDate := time.Now().Add(time.Second * time.Duration(expires)) + _, err = x.Exec("update dashboard_snapshot set expires = ? where "+dialect.Quote("key")+" = ?", expireDate, key) + So(err, ShouldBeNil) + + return cmd.Result +} diff --git a/pkg/services/sqlstore/dashboard_test.go b/pkg/services/sqlstore/dashboard_test.go index a055500592b..e0a73b9a49a 100644 --- a/pkg/services/sqlstore/dashboard_test.go +++ b/pkg/services/sqlstore/dashboard_test.go @@ -1,49 +1,64 @@ package sqlstore import ( + "fmt" "testing" + "time" - . "github.com/smartystreets/goconvey/convey" - - "github.com/gosimple/slug" + "github.com/go-xorm/xorm" "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/search" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" + . "github.com/smartystreets/goconvey/convey" ) -func insertTestDashboard(title string, orgId int64, tags ...interface{}) *m.Dashboard { - cmd := m.SaveDashboardCommand{ - OrgId: orgId, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": title, - "tags": tags, - }), - } - - err := SaveDashboard(&cmd) - So(err, ShouldBeNil) - - return cmd.Result -} - func TestDashboardDataAccess(t *testing.T) { + var x *xorm.Engine Convey("Testing DB", t, func() { - InitTestDB(t) + x = InitTestDB(t) Convey("Given saved dashboard", func() { - savedDash := insertTestDashboard("test dash 23", 1, "prod", "webapp") - insertTestDashboard("test dash 45", 1, "prod") - insertTestDashboard("test dash 67", 1, "prod", "webapp") + savedFolder := insertTestDashboard("1 test dash folder", 1, 0, true, "prod", "webapp") + savedDash := insertTestDashboard("test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + insertTestDashboard("test dash 45", 1, savedFolder.Id, false, "prod") + insertTestDashboard("test dash 67", 1, 0, false, "prod", "webapp") Convey("Should return dashboard model", func() { So(savedDash.Title, ShouldEqual, "test dash 23") So(savedDash.Slug, ShouldEqual, "test-dash-23") So(savedDash.Id, ShouldNotEqual, 0) + So(savedDash.IsFolder, ShouldBeFalse) + So(savedDash.FolderId, ShouldBeGreaterThan, 0) + So(len(savedDash.Uid), ShouldBeGreaterThan, 0) + + So(savedFolder.Title, ShouldEqual, "1 test dash folder") + So(savedFolder.Slug, ShouldEqual, "1-test-dash-folder") + So(savedFolder.Id, ShouldNotEqual, 0) + So(savedFolder.IsFolder, ShouldBeTrue) + So(savedFolder.FolderId, ShouldEqual, 0) + So(len(savedFolder.Uid), ShouldBeGreaterThan, 0) }) - Convey("Should be able to get dashboard", func() { + Convey("Should be able to get dashboard by id", func() { + query := m.GetDashboardQuery{ + Id: savedDash.Id, + OrgId: 1, + } + + err := GetDashboard(&query) + So(err, ShouldBeNil) + + So(query.Result.Title, ShouldEqual, "test dash 23") + So(query.Result.Slug, ShouldEqual, "test-dash-23") + So(query.Result.Id, ShouldEqual, savedDash.Id) + So(query.Result.Uid, ShouldEqual, savedDash.Uid) + So(query.Result.IsFolder, ShouldBeFalse) + }) + + Convey("Should be able to get dashboard by slug", func() { query := m.GetDashboardQuery{ Slug: "test-dash-23", OrgId: 1, @@ -54,22 +69,144 @@ func TestDashboardDataAccess(t *testing.T) { So(query.Result.Title, ShouldEqual, "test dash 23") So(query.Result.Slug, ShouldEqual, "test-dash-23") + So(query.Result.Id, ShouldEqual, savedDash.Id) + So(query.Result.Uid, ShouldEqual, savedDash.Uid) + So(query.Result.IsFolder, ShouldBeFalse) + }) + + Convey("Should be able to get dashboard by uid", func() { + query := m.GetDashboardQuery{ + Uid: savedDash.Uid, + OrgId: 1, + } + + err := GetDashboard(&query) + So(err, ShouldBeNil) + + So(query.Result.Title, ShouldEqual, "test dash 23") + So(query.Result.Slug, ShouldEqual, "test-dash-23") + So(query.Result.Id, ShouldEqual, savedDash.Id) + So(query.Result.Uid, ShouldEqual, savedDash.Uid) + So(query.Result.IsFolder, ShouldBeFalse) }) Convey("Should be able to delete dashboard", func() { - insertTestDashboard("delete me", 1, "delete this") - - dashboardSlug := slug.Make("delete me") + dash := insertTestDashboard("delete me", 1, 0, false, "delete this") err := DeleteDashboard(&m.DeleteDashboardCommand{ - Slug: dashboardSlug, + Id: dash.Id, OrgId: 1, }) So(err, ShouldBeNil) }) - Convey("Should return error if no dashboard is updated", func() { + Convey("Should retry generation of uid once if it fails.", func() { + timesCalled := 0 + generateNewUid = func() string { + timesCalled += 1 + if timesCalled <= 2 { + return savedDash.Uid + } else { + return util.GenerateShortUid() + } + } + cmd := m.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "new dash 12334", + "tags": []interface{}{}, + }), + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + + generateNewUid = util.GenerateShortUid + }) + + Convey("Should be able to create dashboard", func() { + cmd := m.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "title": "folderId", + "tags": []interface{}{}, + }), + UserId: 100, + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + So(cmd.Result.CreatedBy, ShouldEqual, 100) + So(cmd.Result.Created.IsZero(), ShouldBeFalse) + So(cmd.Result.UpdatedBy, ShouldEqual, 100) + So(cmd.Result.Updated.IsZero(), ShouldBeFalse) + }) + + Convey("Should be able to update dashboard by id and remove folderId", func() { + cmd := m.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDash.Id, + "title": "folderId", + "tags": []interface{}{}, + }), + Overwrite: true, + FolderId: 2, + UserId: 100, + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + So(cmd.Result.FolderId, ShouldEqual, 2) + + cmd = m.SaveDashboardCommand{ + OrgId: 1, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": savedDash.Id, + "title": "folderId", + "tags": []interface{}{}, + }), + FolderId: 0, + Overwrite: true, + UserId: 100, + } + + err = SaveDashboard(&cmd) + So(err, ShouldBeNil) + + query := m.GetDashboardQuery{ + Id: savedDash.Id, + OrgId: 1, + } + + err = GetDashboard(&query) + So(err, ShouldBeNil) + So(query.Result.FolderId, ShouldEqual, 0) + So(query.Result.CreatedBy, ShouldEqual, savedDash.CreatedBy) + So(query.Result.Created, ShouldEqual, savedDash.Created.Truncate(time.Second)) + So(query.Result.UpdatedBy, ShouldEqual, 100) + So(query.Result.Updated.IsZero(), ShouldBeFalse) + }) + + Convey("Should be able to delete a dashboard folder and its children", func() { + deleteCmd := &m.DeleteDashboardCommand{Id: savedFolder.Id} + err := DeleteDashboard(deleteCmd) + So(err, ShouldBeNil) + + query := search.FindPersistedDashboardsQuery{ + OrgId: 1, + FolderIds: []int64{savedFolder.Id}, + SignedInUser: &m.SignedInUser{}, + } + + err = SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 0) + }) + + Convey("Should return error if no dashboard is found for update when dashboard id is greater than zero", func() { cmd := m.SaveDashboardCommand{ OrgId: 1, Overwrite: true, @@ -81,31 +218,38 @@ func TestDashboardDataAccess(t *testing.T) { } err := SaveDashboard(&cmd) - So(err, ShouldNotBeNil) + So(err, ShouldEqual, m.ErrDashboardNotFound) }) - Convey("Should not be able to overwrite dashboard in another org", func() { - query := m.GetDashboardQuery{Slug: "test-dash-23", OrgId: 1} - GetDashboard(&query) - + Convey("Should not return error if no dashboard is found for update when dashboard id is zero", func() { cmd := m.SaveDashboardCommand{ - OrgId: 2, + OrgId: 1, Overwrite: true, Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": float64(query.Result.Id), - "title": "Expect error", + "id": 0, + "title": "New dash", "tags": []interface{}{}, }), } err := SaveDashboard(&cmd) - So(err, ShouldNotBeNil) + So(err, ShouldBeNil) }) - Convey("Should be able to search for dashboard", func() { + Convey("Should be able to get dashboard tags", func() { + query := m.GetDashboardTagsQuery{OrgId: 1} + + err := GetDashboardTags(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + }) + + Convey("Should be able to search for dashboard folder", func() { query := search.FindPersistedDashboardsQuery{ - Title: "test dash 23", - OrgId: 1, + Title: "1 test dash folder", + OrgId: 1, + SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR}, } err := SearchDashboards(&query) @@ -113,14 +257,36 @@ func TestDashboardDataAccess(t *testing.T) { So(len(query.Result), ShouldEqual, 1) hit := query.Result[0] - So(len(hit.Tags), ShouldEqual, 2) + So(hit.Type, ShouldEqual, search.DashHitFolder) + So(hit.Url, ShouldEqual, fmt.Sprintf("/dashboards/f/%s/%s", savedFolder.Uid, savedFolder.Slug)) + So(hit.FolderTitle, ShouldEqual, "") + }) + + Convey("Should be able to search for a dashboard folder's children", func() { + query := search.FindPersistedDashboardsQuery{ + OrgId: 1, + FolderIds: []int64{savedFolder.Id}, + SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR}, + } + + err := SearchDashboards(&query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 2) + hit := query.Result[0] + So(hit.Id, ShouldEqual, savedDash.Id) + So(hit.Url, ShouldEqual, fmt.Sprintf("/d/%s/%s", savedDash.Uid, savedDash.Slug)) + So(hit.FolderId, ShouldEqual, savedFolder.Id) + So(hit.FolderUid, ShouldEqual, savedFolder.Uid) + So(hit.FolderTitle, ShouldEqual, savedFolder.Title) + So(hit.FolderUrl, ShouldEqual, fmt.Sprintf("/dashboards/f/%s/%s", savedFolder.Uid, savedFolder.Slug)) }) Convey("Should be able to search for dashboard by dashboard ids", func() { Convey("should be able to find two dashboards by id", func() { query := search.FindPersistedDashboardsQuery{ - DashboardIds: []int{1, 2}, - OrgId: 1, + DashboardIds: []int64{2, 3}, + SignedInUser: &m.SignedInUser{OrgId: 1, OrgRole: m.ROLE_EDITOR}, } err := SearchDashboards(&query) @@ -134,44 +300,10 @@ func TestDashboardDataAccess(t *testing.T) { hit2 := query.Result[1] So(len(hit2.Tags), ShouldEqual, 1) }) - - Convey("DashboardIds that does not exists should not cause errors", func() { - query := search.FindPersistedDashboardsQuery{ - DashboardIds: []int{1000}, - OrgId: 1, - } - - err := SearchDashboards(&query) - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 0) - }) - }) - - Convey("Should not be able to save dashboard with same name", func() { - cmd := m.SaveDashboardCommand{ - OrgId: 1, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": "test dash 23", - "tags": []interface{}{}, - }), - } - - err := SaveDashboard(&cmd) - So(err, ShouldNotBeNil) - }) - - Convey("Should be able to get dashboard tags", func() { - query := m.GetDashboardTagsQuery{OrgId: 1} - - err := GetDashboardTags(&query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 2) }) Convey("Given two dashboards, one is starred dashboard by user 10, other starred by user 1", func() { - starredDash := insertTestDashboard("starred dash", 1) + starredDash := insertTestDashboard("starred dash", 1, 0, false) StarDashboard(&m.StarDashboardCommand{ DashboardId: starredDash.Id, UserId: 10, @@ -183,7 +315,10 @@ func TestDashboardDataAccess(t *testing.T) { }) Convey("Should be able to search for starred dashboards", func() { - query := search.FindPersistedDashboardsQuery{OrgId: 1, UserId: 10, IsStarred: true} + query := search.FindPersistedDashboardsQuery{ + SignedInUser: &m.SignedInUser{UserId: 10, OrgId: 1, OrgRole: m.ROLE_EDITOR}, + IsStarred: true, + } err := SearchDashboards(&query) So(err, ShouldBeNil) @@ -192,5 +327,92 @@ func TestDashboardDataAccess(t *testing.T) { }) }) }) + + Convey("Given a plugin with imported dashboards", func() { + pluginId := "test-app" + + appFolder := insertTestDashboardForPlugin("app-test", 1, 0, true, pluginId) + insertTestDashboardForPlugin("app-dash1", 1, appFolder.Id, false, pluginId) + insertTestDashboardForPlugin("app-dash2", 1, appFolder.Id, false, pluginId) + + Convey("Should return imported dashboard", func() { + query := m.GetDashboardsByPluginIdQuery{ + PluginId: pluginId, + OrgId: 1, + } + + err := GetDashboardsByPluginId(&query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 2) + }) + }) }) } + +func insertTestDashboard(title string, orgId int64, folderId int64, isFolder bool, tags ...interface{}) *m.Dashboard { + cmd := m.SaveDashboardCommand{ + OrgId: orgId, + FolderId: folderId, + IsFolder: isFolder, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + "tags": tags, + }), + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + + cmd.Result.Data.Set("id", cmd.Result.Id) + cmd.Result.Data.Set("uid", cmd.Result.Uid) + + return cmd.Result +} + +func insertTestDashboardForPlugin(title string, orgId int64, folderId int64, isFolder bool, pluginId string) *m.Dashboard { + cmd := m.SaveDashboardCommand{ + OrgId: orgId, + FolderId: folderId, + IsFolder: isFolder, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + }), + PluginId: pluginId, + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + + return cmd.Result +} + +func createUser(name string, role string, isAdmin bool) m.User { + setting.AutoAssignOrg = true + setting.AutoAssignOrgRole = role + + currentUserCmd := m.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin} + err := CreateUser(¤tUserCmd) + So(err, ShouldBeNil) + + q1 := m.GetUserOrgListQuery{UserId: currentUserCmd.Result.Id} + GetUserOrgList(&q1) + So(q1.Result[0].Role, ShouldEqual, role) + + return currentUserCmd.Result +} + +func moveDashboard(orgId int64, dashboard *simplejson.Json, newFolderId int64) *m.Dashboard { + cmd := m.SaveDashboardCommand{ + OrgId: orgId, + FolderId: newFolderId, + Dashboard: dashboard, + Overwrite: true, + } + + err := SaveDashboard(&cmd) + So(err, ShouldBeNil) + + return cmd.Result +} diff --git a/pkg/services/sqlstore/dashboard_version.go b/pkg/services/sqlstore/dashboard_version.go index 484a7e281dc..547f62628f3 100644 --- a/pkg/services/sqlstore/dashboard_version.go +++ b/pkg/services/sqlstore/dashboard_version.go @@ -36,6 +36,10 @@ func GetDashboardVersion(query *m.GetDashboardVersionQuery) error { // GetDashboardVersions gets all dashboard versions for the given dashboard ID. func GetDashboardVersions(query *m.GetDashboardVersionsQuery) error { + if query.Limit == 0 { + query.Limit = 1000 + } + err := x.Table("dashboard_version"). Select(`dashboard_version.id, dashboard_version.dashboard_id, @@ -65,7 +69,6 @@ func GetDashboardVersions(query *m.GetDashboardVersionsQuery) error { func DeleteExpiredVersions(cmd *m.DeleteExpiredVersionsCommand) error { return inTransaction(func(sess *DBSession) error { - expiredCount := int64(0) versions := []DashboardVersionExp{} versionsToKeep := setting.DashboardVersionsToKeep @@ -94,8 +97,7 @@ func DeleteExpiredVersions(cmd *m.DeleteExpiredVersionsCommand) error { if err != nil { return err } - expiredCount, _ = expiredResponse.RowsAffected() - sqlog.Debug("Deleted old/expired dashboard versions", "expired", expiredCount) + cmd.DeletedRows, _ = expiredResponse.RowsAffected() } return nil diff --git a/pkg/services/sqlstore/dashboard_version_test.go b/pkg/services/sqlstore/dashboard_version_test.go index a27d4385637..1b74e7847c4 100644 --- a/pkg/services/sqlstore/dashboard_version_test.go +++ b/pkg/services/sqlstore/dashboard_version_test.go @@ -12,7 +12,7 @@ import ( ) func updateTestDashboard(dashboard *m.Dashboard, data map[string]interface{}) { - data["title"] = dashboard.Title + data["id"] = dashboard.Id saveCmd := m.SaveDashboardCommand{ OrgId: dashboard.OrgId, @@ -29,7 +29,7 @@ func TestGetDashboardVersion(t *testing.T) { InitTestDB(t) Convey("Get a Dashboard ID and version ID", func() { - savedDash := insertTestDashboard("test dash 26", 1, "diff") + savedDash := insertTestDashboard("test dash 26", 1, 0, false, "diff") query := m.GetDashboardVersionQuery{ DashboardId: savedDash.Id, @@ -44,7 +44,7 @@ func TestGetDashboardVersion(t *testing.T) { dashCmd := m.GetDashboardQuery{ OrgId: savedDash.OrgId, - Slug: savedDash.Slug, + Uid: savedDash.Uid, } err = GetDashboard(&dashCmd) @@ -70,7 +70,7 @@ func TestGetDashboardVersion(t *testing.T) { func TestGetDashboardVersions(t *testing.T) { Convey("Testing dashboard versions retrieval", t, func() { InitTestDB(t) - savedDash := insertTestDashboard("test dash 43", 1, "diff-all") + savedDash := insertTestDashboard("test dash 43", 1, 0, false, "diff-all") Convey("Get all versions for a given Dashboard ID", func() { query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} @@ -110,7 +110,7 @@ func TestDeleteExpiredVersions(t *testing.T) { versionsToWrite := 10 setting.DashboardVersionsToKeep = versionsToKeep - savedDash := insertTestDashboard("test dash 53", 1, "diff-all") + savedDash := insertTestDashboard("test dash 53", 1, 0, false, "diff-all") for i := 0; i < versionsToWrite-1; i++ { updateTestDashboard(savedDash, map[string]interface{}{ "tags": "different-tag", diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index e9b400a1772..00d520bcfc6 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -27,6 +27,9 @@ func GetDataSourceById(query *m.GetDataSourceByIdQuery) error { datasource := m.DataSource{OrgId: query.OrgId, Id: query.Id} has, err := x.Get(&datasource) + if err != nil { + return err + } if !has { return m.ErrDataSourceNotFound diff --git a/pkg/services/sqlstore/datasource_test.go b/pkg/services/sqlstore/datasource_test.go index 135867cf0f5..90300e20029 100644 --- a/pkg/services/sqlstore/datasource_test.go +++ b/pkg/services/sqlstore/datasource_test.go @@ -3,32 +3,11 @@ package sqlstore import ( "testing" - "github.com/go-xorm/xorm" - . "github.com/smartystreets/goconvey/convey" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" ) -func InitTestDB(t *testing.T) { - x, err := xorm.NewEngine(sqlutil.TestDB_Sqlite3.DriverName, sqlutil.TestDB_Sqlite3.ConnStr) - //x, err := xorm.NewEngine(sqlutil.TestDB_Mysql.DriverName, sqlutil.TestDB_Mysql.ConnStr) - //x, err := xorm.NewEngine(sqlutil.TestDB_Postgres.DriverName, sqlutil.TestDB_Postgres.ConnStr) - - // x.ShowSQL() - - if err != nil { - t.Fatalf("Failed to init in memory sqllite3 db %v", err) - } - - sqlutil.CleanDB(x) - - if err := SetEngine(x); err != nil { - t.Fatal(err) - } -} - type Test struct { Id int64 Name string diff --git a/pkg/services/sqlstore/login_attempt.go b/pkg/services/sqlstore/login_attempt.go new file mode 100644 index 00000000000..78da198e8e7 --- /dev/null +++ b/pkg/services/sqlstore/login_attempt.go @@ -0,0 +1,91 @@ +package sqlstore + +import ( + "strconv" + "time" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +var getTimeNow = time.Now + +func init() { + bus.AddHandler("sql", CreateLoginAttempt) + bus.AddHandler("sql", DeleteOldLoginAttempts) + bus.AddHandler("sql", GetUserLoginAttemptCount) +} + +func CreateLoginAttempt(cmd *m.CreateLoginAttemptCommand) error { + return inTransaction(func(sess *DBSession) error { + loginAttempt := m.LoginAttempt{ + Username: cmd.Username, + IpAddress: cmd.IpAddress, + Created: getTimeNow().Unix(), + } + + if _, err := sess.Insert(&loginAttempt); err != nil { + return err + } + + cmd.Result = loginAttempt + + return nil + }) +} + +func DeleteOldLoginAttempts(cmd *m.DeleteOldLoginAttemptsCommand) error { + return inTransaction(func(sess *DBSession) error { + var maxId int64 + sql := "SELECT max(id) as id FROM login_attempt WHERE created < ?" + result, err := sess.Query(sql, cmd.OlderThan.Unix()) + + if err != nil { + return err + } + + maxId = toInt64(result[0]["id"]) + + if maxId == 0 { + return nil + } + + sql = "DELETE FROM login_attempt WHERE id <= ?" + + if result, err := sess.Exec(sql, maxId); err != nil { + return err + } else if cmd.DeletedRows, err = result.RowsAffected(); err != nil { + return err + } + + return nil + }) +} + +func GetUserLoginAttemptCount(query *m.GetUserLoginAttemptCountQuery) error { + loginAttempt := new(m.LoginAttempt) + total, err := x. + Where("username = ?", query.Username). + And("created >= ?", query.Since.Unix()). + Count(loginAttempt) + + if err != nil { + return err + } + + query.Result = total + return nil +} + +func toInt64(i interface{}) int64 { + switch i.(type) { + case []byte: + n, _ := strconv.ParseInt(string(i.([]byte)), 10, 64) + return n + case int: + return int64(i.(int)) + case int64: + return i.(int64) + } + return 0 +} diff --git a/pkg/services/sqlstore/login_attempt_test.go b/pkg/services/sqlstore/login_attempt_test.go new file mode 100644 index 00000000000..8008e2d8a62 --- /dev/null +++ b/pkg/services/sqlstore/login_attempt_test.go @@ -0,0 +1,125 @@ +package sqlstore + +import ( + "testing" + "time" + + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func mockTime(mock time.Time) time.Time { + getTimeNow = func() time.Time { return mock } + return mock +} + +func TestLoginAttempts(t *testing.T) { + Convey("Testing Login Attempts DB Access", t, func() { + InitTestDB(t) + + user := "user" + beginningOfTime := mockTime(time.Date(2017, 10, 22, 8, 0, 0, 0, time.Local)) + + err := CreateLoginAttempt(&m.CreateLoginAttemptCommand{ + Username: user, + IpAddress: "192.168.0.1", + }) + So(err, ShouldBeNil) + + timePlusOneMinute := mockTime(beginningOfTime.Add(time.Minute * 1)) + + err = CreateLoginAttempt(&m.CreateLoginAttemptCommand{ + Username: user, + IpAddress: "192.168.0.1", + }) + So(err, ShouldBeNil) + + timePlusTwoMinutes := mockTime(beginningOfTime.Add(time.Minute * 2)) + + err = CreateLoginAttempt(&m.CreateLoginAttemptCommand{ + Username: user, + IpAddress: "192.168.0.1", + }) + So(err, ShouldBeNil) + + Convey("Should return a total count of zero login attempts when comparing since beginning of time + 2min and 1s", func() { + query := m.GetUserLoginAttemptCountQuery{ + Username: user, + Since: timePlusTwoMinutes.Add(time.Second * 1), + } + err := GetUserLoginAttemptCount(&query) + So(err, ShouldBeNil) + So(query.Result, ShouldEqual, 0) + }) + + Convey("Should return the total count of login attempts since beginning of time", func() { + query := m.GetUserLoginAttemptCountQuery{ + Username: user, + Since: beginningOfTime, + } + err := GetUserLoginAttemptCount(&query) + So(err, ShouldBeNil) + So(query.Result, ShouldEqual, 3) + }) + + Convey("Should return the total count of login attempts since beginning of time + 1min", func() { + query := m.GetUserLoginAttemptCountQuery{ + Username: user, + Since: timePlusOneMinute, + } + err := GetUserLoginAttemptCount(&query) + So(err, ShouldBeNil) + So(query.Result, ShouldEqual, 2) + }) + + Convey("Should return the total count of login attempts since beginning of time + 2min", func() { + query := m.GetUserLoginAttemptCountQuery{ + Username: user, + Since: timePlusTwoMinutes, + } + err := GetUserLoginAttemptCount(&query) + So(err, ShouldBeNil) + So(query.Result, ShouldEqual, 1) + }) + + Convey("Should return deleted rows older than beginning of time", func() { + cmd := m.DeleteOldLoginAttemptsCommand{ + OlderThan: beginningOfTime, + } + err := DeleteOldLoginAttempts(&cmd) + + So(err, ShouldBeNil) + So(cmd.DeletedRows, ShouldEqual, 0) + }) + + Convey("Should return deleted rows older than beginning of time + 1min", func() { + cmd := m.DeleteOldLoginAttemptsCommand{ + OlderThan: timePlusOneMinute, + } + err := DeleteOldLoginAttempts(&cmd) + + So(err, ShouldBeNil) + So(cmd.DeletedRows, ShouldEqual, 1) + }) + + Convey("Should return deleted rows older than beginning of time + 2min", func() { + cmd := m.DeleteOldLoginAttemptsCommand{ + OlderThan: timePlusTwoMinutes, + } + err := DeleteOldLoginAttempts(&cmd) + + So(err, ShouldBeNil) + So(cmd.DeletedRows, ShouldEqual, 2) + }) + + Convey("Should return deleted rows older than beginning of time + 2min and 1s", func() { + cmd := m.DeleteOldLoginAttemptsCommand{ + OlderThan: timePlusTwoMinutes.Add(time.Second * 1), + } + err := DeleteOldLoginAttempts(&cmd) + + So(err, ShouldBeNil) + So(cmd.DeletedRows, ShouldEqual, 3) + }) + }) +} diff --git a/pkg/services/sqlstore/migrations/common.go b/pkg/services/sqlstore/migrations/common.go index cf0b39f1a35..cc31b1d4580 100644 --- a/pkg/services/sqlstore/migrations/common.go +++ b/pkg/services/sqlstore/migrations/common.go @@ -24,3 +24,24 @@ func addTableRenameMigration(mg *Migrator, oldName string, newName string, versi migrationId := fmt.Sprintf("Rename table %s to %s - %s", oldName, newName, versionSuffix) mg.AddMigration(migrationId, NewRenameTableMigration(oldName, newName)) } + +func addTableReplaceMigrations(mg *Migrator, from Table, to Table, migrationVersion int64, tableDataMigration map[string]string) { + fromV := version(migrationVersion - 1) + toV := version(migrationVersion) + tmpTableName := to.Name + "_tmp_qwerty" + + createTable := fmt.Sprintf("create %v %v", to.Name, toV) + copyTableData := fmt.Sprintf("copy %v %v to %v", to.Name, fromV, toV) + dropTable := fmt.Sprintf("drop %v", tmpTableName) + + addDropAllIndicesMigrations(mg, fromV, from) + addTableRenameMigration(mg, from.Name, tmpTableName, fromV) + mg.AddMigration(createTable, NewAddTableMigration(to)) + addTableIndicesMigrations(mg, toV, to) + mg.AddMigration(copyTableData, NewCopyTableDataMigration(to.Name, tmpTableName, tableDataMigration)) + mg.AddMigration(dropTable, NewDropTableMigration(tmpTableName)) +} + +func version(v int64) string { + return fmt.Sprintf("v%v", v) +} diff --git a/pkg/services/sqlstore/migrations/dashboard_acl.go b/pkg/services/sqlstore/migrations/dashboard_acl.go new file mode 100644 index 00000000000..cc3b813c12f --- /dev/null +++ b/pkg/services/sqlstore/migrations/dashboard_acl.go @@ -0,0 +1,52 @@ +package migrations + +import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + +func addDashboardAclMigrations(mg *Migrator) { + dashboardAclV1 := Table{ + Name: "dashboard_acl", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "org_id", Type: DB_BigInt}, + {Name: "dashboard_id", Type: DB_BigInt}, + {Name: "user_id", Type: DB_BigInt, Nullable: true}, + {Name: "team_id", Type: DB_BigInt, Nullable: true}, + {Name: "permission", Type: DB_SmallInt, Default: "4"}, + {Name: "role", Type: DB_Varchar, Length: 20, Nullable: true}, + {Name: "created", Type: DB_DateTime, Nullable: false}, + {Name: "updated", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"dashboard_id"}}, + {Cols: []string{"dashboard_id", "user_id"}, Type: UniqueIndex}, + {Cols: []string{"dashboard_id", "team_id"}, Type: UniqueIndex}, + }, + } + + mg.AddMigration("create dashboard acl table", NewAddTableMigration(dashboardAclV1)) + + //------- indexes ------------------ + mg.AddMigration("add index dashboard_acl_dashboard_id", NewAddIndexMigration(dashboardAclV1, dashboardAclV1.Indices[0])) + mg.AddMigration("add unique index dashboard_acl_dashboard_id_user_id", NewAddIndexMigration(dashboardAclV1, dashboardAclV1.Indices[1])) + mg.AddMigration("add unique index dashboard_acl_dashboard_id_team_id", NewAddIndexMigration(dashboardAclV1, dashboardAclV1.Indices[2])) + + const rawSQL = ` +INSERT INTO dashboard_acl + ( + org_id, + dashboard_id, + permission, + role, + created, + updated + ) + VALUES + (-1,-1, 1,'Viewer','2017-06-20','2017-06-20'), + (-1,-1, 2,'Editor','2017-06-20','2017-06-20') + ` + + mg.AddMigration("save default acl rules in dashboard_acl table", new(RawSqlMigration). + Sqlite(rawSQL). + Postgres(rawSQL). + Mysql(rawSQL)) +} diff --git a/pkg/services/sqlstore/migrations/dashboard_mig.go b/pkg/services/sqlstore/migrations/dashboard_mig.go index ee0cc1d893f..296950ee497 100644 --- a/pkg/services/sqlstore/migrations/dashboard_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_mig.go @@ -1,6 +1,8 @@ package migrations -import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +import ( + . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +) func addDashboardMigration(mg *Migrator) { var dashboardV1 = Table{ @@ -136,4 +138,79 @@ func addDashboardMigration(mg *Migrator) { mg.AddMigration("Update dashboard_tag table charset", NewTableCharsetMigration("dashboard_tag", []*Column{ {Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false}, })) + + // add column to store folder_id for dashboard folder structure + mg.AddMigration("Add column folder_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{ + Name: "folder_id", Type: DB_BigInt, Nullable: false, Default: "0", + })) + + mg.AddMigration("Add column isFolder in dashboard", NewAddColumnMigration(dashboardV2, &Column{ + Name: "is_folder", Type: DB_Bool, Nullable: false, Default: "0", + })) + + // add column to flag if dashboard has an ACL + mg.AddMigration("Add column has_acl in dashboard", NewAddColumnMigration(dashboardV2, &Column{ + Name: "has_acl", Type: DB_Bool, Nullable: false, Default: "0", + })) + + mg.AddMigration("Add column uid in dashboard", NewAddColumnMigration(dashboardV2, &Column{ + Name: "uid", Type: DB_NVarchar, Length: 40, Nullable: true, + })) + + mg.AddMigration("Update uid column values in dashboard", new(RawSqlMigration). + Sqlite("UPDATE dashboard SET uid=printf('%09d',id) WHERE uid IS NULL;"). + Postgres("UPDATE dashboard SET uid=lpad('' || id,9,'0') WHERE uid IS NULL;"). + Mysql("UPDATE dashboard SET uid=lpad(id,9,'0') WHERE uid IS NULL;")) + + mg.AddMigration("Add unique index dashboard_org_id_uid", NewAddIndexMigration(dashboardV2, &Index{ + Cols: []string{"org_id", "uid"}, Type: UniqueIndex, + })) + + mg.AddMigration("Remove unique index org_id_slug", NewDropIndexMigration(dashboardV2, &Index{ + Cols: []string{"org_id", "slug"}, Type: UniqueIndex, + })) + + mg.AddMigration("Update dashboard title length", NewTableCharsetMigration("dashboard", []*Column{ + {Name: "title", Type: DB_NVarchar, Length: 189, Nullable: false}, + })) + + mg.AddMigration("Add unique index for dashboard_org_id_title_folder_id", NewAddIndexMigration(dashboardV2, &Index{ + Cols: []string{"org_id", "folder_id", "title"}, Type: UniqueIndex, + })) + + dashboardExtrasTable := Table{ + Name: "dashboard_provisioning", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "dashboard_id", Type: DB_BigInt, Nullable: true}, + {Name: "name", Type: DB_NVarchar, Length: 150, Nullable: false}, + {Name: "external_id", Type: DB_Text, Nullable: false}, + {Name: "updated", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{}, + } + + mg.AddMigration("create dashboard_provisioning", NewAddTableMigration(dashboardExtrasTable)) + + dashboardExtrasTableV2 := Table{ + Name: "dashboard_provisioning", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "dashboard_id", Type: DB_BigInt, Nullable: true}, + {Name: "name", Type: DB_NVarchar, Length: 150, Nullable: false}, + {Name: "external_id", Type: DB_Text, Nullable: false}, + {Name: "updated", Type: DB_Int, Default: "0", Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"dashboard_id"}}, + {Cols: []string{"dashboard_id", "name"}, Type: IndexType}, + }, + } + + addTableReplaceMigrations(mg, dashboardExtrasTable, dashboardExtrasTableV2, 2, map[string]string{ + "id": "id", + "dashboard_id": "dashboard_id", + "name": "name", + "external_id": "external_id", + }) } diff --git a/pkg/services/sqlstore/migrations/login_attempt_mig.go b/pkg/services/sqlstore/migrations/login_attempt_mig.go new file mode 100644 index 00000000000..df14eb4effa --- /dev/null +++ b/pkg/services/sqlstore/migrations/login_attempt_mig.go @@ -0,0 +1,42 @@ +package migrations + +import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + +func addLoginAttemptMigrations(mg *Migrator) { + loginAttemptV1 := Table{ + Name: "login_attempt", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "username", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "ip_address", Type: DB_NVarchar, Length: 30, Nullable: false}, + {Name: "created", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"username"}}, + }, + } + + // create table + mg.AddMigration("create login attempt table", NewAddTableMigration(loginAttemptV1)) + // add indices + mg.AddMigration("add index login_attempt.username", NewAddIndexMigration(loginAttemptV1, loginAttemptV1.Indices[0])) + + loginAttemptV2 := Table{ + Name: "login_attempt", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "username", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "ip_address", Type: DB_NVarchar, Length: 30, Nullable: false}, + {Name: "created", Type: DB_Int, Default: "0", Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"username"}}, + }, + } + + addTableReplaceMigrations(mg, loginAttemptV1, loginAttemptV2, 2, map[string]string{ + "id": "id", + "username": "username", + "ip_address": "ip_address", + }) +} diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index 4984ff18592..282f98e7318 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -26,7 +26,10 @@ func AddMigrations(mg *Migrator) { addAnnotationMig(mg) addTestDataMigrations(mg) addDashboardVersionMigration(mg) + addTeamMigrations(mg) + addDashboardAclMigrations(mg) addTagMigration(mg) + addLoginAttemptMigrations(mg) } func addMigrationLogMigrations(mg *Migrator) { diff --git a/pkg/services/sqlstore/migrations/migrations_test.go b/pkg/services/sqlstore/migrations/migrations_test.go index 5bddf6ff605..51aea0bbdef 100644 --- a/pkg/services/sqlstore/migrations/migrations_test.go +++ b/pkg/services/sqlstore/migrations/migrations_test.go @@ -14,13 +14,15 @@ import ( var indexTypes = []string{"Unknown", "INDEX", "UNIQUE INDEX"} func TestMigrations(t *testing.T) { - //log.NewLogger(0, "console", `{"level": 0}`) - testDBs := []sqlutil.TestDB{ sqlutil.TestDB_Sqlite3, } for _, testDB := range testDBs { + sql := `select count(*) as count from migration_log` + r := struct { + Count int64 + }{} Convey("Initial "+testDB.DriverName+" migration", t, func() { x, err := xorm.NewEngine(testDB.DriverName, testDB.ConnStr) @@ -28,30 +30,31 @@ func TestMigrations(t *testing.T) { sqlutil.CleanDB(x) + has, err := x.SQL(sql).Get(&r) + So(err, ShouldNotBeNil) + mg := NewMigrator(x) AddMigrations(mg) err = mg.Start() So(err, ShouldBeNil) - // tables, err := x.DBMetas() - // So(err, ShouldBeNil) - // - // fmt.Printf("\nDB Schema after migration: table count: %v\n", len(tables)) - // - // for _, table := range tables { - // fmt.Printf("\nTable: %v \n", table.Name) - // for _, column := range table.Columns() { - // fmt.Printf("\t %v \n", column.String(x.Dialect())) - // } - // - // if len(table.Indexes) > 0 { - // fmt.Printf("\n\tIndexes:\n") - // for _, index := range table.Indexes { - // fmt.Printf("\t %v (%v) %v \n", index.Name, strings.Join(index.Cols, ","), indexTypes[index.Type]) - // } - // } - // } + has, err = x.SQL(sql).Get(&r) + So(err, ShouldBeNil) + So(has, ShouldBeTrue) + expectedMigrations := mg.MigrationsCount() - 2 //we currently skip to migrations. We should rewrite skipped migrations to write in the log as well. until then we have to keep this + So(r.Count, ShouldEqual, expectedMigrations) + + mg = NewMigrator(x) + AddMigrations(mg) + + err = mg.Start() + So(err, ShouldBeNil) + + has, err = x.SQL(sql).Get(&r) + So(err, ShouldBeNil) + So(has, ShouldBeTrue) + So(r.Count, ShouldEqual, expectedMigrations) }) } } diff --git a/pkg/services/sqlstore/migrations/org_mig.go b/pkg/services/sqlstore/migrations/org_mig.go index 12e0a04256a..cf9b19f6f5b 100644 --- a/pkg/services/sqlstore/migrations/org_mig.go +++ b/pkg/services/sqlstore/migrations/org_mig.go @@ -83,4 +83,10 @@ func addOrgMigrations(mg *Migrator) { mg.AddMigration("Update org_user table charset", NewTableCharsetMigration("org_user", []*Column{ {Name: "role", Type: DB_NVarchar, Length: 20}, })) + + const migrateReadOnlyViewersToViewers = `UPDATE org_user SET role = 'Viewer' WHERE role = 'Read Only Editor'` + mg.AddMigration("Migrate all Read Only Viewers to Viewers", new(RawSqlMigration). + Sqlite(migrateReadOnlyViewersToViewers). + Postgres(migrateReadOnlyViewersToViewers). + Mysql(migrateReadOnlyViewersToViewers)) } diff --git a/pkg/services/sqlstore/migrations/team_mig.go b/pkg/services/sqlstore/migrations/team_mig.go new file mode 100644 index 00000000000..eb0641fbc32 --- /dev/null +++ b/pkg/services/sqlstore/migrations/team_mig.go @@ -0,0 +1,53 @@ +package migrations + +import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + +func addTeamMigrations(mg *Migrator) { + teamV1 := Table{ + Name: "team", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "org_id", Type: DB_BigInt}, + {Name: "created", Type: DB_DateTime, Nullable: false}, + {Name: "updated", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"org_id"}}, + {Cols: []string{"org_id", "name"}, Type: UniqueIndex}, + }, + } + + mg.AddMigration("create team table", NewAddTableMigration(teamV1)) + + //------- indexes ------------------ + mg.AddMigration("add index team.org_id", NewAddIndexMigration(teamV1, teamV1.Indices[0])) + mg.AddMigration("add unique index team_org_id_name", NewAddIndexMigration(teamV1, teamV1.Indices[1])) + + teamMemberV1 := Table{ + Name: "team_member", + Columns: []*Column{ + {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "org_id", Type: DB_BigInt}, + {Name: "team_id", Type: DB_BigInt}, + {Name: "user_id", Type: DB_BigInt}, + {Name: "created", Type: DB_DateTime, Nullable: false}, + {Name: "updated", Type: DB_DateTime, Nullable: false}, + }, + Indices: []*Index{ + {Cols: []string{"org_id"}}, + {Cols: []string{"org_id", "team_id", "user_id"}, Type: UniqueIndex}, + }, + } + + mg.AddMigration("create team member table", NewAddTableMigration(teamMemberV1)) + + //------- indexes ------------------ + mg.AddMigration("add index team_member.org_id", NewAddIndexMigration(teamMemberV1, teamMemberV1.Indices[0])) + mg.AddMigration("add unique index team_member_org_id_team_id_user_id", NewAddIndexMigration(teamMemberV1, teamMemberV1.Indices[1])) + + // add column email + mg.AddMigration("Add column email to team table", NewAddColumnMigration(teamV1, &Column{ + Name: "email", Type: DB_NVarchar, Nullable: true, Length: 190, + })) +} diff --git a/pkg/services/sqlstore/migrator/dialect.go b/pkg/services/sqlstore/migrator/dialect.go index 651405921d9..064b5981063 100644 --- a/pkg/services/sqlstore/migrator/dialect.go +++ b/pkg/services/sqlstore/migrator/dialect.go @@ -19,6 +19,7 @@ type Dialect interface { LikeStr() string Default(col *Column) string BooleanStr(bool) string + DateTimeFunc(string) string CreateIndexSql(tableName string, index *Index) string CreateTableSql(table *Table) string @@ -78,6 +79,10 @@ func (b *BaseDialect) Default(col *Column) string { return col.Default } +func (db *BaseDialect) DateTimeFunc(value string) string { + return value +} + func (b *BaseDialect) CreateTableSql(table *Table) string { var sql string sql = "CREATE TABLE IF NOT EXISTS " diff --git a/pkg/services/sqlstore/migrator/migrator.go b/pkg/services/sqlstore/migrator/migrator.go index 64831ee46b4..a8bd36ac8a3 100644 --- a/pkg/services/sqlstore/migrator/migrator.go +++ b/pkg/services/sqlstore/migrator/migrator.go @@ -35,6 +35,10 @@ func NewMigrator(engine *xorm.Engine) *Migrator { return mg } +func (mg *Migrator) MigrationsCount() int { + return len(mg.migrations) +} + func (mg *Migrator) AddMigration(id string, m Migration) { m.SetId(id) mg.migrations = append(mg.migrations, m) diff --git a/pkg/services/sqlstore/migrator/sqlite_dialect.go b/pkg/services/sqlstore/migrator/sqlite_dialect.go index fe1e781c8df..1a31cee4f5e 100644 --- a/pkg/services/sqlstore/migrator/sqlite_dialect.go +++ b/pkg/services/sqlstore/migrator/sqlite_dialect.go @@ -36,6 +36,10 @@ func (db *Sqlite3) BooleanStr(value bool) string { return "0" } +func (db *Sqlite3) DateTimeFunc(value string) string { + return "datetime(" + value + ")" +} + func (db *Sqlite3) SqlType(c *Column) string { switch c.Type { case DB_Date, DB_DateTime, DB_TimeStamp, DB_Time: diff --git a/pkg/services/sqlstore/org_test.go b/pkg/services/sqlstore/org_test.go index e7c718fc9a8..c57d15a48d5 100644 --- a/pkg/services/sqlstore/org_test.go +++ b/pkg/services/sqlstore/org_test.go @@ -123,6 +123,31 @@ func TestAccountDataAccess(t *testing.T) { So(query.Result[0].Role, ShouldEqual, "Admin") }) + Convey("Can get organization users with query", func() { + query := m.GetOrgUsersQuery{ + OrgId: ac1.OrgId, + Query: "ac1", + } + err := GetOrgUsers(&query) + + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Email, ShouldEqual, ac1.Email) + }) + + Convey("Can get organization users with query and limit", func() { + query := m.GetOrgUsersQuery{ + OrgId: ac1.OrgId, + Query: "ac", + Limit: 1, + } + err := GetOrgUsers(&query) + + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Email, ShouldEqual, ac1.Email) + }) + Convey("Can set using org", func() { cmd := m.SetUsingOrgCommand{UserId: ac2.Id, OrgId: ac1.Id} err := SetUsingOrg(&cmd) @@ -154,7 +179,69 @@ func TestAccountDataAccess(t *testing.T) { So(err, ShouldEqual, m.ErrLastOrgAdmin) }) + Convey("Given an org user with dashboard permissions", func() { + ac3cmd := m.CreateUserCommand{Login: "ac3", Email: "ac3@test.com", Name: "ac3 name", IsAdmin: false} + err := CreateUser(&ac3cmd) + So(err, ShouldBeNil) + ac3 := ac3cmd.Result + + orgUserCmd := m.AddOrgUserCommand{ + OrgId: ac1.OrgId, + UserId: ac3.Id, + Role: m.ROLE_VIEWER, + } + + err = AddOrgUser(&orgUserCmd) + So(err, ShouldBeNil) + + query := m.GetOrgUsersQuery{OrgId: ac1.OrgId} + err = GetOrgUsers(&query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 3) + + dash1 := insertTestDashboard("1 test dash", ac1.OrgId, 0, false, "prod", "webapp") + dash2 := insertTestDashboard("2 test dash", ac3.OrgId, 0, false, "prod", "webapp") + + err = testHelperUpdateDashboardAcl(dash1.Id, m.DashboardAcl{DashboardId: dash1.Id, OrgId: ac1.OrgId, UserId: ac3.Id, Permission: m.PERMISSION_EDIT}) + So(err, ShouldBeNil) + + err = testHelperUpdateDashboardAcl(dash2.Id, m.DashboardAcl{DashboardId: dash2.Id, OrgId: ac3.OrgId, UserId: ac3.Id, Permission: m.PERMISSION_EDIT}) + So(err, ShouldBeNil) + + Convey("When org user is deleted", func() { + cmdRemove := m.RemoveOrgUserCommand{OrgId: ac1.OrgId, UserId: ac3.Id} + err := RemoveOrgUser(&cmdRemove) + So(err, ShouldBeNil) + + Convey("Should remove dependent permissions for deleted org user", func() { + permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: ac1.OrgId} + err = GetDashboardAclInfoList(permQuery) + So(err, ShouldBeNil) + + So(len(permQuery.Result), ShouldEqual, 0) + }) + + Convey("Should not remove dashboard permissions for same user in another org", func() { + permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 2, OrgId: ac3.OrgId} + err = GetDashboardAclInfoList(permQuery) + So(err, ShouldBeNil) + + So(len(permQuery.Result), ShouldEqual, 1) + So(permQuery.Result[0].OrgId, ShouldEqual, ac3.OrgId) + So(permQuery.Result[0].UserId, ShouldEqual, ac3.Id) + }) + + }) + }) }) }) }) } + +func testHelperUpdateDashboardAcl(dashboardId int64, items ...m.DashboardAcl) error { + cmd := m.UpdateDashboardAclCommand{DashboardId: dashboardId} + for _, item := range items { + cmd.Items = append(cmd.Items, &item) + } + return UpdateDashboardAcl(&cmd) +} diff --git a/pkg/services/sqlstore/org_users.go b/pkg/services/sqlstore/org_users.go index 60800d1cb13..0b991c73c55 100644 --- a/pkg/services/sqlstore/org_users.go +++ b/pkg/services/sqlstore/org_users.go @@ -2,6 +2,7 @@ package sqlstore import ( "fmt" + "strings" "time" "github.com/grafana/grafana/pkg/bus" @@ -69,9 +70,30 @@ func UpdateOrgUser(cmd *m.UpdateOrgUserCommand) error { func GetOrgUsers(query *m.GetOrgUsersQuery) error { query.Result = make([]*m.OrgUserDTO, 0) + sess := x.Table("org_user") sess.Join("INNER", "user", fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user"))) - sess.Where("org_user.org_id=?", query.OrgId) + + whereConditions := make([]string, 0) + whereParams := make([]interface{}, 0) + + whereConditions = append(whereConditions, "org_user.org_id = ?") + whereParams = append(whereParams, query.OrgId) + + if query.Query != "" { + queryWithWildcards := "%" + query.Query + "%" + whereConditions = append(whereConditions, "(email "+dialect.LikeStr()+" ? OR name "+dialect.LikeStr()+" ? OR login "+dialect.LikeStr()+" ?)") + whereParams = append(whereParams, queryWithWildcards, queryWithWildcards, queryWithWildcards) + } + + if len(whereConditions) > 0 { + sess.Where(strings.Join(whereConditions, " AND "), whereParams...) + } + + if query.Limit > 0 { + sess.Limit(query.Limit, 0) + } + sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role", "user.last_seen_at") sess.Asc("user.email", "user.login") @@ -88,10 +110,17 @@ func GetOrgUsers(query *m.GetOrgUsersQuery) error { func RemoveOrgUser(cmd *m.RemoveOrgUserCommand) error { return inTransaction(func(sess *DBSession) error { - var rawSql = "DELETE FROM org_user WHERE org_id=? and user_id=?" - _, err := sess.Exec(rawSql, cmd.OrgId, cmd.UserId) - if err != nil { - return err + deletes := []string{ + "DELETE FROM org_user WHERE org_id=? and user_id=?", + "DELETE FROM dashboard_acl WHERE org_id=? and user_id = ?", + "DELETE FROM team_member WHERE org_id=? and user_id = ?", + } + + for _, sql := range deletes { + _, err := sess.Exec(sql, cmd.OrgId, cmd.UserId) + if err != nil { + return err + } } return validateOneAdminLeftInOrg(cmd.OrgId, sess) diff --git a/pkg/services/sqlstore/playlist.go b/pkg/services/sqlstore/playlist.go index 72f3079db8d..67720cbadb8 100644 --- a/pkg/services/sqlstore/playlist.go +++ b/pkg/services/sqlstore/playlist.go @@ -1,8 +1,6 @@ package sqlstore import ( - "fmt" - "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" ) @@ -17,17 +15,13 @@ func init() { } func CreatePlaylist(cmd *m.CreatePlaylistCommand) error { - var err error - playlist := m.Playlist{ Name: cmd.Name, Interval: cmd.Interval, OrgId: cmd.OrgId, } - _, err = x.Insert(&playlist) - - fmt.Printf("%v", playlist.Id) + _, err := x.Insert(&playlist) playlistItems := make([]m.PlaylistItem, 0) for _, item := range cmd.Items { @@ -47,7 +41,6 @@ func CreatePlaylist(cmd *m.CreatePlaylistCommand) error { } func UpdatePlaylist(cmd *m.UpdatePlaylistCommand) error { - var err error playlist := m.Playlist{ Id: cmd.Id, OrgId: cmd.OrgId, @@ -68,7 +61,7 @@ func UpdatePlaylist(cmd *m.UpdatePlaylistCommand) error { Interval: playlist.Interval, } - _, err = x.Id(cmd.Id).Cols("id", "name", "interval").Update(&playlist) + _, err := x.ID(cmd.Id).Cols("id", "name", "interval").Update(&playlist) if err != nil { return err @@ -104,7 +97,7 @@ func GetPlaylist(query *m.GetPlaylistByIdQuery) error { } playlist := m.Playlist{} - _, err := x.Id(query.Id).Get(&playlist) + _, err := x.ID(query.Id).Get(&playlist) query.Result = &playlist diff --git a/pkg/services/sqlstore/search_builder.go b/pkg/services/sqlstore/search_builder.go new file mode 100644 index 00000000000..ddfbfbfc551 --- /dev/null +++ b/pkg/services/sqlstore/search_builder.go @@ -0,0 +1,197 @@ +package sqlstore + +import ( + "strings" + + m "github.com/grafana/grafana/pkg/models" +) + +// SearchBuilder is a builder/object mother that builds a dashboard search query +type SearchBuilder struct { + SqlBuilder + tags []string + isStarred bool + limit int + signedInUser *m.SignedInUser + whereDashboardIdsIn []int64 + whereTitle string + whereTypeFolder bool + whereTypeDash bool + whereFolderIds []int64 + permission m.PermissionType +} + +func NewSearchBuilder(signedInUser *m.SignedInUser, limit int, permission m.PermissionType) *SearchBuilder { + searchBuilder := &SearchBuilder{ + signedInUser: signedInUser, + limit: limit, + permission: permission, + } + + return searchBuilder +} + +func (sb *SearchBuilder) WithTags(tags []string) *SearchBuilder { + if len(tags) > 0 { + sb.tags = tags + } + + return sb +} + +func (sb *SearchBuilder) IsStarred() *SearchBuilder { + sb.isStarred = true + + return sb +} + +func (sb *SearchBuilder) WithDashboardIdsIn(ids []int64) *SearchBuilder { + if len(ids) > 0 { + sb.whereDashboardIdsIn = ids + } + + return sb +} + +func (sb *SearchBuilder) WithTitle(title string) *SearchBuilder { + sb.whereTitle = title + + return sb +} + +func (sb *SearchBuilder) WithType(queryType string) *SearchBuilder { + if len(queryType) > 0 && queryType == "dash-folder" { + sb.whereTypeFolder = true + } + + if len(queryType) > 0 && queryType == "dash-db" { + sb.whereTypeDash = true + } + + return sb +} + +func (sb *SearchBuilder) WithFolderIds(folderIds []int64) *SearchBuilder { + sb.whereFolderIds = folderIds + return sb +} + +// ToSql builds the sql and returns it as a string, together with the params. +func (sb *SearchBuilder) ToSql() (string, []interface{}) { + sb.params = make([]interface{}, 0) + + sb.buildSelect() + + if len(sb.tags) > 0 { + sb.buildTagQuery() + } else { + sb.buildMainQuery() + } + + sb.sql.WriteString(` + LEFT OUTER JOIN dashboard folder on folder.id = dashboard.folder_id + LEFT OUTER JOIN dashboard_tag on dashboard.id = dashboard_tag.dashboard_id`) + + sb.sql.WriteString(" ORDER BY dashboard.title ASC LIMIT 5000") + + return sb.sql.String(), sb.params +} + +func (sb *SearchBuilder) buildSelect() { + sb.sql.WriteString( + `SELECT + dashboard.id, + dashboard.uid, + dashboard.title, + dashboard.slug, + dashboard_tag.term, + dashboard.is_folder, + dashboard.folder_id, + folder.uid as folder_uid, + folder.slug as folder_slug, + folder.title as folder_title + FROM `) +} + +func (sb *SearchBuilder) buildTagQuery() { + sb.sql.WriteString( + `( + SELECT + dashboard.id FROM dashboard + LEFT OUTER JOIN dashboard_tag ON dashboard_tag.dashboard_id = dashboard.id + `) + + if sb.isStarred { + sb.sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id") + } + + sb.sql.WriteString(` WHERE dashboard_tag.term IN (?` + strings.Repeat(",?", len(sb.tags)-1) + `) AND `) + for _, tag := range sb.tags { + sb.params = append(sb.params, tag) + } + + sb.buildSearchWhereClause() + + // this ends the inner select (tag filtered part) + sb.sql.WriteString(` + GROUP BY dashboard.id HAVING COUNT(dashboard.id) >= ? + LIMIT ?) as ids + INNER JOIN dashboard on ids.id = dashboard.id + `) + + sb.params = append(sb.params, len(sb.tags)) + sb.params = append(sb.params, sb.limit) +} + +func (sb *SearchBuilder) buildMainQuery() { + sb.sql.WriteString(`( SELECT dashboard.id FROM dashboard `) + + if sb.isStarred { + sb.sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id") + } + + sb.sql.WriteString(` WHERE `) + sb.buildSearchWhereClause() + + sb.sql.WriteString(` LIMIT ?) as ids INNER JOIN dashboard on ids.id = dashboard.id `) + sb.params = append(sb.params, sb.limit) +} + +func (sb *SearchBuilder) buildSearchWhereClause() { + sb.sql.WriteString(` dashboard.org_id=?`) + sb.params = append(sb.params, sb.signedInUser.OrgId) + + if sb.isStarred { + sb.sql.WriteString(` AND star.user_id=?`) + sb.params = append(sb.params, sb.signedInUser.UserId) + } + + if len(sb.whereDashboardIdsIn) > 0 { + sb.sql.WriteString(` AND dashboard.id IN (?` + strings.Repeat(",?", len(sb.whereDashboardIdsIn)-1) + `)`) + for _, dashboardId := range sb.whereDashboardIdsIn { + sb.params = append(sb.params, dashboardId) + } + } + + sb.writeDashboardPermissionFilter(sb.signedInUser, sb.permission) + + if len(sb.whereTitle) > 0 { + sb.sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?") + sb.params = append(sb.params, "%"+sb.whereTitle+"%") + } + + if sb.whereTypeFolder { + sb.sql.WriteString(" AND dashboard.is_folder = " + dialect.BooleanStr(true)) + } + + if sb.whereTypeDash { + sb.sql.WriteString(" AND dashboard.is_folder = " + dialect.BooleanStr(false)) + } + + if len(sb.whereFolderIds) > 0 { + sb.sql.WriteString(` AND dashboard.folder_id IN (?` + strings.Repeat(",?", len(sb.whereFolderIds)-1) + `) `) + for _, id := range sb.whereFolderIds { + sb.params = append(sb.params, id) + } + } +} diff --git a/pkg/services/sqlstore/search_builder_test.go b/pkg/services/sqlstore/search_builder_test.go new file mode 100644 index 00000000000..e8b02c445ec --- /dev/null +++ b/pkg/services/sqlstore/search_builder_test.go @@ -0,0 +1,38 @@ +package sqlstore + +import ( + "testing" + + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + . "github.com/smartystreets/goconvey/convey" +) + +func TestSearchBuilder(t *testing.T) { + dialect = migrator.NewDialect("sqlite3") + + Convey("Testing building a search", t, func() { + signedInUser := &m.SignedInUser{ + OrgId: 1, + UserId: 1, + } + + sb := NewSearchBuilder(signedInUser, 1000, m.PERMISSION_VIEW) + + Convey("When building a normal search", func() { + sql, params := sb.IsStarred().WithTitle("test").ToSql() + So(sql, ShouldStartWith, "SELECT") + So(sql, ShouldContainSubstring, "INNER JOIN dashboard on ids.id = dashboard.id") + So(sql, ShouldEndWith, "ORDER BY dashboard.title ASC LIMIT 5000") + So(len(params), ShouldBeGreaterThan, 0) + }) + + Convey("When building a search with tag filter", func() { + sql, params := sb.WithTags([]string{"tag1", "tag2"}).ToSql() + So(sql, ShouldStartWith, "SELECT") + So(sql, ShouldContainSubstring, "LEFT OUTER JOIN dashboard_tag") + So(sql, ShouldEndWith, "ORDER BY dashboard.title ASC LIMIT 5000") + So(len(params), ShouldBeGreaterThan, 0) + }) + }) +} diff --git a/pkg/services/sqlstore/sqlbuilder.go b/pkg/services/sqlstore/sqlbuilder.go new file mode 100644 index 00000000000..b42c7926203 --- /dev/null +++ b/pkg/services/sqlstore/sqlbuilder.go @@ -0,0 +1,75 @@ +package sqlstore + +import ( + "bytes" + "strings" + + m "github.com/grafana/grafana/pkg/models" +) + +type SqlBuilder struct { + sql bytes.Buffer + params []interface{} +} + +func (sb *SqlBuilder) Write(sql string, params ...interface{}) { + sb.sql.WriteString(sql) + + if len(params) > 0 { + sb.params = append(sb.params, params...) + } +} + +func (sb *SqlBuilder) GetSqlString() string { + return sb.sql.String() +} + +func (sb *SqlBuilder) AddParams(params ...interface{}) { + sb.params = append(sb.params, params...) +} + +func (sb *SqlBuilder) writeDashboardPermissionFilter(user *m.SignedInUser, permission m.PermissionType) { + + if user.OrgRole == m.ROLE_ADMIN { + return + } + + okRoles := []interface{}{user.OrgRole} + + if user.OrgRole == m.ROLE_EDITOR { + okRoles = append(okRoles, m.ROLE_VIEWER) + } + + falseStr := dialect.BooleanStr(false) + + sb.sql.WriteString(` AND + ( + dashboard.id IN ( + SELECT distinct d.id AS DashboardId + FROM dashboard AS d + LEFT JOIN dashboard folder on folder.id = d.folder_id + LEFT JOIN dashboard_acl AS da ON + da.dashboard_id = d.id OR + da.dashboard_id = d.folder_id OR + ( + -- include default permissions --> + da.org_id = -1 AND ( + (folder.id IS NOT NULL AND folder.has_acl = ` + falseStr + `) OR + (folder.id IS NULL AND d.has_acl = ` + falseStr + `) + ) + ) + LEFT JOIN team_member as ugm on ugm.team_id = da.team_id + WHERE + d.org_id = ? AND + da.permission >= ? AND + ( + da.user_id = ? OR + ugm.user_id = ? OR + da.role IN (?` + strings.Repeat(",?", len(okRoles)-1) + `) + ) + ) + )`) + + sb.params = append(sb.params, user.OrgId, permission, user.UserId, user.UserId) + sb.params = append(sb.params, okRoles...) +} diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index 2655bf9c22e..5843c5c300b 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -7,14 +7,15 @@ import ( "path" "path/filepath" "strings" + "testing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/annotations" - "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/sqlstore/migrations" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" "github.com/grafana/grafana/pkg/setting" "github.com/go-sql-driver/mysql" @@ -101,7 +102,6 @@ func SetEngine(engine *xorm.Engine) (err error) { // Init repo instances annotations.SetRepository(&SqlAnnotationRepo{}) - dashboards.SetRepository(&dashboards.DashboardRepository{}) return nil } @@ -216,3 +216,46 @@ func LoadConfig() { DbCfg.ServerCertName = sec.Key("server_cert_name").String() DbCfg.Path = sec.Key("path").MustString("data/grafana.db") } + +var ( + dbSqlite = "sqlite" + dbMySql = "mysql" + dbPostgres = "postgres" +) + +func InitTestDB(t *testing.T) *xorm.Engine { + selectedDb := dbSqlite + //selectedDb := dbMySql + //selectedDb := dbPostgres + + var x *xorm.Engine + var err error + + // environment variable present for test db? + if db, present := os.LookupEnv("GRAFANA_TEST_DB"); present { + selectedDb = db + } + + switch strings.ToLower(selectedDb) { + case dbMySql: + x, err = xorm.NewEngine(sqlutil.TestDB_Mysql.DriverName, sqlutil.TestDB_Mysql.ConnStr) + case dbPostgres: + x, err = xorm.NewEngine(sqlutil.TestDB_Postgres.DriverName, sqlutil.TestDB_Postgres.ConnStr) + default: + x, err = xorm.NewEngine(sqlutil.TestDB_Sqlite3.DriverName, sqlutil.TestDB_Sqlite3.ConnStr) + } + + // x.ShowSQL() + + if err != nil { + t.Fatalf("Failed to init in memory sqllite3 db %v", err) + } + + sqlutil.CleanDB(x) + + if err := SetEngine(x); err != nil { + t.Fatal(err) + } + + return x +} diff --git a/pkg/services/sqlstore/sqlutil/sqlutil.go b/pkg/services/sqlstore/sqlutil/sqlutil.go index 4aa2ec27216..26a58811e0f 100644 --- a/pkg/services/sqlstore/sqlutil/sqlutil.go +++ b/pkg/services/sqlstore/sqlutil/sqlutil.go @@ -11,7 +11,7 @@ type TestDB struct { ConnStr string } -var TestDB_Sqlite3 = TestDB{DriverName: "sqlite3", ConnStr: ":memory:?_loc=Local"} +var TestDB_Sqlite3 = TestDB{DriverName: "sqlite3", ConnStr: ":memory:"} var TestDB_Mysql = TestDB{DriverName: "mysql", ConnStr: "grafana:password@tcp(localhost:3306)/grafana_tests?collation=utf8mb4_unicode_ci"} var TestDB_Postgres = TestDB{DriverName: "postgres", ConnStr: "user=grafanatest password=grafanatest host=localhost port=5432 dbname=grafanatest sslmode=disable"} diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index aa01c8a3761..cfe2d88c82c 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -13,12 +13,12 @@ func init() { bus.AddHandler("sql", GetAdminStats) } -var activeUserTimeLimit time.Duration = time.Hour * 24 * 14 +var activeUserTimeLimit time.Duration = time.Hour * 24 * 30 func GetDataSourceStats(query *m.GetDataSourceStatsQuery) error { var rawSql = `SELECT COUNT(*) as count, type FROM data_source GROUP BY type` query.Result = make([]*m.DataSourceStats, 0) - err := x.Sql(rawSql).Find(&query.Result) + err := x.SQL(rawSql).Find(&query.Result) if err != nil { return err } @@ -30,36 +30,39 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error { var rawSql = `SELECT ( SELECT COUNT(*) - FROM ` + dialect.Quote("user") + ` - ) AS users, + FROM ` + dialect.Quote("user") + ` + ) AS users, ( SELECT COUNT(*) - FROM ` + dialect.Quote("org") + ` - ) AS orgs, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("dashboard") + ` - ) AS dashboards, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("data_source") + ` - ) AS datasources, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("playlist") + ` - ) AS playlists, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("alert") + ` - ) AS alerts, + FROM ` + dialect.Quote("org") + ` + ) AS orgs, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("dashboard") + ` + ) AS dashboards, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("data_source") + ` + ) AS datasources, + ( + SELECT COUNT(*) FROM ` + dialect.Quote("star") + ` + ) AS stars, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("playlist") + ` + ) AS playlists, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("alert") + ` + ) AS alerts, ( SELECT COUNT(*) FROM ` + dialect.Quote("user") + ` where last_seen_at > ? - ) as active_users + ) as active_users ` activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit) var stats m.SystemStats - _, err := x.Sql(rawSql, activeUserDeadlineDate).Get(&stats) + _, err := x.SQL(rawSql, activeUserDeadlineDate).Get(&stats) if err != nil { return err } @@ -70,51 +73,51 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error { func GetAdminStats(query *m.GetAdminStatsQuery) error { var rawSql = `SELECT - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("user") + ` - ) AS users, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("org") + ` - ) AS orgs, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("dashboard") + ` - ) AS dashboards, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("dashboard_snapshot") + ` - ) AS snapshots, - ( - SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` )) - FROM ` + dialect.Quote("dashboard_tag") + ` - ) AS tags, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("data_source") + ` - ) AS datasources, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("playlist") + ` - ) AS playlists, - ( - SELECT COUNT(*) FROM ` + dialect.Quote("star") + ` - ) AS stars, - ( - SELECT COUNT(*) - FROM ` + dialect.Quote("alert") + ` - ) AS alerts, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("user") + ` + ) AS users, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("org") + ` + ) AS orgs, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("dashboard") + ` + ) AS dashboards, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("dashboard_snapshot") + ` + ) AS snapshots, + ( + SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` )) + FROM ` + dialect.Quote("dashboard_tag") + ` + ) AS tags, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("data_source") + ` + ) AS datasources, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("playlist") + ` + ) AS playlists, + ( + SELECT COUNT(*) FROM ` + dialect.Quote("star") + ` + ) AS stars, + ( + SELECT COUNT(*) + FROM ` + dialect.Quote("alert") + ` + ) AS alerts, ( SELECT COUNT(*) - from ` + dialect.Quote("user") + ` where last_seen_at > ? + from ` + dialect.Quote("user") + ` where last_seen_at > ? ) as active_users - ` + ` activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit) var stats m.AdminStats - _, err := x.Sql(rawSql, activeUserDeadlineDate).Get(&stats) + _, err := x.SQL(rawSql, activeUserDeadlineDate).Get(&stats) if err != nil { return err } diff --git a/pkg/services/sqlstore/team.go b/pkg/services/sqlstore/team.go new file mode 100644 index 00000000000..d238301c7ce --- /dev/null +++ b/pkg/services/sqlstore/team.go @@ -0,0 +1,282 @@ +package sqlstore + +import ( + "bytes" + "fmt" + "time" + + "github.com/grafana/grafana/pkg/bus" + m "github.com/grafana/grafana/pkg/models" +) + +func init() { + bus.AddHandler("sql", CreateTeam) + bus.AddHandler("sql", UpdateTeam) + bus.AddHandler("sql", DeleteTeam) + bus.AddHandler("sql", SearchTeams) + bus.AddHandler("sql", GetTeamById) + bus.AddHandler("sql", GetTeamsByUser) + + bus.AddHandler("sql", AddTeamMember) + bus.AddHandler("sql", RemoveTeamMember) + bus.AddHandler("sql", GetTeamMembers) +} + +func CreateTeam(cmd *m.CreateTeamCommand) error { + return inTransaction(func(sess *DBSession) error { + + if isNameTaken, err := isTeamNameTaken(cmd.OrgId, cmd.Name, 0, sess); err != nil { + return err + } else if isNameTaken { + return m.ErrTeamNameTaken + } + + team := m.Team{ + Name: cmd.Name, + Email: cmd.Email, + OrgId: cmd.OrgId, + Created: time.Now(), + Updated: time.Now(), + } + + _, err := sess.Insert(&team) + + cmd.Result = team + + return err + }) +} + +func UpdateTeam(cmd *m.UpdateTeamCommand) error { + return inTransaction(func(sess *DBSession) error { + + if isNameTaken, err := isTeamNameTaken(cmd.OrgId, cmd.Name, cmd.Id, sess); err != nil { + return err + } else if isNameTaken { + return m.ErrTeamNameTaken + } + + team := m.Team{ + Name: cmd.Name, + Email: cmd.Email, + Updated: time.Now(), + } + + sess.MustCols("email") + + affectedRows, err := sess.Id(cmd.Id).Update(&team) + + if err != nil { + return err + } + + if affectedRows == 0 { + return m.ErrTeamNotFound + } + + return nil + }) +} + +// DeleteTeam will delete a team, its member and any permissions connected to the team +func DeleteTeam(cmd *m.DeleteTeamCommand) error { + return inTransaction(func(sess *DBSession) error { + if teamExists, err := teamExists(cmd.OrgId, cmd.Id, sess); err != nil { + return err + } else if !teamExists { + return m.ErrTeamNotFound + } + + deletes := []string{ + "DELETE FROM team_member WHERE org_id=? and team_id = ?", + "DELETE FROM team WHERE org_id=? and id = ?", + "DELETE FROM dashboard_acl WHERE org_id=? and team_id = ?", + } + + for _, sql := range deletes { + _, err := sess.Exec(sql, cmd.OrgId, cmd.Id) + if err != nil { + return err + } + } + return nil + }) +} + +func teamExists(orgId int64, teamId int64, sess *DBSession) (bool, error) { + if res, err := sess.Query("SELECT 1 from team WHERE org_id=? and id=?", orgId, teamId); err != nil { + return false, err + } else if len(res) != 1 { + return false, nil + } + + return true, nil +} + +func isTeamNameTaken(orgId int64, name string, existingId int64, sess *DBSession) (bool, error) { + var team m.Team + exists, err := sess.Where("org_id=? and name=?", orgId, name).Get(&team) + + if err != nil { + return false, nil + } + + if exists && existingId != team.Id { + return true, nil + } + + return false, nil +} + +func SearchTeams(query *m.SearchTeamsQuery) error { + query.Result = m.SearchTeamQueryResult{ + Teams: make([]*m.SearchTeamDto, 0), + } + queryWithWildcards := "%" + query.Query + "%" + + var sql bytes.Buffer + params := make([]interface{}, 0) + + sql.WriteString(`select + team.id as id, + team.org_id, + team.name as name, + team.email as email, + (select count(*) from team_member where team_member.team_id = team.id) as member_count + from team as team + where team.org_id = ?`) + + params = append(params, query.OrgId) + + if query.Query != "" { + sql.WriteString(` and team.name ` + dialect.LikeStr() + ` ?`) + params = append(params, queryWithWildcards) + } + + if query.Name != "" { + sql.WriteString(` and team.name = ?`) + params = append(params, query.Name) + } + + sql.WriteString(` order by team.name asc`) + + if query.Limit != 0 { + sql.WriteString(` limit ? offset ?`) + offset := query.Limit * (query.Page - 1) + params = append(params, query.Limit, offset) + } + + if err := x.Sql(sql.String(), params...).Find(&query.Result.Teams); err != nil { + return err + } + + team := m.Team{} + countSess := x.Table("team") + if query.Query != "" { + countSess.Where(`name `+dialect.LikeStr()+` ?`, queryWithWildcards) + } + + if query.Name != "" { + countSess.Where("name=?", query.Name) + } + + count, err := countSess.Count(&team) + query.Result.TotalCount = count + + return err +} + +func GetTeamById(query *m.GetTeamByIdQuery) error { + var team m.Team + exists, err := x.Where("org_id=? and id=?", query.OrgId, query.Id).Get(&team) + if err != nil { + return err + } + + if !exists { + return m.ErrTeamNotFound + } + + query.Result = &team + return nil +} + +// GetTeamsByUser is used by the Guardian when checking a users' permissions +func GetTeamsByUser(query *m.GetTeamsByUserQuery) error { + query.Result = make([]*m.Team, 0) + + sess := x.Table("team") + sess.Join("INNER", "team_member", "team.id=team_member.team_id") + sess.Where("team.org_id=? and team_member.user_id=?", query.OrgId, query.UserId) + + err := sess.Find(&query.Result) + if err != nil { + return err + } + + return nil +} + +// AddTeamMember adds a user to a team +func AddTeamMember(cmd *m.AddTeamMemberCommand) error { + return inTransaction(func(sess *DBSession) error { + if res, err := sess.Query("SELECT 1 from team_member WHERE org_id=? and team_id=? and user_id=?", cmd.OrgId, cmd.TeamId, cmd.UserId); err != nil { + return err + } else if len(res) == 1 { + return m.ErrTeamMemberAlreadyAdded + } + + if teamExists, err := teamExists(cmd.OrgId, cmd.TeamId, sess); err != nil { + return err + } else if !teamExists { + return m.ErrTeamNotFound + } + + entity := m.TeamMember{ + OrgId: cmd.OrgId, + TeamId: cmd.TeamId, + UserId: cmd.UserId, + Created: time.Now(), + Updated: time.Now(), + } + + _, err := sess.Insert(&entity) + return err + }) +} + +// RemoveTeamMember removes a member from a team +func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error { + return inTransaction(func(sess *DBSession) error { + if teamExists, err := teamExists(cmd.OrgId, cmd.TeamId, sess); err != nil { + return err + } else if !teamExists { + return m.ErrTeamNotFound + } + + var rawSql = "DELETE FROM team_member WHERE org_id=? and team_id=? and user_id=?" + res, err := sess.Exec(rawSql, cmd.OrgId, cmd.TeamId, cmd.UserId) + if err != nil { + return err + } + rows, err := res.RowsAffected() + if rows == 0 { + return m.ErrTeamMemberNotFound + } + + return err + }) +} + +// GetTeamMembers return a list of members for the specified team +func GetTeamMembers(query *m.GetTeamMembersQuery) error { + query.Result = make([]*m.TeamMemberDTO, 0) + sess := x.Table("team_member") + sess.Join("INNER", "user", fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user"))) + sess.Where("team_member.org_id=? and team_member.team_id=?", query.OrgId, query.TeamId) + sess.Cols("user.org_id", "team_member.team_id", "team_member.user_id", "user.email", "user.login") + sess.Asc("user.login", "user.email") + + err := sess.Find(&query.Result) + return err +} diff --git a/pkg/services/sqlstore/team_test.go b/pkg/services/sqlstore/team_test.go new file mode 100644 index 00000000000..f136411eeba --- /dev/null +++ b/pkg/services/sqlstore/team_test.go @@ -0,0 +1,122 @@ +package sqlstore + +import ( + "fmt" + "testing" + + . "github.com/smartystreets/goconvey/convey" + + m "github.com/grafana/grafana/pkg/models" +) + +func TestTeamCommandsAndQueries(t *testing.T) { + + Convey("Testing Team commands & queries", t, func() { + InitTestDB(t) + + Convey("Given saved users and two teams", func() { + var userIds []int64 + for i := 0; i < 5; i++ { + userCmd := &m.CreateUserCommand{ + Email: fmt.Sprint("user", i, "@test.com"), + Name: fmt.Sprint("user", i), + Login: fmt.Sprint("loginuser", i), + } + err := CreateUser(userCmd) + So(err, ShouldBeNil) + userIds = append(userIds, userCmd.Result.Id) + } + + var testOrgId int64 = 1 + group1 := m.CreateTeamCommand{OrgId: testOrgId, Name: "group1 name", Email: "test1@test.com"} + group2 := m.CreateTeamCommand{OrgId: testOrgId, Name: "group2 name", Email: "test2@test.com"} + + err := CreateTeam(&group1) + So(err, ShouldBeNil) + err = CreateTeam(&group2) + So(err, ShouldBeNil) + + Convey("Should be able to create teams and add users", func() { + query := &m.SearchTeamsQuery{OrgId: testOrgId, Name: "group1 name", Page: 1, Limit: 10} + err = SearchTeams(query) + So(err, ShouldBeNil) + So(query.Page, ShouldEqual, 1) + + team1 := query.Result.Teams[0] + So(team1.Name, ShouldEqual, "group1 name") + So(team1.Email, ShouldEqual, "test1@test.com") + So(team1.OrgId, ShouldEqual, testOrgId) + + err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userIds[0]}) + So(err, ShouldBeNil) + + q1 := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: team1.Id} + err = GetTeamMembers(q1) + So(err, ShouldBeNil) + So(q1.Result[0].TeamId, ShouldEqual, team1.Id) + So(q1.Result[0].Login, ShouldEqual, "loginuser0") + So(q1.Result[0].OrgId, ShouldEqual, testOrgId) + }) + + Convey("Should be able to search for teams", func() { + query := &m.SearchTeamsQuery{OrgId: testOrgId, Query: "group", Page: 1} + err = SearchTeams(query) + So(err, ShouldBeNil) + So(len(query.Result.Teams), ShouldEqual, 2) + So(query.Result.TotalCount, ShouldEqual, 2) + + query2 := &m.SearchTeamsQuery{OrgId: testOrgId, Query: ""} + err = SearchTeams(query2) + So(err, ShouldBeNil) + So(len(query2.Result.Teams), ShouldEqual, 2) + }) + + Convey("Should be able to return all teams a user is member of", func() { + groupId := group2.Result.Id + err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[0]}) + + query := &m.GetTeamsByUserQuery{OrgId: testOrgId, UserId: userIds[0]} + err = GetTeamsByUser(query) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 1) + So(query.Result[0].Name, ShouldEqual, "group2 name") + So(query.Result[0].Email, ShouldEqual, "test2@test.com") + }) + + Convey("Should be able to remove users from a group", func() { + err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0]}) + So(err, ShouldBeNil) + + err = RemoveTeamMember(&m.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0]}) + So(err, ShouldBeNil) + + q2 := &m.GetTeamMembersQuery{OrgId: testOrgId, TeamId: group1.Result.Id} + err = GetTeamMembers(q2) + So(err, ShouldBeNil) + So(len(q2.Result), ShouldEqual, 0) + }) + + Convey("Should be able to remove a group with users and permissions", func() { + groupId := group2.Result.Id + err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[1]}) + So(err, ShouldBeNil) + err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[2]}) + So(err, ShouldBeNil) + err = testHelperUpdateDashboardAcl(1, m.DashboardAcl{DashboardId: 1, OrgId: testOrgId, Permission: m.PERMISSION_EDIT, TeamId: groupId}) + + err = DeleteTeam(&m.DeleteTeamCommand{OrgId: testOrgId, Id: groupId}) + So(err, ShouldBeNil) + + query := &m.GetTeamByIdQuery{OrgId: testOrgId, Id: groupId} + err = GetTeamById(query) + So(err, ShouldEqual, m.ErrTeamNotFound) + + permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: testOrgId} + err = GetDashboardAclInfoList(permQuery) + So(err, ShouldBeNil) + + So(len(permQuery.Result), ShouldEqual, 0) + }) + }) + }) +} diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index 4c199d306f0..73ea07f031f 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -350,6 +350,7 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error { u.name as name, u.help_flags1 as help_flags1, u.last_seen_at as last_seen_at, + (SELECT COUNT(*) FROM org_user where org_user.user_id = u.id) as org_count, org.name as org_name, org_user.role as org_role, org.id as org_id @@ -438,6 +439,10 @@ func DeleteUser(cmd *m.DeleteUserCommand) error { deletes := []string{ "DELETE FROM star WHERE user_id = ?", "DELETE FROM " + dialect.Quote("user") + " WHERE id = ?", + "DELETE FROM org_user WHERE user_id = ?", + "DELETE FROM dashboard_acl WHERE user_id = ?", + "DELETE FROM preferences WHERE user_id = ?", + "DELETE FROM team_member WHERE user_id = ?", } for _, sql := range deletes { diff --git a/pkg/services/sqlstore/user_test.go b/pkg/services/sqlstore/user_test.go index decb4682552..2830733c96a 100644 --- a/pkg/services/sqlstore/user_test.go +++ b/pkg/services/sqlstore/user_test.go @@ -6,7 +6,7 @@ import ( . "github.com/smartystreets/goconvey/convey" - "github.com/grafana/grafana/pkg/models" + m "github.com/grafana/grafana/pkg/models" ) func TestUserDataAccess(t *testing.T) { @@ -14,80 +14,134 @@ func TestUserDataAccess(t *testing.T) { Convey("Testing DB", t, func() { InitTestDB(t) - var err error - for i := 0; i < 5; i++ { - err = CreateUser(&models.CreateUserCommand{ - Email: fmt.Sprint("user", i, "@test.com"), - Name: fmt.Sprint("user", i), - Login: fmt.Sprint("loginuser", i), + Convey("Given 5 users", func() { + var err error + var cmd *m.CreateUserCommand + users := []m.User{} + for i := 0; i < 5; i++ { + cmd = &m.CreateUserCommand{ + Email: fmt.Sprint("user", i, "@test.com"), + Name: fmt.Sprint("user", i), + Login: fmt.Sprint("loginuser", i), + } + err = CreateUser(cmd) + So(err, ShouldBeNil) + users = append(users, cmd.Result) + } + + Convey("Can return the first page of users and a total count", func() { + query := m.SearchUsersQuery{Query: "", Page: 1, Limit: 3} + err = SearchUsers(&query) + + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 3) + So(query.Result.TotalCount, ShouldEqual, 5) }) - So(err, ShouldBeNil) - } - Convey("Can return the first page of users and a total count", func() { - query := models.SearchUsersQuery{Query: "", Page: 1, Limit: 3} - err = SearchUsers(&query) + Convey("Can return the second page of users and a total count", func() { + query := m.SearchUsersQuery{Query: "", Page: 2, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 3) - So(query.Result.TotalCount, ShouldEqual, 5) - }) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 2) + So(query.Result.TotalCount, ShouldEqual, 5) + }) - Convey("Can return the second page of users and a total count", func() { - query := models.SearchUsersQuery{Query: "", Page: 2, Limit: 3} - err = SearchUsers(&query) + Convey("Can return list of users matching query on user name", func() { + query := m.SearchUsersQuery{Query: "use", Page: 1, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 2) - So(query.Result.TotalCount, ShouldEqual, 5) - }) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 3) + So(query.Result.TotalCount, ShouldEqual, 5) - Convey("Can return list of users matching query on user name", func() { - query := models.SearchUsersQuery{Query: "use", Page: 1, Limit: 3} - err = SearchUsers(&query) + query = m.SearchUsersQuery{Query: "ser1", Page: 1, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 3) - So(query.Result.TotalCount, ShouldEqual, 5) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 1) + So(query.Result.TotalCount, ShouldEqual, 1) - query = models.SearchUsersQuery{Query: "ser1", Page: 1, Limit: 3} - err = SearchUsers(&query) + query = m.SearchUsersQuery{Query: "USER1", Page: 1, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 1) - So(query.Result.TotalCount, ShouldEqual, 1) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 1) + So(query.Result.TotalCount, ShouldEqual, 1) - query = models.SearchUsersQuery{Query: "USER1", Page: 1, Limit: 3} - err = SearchUsers(&query) + query = m.SearchUsersQuery{Query: "idontexist", Page: 1, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 1) - So(query.Result.TotalCount, ShouldEqual, 1) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 0) + So(query.Result.TotalCount, ShouldEqual, 0) + }) - query = models.SearchUsersQuery{Query: "idontexist", Page: 1, Limit: 3} - err = SearchUsers(&query) + Convey("Can return list of users matching query on email", func() { + query := m.SearchUsersQuery{Query: "ser1@test.com", Page: 1, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 0) - So(query.Result.TotalCount, ShouldEqual, 0) - }) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 1) + So(query.Result.TotalCount, ShouldEqual, 1) + }) - Convey("Can return list of users matching query on email", func() { - query := models.SearchUsersQuery{Query: "ser1@test.com", Page: 1, Limit: 3} - err = SearchUsers(&query) + Convey("Can return list of users matching query on login name", func() { + query := m.SearchUsersQuery{Query: "loginuser1", Page: 1, Limit: 3} + err = SearchUsers(&query) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 1) - So(query.Result.TotalCount, ShouldEqual, 1) - }) + So(err, ShouldBeNil) + So(len(query.Result.Users), ShouldEqual, 1) + So(query.Result.TotalCount, ShouldEqual, 1) + }) - Convey("Can return list of users matching query on login name", func() { - query := models.SearchUsersQuery{Query: "loginuser1", Page: 1, Limit: 3} - err = SearchUsers(&query) + Convey("when a user is an org member and has been assigned permissions", func() { + err = AddOrgUser(&m.AddOrgUserCommand{LoginOrEmail: users[0].Login, Role: m.ROLE_VIEWER, OrgId: users[0].OrgId}) + So(err, ShouldBeNil) - So(err, ShouldBeNil) - So(len(query.Result.Users), ShouldEqual, 1) - So(query.Result.TotalCount, ShouldEqual, 1) + testHelperUpdateDashboardAcl(1, m.DashboardAcl{DashboardId: 1, OrgId: users[0].OrgId, UserId: users[0].Id, Permission: m.PERMISSION_EDIT}) + So(err, ShouldBeNil) + + err = SavePreferences(&m.SavePreferencesCommand{UserId: users[0].Id, OrgId: users[0].OrgId, HomeDashboardId: 1, Theme: "dark"}) + So(err, ShouldBeNil) + + Convey("when the user is deleted", func() { + err = DeleteUser(&m.DeleteUserCommand{UserId: users[0].Id}) + So(err, ShouldBeNil) + + Convey("Should delete connected org users and permissions", func() { + query := &m.GetOrgUsersQuery{OrgId: 1} + err = GetOrgUsersForTest(query) + So(err, ShouldBeNil) + + So(len(query.Result), ShouldEqual, 1) + + permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: 1} + err = GetDashboardAclInfoList(permQuery) + So(err, ShouldBeNil) + + So(len(permQuery.Result), ShouldEqual, 0) + + prefsQuery := &m.GetPreferencesQuery{OrgId: users[0].OrgId, UserId: users[0].Id} + err = GetPreferences(prefsQuery) + So(err, ShouldBeNil) + + So(prefsQuery.Result.OrgId, ShouldEqual, 0) + So(prefsQuery.Result.UserId, ShouldEqual, 0) + }) + }) + }) }) }) } + +func GetOrgUsersForTest(query *m.GetOrgUsersQuery) error { + query.Result = make([]*m.OrgUserDTO, 0) + sess := x.Table("org_user") + sess.Join("LEFT ", "user", fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user"))) + sess.Where("org_user.org_id=?", query.OrgId) + sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role") + + err := sess.Find(&query.Result) + return err +} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index ef4a7c42e86..6099388f668 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -75,19 +75,19 @@ var ( EnforceDomain bool // Security settings. - SecretKey string - LogInRememberDays int - CookieUserName string - CookieRememberName string - DisableGravatar bool - EmailCodeValidMinutes int - DataProxyWhiteList map[string]bool + SecretKey string + LogInRememberDays int + CookieUserName string + CookieRememberName string + DisableGravatar bool + EmailCodeValidMinutes int + DataProxyWhiteList map[string]bool + DisableBruteForceLoginProtection bool // Snapshots ExternalSnapshotUrl string ExternalSnapshotName string ExternalEnabled bool - SnapShotTTLDays int SnapShotRemoveExpired bool // Dashboard history @@ -106,6 +106,7 @@ var ( ExternalUserMngLinkUrl string ExternalUserMngLinkName string ExternalUserMngInfo string + ViewersCanEdit bool // Http auth AdminUser string @@ -513,6 +514,7 @@ func NewConfigContext(args *CommandLineArgs) error { CookieUserName = security.Key("cookie_username").String() CookieRememberName = security.Key("cookie_remember_name").String() DisableGravatar = security.Key("disable_gravatar").MustBool(true) + DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false) // read snapshots settings snapshots := Cfg.Section("snapshots") @@ -520,7 +522,6 @@ func NewConfigContext(args *CommandLineArgs) error { ExternalSnapshotName = snapshots.Key("external_snapshot_name").String() ExternalEnabled = snapshots.Key("external_enabled").MustBool(true) SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true) - SnapShotTTLDays = snapshots.Key("snapshot_TTL_days").MustInt(90) // read dashboard settings dashboards := Cfg.Section("dashboards") @@ -540,13 +541,14 @@ func NewConfigContext(args *CommandLineArgs) error { AllowUserSignUp = users.Key("allow_sign_up").MustBool(true) AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true) AutoAssignOrg = users.Key("auto_assign_org").MustBool(true) - AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Read Only Editor", "Viewer"}) + AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"}) VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false) LoginHint = users.Key("login_hint").String() DefaultTheme = users.Key("default_theme").String() ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String() ExternalUserMngLinkName = users.Key("external_manage_link_name").String() ExternalUserMngInfo = users.Key("external_manage_info").String() + ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false) // auth auth := Cfg.Section("auth") @@ -576,7 +578,7 @@ func NewConfigContext(args *CommandLineArgs) error { // PhantomJS rendering ImagesDir = filepath.Join(DataPath, "png") - PhantomDir = filepath.Join(HomePath, "vendor/phantomjs") + PhantomDir = filepath.Join(HomePath, "tools/phantomjs") analytics := Cfg.Section("analytics") ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true) @@ -598,7 +600,7 @@ func NewConfigContext(args *CommandLineArgs) error { readQuotaSettings() if VerifyEmailEnabled && !Smtp.Enabled { - log.Warn("require_email_validation is enabled but smpt is disabled") + log.Warn("require_email_validation is enabled but smtp is disabled") } // check old key name @@ -608,7 +610,7 @@ func NewConfigContext(args *CommandLineArgs) error { } imageUploadingSection := Cfg.Section("external_image_storage") - ImageUploadProvider = imageUploadingSection.Key("provider").MustString("internal") + ImageUploadProvider = imageUploadingSection.Key("provider").MustString("") return nil } diff --git a/pkg/social/generic_oauth.go b/pkg/social/generic_oauth.go index ec3c445ebb2..2411e0006a2 100644 --- a/pkg/social/generic_oauth.go +++ b/pkg/social/generic_oauth.go @@ -1,18 +1,21 @@ package social import ( + "encoding/base64" "encoding/json" "errors" "fmt" "net/http" + "net/mail" + "regexp" "github.com/grafana/grafana/pkg/models" "golang.org/x/oauth2" ) -type GenericOAuth struct { - *oauth2.Config +type SocialGenericOAuth struct { + *SocialBase allowedDomains []string allowedOrganizations []string apiUrl string @@ -20,19 +23,19 @@ type GenericOAuth struct { teamIds []int } -func (s *GenericOAuth) Type() int { +func (s *SocialGenericOAuth) Type() int { return int(models.GENERIC) } -func (s *GenericOAuth) IsEmailAllowed(email string) bool { +func (s *SocialGenericOAuth) IsEmailAllowed(email string) bool { return isEmailAllowed(email, s.allowedDomains) } -func (s *GenericOAuth) IsSignupAllowed() bool { +func (s *SocialGenericOAuth) IsSignupAllowed() bool { return s.allowSignup } -func (s *GenericOAuth) IsTeamMember(client *http.Client) bool { +func (s *SocialGenericOAuth) IsTeamMember(client *http.Client) bool { if len(s.teamIds) == 0 { return true } @@ -53,7 +56,7 @@ func (s *GenericOAuth) IsTeamMember(client *http.Client) bool { return false } -func (s *GenericOAuth) IsOrganizationMember(client *http.Client) bool { +func (s *SocialGenericOAuth) IsOrganizationMember(client *http.Client) bool { if len(s.allowedOrganizations) == 0 { return true } @@ -74,7 +77,7 @@ func (s *GenericOAuth) IsOrganizationMember(client *http.Client) bool { return false } -func (s *GenericOAuth) FetchPrivateEmail(client *http.Client) (string, error) { +func (s *SocialGenericOAuth) FetchPrivateEmail(client *http.Client) (string, error) { type Record struct { Email string `json:"email"` Primary bool `json:"primary"` @@ -115,7 +118,7 @@ func (s *GenericOAuth) FetchPrivateEmail(client *http.Client) (string, error) { return email, nil } -func (s *GenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, error) { +func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, error) { type Record struct { Id int `json:"id"` } @@ -140,7 +143,7 @@ func (s *GenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, error) return ids, nil } -func (s *GenericOAuth) FetchOrganizations(client *http.Client) ([]string, error) { +func (s *SocialGenericOAuth) FetchOrganizations(client *http.Client) ([]string, error) { type Record struct { Login string `json:"login"` } @@ -165,53 +168,50 @@ func (s *GenericOAuth) FetchOrganizations(client *http.Client) ([]string, error) return logins, nil } -func (s *GenericOAuth) UserInfo(client *http.Client) (*BasicUserInfo, error) { - var data struct { - Name string `json:"name"` - DisplayName string `json:"display_name"` - Login string `json:"login"` - Username string `json:"username"` - Email string `json:"email"` - Attributes map[string][]string `json:"attributes"` - } +type UserInfoJson struct { + Name string `json:"name"` + DisplayName string `json:"display_name"` + Login string `json:"login"` + Username string `json:"username"` + Email string `json:"email"` + Upn string `json:"upn"` + Attributes map[string][]string `json:"attributes"` +} - response, err := HttpGet(client, s.apiUrl) - if err != nil { - return nil, fmt.Errorf("Error getting user info: %s", err) - } +func (s *SocialGenericOAuth) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) { + var data UserInfoJson - err = json.Unmarshal(response.Body, &data) - if err != nil { - return nil, fmt.Errorf("Error getting user info: %s", err) - } - - userInfo := &BasicUserInfo{ - Name: data.Name, - Login: data.Login, - Email: data.Email, - } - - if userInfo.Email == "" && data.Attributes["email:primary"] != nil { - userInfo.Email = data.Attributes["email:primary"][0] - } - - if userInfo.Email == "" { - userInfo.Email, err = s.FetchPrivateEmail(client) + if s.extractToken(&data, token) != true { + response, err := HttpGet(client, s.apiUrl) if err != nil { - return nil, err + return nil, fmt.Errorf("Error getting user info: %s", err) + } + + err = json.Unmarshal(response.Body, &data) + if err != nil { + return nil, fmt.Errorf("Error decoding user info JSON: %s", err) } } - if userInfo.Name == "" && data.DisplayName != "" { - userInfo.Name = data.DisplayName + name, err := s.extractName(data) + if err != nil { + return nil, err } - if userInfo.Login == "" && data.Username != "" { - userInfo.Login = data.Username + email, err := s.extractEmail(data, client) + if err != nil { + return nil, err } - if userInfo.Login == "" { - userInfo.Login = data.Email + login, err := s.extractLogin(data, email) + if err != nil { + return nil, err + } + + userInfo := &BasicUserInfo{ + Name: name, + Login: login, + Email: email, } if !s.IsTeamMember(client) { @@ -224,3 +224,76 @@ func (s *GenericOAuth) UserInfo(client *http.Client) (*BasicUserInfo, error) { return userInfo, nil } + +func (s *SocialGenericOAuth) extractToken(data *UserInfoJson, token *oauth2.Token) bool { + idToken := token.Extra("id_token") + if idToken == nil { + s.log.Debug("No id_token found", "token", token) + return false + } + + jwtRegexp := regexp.MustCompile("^([-_a-zA-Z0-9]+)[.]([-_a-zA-Z0-9]+)[.]([-_a-zA-Z0-9]+)$") + matched := jwtRegexp.FindStringSubmatch(idToken.(string)) + if matched == nil { + s.log.Debug("id_token is not in JWT format", "id_token", idToken.(string)) + return false + } + + payload, err := base64.RawURLEncoding.DecodeString(matched[2]) + if err != nil { + s.log.Error("Error base64 decoding id_token", "raw_payload", matched[2], "err", err) + return false + } + + err = json.Unmarshal(payload, data) + if err != nil { + s.log.Error("Error decoding id_token JSON", "payload", string(payload), "err", err) + return false + } + + s.log.Debug("Received id_token", "json", string(payload), "data", data) + return true +} + +func (s *SocialGenericOAuth) extractEmail(data UserInfoJson, client *http.Client) (string, error) { + if data.Email != "" { + return data.Email, nil + } + + if data.Attributes["email:primary"] != nil { + return data.Attributes["email:primary"][0], nil + } + + if data.Upn != "" { + emailAddr, emailErr := mail.ParseAddress(data.Upn) + if emailErr == nil { + return emailAddr.Address, nil + } + } + + return s.FetchPrivateEmail(client) +} + +func (s *SocialGenericOAuth) extractLogin(data UserInfoJson, email string) (string, error) { + if data.Login != "" { + return data.Login, nil + } + + if data.Username != "" { + return data.Username, nil + } + + return email, nil +} + +func (s *SocialGenericOAuth) extractName(data UserInfoJson) (string, error) { + if data.Name != "" { + return data.Name, nil + } + + if data.DisplayName != "" { + return data.DisplayName, nil + } + + return "", nil +} diff --git a/pkg/social/github_oauth.go b/pkg/social/github_oauth.go index 7e348e2363a..815c684cf03 100644 --- a/pkg/social/github_oauth.go +++ b/pkg/social/github_oauth.go @@ -12,7 +12,7 @@ import ( ) type SocialGithub struct { - *oauth2.Config + *SocialBase allowedDomains []string allowedOrganizations []string apiUrl string @@ -192,13 +192,12 @@ func (s *SocialGithub) FetchOrganizations(client *http.Client, organizationsUrl return logins, nil } -func (s *SocialGithub) UserInfo(client *http.Client) (*BasicUserInfo, error) { +func (s *SocialGithub) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) { var data struct { - Id int `json:"id"` - Login string `json:"login"` - Email string `json:"email"` - OrganizationsUrl string `json:"organizations_url"` + Id int `json:"id"` + Login string `json:"login"` + Email string `json:"email"` } response, err := HttpGet(client, s.apiUrl) @@ -217,11 +216,13 @@ func (s *SocialGithub) UserInfo(client *http.Client) (*BasicUserInfo, error) { Email: data.Email, } + organizationsUrl := fmt.Sprintf(s.apiUrl + "/orgs") + if !s.IsTeamMember(client) { return nil, ErrMissingTeamMembership } - if !s.IsOrganizationMember(client, data.OrganizationsUrl) { + if !s.IsOrganizationMember(client, organizationsUrl) { return nil, ErrMissingOrganizationMembership } diff --git a/pkg/social/google_oauth.go b/pkg/social/google_oauth.go index c44720fbe21..e9ab08305f6 100644 --- a/pkg/social/google_oauth.go +++ b/pkg/social/google_oauth.go @@ -11,7 +11,7 @@ import ( ) type SocialGoogle struct { - *oauth2.Config + *SocialBase allowedDomains []string hostedDomain string apiUrl string @@ -30,7 +30,7 @@ func (s *SocialGoogle) IsSignupAllowed() bool { return s.allowSignup } -func (s *SocialGoogle) UserInfo(client *http.Client) (*BasicUserInfo, error) { +func (s *SocialGoogle) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) { var data struct { Name string `json:"name"` Email string `json:"email"` diff --git a/pkg/social/grafana_com_oauth.go b/pkg/social/grafana_com_oauth.go index 9cc87d4b41c..d3614520d61 100644 --- a/pkg/social/grafana_com_oauth.go +++ b/pkg/social/grafana_com_oauth.go @@ -11,7 +11,7 @@ import ( ) type SocialGrafanaCom struct { - *oauth2.Config + *SocialBase url string allowedOrganizations []string allowSignup bool @@ -49,7 +49,7 @@ func (s *SocialGrafanaCom) IsOrganizationMember(organizations []OrgRecord) bool return false } -func (s *SocialGrafanaCom) UserInfo(client *http.Client) (*BasicUserInfo, error) { +func (s *SocialGrafanaCom) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) { var data struct { Name string `json:"name"` Login string `json:"username"` diff --git a/pkg/social/social.go b/pkg/social/social.go index d40c0a0c965..b763e2d71b2 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -4,9 +4,11 @@ import ( "net/http" "strings" - "golang.org/x/net/context" + "context" + "golang.org/x/oauth2" + "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -21,7 +23,7 @@ type BasicUserInfo struct { type SocialConnector interface { Type() int - UserInfo(client *http.Client) (*BasicUserInfo, error) + UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) IsEmailAllowed(email string) bool IsSignupAllowed() bool @@ -30,6 +32,11 @@ type SocialConnector interface { Client(ctx context.Context, t *oauth2.Token) *http.Client } +type SocialBase struct { + *oauth2.Config + log log.Logger +} + type Error struct { s string } @@ -90,10 +97,15 @@ func NewOAuthService() { Scopes: info.Scopes, } + logger := log.New("oauth." + name) + // GitHub. if name == "github" { SocialMap["github"] = &SocialGithub{ - Config: &config, + SocialBase: &SocialBase{ + Config: &config, + log: logger, + }, allowedDomains: info.AllowedDomains, apiUrl: info.ApiUrl, allowSignup: info.AllowSignup, @@ -105,7 +117,10 @@ func NewOAuthService() { // Google. if name == "google" { SocialMap["google"] = &SocialGoogle{ - Config: &config, + SocialBase: &SocialBase{ + Config: &config, + log: logger, + }, allowedDomains: info.AllowedDomains, hostedDomain: info.HostedDomain, apiUrl: info.ApiUrl, @@ -115,8 +130,11 @@ func NewOAuthService() { // Generic - Uses the same scheme as Github. if name == "generic_oauth" { - SocialMap["generic_oauth"] = &GenericOAuth{ - Config: &config, + SocialMap["generic_oauth"] = &SocialGenericOAuth{ + SocialBase: &SocialBase{ + Config: &config, + log: logger, + }, allowedDomains: info.AllowedDomains, apiUrl: info.ApiUrl, allowSignup: info.AllowSignup, @@ -138,7 +156,10 @@ func NewOAuthService() { } SocialMap["grafana_com"] = &SocialGrafanaCom{ - Config: &config, + SocialBase: &SocialBase{ + Config: &config, + log: logger, + }, url: setting.GrafanaComUrl, allowSignup: info.AllowSignup, allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()), diff --git a/pkg/tsdb/cloudwatch/credentials.go b/pkg/tsdb/cloudwatch/credentials.go index 784f3b729ac..06848323fbb 100644 --- a/pkg/tsdb/cloudwatch/credentials.go +++ b/pkg/tsdb/cloudwatch/credentials.go @@ -11,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" + "github.com/aws/aws-sdk-go/aws/defaults" "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/cloudwatch" @@ -128,10 +129,10 @@ func remoteCredProvider(sess *session.Session) credentials.Provider { func ecsCredProvider(sess *session.Session, uri string) credentials.Provider { const host = `169.254.170.2` - c := ec2metadata.New(sess) + d := defaults.Get() return endpointcreds.NewProviderClient( - c.Client.Config, - c.Client.Handlers, + *d.Config, + d.Handlers, fmt.Sprintf("http://%s%s", host, uri), func(p *endpointcreds.Provider) { p.ExpiryWindow = 5 * time.Minute }) } @@ -141,6 +142,11 @@ func ec2RoleProvider(sess *session.Session) credentials.Provider { } func (e *CloudWatchExecutor) getDsInfo(region string) *DatasourceInfo { + defaultRegion := e.DataSource.JsonData.Get("defaultRegion").MustString() + if region == "default" { + region = defaultRegion + } + authType := e.DataSource.JsonData.Get("authType").MustString() assumeRoleArn := e.DataSource.JsonData.Get("assumeRoleArn").MustString() accessKey := "" diff --git a/pkg/tsdb/cloudwatch/metric_find_query.go b/pkg/tsdb/cloudwatch/metric_find_query.go index b9d4d5b6a80..c82cff390c3 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query.go +++ b/pkg/tsdb/cloudwatch/metric_find_query.go @@ -3,6 +3,7 @@ package cloudwatch import ( "context" "errors" + "fmt" "reflect" "sort" "strings" @@ -37,6 +38,7 @@ var customMetricsDimensionsMap map[string]map[string]map[string]*CustomMetricsCa func init() { metricsMap = map[string][]string{ + "AWS/AmazonMQ": {"CpuUtilization", "HeapUsage", "NetworkIn", "NetworkOut", "TotalMessageCount", "ConsumerCount", "EnqueueCount", "EnqueueTime", "ExpiredCount", "InflightCount", "DispatchCount", "DequeueCount", "MemoryUsage", "ProducerCount", "QueueSize"}, "AWS/ApiGateway": {"4XXError", "5XXError", "CacheHitCount", "CacheMissCount", "Count", "IntegrationLatency", "Latency"}, "AWS/ApplicationELB": {"ActiveConnectionCount", "ClientTLSNegotiationErrorCount", "HealthyHostCount", "HTTPCode_ELB_4XX_Count", "HTTPCode_ELB_5XX_Count", "HTTPCode_Target_2XX_Count", "HTTPCode_Target_3XX_Count", "HTTPCode_Target_4XX_Count", "HTTPCode_Target_5XX_Count", "IPv6ProcessedBytes", "IPv6RequestCount", "NewConnectionCount", "ProcessedBytes", "RejectedConnectionCount", "RequestCount", "RequestCountPerTarget", "TargetConnectionErrorCount", "TargetResponseTime", "TargetTLSNegotiationErrorCount", "UnHealthyHostCount"}, "AWS/AutoScaling": {"GroupMinSize", "GroupMaxSize", "GroupDesiredCapacity", "GroupInServiceInstances", "GroupPendingInstances", "GroupStandbyInstances", "GroupTerminatingInstances", "GroupTotalInstances"}, @@ -96,16 +98,19 @@ func init() { "AWS/SES": {"Bounce", "Complaint", "Delivery", "Reject", "Send"}, "AWS/SNS": {"NumberOfMessagesPublished", "PublishSize", "NumberOfNotificationsDelivered", "NumberOfNotificationsFailed"}, "AWS/SQS": {"NumberOfMessagesSent", "SentMessageSize", "NumberOfMessagesReceived", "NumberOfEmptyReceives", "NumberOfMessagesDeleted", "ApproximateAgeOfOldestMessage", "ApproximateNumberOfMessagesDelayed", "ApproximateNumberOfMessagesVisible", "ApproximateNumberOfMessagesNotVisible"}, + "AWS/States": {"ExecutionTime", "ExecutionThrottled", "ExecutionsAborted", "ExecutionsFailed", "ExecutionsStarted", "ExecutionsSucceeded", "ExecutionsTimedOut", "ActivityRunTime", "ActivityScheduleTime", "ActivityTime", "ActivitiesFailed", "ActivitiesHeartbeatTimedOut", "ActivitiesScheduled", "ActivitiesScheduled", "ActivitiesSucceeded", "ActivitiesTimedOut", "LambdaFunctionRunTime", "LambdaFunctionScheduleTime", "LambdaFunctionTime", "LambdaFunctionsFailed", "LambdaFunctionsHeartbeatTimedOut", "LambdaFunctionsScheduled", "LambdaFunctionsStarted", "LambdaFunctionsSucceeded", "LambdaFunctionsTimedOut"}, "AWS/StorageGateway": {"CacheHitPercent", "CachePercentUsed", "CachePercentDirty", "CloudBytesDownloaded", "CloudDownloadLatency", "CloudBytesUploaded", "UploadBufferFree", "UploadBufferPercentUsed", "UploadBufferUsed", "QueuedWrites", "ReadBytes", "ReadTime", "TotalCacheSize", "WriteBytes", "WriteTime", "TimeSinceLastRecoveryPoint", "WorkingStorageFree", "WorkingStoragePercentUsed", "WorkingStorageUsed", "CacheHitPercent", "CachePercentUsed", "CachePercentDirty", "ReadBytes", "ReadTime", "WriteBytes", "WriteTime", "QueuedWrites"}, "AWS/SWF": {"DecisionTaskScheduleToStartTime", "DecisionTaskStartToCloseTime", "DecisionTasksCompleted", "StartedDecisionTasksTimedOutOnClose", "WorkflowStartToCloseTime", "WorkflowsCanceled", "WorkflowsCompleted", "WorkflowsContinuedAsNew", "WorkflowsFailed", "WorkflowsTerminated", "WorkflowsTimedOut", "ActivityTaskScheduleToCloseTime", "ActivityTaskScheduleToStartTime", "ActivityTaskStartToCloseTime", "ActivityTasksCanceled", "ActivityTasksCompleted", "ActivityTasksFailed", "ScheduledActivityTasksTimedOutOnClose", "ScheduledActivityTasksTimedOutOnStart", "StartedActivityTasksTimedOutOnClose", "StartedActivityTasksTimedOutOnHeartbeat"}, "AWS/VPN": {"TunnelState", "TunnelDataIn", "TunnelDataOut"}, + "Rekognition": {"SuccessfulRequestCount", "ThrottledCount", "ResponseTime", "DetectedFaceCount", "DetectedLabelCount", "ServerErrorCount", "UserErrorCount"}, "WAF": {"AllowedRequests", "BlockedRequests", "CountedRequests"}, "AWS/WorkSpaces": {"Available", "Unhealthy", "ConnectionAttempt", "ConnectionSuccess", "ConnectionFailure", "SessionLaunchTime", "InSessionLatency", "SessionDisconnect"}, "KMS": {"SecondsUntilKeyMaterialExpiration"}, } dimensionsMap = map[string][]string{ + "AWS/AmazonMQ": {"Broker", "Topic", "Queue"}, "AWS/ApiGateway": {"ApiName", "Method", "Resource", "Stage"}, "AWS/ApplicationELB": {"LoadBalancer", "TargetGroup", "AvailabilityZone"}, "AWS/AutoScaling": {"AutoScalingGroupName"}, @@ -127,7 +132,7 @@ func init() { "AWS/Events": {"RuleName"}, "AWS/Firehose": {"DeliveryStreamName"}, "AWS/IoT": {"Protocol"}, - "AWS/Kinesis": {"StreamName", "ShardID"}, + "AWS/Kinesis": {"StreamName", "ShardId"}, "AWS/KinesisAnalytics": {"Flow", "Id", "Application"}, "AWS/Lambda": {"FunctionName", "Resource", "Version", "Alias"}, "AWS/Logs": {"LogGroupName", "DestinationType", "FilterName"}, @@ -142,9 +147,11 @@ func init() { "AWS/SES": {}, "AWS/SNS": {"Application", "Platform", "TopicName"}, "AWS/SQS": {"QueueName"}, + "AWS/States": {"StateMachineArn", "ActivityArn", "LambdaFunctionArn"}, "AWS/StorageGateway": {"GatewayId", "GatewayName", "VolumeId"}, "AWS/SWF": {"Domain", "WorkflowTypeName", "WorkflowTypeVersion", "ActivityTypeName", "ActivityTypeVersion"}, "AWS/VPN": {"VpnId", "TunnelIpAddress"}, + "Rekognition": {}, "WAF": {"Rule", "WebACL"}, "AWS/WorkSpaces": {"DirectoryId", "WorkspaceId"}, "KMS": {"KeyId"}, @@ -185,18 +192,6 @@ func (e *CloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryCo data, err = e.handleGetEbsVolumeIds(ctx, parameters, queryContext) break case "ec2_instance_attribute": - region := parameters.Get("region").MustString() - dsInfo := e.getDsInfo(region) - cfg, err := e.getAwsConfig(dsInfo) - if err != nil { - return nil, errors.New("Failed to call ec2:DescribeInstances") - } - sess, err := session.NewSession(cfg) - if err != nil { - return nil, errors.New("Failed to call ec2:DescribeInstances") - } - e.ec2Svc = ec2.New(sess, cfg) - data, err = e.handleGetEc2InstanceAttribute(ctx, parameters, queryContext) break } @@ -224,6 +219,21 @@ func transformToTable(data []suggestData, result *tsdb.QueryResult) { result.Meta.Set("rowCount", len(data)) } +func parseMultiSelectValue(input string) []string { + trimmedInput := strings.TrimSpace(input) + + if strings.HasPrefix(trimmedInput, "{") { + values := strings.Split(strings.TrimRight(strings.TrimLeft(trimmedInput, "{"), "}"), ",") + trimValues := make([]string, len(values)) + for i, v := range values { + trimValues[i] = strings.TrimSpace(v) + } + return trimValues + } else { + return []string{trimmedInput} + } +} + // Whenever this list is updated, frontend list should also be updated. // Please update the region list in public/app/plugins/datasource/cloudwatch/partials/config.html func (e *CloudWatchExecutor) handleGetRegions(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) { @@ -362,19 +372,44 @@ func (e *CloudWatchExecutor) handleGetDimensionValues(ctx context.Context, param return result, nil } +func (e *CloudWatchExecutor) ensureClientSession(region string) error { + if e.ec2Svc == nil { + dsInfo := e.getDsInfo(region) + cfg, err := e.getAwsConfig(dsInfo) + if err != nil { + return fmt.Errorf("Failed to call ec2:getAwsConfig, %v", err) + } + sess, err := session.NewSession(cfg) + if err != nil { + return fmt.Errorf("Failed to call ec2:NewSession, %v", err) + } + e.ec2Svc = ec2.New(sess, cfg) + } + return nil +} + func (e *CloudWatchExecutor) handleGetEbsVolumeIds(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) { region := parameters.Get("region").MustString() instanceId := parameters.Get("instanceId").MustString() - instanceIds := []*string{aws.String(instanceId)} + err := e.ensureClientSession(region) + if err != nil { + return nil, err + } + + instanceIds := aws.StringSlice(parseMultiSelectValue(instanceId)) instances, err := e.ec2DescribeInstances(region, nil, instanceIds) if err != nil { return nil, err } result := make([]suggestData, 0) - for _, mapping := range instances.Reservations[0].Instances[0].BlockDeviceMappings { - result = append(result, suggestData{Text: *mapping.Ebs.VolumeId, Value: *mapping.Ebs.VolumeId}) + for _, reservation := range instances.Reservations { + for _, instance := range reservation.Instances { + for _, mapping := range instance.BlockDeviceMappings { + result = append(result, suggestData{Text: *mapping.Ebs.VolumeId, Value: *mapping.Ebs.VolumeId}) + } + } } return result, nil @@ -401,6 +436,11 @@ func (e *CloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context, } } + err := e.ensureClientSession(region) + if err != nil { + return nil, err + } + instances, err := e.ec2DescribeInstances(region, filters, nil) if err != nil { return nil, err @@ -476,7 +516,7 @@ func (e *CloudWatchExecutor) cloudwatchListMetrics(region string, namespace stri return !lastPage }) if err != nil { - return nil, errors.New("Failed to call cloudwatch:ListMetrics") + return nil, fmt.Errorf("Failed to call cloudwatch:ListMetrics, %v", err) } return &resp, nil diff --git a/pkg/tsdb/cloudwatch/metric_find_query_test.go b/pkg/tsdb/cloudwatch/metric_find_query_test.go index 255b343a33a..bf87e7b7d41 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query_test.go +++ b/pkg/tsdb/cloudwatch/metric_find_query_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/bmizerany/assert" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/tsdb" . "github.com/smartystreets/goconvey/convey" @@ -114,4 +115,85 @@ func TestCloudWatchMetrics(t *testing.T) { So(result[0].Text, ShouldEqual, "i-12345678") }) }) + + Convey("When calling handleGetEbsVolumeIds", t, func() { + + executor := &CloudWatchExecutor{ + ec2Svc: mockedEc2{Resp: ec2.DescribeInstancesOutput{ + Reservations: []*ec2.Reservation{ + { + Instances: []*ec2.Instance{ + { + InstanceId: aws.String("i-1"), + BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{ + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-1-1")}}, + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-1-2")}}, + }, + }, + { + InstanceId: aws.String("i-2"), + BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{ + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-2-1")}}, + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-2-2")}}, + }, + }, + }, + }, + { + Instances: []*ec2.Instance{ + { + InstanceId: aws.String("i-3"), + BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{ + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-3-1")}}, + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-3-2")}}, + }, + }, + { + InstanceId: aws.String("i-4"), + BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{ + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-4-1")}}, + {Ebs: &ec2.EbsInstanceBlockDevice{VolumeId: aws.String("vol-4-2")}}, + }, + }, + }, + }, + }, + }}, + } + + json := simplejson.New() + json.Set("region", "us-east-1") + json.Set("instanceId", "{i-1, i-2, i-3, i-4}") + result, _ := executor.handleGetEbsVolumeIds(context.Background(), json, &tsdb.TsdbQuery{}) + + Convey("Should return all 8 VolumeIds", func() { + So(len(result), ShouldEqual, 8) + So(result[0].Text, ShouldEqual, "vol-1-1") + So(result[1].Text, ShouldEqual, "vol-1-2") + So(result[2].Text, ShouldEqual, "vol-2-1") + So(result[3].Text, ShouldEqual, "vol-2-2") + So(result[4].Text, ShouldEqual, "vol-3-1") + So(result[5].Text, ShouldEqual, "vol-3-2") + So(result[6].Text, ShouldEqual, "vol-4-1") + So(result[7].Text, ShouldEqual, "vol-4-2") + }) + }) +} + +func TestParseMultiSelectValue(t *testing.T) { + + var values []string + + values = parseMultiSelectValue(" i-someInstance ") + assert.Equal(t, []string{"i-someInstance"}, values) + + values = parseMultiSelectValue("{i-05}") + assert.Equal(t, []string{"i-05"}, values) + + values = parseMultiSelectValue(" {i-01, i-03, i-04} ") + assert.Equal(t, []string{"i-01", "i-03", "i-04"}, values) + + values = parseMultiSelectValue("i-{01}") + assert.Equal(t, []string{"i-{01}"}, values) + } diff --git a/pkg/tsdb/influxdb/query.go b/pkg/tsdb/influxdb/query.go index 499f446e9f0..0a16a507877 100644 --- a/pkg/tsdb/influxdb/query.go +++ b/pkg/tsdb/influxdb/query.go @@ -70,7 +70,7 @@ func (query *Query) renderTags() []string { } else if tag.Operator == "<" || tag.Operator == ">" { textValue = tag.Value } else { - textValue = fmt.Sprintf("'%s'", tag.Value) + textValue = fmt.Sprintf("'%s'", strings.Replace(tag.Value, `\`, `\\`, -1)) } res = append(res, fmt.Sprintf(`%s"%s" %s %s`, str, tag.Key, tag.Operator, textValue)) diff --git a/pkg/tsdb/influxdb/query_test.go b/pkg/tsdb/influxdb/query_test.go index 4a620539a26..f1270560269 100644 --- a/pkg/tsdb/influxdb/query_test.go +++ b/pkg/tsdb/influxdb/query_test.go @@ -170,6 +170,12 @@ func TestInfluxdbQueryBuilder(t *testing.T) { So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'value'`) }) + Convey("can escape backslashes when rendering string tags", func() { + query := &Query{Tags: []*Tag{{Operator: "=", Value: `C:\test\`, Key: "key"}}} + + So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'C:\\test\\'`) + }) + Convey("can render regular measurement", func() { query := &Query{Measurement: `apa`, Policy: "policy"} diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go index cbda7c97515..dee7289af7f 100644 --- a/pkg/tsdb/models.go +++ b/pkg/tsdb/models.go @@ -14,9 +14,7 @@ type TsdbQuery struct { type Query struct { RefId string Model *simplejson.Json - Depends []string DataSource *models.DataSource - Results []*TimeSeries MaxDataPoints int64 IntervalMs int64 } diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index ddd90b77642..f3060e235e5 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -6,8 +6,8 @@ import ( "database/sql" "fmt" "math" + "reflect" "strconv" - "time" "github.com/go-sql-driver/mysql" @@ -74,24 +74,36 @@ func (e MysqlQueryEndpoint) transformToTable(query *tsdb.Query, rows *core.Rows, table.Columns[i].Text = name } - columnTypes, err := rows.ColumnTypes() - if err != nil { - return err - } - rowLimit := 1000000 rowCount := 0 + timeIndex := -1 + + // check if there is a column named time + for i, col := range columnNames { + switch col { + case "time_sec": + timeIndex = i + } + } for ; rows.Next(); rowCount++ { if rowCount > rowLimit { return fmt.Errorf("MySQL query row limit exceeded, limit %d", rowLimit) } - values, err := e.getTypedRowData(columnTypes, rows) + values, err := e.getTypedRowData(rows) if err != nil { return err } + // for annotations, convert to epoch + if timeIndex != -1 { + switch value := values[timeIndex].(type) { + case time.Time: + values[timeIndex] = float64(value.UnixNano() / 1e9) + } + } + table.Rows = append(table.Rows, values) } @@ -100,60 +112,20 @@ func (e MysqlQueryEndpoint) transformToTable(query *tsdb.Query, rows *core.Rows, return nil } -func (e MysqlQueryEndpoint) getTypedRowData(types []*sql.ColumnType, rows *core.Rows) (tsdb.RowValues, error) { +func (e MysqlQueryEndpoint) getTypedRowData(rows *core.Rows) (tsdb.RowValues, error) { + types, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + values := make([]interface{}, len(types)) - for i, stype := range types { - e.log.Debug("type", "type", stype) - switch stype.DatabaseTypeName() { - case mysql.FieldTypeNameTiny: - values[i] = new(int8) - case mysql.FieldTypeNameInt24: - values[i] = new(int32) - case mysql.FieldTypeNameShort: - values[i] = new(int16) - case mysql.FieldTypeNameVarString: - values[i] = new(string) - case mysql.FieldTypeNameVarChar: - values[i] = new(string) - case mysql.FieldTypeNameLong: - values[i] = new(int) - case mysql.FieldTypeNameLongLong: - values[i] = new(int64) - case mysql.FieldTypeNameDouble: - values[i] = new(float64) - case mysql.FieldTypeNameDecimal: - values[i] = new(float32) - case mysql.FieldTypeNameNewDecimal: - values[i] = new(float64) - case mysql.FieldTypeNameFloat: - values[i] = new(float64) - case mysql.FieldTypeNameTimestamp: - values[i] = new(time.Time) - case mysql.FieldTypeNameDateTime: - values[i] = new(time.Time) - case mysql.FieldTypeNameTime: - values[i] = new(string) - case mysql.FieldTypeNameYear: - values[i] = new(int16) - case mysql.FieldTypeNameNULL: - values[i] = nil - case mysql.FieldTypeNameBit: + for i := range values { + scanType := types[i].ScanType() + values[i] = reflect.New(scanType).Interface() + + if types[i].DatabaseTypeName() == "BIT" { values[i] = new([]byte) - case mysql.FieldTypeNameBLOB: - values[i] = new(string) - case mysql.FieldTypeNameTinyBLOB: - values[i] = new(string) - case mysql.FieldTypeNameMediumBLOB: - values[i] = new(string) - case mysql.FieldTypeNameLongBLOB: - values[i] = new(string) - case mysql.FieldTypeNameString: - values[i] = new(string) - case mysql.FieldTypeNameDate: - values[i] = new(string) - default: - return nil, fmt.Errorf("Database type %s not supported", stype.DatabaseTypeName()) } } @@ -161,14 +133,54 @@ func (e MysqlQueryEndpoint) getTypedRowData(types []*sql.ColumnType, rows *core. return nil, err } + for i := 0; i < len(types); i++ { + typeName := reflect.ValueOf(values[i]).Type().String() + + switch typeName { + case "*sql.RawBytes": + values[i] = string(*values[i].(*sql.RawBytes)) + case "*mysql.NullTime": + sqlTime := (*values[i].(*mysql.NullTime)) + if sqlTime.Valid { + values[i] = sqlTime.Time + } else { + values[i] = nil + } + case "*sql.NullInt64": + nullInt64 := (*values[i].(*sql.NullInt64)) + if nullInt64.Valid { + values[i] = nullInt64.Int64 + } else { + values[i] = nil + } + case "*sql.NullFloat64": + nullFloat64 := (*values[i].(*sql.NullFloat64)) + if nullFloat64.Valid { + values[i] = nullFloat64.Float64 + } else { + values[i] = nil + } + } + + if types[i].DatabaseTypeName() == "DECIMAL" { + f, err := strconv.ParseFloat(values[i].(string), 64) + + if err == nil { + values[i] = f + } else { + values[i] = nil + } + } + } + return values, nil } func (e MysqlQueryEndpoint) transformToTimeSeries(query *tsdb.Query, rows *core.Rows, result *tsdb.QueryResult, tsdbQuery *tsdb.TsdbQuery) error { pointsBySeries := make(map[string]*tsdb.TimeSeries) seriesByQueryOrder := list.New() - columnNames, err := rows.Columns() + columnNames, err := rows.Columns() if err != nil { return err } diff --git a/pkg/tsdb/mysql/mysql_test.go b/pkg/tsdb/mysql/mysql_test.go index 55def0b4129..fe2c82223d2 100644 --- a/pkg/tsdb/mysql/mysql_test.go +++ b/pkg/tsdb/mysql/mysql_test.go @@ -30,19 +30,19 @@ func TestMySQL(t *testing.T) { defer sess.Close() sql := "CREATE TABLE `mysql_types` (" - sql += "`atinyint` tinyint(1)," - sql += "`avarchar` varchar(3)," + sql += "`atinyint` tinyint(1) NOT NULL," + sql += "`avarchar` varchar(3) NOT NULL," sql += "`achar` char(3)," - sql += "`amediumint` mediumint," - sql += "`asmallint` smallint," - sql += "`abigint` bigint," - sql += "`aint` int(11)," + sql += "`amediumint` mediumint NOT NULL," + sql += "`asmallint` smallint NOT NULL," + sql += "`abigint` bigint NOT NULL," + sql += "`aint` int(11) NOT NULL," sql += "`adouble` double(10,2)," sql += "`anewdecimal` decimal(10,2)," - sql += "`afloat` float(10,2)," + sql += "`afloat` float(10,2) NOT NULL," sql += "`atimestamp` timestamp NOT NULL," - sql += "`adatetime` datetime," - sql += "`atime` time," + sql += "`adatetime` datetime NOT NULL," + sql += "`atime` time NOT NULL," // sql += "`ayear` year," // Crashes xorm when running cleandb sql += "`abit` bit(1)," sql += "`atinytext` tinytext," @@ -55,7 +55,12 @@ func TestMySQL(t *testing.T) { sql += "`alongblob` longblob," sql += "`aenum` enum('val1', 'val2')," sql += "`aset` set('a', 'b', 'c', 'd')," - sql += "`adate` date" + sql += "`adate` date," + sql += "`time_sec` datetime(6)," + sql += "`aintnull` int(11)," + sql += "`afloatnull` float(10,2)," + sql += "`avarcharnull` varchar(3)," + sql += "`adecimalnull` decimal(10,2)" sql += ") ENGINE=InnoDB DEFAULT CHARSET=latin1;" _, err := sess.Exec(sql) So(err, ShouldBeNil) @@ -64,11 +69,11 @@ func TestMySQL(t *testing.T) { sql += "(`atinyint`, `avarchar`, `achar`, `amediumint`, `asmallint`, `abigint`, `aint`, `adouble`, " sql += "`anewdecimal`, `afloat`, `adatetime`, `atimestamp`, `atime`, `abit`, `atinytext`, " sql += "`atinyblob`, `atext`, `ablob`, `amediumtext`, `amediumblob`, `alongtext`, `alongblob`, " - sql += "`aenum`, `aset`, `adate`) " + sql += "`aenum`, `aset`, `adate`, `time_sec`) " sql += "VALUES(1, 'abc', 'def', 1, 10, 100, 1420070400, 1.11, " sql += "2.22, 3.33, now(), current_timestamp(), '11:11:11', 1, 'tinytext', " sql += "'tinyblob', 'text', 'blob', 'mediumtext', 'mediumblob', 'longtext', 'longblob', " - sql += "'val2', 'a,b', curdate());" + sql += "'val2', 'a,b', curdate(), '2018-01-01 00:01:01.123456');" _, err = sess.Exec(sql) So(err, ShouldBeNil) @@ -90,32 +95,38 @@ func TestMySQL(t *testing.T) { So(err, ShouldBeNil) column := queryResult.Tables[0].Rows[0] + So(*column[0].(*int8), ShouldEqual, 1) - So(*column[1].(*string), ShouldEqual, "abc") - So(*column[2].(*string), ShouldEqual, "def") + So(column[1].(string), ShouldEqual, "abc") + So(column[2].(string), ShouldEqual, "def") So(*column[3].(*int32), ShouldEqual, 1) So(*column[4].(*int16), ShouldEqual, 10) So(*column[5].(*int64), ShouldEqual, 100) - So(*column[6].(*int), ShouldEqual, 1420070400) - So(*column[7].(*float64), ShouldEqual, 1.11) - So(*column[8].(*float64), ShouldEqual, 2.22) - So(*column[9].(*float64), ShouldEqual, 3.33) + So(*column[6].(*int32), ShouldEqual, 1420070400) + So(column[7].(float64), ShouldEqual, 1.11) + So(column[8].(float64), ShouldEqual, 2.22) + So(*column[9].(*float32), ShouldEqual, 3.33) _, offset := time.Now().Zone() - So((*column[10].(*time.Time)), ShouldHappenWithin, time.Duration(10*time.Second), time.Now().Add(time.Duration(offset)*time.Second)) - So(*column[11].(*time.Time), ShouldHappenWithin, time.Duration(10*time.Second), time.Now().Add(time.Duration(offset)*time.Second)) - So(*column[12].(*string), ShouldEqual, "11:11:11") + So(column[10].(time.Time), ShouldHappenWithin, time.Duration(10*time.Second), time.Now().Add(time.Duration(offset)*time.Second)) + So(column[11].(time.Time), ShouldHappenWithin, time.Duration(10*time.Second), time.Now().Add(time.Duration(offset)*time.Second)) + So(column[12].(string), ShouldEqual, "11:11:11") So(*column[13].(*[]byte), ShouldHaveSameTypeAs, []byte{1}) - So(*column[14].(*string), ShouldEqual, "tinytext") - So(*column[15].(*string), ShouldEqual, "tinyblob") - So(*column[16].(*string), ShouldEqual, "text") - So(*column[17].(*string), ShouldEqual, "blob") - So(*column[18].(*string), ShouldEqual, "mediumtext") - So(*column[19].(*string), ShouldEqual, "mediumblob") - So(*column[20].(*string), ShouldEqual, "longtext") - So(*column[21].(*string), ShouldEqual, "longblob") - So(*column[22].(*string), ShouldEqual, "val2") - So(*column[23].(*string), ShouldEqual, "a,b") - So(*column[24].(*string), ShouldEqual, time.Now().Format("2006-01-02T00:00:00Z")) + So(column[14].(string), ShouldEqual, "tinytext") + So(column[15].(string), ShouldEqual, "tinyblob") + So(column[16].(string), ShouldEqual, "text") + So(column[17].(string), ShouldEqual, "blob") + So(column[18].(string), ShouldEqual, "mediumtext") + So(column[19].(string), ShouldEqual, "mediumblob") + So(column[20].(string), ShouldEqual, "longtext") + So(column[21].(string), ShouldEqual, "longblob") + So(column[22].(string), ShouldEqual, "val2") + So(column[23].(string), ShouldEqual, "a,b") + So(column[24].(time.Time).Format("2006-01-02T00:00:00Z"), ShouldEqual, time.Now().Format("2006-01-02T00:00:00Z")) + So(column[25].(float64), ShouldEqual, 1514764861) + So(column[26], ShouldEqual, nil) + So(column[27], ShouldEqual, nil) + So(column[28], ShouldEqual, "") + So(column[29], ShouldEqual, nil) }) }) } diff --git a/pkg/tsdb/postgres/postgres.go b/pkg/tsdb/postgres/postgres.go index 067b173ad5a..21ce006edb6 100644 --- a/pkg/tsdb/postgres/postgres.go +++ b/pkg/tsdb/postgres/postgres.go @@ -233,14 +233,14 @@ func (e PostgresQueryEndpoint) transformToTimeSeries(query *tsdb.Query, rows *co case time.Time: timestamp = float64(columnValue.UnixNano() / 1e6) default: - return fmt.Errorf("Invalid type for column time, must be of type timestamp or unix timestamp") + return fmt.Errorf("Invalid type for column time, must be of type timestamp or unix timestamp, got: %T %v", columnValue, columnValue) } if metricIndex >= 0 { if columnValue, ok := values[metricIndex].(string); ok == true { metric = columnValue } else { - return fmt.Errorf("Column metric must be of type char,varchar or text") + return fmt.Errorf("Column metric must be of type char,varchar or text, got: %T %v", values[metricIndex], values[metricIndex]) } } diff --git a/pkg/tsdb/prometheus/prometheus.go b/pkg/tsdb/prometheus/prometheus.go index e798b92c6fe..1186fccbbf9 100644 --- a/pkg/tsdb/prometheus/prometheus.go +++ b/pkg/tsdb/prometheus/prometheus.go @@ -83,41 +83,48 @@ func (e *PrometheusExecutor) getClient(dsInfo *models.DataSource) (apiv1.API, er } func (e *PrometheusExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) { - result := &tsdb.Response{} + result := &tsdb.Response{ + Results: map[string]*tsdb.QueryResult{}, + } client, err := e.getClient(dsInfo) if err != nil { return nil, err } - query, err := parseQuery(dsInfo, tsdbQuery.Queries, tsdbQuery) + querys, err := parseQuery(dsInfo, tsdbQuery.Queries, tsdbQuery) if err != nil { return nil, err } - timeRange := apiv1.Range{ - Start: query.Start, - End: query.End, - Step: query.Step, + for _, query := range querys { + timeRange := apiv1.Range{ + Start: query.Start, + End: query.End, + Step: query.Step, + } + + plog.Debug("Sending query", "start", timeRange.Start, "end", timeRange.End, "step", timeRange.Step, "query", query.Expr) + + span, ctx := opentracing.StartSpanFromContext(ctx, "alerting.prometheus") + span.SetTag("expr", query.Expr) + span.SetTag("start_unixnano", int64(query.Start.UnixNano())) + span.SetTag("stop_unixnano", int64(query.End.UnixNano())) + defer span.Finish() + + value, err := client.QueryRange(ctx, query.Expr, timeRange) + + if err != nil { + return nil, err + } + + queryResult, err := parseResponse(value, query) + if err != nil { + return nil, err + } + result.Results[query.RefId] = queryResult } - span, ctx := opentracing.StartSpanFromContext(ctx, "alerting.prometheus") - span.SetTag("expr", query.Expr) - span.SetTag("start_unixnano", int64(query.Start.UnixNano())) - span.SetTag("stop_unixnano", int64(query.End.UnixNano())) - defer span.Finish() - - value, err := client.QueryRange(ctx, query.Expr, timeRange) - - if err != nil { - return nil, err - } - - queryResult, err := parseResponse(value, query) - if err != nil { - return nil, err - } - result.Results = queryResult return result, nil } @@ -140,51 +147,54 @@ func formatLegend(metric model.Metric, query *PrometheusQuery) string { return string(result) } -func parseQuery(dsInfo *models.DataSource, queries []*tsdb.Query, queryContext *tsdb.TsdbQuery) (*PrometheusQuery, error) { - queryModel := queries[0] +func parseQuery(dsInfo *models.DataSource, queries []*tsdb.Query, queryContext *tsdb.TsdbQuery) ([]*PrometheusQuery, error) { + qs := []*PrometheusQuery{} + for _, queryModel := range queries { + expr, err := queryModel.Model.Get("expr").String() + if err != nil { + return nil, err + } - expr, err := queryModel.Model.Get("expr").String() - if err != nil { - return nil, err + format := queryModel.Model.Get("legendFormat").MustString("") + + start, err := queryContext.TimeRange.ParseFrom() + if err != nil { + return nil, err + } + + end, err := queryContext.TimeRange.ParseTo() + if err != nil { + return nil, err + } + + dsInterval, err := tsdb.GetIntervalFrom(dsInfo, queryModel.Model, time.Second*15) + if err != nil { + return nil, err + } + + intervalFactor := queryModel.Model.Get("intervalFactor").MustInt64(1) + interval := intervalCalculator.Calculate(queryContext.TimeRange, dsInterval) + step := time.Duration(int64(interval.Value) * intervalFactor) + + qs = append(qs, &PrometheusQuery{ + Expr: expr, + Step: step, + LegendFormat: format, + Start: start, + End: end, + RefId: queryModel.RefId, + }) } - format := queryModel.Model.Get("legendFormat").MustString("") - - start, err := queryContext.TimeRange.ParseFrom() - if err != nil { - return nil, err - } - - end, err := queryContext.TimeRange.ParseTo() - if err != nil { - return nil, err - } - - dsInterval, err := tsdb.GetIntervalFrom(dsInfo, queryModel.Model, time.Second*15) - if err != nil { - return nil, err - } - - intervalFactor := queryModel.Model.Get("intervalFactor").MustInt64(1) - interval := intervalCalculator.Calculate(queryContext.TimeRange, dsInterval) - step := time.Duration(int64(interval.Value) * intervalFactor) - - return &PrometheusQuery{ - Expr: expr, - Step: step, - LegendFormat: format, - Start: start, - End: end, - }, nil + return qs, nil } -func parseResponse(value model.Value, query *PrometheusQuery) (map[string]*tsdb.QueryResult, error) { - queryResults := make(map[string]*tsdb.QueryResult) +func parseResponse(value model.Value, query *PrometheusQuery) (*tsdb.QueryResult, error) { queryRes := tsdb.NewQueryResult() data, ok := value.(model.Matrix) if !ok { - return queryResults, fmt.Errorf("Unsupported result format: %s", value.Type().String()) + return queryRes, fmt.Errorf("Unsupported result format: %s", value.Type().String()) } for _, v := range data { @@ -204,6 +214,5 @@ func parseResponse(value model.Value, query *PrometheusQuery) (map[string]*tsdb. queryRes.Series = append(queryRes.Series, &series) } - queryResults["A"] = queryRes - return queryResults, nil + return queryRes, nil } diff --git a/pkg/tsdb/prometheus/prometheus_test.go b/pkg/tsdb/prometheus/prometheus_test.go index c551ab98112..efb42318214 100644 --- a/pkg/tsdb/prometheus/prometheus_test.go +++ b/pkg/tsdb/prometheus/prometheus_test.go @@ -60,9 +60,10 @@ func TestPrometheus(t *testing.T) { Convey("with 48h time range", func() { queryContext.TimeRange = tsdb.NewTimeRange("12h", "now") - model, err := parseQuery(dsInfo, queryModels, queryContext) - + models, err := parseQuery(dsInfo, queryModels, queryContext) So(err, ShouldBeNil) + + model := models[0] So(model.Step, ShouldEqual, time.Second*30) }) }) @@ -83,18 +84,22 @@ func TestPrometheus(t *testing.T) { Convey("with 48h time range", func() { queryContext.TimeRange = tsdb.NewTimeRange("48h", "now") - model, err := parseQuery(dsInfo, queryModels, queryContext) + models, err := parseQuery(dsInfo, queryModels, queryContext) So(err, ShouldBeNil) + + model := models[0] So(model.Step, ShouldEqual, time.Minute*2) }) Convey("with 1h time range", func() { queryContext.TimeRange = tsdb.NewTimeRange("1h", "now") - model, err := parseQuery(dsInfo, queryModels, queryContext) + models, err := parseQuery(dsInfo, queryModels, queryContext) So(err, ShouldBeNil) + + model := models[0] So(model.Step, ShouldEqual, time.Second*15) }) }) @@ -116,9 +121,11 @@ func TestPrometheus(t *testing.T) { Convey("with 48h time range", func() { queryContext.TimeRange = tsdb.NewTimeRange("48h", "now") - model, err := parseQuery(dsInfo, queryModels, queryContext) + models, err := parseQuery(dsInfo, queryModels, queryContext) So(err, ShouldBeNil) + + model := models[0] So(model.Step, ShouldEqual, time.Minute*20) }) }) @@ -139,9 +146,11 @@ func TestPrometheus(t *testing.T) { Convey("with 48h time range", func() { queryContext.TimeRange = tsdb.NewTimeRange("48h", "now") - model, err := parseQuery(dsInfo, queryModels, queryContext) + models, err := parseQuery(dsInfo, queryModels, queryContext) So(err, ShouldBeNil) + + model := models[0] So(model.Step, ShouldEqual, time.Minute*2) }) }) diff --git a/pkg/tsdb/prometheus/types.go b/pkg/tsdb/prometheus/types.go index 8ed665d0123..cf8c16682e8 100644 --- a/pkg/tsdb/prometheus/types.go +++ b/pkg/tsdb/prometheus/types.go @@ -8,4 +8,5 @@ type PrometheusQuery struct { LegendFormat string Start time.Time End time.Time + RefId string } diff --git a/pkg/tsdb/time_range.go b/pkg/tsdb/time_range.go index cf6bc6a5048..fd797bf731a 100644 --- a/pkg/tsdb/time_range.go +++ b/pkg/tsdb/time_range.go @@ -11,14 +11,14 @@ func NewTimeRange(from, to string) *TimeRange { return &TimeRange{ From: from, To: to, - Now: time.Now(), + now: time.Now(), } } type TimeRange struct { From string To string - Now time.Time + now time.Time } func (tr *TimeRange) GetFromAsMsEpoch() int64 { @@ -65,12 +65,12 @@ func (tr *TimeRange) ParseFrom() (time.Time, error) { return time.Time{}, err } - return tr.Now.Add(diff), nil + return tr.now.Add(diff), nil } func (tr *TimeRange) ParseTo() (time.Time, error) { if tr.To == "now" { - return tr.Now, nil + return tr.now, nil } else if strings.HasPrefix(tr.To, "now-") { withoutNow := strings.Replace(tr.To, "now-", "", 1) @@ -79,7 +79,7 @@ func (tr *TimeRange) ParseTo() (time.Time, error) { return time.Time{}, nil } - return tr.Now.Add(diff), nil + return tr.now.Add(diff), nil } if res, ok := tryParseUnixMsEpoch(tr.To); ok { diff --git a/pkg/tsdb/time_range_test.go b/pkg/tsdb/time_range_test.go index 5d89e3977b8..37ced412e4d 100644 --- a/pkg/tsdb/time_range_test.go +++ b/pkg/tsdb/time_range_test.go @@ -16,7 +16,7 @@ func TestTimeRange(t *testing.T) { tr := TimeRange{ From: "5m", To: "now", - Now: now, + now: now, } Convey("5m ago ", func() { @@ -39,7 +39,7 @@ func TestTimeRange(t *testing.T) { tr := TimeRange{ From: "5h", To: "now-10m", - Now: now, + now: now, } Convey("5h ago ", func() { @@ -65,7 +65,7 @@ func TestTimeRange(t *testing.T) { tr := TimeRange{ From: "1474973725473", To: "1474975757930", - Now: now, + now: now, } res, err := tr.ParseFrom() @@ -82,7 +82,7 @@ func TestTimeRange(t *testing.T) { tr := TimeRange{ From: "asdf", To: "asdf", - Now: now, + now: now, } _, err = tr.ParseFrom() diff --git a/pkg/util/shortid_generator.go b/pkg/util/shortid_generator.go new file mode 100644 index 00000000000..d87b6f70fe6 --- /dev/null +++ b/pkg/util/shortid_generator.go @@ -0,0 +1,30 @@ +package util + +import ( + "regexp" + + "github.com/teris-io/shortid" +) + +var allowedChars = shortid.DefaultABC + +var validUidPattern = regexp.MustCompile(`^[a-zA-Z0-9\-\_]*$`).MatchString + +func init() { + gen, _ := shortid.New(1, allowedChars, 1) + shortid.SetDefault(gen) +} + +// IsValidShortUid checks if short unique identifier contains valid characters +func IsValidShortUid(uid string) bool { + if !validUidPattern(uid) { + return false + } + + return true +} + +// GenerateShortUid generates a short unique identifier. +func GenerateShortUid() string { + return shortid.MustGenerate() +} diff --git a/pkg/util/shortid_generator_test.go b/pkg/util/shortid_generator_test.go new file mode 100644 index 00000000000..359e054a0ca --- /dev/null +++ b/pkg/util/shortid_generator_test.go @@ -0,0 +1,11 @@ +package util + +import "testing" + +func TestAllowedCharMatchesUidPattern(t *testing.T) { + for _, c := range allowedChars { + if !IsValidShortUid(string(c)) { + t.Fatalf("charset for creating new shortids contains chars not present in uid pattern") + } + } +} diff --git a/public/app/app.ts b/public/app/app.ts index 8e345c6abed..9ac76b8ec91 100644 --- a/public/app/app.ts +++ b/public/app/app.ts @@ -9,7 +9,6 @@ import 'angular-native-dragdrop'; import 'angular-bindonce'; import 'react'; import 'react-dom'; -import 'ngreact'; import 'vendor/bootstrap/bootstrap'; import 'vendor/angular-ui/ui-bootstrap-tpls'; @@ -22,12 +21,15 @@ import _ from 'lodash'; import moment from 'moment'; // add move to lodash for backward compatabiltiy -_.move = function (array, fromIndex, toIndex) { +_.move = function(array, fromIndex, toIndex) { array.splice(toIndex, 0, array.splice(fromIndex, 1)[0]); return array; }; -import {coreModule, registerAngularDirectives} from './core/core'; +import { coreModule, registerAngularDirectives } from './core/core'; +import { setupAngularRoutes } from './routes/routes'; + +declare var System: any; export class GrafanaApp { registerFunctions: any; @@ -66,24 +68,28 @@ export class GrafanaApp { $httpProvider.useApplyAsync(true); this.registerFunctions.controller = $controllerProvider.register; - this.registerFunctions.directive = $compileProvider.directive; - this.registerFunctions.factory = $provide.factory; - this.registerFunctions.service = $provide.service; - this.registerFunctions.filter = $filterProvider.register; + this.registerFunctions.directive = $compileProvider.directive; + this.registerFunctions.factory = $provide.factory; + this.registerFunctions.service = $provide.service; + this.registerFunctions.filter = $filterProvider.register; - $provide.decorator("$http", ["$delegate", "$templateCache", function($delegate, $templateCache) { - var get = $delegate.get; - $delegate.get = function(url, config) { - if (url.match(/\.html$/)) { - // some template's already exist in the cache - if (!$templateCache.get(url)) { - url += "?v=" + new Date().getTime(); + $provide.decorator('$http', [ + '$delegate', + '$templateCache', + function($delegate, $templateCache) { + var get = $delegate.get; + $delegate.get = function(url, config) { + if (url.match(/\.html$/)) { + // some template's already exist in the cache + if (!$templateCache.get(url)) { + url += '?v=' + new Date().getTime(); + } } - } - return get(url, config); - }; - return $delegate; - }]); + return get(url, config); + }; + return $delegate; + }, + ]); }); this.ngModuleDependencies = [ @@ -96,7 +102,7 @@ export class GrafanaApp { 'pasvaz.bindonce', 'ui.bootstrap', 'ui.bootstrap.tpls', - 'react' + 'react', ]; var module_types = ['controllers', 'directives', 'factories', 'services', 'filters', 'routes']; @@ -110,24 +116,28 @@ export class GrafanaApp { this.useModule(coreModule); // register react angular wrappers + coreModule.config(setupAngularRoutes); registerAngularDirectives(); var preBootRequires = [System.import('app/features/all')]; - Promise.all(preBootRequires).then(() => { - // disable tool tip animation - $.fn.tooltip.defaults.animation = false; - // bootstrap the app - angular.bootstrap(document, this.ngModuleDependencies).invoke(() => { - _.each(this.preBootModules, module => { - _.extend(module, this.registerFunctions); - }); + Promise.all(preBootRequires) + .then(() => { + // disable tool tip animation + $.fn.tooltip.defaults.animation = false; - this.preBootModules = null; + // bootstrap the app + angular.bootstrap(document, this.ngModuleDependencies).invoke(() => { + _.each(this.preBootModules, module => { + _.extend(module, this.registerFunctions); + }); + + this.preBootModules = null; + }); + }) + .catch(function(err) { + console.log('Application boot failed:', err); }); - }).catch(function(err) { - console.log('Application boot failed:', err); - }); } } diff --git a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx new file mode 100644 index 00000000000..eac18a6c69d --- /dev/null +++ b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import moment from 'moment'; +import { AlertRuleList } from './AlertRuleList'; +import { RootStore } from 'app/stores/RootStore/RootStore'; +import { backendSrv, createNavTree } from 'test/mocks/common'; +import { mount } from 'enzyme'; +import toJson from 'enzyme-to-json'; + +describe('AlertRuleList', () => { + let page, store; + + beforeAll(() => { + backendSrv.get.mockReturnValue( + Promise.resolve([ + { + id: 11, + dashboardId: 58, + panelId: 3, + name: 'Panel Title alert', + state: 'ok', + newStateDate: moment() + .subtract(5, 'minutes') + .format(), + evalData: {}, + executionError: '', + url: 'd/ufkcofof/my-goal', + canEdit: true, + }, + ]) + ); + + store = RootStore.create( + {}, + { + backendSrv: backendSrv, + navTree: createNavTree('alerting', 'alert-list'), + } + ); + + page = mount(); + }); + + it('should call api to get rules', () => { + expect(backendSrv.get.mock.calls[0][0]).toEqual('/api/alerts'); + }); + + it('should render 1 rule', () => { + page.update(); + let ruleNode = page.find('.alert-rule-item'); + expect(toJson(ruleNode)).toMatchSnapshot(); + }); + + it('toggle state should change pause rule if not paused', async () => { + backendSrv.post.mockReturnValue( + Promise.resolve({ + state: 'paused', + }) + ); + + page.find('.fa-pause').simulate('click'); + + // wait for api call to resolve + await Promise.resolve(); + page.update(); + + expect(store.alertList.rules[0].state).toBe('paused'); + expect(page.find('.fa-play')).toHaveLength(1); + }); +}); diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx new file mode 100644 index 00000000000..9ecb9a177d7 --- /dev/null +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -0,0 +1,175 @@ +import React from 'react'; +import classNames from 'classnames'; +import { inject, observer } from 'mobx-react'; +import PageHeader from 'app/core/components/PageHeader/PageHeader'; +import { IAlertRule } from 'app/stores/AlertListStore/AlertListStore'; +import appEvents from 'app/core/app_events'; +import IContainerProps from 'app/containers/IContainerProps'; +import Highlighter from 'react-highlight-words'; + +@inject('view', 'nav', 'alertList') +@observer +export class AlertRuleList extends React.Component { + stateFilters = [ + { text: 'All', value: 'all' }, + { text: 'OK', value: 'ok' }, + { text: 'Not OK', value: 'not_ok' }, + { text: 'Alerting', value: 'alerting' }, + { text: 'No Data', value: 'no_data' }, + { text: 'Paused', value: 'paused' }, + ]; + + constructor(props) { + super(props); + + this.props.nav.load('alerting', 'alert-list'); + this.fetchRules(); + } + + onStateFilterChanged = evt => { + this.props.view.updateQuery({ state: evt.target.value }); + this.fetchRules(); + }; + + fetchRules() { + this.props.alertList.loadRules({ + state: this.props.view.query.get('state') || 'all', + }); + } + + onOpenHowTo = () => { + appEvents.emit('show-modal', { + src: 'public/app/features/alerting/partials/alert_howto.html', + modalClass: 'confirm-modal', + model: {}, + }); + }; + + onSearchQueryChange = evt => { + this.props.alertList.setSearchQuery(evt.target.value); + }; + + render() { + const { nav, alertList } = this.props; + + return ( +
+ +
+
+
+ +
+
+ + +
+ +
+
+ + + +
+
    + {alertList.filteredRules.map(rule => ( + + ))} +
+
+
+
+ ); + } +} + +function AlertStateFilterOption({ text, value }) { + return ( + + ); +} + +export interface AlertRuleItemProps { + rule: IAlertRule; + search: string; +} + +@observer +export class AlertRuleItem extends React.Component { + toggleState = () => { + this.props.rule.togglePaused(); + }; + + renderText(text: string) { + return ( + + ); + } + + render() { + const { rule } = this.props; + + let stateClass = classNames({ + fa: true, + 'fa-play': rule.isPaused, + 'fa-pause': !rule.isPaused, + }); + + let ruleUrl = `${rule.url}?panelId=${rule.panelId}&fullscreen=true&edit=true&tab=alert`; + + return ( +
  • + + + +
    +
    + +
    + {this.renderText(rule.stateText)} + for {rule.stateAge} +
    +
    + {rule.info &&
    {this.renderText(rule.info)}
    } +
    + +
    + + + + +
    +
  • + ); + } +} diff --git a/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap new file mode 100644 index 00000000000..f408f6409be --- /dev/null +++ b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AlertRuleList should render 1 rule 1`] = ` +
  • + + + +
    +
    + +
    + + + + + OK + + + + + + for + 5 minutes + +
    +
    +
    +
    + + + + +
    +
  • +`; diff --git a/public/app/containers/IContainerProps.ts b/public/app/containers/IContainerProps.ts new file mode 100644 index 00000000000..6e790cee06d --- /dev/null +++ b/public/app/containers/IContainerProps.ts @@ -0,0 +1,20 @@ +import { SearchStore } from './../stores/SearchStore/SearchStore'; +import { ServerStatsStore } from './../stores/ServerStatsStore/ServerStatsStore'; +import { NavStore } from './../stores/NavStore/NavStore'; +import { PermissionsStore } from './../stores/PermissionsStore/PermissionsStore'; +import { AlertListStore } from './../stores/AlertListStore/AlertListStore'; +import { ViewStore } from './../stores/ViewStore/ViewStore'; +import { FolderStore } from './../stores/FolderStore/FolderStore'; + +interface IContainerProps { + search: typeof SearchStore.Type; + serverStats: typeof ServerStatsStore.Type; + nav: typeof NavStore.Type; + alertList: typeof AlertListStore.Type; + permissions: typeof PermissionsStore.Type; + view: typeof ViewStore.Type; + folder: typeof FolderStore.Type; + backendSrv: any; +} + +export default IContainerProps; diff --git a/public/app/containers/ManageDashboards/FolderPermissions.tsx b/public/app/containers/ManageDashboards/FolderPermissions.tsx new file mode 100644 index 00000000000..9c82db1c18c --- /dev/null +++ b/public/app/containers/ManageDashboards/FolderPermissions.tsx @@ -0,0 +1,74 @@ +import React, { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import { toJS } from 'mobx'; +import IContainerProps from 'app/containers/IContainerProps'; +import PageHeader from 'app/core/components/PageHeader/PageHeader'; +import Permissions from 'app/core/components/Permissions/Permissions'; +import Tooltip from 'app/core/components/Tooltip/Tooltip'; +import PermissionsInfo from 'app/core/components/Permissions/PermissionsInfo'; +import AddPermissions from 'app/core/components/Permissions/AddPermissions'; +import SlideDown from 'app/core/components/Animations/SlideDown'; + +@inject('nav', 'folder', 'view', 'permissions') +@observer +export class FolderPermissions extends Component { + constructor(props) { + super(props); + this.handleAddPermission = this.handleAddPermission.bind(this); + this.loadStore(); + } + + componentWillUnmount() { + const { permissions } = this.props; + permissions.hideAddPermissions(); + } + + loadStore() { + const { nav, folder, view } = this.props; + return folder.load(view.routeParams.get('uid') as string).then(res => { + view.updatePathAndQuery(`${res.url}/permissions`, {}, {}); + return nav.initFolderNav(toJS(folder.folder), 'manage-folder-permissions'); + }); + } + + handleAddPermission() { + const { permissions } = this.props; + permissions.toggleAddPermissions(); + } + + render() { + const { nav, folder, permissions, backendSrv } = this.props; + + if (!folder.folder || !nav.main) { + return

    Loading

    ; + } + + const dashboardId = folder.folder.id; + + return ( +
    + +
    +
    +

    Folder Permissions

    + + + +
    + +
    + + + + +
    +
    + ); + } +} diff --git a/public/app/containers/ManageDashboards/FolderSettings.jest.tsx b/public/app/containers/ManageDashboards/FolderSettings.jest.tsx new file mode 100644 index 00000000000..bed3d569bcc --- /dev/null +++ b/public/app/containers/ManageDashboards/FolderSettings.jest.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { FolderSettings } from './FolderSettings'; +import { RootStore } from 'app/stores/RootStore/RootStore'; +import { backendSrv } from 'test/mocks/common'; +import { shallow } from 'enzyme'; + +describe('FolderSettings', () => { + let wrapper; + let page; + + beforeAll(() => { + backendSrv.getFolderByUid.mockReturnValue( + Promise.resolve({ + id: 1, + uid: 'uid', + title: 'Folder Name', + url: '/dashboards/f/uid/folder-name', + canSave: true, + version: 1, + }) + ); + + const store = RootStore.create( + { + view: { + path: 'asd', + query: {}, + routeParams: { + uid: 'uid-str', + }, + }, + }, + { + backendSrv: backendSrv, + } + ); + + wrapper = shallow(); + page = wrapper.dive(); + return page + .instance() + .loadStore() + .then(() => { + page.update(); + }); + }); + + it('should set the title input field', () => { + const titleInput = page.find('.gf-form-input'); + expect(titleInput).toHaveLength(1); + expect(titleInput.prop('value')).toBe('Folder Name'); + }); + + it('should update title and enable save button when changed', () => { + const titleInput = page.find('.gf-form-input'); + const disabledSubmitButton = page.find('button[type="submit"]'); + expect(disabledSubmitButton.prop('disabled')).toBe(true); + + titleInput.simulate('change', { target: { value: 'New Title' } }); + + const updatedTitleInput = page.find('.gf-form-input'); + expect(updatedTitleInput.prop('value')).toBe('New Title'); + const enabledSubmitButton = page.find('button[type="submit"]'); + expect(enabledSubmitButton.prop('disabled')).toBe(false); + }); + + it('should disable save button if title is changed back to old title', () => { + const titleInput = page.find('.gf-form-input'); + + titleInput.simulate('change', { target: { value: 'Folder Name' } }); + + const enabledSubmitButton = page.find('button[type="submit"]'); + expect(enabledSubmitButton.prop('disabled')).toBe(true); + }); + + it('should disable save button if title is changed to empty string', () => { + const titleInput = page.find('.gf-form-input'); + + titleInput.simulate('change', { target: { value: '' } }); + + const enabledSubmitButton = page.find('button[type="submit"]'); + expect(enabledSubmitButton.prop('disabled')).toBe(true); + }); +}); diff --git a/public/app/containers/ManageDashboards/FolderSettings.tsx b/public/app/containers/ManageDashboards/FolderSettings.tsx new file mode 100644 index 00000000000..586a8f05b4c --- /dev/null +++ b/public/app/containers/ManageDashboards/FolderSettings.tsx @@ -0,0 +1,158 @@ +import React from 'react'; +import { inject, observer } from 'mobx-react'; +import { toJS } from 'mobx'; +import PageHeader from 'app/core/components/PageHeader/PageHeader'; +import IContainerProps from 'app/containers/IContainerProps'; +import { getSnapshot } from 'mobx-state-tree'; +import appEvents from 'app/core/app_events'; + +@inject('nav', 'folder', 'view') +@observer +export class FolderSettings extends React.Component { + formSnapshot: any; + + constructor(props) { + super(props); + this.loadStore(); + } + + loadStore() { + const { nav, folder, view } = this.props; + + return folder.load(view.routeParams.get('uid') as string).then(res => { + this.formSnapshot = getSnapshot(folder); + view.updatePathAndQuery(`${res.url}/settings`, {}, {}); + + return nav.initFolderNav(toJS(folder.folder), 'manage-folder-settings'); + }); + } + + onTitleChange(evt) { + this.props.folder.setTitle(this.getFormSnapshot().folder.title, evt.target.value); + } + + getFormSnapshot() { + if (!this.formSnapshot) { + this.formSnapshot = getSnapshot(this.props.folder); + } + + return this.formSnapshot; + } + + save(evt) { + if (evt) { + evt.stopPropagation(); + evt.preventDefault(); + } + + const { nav, folder, view } = this.props; + + folder + .saveFolder({ overwrite: false }) + .then(newUrl => { + view.updatePathAndQuery(newUrl, {}, {}); + + appEvents.emit('dashboard-saved'); + appEvents.emit('alert-success', ['Folder saved']); + }) + .then(() => { + return nav.initFolderNav(toJS(folder.folder), 'manage-folder-settings'); + }) + .catch(this.handleSaveFolderError.bind(this)); + } + + delete(evt) { + if (evt) { + evt.stopPropagation(); + evt.preventDefault(); + } + + const { folder, view } = this.props; + const title = folder.folder.title; + + appEvents.emit('confirm-modal', { + title: 'Delete', + text: `Do you want to delete this folder and all its dashboards?`, + icon: 'fa-trash', + yesText: 'Delete', + onConfirm: () => { + return folder.deleteFolder().then(() => { + appEvents.emit('alert-success', ['Folder Deleted', `${title} has been deleted`]); + view.updatePathAndQuery('dashboards', '', ''); + }); + }, + }); + } + + handleSaveFolderError(err) { + if (err.data && err.data.status === 'version-mismatch') { + err.isHandled = true; + + const { nav, folder, view } = this.props; + + appEvents.emit('confirm-modal', { + title: 'Conflict', + text: 'Someone else has updated this folder.', + text2: 'Would you still like to save this folder?', + yesText: 'Save & Overwrite', + icon: 'fa-warning', + onConfirm: () => { + folder + .saveFolder({ overwrite: true }) + .then(newUrl => { + view.updatePathAndQuery(newUrl, {}, {}); + + appEvents.emit('dashboard-saved'); + appEvents.emit('alert-success', ['Folder saved']); + }) + .then(() => { + return nav.initFolderNav(toJS(folder.folder), 'manage-folder-settings'); + }); + }, + }); + } + } + + render() { + const { nav, folder } = this.props; + + if (!folder.folder || !nav.main) { + return

    Loading

    ; + } + + return ( +
    + +
    +

    Folder Settings

    + +
    +
    +
    + + +
    +
    + + +
    + +
    +
    +
    + ); + } +} diff --git a/public/app/containers/ServerStats/ServerStats.jest.tsx b/public/app/containers/ServerStats/ServerStats.jest.tsx new file mode 100644 index 00000000000..a329a47527d --- /dev/null +++ b/public/app/containers/ServerStats/ServerStats.jest.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { ServerStats } from './ServerStats'; +import { RootStore } from 'app/stores/RootStore/RootStore'; +import { backendSrv, createNavTree } from 'test/mocks/common'; + +describe('ServerStats', () => { + it('Should render table with stats', done => { + backendSrv.get.mockReturnValue( + Promise.resolve({ + dashboards: 10, + }) + ); + + const store = RootStore.create( + {}, + { + backendSrv: backendSrv, + navTree: createNavTree('cfg', 'admin', 'server-stats'), + } + ); + + const page = renderer.create(); + + setTimeout(() => { + expect(page.toJSON()).toMatchSnapshot(); + done(); + }); + }); +}); diff --git a/public/app/containers/ServerStats/ServerStats.tsx b/public/app/containers/ServerStats/ServerStats.tsx new file mode 100644 index 00000000000..e40b441d967 --- /dev/null +++ b/public/app/containers/ServerStats/ServerStats.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { inject, observer } from 'mobx-react'; +import PageHeader from 'app/core/components/PageHeader/PageHeader'; +import IContainerProps from 'app/containers/IContainerProps'; + +@inject('nav', 'serverStats') +@observer +export class ServerStats extends React.Component { + constructor(props) { + super(props); + const { nav, serverStats } = this.props; + + nav.load('cfg', 'admin', 'server-stats'); + serverStats.load(); + } + + render() { + const { nav, serverStats } = this.props; + return ( +
    + +
    + + + + + + + + {serverStats.stats.map(StatItem)} +
    NameValue
    +
    +
    + ); + } +} + +function StatItem(stat) { + return ( + + {stat.name} + {stat.value} + + ); +} diff --git a/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap b/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap new file mode 100644 index 00000000000..eac793ca2ca --- /dev/null +++ b/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap @@ -0,0 +1,170 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ServerStats Should render table with stats 1`] = ` +
    +
    +
    +
    +
    + + + + +
    +

    + admin-Text +

    + +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Name + + Value +
    + Total dashboards + + 10 +
    + Total users + + 0 +
    + Active users (seen last 30 days) + + 0 +
    + Total orgs + + 0 +
    + Total playlists + + 0 +
    + Total snapshots + + 0 +
    + Total dashboard tags + + 0 +
    + Total starred dashboards + + 0 +
    + Total alerts + + 0 +
    +
    +
    +`; diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts index 7acdc79d55a..ace0eb00b07 100644 --- a/public/app/core/angular_wrappers.ts +++ b/public/app/core/angular_wrappers.ts @@ -1,8 +1,24 @@ import { react2AngularDirective } from 'app/core/utils/react2angular'; import { PasswordStrength } from './components/PasswordStrength'; +import PageHeader from './components/PageHeader/PageHeader'; +import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA'; +import LoginBackground from './components/Login/LoginBackground'; +import { SearchResult } from './components/search/SearchResult'; +import { TagFilter } from './components/TagFilter/TagFilter'; +import UserPicker from './components/Picker/UserPicker'; +import DashboardPermissions from './components/Permissions/DashboardPermissions'; export function registerAngularDirectives() { - react2AngularDirective('passwordStrength', PasswordStrength, ['password']); - + react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']); + react2AngularDirective('emptyListCta', EmptyListCTA, ['model']); + react2AngularDirective('loginBackground', LoginBackground, []); + react2AngularDirective('searchResult', SearchResult, []); + react2AngularDirective('tagFilter', TagFilter, [ + 'tags', + ['onSelect', { watchDepth: 'reference' }], + ['tagOptions', { watchDepth: 'reference' }], + ]); + react2AngularDirective('selectUserPicker', UserPicker, ['backendSrv', 'handlePicked']); + react2AngularDirective('dashboardPermissions', DashboardPermissions, ['backendSrv', 'dashboardId', 'folder']); } diff --git a/public/app/core/app_events.ts b/public/app/core/app_events.ts index 4507246d2be..26dd74bcb00 100644 --- a/public/app/core/app_events.ts +++ b/public/app/core/app_events.ts @@ -1,6 +1,4 @@ -/// - -import {Emitter} from './utils/emitter'; +import { Emitter } from './utils/emitter'; var appEvents = new Emitter(); export default appEvents; diff --git a/public/app/core/components/Animations/SlideDown.tsx b/public/app/core/components/Animations/SlideDown.tsx new file mode 100644 index 00000000000..4d515f98f16 --- /dev/null +++ b/public/app/core/components/Animations/SlideDown.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import Transition from 'react-transition-group/Transition'; + +const defaultMaxHeight = '200px'; // When animating using max-height we need to use a static value. +// If this is not enough, pass in +
    {title}
    + {buttonTitle} +
    + ProTip: {proTip} + {proTipLinkTitle} +
    +
    + ); + } +} + +export default EmptyListCTA; diff --git a/public/app/core/components/EmptyListCTA/__snapshots__/EmptyListCTA.jest.tsx.snap b/public/app/core/components/EmptyListCTA/__snapshots__/EmptyListCTA.jest.tsx.snap new file mode 100644 index 00000000000..6d47c984d5e --- /dev/null +++ b/public/app/core/components/EmptyListCTA/__snapshots__/EmptyListCTA.jest.tsx.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EmptyListCTA renders correctly 1`] = ` +
    +
    + Title +
    + + + Click me + +
    + + ProTip: + This is a tip + + Learn more + +
    +
    +`; diff --git a/public/app/core/components/Login/LoginBackground.tsx b/public/app/core/components/Login/LoginBackground.tsx new file mode 100644 index 00000000000..83e228ab6e0 --- /dev/null +++ b/public/app/core/components/Login/LoginBackground.tsx @@ -0,0 +1,1240 @@ +import React, { Component } from 'react'; + +const xCount = 50; +const yCount = 50; + +function Cell({ x, y, flipIndex }) { + const index = (y * xCount) + x; + const bgColor1 = getColor(x, y); + return ( +
    + ); +} + +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive +} + +export default class LoginBackground extends Component { + cancelInterval: any; + + constructor(props) { + super(props); + + this.state = { + flipIndex: null, + }; + + this.flipElements = this.flipElements.bind(this); + } + + flipElements() { + const elementIndexToFlip = getRandomInt(0, (xCount * yCount) - 1); + this.setState(prevState => { + return { + ...prevState, + flipIndex: elementIndexToFlip, + }; + }); + } + + componentWillMount() { + this.cancelInterval = setInterval(this.flipElements, 3000); + } + + componentWillUnmount() { + clearInterval(this.cancelInterval); + } + + render() { + console.log('re-render!', this.state.flipIndex); + + return ( +
    + {Array.from(Array(yCount)).map((el, y) => { + return ( +
    + {Array.from(Array(xCount)).map((el2, x) => { + return ( + + ); + })} +
    + ); + })} +
    + ); + } +} + +function getColor(x, y) { + const colors = [ + '#14161A', + '#111920', + '#121E27', + '#13212B', + '#122029', + '#101C24', + '#0F1B23', + '#0F1B22', + '#111C24', + '#101A22', + '#101A21', + '#111D25', + '#101E27', + '#101D26', + '#101B23', + '#11191E', + '#131519', + '#131518', + '#101B21', + '#121F29', + '#10232D', + '#11212B', + '#0E1C25', + '#0E1C24', + '#111F29', + '#11222B', + '#101E28', + '#102028', + '#111F2A', + '#11202A', + '#11191F', + '#121417', + '#12191D', + '#101D25', + '#11212C', + '#10242F', + '#0F212B', + '#0F1E27', + '#0F1D26', + '#0F1F29', + '#0F2029', + '#11232E', + '#10212B', + '#10222C', + '#0F202A', + '#112530', + '#10252F', + '#0F242E', + '#10222D', + '#10202A', + '#0F1C24', + '#0F1E28', + '#0F212A', + '#0F222B', + '#14171A', + '#0F1A20', + '#0F1C25', + '#10232E', + '#0E202A', + '#0E1E27', + '#0E1D26', + '#0F202B', + '#11232F', + '#102632', + '#102530', + '#122430', + '#0F1B21', + '#0F212C', + '#0E1F29', + '#112531', + '#0F2734', + '#0F2835', + '#0D1B23', + '#0F1A21', + '#0F1A23', + '#0F1D27', + '#0F222D', + '#102430', + '#102531', + '#10222E', + '#0F232D', + '#0E2633', + '#0E2734', + '#0F2834', + '#0E2835', + '#0F2633', + '#0F2532', + '#0E1A22', + '#0D1C24', + '#0F2735', + '#0F2937', + '#102A38', + '#112938', + '#102A39', + '#0F2A38', + '#102836', + '#0E1B23', + '#0F2938', + '#102A3A', + '#102D3D', + '#0F3040', + '#102D3E', + '#0F2E3E', + '#112C3B', + '#102B3B', + '#102B3A', + '#102D3C', + '#0F2A39', + '#0F2634', + '#0E2029', + '#0E1A21', + '#0F2B39', + '#0F2D3D', + '#0F2F40', + '#0E3142', + '#113445', + '#122431', + '#102E3E', + '#0F3345', + '#0E2F40', + '#0F3143', + '#102C3C', + '#0F2B3A', + '#0F1F28', + '#0F3344', + '#113548', + '#113C51', + '#144258', + '#103A4E', + '#103A4F', + '#103547', + '#10364A', + '#103649', + '#0F3448', + '#102C3A', + '#0F2836', + '#103447', + '#0F384C', + '#123F55', + '#15445A', + '#133F55', + '#103B50', + '#113E54', + '#103446', + '#0F3A4F', + '#0F3548', + '#0D3142', + '#102C3B', + '#0E2937', + '#103D52', + '#0E3544', + '#184C65', + '#154760', + '#14435B', + '#15465F', + '#124159', + '#0F3D53', + '#103C51', + '#0F3447', + '#0E3243', + '#113143', + '#113D53', + '#184B64', + '#184D67', + '#184C66', + '#174A63', + '#15455C', + '#13425A', + '#14445A', + '#10384C', + '#0E3446', + '#10181E', + '#103243', + '#0F384D', + '#14455C', + '#164761', + '#164C66', + '#1D627D', + '#12425A', + '#164A63', + '#14465D', + '#13435A', + '#0A2B38', + '#0F3446', + '#0D2F40', + '#0D2F3F', + '#0F2531', + '#102937', + '#10384B', + '#0F3649', + '#184E68', + '#1A5472', + '#184D68', + '#154A63', + '#19506B', + '#19536F', + '#1A4F69', + '#144760', + '#114058', + '#0E3A4F', + '#0E3547', + '#0C3042', + '#0E1B24', + '#11222C', + '#154C65', + '#1A5776', + '#1B5675', + '#113847', + '#1A5371', + '#194E68', + '#0E2D3D', + '#112D3B', + '#113D52', + '#18516D', + '#1A5979', + '#1B5878', + '#19526E', + '#1A526E', + '#13435B', + '#0F3E55', + '#0B374C', + '#0E3448', + '#0D2E3F', + '#0F2B3B', + '#112E3E', + '#113B50', + '#15465D', + '#1A526F', + '#1E5E81', + '#1D5B7B', + '#1A5777', + '#154456', + '#113949', + '#0D394E', + '#0F3549', + '#0F2C3B', + '#0E2733', + '#112E3D', + '#123D52', + '#10394C', + '#1B5674', + '#1A5370', + '#144861', + '#104058', + '#104159', + '#0E384C', + '#0D2D3D', + '#0E2533', + '#112C3A', + '#1B5979', + '#1B5C7D', + '#1A5675', + '#104057', + '#0F3C51', + '#11425A', + '#0E394D', + '#0C3243', + '#0E2735', + '#112F3E', + '#134158', + '#1D5E7F', + '#1D6083', + '#1C5877', + '#1A5573', + '#184D66', + '#164962', + '#0F3D54', + '#0E3D53', + '#0E3447', + '#0F2A3A', + '#0F2936', + '#101F28', + '#103040', + '#124056', + '#164E69', + '#144B64', + '#164D66', + '#0F3E54', + '#0E3B51', + '#0D3346', + '#0E1F27', + '#124158', + '#164961', + '#0E3C52', + '#19506C', + '#0F2C3C', + '#0E3244', + '#0E2A39', + '#0E2938', + '#113040', + '#134057', + '#1A5471', + '#154B63', + '#1C597A', + '#164760', + '#10374B', + '#0E374C', + '#0E384D', + '#11242F', + '#10394D', + '#18526E', + '#154B65', + '#103F55', + '#0D3345', + '#102532', + '#102029', + '#113142', + '#1B5973', + '#1A516B', + '#1C5979', + '#1C5A7A', + '#184A65', + '#164C65', + '#0D3041', + '#123142', + '#123E54', + '#1B5877', + '#1A5574', + '#1C5878', + '#13435C', + '#0F374B', + '#0C3143', + '#112F40', + '#123C51', + '#174E68', + '#1D5C7D', + '#14465F', + '#0F3F56', + '#0B3041', + '#123243', + '#15435B', + '#19516D', + '#1D5D7E', + '#1C5C7D', + '#184F69', + '#11374B', + '#103E54', + '#0E3143', + '#0F2D3C', + '#11242E', + '#133445', + '#1A5674', + '#1D6184', + '#1F658B', + '#0D3A50', + '#0C374B', + '#154862', + '#164B64', + '#154961', + '#0D384D', + '#102631', + '#113242', + '#134259', + '#185270', + '#1D6386', + '#1E678C', + '#1C5978', + '#0D3549', + '#0F2632', + '#184961', + '#1D5E80', + '#1E6488', + '#1F678D', + '#1E5B7C', + '#164862', + '#19526D', + '#113C52', + '#15455E', + '#0F2F3F', + '#144259', + '#194D67', + '#1D6991', + '#195777', + '#19516C', + '#103F56', + '#144660', + '#0D2E3E', + '#10212A', + '#113141', + '#16455C', + '#1D5B7C', + '#1F6589', + '#1E668C', + '#1E5F81', + '#0F3B50', + '#0D3244', + '#164A64', + '#184E69', + '#0E364A', + '#0E2E3E', + '#10222B', + '#19475E', + '#1B5A7B', + '#1E5D7F', + '#1E678D', + '#1E6184', + '#19506A', + '#1B5370', + '#1B5573', + '#0E3041', + '#122E3E', + '#16455B', + '#195370', + '#1D6489', + '#1D6B93', + '#164A65', + '#154A64', + '#1A5572', + '#1D6082', + '#1F6286', + '#1D6C94', + '#1E709A', + '#174A65', + '#1B526F', + '#1E6589', + '#1D6384', + '#0D3143', + '#0E2F3F', + '#174760', + '#1F6487', + '#1D668C', + '#0D2F41', + '#103B4F', + '#1C5C7E', + '#1F688F', + '#1C5B7C', + '#164D68', + '#1D6285', + '#0D364A', + '#1D5A7A', + '#1E6990', + '#1D6488', + '#18516B', + '#1A506B', + '#0E3B50', + '#0E3548', + '#124259', + '#13455C', + '#14485F', + '#1E5C7D', + '#122D3C', + '#1E6E98', + '#1E6A91', + '#1E6286', + '#1E6C95', + '#1D6990', + '#101F29', + '#174A62', + '#10394E', + '#1D6D96', + '#1E688E', + '#1D6E97', + '#1E6C94', + '#0E394E', + '#112B39', + '#195270', + '#1E668B', + '#1E6386', + '#1D6385', + '#0C3142', + '#1E6083', + '#1E729C', + '#1F709A', + '#1E6F98', + '#1D5F81', + '#1F688D', + '#1C6488', + '#1D6588', + '#1C6A93', + '#1E658B', + '#1F6C95', + '#0D3C52', + '#1C6385', + '#1E5F82', + '#0E3D54', + '#0F3244', + '#18485F', + '#1E6991', + '#1C5B7B', + '#1F6082', + '#0F3346', + '#18536F', + '#114056', + '#1D6B92', + '#1B5776', + '#0F3C52', + '#1E6890', + '#1F688E', + '#0C394E', + '#0F1D25', + '#1F6386', + '#1E688D', + '#1F6488', + '#20668C', + '#1D5978', + '#0F3D52', + '#0F1E26', + '#13465F', + '#0D374C', + '#1B5C7C', + '#0E1A23', + '#0F374A', + '#1B5574', + '#0F394C', + '#0E2A38', + '#102A37', + '#18506B', + '#1E5A7A', + '#0F3245', + '#0E2E3F', + '#1E678E', + '#1C5D7E', + '#1A5A7A', + '#0E2837', + '#102733', + '#0F3B51', + '#15475E', + '#1E6B93', + '#1E648A', + '#194961', + '#0F3A4E', + '#0E1D25', + '#194F69', + '#103345', + '#0F394D', + '#102B39', + '#103E55', + '#1B5572', + '#164861', + '#174861', + '#113B4F', + '#102936', + '#0F3041', + '#174961', + '#113E53', + '#134056', + '#124057', + '#194B63', + '#0E364B', + '#15445B', + '#16475E', + '#102F3F', + '#16485F', + '#0F2E3D', + '#101920', + '#12222C', + '#122C3B', + '#144157', + '#123B50', + '#16465D', + '#184960', + '#112B3A', + '#12232F', + '#132430', + '#113344', + '#11394C', + '#113649', + '#11364A', + '#133F56', + '#121D25', + '#112733', + '#112A38', + '#0F1F2A', + '#113447', + '#113A4E', + '#0F222C', + '#13222B', + '#112836', + '#102F3E', + '#113243', + '#123445', + '#12374B', + '#121E26', + '#122531', + '#11303F', + '#0D1D25', + '#102835', + '#112834', + '#101C23', + '#111C23', + '#12212B', + '#11222D', + '#0E1B22', + '#0E1D27', + '#121C22', + '#12202A', + '#101A20', + '#13191E', + '#111E28', + '#11212D', + '#0F1B24', + '#0F1C23', + '#13181D', + '#15171A', + '#121D23', + '#121F27', + '#111E27', + '#101B22', + '#121F28', + '#111E26', + '#101D24', + '#111C22', + '#12161E', + '#101925', + '#121E2D', + '#112033', + '#111E2F', + '#0F1B29', + '#0F1A28', + '#101B2A', + '#0E1A27', + '#101C2B', + '#111D2D', + '#111D2B', + '#0F1B28', + '#101923', + '#13161D', + '#13161C', + '#0F1A26', + '#101E2F', + '#112235', + '#102031', + '#0F1B2A', + '#112031', + '#102032', + '#101D2E', + '#121F2F', + '#112133', + '#101E30', + '#101F30', + '#102336', + '#101B2C', + '#0F1C2B', + '#111E2E', + '#0F2134', + '#102236', + '#0F2133', + '#101F31', + '#0F2438', + '#102337', + '#102235', + '#102133', + '#11171E', + '#101F2F', + '#102030', + '#102234', + '#102132', + '#12181F', + '#0F1A25', + '#0F2135', + '#0F1F30', + '#0F1C2D', + '#101D2C', + '#0F2033', + '#0E2338', + '#0F2237', + '#0F2236', + '#0B243B', + '#0D2338', + '#0E1A26', + '#0F1D2E', + '#0F2032', + '#0D2339', + '#0B253F', + '#0A253F', + '#0A253E', + '#0C2439', + '#0E1925', + '#0E2135', + '#0F2235', + '#0A243A', + '#08253E', + '#09253E', + '#0A263F', + '#0A243C', + '#0B233B', + '#0E1A28', + '#0D1A26', + '#09253F', + '#0A2743', + '#0B2844', + '#0B2641', + '#0A2744', + '#0A2844', + '#0B2743', + '#092745', + '#0F2337', + '#101D2D', + '#092743', + '#092846', + '#0E2B4C', + '#102E4F', + '#0E2C4D', + '#0B2A49', + '#082947', + '#0D2B4B', + '#0C2A4A', + '#092946', + '#082845', + '#0C2B4B', + '#0F2D4E', + '#103051', + '#133257', + '#0E2D4E', + '#143156', + '#112F51', + '#0B243A', + '#082744', + '#092844', + '#123054', + '#143359', + '#173A64', + '#183F6E', + '#173F6D', + '#153961', + '#163962', + '#133358', + '#15345B', + '#14345A', + '#102F50', + '#0A2948', + '#082844', + '#092641', + '#16375F', + '#193C69', + '#174170', + '#173E6B', + '#163A63', + '#173D69', + '#183D6A', + '#15365E', + '#112E50', + '#0A2A49', + '#082743', + '#0E1927', + '#173C68', + '#13487E', + '#164476', + '#174375', + '#193F6F', + '#173B66', + '#163B65', + '#082A48', + '#0A2641', + '#09243C', + '#174171', + '#14477C', + '#124980', + '#14487F', + '#174374', + '#15467B', + '#184172', + '#17406F', + '#184070', + '#163C67', + '#16355D', + '#123256', + '#0E1B29', + '#0F1923', + '#113052', + '#184274', + '#164579', + '#13477C', + '#193E6D', + '#0A243E', + '#0B233A', + '#0D1A29', + '#0B2742', + '#17365E', + '#163860', + '#124A84', + '#095191', + '#114A83', + '#0D4D8A', + '#0C4D8C', + '#104B85', + '#15477E', + '#174477', + '#183862', + '#0A233A', + '#092947', + '#09243D', + '#173963', + '#194173', + '#085396', + '#085394', + '#114B87', + '#144983', + '#094F8E', + '#075090', + '#0F4C89', + '#215287', + '#0E1A29', + '#184376', + '#0C4D8B', + '#07549A', + '#0A4E8D', + '#0F4C88', + '#0A4E8C', + '#174273', + '#193C6A', + '#0B2948', + '#0B2C4B', + '#0C4E8D', + '#1259A4', + '#0C579E', + '#0D4D8B', + '#095397', + '#085397', + '#085295', + '#144880', + '#173861', + '#15335A', + '#0F2C4D', + '#0C2949', + '#0B4E8D', + '#08559C', + '#07508F', + '#154578', + '#17365F', + '#122F53', + '#111D2C', + '#092A48', + '#08559D', + '#08559E', + '#0C56A1', + '#164271', + '#163E6A', + '#194071', + '#082642', + '#0F1E30', + '#0D2D4D', + '#114C87', + '#0E59A3', + '#135BA6', + '#085498', + '#085497', + '#095192', + '#0E4D8B', + '#0C4E8A', + '#134982', + '#17457B', + '#121F2E', + '#183E6C', + '#153E69', + '#07508E', + '#173F6C', + '#193D6B', + '#112D4F', + '#0A243B', + '#072946', + '#111E2D', + '#0B2740', + '#10497F', + '#17406E', + '#084F8D', + '#104A80', + '#0E2E4F', + '#143358', + '#16365D', + '#0A2742', + '#13477B', + '#154474', + '#104C86', + '#095291', + '#0B4F8E', + '#114A80', + '#095090', + '#075296', + '#163760', + '#2D6DB5', + '#0C2843', + '#0C233A', + '#153A62', + '#14467A', + '#075498', + '#085293', + '#09263F', + '#122030', + '#09559D', + '#0F4B83', + '#08549A', + '#14375D', + '#085499', + '#075499', + '#0A243D', + '#143E68', + '#10497E', + '#074F8E', + '#085496', + '#0C58A3', + '#065499', + '#085190', + '#0A2B4A', + '#104C88', + '#0D4F8E', + '#0F58A2', + '#0B569B', + '#0D58A1', + '#134A81', + '#09559C', + '#0A5293', + '#114B86', + '#0D2C4C', + '#103255', + '#16457A', + '#074F8C', + '#07559C', + '#185DA9', + '#1D61AD', + '#175CA8', + '#16406D', + '#153C65', + '#0E243A', + '#144679', + '#085192', + '#1A5EAC', + '#1D61AE', + '#11497F', + '#12487E', + '#0C243C', + '#123155', + '#0F59A3', + '#1B5FAB', + '#1E61AD', + '#145CA4', + '#0E599F', + '#11497E', + '#094F8D', + '#15345A', + '#134A85', + '#165CA8', + '#2263AF', + '#124466', + '#0A518F', + '#08569D', + '#16416F', + '#0B2B4A', + '#124A83', + '#0C57A2', + '#1E60AD', + '#1E62AE', + '#165DA8', + '#1059A4', + '#15406C', + '#0A4F8E', + '#12365A', + '#0A5191', + '#16355C', + '#1C5EAB', + '#155CA7', + '#085292', + '#174478', + '#153258', + '#111F2F', + '#174272', + '#1159A5', + '#1C5EAC', + '#2F74BB', + '#0C58A2', + '#0D59A3', + '#14477D', + '#132F53', + '#155BA6', + '#195FAA', + '#2366B1', + '#2967B2', + '#14477E', + '#1B5EAB', + '#175DA8', + '#0F4C86', + '#065090', + '#1C5FAC', + '#185CA8', + '#0D58A3', + '#0C4E8C', + '#134981', + '#14416D', + '#0F5AA5', + '#1F63AF', + '#114B88', + '#09508E', + '#0A569D', + '#195DAA', + '#0F1D2F', + '#1059A2', + '#0E599E', + '#2063AF', + '#1F63AE', + '#1A5EAA', + '#0C57A0', + '#195EAA', + '#1A5EA9', + '#0E4E8A', + '#12487D', + '#185DAA', + '#175EAA', + '#0A508E', + '#1559A6', + '#0E58A3', + '#095399', + '#0B4E8B', + '#0B569F', + '#0C57A1', + '#2967B1', + '#2365B0', + '#2163AE', + '#1A5DAA', + '#195EAB', + '#1E5FAC', + '#2564AF', + '#2767B1', + '#2766B1', + '#0D5A9F', + '#2062AE', + '#1F61AD', + '#195FAB', + '#0D4E8D', + '#173760', + '#111D2E', + '#09518F', + '#1A5FAC', + '#135BA7', + '#085291', + '#183761', + '#0B2845', + '#113457', + '#075393', + '#185EA9', + '#2B69B3', + '#2A67B2', + '#2867B1', + '#155DA8', + '#135CA6', + '#135AA5', + '#114980', + '#2566B1', + '#2064AF', + '#2364AF', + '#13365B', + '#154475', + '#08549B', + '#164373', + '#085392', + '#144576', + '#12497E', + '#0E5392', + '#135BA3', + '#0C5395', + '#0C5291', + '#0E579C', + '#0E5290', + '#134C83', + '#2163AC', + '#195CA6', + '#0D4E8C', + '#082945', + '#133256', + '#0E2F50', + '#105AA6', + '#134677', + '#144475', + '#145BA7', + '#154270', + '#1D60AD', + '#09569B', + '#09243E', + '#134A86', + '#0E59A4', + '#0A4E8B', + '#0E4B83', + '#1D5EAC', + '#101C2A', + '#134A84', + '#0E518F', + '#145CA7', + '#0E5699', + '#145BA5', + '#095292', + '#15416E', + '#153D67', + '#153F6B', + '#125AA5', + '#16406E', + '#0E1B27', + '#0D4F8C', + '#0F58A3', + '#114A82', + '#09569C', + '#0C2339', + '#0E1B28', + '#0D59A4', + '#07559D', + '#08569E', + '#095190', + '#0B253E', + '#0C2B49', + '#2264AF', + '#09549A', + '#09569F', + '#163D68', + '#0C263F', + '#143960', + '#183A65', + '#075496', + '#0C579F', + '#085191', + '#102438', + '#075295', + '#082946', + '#102437', + '#0C2642', + '#101C29', + '#0C253E', + '#15355C', + '#0B2E4D', + '#0F3253', + '#154577', + '#16335B', + '#0F1925', + '#0C2742', + '#0B2946', + '#0E2C4B', + '#0E2B48', + '#0E2237', + '#102237', + '#0B253D', + '#0A2946', + '#0C2841', + '#0D2A47', + '#0C2C4A', + '#08253F', + '#08243D', + '#111C2B', + '#0C2844', + '#0C2945', + '#0D243A', + '#122134', + '#0B2642', + '#113154', + '#113255', + '#0A2642', + '#0A2945', + '#0B263F', + '#0D2E4E', + '#0F1E2E', + '#0A2845', + '#0D2439', + '#0F1A29', + '#101C2E', + '#111923', + '#13181F', + '#111D2F', + '#111F30', + '#121E30', + '#121E2E', + '#101B27', + '#101A27', + '#13171F', + ]; + + // let randX = getRandomInt(0, x); + // let randY = getRandomInt(0, y); + // let randIndex = randY * xCount + randX; + + return colors[(y*xCount + x) % colors.length]; +} diff --git a/public/app/core/components/PageHeader/PageHeader.jest.tsx b/public/app/core/components/PageHeader/PageHeader.jest.tsx new file mode 100644 index 00000000000..a9ba8d008a3 --- /dev/null +++ b/public/app/core/components/PageHeader/PageHeader.jest.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import PageHeader from './PageHeader'; +import { shallow } from 'enzyme'; + +describe('PageHeader', () => { + let wrapper; + + describe('when the nav tree has a node with a title', () => { + beforeAll(() => { + const nav = { + main: { + icon: 'fa fa-folder-open', + id: 'node', + subTitle: 'node subtitle', + url: '', + text: 'node', + }, + node: {}, + }; + wrapper = shallow(); + }); + + it('should render the title', () => { + const title = wrapper.find('.page-header__title'); + expect(title.text()).toBe('node'); + }); + }); + + describe('when the nav tree has a node with breadcrumbs and a title', () => { + beforeAll(() => { + const nav = { + main: { + icon: 'fa fa-folder-open', + id: 'child', + subTitle: 'child subtitle', + url: '', + text: 'child', + breadcrumbs: [{ title: 'Parent', url: 'parentUrl' }], + }, + node: {}, + }; + wrapper = shallow(); + }); + + it('should render the title with breadcrumbs first and then title last', () => { + const title = wrapper.find('.page-header__title'); + expect(title.text()).toBe('Parent / child'); + + const parentLink = wrapper.find('.page-header__title > a.text-link'); + expect(parentLink.prop('href')).toBe('parentUrl'); + }); + }); +}); diff --git a/public/app/core/components/PageHeader/PageHeader.tsx b/public/app/core/components/PageHeader/PageHeader.tsx new file mode 100644 index 00000000000..f998cb9981f --- /dev/null +++ b/public/app/core/components/PageHeader/PageHeader.tsx @@ -0,0 +1,164 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { NavModel, NavModelItem } from '../../nav_model_srv'; +import classNames from 'classnames'; +import appEvents from 'app/core/app_events'; +import { toJS } from 'mobx'; + +export interface IProps { + model: NavModel; +} + +const SelectNav = ({ main, customCss }: { main: NavModelItem; customCss: string }) => { + const defaultSelectedItem = main.children.find(navItem => { + return navItem.active === true; + }); + + const gotoUrl = evt => { + var element = evt.target; + var url = element.options[element.selectedIndex].value; + appEvents.emit('location-change', { href: url }); + }; + + return ( +
    +
    + ); +}; + +const Tabs = ({ main, customCss }: { main: NavModelItem; customCss: string }) => { + return ( +
      + {main.children.map((tab, idx) => { + if (tab.hideFromTabs) { + return null; + } + + const tabClasses = classNames({ + 'gf-tabs-link': true, + active: tab.active, + }); + + return ( +
    • + + + {tab.text} + +
    • + ); + })} +
    + ); +}; + +const Navigation = ({ main }: { main: NavModelItem }) => { + return ( + + ); +}; + +@observer +export default class PageHeader extends React.Component { + constructor(props) { + super(props); + } + + shouldComponentUpdate() { + //Hack to re-render on changed props from angular with the @observer decorator + return true; + } + + renderTitle(title: string, breadcrumbs: any[]) { + if (!title && (!breadcrumbs || breadcrumbs.length === 0)) { + return null; + } + + if (!breadcrumbs || breadcrumbs.length === 0) { + return

    {title}

    ; + } + + const breadcrumbsResult = []; + for (let i = 0; i < breadcrumbs.length; i++) { + const bc = breadcrumbs[i]; + if (bc.url) { + breadcrumbsResult.push( + + {bc.title} + + ); + } else { + breadcrumbsResult.push( / {bc.title}); + } + } + breadcrumbsResult.push( / {title}); + + return

    {breadcrumbsResult}

    ; + } + + renderHeaderTitle(main) { + return ( +
    + + {main.icon && } + {main.img && } + + +
    + {this.renderTitle(main.text, main.breadcrumbs)} + {main.subTitle &&
    {main.subTitle}
    } + {main.subType && ( +
    + + {main.subType.text} +
    + )} +
    +
    + ); + } + + render() { + const { model } = this.props; + + if (!model) { + return null; + } + + const main = toJS(model.main); // Convert to JS if its a mobx observable + + return ( +
    +
    +
    + {this.renderHeaderTitle(main)} + {main.children && } +
    +
    +
    + ); + } +} diff --git a/public/app/core/components/PasswordStrength.tsx b/public/app/core/components/PasswordStrength.tsx index 1fede3e5cd5..8f92b18445c 100644 --- a/public/app/core/components/PasswordStrength.tsx +++ b/public/app/core/components/PasswordStrength.tsx @@ -11,15 +11,20 @@ export class PasswordStrength extends React.Component { } render() { + const { password } = this.props; let strengthText = "strength: strong like a bull."; let strengthClass = "password-strength-good"; - if (this.props.password.length <= 8) { + if (!password) { + return null; + } + + if (password.length <= 8) { strengthText = "strength: you can do better."; strengthClass = "password-strength-ok"; } - if (this.props.password.length < 4) { + if (password.length < 4) { strengthText = "strength: weak sauce."; strengthClass = "password-strength-bad"; } diff --git a/public/app/core/components/Permissions/AddPermissions.jest.tsx b/public/app/core/components/Permissions/AddPermissions.jest.tsx new file mode 100644 index 00000000000..fe97c4c7e62 --- /dev/null +++ b/public/app/core/components/Permissions/AddPermissions.jest.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import AddPermissions from './AddPermissions'; +import { RootStore } from 'app/stores/RootStore/RootStore'; +import { backendSrv } from 'test/mocks/common'; +import { shallow } from 'enzyme'; + +describe('AddPermissions', () => { + let wrapper; + let store; + let instance; + + beforeAll(() => { + backendSrv.get.mockReturnValue( + Promise.resolve([ + { id: 2, dashboardId: 1, role: 'Viewer', permission: 1, permissionName: 'View' }, + { id: 3, dashboardId: 1, role: 'Editor', permission: 1, permissionName: 'Edit' }, + ]) + ); + + backendSrv.post = jest.fn(() => Promise.resolve({})); + + store = RootStore.create( + {}, + { + backendSrv: backendSrv, + } + ); + + wrapper = shallow(); + instance = wrapper.instance(); + return store.permissions.load(1, true, false); + }); + + describe('when permission for a user is added', () => { + it('should save permission to db', () => { + const evt = { + target: { + value: 'User', + }, + }; + const userItem = { + id: 2, + login: 'user2', + }; + + instance.typeChanged(evt); + instance.userPicked(userItem); + + wrapper.update(); + + expect(wrapper.find('[data-save-permission]').prop('disabled')).toBe(false); + + wrapper.find('form').simulate('submit', { preventDefault() {} }); + + expect(backendSrv.post.mock.calls.length).toBe(1); + expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/permissions'); + }); + }); + + describe('when permission for team is added', () => { + it('should save permission to db', () => { + const evt = { + target: { + value: 'Group', + }, + }; + + const teamItem = { + id: 2, + name: 'ug1', + }; + + instance.typeChanged(evt); + instance.teamPicked(teamItem); + + wrapper.update(); + + expect(wrapper.find('[data-save-permission]').prop('disabled')).toBe(false); + + wrapper.find('form').simulate('submit', { preventDefault() {} }); + + expect(backendSrv.post.mock.calls.length).toBe(1); + expect(backendSrv.post.mock.calls[0][0]).toBe('/api/dashboards/id/1/permissions'); + }); + }); + + afterEach(() => { + backendSrv.post.mockClear(); + }); +}); diff --git a/public/app/core/components/Permissions/AddPermissions.tsx b/public/app/core/components/Permissions/AddPermissions.tsx new file mode 100644 index 00000000000..07ccfdbbef5 --- /dev/null +++ b/public/app/core/components/Permissions/AddPermissions.tsx @@ -0,0 +1,143 @@ +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; +import { aclTypes } from 'app/stores/PermissionsStore/PermissionsStore'; +import UserPicker, { User } from 'app/core/components/Picker/UserPicker'; +import TeamPicker, { Team } from 'app/core/components/Picker/TeamPicker'; +import DescriptionPicker, { OptionWithDescription } from 'app/core/components/Picker/DescriptionPicker'; +import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore'; + +export interface IProps { + permissions: any; + backendSrv: any; +} +@observer +class AddPermissions extends Component { + constructor(props) { + super(props); + this.userPicked = this.userPicked.bind(this); + this.teamPicked = this.teamPicked.bind(this); + this.permissionPicked = this.permissionPicked.bind(this); + this.typeChanged = this.typeChanged.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + + componentWillMount() { + const { permissions } = this.props; + permissions.resetNewType(); + } + + typeChanged(evt) { + const { value } = evt.target; + const { permissions } = this.props; + + permissions.setNewType(value); + } + + userPicked(user: User) { + const { permissions } = this.props; + if (!user) { + permissions.newItem.setUser(null, null); + return; + } + return permissions.newItem.setUser(user.id, user.login); + } + + teamPicked(team: Team) { + const { permissions } = this.props; + if (!team) { + permissions.newItem.setTeam(null, null); + return; + } + return permissions.newItem.setTeam(team.id, team.name); + } + + permissionPicked(permission: OptionWithDescription) { + const { permissions } = this.props; + return permissions.newItem.setPermission(permission.value); + } + + resetNewType() { + const { permissions } = this.props; + return permissions.resetNewType(); + } + + handleSubmit(evt) { + evt.preventDefault(); + const { permissions } = this.props; + permissions.addStoreItem(); + } + + render() { + const { permissions, backendSrv } = this.props; + const newItem = permissions.newItem; + const pickerClassName = 'width-20'; + + const isValid = newItem.isValid(); + + return ( +
    + +
    +
    Add Permission For
    +
    +
    +
    + +
    +
    + + {newItem.type === 'User' ? ( +
    + +
    + ) : null} + + {newItem.type === 'Group' ? ( +
    + +
    + ) : null} + +
    + +
    + +
    + +
    +
    +
    +
    + ); + } +} + +export default AddPermissions; diff --git a/public/app/core/components/Permissions/DashboardPermissions.tsx b/public/app/core/components/Permissions/DashboardPermissions.tsx new file mode 100644 index 00000000000..12339cc7c34 --- /dev/null +++ b/public/app/core/components/Permissions/DashboardPermissions.tsx @@ -0,0 +1,70 @@ +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; +import { store } from 'app/stores/store'; +import Permissions from 'app/core/components/Permissions/Permissions'; +import Tooltip from 'app/core/components/Tooltip/Tooltip'; +import PermissionsInfo from 'app/core/components/Permissions/PermissionsInfo'; +import AddPermissions from 'app/core/components/Permissions/AddPermissions'; +import SlideDown from 'app/core/components/Animations/SlideDown'; +import { FolderInfo } from './FolderInfo'; + +export interface IProps { + dashboardId: number; + folder?: FolderInfo; + backendSrv: any; +} +@observer +class DashboardPermissions extends Component { + permissions: any; + + constructor(props) { + super(props); + this.handleAddPermission = this.handleAddPermission.bind(this); + this.permissions = store.permissions; + } + + handleAddPermission() { + this.permissions.toggleAddPermissions(); + } + + componentWillUnmount() { + this.permissions.hideAddPermissions(); + } + + render() { + const { dashboardId, folder, backendSrv } = this.props; + + return ( +
    +
    +
    +

    Permissions

    + + + +
    + +
    +
    + + + + +
    + ); + } +} + +export default DashboardPermissions; diff --git a/public/app/core/components/Permissions/DisabledPermissionsListItem.tsx b/public/app/core/components/Permissions/DisabledPermissionsListItem.tsx new file mode 100644 index 00000000000..db45714136e --- /dev/null +++ b/public/app/core/components/Permissions/DisabledPermissionsListItem.tsx @@ -0,0 +1,40 @@ +import React, { Component } from 'react'; +import DescriptionPicker from 'app/core/components/Picker/DescriptionPicker'; +import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore'; + +export interface IProps { + item: any; +} + +export default class DisabledPermissionListItem extends Component { + render() { + const { item } = this.props; + + return ( + + + + + + + Can + +
    + {}} + value={item.permission} + disabled={true} + className={'gf-form-input--form-dropdown-right'} + /> +
    + + + + + + ); + } +} diff --git a/public/app/core/components/Permissions/FolderInfo.ts b/public/app/core/components/Permissions/FolderInfo.ts new file mode 100644 index 00000000000..d4a6020bb71 --- /dev/null +++ b/public/app/core/components/Permissions/FolderInfo.ts @@ -0,0 +1,5 @@ +export interface FolderInfo { + id: number; + title: string; + url: string; +} diff --git a/public/app/core/components/Permissions/Permissions.tsx b/public/app/core/components/Permissions/Permissions.tsx new file mode 100644 index 00000000000..0a0572ed86e --- /dev/null +++ b/public/app/core/components/Permissions/Permissions.tsx @@ -0,0 +1,92 @@ +import React, { Component } from 'react'; +import PermissionsList from './PermissionsList'; +import { observer } from 'mobx-react'; +import { FolderInfo } from './FolderInfo'; + +export interface DashboardAcl { + id?: number; + dashboardId?: number; + userId?: number; + userLogin?: string; + userEmail?: string; + teamId?: number; + team?: string; + permission?: number; + permissionName?: string; + role?: string; + icon?: string; + nameHtml?: string; + inherited?: boolean; + sortName?: string; + sortRank?: number; +} + +export interface IProps { + dashboardId: number; + folderInfo?: FolderInfo; + permissions?: any; + isFolder: boolean; + backendSrv: any; +} + +@observer +class Permissions extends Component { + constructor(props) { + super(props); + const { dashboardId, isFolder, folderInfo } = this.props; + this.permissionChanged = this.permissionChanged.bind(this); + this.typeChanged = this.typeChanged.bind(this); + this.removeItem = this.removeItem.bind(this); + this.loadStore(dashboardId, isFolder, folderInfo && folderInfo.id === 0); + } + + loadStore(dashboardId, isFolder, isInRoot = false) { + return this.props.permissions.load(dashboardId, isFolder, isInRoot); + } + + permissionChanged(index: number, permission: number, permissionName: string) { + const { permissions } = this.props; + permissions.updatePermissionOnIndex(index, permission, permissionName); + } + + removeItem(index: number) { + const { permissions } = this.props; + permissions.removeStoreItem(index); + } + + resetNewType() { + const { permissions } = this.props; + permissions.resetNewType(); + } + + typeChanged(evt) { + const { value } = evt.target; + const { permissions, dashboardId } = this.props; + + if (value === 'Viewer' || value === 'Editor') { + permissions.addStoreItem({ permission: 1, role: value, dashboardId: dashboardId }, dashboardId); + this.resetNewType(); + return; + } + + permissions.setNewType(value); + } + + render() { + const { permissions, folderInfo } = this.props; + + return ( +
    + +
    + ); + } +} + +export default Permissions; diff --git a/public/app/core/components/Permissions/PermissionsInfo.tsx b/public/app/core/components/Permissions/PermissionsInfo.tsx new file mode 100644 index 00000000000..9791e344085 --- /dev/null +++ b/public/app/core/components/Permissions/PermissionsInfo.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +export default () => { + return ( +
    +
    What are Permissions?
    +

    + An Access Control List (ACL) model is used to limit access to Dashboard Folders. A user or a Team can be + assigned permissions for a folder or for a single dashboard. +

    +
    + ); +}; diff --git a/public/app/core/components/Permissions/PermissionsList.tsx b/public/app/core/components/Permissions/PermissionsList.tsx new file mode 100644 index 00000000000..b215dad2391 --- /dev/null +++ b/public/app/core/components/Permissions/PermissionsList.tsx @@ -0,0 +1,64 @@ +import React, { Component } from 'react'; +import PermissionsListItem from './PermissionsListItem'; +import DisabledPermissionsListItem from './DisabledPermissionsListItem'; +import { observer } from 'mobx-react'; +import { FolderInfo } from './FolderInfo'; + +export interface IProps { + permissions: any[]; + removeItem: any; + permissionChanged: any; + fetching: boolean; + folderInfo?: FolderInfo; +} + +@observer +class PermissionsList extends Component { + render() { + const { permissions, removeItem, permissionChanged, fetching, folderInfo } = this.props; + + return ( + + + Admin Role', + permission: 4, + icon: 'fa fa-fw fa-street-view', + }} + /> + {permissions.map((item, idx) => { + return ( + + ); + })} + {fetching === true && permissions.length < 1 ? ( + + + + ) : null} + + {fetching === false && permissions.length < 1 ? ( + + + + ) : null} + +
    + Loading permissions... +
    + No permissions are set. Will only be accessible by admins. +
    + ); + } +} + +export default PermissionsList; diff --git a/public/app/core/components/Permissions/PermissionsListItem.tsx b/public/app/core/components/Permissions/PermissionsListItem.tsx new file mode 100644 index 00000000000..3140b8fcc0c --- /dev/null +++ b/public/app/core/components/Permissions/PermissionsListItem.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import DescriptionPicker from 'app/core/components/Picker/DescriptionPicker'; +import { permissionOptions } from 'app/stores/PermissionsStore/PermissionsStore'; + +const setClassNameHelper = inherited => { + return inherited ? 'gf-form-disabled' : ''; +}; + +export default observer(({ item, removeItem, permissionChanged, itemIndex, folderInfo }) => { + const handleRemoveItem = evt => { + evt.preventDefault(); + removeItem(itemIndex); + }; + + const handleChangePermission = permissionOption => { + permissionChanged(itemIndex, permissionOption.value, permissionOption.label); + }; + + const inheritedFromRoot = item.dashboardId === -1 && folderInfo && folderInfo.id === 0; + + return ( + + + + + + + {item.inherited && + folderInfo && ( + + Inherited from folder{' '} + + {folderInfo.title} + {' '} + + )} + {inheritedFromRoot && Default Permission} + + Can + +
    + +
    + + + {!item.inherited ? ( + + + + ) : ( + + )} + + + ); +}); diff --git a/public/app/core/components/Picker/DescriptionOption.tsx b/public/app/core/components/Picker/DescriptionOption.tsx new file mode 100644 index 00000000000..12a1fdd9163 --- /dev/null +++ b/public/app/core/components/Picker/DescriptionOption.tsx @@ -0,0 +1,56 @@ +import React, { Component } from 'react'; + +export interface IProps { + onSelect: any; + onFocus: any; + option: any; + isFocused: any; + className: any; +} + +class DescriptionOption extends Component { + constructor(props) { + super(props); + this.handleMouseDown = this.handleMouseDown.bind(this); + this.handleMouseEnter = this.handleMouseEnter.bind(this); + this.handleMouseMove = this.handleMouseMove.bind(this); + } + + handleMouseDown(event) { + event.preventDefault(); + event.stopPropagation(); + this.props.onSelect(this.props.option, event); + } + + handleMouseEnter(event) { + this.props.onFocus(this.props.option, event); + } + + handleMouseMove(event) { + if (this.props.isFocused) { + return; + } + this.props.onFocus(this.props.option, event); + } + + render() { + const { option, children, className } = this.props; + return ( +
    +
    diff --git a/public/app/core/components/sidemenu/sidemenu.ts b/public/app/core/components/sidemenu/sidemenu.ts index 94002677de6..fb9d9be7f70 100644 --- a/public/app/core/components/sidemenu/sidemenu.ts +++ b/public/app/core/components/sidemenu/sidemenu.ts @@ -1,105 +1,66 @@ -/// - +import _ from 'lodash'; import config from 'app/core/config'; import $ from 'jquery'; import coreModule from '../../core_module'; +import appEvents from 'app/core/app_events'; export class SideMenuCtrl { - isSignedIn: boolean; - showSignout: boolean; user: any; mainLinks: any; - orgMenu: any; - appSubUrl: string; + bottomNav: any; loginUrl: string; - orgFilter: string; - orgItems: any; - orgs: any; - maxShownOrgs: number; + isSignedIn: boolean; + isOpenMobile: boolean; /** @ngInject */ - constructor(private $scope, private $location, private contextSrv, private backendSrv) { + constructor(private $scope, private $rootScope, private $location, private contextSrv, private $timeout) { this.isSignedIn = contextSrv.isSignedIn; this.user = contextSrv.user; - this.appSubUrl = config.appSubUrl; - this.showSignout = this.contextSrv.isSignedIn && !config['disableSignoutMenu']; - this.maxShownOrgs = 10; - this.mainLinks = config.bootData.mainNavLinks; - this.openUserDropdown(); + let navTree = _.cloneDeep(config.bootData.navTree); + this.mainLinks = _.filter(navTree, item => !item.hideFromMenu); + this.bottomNav = _.filter(navTree, item => item.hideFromMenu); this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path()); - this.$scope.$on('$routeChangeSuccess', () => { - if (!this.contextSrv.pinned) { - this.contextSrv.sidemenu = false; + if (contextSrv.user.orgCount > 1) { + let profileNode = _.find(this.bottomNav, { id: 'profile' }); + if (profileNode) { + profileNode.showOrgSwitcher = true; } + } + + this.$scope.$on('$routeChangeSuccess', () => { this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path()); }); - - this.orgFilter = ''; } - getUrl(url) { - return config.appSubUrl + url; - } + toggleSideMenu() { + this.contextSrv.toggleSideMenu(); + appEvents.emit('toggle-sidemenu'); - openUserDropdown() { - this.orgMenu = [ - {section: 'You', cssClass: 'dropdown-menu-title'}, - {text: 'Profile', url: this.getUrl('/profile')}, - ]; + this.$timeout(() => { + this.$rootScope.$broadcast('render'); + }); + } - if (this.showSignout) { - this.orgMenu.push({text: "Sign out", url: this.getUrl("/logout"), target: "_self"}); - } + toggleSideMenuSmallBreakpoint() { + appEvents.emit('toggle-sidemenu-mobile'); + } - if (this.contextSrv.hasRole('Admin')) { - this.orgMenu.push({section: this.user.orgName, cssClass: 'dropdown-menu-title'}); - this.orgMenu.push({ - text: "Preferences", - url: this.getUrl("/org") - }); - this.orgMenu.push({ - text: "Users", - url: this.getUrl("/org/users") - }); - this.orgMenu.push({ - text: "API Keys", - url: this.getUrl("/org/apikeys") - }); - } + switchOrg() { + this.$rootScope.appEvent('show-modal', { + templateHtml: '', + }); + } - this.orgMenu.push({cssClass: "divider"}); - this.backendSrv.get('/api/user/orgs').then(orgs => { - this.orgs = orgs; - this.loadOrgsItems(); - }); - } - - loadOrgsItems() { - this.orgItems = []; - this.orgs.forEach(org => { - if (org.orgId === this.contextSrv.user.orgId) { - return; - } - - if (this.orgItems.length === this.maxShownOrgs) { - return; - } - - if (this.orgFilter === '' || (org.name.toLowerCase().indexOf(this.orgFilter.toLowerCase()) !== -1)) { - this.orgItems.push({ - text: "Switch to " + org.name, - icon: "fa fa-fw fa-random", - url: this.getUrl('/profile/switch-org/' + org.orgId), - target: '_self' - }); - } - }); - if (config.allowOrgCreate) { - this.orgItems.push({text: "New organization", icon: "fa fa-fw fa-plus", url: this.getUrl('/org/new')}); - } - } + itemClicked(item, evt) { + if (item.url === '/shortcuts') { + appEvents.emit('show-modal', { + templateHtml: '', + }); + evt.preventDefault(); + } + } } export function sideMenuDirective() { @@ -121,11 +82,7 @@ export function sideMenuDirective() { parent.append(menu); }, 100); }); - - scope.$on("$destory", function() { - elem.off('click.dropdown'); - }); - } + }, }; } diff --git a/public/app/core/components/switch.ts b/public/app/core/components/switch.ts index f7a2658a0ff..d2de09216cc 100644 --- a/public/app/core/components/switch.ts +++ b/public/app/core/components/switch.ts @@ -1,5 +1,3 @@ -/// - import coreModule from 'app/core/core_module'; var template = ` @@ -33,7 +31,6 @@ export class SwitchCtrl { return this.onChange(); }); } - } export function switchDirective() { @@ -43,12 +40,12 @@ export function switchDirective() { controllerAs: 'ctrl', bindToController: true, scope: { - checked: "=", - label: "@", - labelClass: "@", - tooltip: "@", - switchClass: "@", - onChange: "&", + checked: '=', + label: '@', + labelClass: '@', + tooltip: '@', + switchClass: '@', + onChange: '&', }, template: template, }; diff --git a/public/app/core/components/team_picker.ts b/public/app/core/components/team_picker.ts new file mode 100644 index 00000000000..228767a76c4 --- /dev/null +++ b/public/app/core/components/team_picker.ts @@ -0,0 +1,64 @@ +import coreModule from 'app/core/core_module'; +import _ from 'lodash'; + +const template = ` + +`; +export class TeamPickerCtrl { + group: any; + teamPicked: any; + debouncedSearchGroups: any; + + /** @ngInject */ + constructor(private backendSrv) { + this.debouncedSearchGroups = _.debounce(this.searchGroups, 500, { + leading: true, + trailing: false, + }); + this.reset(); + } + + reset() { + this.group = { text: 'Choose', value: null }; + } + + searchGroups(query: string) { + return Promise.resolve( + this.backendSrv.get('/api/teams/search?perpage=10&page=1&query=' + query).then(result => { + return _.map(result.teams, ug => { + return { text: ug.name, value: ug }; + }); + }) + ); + } + + onChange(option) { + this.teamPicked({ $group: option.value }); + } +} + +export function teamPicker() { + return { + restrict: 'E', + template: template, + controller: TeamPickerCtrl, + bindToController: true, + controllerAs: 'ctrl', + scope: { + teamPicked: '&', + }, + link: function(scope, elem, attrs, ctrl) { + scope.$on('team-picker-reset', () => { + ctrl.reset(); + }); + }, + }; +} + +coreModule.directive('teamPicker', teamPicker); diff --git a/public/app/core/components/user_picker.ts b/public/app/core/components/user_picker.ts new file mode 100644 index 00000000000..606ded09885 --- /dev/null +++ b/public/app/core/components/user_picker.ts @@ -0,0 +1,71 @@ +import coreModule from 'app/core/core_module'; +import _ from 'lodash'; + +const template = ` + +`; +export class UserPickerCtrl { + user: any; + debouncedSearchUsers: any; + userPicked: any; + + /** @ngInject */ + constructor(private backendSrv) { + this.reset(); + this.debouncedSearchUsers = _.debounce(this.searchUsers, 500, { + leading: true, + trailing: false, + }); + } + + searchUsers(query: string) { + return Promise.resolve( + this.backendSrv.get('/api/users/search?perpage=10&page=1&query=' + query).then(result => { + return _.map(result.users, user => { + return { text: user.login + ' - ' + user.email, value: user }; + }); + }) + ); + } + + onChange(option) { + this.userPicked({ $user: option.value }); + } + + reset() { + this.user = { text: 'Choose', value: null }; + } +} + +export interface User { + id: number; + name: string; + login: string; + email: string; +} + +export function userPicker() { + return { + restrict: 'E', + template: template, + controller: UserPickerCtrl, + bindToController: true, + controllerAs: 'ctrl', + scope: { + userPicked: '&', + }, + link: function(scope, elem, attrs, ctrl) { + scope.$on('user-picker-reset', () => { + ctrl.reset(); + }); + }, + }; +} + +coreModule.directive('userPicker', userPicker); diff --git a/public/app/core/config.ts b/public/app/core/config.ts index e54d62d7c0e..91b1cfef3a4 100644 --- a/public/app/core/config.ts +++ b/public/app/core/config.ts @@ -1,39 +1,39 @@ import _ from 'lodash'; class Settings { - datasources: any; - panels: any; - appSubUrl: string; - window_title_prefix: string; - buildInfo: any; - new_panel_title: string; - bootData: any; - externalUserMngLinkUrl: string; - externalUserMngLinkName: string; - externalUserMngInfo: string; - allowOrgCreate: boolean; - disableLoginForm: boolean; - defaultDatasource: string; - alertingEnabled: boolean; - authProxyEnabled: boolean; - ldapEnabled: boolean; - oauth: any; - disableUserSignUp: boolean; - loginHint: any; - loginError: any; + datasources: any; + panels: any; + appSubUrl: string; + window_title_prefix: string; + buildInfo: any; + new_panel_title: string; + bootData: any; + externalUserMngLinkUrl: string; + externalUserMngLinkName: string; + externalUserMngInfo: string; + allowOrgCreate: boolean; + disableLoginForm: boolean; + defaultDatasource: string; + alertingEnabled: boolean; + authProxyEnabled: boolean; + ldapEnabled: boolean; + oauth: any; + disableUserSignUp: boolean; + loginHint: any; + loginError: any; - constructor(options) { - var defaults = { - datasources: {}, - window_title_prefix: 'Grafana - ', - panels: {}, - new_panel_title: 'Panel Title', - playlist_timespan: "1m", - unsaved_changes_warning: true, - appSubUrl: "" - }; - _.extend(this, defaults, options); - } + constructor(options) { + var defaults = { + datasources: {}, + window_title_prefix: 'Grafana - ', + panels: {}, + new_panel_title: 'Panel Title', + playlist_timespan: '1m', + unsaved_changes_warning: true, + appSubUrl: '', + }; + _.extend(this, defaults, options); + } } var bootData = (window).grafanaBootData || { settings: {} }; diff --git a/public/app/core/constants.ts b/public/app/core/constants.ts new file mode 100644 index 00000000000..2642c5e400a --- /dev/null +++ b/public/app/core/constants.ts @@ -0,0 +1,10 @@ +export const GRID_CELL_HEIGHT = 30; +export const GRID_CELL_VMARGIN = 10; +export const GRID_COLUMN_COUNT = 24; +export const REPEAT_DIR_VERTICAL = 'v'; + +export const DEFAULT_PANEL_SPAN = 4; +export const DEFAULT_ROW_HEIGHT = 250; +export const MIN_PANEL_HEIGHT = GRID_CELL_HEIGHT * 3; + +export const LS_PANEL_COPY_KEY = 'panel-copy'; diff --git a/public/app/core/controllers/error_ctrl.ts b/public/app/core/controllers/error_ctrl.ts index fe894a69806..a47cae9fea3 100644 --- a/public/app/core/controllers/error_ctrl.ts +++ b/public/app/core/controllers/error_ctrl.ts @@ -1,18 +1,21 @@ import config from 'app/core/config'; import coreModule from '../core_module'; +import appEvents from 'app/core/app_events'; export class ErrorCtrl { - /** @ngInject */ constructor($scope, contextSrv, navModelSrv) { $scope.navModel = navModelSrv.getNotFoundNav(); $scope.appSubUrl = config.appSubUrl; - var showSideMenu = contextSrv.sidemenu; - contextSrv.sidemenu = false; + if (!contextSrv.isSignedIn) { + appEvents.emit('toggle-sidemenu-hidden'); + } - $scope.$on('$destroy', function() { - contextSrv.sidemenu = showSideMenu; + $scope.$on('destroy', () => { + if (!contextSrv.isSignedIn) { + appEvents.emit('toggle-sidemenu-hidden'); + } }); } } diff --git a/public/app/core/controllers/inspect_ctrl.ts b/public/app/core/controllers/inspect_ctrl.ts index 70516986099..5dd4cb3d06f 100644 --- a/public/app/core/controllers/inspect_ctrl.ts +++ b/public/app/core/controllers/inspect_ctrl.ts @@ -4,20 +4,19 @@ import $ from 'jquery'; import coreModule from '../core_module'; export class InspectCtrl { - /** @ngInject */ constructor($scope, $sanitize) { var model = $scope.inspector; - $scope.init = function () { + $scope.init = function() { $scope.editor = { index: 0 }; - if (!model.error) { + if (!model.error) { return; } if (_.isString(model.error.data)) { - $scope.response = $("
    " + model.error.data + "
    ").text(); + $scope.response = $('
    ' + model.error.data + '
    ').text(); } else if (model.error.data) { if (model.error.data.response) { $scope.response = $sanitize(model.error.data.response); @@ -30,7 +29,7 @@ export class InspectCtrl { if (model.error.config && model.error.config.params) { $scope.request_parameters = _.map(model.error.config.params, function(value, key) { - return { key: key, value: value}; + return { key: key, value: value }; }); } @@ -45,9 +44,9 @@ export class InspectCtrl { if (_.isString(model.error.config.data)) { $scope.request_parameters = this.getParametersFromQueryString(model.error.config.data); - } else { + } else { $scope.request_parameters = _.map(model.error.config.data, function(value, key) { - return {key: key, value: angular.toJson(value, true)}; + return { key: key, value: angular.toJson(value, true) }; }); } } @@ -55,11 +54,14 @@ export class InspectCtrl { } getParametersFromQueryString(queryString) { var result = []; - var parameters = queryString.split("&"); + var parameters = queryString.split('&'); for (var i = 0; i < parameters.length; i++) { - var keyValue = parameters[i].split("="); + var keyValue = parameters[i].split('='); if (keyValue[1].length > 0) { - result.push({ key: keyValue[0], value: (window).unescape(keyValue[1]) }); + result.push({ + key: keyValue[0], + value: (window).unescape(keyValue[1]), + }); } } return result; diff --git a/public/app/core/controllers/invited_ctrl.ts b/public/app/core/controllers/invited_ctrl.ts index ed4bd1793b8..e9127af26b7 100644 --- a/public/app/core/controllers/invited_ctrl.ts +++ b/public/app/core/controllers/invited_ctrl.ts @@ -2,18 +2,26 @@ import coreModule from '../core_module'; import config from 'app/core/config'; export class InvitedCtrl { - /** @ngInject */ constructor($scope, $routeParams, contextSrv, backendSrv) { contextSrv.sidemenu = false; $scope.formModel = {}; + $scope.navModel = { + main: { + icon: 'gicon gicon-branding', + text: 'Invite', + subTitle: 'Register your Grafana account', + breadcrumbs: [{ title: 'Login', url: 'login' }], + }, + }; + $scope.init = function() { backendSrv.get('/api/user/invite/' + $routeParams.code).then(function(invite) { $scope.formModel.name = invite.name; $scope.formModel.email = invite.email; $scope.formModel.username = invite.email; - $scope.formModel.inviteCode = $routeParams.code; + $scope.formModel.inviteCode = $routeParams.code; $scope.greeting = invite.name || invite.email || invite.username; $scope.invitedBy = invite.invitedBy; diff --git a/public/app/core/controllers/json_editor_ctrl.ts b/public/app/core/controllers/json_editor_ctrl.ts index ba6d9abfd74..d369fe8b3c0 100644 --- a/public/app/core/controllers/json_editor_ctrl.ts +++ b/public/app/core/controllers/json_editor_ctrl.ts @@ -2,16 +2,18 @@ import angular from 'angular'; import coreModule from '../core_module'; export class JsonEditorCtrl { - /** @ngInject */ constructor($scope) { $scope.json = angular.toJson($scope.object, true); $scope.canUpdate = $scope.updateHandler !== void 0 && $scope.contextSrv.isEditor; + $scope.canCopy = $scope.enableCopy; - $scope.update = function () { + $scope.update = function() { var newObject = angular.fromJson($scope.json); $scope.updateHandler(newObject, $scope.object); }; + + $scope.getContentForClipboard = () => $scope.json; } } diff --git a/public/app/core/controllers/login_ctrl.ts b/public/app/core/controllers/login_ctrl.ts index 11bebbce8e6..313fc2efa1a 100644 --- a/public/app/core/controllers/login_ctrl.ts +++ b/public/app/core/controllers/login_ctrl.ts @@ -3,7 +3,6 @@ import coreModule from '../core_module'; import config from 'app/core/config'; export class LoginCtrl { - /** @ngInject */ constructor($scope, backendSrv, contextSrv, $location) { $scope.formModel = { @@ -19,13 +18,13 @@ export class LoginCtrl { $scope.disableLoginForm = config.disableLoginForm; $scope.disableUserSignUp = config.disableUserSignUp; - $scope.loginHint = config.loginHint; + $scope.loginHint = config.loginHint; $scope.loginMode = true; $scope.submitBtnText = 'Log in'; $scope.init = function() { - $scope.$watch("loginMode", $scope.loginModeChanged); + $scope.$watch('loginMode', $scope.loginModeChanged); if (config.loginError) { $scope.appEvent('alert-warning', ['Login Failed', config.loginError]); @@ -51,7 +50,7 @@ export class LoginCtrl { backendSrv.post('/api/user/signup', $scope.formModel).then(function(result) { if (result.status === 'SignUpCreated') { - $location.path('/signup').search({email: $scope.formModel.email}); + $location.path('/signup').search({ email: $scope.formModel.email }); } else { window.location.href = config.appSubUrl + '/'; } diff --git a/public/app/core/controllers/reset_password_ctrl.ts b/public/app/core/controllers/reset_password_ctrl.ts index 524cfb7af64..360c5bf8071 100644 --- a/public/app/core/controllers/reset_password_ctrl.ts +++ b/public/app/core/controllers/reset_password_ctrl.ts @@ -1,7 +1,6 @@ import coreModule from '../core_module'; export class ResetPasswordCtrl { - /** @ngInject */ constructor($scope, contextSrv, backendSrv, $location) { contextSrv.sidemenu = false; @@ -14,6 +13,15 @@ export class ResetPasswordCtrl { $scope.formModel.code = params.code; } + $scope.navModel = { + main: { + icon: 'gicon gicon-branding', + text: 'Reset Password', + subTitle: 'Reset your Grafana password', + breadcrumbs: [{ title: 'Login', url: 'login' }], + }, + }; + $scope.sendResetEmail = function() { if (!$scope.sendResetForm.$valid) { return; @@ -24,7 +32,9 @@ export class ResetPasswordCtrl { }; $scope.submitReset = function() { - if (!$scope.resetForm.$valid) { return; } + if (!$scope.resetForm.$valid) { + return; + } if ($scope.formModel.newPassword !== $scope.formModel.confirmPassword) { $scope.appEvent('alert-warning', ['New passwords do not match', '']); diff --git a/public/app/core/controllers/signup_ctrl.ts b/public/app/core/controllers/signup_ctrl.ts index eb54110eb6d..ad23e0f7f22 100644 --- a/public/app/core/controllers/signup_ctrl.ts +++ b/public/app/core/controllers/signup_ctrl.ts @@ -1,23 +1,22 @@ -/// - import config from 'app/core/config'; import coreModule from '../core_module'; export class SignUpCtrl { - /** @ngInject */ - constructor( - private $scope: any, - private backendSrv: any, - $location: any, - contextSrv: any) { - + constructor(private $scope: any, private backendSrv: any, $location: any, contextSrv: any) { contextSrv.sidemenu = false; $scope.ctrl = this; $scope.formModel = {}; var params = $location.search(); + + // validate email is semi ok + if (params.email && !params.email.match(/^\S+@\S+$/)) { + console.log('invalid email'); + return; + } + $scope.formModel.orgName = params.email; $scope.formModel.email = params.email; $scope.formModel.username = params.email; @@ -26,13 +25,22 @@ export class SignUpCtrl { $scope.verifyEmailEnabled = false; $scope.autoAssignOrg = false; + $scope.navModel = { + main: { + icon: 'gicon gicon-branding', + text: 'Sign Up', + subTitle: 'Register your Grafana account', + breadcrumbs: [{ title: 'Login', url: 'login' }], + }, + }; + backendSrv.get('/api/user/signup/options').then(options => { $scope.verifyEmailEnabled = options.verifyEmailEnabled; $scope.autoAssignOrg = options.autoAssignOrg; }); } - submit () { + submit() { if (!this.$scope.signUpForm.$valid) { return; } @@ -48,4 +56,3 @@ export class SignUpCtrl { } coreModule.controller('SignUpCtrl', SignUpCtrl); - diff --git a/public/app/core/core.ts b/public/app/core/core.ts index fb92fd81d19..353d8762a9a 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -1,14 +1,13 @@ -import "./directives/dash_class"; -import "./directives/dash_edit_link"; -import "./directives/dropdown_typeahead"; -import "./directives/metric_segment"; -import "./directives/misc"; -import "./directives/ng_model_on_blur"; -import "./directives/tags"; -import "./directives/value_select_dropdown"; -import "./directives/rebuild_on_change"; -import "./directives/give_focus"; -import "./directives/diff-view"; +import './directives/dash_class'; +import './directives/dropdown_typeahead'; +import './directives/metric_segment'; +import './directives/misc'; +import './directives/ng_model_on_blur'; +import './directives/tags'; +import './directives/value_select_dropdown'; +import './directives/rebuild_on_change'; +import './directives/give_focus'; +import './directives/diff-view'; import './jquery_extended'; import './partials'; import './components/jsontree/jsontree'; @@ -17,36 +16,48 @@ import './utils/outline'; import './components/colorpicker/ColorPicker'; import './components/colorpicker/SeriesColorPicker'; import './components/colorpicker/spectrum_picker'; +import './services/search_srv'; +import './services/ng_react'; -import {grafanaAppDirective} from './components/grafana_app'; -import {sideMenuDirective} from './components/sidemenu/sidemenu'; -import {searchDirective} from './components/search/search'; -import {infoPopover} from './components/info_popover'; -import {navbarDirective} from './components/navbar/navbar'; -import {arrayJoin} from './directives/array_join'; -import {liveSrv} from './live/live_srv'; -import {Emitter} from './utils/emitter'; -import {layoutSelector} from './components/layout_selector/layout_selector'; -import {switchDirective} from './components/switch'; -import {dashboardSelector} from './components/dashboard_selector'; -import {queryPartEditorDirective} from './components/query_part/query_part_editor'; -import {formDropdownDirective} from './components/form_dropdown/form_dropdown'; +import { grafanaAppDirective } from './components/grafana_app'; +import { sideMenuDirective } from './components/sidemenu/sidemenu'; +import { searchDirective } from './components/search/search'; +import { infoPopover } from './components/info_popover'; +import { navbarDirective } from './components/navbar/navbar'; +import { arrayJoin } from './directives/array_join'; +import { liveSrv } from './live/live_srv'; +import { Emitter } from './utils/emitter'; +import { layoutSelector } from './components/layout_selector/layout_selector'; +import { switchDirective } from './components/switch'; +import { dashboardSelector } from './components/dashboard_selector'; +import { queryPartEditorDirective } from './components/query_part/query_part_editor'; +import { formDropdownDirective } from './components/form_dropdown/form_dropdown'; import 'app/core/controllers/all'; import 'app/core/services/all'; -import 'app/core/routes/routes'; import './filters/filters'; import coreModule from './core_module'; import appEvents from './app_events'; import colors from './utils/colors'; -import {assignModelProperties} from './utils/model_utils'; -import {contextSrv} from './services/context_srv'; -import {KeybindingSrv} from './services/keybindingSrv'; -import {helpModal} from './components/help/help'; -import {JsonExplorer} from './components/json_explorer/json_explorer'; -import {NavModelSrv, NavModel} from './nav_model_srv'; -import {registerAngularDirectives} from './angular_wrappers'; +import { assignModelProperties } from './utils/model_utils'; +import { contextSrv } from './services/context_srv'; +import { KeybindingSrv } from './services/keybindingSrv'; +import { helpModal } from './components/help/help'; +import { JsonExplorer } from './components/json_explorer/json_explorer'; +import { NavModelSrv, NavModel } from './nav_model_srv'; +import { userPicker } from './components/user_picker'; +import { teamPicker } from './components/team_picker'; +import { geminiScrollbar } from './components/scroll/scroll'; +import { gfPageDirective } from './components/gf_page'; +import { orgSwitcher } from './components/org_switcher'; +import { profiler } from './profiler'; +import { registerAngularDirectives } from './angular_wrappers'; +import { updateLegendValues } from './time_series2'; +import TimeSeries from './time_series2'; +import { searchResultsDirective } from './components/search/search_results'; +import { manageDashboardsDirective } from './components/manage_dashboards/manage_dashboards'; export { + profiler, registerAngularDirectives, arrayJoin, coreModule, @@ -71,4 +82,13 @@ export { JsonExplorer, NavModelSrv, NavModel, + userPicker, + teamPicker, + geminiScrollbar, + gfPageDirective, + orgSwitcher, + manageDashboardsDirective, + TimeSeries, + updateLegendValues, + searchResultsDirective, }; diff --git a/public/app/core/directives/array_join.ts b/public/app/core/directives/array_join.ts index 6eb1cc0dd65..f3416f43576 100644 --- a/public/app/core/directives/array_join.ts +++ b/public/app/core/directives/array_join.ts @@ -1,5 +1,3 @@ -/// - import _ from 'lodash'; import coreModule from '../core_module'; @@ -10,7 +8,6 @@ export function arrayJoin() { restrict: 'A', require: 'ngModel', link: function(scope, element, attr, ngModel) { - function split_array(text) { return (text || '').split(','); } @@ -25,9 +22,8 @@ export function arrayJoin() { ngModel.$parsers.push(split_array); ngModel.$formatters.push(join_array); - } + }, }; } coreModule.directive('arrayJoin', arrayJoin); - diff --git a/public/app/core/directives/dash_class.js b/public/app/core/directives/dash_class.js index 08f4d3c7326..4a139272632 100644 --- a/public/app/core/directives/dash_class.js +++ b/public/app/core/directives/dash_class.js @@ -18,21 +18,16 @@ function (_, $, coreModule) { elem.toggleClass('panel-in-fullscreen', false); }); - var lastHideControlsVal; - $scope.$watch('dashboard.hideControls', function() { - if (!$scope.dashboard) { - return; + $scope.$watch('ctrl.dashboardViewState.state.editview', function(newValue) { + if (newValue) { + elem.toggleClass('dashboard-page--settings-opening', _.isString(newValue)); + setTimeout(function() { + elem.toggleClass('dashboard-page--settings-open', _.isString(newValue)); + }, 10); + } else { + elem.removeClass('dashboard-page--settings-opening'); + elem.removeClass('dashboard-page--settings-open'); } - - var hideControls = $scope.dashboard.hideControls; - if (lastHideControlsVal !== hideControls) { - elem.toggleClass('hide-controls', hideControls); - lastHideControlsVal = hideControls; - } - }); - - $scope.$watch('playlistSrv.isPlaying', function(newValue) { - elem.toggleClass('playlist-active', newValue === true); }); } }; diff --git a/public/app/core/directives/dash_edit_link.js b/public/app/core/directives/dash_edit_link.js deleted file mode 100644 index d9a439b95c2..00000000000 --- a/public/app/core/directives/dash_edit_link.js +++ /dev/null @@ -1,137 +0,0 @@ -define([ - 'jquery', - 'angular', - '../core_module', -], -function ($, angular, coreModule) { - 'use strict'; - - var editViewMap = { - 'settings': { src: 'public/app/features/dashboard/partials/settings.html'}, - 'annotations': { src: 'public/app/features/annotations/partials/editor.html'}, - 'templating': { src: 'public/app/features/templating/partials/editor.html'}, - 'history': { html: ''}, - 'timepicker': { src: 'public/app/features/dashboard/timepicker/dropdown.html' }, - 'import': { html: '' } - }; - - coreModule.default.directive('dashEditorView', function($compile, $location, $rootScope) { - return { - restrict: 'A', - link: function(scope, elem) { - var editorScope; - var lastEditView; - - function hideEditorPane(hideToShowOtherView) { - if (editorScope) { - editorScope.dismiss(hideToShowOtherView); - } - } - - function showEditorPane(evt, options) { - if (options.editview) { - options.src = editViewMap[options.editview].src; - options.html = editViewMap[options.editview].html; - } - - if (lastEditView && lastEditView === options.editview) { - hideEditorPane(false); - return; - } - - hideEditorPane(true); - - lastEditView = options.editview; - editorScope = options.scope ? options.scope.$new() : scope.$new(); - - editorScope.dismiss = function(hideToShowOtherView) { - editorScope.$destroy(); - lastEditView = null; - editorScope = null; - elem.removeClass('dash-edit-view--open'); - - if (!hideToShowOtherView) { - setTimeout(function() { - elem.empty(); - }, 250); - } - - if (options.editview) { - var urlParams = $location.search(); - if (options.editview === urlParams.editview) { - delete urlParams.editview; - - // even though we always are in apply phase here - // some angular bug is causing location search updates to - // not happen always so this is a hack fix or that - setTimeout(function() { - $rootScope.$apply(function() { - $location.search(urlParams); - }); - }); - } - } - }; - - if (options.editview === 'import') { - var modalScope = $rootScope.$new(); - modalScope.$on("$destroy", function() { - editorScope.dismiss(); - }); - - $rootScope.appEvent('show-modal', { - templateHtml: '', - scope: modalScope, - backdrop: 'static' - }); - - return; - } - - var view; - if (options.src) { - view = angular.element(document.createElement('div')); - view.html('
    '); - } else { - view = angular.element(document.createElement('div')); - view.addClass('tabbed-view'); - view.html(options.html); - } - - $compile(view)(editorScope); - - setTimeout(function() { - elem.empty(); - elem.append(view); - setTimeout(function() { - elem.addClass('dash-edit-view--open'); - }, 10); - }, 10); - } - - scope.$watch("dashboardViewState.state.editview", function(newValue, oldValue) { - if (newValue) { - showEditorPane(null, {editview: newValue}); - } else if (oldValue) { - if (lastEditView === oldValue) { - hideEditorPane(); - } - } - }); - - scope.$on("$destroy", hideEditorPane); - - scope.onAppEvent('hide-dash-editor', function() { - hideEditorPane(false); - }); - - scope.onAppEvent('show-dash-editor', showEditorPane); - - scope.onAppEvent('panel-fullscreen-enter', function() { - scope.appEvent('hide-dash-editor'); - }); - } - }; - }); -}); - diff --git a/public/app/core/directives/diff-view.ts b/public/app/core/directives/diff-view.ts index db76681498c..84cb597e543 100644 --- a/public/app/core/directives/diff-view.ts +++ b/public/app/core/directives/diff-view.ts @@ -1,5 +1,3 @@ -/// - import angular from 'angular'; import coreModule from '../core_module'; @@ -8,8 +6,7 @@ export class DeltaCtrl { /** @ngInject */ constructor(private $rootScope) { - - const waitForCompile = (mutations) => { + const waitForCompile = mutations => { if (mutations.length === 1) { this.$rootScope.appEvent('json-diff-ready'); } @@ -72,7 +69,7 @@ export function linkJson() { link: '@lineLink', switchView: '&', }, - template: `Line {{ line }}` + template: `Line {{ line }}`, }; } coreModule.directive('diffLinkJson', linkJson); diff --git a/public/app/core/directives/dropdown_typeahead.js b/public/app/core/directives/dropdown_typeahead.js index b44e953785e..25772b4638a 100644 --- a/public/app/core/directives/dropdown_typeahead.js +++ b/public/app/core/directives/dropdown_typeahead.js @@ -12,7 +12,7 @@ function (_, $, coreModule) { ' class="gf-form-input input-medium tight-form-input"' + ' spellcheck="false" style="display:none">'; - var buttonTemplate = ''; diff --git a/public/app/core/directives/give_focus.ts b/public/app/core/directives/give_focus.ts index 722cc4e5c10..32e7205f84b 100644 --- a/public/app/core/directives/give_focus.ts +++ b/public/app/core/directives/give_focus.ts @@ -1,5 +1,3 @@ -/// - import coreModule from '../core_module'; coreModule.directive('giveFocus', function() { @@ -8,19 +6,23 @@ coreModule.directive('giveFocus', function() { e.stopPropagation(); }); - scope.$watch(attrs.giveFocus, function (newValue) { - if (!newValue) { - return; - } - setTimeout(function() { - element.focus(); - var domEl = element[0]; - if (domEl.setSelectionRange) { - var pos = element.val().length * 2; - domEl.setSelectionRange(pos, pos); + scope.$watch( + attrs.giveFocus, + function(newValue) { + if (!newValue) { + return; } - }, 200); - }, true); + setTimeout(function() { + element.focus(); + var domEl = element[0]; + if (domEl.setSelectionRange) { + var pos = element.val().length * 2; + domEl.setSelectionRange(pos, pos); + } + }, 200); + }, + true + ); }; }); diff --git a/public/app/core/directives/metric_segment.js b/public/app/core/directives/metric_segment.js index 2754f8d8c6e..7ba4a5a5259 100644 --- a/public/app/core/directives/metric_segment.js +++ b/public/app/core/directives/metric_segment.js @@ -22,6 +22,7 @@ function (_, $, coreModule) { segment: "=", getOptions: "&", onChange: "&", + debounce: "@", }, link: function($scope, elem) { var $input = $(inputTemplate); @@ -30,6 +31,7 @@ function (_, $, coreModule) { var options = null; var cancelBlur = null; var linkMode = true; + var debounceLookup = $scope.debounce; $input.appendTo(elem); $button.appendTo(elem); @@ -135,6 +137,10 @@ function (_, $, coreModule) { return items ? this.process(items) : items; }; + if (debounceLookup) { + typeahead.lookup = _.debounce(typeahead.lookup, 500, {leading: true}); + } + $button.keydown(function(evt) { // trigger typeahead on down arrow or enter key if (evt.keyCode === 40 || evt.keyCode === 13) { diff --git a/public/app/core/directives/misc.ts b/public/app/core/directives/misc.ts index 3ec5add0c35..299de05f112 100644 --- a/public/app/core/directives/misc.ts +++ b/public/app/core/directives/misc.ts @@ -1,50 +1,55 @@ -import angular from "angular"; -import Clipboard from "clipboard"; -import coreModule from "../core_module"; -import kbn from "app/core/utils/kbn"; +import angular from 'angular'; +import Clipboard from 'clipboard'; +import coreModule from '../core_module'; +import kbn from 'app/core/utils/kbn'; +import { appEvents } from 'app/core/core'; /** @ngInject */ function tip($compile) { return { - restrict: "E", + restrict: 'E', link: function(scope, elem, attrs) { var _t = '"; - _t = _t.replace(/{/g, "\\{").replace(/}/g, "\\}"); + '\'">
    '; + _t = _t.replace(/{/g, '\\{').replace(/}/g, '\\}'); elem.replaceWith($compile(angular.element(_t))(scope)); - } + }, }; } function clipboardButton() { return { scope: { - getText: "&clipboardButton" + getText: '&clipboardButton', }, link: function(scope, elem) { scope.clipboard = new Clipboard(elem[0], { text: function() { return scope.getText(); - } + }, }); - scope.$on("$destroy", function() { + scope.clipboard.on('success', () => { + appEvents.emit('alert-success', ['Content copied to clipboard']); + }); + + scope.$on('$destroy', function() { if (scope.clipboard) { scope.clipboard.destroy(); } }); - } + }, }; } /** @ngInject */ function compile($compile) { return { - restrict: "A", + restrict: 'A', link: function(scope, element, attrs) { scope.$watch( function(scope) { @@ -55,42 +60,42 @@ function compile($compile) { $compile(element.contents())(scope); } ); - } + }, }; } function watchChange() { return { - scope: { onchange: "&watchChange" }, + scope: { onchange: '&watchChange' }, link: function(scope, element) { - element.on("input", function() { + element.on('input', function() { scope.$apply(function() { scope.onchange({ inputValue: element.val() }); }); }); - } + }, }; } /** @ngInject */ function editorOptBool($compile) { return { - restrict: "E", + restrict: 'E', link: function(scope, elem, attrs) { - var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : ""; - var tip = attrs.tip ? " " + attrs.tip + "" : ""; - var showIf = attrs.showIf ? ' ng-show="' + attrs.showIf + '" ' : ""; + var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : ''; + var tip = attrs.tip ? ' ' + attrs.tip + '' : ''; + var showIf = attrs.showIf ? ' ng-show="' + attrs.showIf + '" ' : ''; var template = '
    " + + '>' + ' " + + '' + ''; elem.replaceWith($compile(angular.element(template))(scope)); - } + }, }; } /** @ngInject */ function editorCheckbox($compile, $interpolate) { return { - restrict: "E", + restrict: 'E', link: function(scope, elem, attrs) { var text = $interpolate(attrs.text)(scope); var model = $interpolate(attrs.model)(scope); - var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : ""; - var tip = attrs.tip ? " " + attrs.tip + "" : ""; - var label = - '"; + var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : ''; + var tip = attrs.tip ? ' ' + attrs.tip + '' : ''; + var label = ''; var template = ''; template = template + label; - elem.addClass("gf-form-checkbox"); + elem.addClass('gf-form-checkbox'); elem.html($compile(angular.element(template))(scope)); - } + }, }; } /** @ngInject */ function gfDropdown($parse, $compile, $timeout) { function buildTemplate(items, placement?) { - var upclass = placement === "top" ? "dropup" : ""; - var ul = [ - '" - ]; + var upclass = placement === 'top' ? 'dropup' : ''; + var ul = ['']; for (let index = 0; index < items.length; index++) { let item = items[index]; @@ -171,26 +164,24 @@ function gfDropdown($parse, $compile, $timeout) { } var li = - "" + + '' + '" + - (item.text || "") + - ""; + (item.click ? ' ng-click="' + item.click + '"' : '') + + (item.target ? ' target="' + item.target + '"' : '') + + (item.method ? ' data-method="' + item.method + '"' : '') + + '>' + + (item.text || '') + + ''; if (item.submenu && item.submenu.length) { - li += buildTemplate(item.submenu).join("\n"); + li += buildTemplate(item.submenu).join('\n'); } - li += ""; + li += ''; ul.splice(index + 1, 0, li); } @@ -198,29 +189,27 @@ function gfDropdown($parse, $compile, $timeout) { } return { - restrict: "EA", + restrict: 'EA', scope: true, link: function postLink(scope, iElement, iAttrs) { var getter = $parse(iAttrs.gfDropdown), items = getter(scope); $timeout(function() { - var placement = iElement.data("placement"); - var dropdown = angular.element( - buildTemplate(items, placement).join("") - ); + var placement = iElement.data('placement'); + var dropdown = angular.element(buildTemplate(items, placement).join('')); dropdown.insertAfter(iElement); - $compile(iElement.next("ul.dropdown-menu"))(scope); + $compile(iElement.next('ul.dropdown-menu'))(scope); }); - iElement.addClass("dropdown-toggle").attr("data-toggle", "dropdown"); - } + iElement.addClass('dropdown-toggle').attr('data-toggle', 'dropdown'); + }, }; } -coreModule.directive("tip", tip); -coreModule.directive("clipboardButton", clipboardButton); -coreModule.directive("compile", compile); -coreModule.directive("watchChange", watchChange); -coreModule.directive("editorOptBool", editorOptBool); -coreModule.directive("editorCheckbox", editorCheckbox); -coreModule.directive("gfDropdown", gfDropdown); +coreModule.directive('tip', tip); +coreModule.directive('clipboardButton', clipboardButton); +coreModule.directive('compile', compile); +coreModule.directive('watchChange', watchChange); +coreModule.directive('editorOptBool', editorOptBool); +coreModule.directive('editorCheckbox', editorCheckbox); +coreModule.directive('gfDropdown', gfDropdown); diff --git a/public/app/core/directives/ng_model_on_blur.ts b/public/app/core/directives/ng_model_on_blur.ts index 2f7de3bf20c..4385c72f1b0 100644 --- a/public/app/core/directives/ng_model_on_blur.ts +++ b/public/app/core/directives/ng_model_on_blur.ts @@ -17,7 +17,7 @@ function ngModelOnBlur() { ngModelCtrl.$setViewValue(elm.val()); }); }); - } + }, }; } @@ -25,12 +25,14 @@ function emptyToNull() { return { restrict: 'A', require: 'ngModel', - link: function (scope, elm, attrs, ctrl) { - ctrl.$parsers.push(function (viewValue) { - if (viewValue === "") { return null; } + link: function(scope, elm, attrs, ctrl) { + ctrl.$parsers.push(function(viewValue) { + if (viewValue === '') { + return null; + } return viewValue; }); - } + }, }; } @@ -48,7 +50,7 @@ function validTimeSpan() { var info = rangeUtil.describeTextRange(viewValue); return info.invalid !== true; }; - } + }, }; } diff --git a/public/app/core/directives/rebuild_on_change.ts b/public/app/core/directives/rebuild_on_change.ts index db2634869c0..15907dc6c19 100644 --- a/public/app/core/directives/rebuild_on_change.ts +++ b/public/app/core/directives/rebuild_on_change.ts @@ -20,7 +20,6 @@ function getBlockNodes(nodes) { /** @ngInject **/ function rebuildOnChange($animate) { - return { multiElement: true, terminal: true, @@ -57,14 +56,14 @@ function rebuildOnChange($animate) { transclude(function(clone, newScope) { childScope = newScope; clone[clone.length++] = document.createComment(' end rebuild on change '); - block = {clone: clone}; + block = { clone: clone }; $animate.enter(clone, elem.parent(), elem); }); } else { cleanUp(); } }); - } + }, }; } diff --git a/public/app/core/directives/tags.ts b/public/app/core/directives/tags.ts index 0f4d0990d47..6b36ee7d503 100644 --- a/public/app/core/directives/tags.ts +++ b/public/app/core/directives/tags.ts @@ -1,46 +1,21 @@ import angular from 'angular'; import $ from 'jquery'; import coreModule from '../core_module'; +import tags from 'app/core/utils/tags'; import 'vendor/tagsinput/bootstrap-tagsinput.js'; -function djb2(str) { - var hash = 5381; - for (var i = 0; i < str.length; i++) { - hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */ - } - return hash; -} - function setColor(name, element) { - var hash = djb2(name.toLowerCase()); - var colors = [ - "#E24D42","#1F78C1","#BA43A9","#705DA0","#466803", - "#508642","#447EBC","#C15C17","#890F02","#757575", - "#0A437C","#6D1F62","#584477","#629E51","#2F4F4F", - "#BF1B00","#806EB7","#8a2eb8", "#699e00","#000000", - "#3F6833","#2F575E","#99440A","#E0752D","#0E4AB4", - "#58140C","#052B51","#511749","#3F2B5B", - ]; - var borderColors = [ - "#FF7368","#459EE7","#E069CF","#9683C6","#6C8E29", - "#76AC68","#6AA4E2","#E7823D","#AF3528","#9B9B9B", - "#3069A2","#934588","#7E6A9D","#88C477","#557575", - "#E54126","#A694DD","#B054DE", "#8FC426","#262626", - "#658E59","#557D84","#BF6A30","#FF9B53","#3470DA", - "#7E3A32","#2B5177","#773D6F","#655181", - ]; - var color = colors[Math.abs(hash % colors.length)]; - var borderColor = borderColors[Math.abs(hash % borderColors.length)]; - element.css("background-color", color); - element.css("border-color", borderColor); + const { color, borderColor } = tags.getTagColorsFromName(name); + element.css('background-color', color); + element.css('border-color', borderColor); } function tagColorFromName() { return { - scope: { tagColorFromName: "=" }, - link: function (scope, element) { + scope: { tagColorFromName: '=' }, + link: function(scope, element) { setColor(scope.tagColorFromName, element); - } + }, }; } @@ -63,12 +38,11 @@ function bootstrapTagsinput() { restrict: 'EA', scope: { model: '=ngModel', - onTagsUpdated: "&", + onTagsUpdated: '&', }, template: '', replace: false, link: function(scope, element, attrs) { - if (!angular.isArray(scope.model)) { scope.model = []; } @@ -81,13 +55,18 @@ function bootstrapTagsinput() { select.tagsinput({ typeahead: { - source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null + source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) + ? scope.$parent[attrs.typeaheadSource] + : null, }, widthClass: attrs.widthClass, itemValue: getItemProperty(scope, attrs.itemvalue), - itemText : getItemProperty(scope, attrs.itemtext), - tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ? - scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; } + itemText: getItemProperty(scope, attrs.itemtext), + tagClass: angular.isFunction(scope.$parent[attrs.tagclass]) + ? scope.$parent[attrs.tagclass] + : function() { + return attrs.tagclass; + }, }); select.on('itemAdded', function(event) { @@ -97,7 +76,12 @@ function bootstrapTagsinput() { scope.onTagsUpdated(); } } - var tagElement = select.next().children("span").filter(function() { return $(this).text() === event.item; }); + var tagElement = select + .next() + .children('span') + .filter(function() { + return $(this).text() === event.item; + }); setColor(event.item, tagElement); }); @@ -111,19 +95,22 @@ function bootstrapTagsinput() { } }); - scope.$watch("model", function() { - if (!angular.isArray(scope.model)) { - scope.model = []; - } + scope.$watch( + 'model', + function() { + if (!angular.isArray(scope.model)) { + scope.model = []; + } - select.tagsinput('removeAll'); + select.tagsinput('removeAll'); - for (var i = 0; i < scope.model.length; i++) { - select.tagsinput('add', scope.model[i]); - } - - }, true); - } + for (var i = 0; i < scope.model.length; i++) { + select.tagsinput('add', scope.model[i]); + } + }, + true + ); + }, }; } diff --git a/public/app/core/filters/filters.ts b/public/app/core/filters/filters.ts index 0f53df8b4fb..c6aea32d38d 100644 --- a/public/app/core/filters/filters.ts +++ b/public/app/core/filters/filters.ts @@ -1,5 +1,3 @@ -/// - import _ from 'lodash'; import angular from 'angular'; import moment from 'moment'; @@ -41,19 +39,17 @@ coreModule.filter('moment', function() { coreModule.filter('noXml', function() { var noXml = function(text) { - return _.isString(text) - ? text - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - : text; + return _.isString(text) + ? text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/'/g, ''') + .replace(/"/g, '"') + : text; }; return function(text) { - return _.isArray(text) - ? _.map(text, noXml) - : noXml(text); + return _.isArray(text) ? _.map(text, noXml) : noXml(text); }; }); diff --git a/public/app/core/live/live_srv.ts b/public/app/core/live/live_srv.ts index 8e808e60e1a..e03e8296794 100644 --- a/public/app/core/live/live_srv.ts +++ b/public/app/core/live/live_srv.ts @@ -1,7 +1,7 @@ import _ from 'lodash'; import config from 'app/core/config'; -import {Observable} from 'rxjs/Observable'; +import { Observable } from 'rxjs/Observable'; export class LiveSrv { conn: any; @@ -14,7 +14,7 @@ export class LiveSrv { getWebSocketUrl() { var l = window.location; - return ((l.protocol === "https:") ? "wss://" : "ws://") + l.host + config.appSubUrl + '/ws'; + return (l.protocol === 'https:' ? 'wss://' : 'ws://') + l.host + config.appSubUrl + '/ws'; } getConnection() { @@ -30,25 +30,25 @@ export class LiveSrv { console.log('Live: connecting...'); this.conn = new WebSocket(this.getWebSocketUrl()); - this.conn.onclose = (evt) => { - console.log("Live: websocket onclose", evt); - reject({message: 'Connection closed'}); + this.conn.onclose = evt => { + console.log('Live: websocket onclose', evt); + reject({ message: 'Connection closed' }); this.initPromise = null; setTimeout(this.reconnect.bind(this), 2000); }; - this.conn.onmessage = (evt) => { + this.conn.onmessage = evt => { this.handleMessage(evt.data); }; - this.conn.onerror = (evt) => { + this.conn.onerror = evt => { this.initPromise = null; - reject({message: 'Connection error'}); - console.log("Live: websocket error", evt); + reject({ message: 'Connection error' }); + console.log('Live: websocket error', evt); }; - this.conn.onopen = (evt) => { + this.conn.onopen = evt => { console.log('opened'); this.initPromise = null; resolve(this.conn); @@ -62,7 +62,7 @@ export class LiveSrv { message = JSON.parse(message); if (!message.stream) { - console.log("Error: stream message without stream!", message); + console.log('Error: stream message without stream!', message); return; } @@ -85,7 +85,7 @@ export class LiveSrv { this.getConnection().then(conn => { _.each(this.observers, (value, key) => { - this.send({action: 'subscribe', stream: key}); + this.send({ action: 'subscribe', stream: key }); }); }); } @@ -98,7 +98,7 @@ export class LiveSrv { this.observers[stream] = observer; this.getConnection().then(conn => { - this.send({action: 'subscribe', stream: stream}); + this.send({ action: 'subscribe', stream: stream }); }); } @@ -107,7 +107,7 @@ export class LiveSrv { delete this.observers[stream]; this.getConnection().then(conn => { - this.send({action: 'unsubscribe', stream: stream}); + this.send({ action: 'unsubscribe', stream: stream }); }); } @@ -126,8 +126,7 @@ export class LiveSrv { // this.send({action: 'subscribe', stream: name}); // }); } - } var instance = new LiveSrv(); -export {instance as liveSrv}; +export { instance as liveSrv }; diff --git a/public/app/core/mod_defs.d.ts b/public/app/core/mod_defs.d.ts index e42bac80310..d5b2e6c2a8a 100644 --- a/public/app/core/mod_defs.d.ts +++ b/public/app/core/mod_defs.d.ts @@ -1,18 +1,14 @@ -declare module "app/core/controllers/all" { +declare module 'app/core/controllers/all' { let json: any; - export {json}; + export { json }; } -declare module "app/core/routes/all" { +declare module 'app/core/routes/all' { let json: any; - export {json}; + export { json }; } -declare module "app/core/services/all" { +declare module 'app/core/services/all' { let json: any; export default json; } - - - - diff --git a/public/app/core/nav_model_srv.ts b/public/app/core/nav_model_srv.ts index dd61db5d346..a9ebd4e79ed 100644 --- a/public/app/core/nav_model_srv.ts +++ b/public/app/core/nav_model_srv.ts @@ -1,224 +1,84 @@ -/// - import coreModule from 'app/core/core_module'; +import config from 'app/core/config'; +import _ from 'lodash'; export interface NavModelItem { - title: string; + text: string; url: string; icon?: string; - iconUrl?: string; + img?: string; + id: string; + active?: boolean; + hideFromTabs?: boolean; + divider?: boolean; + children: NavModelItem[]; + target?: string; } -export interface NavModel { - section: NavModelItem; - menu: NavModelItem[]; +export class NavModel { + breadcrumbs: NavModelItem[]; + main: NavModelItem; + node: NavModelItem; + + constructor() { + this.breadcrumbs = []; + } } export class NavModelSrv { - + navItems: any; /** @ngInject */ - constructor(private contextSrv) { + constructor() { + this.navItems = config.bootData.navTree; } - getAlertingNav(subPage) { - return { - section: { - title: 'Alerting', - url: 'plugins', - icon: 'icon-gf icon-gf-alert' - }, - menu: [ - {title: 'Alert List', active: subPage === 0, url: 'alerting/list', icon: 'fa fa-list-ul'}, - {title: 'Notification channels', active: subPage === 1, url: 'alerting/notifications', icon: 'fa fa-bell-o'}, - ] - }; + getCfgNode() { + return _.find(this.navItems, { id: 'cfg' }); } - getDatasourceNav(subPage) { - return { - section: { - title: 'Data Sources', - url: 'datasources', - icon: 'icon-gf icon-gf-datasources' - }, - menu: [ - {title: 'List view', active: subPage === 0, url: 'datasources', icon: 'fa fa-list-ul'}, - {title: 'Add data source', active: subPage === 1, url: 'datasources/new', icon: 'fa fa-plus'}, - ] - }; - } + getNav(...args) { + var children = this.navItems; + var nav = new NavModel(); - getPlaylistsNav(subPage) { - return { - section: { - title: 'Playlists', - url: 'playlists', - icon: 'fa fa-fw fa-film' - }, - menu: [ - {title: 'List view', active: subPage === 0, url: 'playlists', icon: 'fa fa-list-ul'}, - {title: 'Add Playlist', active: subPage === 1, url: 'playlists/create', icon: 'fa fa-plus'}, - ] - }; - } + for (let id of args) { + // if its a number then it's the index to use for main + if (_.isNumber(id)) { + nav.main = nav.breadcrumbs[id]; + break; + } - getProfileNav() { - return { - section: { - title: 'User Profile', - url: 'profile', - icon: 'fa fa-fw fa-user' - }, - menu: [] - }; + let node = _.find(children, { id: id }); + nav.breadcrumbs.push(node); + nav.node = node; + nav.main = node; + children = node.children; + } + + if (nav.main.children) { + for (let item of nav.main.children) { + item.active = false; + + if (item.url === nav.node.url) { + item.active = true; + } + } + } + + return nav; } getNotFoundNav() { - return { - section: { - title: 'Page', - url: '', - icon: 'fa fa-fw fa-warning' - }, - menu: [] + var node = { + text: 'Page not found', + icon: 'fa fa-fw fa-warning', + subTitle: '404 Error', }; - } - - getOrgNav(subPage) { - return { - section: { - title: 'Organization', - url: 'org', - icon: 'icon-gf icon-gf-users' - }, - menu: [ - {title: 'Preferences', active: subPage === 0, url: 'org', icon: 'fa fa-fw fa-cog'}, - {title: 'Org Users', active: subPage === 1, url: 'org/users', icon: 'fa fa-fw fa-users'}, - {title: 'API Keys', active: subPage === 2, url: 'org/apikeys', icon: 'fa fa-fw fa-key'}, - ] - }; - } - - getAdminNav(subPage) { - return { - section: { - title: 'Admin', - url: 'admin', - icon: 'fa fa-fw fa-cogs' - }, - menu: [ - {title: 'Users', active: subPage === 0, url: 'admin/users', icon: 'fa fa-fw fa-user'}, - {title: 'Orgs', active: subPage === 1, url: 'admin/orgs', icon: 'fa fa-fw fa-users'}, - {title: 'Server Settings', active: subPage === 2, url: 'admin/settings', icon: 'fa fa-fw fa-cogs'}, - {title: 'Server Stats', active: subPage === 2, url: 'admin/stats', icon: 'fa fa-fw fa-line-chart'}, - {title: 'Style Guide', active: subPage === 2, url: 'styleguide', icon: 'fa fa-fw fa-key'}, - ] - }; - } - - getPluginsNav() { - return { - section: { - title: 'Plugins', - url: 'plugins', - icon: 'icon-gf icon-gf-apps' - }, - menu: [] - }; - } - - getDashboardNav(dashboard, dashNavCtrl) { - // special handling for snapshots - if (dashboard.meta.isSnapshot) { - return { - section: { - title: dashboard.title, - icon: 'icon-gf icon-gf-snapshot' - }, - menu: [ - { - title: 'Go to original dashboard', - icon: 'fa fa-fw fa-external-link', - url: dashboard.snapshot.originalUrl, - } - ] - }; - } - - var menu = []; - - if (dashboard.meta.canEdit) { - menu.push({ - title: 'Settings', - icon: 'fa fa-fw fa-cog', - clickHandler: () => dashNavCtrl.openEditView('settings') - }); - - menu.push({ - title: 'Templating', - icon: 'fa fa-fw fa-code', - clickHandler: () => dashNavCtrl.openEditView('templating') - }); - - menu.push({ - title: 'Annotations', - icon: 'fa fa-fw fa-comment', - clickHandler: () => dashNavCtrl.openEditView('annotations') - }); - - if (!dashboard.meta.isHome) { - menu.push({ - title: 'Version history', - icon: 'fa fa-fw fa-history', - clickHandler: () => dashNavCtrl.openEditView('history') - }); - } - - menu.push({ - title: 'View JSON', - icon: 'fa fa-fw fa-eye', - clickHandler: () => dashNavCtrl.viewJson() - }); - } - - if (this.contextSrv.isEditor && !dashboard.editable) { - menu.push({ - title: 'Make Editable', - icon: 'fa fa-fw fa-edit', - clickHandler: () => dashNavCtrl.makeEditable() - }); - } - - menu.push({ - title: 'Shortcuts', - icon: 'fa fa-fw fa-keyboard-o', - clickHandler: () => dashNavCtrl.showHelpModal() - }); - - if (this.contextSrv.isEditor) { - menu.push({ - title: 'Save As ...', - icon: 'fa fa-fw fa-save', - clickHandler: () => dashNavCtrl.saveDashboardAs() - }); - } - - if (dashboard.meta.canSave) { - menu.push({ - title: 'Delete', - icon: 'fa fa-fw fa-trash', - clickHandler: () => dashNavCtrl.deleteDashboard() - }); - - } return { - section: { - title: dashboard.title, - icon: 'icon-gf icon-gf-dashboard' - }, - menu: menu + breadcrumbs: [node], + node: node, + main: node, }; } } diff --git a/public/app/core/profiler.ts b/public/app/core/profiler.ts index e762b3fc4b3..f459c5d4557 100644 --- a/public/app/core/profiler.ts +++ b/public/app/core/profiler.ts @@ -20,10 +20,13 @@ export class Profiler { return; } - $rootScope.$watch(() => { - this.digestCounter++; - return false; - }, () => {}); + $rootScope.$watch( + () => { + this.digestCounter++; + return false; + }, + () => {} + ); $rootScope.onAppEvent('refresh', this.refresh.bind(this), $rootScope); $rootScope.onAppEvent('dashboard-fetch-end', this.dashboardFetched.bind(this), $rootScope); @@ -55,12 +58,12 @@ export class Profiler { dashboardInitialized() { setTimeout(() => { - console.log("Dashboard::Performance Total Digests: " + this.digestCounter); - console.log("Dashboard::Performance Total Watchers: " + this.getTotalWatcherCount()); - console.log("Dashboard::Performance Total ScopeCount: " + this.scopeCount); + console.log('Dashboard::Performance Total Digests: ' + this.digestCounter); + console.log('Dashboard::Performance Total Watchers: ' + this.getTotalWatcherCount()); + console.log('Dashboard::Performance Total ScopeCount: ' + this.scopeCount); var timeTaken = this.timings.lastPanelInitializedAt - this.timings.dashboardLoadStart; - console.log("Dashboard::Performance All panels initialized in " + timeTaken + " ms"); + console.log('Dashboard::Performance All panels initialized in ' + timeTaken + ' ms'); // measure digest performance var rootDigestStart = window.performance.now(); @@ -68,7 +71,7 @@ export class Profiler { this.$rootScope.$apply(); } - console.log("Dashboard::Performance Root Digest " + ((window.performance.now() - rootDigestStart) / 30)); + console.log('Dashboard::Performance Root Digest ' + (window.performance.now() - rootDigestStart) / 30); }, 3000); } @@ -77,15 +80,15 @@ export class Profiler { var scopes = 0; var root = $(document.getElementsByTagName('body')); - var f = function (element) { + var f = function(element) { if (element.data().hasOwnProperty('$scope')) { scopes++; - angular.forEach(element.data().$scope.$$watchers, function () { + angular.forEach(element.data().$scope.$$watchers, function() { count++; }); } - angular.forEach(element.children(), function (childElement) { + angular.forEach(element.children(), function(childElement) { f($(childElement)); }); }; @@ -116,8 +119,7 @@ export class Profiler { this.panelsInitCount++; this.timings.lastPanelInitializedAt = new Date().getTime(); } - } var profiler = new Profiler(); -export {profiler}; +export { profiler }; diff --git a/public/app/core/routes/bundle_loader.ts b/public/app/core/routes/bundle_loader.ts deleted file mode 100644 index b86f9fb1495..00000000000 --- a/public/app/core/routes/bundle_loader.ts +++ /dev/null @@ -1,22 +0,0 @@ -export class BundleLoader { - lazy: any; - - constructor(bundleName) { - var defer = null; - - this.lazy = ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { - if (defer) { - return defer.promise; - } - - defer = $q.defer(); - - System.import(bundleName).then(() => { - defer.resolve(); - }); - - return defer.promise; - }]; - - } -} diff --git a/public/app/core/routes/dashboard_loaders.ts b/public/app/core/routes/dashboard_loaders.ts deleted file mode 100644 index 14e093d5169..00000000000 --- a/public/app/core/routes/dashboard_loaders.ts +++ /dev/null @@ -1,50 +0,0 @@ -import coreModule from '../core_module'; - -export class LoadDashboardCtrl { - - /** @ngInject */ - constructor($scope, $routeParams, dashboardLoaderSrv, backendSrv, $location) { - $scope.appEvent("dashboard-fetch-start"); - - if (!$routeParams.slug) { - backendSrv.get('/api/dashboards/home').then(function(homeDash) { - if (homeDash.redirectUri) { - $location.path('dashboard/' + homeDash.redirectUri); - } else { - var meta = homeDash.meta; - meta.canSave = meta.canShare = meta.canStar = false; - $scope.initDashboard(homeDash, $scope); - } - }); - return; - } - - dashboardLoaderSrv.loadDashboard($routeParams.type, $routeParams.slug).then(function(result) { - $scope.initDashboard(result, $scope); - }); - } -} - -export class NewDashboardCtrl { - - /** @ngInject */ - constructor($scope) { - $scope.initDashboard({ - meta: { canStar: false, canShare: false, isNew: true }, - dashboard: { - title: "New dashboard", - rows: [ - { - title: 'Dashboard Row', - height: '250px', - panels: [], - isNew: true, - } - ] - }, - }, $scope); - } -} - -coreModule.controller('LoadDashboardCtrl', LoadDashboardCtrl); -coreModule.controller('NewDashboardCtrl', NewDashboardCtrl); diff --git a/public/app/core/routes/routes.ts b/public/app/core/routes/routes.ts deleted file mode 100644 index 1f9dbcae57c..00000000000 --- a/public/app/core/routes/routes.ts +++ /dev/null @@ -1,233 +0,0 @@ -import './dashboard_loaders'; -import coreModule from 'app/core/core_module'; - -/** @ngInject **/ -function setupAngularRoutes($routeProvider, $locationProvider) { - $locationProvider.html5Mode(true); - - var loadOrgBundle = { - lazy: ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { - return System.import('app/features/org/all'); - }] - }; - - var loadAdminBundle = { - lazy: ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { - return System.import('app/features/admin/admin'); - }] - }; - - var loadAlertingBundle = { - lazy: ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { - return System.import('app/features/alerting/all'); - }] - }; - - $routeProvider - .when('/', { - templateUrl: 'public/app/partials/dashboard.html', - controller : 'LoadDashboardCtrl', - reloadOnSearch: false, - pageClass: 'page-dashboard', - }) - .when('/dashboard/:type/:slug', { - templateUrl: 'public/app/partials/dashboard.html', - controller : 'LoadDashboardCtrl', - reloadOnSearch: false, - pageClass: 'page-dashboard', - }) - .when('/dashboard-solo/:type/:slug', { - templateUrl: 'public/app/features/panel/partials/soloPanel.html', - controller : 'SoloPanelCtrl', - reloadOnSearch: false, - pageClass: 'page-dashboard', - }) - .when('/dashboard/new', { - templateUrl: 'public/app/partials/dashboard.html', - controller : 'NewDashboardCtrl', - reloadOnSearch: false, - pageClass: 'page-dashboard', - }) - .when('/dashboards/list', { - templateUrl: 'public/app/features/dashboard/partials/dash_list.html', - controller : 'DashListCtrl', - }) - .when('/datasources', { - templateUrl: 'public/app/features/plugins/partials/ds_list.html', - controller : 'DataSourcesCtrl', - controllerAs: 'ctrl', - }) - .when('/datasources/edit/:id', { - templateUrl: 'public/app/features/plugins/partials/ds_edit.html', - controller : 'DataSourceEditCtrl', - controllerAs: 'ctrl', - }) - .when('/datasources/new', { - templateUrl: 'public/app/features/plugins/partials/ds_edit.html', - controller : 'DataSourceEditCtrl', - controllerAs: 'ctrl', - }) - .when('/org', { - templateUrl: 'public/app/features/org/partials/orgDetails.html', - controller : 'OrgDetailsCtrl', - resolve: loadOrgBundle, - }) - .when('/org/new', { - templateUrl: 'public/app/features/org/partials/newOrg.html', - controller : 'NewOrgCtrl', - resolve: loadOrgBundle, - }) - .when('/org/users', { - templateUrl: 'public/app/features/org/partials/orgUsers.html', - controller : 'OrgUsersCtrl', - controllerAs: 'ctrl', - resolve: loadOrgBundle, - }) - .when('/org/apikeys', { - templateUrl: 'public/app/features/org/partials/orgApiKeys.html', - controller : 'OrgApiKeysCtrl', - resolve: loadOrgBundle, - }) - .when('/profile', { - templateUrl: 'public/app/features/org/partials/profile.html', - controller : 'ProfileCtrl', - controllerAs: 'ctrl', - resolve: loadOrgBundle, - }) - .when('/profile/password', { - templateUrl: 'public/app/features/org/partials/change_password.html', - controller : 'ChangePasswordCtrl', - resolve: loadOrgBundle, - }) - .when('/profile/select-org', { - templateUrl: 'public/app/features/org/partials/select_org.html', - controller : 'SelectOrgCtrl', - resolve: loadOrgBundle, - }) - // ADMIN - .when('/admin', { - templateUrl: 'public/app/features/admin/partials/admin_home.html', - controller : 'AdminHomeCtrl', - controllerAs: 'ctrl', - resolve: loadAdminBundle, - }) - .when('/admin/settings', { - templateUrl: 'public/app/features/admin/partials/settings.html', - controller : 'AdminSettingsCtrl', - controllerAs: 'ctrl', - resolve: loadAdminBundle, - }) - .when('/admin/users', { - templateUrl: 'public/app/features/admin/partials/users.html', - controller : 'AdminListUsersCtrl', - controllerAs: 'ctrl', - resolve: loadAdminBundle, - }) - .when('/admin/users/create', { - templateUrl: 'public/app/features/admin/partials/new_user.html', - controller : 'AdminEditUserCtrl', - resolve: loadAdminBundle, - }) - .when('/admin/users/edit/:id', { - templateUrl: 'public/app/features/admin/partials/edit_user.html', - controller : 'AdminEditUserCtrl', - resolve: loadAdminBundle, - }) - .when('/admin/orgs', { - templateUrl: 'public/app/features/admin/partials/orgs.html', - controller : 'AdminListOrgsCtrl', - controllerAs: 'ctrl', - resolve: loadAdminBundle, - }) - .when('/admin/orgs/edit/:id', { - templateUrl: 'public/app/features/admin/partials/edit_org.html', - controller : 'AdminEditOrgCtrl', - controllerAs: 'ctrl', - resolve: loadAdminBundle, - }) - .when('/admin/stats', { - templateUrl: 'public/app/features/admin/partials/stats.html', - controller : 'AdminStatsCtrl', - controllerAs: 'ctrl', - resolve: loadAdminBundle, - }) - // LOGIN / SIGNUP - .when('/login', { - templateUrl: 'public/app/partials/login.html', - controller : 'LoginCtrl', - }) - .when('/invite/:code', { - templateUrl: 'public/app/partials/signup_invited.html', - controller : 'InvitedCtrl', - }) - .when('/signup', { - templateUrl: 'public/app/partials/signup_step2.html', - controller : 'SignUpCtrl', - }) - .when('/user/password/send-reset-email', { - templateUrl: 'public/app/partials/reset_password.html', - controller : 'ResetPasswordCtrl', - }) - .when('/user/password/reset', { - templateUrl: 'public/app/partials/reset_password.html', - controller : 'ResetPasswordCtrl', - }) - .when('/dashboard/snapshots', { - templateUrl: 'public/app/features/snapshot/partials/snapshots.html', - controller : 'SnapshotsCtrl', - controllerAs: 'ctrl', - }) - .when('/plugins', { - templateUrl: 'public/app/features/plugins/partials/plugin_list.html', - controller: 'PluginListCtrl', - controllerAs: 'ctrl', - }) - .when('/plugins/:pluginId/edit', { - templateUrl: 'public/app/features/plugins/partials/plugin_edit.html', - controller: 'PluginEditCtrl', - controllerAs: 'ctrl', - }) - .when('/plugins/:pluginId/page/:slug', { - templateUrl: 'public/app/features/plugins/partials/plugin_page.html', - controller: 'AppPageCtrl', - controllerAs: 'ctrl', - }) - .when('/styleguide/:page?', { - controller: 'StyleGuideCtrl', - controllerAs: 'ctrl', - templateUrl: 'public/app/features/styleguide/styleguide.html', - }) - .when('/alerting', { - redirectTo: '/alerting/list' - }) - .when('/alerting/list', { - templateUrl: 'public/app/features/alerting/partials/alert_list.html', - controller: 'AlertListCtrl', - controllerAs: 'ctrl', - resolve: loadAlertingBundle, - }) - .when('/alerting/notifications', { - templateUrl: 'public/app/features/alerting/partials/notifications_list.html', - controller: 'AlertNotificationsListCtrl', - controllerAs: 'ctrl', - resolve: loadAlertingBundle, - }) - .when('/alerting/notification/new', { - templateUrl: 'public/app/features/alerting/partials/notification_edit.html', - controller: 'AlertNotificationEditCtrl', - controllerAs: 'ctrl', - resolve: loadAlertingBundle, - }) - .when('/alerting/notification/:id/edit', { - templateUrl: 'public/app/features/alerting/partials/notification_edit.html', - controller: 'AlertNotificationEditCtrl', - controllerAs: 'ctrl', - resolve: loadAlertingBundle, - }) - .otherwise({ - templateUrl: 'public/app/partials/error.html', - controller: 'ErrorCtrl' - }); -} - -coreModule.config(setupAngularRoutes); diff --git a/public/app/core/services/alert_srv.ts b/public/app/core/services/alert_srv.ts index 1a87ed6096c..fc76ef9e371 100644 --- a/public/app/core/services/alert_srv.ts +++ b/public/app/core/services/alert_srv.ts @@ -1,5 +1,3 @@ -/// - import angular from 'angular'; import _ from 'lodash'; import coreModule from 'app/core/core_module'; @@ -9,34 +7,48 @@ export class AlertSrv { list: any[]; /** @ngInject */ - constructor(private $timeout, private $rootScope, private $modal) { + constructor(private $timeout, private $rootScope) { this.list = []; } init() { - this.$rootScope.onAppEvent('alert-error', (e, alert) => { - this.set(alert[0], alert[1], 'error', 12000); - }, this.$rootScope); + this.$rootScope.onAppEvent( + 'alert-error', + (e, alert) => { + this.set(alert[0], alert[1], 'error', 12000); + }, + this.$rootScope + ); - this.$rootScope.onAppEvent('alert-warning', (e, alert) => { - this.set(alert[0], alert[1], 'warning', 5000); - }, this.$rootScope); + this.$rootScope.onAppEvent( + 'alert-warning', + (e, alert) => { + this.set(alert[0], alert[1], 'warning', 5000); + }, + this.$rootScope + ); - this.$rootScope.onAppEvent('alert-success', (e, alert) => { - this.set(alert[0], alert[1], 'success', 3000); - }, this.$rootScope); + this.$rootScope.onAppEvent( + 'alert-success', + (e, alert) => { + this.set(alert[0], alert[1], 'success', 3000); + }, + this.$rootScope + ); appEvents.on('alert-warning', options => this.set(options[0], options[1], 'warning', 5000)); appEvents.on('alert-success', options => this.set(options[0], options[1], 'success', 3000)); appEvents.on('alert-error', options => this.set(options[0], options[1], 'error', 7000)); - appEvents.on('confirm-modal', this.showConfirmModal.bind(this)); } getIconForSeverity(severity) { switch (severity) { - case 'success': return 'fa fa-check'; - case 'error': return 'fa fa-exclamation-triangle'; - default: return 'fa fa-exclamation'; + case 'success': + return 'fa fa-check'; + case 'error': + return 'fa fa-exclamation-triangle'; + default: + return 'fa fa-exclamation'; } } @@ -52,7 +64,7 @@ export class AlertSrv { title: title || '', text: text || '', severity: severity || 'info', - icon: this.getIconForSeverity(severity) + icon: this.getIconForSeverity(severity), }; var newAlertJson = angular.toJson(newAlert); @@ -73,7 +85,7 @@ export class AlertSrv { this.$rootScope.$digest(); } - return(newAlert); + return newAlert; } clear(alert) { @@ -83,45 +95,6 @@ export class AlertSrv { clearAll() { this.list = []; } - - showConfirmModal(payload) { - var scope = this.$rootScope.$new(); - - scope.onConfirm = function() { - payload.onConfirm(); - scope.dismiss(); - }; - - scope.updateConfirmText = function(value) { - scope.confirmTextValid = payload.confirmText.toLowerCase() === value.toLowerCase(); - }; - - scope.title = payload.title; - scope.text = payload.text; - scope.text2 = payload.text2; - scope.confirmText = payload.confirmText; - - scope.onConfirm = payload.onConfirm; - scope.onAltAction = payload.onAltAction; - scope.altActionText = payload.altActionText; - scope.icon = payload.icon || "fa-check"; - scope.yesText = payload.yesText || "Yes"; - scope.noText = payload.noText || "Cancel"; - scope.confirmTextValid = scope.confirmText ? false : true; - - var confirmModal = this.$modal({ - template: 'public/app/partials/confirm_modal.html', - persist: false, - modalClass: 'confirm-modal', - show: false, - scope: scope, - keyboard: false - }); - - confirmModal.then(function(modalEl) { - modalEl.modal('show'); - }); - } } coreModule.service('alertSrv', AlertSrv); diff --git a/public/app/core/services/all.js b/public/app/core/services/all.js index a308febb219..0a973440c5e 100644 --- a/public/app/core/services/all.js +++ b/public/app/core/services/all.js @@ -8,5 +8,6 @@ define([ './segment_srv', './backend_srv', './dynamic_directive_srv', + './bridge_srv' ], function () {}); diff --git a/public/app/core/services/analytics.ts b/public/app/core/services/analytics.ts index 87e84efa706..370773154e5 100644 --- a/public/app/core/services/analytics.ts +++ b/public/app/core/services/analytics.ts @@ -3,14 +3,17 @@ import coreModule from 'app/core/core_module'; import config from 'app/core/config'; export class Analytics { - /** @ngInject */ - constructor(private $rootScope, private $location) { - } + constructor(private $rootScope, private $location) {} gaInit() { $.getScript('https://www.google-analytics.com/analytics.js'); // jQuery shortcut - var ga = (window).ga = (window).ga || function () { (ga.q = ga.q || []).push(arguments); }; ga.l = +new Date; + var ga = ((window).ga = + (window).ga || + function() { + (ga.q = ga.q || []).push(arguments); + }); + ga.l = +new Date(); ga('create', (config).googleAnalyticsId, 'auto'); return ga; } @@ -33,4 +36,3 @@ function startAnalytics(googleAnalyticsSrv) { } coreModule.service('googleAnalyticsSrv', Analytics).run(startAnalytics); - diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts index 544e6c60de8..8b7ca518e8b 100644 --- a/public/app/core/services/backend_srv.ts +++ b/public/app/core/services/backend_srv.ts @@ -1,8 +1,7 @@ -/// - import _ from 'lodash'; import coreModule from 'app/core/core_module'; import appEvents from 'app/core/app_events'; +import { DashboardModel } from 'app/features/dashboard/dashboard_model'; export class BackendSrv { private inFlightRequests = {}; @@ -10,8 +9,7 @@ export class BackendSrv { private noBackendCache: boolean; /** @ngInject */ - constructor(private $http, private alertSrv, private $q, private $timeout, private contextSrv) { - } + constructor(private $http, private alertSrv, private $q, private $timeout, private contextSrv) {} get(url, params?) { return this.request({ method: 'GET', url: url, params: params }); @@ -51,22 +49,22 @@ export class BackendSrv { } if (err.status === 422) { - this.alertSrv.set("Validation failed", data.message, "warning", 4000); + this.alertSrv.set('Validation failed', data.message, 'warning', 4000); throw data; } data.severity = 'error'; if (err.status < 500) { - data.severity = "warning"; + data.severity = 'warning'; } if (data.message) { - let description = ""; + let description = ''; let message = data.message; if (message.length > 80) { description = message; - message = "Error"; + message = 'Error'; } this.alertSrv.set(message, description, data.severity, 10000); } @@ -85,32 +83,35 @@ export class BackendSrv { options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId; } - if (options.url.indexOf("/") === 0) { + if (options.url.indexOf('/') === 0) { options.url = options.url.substring(1); } } - return this.$http(options).then(results => { - if (options.method !== 'GET') { - if (results && results.data.message) { - if (options.showSuccessAlert !== false) { - this.alertSrv.set(results.data.message, '', 'success', 3000); + return this.$http(options).then( + results => { + if (options.method !== 'GET') { + if (results && results.data.message) { + if (options.showSuccessAlert !== false) { + this.alertSrv.set(results.data.message, '', 'success', 3000); + } } } - } - return results.data; - }, err => { - // handle unauthorized - if (err.status === 401 && this.contextSrv.user.isSignedIn && firstAttempt) { - return this.loginPing().then(() => { - options.retry = 1; - return this.request(options); - }); - } + return results.data; + }, + err => { + // handle unauthorized + if (err.status === 401 && this.contextSrv.user.isSignedIn && firstAttempt) { + return this.loginPing().then(() => { + options.retry = 1; + return this.request(options); + }); + } - this.$timeout(this.requestErrorHandler.bind(this, err), 50); - throw err; - }); + this.$timeout(this.requestErrorHandler.bind(this, err), 50); + throw err; + } + ); } addCanceler(requestId, canceler) { @@ -153,7 +154,7 @@ export class BackendSrv { options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId; } - if (options.url.indexOf("/") === 0) { + if (options.url.indexOf('/') === 0) { options.url = options.url.substring(1); } @@ -167,70 +168,200 @@ export class BackendSrv { } } - return this.$http(options).then(response => { - appEvents.emit('ds-request-response', response); - return response; - }).catch(err => { - if (err.status === this.HTTP_REQUEST_CANCELLED) { - throw {err, cancelled: true}; - } + return this.$http(options) + .then(response => { + appEvents.emit('ds-request-response', response); + return response; + }) + .catch(err => { + if (err.status === this.HTTP_REQUEST_CANCELLED) { + throw { err, cancelled: true }; + } - // handle unauthorized for backend requests - if (requestIsLocal && firstAttempt && err.status === 401) { - return this.loginPing().then(() => { - options.retry = 1; - if (canceler) { - canceler.resolve(); - } - return this.datasourceRequest(options); - }); - } + // handle unauthorized for backend requests + if (requestIsLocal && firstAttempt && err.status === 401) { + return this.loginPing().then(() => { + options.retry = 1; + if (canceler) { + canceler.resolve(); + } + return this.datasourceRequest(options); + }); + } - // populate error obj on Internal Error - if (_.isString(err.data) && err.status === 500) { - err.data = { - error: err.statusText, - response: err.data, - }; - } + // populate error obj on Internal Error + if (_.isString(err.data) && err.status === 500) { + err.data = { + error: err.statusText, + response: err.data, + }; + } - // for Prometheus - if (err.data && !err.data.message && _.isString(err.data.error)) { - err.data.message = err.data.error; - } + // for Prometheus + if (err.data && !err.data.message && _.isString(err.data.error)) { + err.data.message = err.data.error; + } - appEvents.emit('ds-request-error', err); - throw err; - - }).finally(() => { - // clean up - if (options.requestId) { - this.inFlightRequests[options.requestId].shift(); - } - }); + appEvents.emit('ds-request-error', err); + throw err; + }) + .finally(() => { + // clean up + if (options.requestId) { + this.inFlightRequests[options.requestId].shift(); + } + }); } loginPing() { - return this.request({url: '/api/login/ping', method: 'GET', retry: 1 }); + return this.request({ url: '/api/login/ping', method: 'GET', retry: 1 }); } search(query) { return this.get('/api/search', query); } - getDashboard(type, slug) { - return this.get('/api/dashboards/' + type + '/' + slug); + getDashboardBySlug(slug) { + return this.get(`/api/dashboards/db/${slug}`); + } + + getDashboardByUid(uid: string) { + return this.get(`/api/dashboards/uid/${uid}`); + } + + getFolderByUid(uid: string) { + return this.get(`/api/folders/${uid}`); } saveDashboard(dash, options) { - options = (options || {}); + options = options || {}; return this.post('/api/dashboards/db/', { dashboard: dash, + folderId: options.folderId, overwrite: options.overwrite === true, message: options.message || '', }); } + + createFolder(payload: any) { + return this.post('/api/folders', payload); + } + + updateFolder(folder, options) { + options = options || {}; + + return this.put(`/api/folders/${folder.uid}`, { + title: folder.title, + version: folder.version, + overwrite: options.overwrite === true, + }); + } + + deleteFolder(uid: string, showSuccessAlert) { + return this.request({ method: 'DELETE', url: `/api/folders/${uid}`, showSuccessAlert: showSuccessAlert === true }); + } + + deleteDashboard(uid, showSuccessAlert) { + return this.request({ + method: 'DELETE', + url: `/api/dashboards/uid/${uid}`, + showSuccessAlert: showSuccessAlert === true, + }); + } + + deleteFoldersAndDashboards(folderUids, dashboardUids) { + const tasks = []; + + for (let folderUid of folderUids) { + tasks.push(this.createTask(this.deleteFolder.bind(this), true, folderUid, true)); + } + + for (let dashboardUid of dashboardUids) { + tasks.push(this.createTask(this.deleteDashboard.bind(this), true, dashboardUid, true)); + } + + return this.executeInOrder(tasks, []); + } + + moveDashboards(dashboardUids, toFolder) { + const tasks = []; + + for (let uid of dashboardUids) { + tasks.push(this.createTask(this.moveDashboard.bind(this), true, uid, toFolder)); + } + + return this.executeInOrder(tasks, []).then(result => { + return { + totalCount: result.length, + successCount: _.filter(result, { succeeded: true }).length, + alreadyInFolderCount: _.filter(result, { alreadyInFolder: true }).length, + }; + }); + } + + private moveDashboard(uid, toFolder) { + let deferred = this.$q.defer(); + + this.getDashboardByUid(uid).then(fullDash => { + const model = new DashboardModel(fullDash.dashboard, fullDash.meta); + + if ((!fullDash.meta.folderId && toFolder.id === 0) || fullDash.meta.folderId === toFolder.id) { + deferred.resolve({ alreadyInFolder: true }); + return; + } + + const clone = model.getSaveModelClone(); + let options = { + folderId: toFolder.id, + overwrite: false, + }; + + this.saveDashboard(clone, options) + .then(() => { + deferred.resolve({ succeeded: true }); + }) + .catch(err => { + if (err.data && err.data.status === 'plugin-dashboard') { + err.isHandled = true; + options.overwrite = true; + + this.saveDashboard(clone, options) + .then(() => { + deferred.resolve({ succeeded: true }); + }) + .catch(err => { + deferred.resolve({ succeeded: false }); + }); + } else { + deferred.resolve({ succeeded: false }); + } + }); + }); + + return deferred.promise; + } + + private createTask(fn, ignoreRejections, ...args: any[]) { + return result => { + return fn + .apply(null, args) + .then(res => { + return Array.prototype.concat(result, [res]); + }) + .catch(err => { + if (ignoreRejections) { + return result; + } + + throw err; + }); + }; + } + + private executeInOrder(tasks, initialValue) { + return tasks.reduce(this.$q.when, initialValue); + } } coreModule.service('backendSrv', BackendSrv); diff --git a/public/app/core/services/bridge_srv.ts b/public/app/core/services/bridge_srv.ts new file mode 100644 index 00000000000..4a5649a6c52 --- /dev/null +++ b/public/app/core/services/bridge_srv.ts @@ -0,0 +1,57 @@ +import coreModule from 'app/core/core_module'; +import appEvents from 'app/core/app_events'; +import { store } from 'app/stores/store'; +import { reaction } from 'mobx'; +import locationUtil from 'app/core/utils/location_util'; + +// Services that handles angular -> mobx store sync & other react <-> angular sync +export class BridgeSrv { + private fullPageReloadRoutes; + + /** @ngInject */ + constructor(private $location, private $timeout, private $window, private $rootScope, private $route) { + this.fullPageReloadRoutes = ['/logout']; + } + + init() { + this.$rootScope.$on('$routeUpdate', (evt, data) => { + let angularUrl = this.$location.url(); + if (store.view.currentUrl !== angularUrl) { + store.view.updatePathAndQuery(this.$location.path(), this.$location.search(), this.$route.current.params); + } + }); + + this.$rootScope.$on('$routeChangeSuccess', (evt, data) => { + store.view.updatePathAndQuery(this.$location.path(), this.$location.search(), this.$route.current.params); + }); + + reaction( + () => store.view.currentUrl, + currentUrl => { + let angularUrl = this.$location.url(); + const url = locationUtil.stripBaseFromUrl(currentUrl); + if (angularUrl !== url) { + this.$timeout(() => { + this.$location.url(url); + }); + console.log('store updating angular $location.url', url); + } + } + ); + + appEvents.on('location-change', payload => { + const urlWithoutBase = locationUtil.stripBaseFromUrl(payload.href); + if (this.fullPageReloadRoutes.indexOf(urlWithoutBase) > -1) { + this.$window.location.href = payload.href; + return; + } + + this.$timeout(() => { + // A hack to use timeout when we're changing things (in this case the url) from outside of Angular. + this.$location.url(urlWithoutBase); + }); + }); + } +} + +coreModule.service('bridgeSrv', BridgeSrv); diff --git a/public/app/core/services/context_srv.ts b/public/app/core/services/context_srv.ts index ddff1093720..5a879895267 100644 --- a/public/app/core/services/context_srv.ts +++ b/public/app/core/services/context_srv.ts @@ -1,5 +1,3 @@ -/// - import config from 'app/core/config'; import _ from 'lodash'; import coreModule from 'app/core/core_module'; @@ -9,6 +7,7 @@ export class User { isGrafanaAdmin: any; isSignedIn: any; orgRole: any; + orgId: number; timezone: string; helpFlags1: number; lightTheme: boolean; @@ -28,18 +27,16 @@ export class ContextSrv { isGrafanaAdmin: any; isEditor: any; sidemenu: any; + sidemenuSmallBreakpoint = false; constructor() { - this.pinned = store.getBool('grafana.sidemenu.pinned', false); - if (this.pinned) { - this.sidemenu = true; - } + this.sidemenu = store.getBool('grafana.sidemenu', true); if (!config.buildInfo) { config.buildInfo = {}; } if (!config.bootData) { - config.bootData = {user: {}, settings: {}}; + config.bootData = { user: {}, settings: {} }; } this.version = config.buildInfo.version; @@ -53,25 +50,18 @@ export class ContextSrv { return this.user.orgRole === role; } - setPinnedState(val) { - this.pinned = val; - store.set('grafana.sidemenu.pinned', val); - } - isGrafanaVisible() { return !!(document.visibilityState === undefined || document.visibilityState === 'visible'); } toggleSideMenu() { this.sidemenu = !this.sidemenu; - if (!this.sidemenu) { - this.setPinnedState(false); - } + store.set('grafana.sidemenu', this.sidemenu); } } var contextSrv = new ContextSrv(); -export {contextSrv}; +export { contextSrv }; coreModule.factory('contextSrv', function() { return contextSrv; diff --git a/public/app/core/services/dynamic_directive_srv.ts b/public/app/core/services/dynamic_directive_srv.ts index 5565e19a3f6..086843b6f9a 100644 --- a/public/app/core/services/dynamic_directive_srv.ts +++ b/public/app/core/services/dynamic_directive_srv.ts @@ -1,10 +1,7 @@ -/// - import angular from 'angular'; import coreModule from '../core_module'; class DynamicDirectiveSrv { - /** @ngInject */ constructor(private $compile, private $rootScope) {} @@ -17,22 +14,25 @@ class DynamicDirectiveSrv { } link(scope, elem, attrs, options) { - options.directive(scope).then(directiveInfo => { - if (!directiveInfo || !directiveInfo.fn) { - elem.empty(); - return; - } + options + .directive(scope) + .then(directiveInfo => { + if (!directiveInfo || !directiveInfo.fn) { + elem.empty(); + return; + } - if (!directiveInfo.fn.registered) { - coreModule.directive(attrs.$normalize(directiveInfo.name), directiveInfo.fn); - directiveInfo.fn.registered = true; - } + if (!directiveInfo.fn.registered) { + coreModule.directive(attrs.$normalize(directiveInfo.name), directiveInfo.fn); + directiveInfo.fn.registered = true; + } - this.addDirective(elem, directiveInfo.name, scope); - }).catch(err => { - console.log('Plugin load:', err); - this.$rootScope.appEvent('alert-error', ['Plugin error', err.toString()]); - }); + this.addDirective(elem, directiveInfo.name, scope); + }) + .catch(err => { + console.log('Plugin load:', err); + this.$rootScope.appEvent('alert-error', ['Plugin error', err.toString()]); + }); } create(options) { @@ -52,7 +52,7 @@ class DynamicDirectiveSrv { } else { this.link(scope, elem, attrs, options); } - } + }, }; return directiveDef; @@ -60,5 +60,3 @@ class DynamicDirectiveSrv { } coreModule.service('dynamicDirectiveSrv', DynamicDirectiveSrv); - - diff --git a/public/app/features/dashboard/impression_store.ts b/public/app/core/services/impression_srv.ts similarity index 75% rename from public/app/features/dashboard/impression_store.ts rename to public/app/core/services/impression_srv.ts index 68478aef09a..3945c048876 100644 --- a/public/app/features/dashboard/impression_store.ts +++ b/public/app/core/services/impression_srv.ts @@ -2,7 +2,7 @@ import store from 'app/core/store'; import _ from 'lodash'; import config from 'app/core/config'; -export class ImpressionsStore { +export class ImpressionSrv { constructor() {} addDashboardImpression(dashboardId) { @@ -15,7 +15,7 @@ export class ImpressionsStore { } } - impressions = impressions.filter((imp) => { + impressions = impressions.filter(imp => { return dashboardId !== imp; }); @@ -28,7 +28,7 @@ export class ImpressionsStore { } getDashboardOpened() { - var impressions = store.get(this.impressionKey(config)) || "[]"; + var impressions = store.get(this.impressionKey(config)) || '[]'; impressions = JSON.parse(impressions); @@ -40,12 +40,9 @@ export class ImpressionsStore { } impressionKey(config) { - return "dashboard_impressions-" + config.bootData.user.orgId; + return 'dashboard_impressions-' + config.bootData.user.orgId; } } -var impressions = new ImpressionsStore(); - -export { - impressions -}; +const impressionSrv = new ImpressionSrv(); +export default impressionSrv; diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index a8f36afc468..1658d74be0a 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -1,5 +1,3 @@ -/// - import $ from 'jquery'; import _ from 'lodash'; @@ -7,15 +5,14 @@ import coreModule from 'app/core/core_module'; import appEvents from 'app/core/app_events'; import Mousetrap from 'mousetrap'; +import 'mousetrap-global-bind'; export class KeybindingSrv { helpModal: boolean; + modalOpen = false; /** @ngInject */ - constructor( - private $rootScope, - private $location) { - + constructor(private $rootScope, private $location) { // clear out all shortcuts on route change $rootScope.$on('$routeChangeSuccess', () => { Mousetrap.reset(); @@ -24,58 +21,99 @@ export class KeybindingSrv { }); this.setupGlobal(); + appEvents.on('show-modal', () => (this.modalOpen = true)); } setupGlobal() { this.bind(['?', 'h'], this.showHelpModal); - this.bind("g h", this.goToHome); - this.bind("g a", this.openAlerting); - this.bind("g p", this.goToProfile); - this.bind("s s", this.openSearchStarred); + this.bind('g h', this.goToHome); + this.bind('g a', this.openAlerting); + this.bind('g p', this.goToProfile); + this.bind('s s', this.openSearchStarred); this.bind('s o', this.openSearch); this.bind('s t', this.openSearchTags); this.bind('f', this.openSearch); + this.bindGlobal('esc', this.exit); } openSearchStarred() { - this.$rootScope.appEvent('show-dash-search', {starred: true}); + appEvents.emit('show-dash-search', { starred: true }); } openSearchTags() { - this.$rootScope.appEvent('show-dash-search', {tagsMode: true}); + appEvents.emit('show-dash-search', { tagsMode: true }); } openSearch() { - this.$rootScope.appEvent('show-dash-search'); + appEvents.emit('show-dash-search'); } openAlerting() { - this.$location.url("/alerting"); + this.$location.url('/alerting'); } goToHome() { - this.$location.url("/"); + this.$location.url('/'); } goToProfile() { - this.$location.url("/profile"); + this.$location.url('/profile'); } showHelpModal() { - appEvents.emit('show-modal', {templateHtml: ''}); + appEvents.emit('show-modal', { templateHtml: '' }); + } + + exit() { + var popups = $('.popover.in'); + if (popups.length > 0) { + return; + } + + appEvents.emit('hide-modal'); + + if (!this.modalOpen) { + this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false }); + } else { + this.modalOpen = false; + } + + // close settings view + var search = this.$location.search(); + if (search.editview) { + delete search.editview; + this.$location.search(search); + } } bind(keyArg, fn) { - Mousetrap.bind(keyArg, evt => { - evt.preventDefault(); - evt.stopPropagation(); - evt.returnValue = false; - return this.$rootScope.$apply(fn.bind(this)); - }, 'keydown'); + Mousetrap.bind( + keyArg, + evt => { + evt.preventDefault(); + evt.stopPropagation(); + evt.returnValue = false; + return this.$rootScope.$apply(fn.bind(this)); + }, + 'keydown' + ); } - showDashEditView(view) { - var search = _.extend(this.$location.search(), {editview: view}); + bindGlobal(keyArg, fn) { + Mousetrap.bindGlobal( + keyArg, + evt => { + evt.preventDefault(); + evt.stopPropagation(); + evt.returnValue = false; + return this.$rootScope.$apply(fn.bind(this)); + }, + 'keydown' + ); + } + + showDashEditView() { + var search = _.extend(this.$location.search(), { editview: 'settings' }); this.$location.search(search); } @@ -83,11 +121,7 @@ export class KeybindingSrv { this.bind('mod+o', () => { dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3; appEvents.emit('graph-hover-clear'); - scope.broadcastRefresh(); - }); - - this.bind('mod+h', () => { - dashboard.hideControls = !dashboard.hideControls; + this.$rootScope.$broadcast('refresh'); }); this.bind('mod+s', e => { @@ -117,7 +151,7 @@ export class KeybindingSrv { fullscreen: true, edit: true, panelId: dashboard.meta.focusPanelId, - toggle: true + toggle: true, }); } }); @@ -137,8 +171,9 @@ export class KeybindingSrv { // delete panel this.bind('p r', () => { if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { - var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); - panelInfo.row.removePanel(panelInfo.panel); + this.$rootScope.appEvent('panel-remove', { + panelId: dashboard.meta.focusPanelId, + }); dashboard.meta.focusPanelId = 0; } }); @@ -146,60 +181,38 @@ export class KeybindingSrv { // share panel this.bind('p s', () => { if (dashboard.meta.focusPanelId) { - var shareScope = scope.$new(); + var shareScope = scope.$new(); var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); shareScope.panel = panelInfo.panel; shareScope.dashboard = dashboard; appEvents.emit('show-modal', { src: 'public/app/features/dashboard/partials/shareModal.html', - scope: shareScope + scope: shareScope, }); } }); - // delete row - this.bind('r r', () => { - if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { - var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); - dashboard.removeRow(panelInfo.row); - dashboard.meta.focusPanelId = 0; - } - }); - - // collapse row - this.bind('r c', () => { - if (dashboard.meta.focusPanelId) { - var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); - panelInfo.row.toggleCollapse(); - dashboard.meta.focusPanelId = 0; - } - }); - // collapse all rows this.bind('d shift+c', () => { - for (let row of dashboard.rows) { - row.collapse = true; - } + dashboard.collapseRows(); }); // expand all rows this.bind('d shift+e', () => { - for (let row of dashboard.rows) { - row.collapse = false; - } + dashboard.expandRows(); }); this.bind('d n', e => { - this.$location.url("/dashboard/new"); + this.$location.url('/dashboard/new'); }); this.bind('d r', () => { - scope.broadcastRefresh(); + this.$rootScope.$broadcast('refresh'); }); this.bind('d s', () => { - this.showDashEditView('settings'); + this.showDashEditView(); }); this.bind('d k', () => { @@ -209,17 +222,6 @@ export class KeybindingSrv { this.bind('d v', () => { appEvents.emit('toggle-view-mode'); }); - - this.bind('esc', () => { - var popups = $('.popover.in'); - if (popups.length > 0) { - return; - } - - scope.appEvent('hide-modal'); - scope.appEvent('hide-dash-editor'); - scope.appEvent('panel-change-view', {fullscreen: false, edit: false}); - }); } } diff --git a/public/app/core/services/ng_react.ts b/public/app/core/services/ng_react.ts new file mode 100644 index 00000000000..3c61412669e --- /dev/null +++ b/public/app/core/services/ng_react.ts @@ -0,0 +1,300 @@ +// +// This is using ng-react with this PR applied https://github.com/ngReact/ngReact/pull/199 +// + +// # ngReact +// ### Use React Components inside of your Angular applications +// +// Composed of +// - reactComponent (generic directive for delegating off to React Components) +// - reactDirective (factory for creating specific directives that correspond to reactComponent directives) + +import React from 'react'; +import ReactDOM from 'react-dom'; +import angular from 'angular'; + +// get a react component from name (components can be an angular injectable e.g. value, factory or +// available on window +function getReactComponent(name, $injector) { + // if name is a function assume it is component and return it + if (angular.isFunction(name)) { + return name; + } + + // a React component name must be specified + if (!name) { + throw new Error('ReactComponent name attribute must be specified'); + } + + // ensure the specified React component is accessible, and fail fast if it's not + var reactComponent; + try { + reactComponent = $injector.get(name); + } catch (e) {} + + if (!reactComponent) { + try { + reactComponent = name.split('.').reduce(function(current, namePart) { + return current[namePart]; + }, window); + } catch (e) {} + } + + if (!reactComponent) { + throw Error('Cannot find react component ' + name); + } + + return reactComponent; +} + +// wraps a function with scope.$apply, if already applied just return +function applied(fn, scope) { + if (fn.wrappedInApply) { + return fn; + } + var wrapped: any = function() { + var args = arguments; + var phase = scope.$root.$$phase; + if (phase === '$apply' || phase === '$digest') { + return fn.apply(null, args); + } else { + return scope.$apply(function() { + return fn.apply(null, args); + }); + } + }; + wrapped.wrappedInApply = true; + return wrapped; +} + +/** + * wraps functions on obj in scope.$apply + * + * keeps backwards compatibility, as if propsConfig is not passed, it will + * work as before, wrapping all functions and won't wrap only when specified. + * + * @version 0.4.1 + * @param obj react component props + * @param scope current scope + * @param propsConfig configuration object for all properties + * @returns {Object} props with the functions wrapped in scope.$apply + */ +function applyFunctions(obj, scope, propsConfig?) { + return Object.keys(obj || {}).reduce(function(prev, key) { + var value = obj[key]; + var config = (propsConfig || {})[key] || {}; + /** + * wrap functions in a function that ensures they are scope.$applied + * ensures that when function is called from a React component + * the Angular digest cycle is run + */ + prev[key] = angular.isFunction(value) && config.wrapApply !== false ? applied(value, scope) : value; + + return prev; + }, {}); +} + +/** + * + * @param watchDepth (value of HTML watch-depth attribute) + * @param scope (angular scope) + * + * Uses the watchDepth attribute to determine how to watch props on scope. + * If watchDepth attribute is NOT reference or collection, watchDepth defaults to deep watching by value + */ +function watchProps(watchDepth, scope, watchExpressions, listener) { + var supportsWatchCollection = angular.isFunction(scope.$watchCollection); + var supportsWatchGroup = angular.isFunction(scope.$watchGroup); + + var watchGroupExpressions = []; + + watchExpressions.forEach(function(expr) { + var actualExpr = getPropExpression(expr); + var exprWatchDepth = getPropWatchDepth(watchDepth, expr); + + if (exprWatchDepth === 'collection' && supportsWatchCollection) { + scope.$watchCollection(actualExpr, listener); + } else if (exprWatchDepth === 'reference' && supportsWatchGroup) { + watchGroupExpressions.push(actualExpr); + } else if (exprWatchDepth === 'one-time') { + //do nothing because we handle our one time bindings after this + } else { + scope.$watch(actualExpr, listener, exprWatchDepth !== 'reference'); + } + }); + + if (watchDepth === 'one-time') { + listener(); + } + + if (watchGroupExpressions.length) { + scope.$watchGroup(watchGroupExpressions, listener); + } +} + +// render React component, with scope[attrs.props] being passed in as the component props +function renderComponent(component, props, scope, elem) { + scope.$evalAsync(function() { + ReactDOM.render(React.createElement(component, props), elem[0]); + }); +} + +// get prop name from prop (string or array) +function getPropName(prop) { + return Array.isArray(prop) ? prop[0] : prop; +} + +// get prop name from prop (string or array) +function getPropConfig(prop) { + return Array.isArray(prop) ? prop[1] : {}; +} + +// get prop expression from prop (string or array) +function getPropExpression(prop) { + return Array.isArray(prop) ? prop[0] : prop; +} + +// find the normalized attribute knowing that React props accept any type of capitalization +function findAttribute(attrs, propName) { + var index = Object.keys(attrs).filter(function(attr) { + return attr.toLowerCase() === propName.toLowerCase(); + })[0]; + return attrs[index]; +} + +// get watch depth of prop (string or array) +function getPropWatchDepth(defaultWatch, prop) { + var customWatchDepth = Array.isArray(prop) && angular.isObject(prop[1]) && prop[1].watchDepth; + return customWatchDepth || defaultWatch; +} + +// # reactComponent +// Directive that allows React components to be used in Angular templates. +// +// Usage: +// +// +// This requires that there exists an injectable or globally available 'Hello' React component. +// The 'props' attribute is optional and is passed to the component. +// +// The following would would create and register the component: +// +// var module = angular.module('ace.react.components'); +// module.value('Hello', React.createClass({ +// render: function() { +// return
    Hello {this.props.name}
    ; +// } +// })); +// +var reactComponent = function($injector) { + return { + restrict: 'E', + replace: true, + link: function(scope, elem, attrs) { + var reactComponent = getReactComponent(attrs.name, $injector); + + var renderMyComponent = function() { + var scopeProps = scope.$eval(attrs.props); + var props = applyFunctions(scopeProps, scope); + + renderComponent(reactComponent, props, scope, elem); + }; + + // If there are props, re-render when they change + attrs.props ? watchProps(attrs.watchDepth, scope, [attrs.props], renderMyComponent) : renderMyComponent(); + + // cleanup when scope is destroyed + scope.$on('$destroy', function() { + if (!attrs.onScopeDestroy) { + ReactDOM.unmountComponentAtNode(elem[0]); + } else { + scope.$eval(attrs.onScopeDestroy, { + unmountComponent: ReactDOM.unmountComponentAtNode.bind(this, elem[0]), + }); + } + }); + }, + }; +}; + +// # reactDirective +// Factory function to create directives for React components. +// +// With a component like this: +// +// var module = angular.module('ace.react.components'); +// module.value('Hello', React.createClass({ +// render: function() { +// return
    Hello {this.props.name}
    ; +// } +// })); +// +// A directive can be created and registered with: +// +// module.directive('hello', function(reactDirective) { +// return reactDirective('Hello', ['name']); +// }); +// +// Where the first argument is the injectable or globally accessible name of the React component +// and the second argument is an array of property names to be watched and passed to the React component +// as props. +// +// This directive can then be used like this: +// +// +// +var reactDirective = function($injector) { + return function(reactComponentName, props, conf, injectableProps) { + var directive = { + restrict: 'E', + replace: true, + link: function(scope, elem, attrs) { + var reactComponent = getReactComponent(reactComponentName, $injector); + + // if props is not defined, fall back to use the React component's propTypes if present + props = props || Object.keys(reactComponent.propTypes || {}); + + // for each of the properties, get their scope value and set it to scope.props + var renderMyComponent = function() { + var scopeProps = {}, + config = {}; + + props.forEach(function(prop) { + var propName = getPropName(prop); + scopeProps[propName] = scope.$eval(findAttribute(attrs, propName)); + config[propName] = getPropConfig(prop); + }); + + scopeProps = applyFunctions(scopeProps, scope, config); + scopeProps = angular.extend({}, scopeProps, injectableProps); + renderComponent(reactComponent, scopeProps, scope, elem); + }; + + // watch each property name and trigger an update whenever something changes, + // to update scope.props with new values + var propExpressions = props.map(function(prop) { + return Array.isArray(prop) ? [attrs[getPropName(prop)], getPropConfig(prop)] : attrs[prop]; + }); + + // If we don't have any props, then our watch statement won't fire. + props.length ? watchProps(attrs.watchDepth, scope, propExpressions, renderMyComponent) : renderMyComponent(); + + // cleanup when scope is destroyed + scope.$on('$destroy', function() { + if (!attrs.onScopeDestroy) { + ReactDOM.unmountComponentAtNode(elem[0]); + } else { + scope.$eval(attrs.onScopeDestroy, { + unmountComponent: ReactDOM.unmountComponentAtNode.bind(this, elem[0]), + }); + } + }); + }, + }; + return angular.extend(directive, conf); + }; +}; + +let ngModule = angular.module('react', []); +ngModule.directive('reactComponent', ['$injector', reactComponent]); +ngModule.factory('reactDirective', ['$injector', reactDirective]); diff --git a/public/app/core/services/popover_srv.ts b/public/app/core/services/popover_srv.ts index bfbd9e9950e..113e1e5fae7 100644 --- a/public/app/core/services/popover_srv.ts +++ b/public/app/core/services/popover_srv.ts @@ -1,5 +1,3 @@ -/// - import _ from 'lodash'; import coreModule from 'app/core/core_module'; import Drop from 'tether-drop'; @@ -57,8 +55,8 @@ function popoverSrv($compile, $rootScope, $timeout) { openOn: options.openOn, hoverCloseDelay: 200, tetherOptions: { - constraints: [{to: 'scrollParent', attachment: "none both"}] - } + constraints: [{ to: 'scrollParent', attachment: 'together' }], + }, }); drop.on('close', () => { @@ -68,6 +66,13 @@ function popoverSrv($compile, $rootScope, $timeout) { openDrop = drop; openDrop.open(); }, 100); + + // return close function + return function() { + if (drop) { + drop.close(); + } + }; }; } diff --git a/public/app/core/services/search_srv.ts b/public/app/core/services/search_srv.ts new file mode 100644 index 00000000000..9f32e21f3f6 --- /dev/null +++ b/public/app/core/services/search_srv.ts @@ -0,0 +1,203 @@ +import _ from 'lodash'; +import coreModule from 'app/core/core_module'; +import impressionSrv from 'app/core/services/impression_srv'; +import store from 'app/core/store'; +import { contextSrv } from 'app/core/services/context_srv'; + +export class SearchSrv { + recentIsOpen: boolean; + starredIsOpen: boolean; + + /** @ngInject */ + constructor(private backendSrv, private $q) { + this.recentIsOpen = store.getBool('search.sections.recent', true); + this.starredIsOpen = store.getBool('search.sections.starred', true); + } + + private getRecentDashboards(sections) { + return this.queryForRecentDashboards().then(result => { + if (result.length > 0) { + sections['recent'] = { + title: 'Recent', + icon: 'fa fa-clock-o', + score: -1, + removable: true, + expanded: this.recentIsOpen, + toggle: this.toggleRecent.bind(this), + items: result, + }; + } + }); + } + + private queryForRecentDashboards() { + var dashIds = _.take(impressionSrv.getDashboardOpened(), 5); + if (dashIds.length === 0) { + return Promise.resolve([]); + } + + return this.backendSrv.search({ dashboardIds: dashIds }).then(result => { + return dashIds + .map(orderId => { + return _.find(result, { id: orderId }); + }) + .filter(hit => hit && !hit.isStarred); + }); + } + + private toggleRecent(section) { + this.recentIsOpen = section.expanded = !section.expanded; + store.set('search.sections.recent', this.recentIsOpen); + + if (!section.expanded || section.items.length) { + return Promise.resolve(section); + } + + return this.queryForRecentDashboards().then(result => { + section.items = result; + return Promise.resolve(section); + }); + } + + private toggleStarred(section) { + this.starredIsOpen = section.expanded = !section.expanded; + store.set('search.sections.starred', this.starredIsOpen); + return Promise.resolve(section); + } + + private getStarred(sections) { + if (!contextSrv.isSignedIn) { + return Promise.resolve(); + } + + return this.backendSrv.search({ starred: true, limit: 5 }).then(result => { + if (result.length > 0) { + sections['starred'] = { + title: 'Starred', + icon: 'fa fa-star-o', + score: -2, + expanded: this.starredIsOpen, + toggle: this.toggleStarred.bind(this), + items: result, + }; + } + }); + } + + search(options) { + let sections: any = {}; + let promises = []; + let query = _.clone(options); + let hasFilters = + options.query || + (options.tag && options.tag.length > 0) || + options.starred || + (options.folderIds && options.folderIds.length > 0); + + if (!options.skipRecent && !hasFilters) { + promises.push(this.getRecentDashboards(sections)); + } + + if (!options.skipStarred && !hasFilters) { + promises.push(this.getStarred(sections)); + } + + query.folderIds = query.folderIds || []; + if (!hasFilters) { + query.folderIds = [0]; + } + + promises.push( + this.backendSrv.search(query).then(results => { + return this.handleSearchResult(sections, results); + }) + ); + + return this.$q.all(promises).then(() => { + return _.sortBy(_.values(sections), 'score'); + }); + } + + private handleSearchResult(sections, results) { + if (results.length === 0) { + return sections; + } + + // create folder index + for (let hit of results) { + if (hit.type === 'dash-folder') { + sections[hit.id] = { + id: hit.id, + uid: hit.uid, + title: hit.title, + expanded: false, + items: [], + toggle: this.toggleFolder.bind(this), + url: hit.url, + icon: 'fa fa-folder', + score: _.keys(sections).length, + }; + } + } + + for (let hit of results) { + if (hit.type === 'dash-folder') { + continue; + } + + let section = sections[hit.folderId || 0]; + if (!section) { + if (hit.folderId) { + section = { + id: hit.folderId, + uid: hit.folderUid, + title: hit.folderTitle, + url: hit.folderUrl, + items: [], + icon: 'fa fa-folder-open', + toggle: this.toggleFolder.bind(this), + score: _.keys(sections).length, + }; + } else { + section = { + id: 0, + title: 'General', + items: [], + icon: 'fa fa-folder-open', + toggle: this.toggleFolder.bind(this), + score: _.keys(sections).length, + }; + } + // add section + sections[hit.folderId || 0] = section; + } + + section.expanded = true; + section.items.push(hit); + } + } + + private toggleFolder(section) { + section.expanded = !section.expanded; + section.icon = section.expanded ? 'fa fa-folder-open' : 'fa fa-folder'; + + if (section.items.length) { + return Promise.resolve(section); + } + + let query = { + folderIds: [section.id], + }; + + return this.backendSrv.search(query).then(results => { + section.items = results; + return Promise.resolve(section); + }); + } + + getDashboardTags() { + return this.backendSrv.get('/api/dashboards/tags'); + } +} + +coreModule.service('searchSrv', SearchSrv); diff --git a/public/app/core/services/segment_srv.js b/public/app/core/services/segment_srv.js index d615525988a..71d0cbfe7a9 100644 --- a/public/app/core/services/segment_srv.js +++ b/public/app/core/services/segment_srv.js @@ -89,7 +89,7 @@ function (angular, _, coreModule) { if (addTemplateVars) { _.each(templateSrv.variables, function(variable) { if (variableTypeFilter === void 0 || variableTypeFilter === variable.type) { - segments.unshift(self.newSegment({ type: 'template', value: '$' + variable.name, expandable: true })); + segments.unshift(self.newSegment({ type: 'value', value: '$' + variable.name, expandable: true })); } }); } @@ -106,10 +106,6 @@ function (angular, _, coreModule) { return new MetricSegment({fake: true, html: '', type: 'plus-button', cssClass: 'query-part' }); }; - this.newSelectTagValue = function() { - return new MetricSegment({value: 'select tag value', fake: true}); - }; - }); }); diff --git a/public/app/core/services/timer.ts b/public/app/core/services/timer.ts index 6355105ee0e..8052b3f2e2c 100644 --- a/public/app/core/services/timer.ts +++ b/public/app/core/services/timer.ts @@ -7,8 +7,7 @@ export class Timer { timers = []; /** @ngInject */ - constructor(private $timeout) { - } + constructor(private $timeout) {} register(promise) { this.timers.push(promise); diff --git a/public/app/core/services/util_srv.ts b/public/app/core/services/util_srv.ts index dca016e1391..1afae0a02f4 100644 --- a/public/app/core/services/util_srv.ts +++ b/public/app/core/services/util_srv.ts @@ -1,5 +1,3 @@ -/// - import coreModule from 'app/core/core_module'; import appEvents from 'app/core/app_events'; @@ -7,12 +5,12 @@ export class UtilSrv { modalScope: any; /** @ngInject */ - constructor(private $rootScope, private $modal) { - } + constructor(private $rootScope, private $modal) {} init() { appEvents.on('show-modal', this.showModal.bind(this), this.$rootScope); appEvents.on('hide-modal', this.hideModal.bind(this), this.$rootScope); + appEvents.on('confirm-modal', this.showConfirmModal.bind(this), this.$rootScope); } hideModal() { @@ -43,13 +41,45 @@ export class UtilSrv { show: false, scope: this.modalScope, keyboard: false, - backdrop: options.backdrop + backdrop: options.backdrop, }); Promise.resolve(modal).then(function(modalEl) { modalEl.modal('show'); }); } + + showConfirmModal(payload) { + var scope = this.$rootScope.$new(); + + scope.onConfirm = function() { + payload.onConfirm(); + scope.dismiss(); + }; + + scope.updateConfirmText = function(value) { + scope.confirmTextValid = payload.confirmText.toLowerCase() === value.toLowerCase(); + }; + + scope.title = payload.title; + scope.text = payload.text; + scope.text2 = payload.text2; + scope.confirmText = payload.confirmText; + + scope.onConfirm = payload.onConfirm; + scope.onAltAction = payload.onAltAction; + scope.altActionText = payload.altActionText; + scope.icon = payload.icon || 'fa-check'; + scope.yesText = payload.yesText || 'Yes'; + scope.noText = payload.noText || 'Cancel'; + scope.confirmTextValid = scope.confirmText ? false : true; + + appEvents.emit('show-modal', { + src: 'public/app/partials/confirm_modal.html', + scope: scope, + modalClass: 'confirm-modal', + }); + } } coreModule.service('utilSrv', UtilSrv); diff --git a/public/app/core/specs/backend_srv_specs.ts b/public/app/core/specs/backend_srv_specs.ts index 0e78007f210..74b058b98c8 100644 --- a/public/app/core/specs/backend_srv_specs.ts +++ b/public/app/core/specs/backend_srv_specs.ts @@ -1,28 +1,30 @@ -import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common'; +import { describe, beforeEach, it, expect, angularMocks } from 'test/lib/common'; import 'app/core/services/backend_srv'; describe('backend_srv', function() { var _backendSrv; - var _http; var _httpBackend; beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module('grafana.services')); - beforeEach(angularMocks.inject(function ($httpBackend, $http, backendSrv) { - _httpBackend = $httpBackend; - _http = $http; - _backendSrv = backendSrv; - })); + beforeEach( + angularMocks.inject(function($httpBackend, $http, backendSrv) { + _httpBackend = $httpBackend; + _backendSrv = backendSrv; + }) + ); describe('when handling errors', function() { it('should return the http status code', function(done) { _httpBackend.whenGET('gateway-error').respond(502); - _backendSrv.datasourceRequest({ - url: 'gateway-error' - }).catch(function(err) { - expect(err.status).to.be(502); - done(); - }); + _backendSrv + .datasourceRequest({ + url: 'gateway-error', + }) + .catch(function(err) { + expect(err.status).to.be(502); + done(); + }); _httpBackend.flush(); }); }); diff --git a/public/app/core/specs/datemath.jest.ts b/public/app/core/specs/datemath.jest.ts index e2bdebcebce..820c53486db 100644 --- a/public/app/core/specs/datemath.jest.ts +++ b/public/app/core/specs/datemath.jest.ts @@ -4,9 +4,9 @@ import * as dateMath from 'app/core/utils/datemath'; import moment from 'moment'; import _ from 'lodash'; -describe("DateMath", () => { +describe('DateMath', () => { var spans = ['s', 'm', 'h', 'd', 'w', 'M', 'y']; - var anchor = '2014-01-01T06:06:06.666Z'; + var anchor = '2014-01-01T06:06:06.666Z'; var unix = moment(anchor).valueOf(); var format = 'YYYY-MM-DDTHH:mm:ss.SSSZ'; var clock; @@ -35,7 +35,7 @@ describe("DateMath", () => { }); }); - it("now/d should set to start of current day", () => { + it('now/d should set to start of current day', () => { var expected = new Date(); expected.setHours(0); expected.setMinutes(0); @@ -46,7 +46,7 @@ describe("DateMath", () => { expect(startOfDay).toBe(expected.getTime()); }); - it("now/d on a utc dashboard should be start of the current day in UTC time", () => { + it('now/d on a utc dashboard should be start of the current day in UTC time', () => { var today = new Date(); var expected = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), 0, 0, 0, 0)); @@ -64,9 +64,9 @@ describe("DateMath", () => { anchored = moment(anchor); }); - _.each(spans, (span) => { + _.each(spans, span => { var nowEx = 'now-5' + span; - var thenEx = anchor + '||-5' + span; + var thenEx = anchor + '||-5' + span; it('should return 5' + span + ' ago', () => { expect(dateMath.parse(nowEx).format(format)).toEqual(now.subtract(5, span).format(format)); @@ -84,20 +84,18 @@ describe("DateMath", () => { describe('rounding', () => { var now; - var anchored; beforeEach(() => { clock = sinon.useFakeTimers(unix); now = moment(); - anchored = moment(anchor); }); - _.each(spans, (span) => { - it('should round now to the beginning of the ' + span, function () { + _.each(spans, span => { + it('should round now to the beginning of the ' + span, function() { expect(dateMath.parse('now/' + span).format(format)).toEqual(now.startOf(span).format(format)); }); - it('should round now to the end of the ' + span, function () { + it('should round now to the end of the ' + span, function() { expect(dateMath.parse('now/' + span, true).format(format)).toEqual(now.endOf(span).format(format)); }); }); @@ -132,7 +130,4 @@ describe("DateMath", () => { expect(date).toEqual(undefined); }); }); - }); - - diff --git a/public/app/core/specs/emitter.jest.ts b/public/app/core/specs/emitter.jest.ts index 1de59852fcc..a819cf0ede2 100644 --- a/public/app/core/specs/emitter.jest.ts +++ b/public/app/core/specs/emitter.jest.ts @@ -1,9 +1,7 @@ -import {Emitter} from '../utils/emitter'; - -describe("Emitter", () => { +import { Emitter } from '../utils/emitter'; +describe('Emitter', () => { describe('given 2 subscribers', () => { - it('should notfiy subscribers', () => { var events = new Emitter(); var sub1Called = false; @@ -45,20 +43,22 @@ describe("Emitter", () => { events.on('test', () => { sub1Called++; - throw {message: "hello"}; + throw { message: 'hello' }; }); events.on('test', () => { sub2Called++; }); - try { events.emit('test', null); } catch (_) { } - try { events.emit('test', null); } catch (_) {} + try { + events.emit('test', null); + } catch (_) {} + try { + events.emit('test', null); + } catch (_) {} expect(sub1Called).toBe(2); expect(sub2Called).toBe(0); }); }); }); - - diff --git a/public/app/core/specs/file_export.jest.ts b/public/app/core/specs/file_export.jest.ts new file mode 100644 index 00000000000..bbb894094ff --- /dev/null +++ b/public/app/core/specs/file_export.jest.ts @@ -0,0 +1,64 @@ +import * as fileExport from '../utils/file_export'; +import { beforeEach, expect } from 'test/lib/common'; + +describe('file_export', () => { + let ctx: any = {}; + + beforeEach(() => { + ctx.seriesList = [ + { + alias: 'series_1', + datapoints: [ + [1, 1500026100000], + [2, 1500026200000], + [null, 1500026300000], + [null, 1500026400000], + [null, 1500026500000], + [6, 1500026600000], + ], + }, + { + alias: 'series_2', + datapoints: [[11, 1500026100000], [12, 1500026200000], [13, 1500026300000], [15, 1500026500000]], + }, + ]; + + ctx.timeFormat = 'X'; // Unix timestamp (seconds) + }); + + describe('when exporting series as rows', () => { + it('should export points in proper order', () => { + let text = fileExport.convertSeriesListToCsv(ctx.seriesList, ctx.timeFormat); + const expectedText = + 'Series;Time;Value\n' + + 'series_1;1500026100;1\n' + + 'series_1;1500026200;2\n' + + 'series_1;1500026300;null\n' + + 'series_1;1500026400;null\n' + + 'series_1;1500026500;null\n' + + 'series_1;1500026600;6\n' + + 'series_2;1500026100;11\n' + + 'series_2;1500026200;12\n' + + 'series_2;1500026300;13\n' + + 'series_2;1500026500;15\n'; + + expect(text).toBe(expectedText); + }); + }); + + describe('when exporting series as columns', () => { + it('should export points in proper order', () => { + let text = fileExport.convertSeriesListToCsvColumns(ctx.seriesList, ctx.timeFormat); + const expectedText = + 'Time;series_1;series_2\n' + + '1500026100;1;11\n' + + '1500026200;2;12\n' + + '1500026300;null;13\n' + + '1500026400;null;null\n' + + '1500026500;null;15\n' + + '1500026600;6;null\n'; + + expect(text).toBe(expectedText); + }); + }); +}); diff --git a/public/app/core/specs/flatten.jest.ts b/public/app/core/specs/flatten.jest.ts index 7fe07128d1e..7c7f4816d94 100644 --- a/public/app/core/specs/flatten.jest.ts +++ b/public/app/core/specs/flatten.jest.ts @@ -1,22 +1,22 @@ import flatten from 'app/core/utils/flatten'; -describe("flatten", () => { - +describe('flatten', () => { it('should return flatten object', () => { - var flattened = flatten({ - level1: 'level1-value', - deeper: { - level2: 'level2-value', + var flattened = flatten( + { + level1: 'level1-value', deeper: { - level3: 'level3-value' - } - } - }, null); + level2: 'level2-value', + deeper: { + level3: 'level3-value', + }, + }, + }, + null + ); expect(flattened['level1']).toBe('level1-value'); expect(flattened['deeper.level2']).toBe('level2-value'); expect(flattened['deeper.deeper.level3']).toBe('level3-value'); }); - }); - diff --git a/public/app/core/specs/kbn.jest.ts b/public/app/core/specs/kbn.jest.ts index 9f50a05d5ad..2bd7c2a9e2d 100644 --- a/public/app/core/specs/kbn.jest.ts +++ b/public/app/core/specs/kbn.jest.ts @@ -5,9 +5,7 @@ import moment from 'moment'; describe('unit format menu', function() { var menu = kbn.getUnitFormats(); menu.map(function(submenu) { - describe('submenu ' + submenu.text, function() { - it('should have a title', function() { expect(typeof submenu.text).toBe('string'); }); @@ -18,8 +16,12 @@ describe('unit format menu', function() { submenu.submenu.map(function(entry) { describe('entry ' + entry.text, function() { - it('should have a title', function() { expect(typeof entry.text).toBe('string'); }); - it('should have a format', function() { expect(typeof entry.value).toBe('string'); }); + it('should have a title', function() { + expect(typeof entry.text).toBe('string'); + }); + it('should have a format', function() { + expect(typeof entry.value).toBe('string'); + }); it('should have a valid format', function() { expect(typeof kbn.valueFormats[entry.value]).toBe('function'); }); @@ -30,7 +32,6 @@ describe('unit format menu', function() { }); function describeValueFormat(desc, value, tickSize, tickDecimals, result) { - describe('value format: ' + desc, function() { it('should translate ' + value + ' as ' + result, function() { var scaledDecimals = tickDecimals - Math.floor(Math.log(tickSize) / Math.LN10); @@ -38,7 +39,6 @@ function describeValueFormat(desc, value, tickSize, tickDecimals, result) { expect(str).toBe(result); }); }); - } describeValueFormat('ms', 0.0024, 0.0005, 4, '0.0024 ms'); @@ -53,7 +53,7 @@ describeValueFormat('none', 2.75e-10, 0, 10, '3e-10'); describeValueFormat('none', 0, 0, 2, '0'); describeValueFormat('dB', 10, 1000, 2, '10.00 dB'); -describeValueFormat('percent', 0, 0, 0, '0%'); +describeValueFormat('percent', 0, 0, 0, '0%'); describeValueFormat('percent', 53, 0, 1, '53.0%'); describeValueFormat('percentunit', 0.0, 0, 0, '0%'); describeValueFormat('percentunit', 0.278, 0, 1, '27.8%'); @@ -63,7 +63,7 @@ describeValueFormat('currencyUSD', 7.42, 10000, 2, '$7.42'); describeValueFormat('currencyUSD', 1532.82, 1000, 1, '$1.53K'); describeValueFormat('currencyUSD', 18520408.7, 10000000, 0, '$19M'); -describeValueFormat('bytes', -1.57e+308, -1.57e+308, 2, 'NA'); +describeValueFormat('bytes', -1.57e308, -1.57e308, 2, 'NA'); describeValueFormat('ns', 25, 1, 0, '25 ns'); describeValueFormat('ns', 2558, 50, 0, '2.56 µs'); @@ -109,7 +109,7 @@ describe('date time formats', function() { it('should format as iso date and skip date when today', function() { var now = moment(); var str = kbn.valueFormats.dateTimeAsIso(now.valueOf(), 1); - expect(str).toBe(now.format("HH:mm:ss")); + expect(str).toBe(now.format('HH:mm:ss')); }); it('should format as US date', function() { @@ -120,7 +120,7 @@ describe('date time formats', function() { it('should format as US date and skip date when today', function() { var now = moment(); var str = kbn.valueFormats.dateTimeAsUS(now.valueOf(), 1); - expect(str).toBe(now.format("h:mm:ss a")); + expect(str).toBe(now.format('h:mm:ss a')); }); it('should format as from now with days', function() { @@ -190,7 +190,7 @@ describe('calculateInterval', function() { }); it('fixed user min interval', function() { - var range = {from: dateMath.parse('now-10m'), to: dateMath.parse('now')}; + var range = { from: dateMath.parse('now-10m'), to: dateMath.parse('now') }; var res = kbn.calculateInterval(range, 1600, '10s'); expect(res.interval).toBe('10s'); expect(res.intervalMs).toBe(10000); @@ -203,7 +203,7 @@ describe('calculateInterval', function() { }); it('large time range and user low limit', function() { - var range = {from: dateMath.parse('now-14d'), to: dateMath.parse('now')}; + var range = { from: dateMath.parse('now-14d'), to: dateMath.parse('now') }; var res = kbn.calculateInterval(range, 1000, '>10s'); expect(res.interval).toBe('20m'); }); @@ -222,7 +222,10 @@ describe('calculateInterval', function() { }); it('86399s 1 resolution', function() { - var range = { from: dateMath.parse('now-86390s'), to: dateMath.parse('now') }; + var range = { + from: dateMath.parse('now-86390s'), + to: dateMath.parse('now'), + }; var res = kbn.calculateInterval(range, 1, null); expect(res.interval).toBe('12h'); expect(res.intervalMs).toBe(43200000); @@ -254,11 +257,11 @@ describe('hex', function() { describe('hex 0x', function() { it('positive integeter', function() { - var str = kbn.valueFormats.hex0x(7999,0); + var str = kbn.valueFormats.hex0x(7999, 0); expect(str).toBe('0x1F3F'); }); it('negative integer', function() { - var str = kbn.valueFormats.hex0x(-584,0); + var str = kbn.valueFormats.hex0x(-584, 0); expect(str).toBe('-0x248'); }); it('null', function() { @@ -277,71 +280,78 @@ describe('hex 0x', function() { describe('duration', function() { it('null', function() { - var str = kbn.toDuration(null, 0, "millisecond"); + var str = kbn.toDuration(null, 0, 'millisecond'); expect(str).toBe(''); }); it('0 milliseconds', function() { - var str = kbn.toDuration(0, 0, "millisecond"); + var str = kbn.toDuration(0, 0, 'millisecond'); expect(str).toBe('0 milliseconds'); }); it('1 millisecond', function() { - var str = kbn.toDuration(1, 0, "millisecond"); + var str = kbn.toDuration(1, 0, 'millisecond'); expect(str).toBe('1 millisecond'); }); it('-1 millisecond', function() { - var str = kbn.toDuration(-1, 0, "millisecond"); + var str = kbn.toDuration(-1, 0, 'millisecond'); expect(str).toBe('1 millisecond ago'); }); it('seconds', function() { - var str = kbn.toDuration(1, 0, "second"); + var str = kbn.toDuration(1, 0, 'second'); expect(str).toBe('1 second'); }); it('minutes', function() { - var str = kbn.toDuration(1, 0, "minute"); + var str = kbn.toDuration(1, 0, 'minute'); expect(str).toBe('1 minute'); }); it('hours', function() { - var str = kbn.toDuration(1, 0, "hour"); + var str = kbn.toDuration(1, 0, 'hour'); expect(str).toBe('1 hour'); }); it('days', function() { - var str = kbn.toDuration(1, 0, "day"); + var str = kbn.toDuration(1, 0, 'day'); expect(str).toBe('1 day'); }); it('weeks', function() { - var str = kbn.toDuration(1, 0, "week"); + var str = kbn.toDuration(1, 0, 'week'); expect(str).toBe('1 week'); }); it('months', function() { - var str = kbn.toDuration(1, 0, "month"); + var str = kbn.toDuration(1, 0, 'month'); expect(str).toBe('1 month'); }); it('years', function() { - var str = kbn.toDuration(1, 0, "year"); + var str = kbn.toDuration(1, 0, 'year'); expect(str).toBe('1 year'); }); it('decimal days', function() { - var str = kbn.toDuration(1.5, 2, "day"); + var str = kbn.toDuration(1.5, 2, 'day'); expect(str).toBe('1 day, 12 hours, 0 minutes'); }); it('decimal months', function() { - var str = kbn.toDuration(1.5, 3, "month"); + var str = kbn.toDuration(1.5, 3, 'month'); expect(str).toBe('1 month, 2 weeks, 1 day, 0 hours'); }); it('no decimals', function() { - var str = kbn.toDuration(38898367008, 0, "millisecond"); + var str = kbn.toDuration(38898367008, 0, 'millisecond'); expect(str).toBe('1 year'); }); it('1 decimal', function() { - var str = kbn.toDuration(38898367008, 1, "millisecond"); + var str = kbn.toDuration(38898367008, 1, 'millisecond'); expect(str).toBe('1 year, 2 months'); }); it('too many decimals', function() { - var str = kbn.toDuration(38898367008, 20, "millisecond"); + var str = kbn.toDuration(38898367008, 20, 'millisecond'); expect(str).toBe('1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, 7 seconds, 8 milliseconds'); }); it('floating point error', function() { - var str = kbn.toDuration(36993906007, 8, "millisecond"); + var str = kbn.toDuration(36993906007, 8, 'millisecond'); expect(str).toBe('1 year, 2 months, 0 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds'); }); }); + +describe('volume', function() { + it('1000m3', function() { + var str = kbn.valueFormats['m3'](1000, 1, null); + expect(str).toBe('1000.0 m3'); + }); +}); diff --git a/public/app/core/specs/location_util.jest.ts b/public/app/core/specs/location_util.jest.ts new file mode 100644 index 00000000000..c109ab7315a --- /dev/null +++ b/public/app/core/specs/location_util.jest.ts @@ -0,0 +1,16 @@ +import locationUtil from 'app/core/utils/location_util'; + +jest.mock('app/core/config', () => { + return { + appSubUrl: '/subUrl', + }; +}); + +describe('locationUtil', () => { + describe('With /subUrl as appSubUrl', () => { + it('/subUrl should be stripped', () => { + const urlWithoutMaster = locationUtil.stripBaseFromUrl('/subUrl/grafana/'); + expect(urlWithoutMaster).toBe('/grafana/'); + }); + }); +}); diff --git a/public/app/core/specs/manage_dashboards.jest.ts b/public/app/core/specs/manage_dashboards.jest.ts new file mode 100644 index 00000000000..4b51e6848d0 --- /dev/null +++ b/public/app/core/specs/manage_dashboards.jest.ts @@ -0,0 +1,566 @@ +import { ManageDashboardsCtrl } from 'app/core/components/manage_dashboards/manage_dashboards'; +import { SearchSrv } from 'app/core/services/search_srv'; +import q from 'q'; + +describe('ManageDashboards', () => { + let ctrl; + + describe('when browsing dashboards', () => { + beforeEach(() => { + const response = [ + { + id: 410, + title: 'afolder', + type: 'dash-folder', + items: [ + { + id: 399, + title: 'Dashboard Test', + url: 'dashboard/db/dashboard-test', + icon: 'fa fa-folder', + tags: [], + isStarred: false, + }, + ], + tags: [], + isStarred: false, + }, + { + id: 0, + title: 'General', + icon: 'fa fa-folder-open', + uri: 'db/something-else', + type: 'dash-db', + items: [ + { + id: 500, + title: 'Dashboard Test', + url: 'dashboard/db/dashboard-test', + icon: 'fa fa-folder', + tags: [], + isStarred: false, + }, + ], + tags: [], + isStarred: false, + }, + ]; + ctrl = createCtrlWithStubs(response); + return ctrl.refreshList(); + }); + + it('should set checked to false on all sections and children', () => { + expect(ctrl.sections.length).toEqual(2); + expect(ctrl.sections[0].checked).toEqual(false); + expect(ctrl.sections[0].items[0].checked).toEqual(false); + expect(ctrl.sections[1].checked).toEqual(false); + expect(ctrl.sections[1].items[0].checked).toEqual(false); + expect(ctrl.sections[0].hideHeader).toBeFalsy(); + }); + }); + + describe('when browsing dashboards for a folder', () => { + beforeEach(() => { + const response = [ + { + id: 410, + title: 'afolder', + type: 'dash-folder', + items: [ + { + id: 399, + title: 'Dashboard Test', + url: 'dashboard/db/dashboard-test', + icon: 'fa fa-folder', + tags: [], + isStarred: false, + }, + ], + tags: [], + isStarred: false, + }, + ]; + ctrl = createCtrlWithStubs(response); + ctrl.folderId = 410; + return ctrl.refreshList(); + }); + + it('should set hide header to true on section', () => { + expect(ctrl.sections[0].hideHeader).toBeTruthy(); + }); + }); + + describe('when searching dashboards', () => { + beforeEach(() => { + const response = [ + { + checked: false, + expanded: true, + hideHeader: true, + items: [ + { + id: 399, + title: 'Dashboard Test', + url: 'dashboard/db/dashboard-test', + icon: 'fa fa-folder', + tags: [], + isStarred: false, + folderId: 410, + folderUid: 'uid', + folderTitle: 'Folder', + folderUrl: '/dashboards/f/uid/folder', + }, + { + id: 500, + title: 'Dashboard Test', + url: 'dashboard/db/dashboard-test', + icon: 'fa fa-folder', + tags: [], + folderId: 499, + isStarred: false, + }, + ], + }, + ]; + + ctrl = createCtrlWithStubs(response); + }); + + describe('with query filter', () => { + beforeEach(() => { + ctrl.query.query = 'd'; + ctrl.canMove = true; + ctrl.canDelete = true; + ctrl.selectAllChecked = true; + return ctrl.refreshList(); + }); + + it('should set checked to false on all sections and children', () => { + expect(ctrl.sections.length).toEqual(1); + expect(ctrl.sections[0].checked).toEqual(false); + expect(ctrl.sections[0].items[0].checked).toEqual(false); + expect(ctrl.sections[0].items[1].checked).toEqual(false); + }); + + it('should uncheck select all', () => { + expect(ctrl.selectAllChecked).toBeFalsy(); + }); + + it('should disable Move To button', () => { + expect(ctrl.canMove).toBeFalsy(); + }); + + it('should disable delete button', () => { + expect(ctrl.canDelete).toBeFalsy(); + }); + + it('should have active filters', () => { + expect(ctrl.hasFilters).toBeTruthy(); + }); + + describe('when select all is checked', () => { + beforeEach(() => { + ctrl.selectAllChecked = true; + ctrl.onSelectAllChanged(); + }); + + it('should select all dashboards', () => { + expect(ctrl.sections[0].checked).toBeFalsy(); + expect(ctrl.sections[0].items[0].checked).toBeTruthy(); + expect(ctrl.sections[0].items[1].checked).toBeTruthy(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + + describe('when clearing filters', () => { + beforeEach(() => { + return ctrl.clearFilters(); + }); + + it('should reset query filter', () => { + expect(ctrl.query.query).toEqual(''); + }); + }); + }); + }); + + describe('with tag filter', () => { + beforeEach(() => { + return ctrl.filterByTag('test'); + }); + + it('should set tag filter', () => { + expect(ctrl.sections.length).toEqual(1); + expect(ctrl.query.tag[0]).toEqual('test'); + }); + + it('should have active filters', () => { + expect(ctrl.hasFilters).toBeTruthy(); + }); + + describe('when clearing filters', () => { + beforeEach(() => { + return ctrl.clearFilters(); + }); + + it('should reset tag filter', () => { + expect(ctrl.query.tag.length).toEqual(0); + }); + }); + }); + + describe('with starred filter', () => { + beforeEach(() => { + const yesOption: any = ctrl.starredFilterOptions[1]; + + ctrl.selectedStarredFilter = yesOption; + return ctrl.onStarredFilterChange(); + }); + + it('should set starred filter', () => { + expect(ctrl.sections.length).toEqual(1); + expect(ctrl.query.starred).toEqual(true); + }); + + it('should have active filters', () => { + expect(ctrl.hasFilters).toBeTruthy(); + }); + + describe('when clearing filters', () => { + beforeEach(() => { + return ctrl.clearFilters(); + }); + + it('should reset starred filter', () => { + expect(ctrl.query.starred).toEqual(false); + }); + }); + }); + }); + + describe('when selecting dashboards', () => { + let ctrl; + + beforeEach(() => { + ctrl = createCtrlWithStubs([]); + }); + + describe('and no dashboards are selected', () => { + beforeEach(() => { + ctrl.sections = [ + { + id: 1, + items: [{ id: 2, checked: false }], + checked: false, + }, + { + id: 0, + items: [{ id: 3, checked: false }], + checked: false, + }, + ]; + ctrl.selectionChanged(); + }); + + it('should disable Move To button', () => { + expect(ctrl.canMove).toBeFalsy(); + }); + + it('should disable delete button', () => { + expect(ctrl.canDelete).toBeFalsy(); + }); + + describe('when select all is checked', () => { + beforeEach(() => { + ctrl.selectAllChecked = true; + ctrl.onSelectAllChanged(); + }); + + it('should select all folders and dashboards', () => { + expect(ctrl.sections[0].checked).toBeTruthy(); + expect(ctrl.sections[0].items[0].checked).toBeTruthy(); + expect(ctrl.sections[1].checked).toBeTruthy(); + expect(ctrl.sections[1].items[0].checked).toBeTruthy(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + }); + }); + + describe('and all folders and dashboards are selected', () => { + beforeEach(() => { + ctrl.sections = [ + { + id: 1, + items: [{ id: 2, checked: true }], + checked: true, + }, + { + id: 0, + items: [{ id: 3, checked: true }], + checked: true, + }, + ]; + ctrl.selectionChanged(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + + describe('when select all is unchecked', () => { + beforeEach(() => { + ctrl.selectAllChecked = false; + ctrl.onSelectAllChanged(); + }); + + it('should uncheck all checked folders and dashboards', () => { + expect(ctrl.sections[0].checked).toBeFalsy(); + expect(ctrl.sections[0].items[0].checked).toBeFalsy(); + expect(ctrl.sections[1].checked).toBeFalsy(); + expect(ctrl.sections[1].items[0].checked).toBeFalsy(); + }); + + it('should disable Move To button', () => { + expect(ctrl.canMove).toBeFalsy(); + }); + + it('should disable delete button', () => { + expect(ctrl.canDelete).toBeFalsy(); + }); + }); + }); + + describe('and one dashboard in root is selected', () => { + beforeEach(() => { + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [{ id: 2, checked: false }], + checked: false, + }, + { + id: 0, + title: 'General', + items: [{ id: 3, checked: true }], + checked: false, + }, + ]; + ctrl.selectionChanged(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + }); + + describe('and one child dashboard is selected', () => { + beforeEach(() => { + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [{ id: 2, checked: true }], + checked: false, + }, + { + id: 0, + title: 'General', + items: [{ id: 3, checked: false }], + checked: false, + }, + ]; + + ctrl.selectionChanged(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + }); + + describe('and one child dashboard and one dashboard is selected', () => { + beforeEach(() => { + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [{ id: 2, checked: true }], + checked: false, + }, + { + id: 0, + title: 'General', + items: [{ id: 3, checked: true }], + checked: false, + }, + ]; + + ctrl.selectionChanged(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + }); + + describe('and one child dashboard and one folder is selected', () => { + beforeEach(() => { + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [{ id: 2, checked: false }], + checked: true, + }, + { + id: 3, + title: 'folder', + items: [{ id: 4, checked: true }], + checked: false, + }, + { + id: 0, + title: 'General', + items: [{ id: 3, checked: false }], + checked: false, + }, + ]; + + ctrl.selectionChanged(); + }); + + it('should enable Move To button', () => { + expect(ctrl.canMove).toBeTruthy(); + }); + + it('should enable delete button', () => { + expect(ctrl.canDelete).toBeTruthy(); + }); + }); + }); + + describe('when deleting dashboards', () => { + let toBeDeleted: any; + + beforeEach(() => { + ctrl = createCtrlWithStubs([]); + + ctrl.sections = [ + { + id: 1, + uid: 'folder', + title: 'folder', + items: [{ id: 2, checked: true, uid: 'folder-dash' }], + checked: true, + }, + { + id: 3, + title: 'folder-2', + items: [{ id: 3, checked: true, uid: 'folder-2-dash' }], + checked: false, + uid: 'folder-2', + }, + { + id: 0, + title: 'General', + items: [{ id: 3, checked: true, uid: 'root-dash' }], + checked: true, + }, + ]; + + toBeDeleted = ctrl.getFoldersAndDashboardsToDelete(); + }); + + it('should return 1 folder', () => { + expect(toBeDeleted.folders.length).toEqual(1); + }); + + it('should return 2 dashboards', () => { + expect(toBeDeleted.dashboards.length).toEqual(2); + }); + + it('should filter out children if parent is checked', () => { + expect(toBeDeleted.folders[0]).toEqual('folder'); + }); + + it('should not filter out children if parent not is checked', () => { + expect(toBeDeleted.dashboards[0]).toEqual('folder-2-dash'); + }); + + it('should not filter out children if parent is checked and root', () => { + expect(toBeDeleted.dashboards[1]).toEqual('root-dash'); + }); + }); + + describe('when moving dashboards', () => { + beforeEach(() => { + ctrl = createCtrlWithStubs([]); + + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [{ id: 2, checked: true, uid: 'dash' }], + checked: false, + uid: 'folder', + }, + { + id: 0, + title: 'General', + items: [{ id: 3, checked: true, uid: 'dash-2' }], + checked: false, + }, + ]; + }); + + it('should get selected dashboards', () => { + const toBeMove = ctrl.getDashboardsToMove(); + expect(toBeMove.length).toEqual(2); + expect(toBeMove[0]).toEqual('dash'); + expect(toBeMove[1]).toEqual('dash-2'); + }); + }); +}); + +function createCtrlWithStubs(searchResponse: any, tags?: any) { + const searchSrvStub = { + search: (options: any) => { + return q.resolve(searchResponse); + }, + getDashboardTags: () => { + return q.resolve(tags || []); + }, + }; + + return new ManageDashboardsCtrl({}, { getNav: () => {} }, searchSrvStub, { isEditor: true }); +} diff --git a/public/app/core/specs/org_switcher.jest.ts b/public/app/core/specs/org_switcher.jest.ts new file mode 100644 index 00000000000..230da81f191 --- /dev/null +++ b/public/app/core/specs/org_switcher.jest.ts @@ -0,0 +1,47 @@ +import { OrgSwitchCtrl } from '../components/org_switcher'; +import q from 'q'; + +jest.mock('app/core/services/context_srv', () => ({ + contextSrv: { + user: { orgId: 1 }, + }, +})); + +jest.mock('app/core/config', () => { + return { + appSubUrl: '/subUrl', + }; +}); + +describe('OrgSwitcher', () => { + describe('when switching org', () => { + let expectedHref; + let expectedUsingUrl; + + beforeEach(() => { + const backendSrvStub: any = { + get: url => { + return q.resolve([]); + }, + post: url => { + expectedUsingUrl = url; + return q.resolve({}); + }, + }; + + const orgSwitcherCtrl = new OrgSwitchCtrl(backendSrvStub); + + orgSwitcherCtrl.setWindowLocation = href => (expectedHref = href); + + return orgSwitcherCtrl.setUsingOrg({ orgId: 2 }); + }); + + it('should switch orgId in call to backend', () => { + expect(expectedUsingUrl).toBe('/api/user/using/2'); + }); + + it('should switch orgId in url and redirect to home page', () => { + expect(expectedHref).toBe('/subUrl/?orgId=2'); + }); + }); +}); diff --git a/public/app/core/specs/rangeutil.jest.ts b/public/app/core/specs/rangeutil.jest.ts index eb9dcfc3ace..6bfc0503900 100644 --- a/public/app/core/specs/rangeutil.jest.ts +++ b/public/app/core/specs/rangeutil.jest.ts @@ -2,17 +2,16 @@ import * as rangeUtil from 'app/core/utils/rangeutil'; import _ from 'lodash'; import moment from 'moment'; -describe("rangeUtil", () => { - - describe("Can get range grouped list of ranges", () => { +describe('rangeUtil', () => { + describe('Can get range grouped list of ranges', () => { it('when custom settings should return default range list', () => { - var groups = rangeUtil.getRelativeTimesList({time_options: []}, 'Last 5 minutes'); + var groups = rangeUtil.getRelativeTimesList({ time_options: [] }, 'Last 5 minutes'); expect(_.keys(groups).length).toBe(4); expect(groups[3][0].active).toBe(true); }); }); - describe("Can get range text described", () => { + describe('Can get range text described', () => { it('should handle simple old expression with only amount and unit', () => { var info = rangeUtil.describeTextRange('5m'); expect(info.display).toBe('Last 5 minutes'); @@ -57,52 +56,62 @@ describe("rangeUtil", () => { }); }); - describe("Can get date range described", () => { + describe('Can get date range described', () => { it('Date range with simple ranges', () => { - var text = rangeUtil.describeTimeRange({from: 'now-1h', to: 'now'}); + var text = rangeUtil.describeTimeRange({ from: 'now-1h', to: 'now' }); expect(text).toBe('Last 1 hour'); }); it('Date range with rounding ranges', () => { - var text = rangeUtil.describeTimeRange({from: 'now/d+6h', to: 'now'}); + var text = rangeUtil.describeTimeRange({ from: 'now/d+6h', to: 'now' }); expect(text).toBe('now/d+6h to now'); }); it('Date range with absolute to now', () => { - var text = rangeUtil.describeTimeRange({from: moment([2014,10,10,2,3,4]), to: 'now'}); + var text = rangeUtil.describeTimeRange({ + from: moment([2014, 10, 10, 2, 3, 4]), + to: 'now', + }); expect(text).toBe('Nov 10, 2014 02:03:04 to a few seconds ago'); }); it('Date range with absolute to relative', () => { - var text = rangeUtil.describeTimeRange({from: moment([2014,10,10,2,3,4]), to: 'now-1d'}); + var text = rangeUtil.describeTimeRange({ + from: moment([2014, 10, 10, 2, 3, 4]), + to: 'now-1d', + }); expect(text).toBe('Nov 10, 2014 02:03:04 to a day ago'); }); it('Date range with relative to absolute', () => { - var text = rangeUtil.describeTimeRange({from: 'now-7d', to: moment([2014,10,10,2,3,4])}); + var text = rangeUtil.describeTimeRange({ + from: 'now-7d', + to: moment([2014, 10, 10, 2, 3, 4]), + }); expect(text).toBe('7 days ago to Nov 10, 2014 02:03:04'); }); it('Date range with non matching default ranges', () => { - var text = rangeUtil.describeTimeRange({from: 'now-13h', to: 'now'}); + var text = rangeUtil.describeTimeRange({ from: 'now-13h', to: 'now' }); expect(text).toBe('Last 13 hours'); }); it('Date range with from and to both are in now-* format', () => { - var text = rangeUtil.describeTimeRange({from: 'now-6h', to: 'now-3h'}); + var text = rangeUtil.describeTimeRange({ from: 'now-6h', to: 'now-3h' }); expect(text).toBe('now-6h to now-3h'); }); it('Date range with from and to both are either in now-* or now/* format', () => { - var text = rangeUtil.describeTimeRange({from: 'now/d+6h', to: 'now-3h'}); + var text = rangeUtil.describeTimeRange({ + from: 'now/d+6h', + to: 'now-3h', + }); expect(text).toBe('now/d+6h to now-3h'); }); it('Date range with from and to both are either in now-* or now+* format', () => { - var text = rangeUtil.describeTimeRange({from: 'now-6h', to: 'now+1h'}); + var text = rangeUtil.describeTimeRange({ from: 'now-6h', to: 'now+1h' }); expect(text).toBe('now-6h to now+1h'); }); - }); - }); diff --git a/public/app/core/specs/search.jest.ts b/public/app/core/specs/search.jest.ts new file mode 100644 index 00000000000..8aea35af213 --- /dev/null +++ b/public/app/core/specs/search.jest.ts @@ -0,0 +1,329 @@ +import { SearchCtrl } from '../components/search/search'; +import { SearchSrv } from '../services/search_srv'; + +jest.mock('app/core/services/context_srv', () => ({ + contextSrv: { + user: { orgId: 1 }, + }, +})); + +describe('SearchCtrl', () => { + const searchSrvStub = { + search: (options: any) => {}, + getDashboardTags: () => {}, + }; + let ctrl = new SearchCtrl({ $on: () => {} }, {}, {}, searchSrvStub); + + describe('Given an empty result', () => { + beforeEach(() => { + ctrl.results = []; + }); + + describe('When navigating down one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + }); + + it('should not navigate', () => { + expect(ctrl.selectedIndex).toBe(0); + }); + }); + + describe('When navigating up one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(-1); + }); + + it('should not navigate', () => { + expect(ctrl.selectedIndex).toBe(0); + }); + }); + }); + + describe('Given a result of one selected collapsed folder with no dashboards and a root folder with 2 dashboards', () => { + beforeEach(() => { + ctrl.results = [ + { + id: 1, + title: 'folder', + items: [], + selected: true, + expanded: false, + toggle: i => (i.expanded = !i.expanded), + }, + { + id: 0, + title: 'General', + items: [{ id: 3, selected: false }, { id: 5, selected: false }], + selected: false, + expanded: true, + toggle: i => (i.expanded = !i.expanded), + }, + ]; + }); + + describe('When navigating down one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + }); + + it('should select first dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeTruthy(); + expect(ctrl.results[1].items[1].selected).toBeFalsy(); + }); + }); + + describe('When navigating down two steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + ctrl.moveSelection(1); + }); + + it('should select last dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeFalsy(); + expect(ctrl.results[1].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating down three steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + ctrl.moveSelection(1); + ctrl.moveSelection(1); + }); + + it('should select first folder', () => { + expect(ctrl.results[0].selected).toBeTruthy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeFalsy(); + expect(ctrl.results[1].items[1].selected).toBeFalsy(); + }); + }); + + describe('When navigating up one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(-1); + }); + + it('should select last dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeFalsy(); + expect(ctrl.results[1].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating up two steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(-1); + ctrl.moveSelection(-1); + }); + + it('should select first dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeTruthy(); + expect(ctrl.results[1].items[1].selected).toBeFalsy(); + }); + }); + }); + + describe('Given a result of one selected collapsed folder with 2 dashboards and a root folder with 2 dashboards', () => { + beforeEach(() => { + ctrl.results = [ + { + id: 1, + title: 'folder', + items: [{ id: 2, selected: false }, { id: 4, selected: false }], + selected: true, + expanded: false, + toggle: i => (i.expanded = !i.expanded), + }, + { + id: 0, + title: 'General', + items: [{ id: 3, selected: false }, { id: 5, selected: false }], + selected: false, + expanded: true, + toggle: i => (i.expanded = !i.expanded), + }, + ]; + }); + + describe('When navigating down one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + }); + + it('should select first dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeTruthy(); + expect(ctrl.results[1].items[1].selected).toBeFalsy(); + }); + }); + + describe('When navigating down two steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + ctrl.moveSelection(1); + }); + + it('should select last dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeFalsy(); + expect(ctrl.results[1].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating down three steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(1); + ctrl.moveSelection(1); + ctrl.moveSelection(1); + }); + + it('should select first folder', () => { + expect(ctrl.results[0].selected).toBeTruthy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeFalsy(); + expect(ctrl.results[1].items[1].selected).toBeFalsy(); + }); + }); + + describe('When navigating up one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(-1); + }); + + it('should select last dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeFalsy(); + expect(ctrl.results[1].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating up two steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 0; + ctrl.moveSelection(-1); + ctrl.moveSelection(-1); + }); + + it('should select first dashboard in root folder', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[1].selected).toBeFalsy(); + expect(ctrl.results[1].items[0].selected).toBeTruthy(); + expect(ctrl.results[1].items[1].selected).toBeFalsy(); + }); + }); + }); + + describe('Given a result of a search with 2 dashboards where the first is selected', () => { + beforeEach(() => { + ctrl.results = [ + { + hideHeader: true, + items: [{ id: 3, selected: true }, { id: 5, selected: false }], + selected: false, + expanded: true, + toggle: i => (i.expanded = !i.expanded), + }, + ]; + }); + + describe('When navigating down one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 1; + ctrl.moveSelection(1); + }); + + it('should select last dashboard', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating down two steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 1; + ctrl.moveSelection(1); + ctrl.moveSelection(1); + }); + + it('should select first dashboard', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeTruthy(); + expect(ctrl.results[0].items[1].selected).toBeFalsy(); + }); + }); + + describe('When navigating down three steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 1; + ctrl.moveSelection(1); + ctrl.moveSelection(1); + ctrl.moveSelection(1); + }); + + it('should select last dashboard', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating up one step', () => { + beforeEach(() => { + ctrl.selectedIndex = 1; + ctrl.moveSelection(-1); + }); + + it('should select last dashboard', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[1].selected).toBeTruthy(); + }); + }); + + describe('When navigating up two steps', () => { + beforeEach(() => { + ctrl.selectedIndex = 1; + ctrl.moveSelection(-1); + ctrl.moveSelection(-1); + }); + + it('should select first dashboard', () => { + expect(ctrl.results[0].selected).toBeFalsy(); + expect(ctrl.results[0].items[0].selected).toBeTruthy(); + expect(ctrl.results[0].items[1].selected).toBeFalsy(); + }); + }); + }); +}); diff --git a/public/app/core/specs/search_results.jest.ts b/public/app/core/specs/search_results.jest.ts new file mode 100644 index 00000000000..830496be3a8 --- /dev/null +++ b/public/app/core/specs/search_results.jest.ts @@ -0,0 +1,144 @@ +import { SearchResultsCtrl } from '../components/search/search_results'; +import { beforeEach, afterEach } from 'test/lib/common'; +import appEvents from 'app/core/app_events'; + +jest.mock('app/core/app_events', () => { + return { + emit: jest.fn(), + }; +}); + +describe('SearchResultsCtrl', () => { + let ctrl; + + describe('when checking an item that is not checked', () => { + let item = { checked: false }; + let selectionChanged = false; + + beforeEach(() => { + ctrl = new SearchResultsCtrl({}); + ctrl.onSelectionChanged = () => (selectionChanged = true); + ctrl.toggleSelection(item); + }); + + it('should set checked to true', () => { + expect(item.checked).toBeTruthy(); + }); + + it('should trigger selection changed callback', () => { + expect(selectionChanged).toBeTruthy(); + }); + }); + + describe('when checking an item that is checked', () => { + let item = { checked: true }; + let selectionChanged = false; + + beforeEach(() => { + ctrl = new SearchResultsCtrl({}); + ctrl.onSelectionChanged = () => (selectionChanged = true); + ctrl.toggleSelection(item); + }); + + it('should set checked to false', () => { + expect(item.checked).toBeFalsy(); + }); + + it('should trigger selection changed callback', () => { + expect(selectionChanged).toBeTruthy(); + }); + }); + + describe('when selecting a tag', () => { + let selectedTag = null; + + beforeEach(() => { + ctrl = new SearchResultsCtrl({}); + ctrl.onTagSelected = tag => (selectedTag = tag); + ctrl.selectTag('tag-test'); + }); + + it('should trigger tag selected callback', () => { + expect(selectedTag['$tag']).toBe('tag-test'); + }); + }); + + describe('when toggle a collapsed folder', () => { + let folderExpanded = false; + + beforeEach(() => { + ctrl = new SearchResultsCtrl({}); + ctrl.onFolderExpanding = () => { + folderExpanded = true; + }; + + let folder = { + expanded: false, + toggle: () => Promise.resolve(folder), + }; + + ctrl.toggleFolderExpand(folder); + }); + + it('should trigger folder expanding callback', () => { + expect(folderExpanded).toBeTruthy(); + }); + }); + + describe('when toggle an expanded folder', () => { + let folderExpanded = false; + + beforeEach(() => { + ctrl = new SearchResultsCtrl({}); + ctrl.onFolderExpanding = () => { + folderExpanded = true; + }; + + let folder = { + expanded: true, + toggle: () => Promise.resolve(folder), + }; + + ctrl.toggleFolderExpand(folder); + }); + + it('should not trigger folder expanding callback', () => { + expect(folderExpanded).toBeFalsy(); + }); + }); + + describe('when clicking on a link in search result', () => { + const dashPath = 'dashboard/path'; + const $location = { path: () => dashPath }; + const appEventsMock = appEvents as any; + + describe('with the same url as current path', () => { + beforeEach(() => { + ctrl = new SearchResultsCtrl($location); + const item = { url: dashPath }; + ctrl.onItemClick(item); + }); + + it('should close the search', () => { + expect(appEventsMock.emit.mock.calls.length).toBe(1); + expect(appEventsMock.emit.mock.calls[0][0]).toBe('hide-dash-search'); + }); + }); + + describe('with a different url than current path', () => { + beforeEach(() => { + ctrl = new SearchResultsCtrl($location); + const item = { url: 'another/path' }; + ctrl.onItemClick(item); + }); + + it('should do nothing', () => { + expect(appEventsMock.emit.mock.calls.length).toBe(0); + }); + }); + + afterEach(() => { + appEventsMock.emit.mockClear(); + }); + }); +}); diff --git a/public/app/core/specs/search_srv.jest.ts b/public/app/core/specs/search_srv.jest.ts new file mode 100644 index 00000000000..550d11bbf9e --- /dev/null +++ b/public/app/core/specs/search_srv.jest.ts @@ -0,0 +1,283 @@ +import { SearchSrv } from 'app/core/services/search_srv'; +import { BackendSrvMock } from 'test/mocks/backend_srv'; +import impressionSrv from 'app/core/services/impression_srv'; +import { contextSrv } from 'app/core/services/context_srv'; +import { beforeEach } from 'test/lib/common'; + +jest.mock('app/core/store', () => { + return { + getBool: jest.fn(), + set: jest.fn(), + }; +}); + +jest.mock('app/core/services/impression_srv', () => { + return { + getDashboardOpened: jest.fn, + }; +}); + +describe('SearchSrv', () => { + let searchSrv, backendSrvMock; + + beforeEach(() => { + backendSrvMock = new BackendSrvMock(); + searchSrv = new SearchSrv(backendSrvMock, Promise); + + contextSrv.isSignedIn = true; + impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]); + }); + + describe('With recent dashboards', () => { + let results; + + beforeEach(() => { + backendSrvMock.search = jest + .fn() + .mockReturnValueOnce( + Promise.resolve([{ id: 2, title: 'second but first' }, { id: 1, title: 'first but second' }]) + ) + .mockReturnValue(Promise.resolve([])); + + impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([1, 2]); + + return searchSrv.search({ query: '' }).then(res => { + results = res; + }); + }); + + it('should include recent dashboards section', () => { + expect(results[0].title).toBe('Recent'); + }); + + it('should return order decided by impressions store not api', () => { + expect(results[0].items[0].title).toBe('first but second'); + expect(results[0].items[1].title).toBe('second but first'); + }); + + describe('and 3 recent dashboards removed in backend', () => { + let results; + + beforeEach(() => { + backendSrvMock.search = jest + .fn() + .mockReturnValueOnce(Promise.resolve([{ id: 2, title: 'two' }, { id: 1, title: 'one' }])) + .mockReturnValue(Promise.resolve([])); + + impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([4, 5, 1, 2, 3]); + + return searchSrv.search({ query: '' }).then(res => { + results = res; + }); + }); + + it('should return 2 dashboards', () => { + expect(results[0].items.length).toBe(2); + expect(results[0].items[0].id).toBe(1); + expect(results[0].items[1].id).toBe(2); + }); + }); + }); + + describe('With starred dashboards', () => { + let results; + + beforeEach(() => { + backendSrvMock.search = jest.fn().mockReturnValue(Promise.resolve([{ id: 1, title: 'starred' }])); + + return searchSrv.search({ query: '' }).then(res => { + results = res; + }); + }); + + it('should include starred dashboards section', () => { + expect(results[0].title).toBe('Starred'); + expect(results[0].items.length).toBe(1); + }); + }); + + describe('With starred dashboards and recent', () => { + let results; + + beforeEach(() => { + backendSrvMock.search = jest + .fn() + .mockReturnValueOnce( + Promise.resolve([{ id: 1, title: 'starred and recent', isStarred: true }, { id: 2, title: 'recent' }]) + ) + .mockReturnValue(Promise.resolve([{ id: 1, title: 'starred and recent' }])); + + impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([1, 2]); + return searchSrv.search({ query: '' }).then(res => { + results = res; + }); + }); + + it('should not show starred in recent', () => { + expect(results[1].title).toBe('Recent'); + expect(results[1].items[0].title).toBe('recent'); + }); + + it('should show starred', () => { + expect(results[0].title).toBe('Starred'); + expect(results[0].items[0].title).toBe('starred and recent'); + }); + }); + + describe('with no query string and dashboards with folders returned', () => { + let results; + + beforeEach(() => { + backendSrvMock.search = jest + .fn() + .mockReturnValueOnce(Promise.resolve([])) + .mockReturnValue( + Promise.resolve([ + { + title: 'folder1', + type: 'dash-folder', + id: 1, + }, + { + title: 'dash with no folder', + type: 'dash-db', + id: 2, + }, + { + title: 'dash in folder1 1', + type: 'dash-db', + id: 3, + folderId: 1, + }, + { + title: 'dash in folder1 2', + type: 'dash-db', + id: 4, + folderId: 1, + }, + ]) + ); + + return searchSrv.search({ query: '' }).then(res => { + results = res; + }); + }); + + it('should create sections for each folder and root', () => { + expect(results).toHaveLength(2); + }); + + it('should place folders first', () => { + expect(results[0].title).toBe('folder1'); + }); + }); + + describe('with query string and dashboards with folders returned', () => { + let results; + + beforeEach(() => { + backendSrvMock.search = jest.fn(); + + backendSrvMock.search.mockReturnValue( + Promise.resolve([ + { + id: 2, + title: 'dash with no folder', + type: 'dash-db', + }, + { + id: 3, + title: 'dash in folder1 1', + type: 'dash-db', + folderId: 1, + folderUid: 'uid', + folderTitle: 'folder1', + folderUrl: '/dashboards/f/uid/folder1', + }, + ]) + ); + + return searchSrv.search({ query: 'search' }).then(res => { + results = res; + }); + }); + + it('should not specify folder ids', () => { + expect(backendSrvMock.search.mock.calls[0][0].folderIds).toHaveLength(0); + }); + + it('should group results by folder', () => { + expect(results).toHaveLength(2); + expect(results[0].id).toEqual(0); + expect(results[1].id).toEqual(1); + expect(results[1].uid).toEqual('uid'); + expect(results[1].title).toEqual('folder1'); + expect(results[1].url).toEqual('/dashboards/f/uid/folder1'); + }); + }); + + describe('with tags', () => { + beforeEach(() => { + backendSrvMock.search = jest.fn(); + backendSrvMock.search.mockReturnValue(Promise.resolve([])); + + return searchSrv.search({ tag: ['atag'] }).then(() => {}); + }); + + it('should send tags query to backend search', () => { + expect(backendSrvMock.search.mock.calls[0][0].tag).toHaveLength(1); + }); + }); + + describe('with starred', () => { + beforeEach(() => { + backendSrvMock.search = jest.fn(); + backendSrvMock.search.mockReturnValue(Promise.resolve([])); + + return searchSrv.search({ starred: true }).then(() => {}); + }); + + it('should send starred query to backend search', () => { + expect(backendSrvMock.search.mock.calls[0][0].starred).toEqual(true); + }); + }); + + describe('when skipping recent dashboards', () => { + let getRecentDashboardsCalled = false; + + beforeEach(() => { + backendSrvMock.search = jest.fn(); + backendSrvMock.search.mockReturnValue(Promise.resolve([])); + + searchSrv.getRecentDashboards = () => { + getRecentDashboardsCalled = true; + }; + + return searchSrv.search({ skipRecent: true }).then(() => {}); + }); + + it('should not fetch recent dashboards', () => { + expect(getRecentDashboardsCalled).toBeFalsy(); + }); + }); + + describe('when skipping starred dashboards', () => { + let getStarredCalled = false; + + beforeEach(() => { + backendSrvMock.search = jest.fn(); + backendSrvMock.search.mockReturnValue(Promise.resolve([])); + impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]); + + searchSrv.getStarred = () => { + getStarredCalled = true; + }; + + return searchSrv.search({ skipStarred: true }).then(() => {}); + }); + + it('should not fetch starred dashboards', () => { + expect(getStarredCalled).toBeFalsy(); + }); + }); +}); diff --git a/public/app/core/specs/store.jest.ts b/public/app/core/specs/store.jest.ts index 44cb2a84959..0162960621d 100644 --- a/public/app/core/specs/store.jest.ts +++ b/public/app/core/specs/store.jest.ts @@ -4,41 +4,37 @@ Object.assign(window, { localStorage: { removeItem(key) { delete window.localStorage[key]; - } - } + }, + }, }); describe('store', () => { - - it("should store", ()=> { - store.set("key1", "123"); - expect(store.get("key1")).toBe("123"); + it('should store', () => { + store.set('key1', '123'); + expect(store.get('key1')).toBe('123'); }); - it("get key when undefined", ()=> { - expect(store.get("key2")).toBe(undefined); + it('get key when undefined', () => { + expect(store.get('key2')).toBe(undefined); }); - it("check if key exixts", ()=> { - store.set("key3", "123"); - expect(store.exists("key3")).toBe(true); + it('check if key exixts', () => { + store.set('key3', '123'); + expect(store.exists('key3')).toBe(true); }); - it("get boolean when no key", ()=> { - expect(store.getBool("key4", false)).toBe(false); + it('get boolean when no key', () => { + expect(store.getBool('key4', false)).toBe(false); }); - it("get boolean", ()=> { - store.set("key5", "true"); - expect(store.getBool("key5", false)).toBe(true); + it('get boolean', () => { + store.set('key5', 'true'); + expect(store.getBool('key5', false)).toBe(true); }); - it("key should be deleted", ()=> { - store.set("key6", "123"); - store.delete("key6"); - expect(store.exists("key6")).toBe(false); + it('key should be deleted', () => { + store.set('key6', '123'); + store.delete('key6'); + expect(store.exists('key6')).toBe(false); }); - }); - - diff --git a/public/app/core/specs/table_model.jest.ts b/public/app/core/specs/table_model.jest.ts index 05c9fbda039..a2c1eb5e1af 100644 --- a/public/app/core/specs/table_model.jest.ts +++ b/public/app/core/specs/table_model.jest.ts @@ -3,7 +3,7 @@ import TableModel from 'app/core/table_model'; describe('when sorting table desc', () => { var table; var panel = { - sort: {col: 0, desc: true}, + sort: { col: 0, desc: true }, }; beforeEach(() => { @@ -19,17 +19,16 @@ describe('when sorting table desc', () => { expect(table.rows[2][0]).toBe(100); }); - it ('should mark column being sorted', () => { + it('should mark column being sorted', () => { expect(table.columns[0].sort).toBe(true); expect(table.columns[0].desc).toBe(true); }); - }); describe('when sorting table asc', () => { var table; var panel = { - sort: {col: 1, desc: false}, + sort: { col: 1, desc: false }, }; beforeEach(() => { @@ -44,6 +43,4 @@ describe('when sorting table asc', () => { expect(table.rows[1][1]).toBe(11); expect(table.rows[2][1]).toBe(15); }); - }); - diff --git a/public/app/core/specs/time_series.jest.ts b/public/app/core/specs/time_series.jest.ts index 1a199daa59f..5043953071a 100644 --- a/public/app/core/specs/time_series.jest.ts +++ b/public/app/core/specs/time_series.jest.ts @@ -1,6 +1,6 @@ import TimeSeries from 'app/core/time_series2'; -describe("TimeSeries", function() { +describe('TimeSeries', function() { var points, series; var yAxisFormats = ['short', 'ms']; var testData; @@ -8,9 +8,7 @@ describe("TimeSeries", function() { beforeEach(function() { testData = { alias: 'test', - datapoints: [ - [1,2],[null,3],[10,4],[8,5] - ] + datapoints: [[1, 2], [null, 3], [10, 4], [8, 5]], }; }); @@ -30,7 +28,7 @@ describe("TimeSeries", function() { it('if last is null current should pick next to last', function() { series = new TimeSeries({ - datapoints: [[10,1], [null, 2]] + datapoints: [[10, 1], [null, 2]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.current).toBe(10); @@ -38,7 +36,7 @@ describe("TimeSeries", function() { it('max value should work for negative values', function() { series = new TimeSeries({ - datapoints: [[-10,1], [-4, 2]] + datapoints: [[-10, 1], [-4, 2]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.max).toBe(-4); @@ -52,7 +50,7 @@ describe("TimeSeries", function() { it('the delta value should account for nulls', function() { series = new TimeSeries({ - datapoints: [[1,2],[3,3],[null,4],[10,5],[15,6]] + datapoints: [[1, 2], [3, 3], [null, 4], [10, 5], [15, 6]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.delta).toBe(14); @@ -60,7 +58,7 @@ describe("TimeSeries", function() { it('the delta value should account for nulls on first', function() { series = new TimeSeries({ - datapoints: [[null,2],[1,3],[10,4],[15,5]] + datapoints: [[null, 2], [1, 3], [10, 4], [15, 5]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.delta).toBe(14); @@ -68,7 +66,7 @@ describe("TimeSeries", function() { it('the delta value should account for nulls on last', function() { series = new TimeSeries({ - datapoints: [[1,2],[5,3],[10,4],[null,5]] + datapoints: [[1, 2], [5, 3], [10, 4], [null, 5]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.delta).toBe(9); @@ -76,7 +74,7 @@ describe("TimeSeries", function() { it('the delta value should account for resets', function() { series = new TimeSeries({ - datapoints: [[1,2],[5,3],[10,4],[0,5],[10,6]] + datapoints: [[1, 2], [5, 3], [10, 4], [0, 5], [10, 6]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.delta).toBe(19); @@ -84,7 +82,7 @@ describe("TimeSeries", function() { it('the delta value should account for resets on last', function() { series = new TimeSeries({ - datapoints: [[1,2],[2,3],[10,4],[8,5]] + datapoints: [[1, 2], [2, 3], [10, 4], [8, 5]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.delta).toBe(17); @@ -101,7 +99,7 @@ describe("TimeSeries", function() { series.getFlotPairs('null', yAxisFormats); expect(series.stats.first).toBe(1); series = new TimeSeries({ - datapoints: [[null,2],[1,3],[10,4],[8,5]] + datapoints: [[null, 2], [1, 3], [10, 4], [8, 5]], }); series.getFlotPairs('null', yAxisFormats); expect(series.stats.first).toBe(1); @@ -115,7 +113,7 @@ describe("TimeSeries", function() { it('average value should be null if all values is null', function() { series = new TimeSeries({ - datapoints: [[null,2],[null,3],[null,4],[null,5]] + datapoints: [[null, 2], [null, 3], [null, 4], [null, 5]], }); series.getFlotPairs('null'); expect(series.stats.avg).toBe(null); @@ -125,7 +123,9 @@ describe("TimeSeries", function() { describe('When checking if ms resolution is needed', function() { describe('msResolution with second resolution timestamps', function() { beforeEach(function() { - series = new TimeSeries({datapoints: [[45, 1234567890], [60, 1234567899]]}); + series = new TimeSeries({ + datapoints: [[45, 1234567890], [60, 1234567899]], + }); }); it('should set hasMsResolution to false', function() { @@ -135,7 +135,9 @@ describe("TimeSeries", function() { describe('msResolution with millisecond resolution timestamps', function() { beforeEach(function() { - series = new TimeSeries({datapoints: [[55, 1236547890001], [90, 1234456709000]]}); + series = new TimeSeries({ + datapoints: [[55, 1236547890001], [90, 1234456709000]], + }); }); it('should show millisecond resolution tooltip', function() { @@ -145,7 +147,9 @@ describe("TimeSeries", function() { describe('msResolution with millisecond resolution timestamps but with trailing zeroes', function() { beforeEach(function() { - series = new TimeSeries({datapoints: [[45, 1234567890000], [60, 1234567899000]]}); + series = new TimeSeries({ + datapoints: [[45, 1234567890000], [60, 1234567899000]], + }); }); it('should not show millisecond resolution tooltip', function() { @@ -277,7 +281,6 @@ describe("TimeSeries", function() { expect(series.zindex).toBe(2); }); }); - }); describe('value formatter', function() { @@ -287,12 +290,11 @@ describe("TimeSeries", function() { }); it('should format non-numeric values as empty string', function() { - expect(series.formatValue(null)).toBe(""); - expect(series.formatValue(undefined)).toBe(""); - expect(series.formatValue(NaN)).toBe(""); - expect(series.formatValue(Infinity)).toBe(""); - expect(series.formatValue(-Infinity)).toBe(""); + expect(series.formatValue(null)).toBe(''); + expect(series.formatValue(undefined)).toBe(''); + expect(series.formatValue(NaN)).toBe(''); + expect(series.formatValue(Infinity)).toBe(''); + expect(series.formatValue(-Infinity)).toBe(''); }); }); - }); diff --git a/public/app/core/specs/value_select_dropdown_specs.ts b/public/app/core/specs/value_select_dropdown_specs.ts index 644320e7e0d..8f6408fb389 100644 --- a/public/app/core/specs/value_select_dropdown_specs.ts +++ b/public/app/core/specs/value_select_dropdown_specs.ts @@ -1,7 +1,7 @@ -import {describe, beforeEach, it, expect, angularMocks, sinon} from 'test/lib/common'; +import { describe, beforeEach, it, expect, angularMocks, sinon } from 'test/lib/common'; import 'app/core/directives/value_select_dropdown'; -describe("SelectDropdownCtrl", function() { +describe('SelectDropdownCtrl', function() { var scope; var ctrl; var tagValuesMap: any = {}; @@ -9,19 +9,21 @@ describe("SelectDropdownCtrl", function() { var q; beforeEach(angularMocks.module('grafana.core')); - beforeEach(angularMocks.inject(function($controller, $rootScope, $q, $httpBackend) { - rootScope = $rootScope; - q = $q; - scope = $rootScope.$new(); - ctrl = $controller('ValueSelectDropdownCtrl', {$scope: scope}); - ctrl.onUpdated = sinon.spy(); - $httpBackend.when('GET', /\.html$/).respond(''); - })); + beforeEach( + angularMocks.inject(function($controller, $rootScope, $q, $httpBackend) { + rootScope = $rootScope; + q = $q; + scope = $rootScope.$new(); + ctrl = $controller('ValueSelectDropdownCtrl', { $scope: scope }); + ctrl.onUpdated = sinon.spy(); + $httpBackend.when('GET', /\.html$/).respond(''); + }) + ); - describe("Given simple variable", function() { + describe('Given simple variable', function() { beforeEach(function() { ctrl.variable = { - current: {text: 'hej', value: 'hej' }, + current: { text: 'hej', value: 'hej' }, getValuesForTag: function(key) { return q.when(tagValuesMap[key]); }, @@ -29,25 +31,25 @@ describe("SelectDropdownCtrl", function() { ctrl.init(); }); - it("Should init labelText and linkText", function() { - expect(ctrl.linkText).to.be("hej"); + it('Should init labelText and linkText', function() { + expect(ctrl.linkText).to.be('hej'); }); }); - describe("Given variable with tags and dropdown is opened", function() { + describe('Given variable with tags and dropdown is opened', function() { beforeEach(function() { ctrl.variable = { - current: {text: 'server-1', value: 'server-1'}, + current: { text: 'server-1', value: 'server-1' }, options: [ - {text: 'server-1', value: 'server-1', selected: true}, - {text: 'server-2', value: 'server-2'}, - {text: 'server-3', value: 'server-3'}, + { text: 'server-1', value: 'server-1', selected: true }, + { text: 'server-2', value: 'server-2' }, + { text: 'server-3', value: 'server-3' }, ], - tags: ["key1", "key2", "key3"], + tags: ['key1', 'key2', 'key3'], getValuesForTag: function(key) { return q.when(tagValuesMap[key]); }, - multi: true + multi: true, }; tagValuesMap.key1 = ['server-1', 'server-3']; tagValuesMap.key2 = ['server-2', 'server-3']; @@ -56,20 +58,20 @@ describe("SelectDropdownCtrl", function() { ctrl.show(); }); - it("should init tags model", function() { + it('should init tags model', function() { expect(ctrl.tags.length).to.be(3); - expect(ctrl.tags[0].text).to.be("key1"); + expect(ctrl.tags[0].text).to.be('key1'); }); - it("should init options model", function() { + it('should init options model', function() { expect(ctrl.options.length).to.be(3); }); - it("should init selected values array", function() { + it('should init selected values array', function() { expect(ctrl.selectedValues.length).to.be(1); }); - it("should set linkText", function() { + it('should set linkText', function() { expect(ctrl.linkText).to.be('server-1'); }); @@ -91,16 +93,16 @@ describe("SelectDropdownCtrl", function() { ctrl.commitChanges(); }); - it("should select tag", function() { + it('should select tag', function() { expect(ctrl.selectedTags.length).to.be(1); }); - it("should select values", function() { + it('should select values', function() { expect(ctrl.options[0].selected).to.be(true); expect(ctrl.options[2].selected).to.be(true); }); - it("link text should not include tag values", function() { + it('link text should not include tag values', function() { expect(ctrl.linkText).to.be(''); }); @@ -111,7 +113,7 @@ describe("SelectDropdownCtrl", function() { rootScope.$digest(); }); - it("should still have selected tag", function() { + it('should still have selected tag', function() { expect(ctrl.selectedTags.length).to.be(1); }); }); @@ -122,7 +124,7 @@ describe("SelectDropdownCtrl", function() { rootScope.$digest(); }); - it("should deselect tag", function() { + it('should deselect tag', function() { expect(ctrl.selectedTags.length).to.be(0); }); }); @@ -132,36 +134,38 @@ describe("SelectDropdownCtrl", function() { ctrl.selectValue(ctrl.options[0], {}); }); - it("should deselect tag", function() { + it('should deselect tag', function() { expect(ctrl.selectedTags.length).to.be(0); }); }); }); }); - describe("Given variable with selected tags", function() { + describe('Given variable with selected tags', function() { beforeEach(function() { ctrl.variable = { - current: {text: 'server-1', value: 'server-1', tags: [{text: 'key1', selected: true}] }, + current: { + text: 'server-1', + value: 'server-1', + tags: [{ text: 'key1', selected: true }], + }, options: [ - {text: 'server-1', value: 'server-1'}, - {text: 'server-2', value: 'server-2'}, - {text: 'server-3', value: 'server-3'}, + { text: 'server-1', value: 'server-1' }, + { text: 'server-2', value: 'server-2' }, + { text: 'server-3', value: 'server-3' }, ], - tags: ["key1", "key2", "key3"], + tags: ['key1', 'key2', 'key3'], getValuesForTag: function(key) { return q.when(tagValuesMap[key]); }, - multi: true + multi: true, }; ctrl.init(); ctrl.show(); }); - it("should set tag as selected", function() { + it('should set tag as selected', function() { expect(ctrl.tags[0].selected).to.be(true); }); - }); }); - diff --git a/public/app/core/store.ts b/public/app/core/store.ts index cbed16510ab..b0714f49256 100644 --- a/public/app/core/store.ts +++ b/public/app/core/store.ts @@ -1,5 +1,4 @@ export class Store { - get(key) { return window.localStorage[key]; } @@ -22,7 +21,6 @@ export class Store { delete(key) { window.localStorage.removeItem(key); } - } const store = new Store(); diff --git a/public/app/core/table_model.ts b/public/app/core/table_model.ts index 6b02e906583..57800b3e48d 100644 --- a/public/app/core/table_model.ts +++ b/public/app/core/table_model.ts @@ -1,4 +1,3 @@ - export default class TableModel { columns: any[]; rows: any[]; diff --git a/public/app/core/time_series2.ts b/public/app/core/time_series2.ts index 0f3dcbc1171..3e02b1ec939 100644 --- a/public/app/core/time_series2.ts +++ b/public/app/core/time_series2.ts @@ -1,8 +1,11 @@ import kbn from 'app/core/utils/kbn'; +import { getFlotTickDecimals } from 'app/core/utils/ticks'; import _ from 'lodash'; function matchSeriesOverride(aliasOrRegex, seriesAlias) { - if (!aliasOrRegex) { return false; } + if (!aliasOrRegex) { + return false; + } if (aliasOrRegex[0] === '/') { var regex = kbn.stringToJsRegex(aliasOrRegex); @@ -13,7 +16,50 @@ function matchSeriesOverride(aliasOrRegex, seriesAlias) { } function translateFillOption(fill) { - return fill === 0 ? 0.001 : fill/10; + return fill === 0 ? 0.001 : fill / 10; +} + +/** + * Calculate decimals for legend and update values for each series. + * @param data series data + * @param panel + */ +export function updateLegendValues(data: TimeSeries[], panel) { + for (let i = 0; i < data.length; i++) { + let series = data[i]; + let yaxes = panel.yaxes; + const seriesYAxis = series.yaxis || 1; + let axis = yaxes[seriesYAxis - 1]; + let { tickDecimals, scaledDecimals } = getFlotTickDecimals(data, axis); + let formater = kbn.valueFormats[panel.yaxes[seriesYAxis - 1].format]; + + // decimal override + if (_.isNumber(panel.decimals)) { + series.updateLegendValues(formater, panel.decimals, null); + } else { + // auto decimals + // legend and tooltip gets one more decimal precision + // than graph legend ticks + tickDecimals = (tickDecimals || -1) + 1; + series.updateLegendValues(formater, tickDecimals, scaledDecimals + 2); + } + } +} + +export function getDataMinMax(data: TimeSeries[]) { + let datamin = null; + let datamax = null; + + for (let series of data) { + if (datamax === null || datamax < series.stats.max) { + datamax = series.stats.max; + } + if (datamin === null || datamin > series.stats.min) { + datamin = series.stats.min; + } + } + + return { datamin, datamax }; } export default class TimeSeries { @@ -63,7 +109,7 @@ export default class TimeSeries { applySeriesOverrides(overrides) { this.lines = {}; this.dashes = { - dashLength: [] + dashLength: [], }; this.points = {}; this.bars = {}; @@ -77,29 +123,59 @@ export default class TimeSeries { if (!matchSeriesOverride(override.alias, this.alias)) { continue; } - if (override.lines !== void 0) { this.lines.show = override.lines; } + if (override.lines !== void 0) { + this.lines.show = override.lines; + } if (override.dashes !== void 0) { - this.dashes.show = override.dashes; - this.lines.lineWidth = 0; + this.dashes.show = override.dashes; + this.lines.lineWidth = 0; + } + if (override.points !== void 0) { + this.points.show = override.points; + } + if (override.bars !== void 0) { + this.bars.show = override.bars; + } + if (override.fill !== void 0) { + this.lines.fill = translateFillOption(override.fill); + } + if (override.stack !== void 0) { + this.stack = override.stack; } - if (override.points !== void 0) { this.points.show = override.points; } - if (override.bars !== void 0) { this.bars.show = override.bars; } - if (override.fill !== void 0) { this.lines.fill = translateFillOption(override.fill); } - if (override.stack !== void 0) { this.stack = override.stack; } if (override.linewidth !== void 0) { - this.lines.lineWidth = this.dashes.show ? 0: override.linewidth; - this.dashes.lineWidth = override.linewidth; + this.lines.lineWidth = this.dashes.show ? 0 : override.linewidth; + this.dashes.lineWidth = override.linewidth; + } + if (override.dashLength !== void 0) { + this.dashes.dashLength[0] = override.dashLength; + } + if (override.spaceLength !== void 0) { + this.dashes.dashLength[1] = override.spaceLength; + } + if (override.nullPointMode !== void 0) { + this.nullPointMode = override.nullPointMode; + } + if (override.pointradius !== void 0) { + this.points.radius = override.pointradius; + } + if (override.steppedLine !== void 0) { + this.lines.steps = override.steppedLine; + } + if (override.zindex !== void 0) { + this.zindex = override.zindex; + } + if (override.fillBelowTo !== void 0) { + this.fillBelowTo = override.fillBelowTo; + } + if (override.color !== void 0) { + this.color = override.color; + } + if (override.transform !== void 0) { + this.transform = override.transform; + } + if (override.legend !== void 0) { + this.legend = override.legend; } - if (override.dashLength !== void 0) { this.dashes.dashLength[0] = override.dashLength; } - if (override.spaceLength !== void 0) { this.dashes.dashLength[1] = override.spaceLength; } - if (override.nullPointMode !== void 0) { this.nullPointMode = override.nullPointMode; } - if (override.pointradius !== void 0) { this.points.radius = override.pointradius; } - if (override.steppedLine !== void 0) { this.lines.steps = override.steppedLine; } - if (override.zindex !== void 0) { this.zindex = override.zindex; } - if (override.fillBelowTo !== void 0) { this.fillBelowTo = override.fillBelowTo; } - if (override.color !== void 0) { this.color = override.color; } - if (override.transform !== void 0) { this.transform = override.transform; } - if (override.legend !== void 0) { this.legend = override.legend; } if (override.yaxis !== void 0) { this.yaxis = override.yaxis; @@ -148,7 +224,9 @@ export default class TimeSeries { previousTime = currentTime; if (currentValue === null) { - if (ignoreNulls) { continue; } + if (ignoreNulls) { + continue; + } if (nullAsZero) { currentValue = 0; } @@ -172,16 +250,18 @@ export default class TimeSeries { if (this.stats.first === null) { this.stats.first = currentValue; } else { - if (previousValue > currentValue) { // counter reset + if (previousValue > currentValue) { + // counter reset previousDeltaUp = false; - if (i === this.datapoints.length-1) { // reset on last - this.stats.delta += currentValue; + if (i === this.datapoints.length - 1) { + // reset on last + this.stats.delta += currentValue; } } else { if (previousDeltaUp) { - this.stats.delta += currentValue - previousValue; // normal increment + this.stats.delta += currentValue - previousValue; // normal increment } else { - this.stats.delta += currentValue; // account for counter reset + this.stats.delta += currentValue; // account for counter reset } previousDeltaUp = true; } @@ -200,14 +280,18 @@ export default class TimeSeries { result.push([currentTime, currentValue]); } - if (this.stats.max === -Number.MAX_VALUE) { this.stats.max = null; } - if (this.stats.min === Number.MAX_VALUE) { this.stats.min = null; } + if (this.stats.max === -Number.MAX_VALUE) { + this.stats.max = null; + } + if (this.stats.min === Number.MAX_VALUE) { + this.stats.min = null; + } if (result.length && !this.allIsNull) { - this.stats.avg = (this.stats.total / nonNulls); - this.stats.current = result[result.length-1][1]; + this.stats.avg = this.stats.total / nonNulls; + this.stats.current = result[result.length - 1][1]; if (this.stats.current === null && result.length > 1) { - this.stats.current = result[result.length-2][1]; + this.stats.current = result[result.length - 2][1]; } } if (this.stats.max !== null && this.stats.min !== null) { @@ -238,7 +322,7 @@ export default class TimeSeries { for (var i = 0; i < this.datapoints.length; i++) { if (this.datapoints[i][1] !== null) { var timestamp = this.datapoints[i][1].toString(); - if (timestamp.length === 13 && (timestamp % 1000) !== 0) { + if (timestamp.length === 13 && timestamp % 1000 !== 0) { return true; } } diff --git a/public/app/core/utils/colors.ts b/public/app/core/utils/colors.ts index a38c92a6476..8a70e093ea2 100644 --- a/public/app/core/utils/colors.ts +++ b/public/app/core/utils/colors.ts @@ -4,19 +4,68 @@ import tinycolor from 'tinycolor2'; export const PALETTE_ROWS = 4; export const PALETTE_COLUMNS = 14; export const DEFAULT_ANNOTATION_COLOR = 'rgba(0, 211, 255, 1)'; -export const OK_COLOR = "rgba(11, 237, 50, 1)"; -export const ALERTING_COLOR = "rgba(237, 46, 24, 1)"; -export const NO_DATA_COLOR = "rgba(150, 150, 150, 1)"; +export const OK_COLOR = 'rgba(11, 237, 50, 1)'; +export const ALERTING_COLOR = 'rgba(237, 46, 24, 1)'; +export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)'; export const REGION_FILL_ALPHA = 0.09; let colors = [ - "#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", - "#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", - "#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", - "#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", - "#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", - "#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", - "#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" + '#7EB26D', + '#EAB839', + '#6ED0E0', + '#EF843C', + '#E24D42', + '#1F78C1', + '#BA43A9', + '#705DA0', + '#508642', + '#CCA300', + '#447EBC', + '#C15C17', + '#890F02', + '#0A437C', + '#6D1F62', + '#584477', + '#B7DBAB', + '#F4D598', + '#70DBED', + '#F9BA8F', + '#F29191', + '#82B5D8', + '#E5A8E2', + '#AEA2E0', + '#629E51', + '#E5AC0E', + '#64B0C8', + '#E0752D', + '#BF1B00', + '#0A50A1', + '#962D82', + '#614D93', + '#9AC48A', + '#F2C96D', + '#65C5DB', + '#F9934E', + '#EA6460', + '#5195CE', + '#D683CE', + '#806EB7', + '#3F6833', + '#967302', + '#2F575E', + '#99440A', + '#58140C', + '#052B51', + '#511749', + '#3F2B5B', + '#E0F9D7', + '#FCEACA', + '#CFFAFF', + '#F9E2D2', + '#FCE2DE', + '#BADFF4', + '#F9D9F9', + '#DEDAF7', ]; export function sortColorsByHue(hexColors) { diff --git a/public/app/core/utils/css_loader.ts b/public/app/core/utils/css_loader.ts index e81e659032d..42f59a9c27c 100644 --- a/public/app/core/utils/css_loader.ts +++ b/public/app/core/utils/css_loader.ts @@ -1,5 +1,3 @@ -/// - var waitSeconds = 100; var head = document.getElementsByTagName('head')[0]; @@ -49,7 +47,9 @@ var loadCSS = function(url) { link.href = url; if (!isWebkit) { - link.onload = function() { _callback(undefined); }; + link.onload = function() { + _callback(undefined); + }; } else { webkitLoadCheck(link, _callback); } @@ -75,4 +75,3 @@ export function fetch(load): any { } return loadCSS(load.address); } - diff --git a/public/app/core/utils/datemath.ts b/public/app/core/utils/datemath.ts index f5608443f49..340591e5d9c 100644 --- a/public/app/core/utils/datemath.ts +++ b/public/app/core/utils/datemath.ts @@ -1,14 +1,18 @@ -/// - import _ from 'lodash'; import moment from 'moment'; var units = ['y', 'M', 'w', 'd', 'h', 'm', 's']; export function parse(text, roundUp?, timezone?) { - if (!text) { return undefined; } - if (moment.isMoment(text)) { return text; } - if (_.isDate(text)) { return moment(text); } + if (!text) { + return undefined; + } + if (moment.isMoment(text)) { + return text; + } + if (_.isDate(text)) { + return moment(text); + } var time; var mathString = ''; @@ -84,7 +88,9 @@ export function parseDateMath(mathString, time, roundUp?) { var numFrom = i; while (!isNaN(mathString.charAt(i))) { i++; - if (i > 10) { return undefined; } + if (i > 10) { + return undefined; + } } num = parseInt(mathString.substring(numFrom, i), 10); } @@ -115,4 +121,3 @@ export function parseDateMath(mathString, time, roundUp?) { } return dateTime; } - diff --git a/public/app/core/utils/emitter.ts b/public/app/core/utils/emitter.ts index 280ccbdc14b..ae2489810a1 100644 --- a/public/app/core/utils/emitter.ts +++ b/public/app/core/utils/emitter.ts @@ -1,6 +1,4 @@ -/// - -import EventEmitter from 'eventemitter3'; +import { EventEmitter } from 'eventemitter3'; export class Emitter { emitter: any; diff --git a/public/app/core/utils/file_export.ts b/public/app/core/utils/file_export.ts index 03fcd147a3e..670326fc068 100644 --- a/public/app/core/utils/file_export.ts +++ b/public/app/core/utils/file_export.ts @@ -1,72 +1,119 @@ import _ from 'lodash'; import moment from 'moment'; -import {saveAs} from 'file-saver'; +import { saveAs } from 'file-saver'; const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ'; +const POINT_TIME_INDEX = 1; +const POINT_VALUE_INDEX = 0; + +export function convertSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { + var text = (excel ? 'sep=;\n' : '') + 'Series;Time;Value\n'; + _.each(seriesList, function(series) { + _.each(series.datapoints, function(dp) { + text += + series.alias + ';' + moment(dp[POINT_TIME_INDEX]).format(dateTimeFormat) + ';' + dp[POINT_VALUE_INDEX] + '\n'; + }); + }); + return text; +} export function exportSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { - var text = (excel ? 'sep=;\n' : '') + 'Series;Time;Value\n'; - _.each(seriesList, function(series) { - _.each(series.datapoints, function(dp) { - text += series.alias + ';' + moment(dp[1]).format(dateTimeFormat) + ';' + dp[0] + '\n'; - }); + var text = convertSeriesListToCsv(seriesList, dateTimeFormat, excel); + saveSaveBlob(text, 'grafana_data_export.csv'); +} + +export function convertSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { + let text = (excel ? 'sep=;\n' : '') + 'Time;'; + // add header + _.each(seriesList, function(series) { + text += series.alias + ';'; + }); + text = text.substring(0, text.length - 1); + text += '\n'; + + // process data + seriesList = mergeSeriesByTime(seriesList); + var dataArr = [[]]; + var sIndex = 1; + _.each(seriesList, function(series) { + var cIndex = 0; + dataArr.push([]); + _.each(series.datapoints, function(dp) { + dataArr[0][cIndex] = moment(dp[POINT_TIME_INDEX]).format(dateTimeFormat); + dataArr[sIndex][cIndex] = dp[POINT_VALUE_INDEX]; + cIndex++; }); - saveSaveBlob(text, 'grafana_data_export.csv'); + sIndex++; + }); + + // make text + for (var i = 0; i < dataArr[0].length; i++) { + text += dataArr[0][i] + ';'; + for (var j = 1; j < dataArr.length; j++) { + text += dataArr[j][i] + ';'; + } + text = text.substring(0, text.length - 1); + text += '\n'; + } + + return text; +} + +/** + * Collect all unique timestamps from series list and use it to fill + * missing points by null. + */ +function mergeSeriesByTime(seriesList) { + let timestamps = []; + for (let i = 0; i < seriesList.length; i++) { + let seriesPoints = seriesList[i].datapoints; + for (let j = 0; j < seriesPoints.length; j++) { + timestamps.push(seriesPoints[j][POINT_TIME_INDEX]); + } + } + timestamps = _.sortedUniq(timestamps.sort()); + + for (let i = 0; i < seriesList.length; i++) { + let seriesPoints = seriesList[i].datapoints; + let seriesTimestamps = _.map(seriesPoints, p => p[POINT_TIME_INDEX]); + let extendedSeries = []; + let pointIndex; + for (let j = 0; j < timestamps.length; j++) { + pointIndex = _.sortedIndexOf(seriesTimestamps, timestamps[j]); + if (pointIndex !== -1) { + extendedSeries.push(seriesPoints[pointIndex]); + } else { + extendedSeries.push([null, timestamps[j]]); + } + } + seriesList[i].datapoints = extendedSeries; + } + return seriesList; } export function exportSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { - var text = (excel ? 'sep=;\n' : '') + 'Time;'; - // add header - _.each(seriesList, function(series) { - text += series.alias + ';'; - }); - text = text.substring(0,text.length-1); - text += '\n'; - - // process data - var dataArr = [[]]; - var sIndex = 1; - _.each(seriesList, function(series) { - var cIndex = 0; - dataArr.push([]); - _.each(series.datapoints, function(dp) { - dataArr[0][cIndex] = moment(dp[1]).format(dateTimeFormat); - dataArr[sIndex][cIndex] = dp[0]; - cIndex++; - }); - sIndex++; - }); - - // make text - for (var i = 0; i < dataArr[0].length; i++) { - text += dataArr[0][i] + ';'; - for (var j = 1; j < dataArr.length; j++) { - text += dataArr[j][i] + ';'; - } - text = text.substring(0,text.length-1); - text += '\n'; - } - saveSaveBlob(text, 'grafana_data_export.csv'); + let text = convertSeriesListToCsvColumns(seriesList, dateTimeFormat, excel); + saveSaveBlob(text, 'grafana_data_export.csv'); } export function exportTableDataToCsv(table, excel = false) { var text = excel ? 'sep=;\n' : ''; - // add header - _.each(table.columns, function(column) { - text += (column.title || column.text) + ';'; + // add header + _.each(table.columns, function(column) { + text += (column.title || column.text) + ';'; + }); + text += '\n'; + // process data + _.each(table.rows, function(row) { + _.each(row, function(value) { + text += value + ';'; }); text += '\n'; - // process data - _.each(table.rows, function(row) { - _.each(row, function(value) { - text += value + ';'; - }); - text += '\n'; - }); - saveSaveBlob(text, 'grafana_data_export.csv'); + }); + saveSaveBlob(text, 'grafana_data_export.csv'); } export function saveSaveBlob(payload, fname) { - var blob = new Blob([payload], { type: "text/csv;charset=utf-8" }); - saveAs(blob, fname); + var blob = new Blob([payload], { type: 'text/csv;charset=utf-8' }); + saveAs(blob, fname); } diff --git a/public/app/core/utils/flatten.ts b/public/app/core/utils/flatten.ts index 927fbf34b78..150017e34f8 100644 --- a/public/app/core/utils/flatten.ts +++ b/public/app/core/utils/flatten.ts @@ -14,7 +14,7 @@ export default function flatten(target, opts): any { var value = object[key]; var isarray = opts.safe && Array.isArray(value); var type = Object.prototype.toString.call(value); - var isobject = type === "[object Object]"; + var isobject = type === '[object Object]'; var newKey = prev ? prev + delimiter + key : key; diff --git a/public/app/core/utils/kbn.ts b/public/app/core/utils/kbn.ts index b0715502114..329b415f1fe 100644 --- a/public/app/core/utils/kbn.ts +++ b/public/app/core/utils/kbn.ts @@ -463,6 +463,15 @@ kbn.valueFormats.Mbits = kbn.formatBuilders.decimalSIPrefix('bps', 2); kbn.valueFormats.GBs = kbn.formatBuilders.decimalSIPrefix('Bs', 3); kbn.valueFormats.Gbits = kbn.formatBuilders.decimalSIPrefix('bps', 3); +// Hash Rate +kbn.valueFormats.Hs = kbn.formatBuilders.decimalSIPrefix('H/s'); +kbn.valueFormats.KHs = kbn.formatBuilders.decimalSIPrefix('H/s', 1); +kbn.valueFormats.MHs = kbn.formatBuilders.decimalSIPrefix('H/s', 2); +kbn.valueFormats.GHs = kbn.formatBuilders.decimalSIPrefix('H/s', 3); +kbn.valueFormats.THs = kbn.formatBuilders.decimalSIPrefix('H/s', 4); +kbn.valueFormats.PHs = kbn.formatBuilders.decimalSIPrefix('H/s', 5); +kbn.valueFormats.EHs = kbn.formatBuilders.decimalSIPrefix('H/s', 6); + // Throughput kbn.valueFormats.ops = kbn.formatBuilders.simpleCountUnit('ops'); kbn.valueFormats.rps = kbn.formatBuilders.simpleCountUnit('rps'); @@ -493,6 +502,7 @@ kbn.valueFormats.kvolt = kbn.formatBuilders.decimalSIPrefix('V', 1); kbn.valueFormats.mvolt = kbn.formatBuilders.decimalSIPrefix('V', -1); kbn.valueFormats.dBm = kbn.formatBuilders.decimalSIPrefix('dBm'); kbn.valueFormats.ohm = kbn.formatBuilders.decimalSIPrefix('Ω'); +kbn.valueFormats.lumens = kbn.formatBuilders.decimalSIPrefix('Lm'); // Temperature kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C'); @@ -541,13 +551,13 @@ kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn'); // Acceleration kbn.valueFormats.accMS2 = kbn.formatBuilders.fixedUnit('m/sec²'); kbn.valueFormats.accFS2 = kbn.formatBuilders.fixedUnit('f/sec²'); -kbn.valueFormats.accG = kbn.formatBuilders.fixedUnit('g'); +kbn.valueFormats.accG = kbn.formatBuilders.fixedUnit('g'); // Volume kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L'); kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1); -kbn.valueFormats.m3 = kbn.formatBuilders.decimalSIPrefix('m3'); -kbn.valueFormats.dm3 = kbn.formatBuilders.decimalSIPrefix('dm3'); +kbn.valueFormats.m3 = kbn.formatBuilders.fixedUnit('m3'); +kbn.valueFormats.dm3 = kbn.formatBuilders.fixedUnit('dm3'); kbn.valueFormats.gallons = kbn.formatBuilders.fixedUnit('gal'); // Flow @@ -557,9 +567,9 @@ kbn.valueFormats.flowcfs = kbn.formatBuilders.fixedUnit('cfs'); kbn.valueFormats.flowcfm = kbn.formatBuilders.fixedUnit('cfm'); // Angle -kbn.valueFormats.degree = kbn.formatBuilders.fixedUnit('°'); -kbn.valueFormats.radian = kbn.formatBuilders.fixedUnit('rad'); -kbn.valueFormats.grad = kbn.formatBuilders.fixedUnit('grad'); +kbn.valueFormats.degree = kbn.formatBuilders.fixedUnit('°'); +kbn.valueFormats.radian = kbn.formatBuilders.fixedUnit('rad'); +kbn.valueFormats.grad = kbn.formatBuilders.fixedUnit('grad'); // Time kbn.valueFormats.hertz = kbn.formatBuilders.decimalSIPrefix('Hz'); @@ -877,6 +887,18 @@ kbn.getUnitFormats = function() { { text: 'gigabits/sec', value: 'Gbits' }, ], }, + { + text: 'hash rate', + submenu: [ + {text: 'hashes/sec', value: 'Hs'}, + {text: 'kilohashes/sec', value: 'KHs'}, + {text: 'megahashes/sec', value: 'MHs'}, + {text: 'gigahashes/sec', value: 'GHs'}, + {text: 'terahashes/sec', value: 'THs'}, + {text: 'petahashes/sec', value: 'PHs'}, + {text: 'exahashes/sec', value: 'EHs'}, + ], + }, { text: 'throughput', submenu: [ @@ -902,10 +924,10 @@ kbn.getUnitFormats = function() { { text: 'area', submenu: [ - {text: 'Square Meters (m²)', value: 'areaM2' }, - {text: 'Square Feet (ft²)', value: 'areaF2' }, - {text: 'Square Miles (mi²)', value: 'areaMI2'}, - ] + { text: 'Square Meters (m²)', value: 'areaM2' }, + { text: 'Square Feet (ft²)', value: 'areaF2' }, + { text: 'Square Miles (mi²)', value: 'areaMI2' }, + ], }, { text: 'mass', @@ -957,7 +979,8 @@ kbn.getUnitFormats = function() { { text: 'Kilovolt (kV)', value: 'kvolt' }, { text: 'Millivolt (mV)', value: 'mvolt' }, { text: 'Decibel-milliwatt (dBm)', value: 'dBm' }, - { text: 'Ohm (Ω)', value: 'ohm' } + { text: 'Ohm (Ω)', value: 'ohm' }, + { text: 'Lumens (Lm)', value: 'lumens' }, ], }, { @@ -1002,17 +1025,17 @@ kbn.getUnitFormats = function() { submenu: [ { text: 'Degrees (°)', value: 'degree' }, { text: 'Radians', value: 'radian' }, - { text: 'Gradian', value: 'grad' } - ] + { text: 'Gradian', value: 'grad' }, + ], }, { text: 'acceleration', submenu: [ { text: 'Meters/sec²', value: 'accMS2' }, - { text: 'Feet/sec²', value: 'accFS2' }, - { text: 'G unit', value: 'accG' } - ] - } + { text: 'Feet/sec²', value: 'accFS2' }, + { text: 'G unit', value: 'accG' }, + ], + }, ]; }; diff --git a/public/app/core/utils/location_util.ts b/public/app/core/utils/location_util.ts new file mode 100644 index 00000000000..f8d6aa4ee5f --- /dev/null +++ b/public/app/core/utils/location_util.ts @@ -0,0 +1,14 @@ +import config from 'app/core/config'; + +const _stripBaseFromUrl = url => { + const appSubUrl = config.appSubUrl; + const stripExtraChars = appSubUrl.endsWith('/') ? 1 : 0; + const urlWithoutBase = + url.length > 0 && url.indexOf(appSubUrl) === 0 ? url.slice(appSubUrl.length - stripExtraChars) : url; + + return urlWithoutBase; +}; + +export default { + stripBaseFromUrl: _stripBaseFromUrl, +}; diff --git a/public/app/core/utils/model_utils.ts b/public/app/core/utils/model_utils.ts index dd620aff53d..e595ada6e13 100644 --- a/public/app/core/utils/model_utils.ts +++ b/public/app/core/utils/model_utils.ts @@ -7,4 +7,3 @@ export function assignModelProperties(target, source, defaults, removeDefaults?) target[key] = source[key] === undefined ? defaults[key] : source[key]; } } - diff --git a/public/app/core/utils/outline.ts b/public/app/core/utils/outline.ts index 109d13d9fc9..94393e781e9 100644 --- a/public/app/core/utils/outline.ts +++ b/public/app/core/utils/outline.ts @@ -5,7 +5,7 @@ function outlineFixer() { var style_element = d.createElement('STYLE'); var dom_events = 'addEventListener' in d; - var add_event_listener = function (type, callback) { + var add_event_listener = function(type, callback) { // Basic cross-browser event handling if (dom_events) { d.addEventListener(type, callback); @@ -14,19 +14,19 @@ function outlineFixer() { } }; - var set_css = function (css_text) { + var set_css = function(css_text) { // Handle setting of + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icn-row.svg b/public/img/icn-row.svg new file mode 100644 index 00000000000..5218991033b --- /dev/null +++ b/public/img/icn-row.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_annotation.svg b/public/img/icons_dark_theme/icon_add_annotation.svg new file mode 100644 index 00000000000..330dfad85ad --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_annotation.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_annotation_alt.svg b/public/img/icons_dark_theme/icon_add_annotation_alt.svg new file mode 100644 index 00000000000..f24a46ee75c --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_annotation_alt.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_data_sources.svg b/public/img/icons_dark_theme/icon_add_data_sources.svg new file mode 100644 index 00000000000..6ea76c00735 --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_data_sources.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_folder.svg b/public/img/icons_dark_theme/icon_add_folder.svg new file mode 100644 index 00000000000..0e3357d1086 --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_folder.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_link.svg b/public/img/icons_dark_theme/icon_add_link.svg new file mode 100644 index 00000000000..fe8e95f1eda --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_link.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_notification_channel.svg b/public/img/icons_dark_theme/icon_add_notification_channel.svg new file mode 100644 index 00000000000..a8dc4b98680 --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_notification_channel.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_panel.svg b/public/img/icons_dark_theme/icon_add_panel.svg new file mode 100644 index 00000000000..a3005b3ee1c --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_panel.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_team.svg b/public/img/icons_dark_theme/icon_add_team.svg new file mode 100644 index 00000000000..35fd526e053 --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_team.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_user.svg b/public/img/icons_dark_theme/icon_add_user.svg new file mode 100644 index 00000000000..6a09f96ef1e --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_user.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_add_variable.svg b/public/img/icons_dark_theme/icon_add_variable.svg new file mode 100644 index 00000000000..9b10092e78f --- /dev/null +++ b/public/img/icons_dark_theme/icon_add_variable.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_alert.svg b/public/img/icons_dark_theme/icon_alert.svg new file mode 100644 index 00000000000..2a3a764a925 --- /dev/null +++ b/public/img/icons_dark_theme/icon_alert.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_alert_alt.svg b/public/img/icons_dark_theme/icon_alert_alt.svg new file mode 100644 index 00000000000..a6c6e9bd051 --- /dev/null +++ b/public/img/icons_dark_theme/icon_alert_alt.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_alert_off.svg b/public/img/icons_dark_theme/icon_alert_off.svg new file mode 100644 index 00000000000..cebbe532ce4 --- /dev/null +++ b/public/img/icons_dark_theme/icon_alert_off.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_alert_rules.svg b/public/img/icons_dark_theme/icon_alert_rules.svg new file mode 100644 index 00000000000..71915eb6d1c --- /dev/null +++ b/public/img/icons_dark_theme/icon_alert_rules.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_annotation.svg b/public/img/icons_dark_theme/icon_annotation.svg new file mode 100644 index 00000000000..514b52fba40 --- /dev/null +++ b/public/img/icons_dark_theme/icon_annotation.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_annotation_alt.svg b/public/img/icons_dark_theme/icon_annotation_alt.svg new file mode 100644 index 00000000000..e798f91805c --- /dev/null +++ b/public/img/icons_dark_theme/icon_annotation_alt.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_apikeys.svg b/public/img/icons_dark_theme/icon_apikeys.svg new file mode 100644 index 00000000000..8cc30794456 --- /dev/null +++ b/public/img/icons_dark_theme/icon_apikeys.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/public/img/icons_dark_theme/icon_cog.svg b/public/img/icons_dark_theme/icon_cog.svg new file mode 100644 index 00000000000..126b529e0df --- /dev/null +++ b/public/img/icons_dark_theme/icon_cog.svg @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_dashboard.svg b/public/img/icons_dark_theme/icon_dashboard.svg new file mode 100644 index 00000000000..a5d4e9b491d --- /dev/null +++ b/public/img/icons_dark_theme/icon_dashboard.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_dashboard_fav.svg b/public/img/icons_dark_theme/icon_dashboard_fav.svg new file mode 100644 index 00000000000..22d2462e922 --- /dev/null +++ b/public/img/icons_dark_theme/icon_dashboard_fav.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_dashboard_list.svg b/public/img/icons_dark_theme/icon_dashboard_list.svg new file mode 100644 index 00000000000..1979400de7b --- /dev/null +++ b/public/img/icons_dark_theme/icon_dashboard_list.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_data_sources.svg b/public/img/icons_dark_theme/icon_data_sources.svg new file mode 100644 index 00000000000..5cce28eb217 --- /dev/null +++ b/public/img/icons_dark_theme/icon_data_sources.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_home.svg b/public/img/icons_dark_theme/icon_home.svg new file mode 100644 index 00000000000..a4f2608d576 --- /dev/null +++ b/public/img/icons_dark_theme/icon_home.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/public/img/icons_dark_theme/icon_import_dashboard.svg b/public/img/icons_dark_theme/icon_import_dashboard.svg new file mode 100644 index 00000000000..d21511c31c5 --- /dev/null +++ b/public/img/icons_dark_theme/icon_import_dashboard.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_json.svg b/public/img/icons_dark_theme/icon_json.svg new file mode 100644 index 00000000000..30b0d9d0972 --- /dev/null +++ b/public/img/icons_dark_theme/icon_json.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_link.svg b/public/img/icons_dark_theme/icon_link.svg new file mode 100644 index 00000000000..ac4bba7fe46 --- /dev/null +++ b/public/img/icons_dark_theme/icon_link.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_new_dashboard.svg b/public/img/icons_dark_theme/icon_new_dashboard.svg new file mode 100644 index 00000000000..33f116dcab1 --- /dev/null +++ b/public/img/icons_dark_theme/icon_new_dashboard.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_notification_channels.svg b/public/img/icons_dark_theme/icon_notification_channels.svg new file mode 100644 index 00000000000..d3bad3f78f4 --- /dev/null +++ b/public/img/icons_dark_theme/icon_notification_channels.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/public/img/icons_dark_theme/icon_org.svg b/public/img/icons_dark_theme/icon_org.svg new file mode 100644 index 00000000000..b9aa21c3a9c --- /dev/null +++ b/public/img/icons_dark_theme/icon_org.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_playlist.svg b/public/img/icons_dark_theme/icon_playlist.svg new file mode 100644 index 00000000000..bf8fc2f80a3 --- /dev/null +++ b/public/img/icons_dark_theme/icon_playlist.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_plugins.svg b/public/img/icons_dark_theme/icon_plugins.svg new file mode 100644 index 00000000000..f00eefea975 --- /dev/null +++ b/public/img/icons_dark_theme/icon_plugins.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/public/img/icons_dark_theme/icon_preferences.svg b/public/img/icons_dark_theme/icon_preferences.svg new file mode 100644 index 00000000000..ed985c39f68 --- /dev/null +++ b/public/img/icons_dark_theme/icon_preferences.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_question.svg b/public/img/icons_dark_theme/icon_question.svg new file mode 100644 index 00000000000..aa33cf29467 --- /dev/null +++ b/public/img/icons_dark_theme/icon_question.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_shield.svg b/public/img/icons_dark_theme/icon_shield.svg new file mode 100644 index 00000000000..7709351a56e --- /dev/null +++ b/public/img/icons_dark_theme/icon_shield.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_sitemap.svg b/public/img/icons_dark_theme/icon_sitemap.svg new file mode 100644 index 00000000000..499273a399e --- /dev/null +++ b/public/img/icons_dark_theme/icon_sitemap.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/public/img/icons_dark_theme/icon_snapshots.svg b/public/img/icons_dark_theme/icon_snapshots.svg new file mode 100644 index 00000000000..5f3543623c7 --- /dev/null +++ b/public/img/icons_dark_theme/icon_snapshots.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_team.svg b/public/img/icons_dark_theme/icon_team.svg new file mode 100644 index 00000000000..1248f5d5e39 --- /dev/null +++ b/public/img/icons_dark_theme/icon_team.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_user.svg b/public/img/icons_dark_theme/icon_user.svg new file mode 100644 index 00000000000..9479e9452ce --- /dev/null +++ b/public/img/icons_dark_theme/icon_user.svg @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_variable.svg b/public/img/icons_dark_theme/icon_variable.svg new file mode 100644 index 00000000000..4fffa63329a --- /dev/null +++ b/public/img/icons_dark_theme/icon_variable.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/public/img/icons_dark_theme/icon_zoom_out.svg b/public/img/icons_dark_theme/icon_zoom_out.svg new file mode 100644 index 00000000000..f94f0fa665e --- /dev/null +++ b/public/img/icons_dark_theme/icon_zoom_out.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_annotation.svg b/public/img/icons_light_theme/icon_add_annotation.svg new file mode 100644 index 00000000000..1cf90df2bcb --- /dev/null +++ b/public/img/icons_light_theme/icon_add_annotation.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_annotation_alt.svg b/public/img/icons_light_theme/icon_add_annotation_alt.svg new file mode 100644 index 00000000000..990df3a9d60 --- /dev/null +++ b/public/img/icons_light_theme/icon_add_annotation_alt.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_data_sources.svg b/public/img/icons_light_theme/icon_add_data_sources.svg new file mode 100644 index 00000000000..554af86bfc8 --- /dev/null +++ b/public/img/icons_light_theme/icon_add_data_sources.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_folder.svg b/public/img/icons_light_theme/icon_add_folder.svg new file mode 100644 index 00000000000..a127eeb4dee --- /dev/null +++ b/public/img/icons_light_theme/icon_add_folder.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_link.svg b/public/img/icons_light_theme/icon_add_link.svg new file mode 100644 index 00000000000..cdeb4450bb4 --- /dev/null +++ b/public/img/icons_light_theme/icon_add_link.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_notification_channel.svg b/public/img/icons_light_theme/icon_add_notification_channel.svg new file mode 100644 index 00000000000..68fad3d13a5 --- /dev/null +++ b/public/img/icons_light_theme/icon_add_notification_channel.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_panel.svg b/public/img/icons_light_theme/icon_add_panel.svg new file mode 100644 index 00000000000..e5630d26bb6 --- /dev/null +++ b/public/img/icons_light_theme/icon_add_panel.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_team.svg b/public/img/icons_light_theme/icon_add_team.svg new file mode 100644 index 00000000000..dd1580f3a3d --- /dev/null +++ b/public/img/icons_light_theme/icon_add_team.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_user.svg b/public/img/icons_light_theme/icon_add_user.svg new file mode 100644 index 00000000000..ef0d1d785f0 --- /dev/null +++ b/public/img/icons_light_theme/icon_add_user.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_add_variable.svg b/public/img/icons_light_theme/icon_add_variable.svg new file mode 100644 index 00000000000..3ae26bf4d9f --- /dev/null +++ b/public/img/icons_light_theme/icon_add_variable.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_alert.svg b/public/img/icons_light_theme/icon_alert.svg new file mode 100644 index 00000000000..5f8b16acaa2 --- /dev/null +++ b/public/img/icons_light_theme/icon_alert.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_alert_alt.svg b/public/img/icons_light_theme/icon_alert_alt.svg new file mode 100644 index 00000000000..542004bc4d3 --- /dev/null +++ b/public/img/icons_light_theme/icon_alert_alt.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_alert_off.svg b/public/img/icons_light_theme/icon_alert_off.svg new file mode 100644 index 00000000000..279f3277ef3 --- /dev/null +++ b/public/img/icons_light_theme/icon_alert_off.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_alert_rules.svg b/public/img/icons_light_theme/icon_alert_rules.svg new file mode 100644 index 00000000000..b7f000dc67b --- /dev/null +++ b/public/img/icons_light_theme/icon_alert_rules.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_annotation.svg b/public/img/icons_light_theme/icon_annotation.svg new file mode 100644 index 00000000000..86cfc857e97 --- /dev/null +++ b/public/img/icons_light_theme/icon_annotation.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_annotation_alt.svg b/public/img/icons_light_theme/icon_annotation_alt.svg new file mode 100644 index 00000000000..aaf3117f313 --- /dev/null +++ b/public/img/icons_light_theme/icon_annotation_alt.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_apikeys.svg b/public/img/icons_light_theme/icon_apikeys.svg new file mode 100644 index 00000000000..a79d66dd370 --- /dev/null +++ b/public/img/icons_light_theme/icon_apikeys.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/public/img/icons_light_theme/icon_cog.svg b/public/img/icons_light_theme/icon_cog.svg new file mode 100644 index 00000000000..049e56f4cca --- /dev/null +++ b/public/img/icons_light_theme/icon_cog.svg @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/public/img/icons_light_theme/icon_dashboard.svg b/public/img/icons_light_theme/icon_dashboard.svg new file mode 100644 index 00000000000..140076e9249 --- /dev/null +++ b/public/img/icons_light_theme/icon_dashboard.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_dashboard_fav.svg b/public/img/icons_light_theme/icon_dashboard_fav.svg new file mode 100644 index 00000000000..64e0c8e0831 --- /dev/null +++ b/public/img/icons_light_theme/icon_dashboard_fav.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_dashboard_list.svg b/public/img/icons_light_theme/icon_dashboard_list.svg new file mode 100644 index 00000000000..0cde7975b2a --- /dev/null +++ b/public/img/icons_light_theme/icon_dashboard_list.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_data_sources.svg b/public/img/icons_light_theme/icon_data_sources.svg new file mode 100644 index 00000000000..aa2829de4ec --- /dev/null +++ b/public/img/icons_light_theme/icon_data_sources.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_home.svg b/public/img/icons_light_theme/icon_home.svg new file mode 100644 index 00000000000..1ce7799c9f2 --- /dev/null +++ b/public/img/icons_light_theme/icon_home.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/public/img/icons_light_theme/icon_import_dashboard.svg b/public/img/icons_light_theme/icon_import_dashboard.svg new file mode 100644 index 00000000000..f2015379be3 --- /dev/null +++ b/public/img/icons_light_theme/icon_import_dashboard.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_json.svg b/public/img/icons_light_theme/icon_json.svg new file mode 100644 index 00000000000..d8f748e5e94 --- /dev/null +++ b/public/img/icons_light_theme/icon_json.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_link.svg b/public/img/icons_light_theme/icon_link.svg new file mode 100644 index 00000000000..ca0de590eb4 --- /dev/null +++ b/public/img/icons_light_theme/icon_link.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_new_dashboard.svg b/public/img/icons_light_theme/icon_new_dashboard.svg new file mode 100644 index 00000000000..83e04863aa4 --- /dev/null +++ b/public/img/icons_light_theme/icon_new_dashboard.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_notification_channels.svg b/public/img/icons_light_theme/icon_notification_channels.svg new file mode 100644 index 00000000000..ae42f0fd8d1 --- /dev/null +++ b/public/img/icons_light_theme/icon_notification_channels.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/public/img/icons_light_theme/icon_org.svg b/public/img/icons_light_theme/icon_org.svg new file mode 100644 index 00000000000..2f0eeb54a9e --- /dev/null +++ b/public/img/icons_light_theme/icon_org.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_playlist.svg b/public/img/icons_light_theme/icon_playlist.svg new file mode 100644 index 00000000000..53cab585fc5 --- /dev/null +++ b/public/img/icons_light_theme/icon_playlist.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_plugins.svg b/public/img/icons_light_theme/icon_plugins.svg new file mode 100644 index 00000000000..49df86fc8e2 --- /dev/null +++ b/public/img/icons_light_theme/icon_plugins.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/public/img/icons_light_theme/icon_preferences.svg b/public/img/icons_light_theme/icon_preferences.svg new file mode 100644 index 00000000000..bbf01f74e52 --- /dev/null +++ b/public/img/icons_light_theme/icon_preferences.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_question.svg b/public/img/icons_light_theme/icon_question.svg new file mode 100644 index 00000000000..c213174208e --- /dev/null +++ b/public/img/icons_light_theme/icon_question.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_shield.svg b/public/img/icons_light_theme/icon_shield.svg new file mode 100644 index 00000000000..d86f0493afe --- /dev/null +++ b/public/img/icons_light_theme/icon_shield.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_sitemap.svg b/public/img/icons_light_theme/icon_sitemap.svg new file mode 100644 index 00000000000..646bccfc41f --- /dev/null +++ b/public/img/icons_light_theme/icon_sitemap.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/public/img/icons_light_theme/icon_snapshots.svg b/public/img/icons_light_theme/icon_snapshots.svg new file mode 100644 index 00000000000..4bfe0ae0ec1 --- /dev/null +++ b/public/img/icons_light_theme/icon_snapshots.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_team.svg b/public/img/icons_light_theme/icon_team.svg new file mode 100644 index 00000000000..d4f453afb6b --- /dev/null +++ b/public/img/icons_light_theme/icon_team.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_user.svg b/public/img/icons_light_theme/icon_user.svg new file mode 100644 index 00000000000..568e5215dd4 --- /dev/null +++ b/public/img/icons_light_theme/icon_user.svg @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/public/img/icons_light_theme/icon_variable.svg b/public/img/icons_light_theme/icon_variable.svg new file mode 100644 index 00000000000..a4603109e14 --- /dev/null +++ b/public/img/icons_light_theme/icon_variable.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/public/img/icons_light_theme/icon_zoom_out.svg b/public/img/icons_light_theme/icon_zoom_out.svg new file mode 100644 index 00000000000..7dfd3cf2600 --- /dev/null +++ b/public/img/icons_light_theme/icon_zoom_out.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index 79ee1799b90..36072fe8929 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -1,97 +1,108 @@ // vendor -@import "../vendor/css/timepicker.css"; -@import "../vendor/css/spectrum.css"; +@import '../vendor/css/timepicker.css'; +@import '../vendor/css/spectrum.css'; // MIXINS -@import "mixins/mixins"; -@import "mixins/animations"; -@import "mixins/buttons"; -@import "mixins/breakpoints"; -@import "mixins/grid"; -@import "mixins/grid-framework"; -@import "mixins/hover"; -@import "mixins/forms"; -@import "mixins/drop_element"; +@import 'mixins/mixins'; +@import 'mixins/animations'; +@import 'mixins/buttons'; +@import 'mixins/breakpoints'; +@import 'mixins/grid'; +@import 'mixins/grid-framework'; +@import 'mixins/hover'; +@import 'mixins/forms'; +@import 'mixins/drop_element'; // BASE -@import "base/normalize"; -@import "base/reboot"; -@import "base/type"; -@import "base/forms"; -@import "base/grid"; -@import "base/fonts"; -@import "base/code"; +@import 'base/normalize'; +@import 'base/reboot'; +@import 'base/type'; +@import 'base/forms'; +@import 'base/grid'; +@import 'base/fonts'; +@import 'base/code'; +@import 'base/icons'; // UTILS -@import "utils/utils"; -@import "utils/validation"; -@import "utils/angular"; -@import "utils/spacings"; -@import "utils/widths"; +@import 'utils/utils'; +@import 'utils/validation'; +@import 'utils/angular'; +@import 'utils/spacings'; +@import 'utils/widths'; // LAYOUTS -@import "layout/lists"; -@import "layout/page"; +@import 'layout/lists'; +@import 'layout/page'; // COMPONENTS -@import "components/cards"; -@import "components/buttons"; -@import "components/navs"; -@import "components/tabs"; -@import "components/alerts"; -@import "components/switch"; -@import "components/tooltip"; -@import "components/tags"; -@import "components/panel_graph"; -@import "components/submenu"; -@import "components/panel_alertlist"; -@import "components/panel_dashlist"; -@import "components/panel_gettingstarted"; -@import "components/panel_pluginlist"; -@import "components/panel_singlestat"; -@import "components/panel_table"; -@import "components/panel_text"; -@import "components/panel_heatmap"; -@import "components/tagsinput"; -@import "components/tables_lists"; -@import "components/search"; -@import "components/gf-form"; -@import "components/sidemenu"; -@import "components/navbar"; -@import "components/timepicker"; -@import "components/filter-controls"; -@import "components/filter-list"; -@import "components/filter-table"; -@import "components/scrollbar"; -@import "components/old_stuff"; -@import "components/typeahead"; -@import "components/modals"; -@import "components/dropdown"; -@import "components/color_picker"; -@import "components/footer"; -@import "components/infobox"; -@import "components/shortcuts"; -@import "components/drop"; -@import "components/query_editor"; -@import "components/tabbed_view"; -@import "components/query_part"; -@import "components/jsontree"; -@import "components/edit_sidemenu.scss"; -@import "components/row.scss"; -@import "components/icon-picker.scss"; -@import "components/json_explorer.scss"; -@import "components/code_editor.scss"; +@import 'components/scrollbar'; +@import 'components/cards'; +@import 'components/buttons'; +@import 'components/navs'; +@import 'components/tabs'; +@import 'components/alerts'; +@import 'components/switch'; +@import 'components/tooltip'; +@import 'components/tags'; +@import 'components/panel_graph'; +@import 'components/submenu'; +@import 'components/panel_alertlist'; +@import 'components/panel_dashlist'; +@import 'components/panel_gettingstarted'; +@import 'components/panel_pluginlist'; +@import 'components/panel_singlestat'; +@import 'components/panel_table'; +@import 'components/panel_text'; +@import 'components/panel_heatmap'; +@import 'components/panel_add_panel'; +@import 'components/settings_permissions'; +@import 'components/tagsinput'; +@import 'components/tables_lists'; +@import 'components/search'; +@import 'components/gf-form'; +@import 'components/sidemenu'; +@import 'components/navbar'; +@import 'components/timepicker'; +@import 'components/filter-controls'; +@import 'components/filter-list'; +@import 'components/filter-table'; +@import 'components/old_stuff'; +@import 'components/typeahead'; +@import 'components/modals'; +@import 'components/dropdown'; +@import 'components/color_picker'; +@import 'components/footer'; +@import 'components/infobox'; +@import 'components/shortcuts'; +@import 'components/drop'; +@import 'components/query_editor'; +@import 'components/tabbed_view'; +@import 'components/query_part'; +@import 'components/jsontree'; +@import 'components/edit_sidemenu'; +@import 'components/row.scss'; +@import 'components/json_explorer'; +@import 'components/code_editor'; +@import 'components/dashboard_grid'; +@import 'components/dashboard_list'; +@import 'components/page_header'; +@import 'components/dashboard_settings'; +@import 'components/empty_list_cta'; +@import 'components/popper'; +@import 'components/form_select_box'; +@import 'components/user-picker'; +@import 'components/description-picker'; // PAGES -@import "pages/login"; -@import "pages/dashboard"; -@import "pages/playlist"; -@import "pages/admin"; -@import "pages/alerting"; -@import "pages/history"; -@import "pages/plugins"; -@import "pages/signup"; -@import "pages/styleguide"; -@import "pages/errorpage"; -@import "old_responsive"; -@import "components/view_states.scss"; +@import 'pages/login'; +@import 'pages/dashboard'; +@import 'pages/playlist'; +@import 'pages/admin'; +@import 'pages/alerting'; +@import 'pages/history'; +@import 'pages/plugins'; +@import 'pages/signup'; +@import 'pages/styleguide'; +@import 'pages/errorpage'; +@import 'old_responsive'; +@import 'components/view_states.scss'; diff --git a/public/sass/_old_responsive.scss b/public/sass/_old_responsive.scss index be56bbae485..991b0f30aa1 100644 --- a/public/sass/_old_responsive.scss +++ b/public/sass/_old_responsive.scss @@ -1,98 +1,65 @@ +.navbar-buttons--zoom { + display: none; +} -.dashnav-back-to-dashboard { +.navbar-page-btn { + max-width: 200px; +} + +.gf-timepicker-nav-btn { + max-width: 120px; +} + +.navbar-buttons--actions { display: none; } // Media queries // --------------------- -@include media-breakpoint-down(sm) { - div.panel { - width: 100% !important; - padding: 0px !important; - } - .panel-margin { - margin-right: 0; - margin-left: 0; - } - body { - padding: 0; - } - .page-dashboard .navbar-page-btn { - max-width: 200px; - } - .gf-timepicker-nav-btn { - max-width: 120px; - } - .dashnav-zoom-out, - .dashnav-move-timeframe, - .dashnav-action-icons { - display: none; - } - .page-container { - padding: ($spacer * 1) ($spacer * 2); - } - - .dash-row-menu-container { - display: none; +@include media-breakpoint-down(xs) { + input[type='text'], + input[type='number'], + textarea { + font-size: 16px; } } -@include media-breakpoint-down(xs) { - .page-dashboard .navbar-page-btn { +@include media-breakpoint-up(sm) { + .navbar-page-btn { max-width: 250px; } -} - -// form styles -@include media-breakpoint-up(md) { - .page-dashboard .navbar-page-btn { - max-width: 280px; - } .gf-timepicker-nav-btn { - max-width: 120px; - } - - .dashnav-move-timeframe { - display: none; - } - - .panel-in-fullscreen { - .dashnav-action-icons { - display: none; - } - .dashnav-back-to-dashboard { - display: block; - } + max-width: 200px; } } -@include media-breakpoint-up(lg) { - .page-dashboard .navbar-page-btn { - max-width: 290px; +@include media-breakpoint-up(md) { + .navbar-buttons--actions { + display: flex; + } + .navbar-page-btn { + max-width: 325px; } .gf-timepicker-nav-btn { max-width: 240px; } - .dashnav-zoom-out { - display: block; - } - .dashnav-move-timeframe { - display: block; - } } -@include media-breakpoint-up(xl) { - .panel-in-fullscreen { - .dashnav-action-icons { - display: block; - } +@include media-breakpoint-up(lg) { + .navbar-buttons--zoom { + display: flex; } - - .page-dashboard .navbar-page-btn { - max-width: none; + .navbar-page-btn { + max-width: 450px; } .gf-timepicker-nav-btn { max-width: none; } } + +@include media-breakpoint-up(xl) { + .navbar-page-btn { + max-width: 600px; + } +} diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss index 27f0e959d34..ef9f1a06996 100644 --- a/public/sass/_variables.dark.scss +++ b/public/sass/_variables.dark.scss @@ -1,287 +1,334 @@ // Global values // -------------------------------------------------- +$theme-name: dark; // Grays // ------------------------- -$black: #000; +$black: #000; // ------------------------- -$black: #000; -$dark-1: #141414; -$dark-2: #1f1d1d; -$dark-3: #292929; -$dark-4: #333333; -$dark-5: #444444; -$gray-1: #555555; -$gray-2: #7B7B7B; -$gray-3: #b3b3b3; -$gray-4: #D8D9DA; -$gray-5: #ECECEC; -$gray-6: #f4f5f8; -$gray-7: #fbfbfb; +$black: #000; +$dark-1: #141414; +$dark-2: #1f1f20; +$dark-3: #262628; +$dark-4: #333333; +$dark-5: #444444; +$gray-1: #555555; +$gray-2: #8e8e8e; +$gray-3: #b3b3b3; +$gray-4: #d8d9da; +$gray-5: #ececec; +$gray-6: #f4f5f8; +$gray-7: #fbfbfb; -$white: #fff; +$gray-blue: #212327; +$input-black: #09090b; + +$white: #fff; // Accent colors // ------------------------- -$blue: #33B5E5; -$blue-dark: #005f81; -$green: #299c46; -$red: #d44a3a; -$yellow: #ECBB13; -$pink: #FF4444; -$purple: #9933CC; -$variable: #32D1DF; -$orange: #eb7b18; +$blue: #33b5e5; +$blue-dark: #005f81; +$green: #299c46; +$red: #d44a3a; +$yellow: #ecbb13; +$pink: #ff4444; +$purple: #9933cc; +$variable: #32d1df; +$orange: #eb7b18; -$brand-primary: $orange; -$brand-success: $green; -$brand-warning: $brand-primary; -$brand-danger: $red; +$brand-primary: $orange; +$brand-success: $green; +$brand-warning: $brand-primary; +$brand-danger: $red; + +$query-blue: $blue; // Status colors // ------------------------- -$online: #10a345; -$warn: #F79520; -$critical: #ed2e18; +$online: #10a345; +$warn: #f79520; +$critical: #ed2e18; // Scaffolding // ------------------------- -$body-bg: rgb(20,20,20); -$page-bg: $dark-2; -$body-color: $gray-4; -$text-color: $gray-4; -$text-color-strong: $white; -$text-color-weak: $gray-2; -$text-color-faint: $dark-5; -$text-color-emphasis: $gray-5; +$body-bg: rgb(23, 24, 25); +$page-bg: rgb(22, 23, 25); + +$body-color: $gray-4; +$text-color: $gray-4; +$text-color-strong: $white; +$text-color-weak: $gray-2; +$text-color-faint: $dark-5; +$text-color-emphasis: $gray-5; $text-shadow-strong: 1px 1px 4px $black; $text-shadow-faint: 1px 1px 4px rgb(45, 45, 45); // gradients -$brand-gradient: linear-gradient(to right, rgba(255,213,0,0.7) 0%, rgba(255,68,0,0.7) 99%, rgba(255,68,0,0.7) 100%); -$page-gradient: linear-gradient(60deg, transparent 70%, darken($page-bg, 4%) 98%); +$brand-gradient: linear-gradient( + to right, + rgba(255, 213, 0, 0.7) 0%, + rgba(255, 68, 0, 0.7) 99%, + rgba(255, 68, 0, 0.7) 100% +); +$page-gradient: linear-gradient(180deg, #222426 10px, rgb(22, 23, 25) 100px); // Links // ------------------------- -$link-color: darken($white, 11%); -$link-color-disabled: darken($link-color, 30%); -$link-hover-color: $white; -$external-link-color: $blue; +$link-color: darken($white, 11%); +$link-color-disabled: darken($link-color, 30%); +$link-hover-color: $white; +$external-link-color: $blue; // Typography // ------------------------- -$headings-color: darken($white,11%); -$abbr-border-color: $gray-3 !default; -$text-muted: $text-color-weak; +$headings-color: darken($white, 11%); +$abbr-border-color: $gray-3 !default; +$text-muted: $text-color-weak; -$blockquote-small-color: $gray-3 !default; +$blockquote-small-color: $gray-3 !default; $blockquote-border-color: $gray-4 !default; -$hr-border-color: rgba(0,0,0,.1) !default; +$hr-border-color: rgba(0, 0, 0, 0.1) !default; // Components $component-active-color: #fff !default; -$component-active-bg: $brand-primary !default; +$component-active-bg: $brand-primary !default; // Panel // ------------------------- -$panel-bg: $dark-2; -$panel-border: solid 1px $dark-3; -$panel-drop-zone-bg: repeating-linear-gradient(-128deg, #111, #111 10px, #191919 10px, #222 20px); -$panel-menu-border: solid 1px black; +$panel-bg: #212124; +$panel-border-color: $dark-1; +$panel-border: solid 1px $panel-border-color; +$panel-drop-zone-bg: repeating-linear-gradient(-128deg, #111, #111 10px, #191919 10px, #222 20px); +$panel-header-hover-bg: $dark-4; +$panel-header-menu-hover-bg: $dark-5; +$panel-edit-shadow: 0 -30px 30px -30px $black; -$divider-border-color: #555; +// page header +$page-header-bg: linear-gradient(90deg, #292a2d, black); +$page-header-shadow: inset 0px -4px 14px $dark-2; +$page-header-border-color: $dark-4; + +$divider-border-color: #555; // Graphite Target Editor -$tight-form-border: #050505; -$tight-form-bg: $dark-3; +$tight-form-bg: $dark-3; -$tight-form-func-bg: #333; -$tight-form-func-highlight-bg: #444; +$tight-form-func-bg: #333334; +$tight-form-func-highlight-bg: #444445; -$modal-background: $black; -$code-tag-bg: $gray-1; -$code-tag-border: lighten($code-tag-bg, 2%); +$modal-backdrop-bg: #353c42; +$code-tag-bg: $gray-1; +$code-tag-border: lighten($code-tag-bg, 2%); +// cards +$card-background: linear-gradient(135deg, #2f2f32, #262628); +$card-background-hover: linear-gradient(135deg, #343436, #262628); +$card-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3); // Lists -$grafanaListBackground: $dark-3; -$grafanaListAccent: lighten($dark-2, 2%); -$grafanaListBorderTop: $dark-3; -$grafanaListBorderBottom: $black; -$grafanaListHighlight: #333; -$grafanaListMainLinkColor: $text-color; +$list-item-bg: $card-background; +$list-item-hover-bg: lighten($gray-blue, 2%); +$list-item-link-color: $text-color; +$list-item-shadow: $card-shadow; +$empty-list-cta-bg: $gray-blue; // Scrollbars -$scrollbarBackground: #3a3a3a; +$scrollbarBackground: #404357; $scrollbarBackground2: #3a3a3a; + $scrollbarBorder: black; // Tables // ------------------------- -$table-bg: transparent; // overall background-color -$table-bg-accent: $dark-3; // for striping -$table-bg-hover: $dark-4; // for hover -$table-border: $dark-3; // table and cell border +$table-bg: transparent; // overall background-color +$table-bg-accent: $dark-3; // for striping +$table-bg-hover: $dark-4; // for hover +$table-border: $dark-3; // table and cell border + +$table-bg-odd: $dark-2; +$table-bg-hover: $dark-3; // Buttons // ------------------------- -$btn-primary-bg: #ff6600; -$btn-primary-bg-hl: #bc3e06; +$btn-primary-bg: #ff6600; +$btn-primary-bg-hl: #bc3e06; -$btn-secondary-bg: $blue-dark; -$btn-secondary-bg-hl: lighten($blue-dark, 5%); +$btn-secondary-bg: $blue-dark; +$btn-secondary-bg-hl: lighten($blue-dark, 5%); -$btn-success-bg: $green; -$btn-success-bg-hl: darken($green, 6%); +$btn-success-bg: $green; +$btn-success-bg-hl: darken($green, 6%); -$btn-warning-bg: $brand-warning; -$btn-warning-bg-hl: lighten($brand-warning, 8%); +$btn-warning-bg: $brand-warning; +$btn-warning-bg-hl: lighten($brand-warning, 8%); -$btn-danger-bg: $red; -$btn-danger-bg-hl: darken($red, 8%); +$btn-danger-bg: $red; +$btn-danger-bg-hl: darken($red, 8%); -$btn-inverse-bg: $dark-3; -$btn-inverse-bg-hl: lighten($dark-3, 4%); -$btn-inverse-text-color: $link-color; +$btn-inverse-bg: $dark-3; +$btn-inverse-bg-hl: lighten($dark-3, 4%); +$btn-inverse-text-color: $link-color; +$btn-inverse-text-shadow: 0px 1px 0 rgba(0, 0, 0, 0.1); -$btn-link-color: $gray-3; +$btn-link-color: $gray-3; -$iconContainerBackground: $black; +$iconContainerBackground: $black; -$btn-divider-left: $dark-4; -$btn-divider-right: $dark-2; +$btn-divider-left: $dark-4; +$btn-divider-right: $dark-2; $btn-drag-image: '../img/grab_dark.svg'; // Forms // ------------------------- -$input-bg: $dark-4; -$input-bg-disabled: $dark-3; +$input-bg: $input-black; +$input-bg-disabled: $dark-3; -$input-color: $gray-4; -$input-border-color: $dark-4; -$input-box-shadow: inset 1px 0px 0.3rem 0px rgba(150, 150, 150, 0.10); -$input-border-focus: $input-border-color !default; -$input-box-shadow-focus: rgba(102,175,233,.6) !default; -$input-color-placeholder: $gray-1 !default; -$input-label-bg: $dark-3; -$input-invalid-border-color: lighten($red, 5%); +$input-color: $gray-4; +$input-border-color: $dark-3; +$input-box-shadow: inset 1px 0px 0.3rem 0px rgba(150, 150, 150, 0.1); +$input-border-focus: $input-border-color; +$input-box-shadow-focus: rgba(102, 175, 233, 0.6); +$input-color-placeholder: $gray-1 !default; +$input-label-bg: $gray-blue; +$input-label-border-color: $dark-3; +$input-invalid-border-color: lighten($red, 5%); // Search -$search-shadow: 0 0 35px 0 $body-bg; +$search-shadow: 0 0 30px 0 $black; +$search-filter-box-bg: $gray-blue; // Dropdowns // ------------------------- -$dropdownBackground: $dark-3; -$dropdownBorder: rgba(0,0,0,.2); -$dropdownDividerTop: transparent; -$dropdownDividerBottom: #444; -$dropdownDivider: $dropdownDividerBottom; -$dropdownTitle: $link-color-disabled; +$dropdownBackground: $dark-3; +$dropdownBorder: rgba(0, 0, 0, 0.2); +$dropdownDividerTop: transparent; +$dropdownDividerBottom: #444; +$dropdownDivider: $dropdownDividerBottom; +$dropdownTitle: $link-color-disabled; -$dropdownLinkColor: $text-color; -$dropdownLinkColorHover: $white; -$dropdownLinkColorActive: $white; +$dropdownLinkColor: $text-color; +$dropdownLinkColorHover: $white; +$dropdownLinkColorActive: $white; -$dropdownLinkBackgroundActive: $dark-4; -$dropdownLinkBackgroundHover: $dark-4; +$dropdownLinkBackgroundActive: $dark-4; +$dropdownLinkBackgroundHover: $dark-4; + +$dropdown-link-color: $gray-3; // COMPONENT VARIABLES // -------------------------------------------------- // ------------------------- -$placeholderText: darken($text-color, 25%); - +$placeholderText: darken($text-color, 25%); // Horizontal forms & lists // ------------------------- -$horizontalComponentOffset: 180px; - +$horizontalComponentOffset: 180px; // Wells // ------------------------- -$wellBackground: #131517; +$wellBackground: #131517; -$navbarHeight: 52px; -$navbarBackgroundHighlight: $dark-3; -$navbarBackground: $dark-3; -$navbarBorder: 1px solid $body-bg; +$navbarHeight: 55px; +$navbarBackgroundHighlight: $dark-3; +$navbarBackground: $panel-bg; +$navbarBorder: 1px solid $dark-3; +$navbarShadow: 0 0 20px black; -$navbarText: $gray-4; -$navbarLinkColor: $gray-4; -$navbarLinkColorHover: $white; -$navbarLinkColorActive: $navbarLinkColorHover; -$navbarLinkBackgroundHover: transparent; -$navbarLinkBackgroundActive: $navbarBackground; -$navbarBrandColor: $link-color; -$navbarDropdownShadow: inset 0px 4px 10px -4px $body-bg; +$navbarText: $gray-4; +$navbarLinkColor: $gray-4; +$navbarLinkColorHover: $white; +$navbarLinkColorActive: $navbarLinkColorHover; +$navbarLinkBackgroundHover: transparent; +$navbarLinkBackgroundActive: $navbarBackground; +$navbarBrandColor: $link-color; +$navbarDropdownShadow: inset 0px 4px 10px -4px $body-bg; -$navbarButtonBackground: lighten($navbarBackground, 3%); -$navbarButtonBackgroundHighlight: lighten($navbarBackground, 5%); +$navbarButtonBackground: $navbarBackground; +$navbarButtonBackgroundHighlight: $body-bg; + +$navbar-button-border: #2f2f32; // Sidemenu // ------------------------- -$side-menu-bg: $body-bg; -$side-menu-item-hover-bg: $dark-3; -$side-menu-opacity: 0.97; +$side-menu-bg: $black; +$side-menu-item-hover-bg: $dark-2; +$side-menu-shadow: 0 0 20px black; +$side-menu-link-color: $link-color; +$breadcrumb-hover-hl: #111; + +// Menu dropdowns +// ------------------------- +$menu-dropdown-bg: $body-bg; +$menu-dropdown-hover-bg: $dark-2; +$menu-dropdown-border-color: $dark-3; +$menu-dropdown-shadow: 5px 5px 20px -5px $black; + +// Breadcrumb +// ------------------------- +$page-nav-bg: $black; +$page-nav-shadow: 5px 5px 20px -5px $black; +$page-nav-breadcrumb-color: $gray-3; + +// Tabs +// ------------------------- +$tab-border-color: $dark-4; // Pagination // ------------------------- -$paginationBackground: $body-bg; -$paginationBorder: transparent; -$paginationActiveBackground: $blue; +$paginationBackground: $body-bg; +$paginationBorder: transparent; +$paginationActiveBackground: $blue; // Form states and alerts // ------------------------- -$warning-text-color: $warn; -$error-text-color: #E84D4D; -$success-text-color: #12D95A; -$info-text-color: $blue-dark; +$warning-text-color: $warn; +$error-text-color: #e84d4d; +$success-text-color: #12d95a; +$info-text-color: $blue-dark; -$alert-error-bg: linear-gradient(90deg, #d44939, #e0603d); -$alert-success-bg: linear-gradient(90deg, #3aa655, #47b274); -$alert-warning-bg: linear-gradient(90deg, #d44939, #e0603d); -$alert-info-bg: linear-gradient(100deg, #1a4552, #00374a); +$alert-error-bg: linear-gradient(90deg, #d44939, #e0603d); +$alert-success-bg: linear-gradient(90deg, #3aa655, #47b274); +$alert-warning-bg: linear-gradient(90deg, #d44939, #e0603d); +$alert-info-bg: linear-gradient(100deg, #1a4552, #00374a); // popover -$popover-bg: $panel-bg; -$popover-color: $text-color; -$popover-border-color: $dark-4; -$popover-shadow: 0 0 20px black; +$popover-bg: $page-bg; +$popover-color: $text-color; +$popover-border-color: $dark-4; +$popover-shadow: 0 0 20px black; -$popover-help-bg: $btn-secondary-bg; -$popover-help-color: $text-color; +$popover-help-bg: $btn-secondary-bg; +$popover-help-color: $text-color; -$popover-error-bg: $btn-danger-bg; +$popover-error-bg: $btn-danger-bg; // Tooltips and popovers // ------------------------- -$tooltipColor: $popover-help-color; -$tooltipBackground: $popover-help-bg; -$tooltipArrowWidth: 5px; -$tooltipArrowColor: $tooltipBackground; -$tooltipLinkColor: $link-color; -$graph-tooltip-bg: $dark-1; +$tooltipColor: $popover-help-color; +$tooltipBackground: $popover-help-bg; +$tooltipArrowWidth: 5px; +$tooltipArrowColor: $tooltipBackground; +$tooltipLinkColor: $link-color; +$graph-tooltip-bg: $dark-1; // images $checkboxImageUrl: '../img/checkbox.png'; -// cards -$card-background: linear-gradient(135deg, #2f2f2f, #262626); -$card-background-hover: linear-gradient(135deg, #343434, #262626); -$card-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .3); - // info box -$info-box-background: linear-gradient(100deg, #1a4552, #00374a); +$info-box-background: linear-gradient(100deg, $blue-dark, darken($blue-dark, 5%)); +$info-box-color: $gray-4; // footer -$footer-link-color: $gray-1; -$footer-link-hover: $gray-4; +$footer-link-color: $gray-2; +$footer-link-hover: $gray-4; // collapse box $collapse-box-body-border: $dark-5; @@ -292,34 +339,34 @@ $json-explorer-default-color: $text-color; $json-explorer-string-color: #23d662; $json-explorer-number-color: $variable; $json-explorer-boolean-color: $variable; -$json-explorer-null-color: #EEC97D; +$json-explorer-null-color: #eec97d; $json-explorer-undefined-color: rgb(239, 143, 190); -$json-explorer-function-color: #FD48CB; +$json-explorer-function-color: #fd48cb; $json-explorer-rotate-time: 100ms; $json-explorer-toggler-opacity: 0.6; -$json-explorer-toggler-color: #45376F; -$json-explorer-bracket-color: #9494FF; -$json-explorer-key-color: #23A0DB; -$json-explorer-url-color: #027BFF; +$json-explorer-toggler-color: #45376f; +$json-explorer-bracket-color: #9494ff; +$json-explorer-key-color: #23a0db; +$json-explorer-url-color: #027bff; // Changelog and diff // ------------------------- -$diff-label-bg: $dark-2; -$diff-label-fg: $white; +$diff-label-bg: $dark-2; +$diff-label-fg: $white; -$diff-group-bg: $dark-4; -$diff-arrow-color: $white; +$diff-group-bg: $dark-4; +$diff-arrow-color: $white; -$diff-json-bg: $dark-4; -$diff-json-fg: $gray-5; +$diff-json-bg: $dark-4; +$diff-json-fg: $gray-5; -$diff-json-added: #457740; -$diff-json-deleted: #a04338; +$diff-json-added: #457740; +$diff-json-deleted: #a04338; -$diff-json-old: #a04338; -$diff-json-new: #457740; +$diff-json-old: #a04338; +$diff-json-new: #457740; -$diff-json-changed-fg: $gray-5; +$diff-json-changed-fg: $gray-5; $diff-json-changed-num: $text-color; -$diff-json-icon: $gray-7; +$diff-json-icon: $gray-7; diff --git a/public/sass/_variables.light.scss b/public/sass/_variables.light.scss index eccebe1debc..eb598f27d4c 100644 --- a/public/sass/_variables.light.scss +++ b/public/sass/_variables.light.scss @@ -2,306 +2,336 @@ // Variables // -------------------------------------------------- - // Global values // -------------------------------------------------- +$theme-name: light; // Grays // ------------------------- -$black: #000; +$black: #000; // ------------------------- -$black: #000; -$dark-1: #141414; -$dark-2: #1f1d1d; -$dark-3: #292929; -$dark-4: #373737; -$dark-5: #444444; -$gray-1: #555555; -$gray-2: #7B7B7B; -$gray-3: #b3b3b3; -$gray-4: #D8D9DA; -$gray-5: #ECECEC; -$gray-6: #f4f5f8; -$gray-7: #fbfbfb; +$black: #000; +$dark-1: #13161d; +$dark-2: #1e2028; +$dark-3: #303133; +$dark-4: #35373f; +$dark-5: #41444b; +$gray-1: #52545c; +$gray-2: #767980; +$gray-3: #acb6bf; +$gray-4: #c7d0d9; +$gray-5: #dde4ed; +$gray-6: #e9edf2; +$gray-7: #f7f8fa; -$white: #fff; +$white: #fff; // Accent colors // ------------------------- -$blue: #2AB2E4; -$blue-dark: #3CAAD6; -$green: #3aa655; -$red: #d44939; -$yellow: #FF851B; -$orange: #Ff7941; -$pink: #E671B8; -$purple: #9954BB; -$variable: #2AB2E4; +$blue: #61c2f2; +$blue-dark: #0083b3; +$green: #3aa655; +$red: #d44939; +$yellow: #ff851b; +$orange: #ff7941; +$pink: #e671b8; +$purple: #9954bb; +$variable: $blue; -$brand-primary: $orange; -$brand-success: $green; -$brand-warning: $orange; -$brand-danger: $red; +$brand-primary: $orange; +$brand-success: $green; +$brand-warning: $orange; +$brand-danger: $red; + +$query-blue: $blue-dark; // Status colors // ------------------------- -$online: #01A64F; -$warn: #F79520; -$critical: #EC2128; +$online: #01a64f; +$warn: #f79520; +$critical: #ec2128; // Scaffolding // ------------------------- -$body-bg: $white; -$page-bg: $white; -$body-color: $gray-1; -$text-color: $gray-1; -$text-color-strong: $white; -$text-color-weak: $gray-3; -$text-color-faint: $gray-4; -$text-color-emphasis: $dark-5; +$body-bg: $gray-7; +$page-bg: $gray-7; +$body-color: $gray-1; +//$text-color: $dark-4; +$text-color: $gray-1; +$text-color-strong: $white; +$text-color-weak: $gray-2; +$text-color-faint: $gray-4; +$text-color-emphasis: $dark-5; $text-shadow-strong: none; $text-shadow-faint: none; +$textShadow: none; // gradients -$brand-gradient: linear-gradient(to right, rgba(255,213,0,1.0) 0%, rgba(255,68,0,1.0) 99%, rgba(255,68,0,1.0) 100%); -$page-gradient: linear-gradient(60deg, transparent 70%, darken($page-bg, 4%) 98%); +$brand-gradient: linear-gradient(to right, rgba(255, 213, 0, 1) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%); +$page-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%); // Links // ------------------------- -$link-color: $gray-1; -$link-color-disabled: lighten($link-color, 30%); -$link-hover-color: darken($link-color, 20%); -$external-link-color: $blue; +$link-color: $gray-1; +$link-color-disabled: lighten($link-color, 30%); +$link-hover-color: darken($link-color, 20%); +$external-link-color: $blue; // Typography // ------------------------- -$headings-color: $text-color; -$abbr-border-color: $gray-2 !default; -$text-muted: $text-color-weak; +$headings-color: $text-color; +$abbr-border-color: $gray-2 !default; +$text-muted: $text-color-weak; -$blockquote-small-color: $gray-2 !default; +$blockquote-small-color: $gray-2 !default; $blockquote-border-color: $gray-3 !default; $hr-border-color: $dark-3 !default; // Components $component-active-color: $white !default; -$component-active-bg: $brand-primary !default; +$component-active-bg: $brand-primary !default; // Panel // ------------------------- -$panel-bg: $gray-7; -$panel-border: solid 1px $gray-6; +$panel-bg: $white; +$panel-border-color: $gray-5; +$panel-border: solid 1px $panel-border-color; $panel-drop-zone-bg: repeating-linear-gradient(-128deg, $body-bg, $body-bg 10px, $gray-6 10px, $gray-6 20px); -$panel-menu-border: solid 1px white; +$panel-header-hover-bg: $gray-6; +$panel-header-menu-hover-bg: $gray-4; +$panel-edit-shadow: 0 0 30px 20px $black; -$divider-border-color: $gray-2; +// Page header +$page-header-bg: linear-gradient(90deg, $white, $gray-7); +$page-header-shadow: inset 0px -3px 10px $gray-6; +$page-header-border-color: $gray-4; + +$divider-border-color: $gray-2; // Graphite Target Editor -$tight-form-border: $gray-4; -$tight-form-bg: $gray-6; +$tight-form-bg: #eaebee; -$tight-form-func-bg: $gray-5; -$tight-form-func-highlight-bg: $gray-6; +$tight-form-func-bg: $gray-5; +$tight-form-func-highlight-bg: $gray-6; -$modal-background: $body-bg; -$code-tag-bg: $gray-6; -$code-tag-border: darken($code-tag-bg, 3%); +$modal-backdrop-bg: $body-bg; +$code-tag-bg: $gray-6; +$code-tag-border: darken($code-tag-bg, 3%); + +// cards +$card-background: linear-gradient(135deg, $gray-6, $gray-5); +$card-background-hover: linear-gradient(135deg, $gray-5, $gray-6); +$card-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1); // Lists -$grafanaListBackground: $gray-6; -$grafanaListAccent: $gray-5; -$grafanaListBorderTop: $gray-3; -$grafanaListBorderBottom: $gray-3; -$grafanaListHighlight: $gray-5; -$grafanaListMainLinkColor: $text-color; - +$list-item-bg: linear-gradient(135deg, $gray-5, $gray-6); //$card-background; +$list-item-hover-bg: darken($gray-5, 5%); +$list-item-link-color: $text-color; +$list-item-shadow: $card-shadow; +$empty-list-cta-bg: $gray-6; // Tables // ------------------------- -$table-bg: transparent; // overall background-color -$table-bg-accent: $gray-5; // for striping -$table-bg-hover: $gray-5; // for hover -$table-bg-active: $table-bg-hover !default; -$table-border: $gray-3; // table and cell border +$table-bg: transparent; // overall background-color +$table-bg-accent: $gray-5; // for striping +$table-bg-hover: $gray-5; // for hover +$table-bg-active: $table-bg-hover !default; +$table-border: $gray-3; // table and cell border + +$table-bg-odd: $gray-6; +$table-bg-hover: $gray-5; // Scrollbars -$scrollbarBackground: $gray-5; -$scrollbarBackground2: $gray-5; -$scrollbarBorder: $gray-4; +$scrollbarBackground: $gray-5; +$scrollbarBackground2: $gray-5; +$scrollbarBorder: $gray-4; // Buttons // ------------------------- -$btn-primary-bg: $brand-primary; -$btn-primary-bg-hl: lighten($brand-primary, 8%); +$btn-primary-bg: $brand-primary; +$btn-primary-bg-hl: lighten($brand-primary, 8%); -$btn-secondary-bg: $blue-dark; -$btn-secondary-bg-hl: lighten($blue-dark, 4%); +$btn-secondary-bg: $blue-dark; +$btn-secondary-bg-hl: lighten($blue-dark, 4%); -$btn-success-bg: lighten($green, 3%); -$btn-success-bg-hl: darken($green, 3%); +$btn-success-bg: lighten($green, 3%); +$btn-success-bg-hl: darken($green, 3%); -$btn-warning-bg: lighten($orange, 3%); -$btn-warning-bg-hl: darken($orange, 3%); +$btn-warning-bg: lighten($orange, 3%); +$btn-warning-bg-hl: darken($orange, 3%); -$btn-danger-bg: lighten($red, 3%); -$btn-danger-bg-hl: darken($red, 3%); +$btn-danger-bg: lighten($red, 3%); +$btn-danger-bg-hl: darken($red, 3%); -$btn-inverse-bg: $gray-5; -$btn-inverse-bg-hl: darken($gray-5, 5%); -$btn-inverse-text-color: $dark-4; +$btn-inverse-bg: $gray-6; +$btn-inverse-bg-hl: darken($gray-6, 5%); +$btn-inverse-text-color: $gray-1; +$btn-inverse-text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4); $btn-link-color: $gray-1; -$btn-divider-left: $gray-4; -$btn-divider-right: $gray-7; -$btn-drag-image: '../img/grab_light.svg'; +$btn-divider-left: $gray-4; +$btn-divider-right: $gray-7; +$btn-drag-image: '../img/grab_light.svg'; $iconContainerBackground: $white; // Forms // ------------------------- -$input-bg: $gray-7; -$input-bg-disabled: $gray-5; +$input-bg: $white; +$input-bg-disabled: $gray-5; -$input-color: $dark-3; -$input-border-color: $gray-5; -$input-box-shadow: none; -$input-border-focus: $blue !default; -$input-box-shadow-focus: $blue !default; -$input-color-placeholder: $gray-4 !default; -$input-label-bg: $gray-6; -$input-invalid-border-color: lighten($red, 5%); +$input-color: $dark-3; +$input-border-color: $gray-5; +$input-box-shadow: none; +$input-border-focus: $blue !default; +$input-box-shadow-focus: $blue !default; +$input-color-placeholder: $gray-4 !default; +$input-label-bg: $gray-5; +$input-label-border-color: $gray-5; +$input-invalid-border-color: lighten($red, 5%); // Sidemenu // ------------------------- -$side-menu-bg: $body-bg; -$side-menu-item-hover-bg: $gray-6; -$side-menu-opacity: 0.97; +$side-menu-bg: $dark-2; +$side-menu-item-hover-bg: $gray-1; +$side-menu-shadow: 5px 0px 10px -5px $gray-1; +$side-menu-link-color: $gray-6; + +// Menu dropdowns +// ------------------------- +$menu-dropdown-bg: $gray-7; +$menu-dropdown-hover-bg: $gray-6; +$menu-dropdown-border-color: $gray-4; +$menu-dropdown-shadow: 5px 5px 10px -5px $gray-1; + +// Breadcrumb +// ------------------------- +$page-nav-bg: $gray-5; +$page-nav-shadow: 5px 5px 20px -5px $gray-4; +$page-nav-breadcrumb-color: $black; +$breadcrumb-hover-hl: #d9dadd; + +// Tabs +// ------------------------- +$tab-border-color: $gray-5; // search -$search-shadow: 0 5px 30px 0 lighten($gray-2, 30%); +$search-shadow: 0 5px 30px 0 $gray-4; +$search-filter-box-bg: $gray-7; // Dropdowns // ------------------------- -$dropdownBackground: $white; -$dropdownBorder: $tight-form-border; -$dropdownDividerTop: $gray-6; -$dropdownDividerBottom: $white; -$dropdownDivider: $dropdownDividerTop; -$dropdownTitle: $gray-3; +$dropdownBackground: $white; +$dropdownBorder: $gray-4; +$dropdownDividerTop: $gray-6; +$dropdownDividerBottom: $white; +$dropdownDivider: $dropdownDividerTop; +$dropdownTitle: $gray-3; -$dropdownLinkColor: $dark-3; -$dropdownLinkColorHover: $link-color; -$dropdownLinkColorActive: $link-color; - -$dropdownLinkBackgroundActive: $gray-6; -$dropdownLinkBackgroundHover: $gray-6; +$dropdownLinkColor: $dark-3; +$dropdownLinkColorHover: $link-color; +$dropdownLinkColorActive: $link-color; +$dropdownLinkBackgroundActive: $gray-6; +$dropdownLinkBackgroundHover: $gray-6; // COMPONENT VARIABLES // -------------------------------------------------- - // Input placeholder text color // ------------------------- -$placeholderText: $gray-2; - +$placeholderText: $gray-2; // Hr border color // ------------------------- -$hrBorder: $gray-3; - +$hrBorder: $gray-3; // Horizontal forms & lists // ------------------------- -$horizontalComponentOffset: 180px; - +$horizontalComponentOffset: 180px; // Wells // ------------------------- -$wellBackground: $gray-3; - +$wellBackground: $gray-3; // Navbar // ------------------------- -$navbarHeight: 52px; -$navbarBackgroundHighlight: #f8f8f8; -$navbarBackground: #f8f8f8; -$navbarBorder: 1px solid $tight-form-border; +$navbarHeight: 52px; +$navbarBackgroundHighlight: $white; +$navbarBackground: $white; +$navbarBorder: 1px solid $gray-4; +$navbarShadow: 0 0 3px #c1c1c1; -$navbarText: #666; -$navbarLinkColor: #666; -$navbarLinkColorHover: #333; -$navbarLinkColorActive: #555; -$navbarLinkBackgroundHover: transparent; -$navbarLinkBackgroundActive: darken($navbarBackground, 6.5%); -$navbarDropdownShadow: inset 0px 4px 7px -4px darken($body-bg, 20%); +$navbarText: #444; +$navbarLinkColor: #444; +$navbarLinkColorHover: #000; +$navbarLinkColorActive: #333; +$navbarLinkBackgroundHover: transparent; +$navbarLinkBackgroundActive: darken($navbarBackground, 6.5%); +$navbarDropdownShadow: inset 0px 4px 7px -4px darken($body-bg, 20%); -$navbarBrandColor: $navbarLinkColor; +$navbarBrandColor: $navbarLinkColor; -$navbarButtonBackground: lighten($navbarBackground, 3%); +$navbarButtonBackground: lighten($navbarBackground, 3%); $navbarButtonBackgroundHighlight: lighten($navbarBackground, 5%); +$navbar-button-border: $gray-4; // Pagination // ------------------------- -$paginationBackground: $gray-2; -$paginationBorder: transparent; -$paginationActiveBackground: $blue; - +$paginationBackground: $gray-2; +$paginationBorder: transparent; +$paginationActiveBackground: $blue; // Form states and alerts // ------------------------- -$warning-text-color: lighten($orange, 10%); -$error-text-color: lighten($red, 10%); -$success-text-color: lighten($green, 10%); -$info-text-color: $blue; +$warning-text-color: lighten($orange, 10%); +$error-text-color: lighten($red, 10%); +$success-text-color: lighten($green, 10%); +$info-text-color: $blue; -$alert-error-bg: linear-gradient(90deg, #d44939, #e0603d); -$alert-success-bg: linear-gradient(90deg, #3aa655, #47b274); -$alert-warning-bg: linear-gradient(90deg, #d44939, #e0603d); -$alert-info-bg: $blue-dark; +$alert-error-bg: linear-gradient(90deg, #d44939, #e04d3d); +$alert-success-bg: linear-gradient(90deg, #3aa655, #47b274); +$alert-warning-bg: linear-gradient(90deg, #d44939, #e04d3d); +$alert-info-bg: $blue-dark; // popover -$popover-bg: $panel-bg; -$popover-color: $text-color; -$popover-border-color: $gray-5; -$popover-shadow: 0 0 20px $white; +$popover-bg: $page-bg; +$popover-color: $text-color; +$popover-border-color: $gray-5; +$popover-shadow: 0 0 20px $white; -$popover-help-bg: $blue-dark; -$popover-help-color: $gray-6; -$popover-error-bg: $btn-danger-bg; +$popover-help-bg: $blue-dark; +$popover-help-color: $gray-6; +$popover-error-bg: $btn-danger-bg; // Tooltips and popovers // ------------------------- -$tooltipColor: $popover-help-color; -$tooltipBackground: $popover-help-bg; -$tooltipArrowWidth: 5px; -$tooltipArrowColor: $tooltipBackground; -$tooltipLinkColor: lighten($popover-help-color, 5%); -$graph-tooltip-bg: $gray-5; +$tooltipColor: $popover-help-color; +$tooltipBackground: $popover-help-bg; +$tooltipArrowWidth: 5px; +$tooltipArrowColor: $tooltipBackground; +$tooltipLinkColor: lighten($popover-help-color, 5%); +$graph-tooltip-bg: $gray-5; // images $checkboxImageUrl: '../img/checkbox_white.png'; -// cards -$card-background: linear-gradient(135deg, $gray-5, $gray-6); -$card-background-hover: linear-gradient(135deg, $gray-6, $gray-7); -$card-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, .1), 1px 1px 0 0 rgba(0, 0, 0, .1); - // info box -$info-box-background: linear-gradient(135deg, #f1fbff, #d7ebff); +$info-box-background: linear-gradient(100deg, $blue-dark, darken($blue-dark, 5%)); +$info-box-color: $gray-7; // footer -$footer-link-color: $gray-3; -$footer-link-hover: $dark-5; +$footer-link-color: $gray-3; +$footer-link-hover: $dark-5; // collapse box $collapse-box-body-border: $gray-4; @@ -312,36 +342,36 @@ $json-explorer-default-color: black; $json-explorer-string-color: green; $json-explorer-number-color: blue; $json-explorer-boolean-color: red; -$json-explorer-null-color: #855A00; +$json-explorer-null-color: #855a00; $json-explorer-undefined-color: rgb(202, 11, 105); -$json-explorer-function-color: #FF20ED; +$json-explorer-function-color: #ff20ed; $json-explorer-rotate-time: 100ms; $json-explorer-toggler-opacity: 0.6; -$json-explorer-toggler-color: #45376F; +$json-explorer-toggler-color: #45376f; $json-explorer-bracket-color: blue; -$json-explorer-key-color: #00008B; +$json-explorer-key-color: #00008b; $json-explorer-url-color: blue; // Changelog and diff // ------------------------- -$diff-label-bg: $gray-5; -$diff-label-fg: $gray-2; +$diff-label-bg: $gray-5; +$diff-label-fg: $gray-2; -$diff-switch-bg: $gray-7; -$diff-switch-disabled: $gray-5; +$diff-switch-bg: $gray-7; +$diff-switch-disabled: $gray-5; -$diff-arrow-color: $dark-3; -$diff-group-bg: $gray-7; +$diff-arrow-color: $dark-3; +$diff-group-bg: $gray-7; -$diff-json-bg: $gray-5; -$diff-json-fg: $gray-2; +$diff-json-bg: $gray-5; +$diff-json-fg: $gray-2; -$diff-json-added: lighten(desaturate($green, 30%), 10%); -$diff-json-deleted: desaturate($red, 35%); +$diff-json-added: lighten(desaturate($green, 30%), 10%); +$diff-json-deleted: desaturate($red, 35%); -$diff-json-old: #5a372a; -$diff-json-new: #664e33; +$diff-json-old: #5a372a; +$diff-json-new: #664e33; -$diff-json-changed-fg: $gray-6; +$diff-json-changed-fg: $gray-6; $diff-json-changed-num: $gray-4; -$diff-json-icon: $gray-4; +$diff-json-icon: $gray-4; diff --git a/public/sass/_variables.scss b/public/sass/_variables.scss index 186b22f2390..f46cacb0dd1 100644 --- a/public/sass/_variables.scss +++ b/public/sass/_variables.scss @@ -1,105 +1,79 @@ - - // Options // // Quickly modify global styling by enabling or disabling optional features. -$enable-flex: true !default; -$enable-rounded: true !default; -$enable-shadows: false !default; -$enable-gradients: false !default; -$enable-transitions: false !default; -$enable-hover-media-query: false !default; -$enable-grid-classes: true !default; -$enable-print-styles: true !default; - +$enable-flex: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: false !default; +$enable-hover-media-query: false !default; +$enable-grid-classes: true !default; +$enable-print-styles: true !default; // Spacing // // Control the default styling of most Bootstrap elements by modifying these // variables. Mostly focused on spacing. -$spacer: 1rem !default; +$spacer: 1rem !default; $spacer-x: $spacer !default; $spacer-y: $spacer !default; $spacers: ( - 0: ( - x: 0, - y: 0 - ), - 1: ( - x: $spacer-x, - y: $spacer-y - ), - 2: ( - x: ($spacer-x * 1.5), - y: ($spacer-y * 1.5) - ), - 3: ( - x: ($spacer-x * 3), - y: ($spacer-y * 3) + 0: (x: 0, y: 0), + 1: (x: $spacer-x, y: $spacer-y), + 2: (x: ($spacer-x * 1.5), y: ($spacer-y * 1.5)), + 3: (x: ($spacer-x * 3), y: ($spacer-y * 3)) ) -) !default; + !default; $border-width: 1px !default; - // Grid breakpoints // // Define the minimum and maximum dimensions at which your layout will change, // adapting to different screen sizes, for use in media queries. -$grid-breakpoints: ( - xs: 0, - sm: 544px, - md: 768px, - lg: 992px, - xl: 1200px -) !default; - +$grid-breakpoints: (xs: 0, sm: 544px, md: 768px, lg: 992px, xl: 1200px) !default; // Grid containers // // Define the maximum width of `.container` for different screen sizes. -$container-max-widths: ( - sm: 576px, - md: 720px, - lg: 940px, - xl: 1140px -) !default; +$container-max-widths: (sm: 576px, md: 720px, lg: 940px, xl: 1080px) !default; // Grid columns // // Set the number of columns and specify the width of the gutters. -$grid-columns: 12 !default; +$grid-columns: 12 !default; $grid-gutter-width: 30px !default; -$enable-flex: false; +$enable-flex: true; // Typography // ------------------------- -$font-family-sans-serif: "Open Sans", Helvetica, Arial, sans-serif; -$font-family-serif: Georgia, "Times New Roman", Times, serif; -$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace; -$font-family-base: $font-family-sans-serif !default; +$font-family-sans-serif: "Roboto", Helvetica, Arial, sans-serif; +$font-family-serif: Georgia, "Times New Roman", Times, serif; +$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace; +$font-family-base: $font-family-sans-serif !default; $font-size-root: 14px !default; +$font-size-base: 13px !default; -$font-size-base: 1rem !default; -$font-size-lg: 1.25rem !default; -$font-size-sm: .875rem !default; -$font-size-xs: .75rem !default; +$font-size-lg: 18px !default; +$font-size-md: 14px !default; +$font-size-sm: 12px !default; +$font-size-xs: 10px !default; $line-height-base: 1.5 !default; -$font-weight-semi-bold: 600; +$font-weight-semi-bold: 500; -$font-size-h1: 2.0rem !default; +$font-size-h1: 2rem !default; $font-size-h2: 1.75rem !default; -$font-size-h3: 1.50rem !default; -$font-size-h4: 1.30rem !default; -$font-size-h5: 1.20rem !default; +$font-size-h3: 1.5rem !default; +$font-size-h4: 1.3rem !default; +$font-size-h5: 1.2rem !default; $font-size-h6: 1rem !default; $display1-size: 6rem !default; @@ -112,16 +86,16 @@ $display2-weight: 400 !default; $display3-weight: 400 !default; $display4-weight: 400 !default; -$lead-font-size: 1.25rem !default; +$lead-font-size: 1.25rem !default; $lead-font-weight: 300 !default; $headings-margin-bottom: ($spacer / 2) !default; -$headings-font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -$headings-font-weight: 400 !default; -$headings-line-height: 1.1 !default; +$headings-font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; +$headings-font-weight: 400 !default; +$headings-line-height: 1.1 !default; -$blockquote-font-size: ($font-size-base * 1.25) !default; -$blockquote-border-width: .25rem !default; +$blockquote-font-size: ($font-size-base * 1.25) !default; +$blockquote-border-width: 0.25rem !default; $hr-border-width: $border-width !default; $dt-font-weight: bold !default; @@ -131,15 +105,15 @@ $list-inline-padding: 5px !default; // // Define common padding and border radius sizes and more. -$line-height-lg: (4 / 3) !default; -$line-height-sm: 1.5 !default; +$line-height-lg: (4 / 3) !default; +$line-height-sm: 1.5 !default; -$border-radius: 0.2rem !default; -$border-radius-lg: 0.3rem !default; -$border-radius-sm: 0.1rem !default; +$border-radius: 3px !default; +$border-radius-lg: 5px !default; +$border-radius-sm: 2px!default; -$caret-width: .3em !default; -$caret-width-lg: $caret-width !default; +$caret-width: 0.3em !default; +$caret-width-lg: $caret-width !default; // Page @@ -148,85 +122,108 @@ $page-sidebar-margin: 4rem; // Links // ------------------------- -$link-decoration: none !default; -$link-hover-decoration: none !default; +$link-decoration: none !default; +$link-hover-decoration: none !default; // Tables // // Customizes the `.table` component with basic values, each used across all table variations. -$table-cell-padding: .75rem !default; -$table-sm-cell-padding: .3rem !default; +$table-cell-padding: 4px 10px !default; +$table-sm-cell-padding: 0.3rem !default; // Forms -$input-padding-x: .75rem !default; -$input-padding-y: .6rem !default; -$input-line-height: 1.35rem !default; +$input-padding-x: 10px !default; +$input-padding-y: 8px !default; +$input-line-height: 18px !default; -$input-btn-border-width: 1px; -$input-border-radius: 0 $border-radius $border-radius 0 !default; -$input-border-radius-lg: 0 $border-radius-lg $border-radius-lg 0 !default; -$input-border-radius-sm: 0 $border-radius-sm $border-radius-sm 0 !default; +$input-btn-border-width: 1px; +$input-border-radius: 0 $border-radius $border-radius 0 !default; +$input-border-radius-lg: 0 $border-radius-lg $border-radius-lg 0 !default; +$input-border-radius-sm: 0 $border-radius-sm $border-radius-sm 0 !default; -$label-border-radius: $border-radius 0 0 $border-radius !default; -$label-border-radius-lg: $border-radius-lg 0 0 $border-radius-lg !default; -$label-border-radius-sm: $border-radius-sm 0 0 $border-radius-sm !default; +$label-border-radius: $border-radius 0 0 $border-radius !default; +$label-border-radius-lg: $border-radius-lg 0 0 $border-radius-lg !default; +$label-border-radius-sm: $border-radius-sm 0 0 $border-radius-sm !default; -$input-padding-x-sm: .5rem !default; -$input-padding-y-sm: .25rem !default; +$input-padding-x-sm: 7px !default; +$input-padding-y-sm: 4px !default; -$input-padding-x-lg: 1.5rem !default; -$input-padding-y-lg: .75rem !default; +$input-padding-x-lg: 20px !default; +$input-padding-y-lg: 10px !default; -$input-height: (($font-size-base * $line-height-base) + ($input-padding-y * 2)) !default; -$input-height-lg: (($font-size-lg * $line-height-lg) + ($input-padding-y-lg * 2)) !default; -$input-height-sm: (($font-size-sm * $line-height-sm) + ($input-padding-y-sm * 2)) !default; +$input-height: (($font-size-base * $line-height-base) + ($input-padding-y * 2)) + !default; +$input-height-lg: ( + ($font-size-lg * $line-height-lg) + ($input-padding-y-lg * 2) + ) + !default; +$input-height-sm: ( + ($font-size-sm * $line-height-sm) + ($input-padding-y-sm * 2) + ) + !default; -$form-group-margin-bottom: $spacer-y !default; +$form-group-margin-bottom: $spacer-y !default; $gf-form-margin: 0.2rem; -$cursor-disabled: not-allowed !default; +$cursor-disabled: not-allowed !default; // Form validation icons -$form-icon-success: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%235cb85c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E") !default; -$form-icon-warning: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23f0ad4e' d='M4.4 5.324h-.8v-2.46h.8zm0 1.42h-.8V5.89h.8zM3.76.63L.04 7.075c-.115.2.016.425.26.426h7.397c.242 0 .372-.226.258-.426C6.726 4.924 5.47 2.79 4.253.63c-.113-.174-.39-.174-.494 0z'/%3E%3C/svg%3E") !default; -$form-icon-danger: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E") !default; +$form-icon-success: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%235cb85c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E") + !default; +$form-icon-warning: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23f0ad4e' d='M4.4 5.324h-.8v-2.46h.8zm0 1.42h-.8V5.89h.8zM3.76.63L.04 7.075c-.115.2.016.425.26.426h7.397c.242 0 .372-.226.258-.426C6.726 4.924 5.47 2.79 4.253.63c-.113-.174-.39-.174-.494 0z'/%3E%3C/svg%3E") + !default; +$form-icon-danger: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E") + !default; // Z-index master list // ------------------------- // Used for a bird's eye view of components dependent on the z-axis // Try to avoid customizing these :) -$zindex-dropdown: 1000; -$zindex-tooltip: 1020; -$zindex-navbar-fixed: 1030; -$zindex-modal-backdrop: 1040; -$zindex-modal: 1050; +$zindex-dropdown: 1000; +$zindex-navbar-fixed: 1020; +$zindex-sidemenu: 1025; +$zindex-tooltip: 1030; +$zindex-modal-backdrop: 1040; +$zindex-modal: 1050; +$zindex-typeahead: 1060; // Buttons // -$btn-padding-x: 1rem !default; -$btn-padding-y: .6rem !default; -$btn-line-height: 1.25 !default; -$btn-font-weight: normal !default; +$btn-padding-x: 1rem !default; +$btn-padding-y: 0.7rem !default; +$btn-line-height: 1 !default; +$btn-font-weight: 500 !default; -$btn-padding-x-sm: .5rem !default; -$btn-padding-y-sm: .25rem !default; +$btn-padding-x-sm: 0.5rem !default; +$btn-padding-y-sm: 0.25rem !default; -$btn-padding-x-lg: 1.5rem !default; -$btn-padding-y-lg: .75rem !default; +$btn-padding-x-lg: 21px !default; +$btn-padding-y-lg: 11px !default; -$btn-border-radius: 2px; +$btn-padding-x-xl: 21px !default; +$btn-padding-y-xl: 11px !default; + +$btn-border-radius: 2px; + +$btn-semi-transparent: rgba(0, 0, 0, 0.2) !default; // sidemenu -$side-menu-width: 14rem; +$side-menu-width: 60px; // dashboard -$panel-margin: 0.4rem; -$dashboard-padding: ($panel-margin * 2) $panel-margin $panel-margin $panel-margin; +$panel-margin: 10px; +$dashboard-padding: $panel-margin * 2; +$panel-padding: 0px 10px 5px 10px; // tabs -$tabs-padding-top: 0.6rem; -$tabs-padding-bottom: 0.4rem; -$tabs-top-margin: 0.5rem; +$tabs-padding: 10px 15px 9px; +$external-services: ( + github: (bgColor: #464646, borderColor: #393939, icon: ""), + google: (bgColor: #e84d3c, borderColor: #b83e31, icon: ""), + grafanacom: (bgColor: inherit, borderColor: #393939, icon: ""), + oauth: (bgColor: inherit, borderColor: #393939, icon: "") + ) + !default; diff --git a/public/sass/base/_code.scss b/public/sass/base/_code.scss index a97f04bc84b..f3584285108 100644 --- a/public/sass/base/_code.scss +++ b/public/sass/base/_code.scss @@ -2,7 +2,6 @@ // Code (inline and blocK) // -------------------------------------------------- - // Inline and block code styles code, pre { diff --git a/public/sass/base/_fonts.scss b/public/sass/base/_fonts.scss index fb360ba5870..558381e169a 100644 --- a/public/sass/base/_fonts.scss +++ b/public/sass/base/_fonts.scss @@ -1,285 +1,254 @@ -@import "base/font_awesome"; -@import "base/grafana_icons"; - -/* Open sans fonts*/ +@import 'font_awesome'; +@import 'grafana_icons'; /* cyrillic-ext */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTa-j2U0lmluP9RWlSytm3ho.woff2) format('woff2'); - unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/roboto/ek4gzZ-GeXAPcSbHtCeQI_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F; } /* cyrillic */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTZX5f-9o1vgP2EXwfjgl7AY.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/roboto/mErvLBYg_cXG3rLvUsKT_fesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTRWV49_lSm1NYrwo-zkhivY.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/roboto/-2n2p-_Y08sg57CNWQfKNvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+1f00-1fff; } /* greek */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTaaRobkAwv3vxw3jMhVENGA.woff2) format('woff2'); - unicode-range: U+0370-03FF; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/roboto/u0TOpm082MNkS5K0Q4rhqvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+0370-03ff; } /* vietnamese */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTf8zf_FOSsgRmwsS7Aa9k2w.woff2) format('woff2'); - unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/roboto/NdF9MtnOpLzo-noMoG0miPesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab; } /* latin-ext */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTT0LW-43aMEzIO6XUTLjad8.woff2) format('woff2'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url(../fonts/roboto/Fcx7Wwv8OzT71A3E1XOAjvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/opensans/DXI1ORHCpsQm3Vp6mXoaTegdm0LZdjqr5-oayXSOefg.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/CWB0XYA8bzo0kSThX0UTuA.woff2) format('woff2'); + unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215; } /* cyrillic-ext */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/K88pR3goAWT7BTt32Z01mxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); - unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/ZLqKeelYbATG60EpZBSDyxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); + unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F; } /* cyrillic */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/oHi30kwQWvpCWqAhzHcCSBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); + unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/LWCjsQkB6EMdfHrEVqA1KRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/rGvHdJnr2l75qb0YND9NyBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); + unicode-range: U+1f00-1fff; } /* greek */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/xozscpT2726on7jbcb_pAhJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); - unicode-range: U+0370-03FF; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/mx9Uck6uB63VIKFYnEMXrRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); + unicode-range: U+0370-03ff; } /* vietnamese */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/59ZRklaO5bWGqF5A9baEERJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); - unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/mbmhprMH69Zi6eEPBYVFhRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); + unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab; } /* latin-ext */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/u-WUoqrET9fUeobQW7jkRRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/oOeFwZNlrTefzLYmlVV1UBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2'); + unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(../fonts/opensans/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url(../fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2) format('woff2'); + unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215; } /* cyrillic-ext */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNSq-j2U0lmluP9RWlSytm3ho.woff2) format('woff2'); - unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/WxrXJa0C3KdtC7lMafG4dRTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); + unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F; } /* cyrillic */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/OpXUqTo0UgQQhGj_SFdLWBTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); + unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNShWV49_lSm1NYrwo-zkhivY.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/1hZf02POANh32k2VkgEoUBTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); + unicode-range: U+1f00-1fff; } /* greek */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNSqaRobkAwv3vxw3jMhVENGA.woff2) format('woff2'); - unicode-range: U+0370-03FF; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/cDKhRaXnQTOVbaoxwdOr9xTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); + unicode-range: U+0370-03ff; } /* vietnamese */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNSv8zf_FOSsgRmwsS7Aa9k2w.woff2) format('woff2'); - unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/K23cxWVTrIFD6DJsEVi07RTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); + unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab; } /* latin-ext */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNSj0LW-43aMEzIO6XUTLjad8.woff2) format('woff2'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/vSzulfKSK0LLjjfeaxcREhTbgVql8nDJpwnrE27mub0.woff2) format('woff2'); + unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(../fonts/opensans/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; + font-family: 'Roboto'; + font-style: italic; + font-weight: 400; + src: local('Roboto Italic'), local('Roboto-Italic'), + url(../fonts/roboto/vPcynSL0qHq_6dX7lKVByfesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'); + unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215; } /* cyrillic-ext */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzK-j2U0lmluP9RWlSytm3ho.woff2) format('woff2'); - unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; + font-family: 'Roboto'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0TTOQ_MqJVwkKsUn0wKzc2I.woff2) format('woff2'); + unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F; } /* cyrillic */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzJX5f-9o1vgP2EXwfjgl7AY.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; + font-family: 'Roboto'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0TUj_cnvWIuuBMVgbX098Mw.woff2) format('woff2'); + unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116; } /* greek-ext */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzBWV49_lSm1NYrwo-zkhivY.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; + font-family: 'Roboto'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0UbcKLIaa1LC45dFaAfauRA.woff2) format('woff2'); + unicode-range: U+1f00-1fff; } /* greek */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzKaRobkAwv3vxw3jMhVENGA.woff2) format('woff2'); - unicode-range: U+0370-03FF; + font-family: 'Roboto'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0Wo_sUJ8uO4YLWRInS22T3Y.woff2) format('woff2'); + unicode-range: U+0370-03ff; } /* vietnamese */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzP8zf_FOSsgRmwsS7Aa9k2w.woff2) format('woff2'); - unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB; + font-family: 'Roboto'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0b6up8jxqWt8HVA3mDhkV_0.woff2) format('woff2'); + unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab; } /* latin-ext */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzD0LW-43aMEzIO6XUTLjad8.woff2) format('woff2'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; + font-family: 'Roboto'; + font-style: italic; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0SYE0-AqJ3nfInTTiDXDjU4.woff2) format('woff2'); + unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF; } /* latin */ @font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/opensans/k3k702ZOKiLJc3WVjuplzOgdm0LZdjqr5-oayXSOefg.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; -} -/* cyrillic-ext */ -@font-face { - font-family: 'Open Sans'; + font-family: 'Roboto'; font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBjTOQ_MqJVwkKsUn0wKzc2I.woff2) format('woff2'); - unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; -} -/* cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBjUj_cnvWIuuBMVgbX098Mw.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* greek-ext */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBkbcKLIaa1LC45dFaAfauRA.woff2) format('woff2'); - unicode-range: U+1F00-1FFF; -} -/* greek */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBmo_sUJ8uO4YLWRInS22T3Y.woff2) format('woff2'); - unicode-range: U+0370-03FF; -} -/* vietnamese */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBr6up8jxqWt8HVA3mDhkV_0.woff2) format('woff2'); - unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBiYE0-AqJ3nfInTTiDXDjU4.woff2) format('woff2'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/opensans/xjAJXh38I15wypJXxuGMBo4P5ICox8Kq3LLUNMylGO4.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; + font-weight: 500; + src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'), + url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0Y4P5ICox8Kq3LLUNMylGO4.woff2) format('woff2'); + unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215; } diff --git a/public/sass/base/_forms.scss b/public/sass/base/_forms.scss index 3c74c7d81ef..3197eb57991 100644 --- a/public/sass/base/_forms.scss +++ b/public/sass/base/_forms.scss @@ -2,7 +2,6 @@ // Forms // -------------------------------------------------- - // GENERAL STYLES // -------------- @@ -20,7 +19,7 @@ legend { // Small small { - font-size: $line-height-base * .75; + font-size: $line-height-base * 0.75; color: $gray-2; } } @@ -100,11 +99,11 @@ input[type="checkbox"]:focus { // not a big fan of number fields input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; + -webkit-appearance: none; + margin: 0; } input[type="number"] { - -moz-appearance: textfield; + -moz-appearance: textfield; } // Placeholder // ------------------------- @@ -119,12 +118,24 @@ textarea { // ----------- // General classes for quick sizes -.input-mini { width: 60px; } -.input-small { width: 90px; } -.input-medium { width: 150px; } -.input-large { width: 210px; } -.input-xlarge { width: 270px; } -.input-xxlarge { width: 530px; } +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} // GRID SIZING FOR INPUTS // ---------------------- @@ -152,7 +163,7 @@ input[type="checkbox"][readonly] { background-color: transparent; } -input[type=text].input-fluid { +input[type="text"].input-fluid { width: 100%; box-sizing: border-box; padding: 10px; @@ -180,10 +191,10 @@ label.cr1 { padding: 0 0 0 20px; vertical-align: top; background: url($checkboxImageUrl) left top no-repeat; - cursor:pointer; + cursor: pointer; } -input[type="checkbox"].cr1:checked+label { +input[type="checkbox"].cr1:checked + label { background: url($checkboxImageUrl) 0px -18px no-repeat; } @@ -192,7 +203,7 @@ input[type="checkbox"].cr1:checked+label { display: block; overflow: hidden; padding-right: 10px; - input[type=text] { + input[type="text"] { width: 100%; padding: 5px 6px; height: 100%; diff --git a/public/sass/base/_grafana_icons.scss b/public/sass/base/_grafana_icons.scss index 42834e704b3..55e57f6d087 100644 --- a/public/sass/base/_grafana_icons.scss +++ b/public/sass/base/_grafana_icons.scss @@ -1,194 +1,201 @@ @font-face { - font-family: 'grafana-icons'; - src: url('../fonts/grafana-icons.eot?okx5td'); - src: url('../fonts/grafana-icons.eot?okx5td#iefix') format('embedded-opentype'), - url('../fonts/grafana-icons.ttf?okx5td') format('truetype'), - url('../fonts/grafana-icons.woff?okx5td') format('woff'), - url('../fonts/grafana-icons.svg?okx5td#grafana-icons') format('svg'); - font-weight: normal; - font-style: normal; + font-family: "grafana-icons"; + src: url("../fonts/grafana-icons.eot?okx5td"); + src: url("../fonts/grafana-icons.eot?okx5td#iefix") + format("embedded-opentype"), + url("../fonts/grafana-icons.ttf?okx5td") format("truetype"), + url("../fonts/grafana-icons.woff?okx5td") format("woff"), + url("../fonts/grafana-icons.svg?okx5td#grafana-icons") format("svg"); + font-weight: normal; + font-style: normal; } .icon-gf { - /* use !important to prevent issues with browser extensions that change fonts */ - font-family: 'grafana-icons' !important; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: "grafana-icons" !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + display: inline-block; + vertical-align: middle; - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-gf-fw { + width: 1.2857142857em; + text-align: center; } .inline-icon-gf { - vertical-align: middle; + vertical-align: middle; } .icon-gf-raintank_wordmark:before { - content: "\e600"; + content: "\e600"; } .micon-gf-raintank_icn:before { - content: "\e601"; + content: "\e601"; } .icon-gf-raintank_r-icn:before { - content: "\e905"; + content: "\e905"; } .icon-gf-check-alt:before { - content: "\e603"; + content: "\e603"; } .icon-gf-check:before { - content: "\e604"; + content: "\e604"; } .icon-gf-collector:before { - content: "\e605"; + content: "\e605"; } .icon-gf-dashboard:before { - content: "\e606"; + content: "\e606"; } .icon-gf-panel:before { - content: "\e904"; + content: "\e904"; } .icon-gf-datasources:before { - content: "\e607"; + content: "\e607"; } .icon-gf-endpoint-tiny:before { - content: "\e608"; + content: "\e608"; } .icon-gf-endpoint:before { - content: "\e609"; + content: "\e609"; } .icon-gf-page:before { - content: "\e908"; + content: "\e908"; } .icon-gf-filter:before { - content: "\e60a"; + content: "\e60a"; } .icon-gf-status:before { - content: "\e60b"; + content: "\e60b"; } .icon-gf-monitoring:before { - content: "\e60c"; + content: "\e60c"; } .icon-gf-monitoring-tiny:before { - content: "\e620"; + content: "\e620"; } .icon-gf-jump-to-dashboard:before { - content: "\e60d"; + content: "\e60d"; } .icon-gf-warn, .icon-gf-warning:before { - content: "\e60e"; + content: "\e60e"; } .icon-gf-nodata:before { - content: "\e60f"; + content: "\e60f"; } .icon-gf-critical:before { - content: "\e610"; + content: "\e610"; } .icon-gf-crit:before { content: "\e610"; } .icon-gf-online:before { - content: "\e611"; + content: "\e611"; } .icon-gf-event-error:before { - content: "\e623"; + content: "\e623"; } .icon-gf-event:before { - content: "\e624"; + content: "\e624"; } .icon-gf-sadface:before { - content: "\e907"; + content: "\e907"; } .icon-gf-private-collector:before { - content: "\e612"; + content: "\e612"; } .icon-gf-alert:before { - content: "\e61f"; + content: "\e61f"; } .icon-gf-alert-disabled:before { - content: "\e621"; + content: "\e621"; } .icon-gf-refresh:before { - content: "\e613"; + content: "\e613"; } .icon-gf-save:before { - content: "\e614"; + content: "\e614"; } .icon-gf-share:before { - content: "\e616"; + content: "\e616"; } .icon-gf-star:before { - content: "\e617"; + content: "\e617"; } .icon-gf-search:before { - content: "\e618"; + content: "\e618"; } .icon-gf-settings:before { - content: "\e615"; + content: "\e615"; } .icon-gf-add:before { - content: "\e619"; + content: "\e619"; } .icon-gf-remove:before { - content: "\e61a"; + content: "\e61a"; } .icon-gf-video:before { - content: "\e61b"; + content: "\e61b"; } .icon-gf-bulk_action:before { - content: "\e61c"; + content: "\e61c"; } .icon-gf-grabber:before { content: "\e90b"; -} +} .icon-gf-users:before { - content: "\e622"; + content: "\e622"; } .icon-gf-globe:before { - content: "\e61d"; + content: "\e61d"; } .icon-gf-snapshot:before { - content: "\e61e"; + content: "\e61e"; } .icon-gf-play-grafana-icon:before { - content: "\e629"; + content: "\e629"; } .icon-gf-grafana-icon:before { - content: "\e625"; + content: "\e625"; } .icon-gf-email:before { - content: "\e628"; + content: "\e628"; } .icon-gf-stopwatch:before { - content: "\e626"; + content: "\e626"; } .icon-gf-skull:before { - content: "\e900"; + content: "\e900"; } .icon-gf-probe:before { - content: "\e901"; + content: "\e901"; } .icon-gf-apps:before { - content: "\e902"; + content: "\e902"; } .icon-gf-scale:before { - content: "\e906"; + content: "\e906"; } .icon-gf-pending:before { - content: "\e909"; + content: "\e909"; } .icon-gf-verified:before { - content: "\e90a"; + content: "\e90a"; } .icon-gf-worldping:before { - content: "\e627"; + content: "\e627"; } .icon-gf-grafana_wordmark:before { - content: "\e903"; + content: "\e903"; } - diff --git a/public/sass/base/_grid.scss b/public/sass/base/_grid.scss index 32cd79f0094..bf825a155e9 100644 --- a/public/sass/base/_grid.scss +++ b/public/sass/base/_grid.scss @@ -1,4 +1,3 @@ - // Container widths // // Set the container width, and override it for fixed navbars in media queries. diff --git a/public/sass/base/_icons.scss b/public/sass/base/_icons.scss new file mode 100644 index 00000000000..c701cc1249e --- /dev/null +++ b/public/sass/base/_icons.scss @@ -0,0 +1,205 @@ +.gicon { + line-height: 1; + display: inline-block; + width: 1.1057142857em; + height: 1.1057142857em; + text-align: center; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + display: inline-block; + vertical-align: middle; +} + +.gicon--has-hover { + opacity: 0.5; + + &:hover { + opacity: 1; + } +} + +.mini { + width: 0.8em; + height: 0.8em; +} + +.gicon-add-annotation { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_annotation.svg'); +} + +.gicon-add-annotation-alt { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_annotation_alt.svg'); +} + +.gicon-add-datasources { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_data_sources.svg'); +} + +.gicon-add-user { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_user.svg'); +} + +.gicon-add-team { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_team.svg'); +} + +.gicon-add-panel { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_panel.svg'); +} + +.gicon-add-link { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_link.svg'); +} + +.gicon-add-variable { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_variable.svg'); +} + +.gicon-add-alert-notification-channel { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_notification_channel.svg'); +} + +.gicon-alert { + background-image: url('../img/icons_#{$theme-name}_theme/icon_alert.svg'); +} + +.gicon-alert-alt { + background-image: url('../img/icons_#{$theme-name}_theme/icon_alert_alt.svg'); +} + +.gicon-alert-rules { + background-image: url('../img/icons_#{$theme-name}_theme/icon_alert_rules.svg'); +} + +.gicon-alert-notification-channel { + background-image: url('../img/icons_#{$theme-name}_theme/icon_notification_channels.svg'); +} + +.gicon-annotation { + background-image: url('../img/icons_#{$theme-name}_theme/icon_annotation.svg'); +} + +.gicon-annotation-alt { + background-image: url('../img/icons_#{$theme-name}_theme/icon_annotation_alt.svg'); +} + +.gicon-apikeys { + background-image: url('../img/icons_#{$theme-name}_theme/icon_apikeys.svg'); +} + +.gicon-branding { + background-image: url('../img/grafana_icon.svg'); +} + +.gicon-cog { + background-image: url('../img/icons_#{$theme-name}_theme/icon_cog.svg'); +} + +.gicon-dashboard { + background-image: url('../img/icons_#{$theme-name}_theme/icon_dashboard.svg'); +} + +.gicon-dashboard-starred { + background-image: url('../img/icons_#{$theme-name}_theme/icon_dashboard_fav.svg'); +} + +.gicon-dashboard-list { + background-image: url('../img/icons_#{$theme-name}_theme/icon_dashboard_list.svg'); +} + +.gicon-dashboard-new { + background-image: url('../img/icons_#{$theme-name}_theme/icon_new_dashboard.svg'); +} + +.gicon-dashboard-import { + background-image: url('../img/icons_#{$theme-name}_theme/icon_import_dashboard.svg'); +} + +.gicon-datasources { + background-image: url('../img/icons_#{$theme-name}_theme/icon_data_sources.svg'); +} + +.gicon-folder-new { + background-image: url('../img/icons_#{$theme-name}_theme/icon_add_folder.svg'); +} + +.gicon-home { + background-image: url('../img/icons_#{$theme-name}_theme/icon_home.svg'); +} + +.gicon-json { + background-image: url('../img/icons_#{$theme-name}_theme/icon_json.svg'); +} + +.gicon-link { + background-image: url('../img/icons_#{$theme-name}_theme/icon_link.svg'); +} + +.gicon-manage { + background-image: url('../img/icons_#{$theme-name}_theme/icon_sitemap.svg'); +} + +.gicon-org { + background-image: url('../img/icons_#{$theme-name}_theme/icon_org.svg'); +} + +.gicon-playlists { + background-image: url('../img/icons_#{$theme-name}_theme/icon_playlist.svg'); +} + +.gicon-plugins { + background-image: url('../img/icons_#{$theme-name}_theme/icon_plugins.svg'); +} + +.gicon-preferences { + background-image: url('../img/icons_#{$theme-name}_theme/icon_preferences.svg'); +} + +.gicon-question { + background-image: url('../img/icons_#{$theme-name}_theme/icon_question.svg'); +} + +.gicon-shield { + background-image: url('../img/icons_#{$theme-name}_theme/icon_shield.svg'); +} + +.gicon-snapshots { + background-image: url('../img/icons_#{$theme-name}_theme/icon_snapshots.svg'); +} + +.gicon-team { + background-image: url('../img/icons_#{$theme-name}_theme/icon_team.svg'); +} + +.gicon-user { + background-image: url('../img/icons_#{$theme-name}_theme/icon_user.svg'); +} + +.gicon-variable { + background-image: url('../img/icons_#{$theme-name}_theme/icon_variable.svg'); +} + +.gicon-zoom-out { + background-image: url('../img/icons_#{$theme-name}_theme/icon_zoom_out.svg'); +} + +.sidemenu { + .gicon-dashboard { + background-image: url('../img/icons_dark_theme/icon_dashboard.svg'); + } + .gicon-alert { + background-image: url('../img/icons_dark_theme/icon_alert.svg'); + } + .gicon-cog { + background-image: url('../img/icons_dark_theme/icon_cog.svg'); + } + .gicon-question { + background-image: url('../img/icons_dark_theme/icon_question.svg'); + } +} + +.fa--permissions-list { + min-width: 20px; + padding-right: 5px; +} diff --git a/public/sass/base/_normalize.scss b/public/sass/base/_normalize.scss index 93dd4521727..057f5c63602 100644 --- a/public/sass/base/_normalize.scss +++ b/public/sass/base/_normalize.scss @@ -291,8 +291,8 @@ select { // button, -html input[type="button"], // 1 -input[type="reset"], +html input[type="button"], +// 1 input[type="reset"], input[type="submit"] { -webkit-appearance: button; // 2 cursor: pointer; // 3 diff --git a/public/sass/base/_reboot.scss b/public/sass/base/_reboot.scss index 806ba2aa43d..e34bdfdb9ed 100644 --- a/public/sass/base/_reboot.scss +++ b/public/sass/base/_reboot.scss @@ -5,7 +5,6 @@ // Global resets to common HTML elements and more for easier usage by Bootstrap. // Adds additional rules on top of Normalize.css, including several overrides. - // Reset the box-sizing // // Change from `box-sizing: content-box` to `border-box` so that when you add @@ -29,7 +28,6 @@ html { box-sizing: inherit; } - // Make viewport responsive // // @viewport is needed because IE 10+ doesn't honor in @@ -46,10 +44,11 @@ html { // Wrap `@viewport` with `@at-root` for when folks do a nested import (e.g., // `.class-name { @import "bootstrap"; }`). @at-root { - @-ms-viewport { width: device-width; } + @-ms-viewport { + width: device-width; + } } - // // Reset HTML, body, and more // @@ -65,7 +64,7 @@ html { // See https://github.com/twbs/bootstrap/issues/18543 -ms-overflow-style: scrollbar; // Changes the default tap highlight to be completely transparent in iOS. - -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); height: 100%; } @@ -79,6 +78,8 @@ body { // By default, `` has no `background-color` so we set one as a best practice. background-color: $body-bg; height: 100%; + width: 100%; + position: absolute; } // Suppress the focus outline on elements that cannot be accessed via keyboard. @@ -90,7 +91,6 @@ body { outline: none !important; } - // // Typography // @@ -99,9 +99,14 @@ body { // // By default, `

    `-`

    ` all receive top and bottom margins. We nuke the top // margin for easier control within type scales as it avoids margin collapsing. -h1, h2, h3, h4, h5, h6 { +h1, +h2, +h3, +h4, +h5, +h6 { margin-top: 0; - margin-bottom: .5rem; + margin-bottom: 0.5rem; } // Reset margins on paragraphs @@ -114,9 +119,7 @@ p { } // Abbreviations and acronyms -abbr[title], -// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257 -abbr[data-original-title] { +abbr[title] { cursor: help; border-bottom: 1px dotted $abbr-border-color; } @@ -146,7 +149,7 @@ dt { } dd { - margin-bottom: .5rem; + margin-bottom: 0.5rem; margin-left: 0; // Undo browser default } @@ -154,7 +157,6 @@ blockquote { margin: 0 0 1rem; } - // // Links // @@ -173,7 +175,6 @@ a { } } - // // Code // @@ -185,7 +186,6 @@ pre { margin-bottom: 1rem; } - // // Figures // @@ -196,7 +196,6 @@ figure { margin: 0 0 1rem; } - // // Images // @@ -209,7 +208,6 @@ img { // For the rationale behind this, see the comments on the `.img-fluid` class. } - // iOS "clickable elements" fix for role="button" // // Fixes "clickability" issue (and more generally, the firing of events such as focus as well) @@ -220,7 +218,6 @@ img { cursor: pointer; } - // Avoid 300ms click delay on touch devices that support the `touch-action` CSS property. // // In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11 @@ -243,7 +240,6 @@ textarea { touch-action: manipulation; } - // // Tables // @@ -266,7 +262,6 @@ th { text-align: left; } - // // Forms // @@ -319,10 +314,10 @@ legend { display: block; width: 100%; padding: 0; - margin-bottom: .5rem; + margin-bottom: 0.5rem; font-size: 1.5rem; line-height: inherit; -// border: 0; + // border: 0; } input[type="search"] { @@ -336,9 +331,9 @@ input[type="search"] { // todo: needed? output { display: inline-block; -// font-size: $font-size-base; -// line-height: $line-height; -// color: $input-color; + // font-size: $font-size-base; + // line-height: $line-height; + // color: $input-color; } // Always hide an element with the `hidden` HTML attribute (from PureCSS). diff --git a/public/sass/base/_type.scss b/public/sass/base/_type.scss index b2b43257654..1c3516c2828 100644 --- a/public/sass/base/_type.scss +++ b/public/sass/base/_type.scss @@ -2,7 +2,6 @@ // Typography // -------------------------------------------------- - // Body text // ------------------------- @@ -21,48 +20,103 @@ p { // ------------------------- // Ex: 14px base font * 85% = about 12px -small { font-size: 85%; } -strong { font-weight: bold; } -em { font-style: italic; color: $headings-color; } -cite { font-style: normal; } +small { + font-size: 85%; +} +strong { + font-weight: bold; +} +em { + font-style: italic; + color: $headings-color; +} +cite { + font-style: normal; +} // Utility classes -.muted { color: $text-muted; } +.muted { + color: $text-muted; +} a.muted:hover, -a.muted:focus { color: darken($text-muted, 10%); } +a.muted:focus { + color: darken($text-muted, 10%); +} -.text-warning { color: $warning-text-color; } +.text-warning { + color: $warning-text-color; +} a.text-warning:hover, -a.text-warning:focus { color: darken($warning-text-color, 10%); } +a.text-warning:focus { + color: darken($warning-text-color, 10%); +} -.text-error { color: $error-text-color; } +.text-error { + color: $error-text-color; +} a.text-error:hover, -a.text-error:focus { color: darken($error-text-color, 10%); } +a.text-error:focus { + color: darken($error-text-color, 10%); +} -.text-info { color: $info-text-color; } +.text-info { + color: $info-text-color; +} a.text-info:hover, -a.text-info:focus { color: darken($info-text-color, 10%); } +a.text-info:focus { + color: darken($info-text-color, 10%); +} -.text-success { color: $success-text-color; } +.text-success { + color: $success-text-color; +} a.text-success:hover, -a.text-success:focus { color: darken($success-text-color, 10%); } -a { cursor: pointer; } +a.text-success:focus { + color: darken($success-text-color, 10%); +} +a { + cursor: pointer; +} + +.text-link { + text-decoration: underline; +} + +a:focus { + outline: 0 none !important; +} a[disabled] { cursor: default; pointer-events: none !important; } -.text-left { text-align: left; } -.text-right { text-align: right; } -.text-center { text-align: center; } +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} // // Headings // -h1, h2, h3, h4, h5, h6, -.h1, .h2, .h3, .h4, .h5, .h6 { +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { margin-bottom: $headings-margin-bottom; font-family: $headings-font-family; font-weight: $headings-font-weight; @@ -70,12 +124,30 @@ h1, h2, h3, h4, h5, h6, color: $headings-color; } -h1, .h1 { font-size: $font-size-h1; font-style: italic; } -h2, .h2 { font-size: $font-size-h2; } -h3, .h3 { font-size: $font-size-h3; } -h4, .h4 { font-size: $font-size-h4; } -h5, .h5 { font-size: $font-size-h5; } -h6, .h6 { font-size: $font-size-h6; } +h1, +.h1 { + font-size: $font-size-h1; +} +h2, +.h2 { + font-size: $font-size-h2; +} +h3, +.h3 { + font-size: $font-size-h3; +} +h4, +.h4 { + font-size: $font-size-h4; +} +h5, +.h5 { + font-size: $font-size-h5; +} +h6, +.h6 { + font-size: $font-size-h6; +} .lead { font-size: $lead-font-size; @@ -100,7 +172,6 @@ h6, .h6 { font-size: $font-size-h6; } font-weight: $display4-weight; } - // // Horizontal rules // @@ -112,7 +183,6 @@ hr { border-top: $hr-border-width solid $hr-border-color; } - // // Emphasis // @@ -129,16 +199,16 @@ small, mark, .mark { - padding: .2em; + padding: 0.2em; background: $alert-warning-bg; } - // Lists // -------------------------------------------------- // Unordered and Ordered lists -ul, ol { +ul, +ol { padding: 0; } ul ul, @@ -203,12 +273,11 @@ dd { // ---- // Abbreviations and acronyms -abbr[title], -// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257 -abbr[data-original-title] { +abbr[title] { cursor: help; border-bottom: 1px dotted $gray-2; } + abbr.initialism { font-size: 90%; text-transform: uppercase; @@ -261,7 +330,7 @@ q:before, q:after, blockquote:before, blockquote:after { - content: ""; + content: ''; } // Addresses @@ -273,11 +342,10 @@ address { } a.external-link { - color: $blue; + color: $external-link-color; text-decoration: underline; } - .link { color: $link-color; cursor: pointer; @@ -296,14 +364,16 @@ a.external-link { max-width: 100%; } - ul, ol { + ul, + ol { padding-left: $spacer*1.5; margin-bottom: $spacer; } table { - td, th { - padding: $spacer*.5 $spacer; + td, + th { + padding: $spacer*0.5 $spacer; } th { font-weight: normal; @@ -311,7 +381,9 @@ a.external-link { } } - table, th, td { + table, + th, + td { border: 1px solid $table-border; border-collapse: collapse; } @@ -328,8 +400,18 @@ a.external-link { margin-bottom: 0; } - ul:last-child, ol:last-child { + ul:last-child, + ol:last-child { margin-bottom: 0; } } +.no-wrap { + white-space: nowrap; +} + +.highlight-search-match { + background: transparent; + color: $yellow; + padding: 0; +} diff --git a/public/sass/base/font-awesome/_animated.scss b/public/sass/base/font-awesome/_animated.scss index 8a020dbfff7..230df6b9ea8 100644 --- a/public/sass/base/font-awesome/_animated.scss +++ b/public/sass/base/font-awesome/_animated.scss @@ -3,32 +3,32 @@ .#{$fa-css-prefix}-spin { -webkit-animation: fa-spin 2s infinite linear; - animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; } .#{$fa-css-prefix}-pulse { -webkit-animation: fa-spin 1s infinite steps(8); - animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); } @-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); - transform: rotate(0deg); + transform: rotate(0deg); } 100% { -webkit-transform: rotate(359deg); - transform: rotate(359deg); + transform: rotate(359deg); } } @keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); - transform: rotate(0deg); + transform: rotate(0deg); } 100% { -webkit-transform: rotate(359deg); - transform: rotate(359deg); + transform: rotate(359deg); } } diff --git a/public/sass/base/font-awesome/_bordered-pulled.scss b/public/sass/base/font-awesome/_bordered-pulled.scss index d4b85a02f24..c9b6b38ea6f 100644 --- a/public/sass/base/font-awesome/_bordered-pulled.scss +++ b/public/sass/base/font-awesome/_bordered-pulled.scss @@ -2,24 +2,40 @@ // ------------------------- .#{$fa-css-prefix}-border { - padding: .2em .25em .15em; - border: solid .08em $fa-border-color; - border-radius: .1em; + padding: 0.2em 0.25em 0.15em; + border: solid 0.08em $fa-border-color; + border-radius: 0.1em; } -.#{$fa-css-prefix}-pull-left { float: left; } -.#{$fa-css-prefix}-pull-right { float: right; } +.#{$fa-css-prefix}-pull-left { + float: left; +} +.#{$fa-css-prefix}-pull-right { + float: right; +} .#{$fa-css-prefix} { - &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } - &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } + &.#{$fa-css-prefix}-pull-left { + margin-right: 0.3em; + } + &.#{$fa-css-prefix}-pull-right { + margin-left: 0.3em; + } } /* Deprecated as of 4.4.0 */ -.pull-right { float: right; } -.pull-left { float: left; } +.pull-right { + float: right; +} +.pull-left { + float: left; +} .#{$fa-css-prefix} { - &.pull-left { margin-right: .3em; } - &.pull-right { margin-left: .3em; } + &.pull-left { + margin-right: 0.3em; + } + &.pull-right { + margin-left: 0.3em; + } } diff --git a/public/sass/base/font-awesome/_core.scss b/public/sass/base/font-awesome/_core.scss index 7425ef85fc8..9940b63463d 100644 --- a/public/sass/base/font-awesome/_core.scss +++ b/public/sass/base/font-awesome/_core.scss @@ -3,10 +3,10 @@ .#{$fa-css-prefix} { display: inline-block; - font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} + FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - } diff --git a/public/sass/base/font-awesome/_icons.scss b/public/sass/base/font-awesome/_icons.scss index e63e702c4d9..6ee6171f359 100644 --- a/public/sass/base/font-awesome/_icons.scss +++ b/public/sass/base/font-awesome/_icons.scss @@ -1,789 +1,2139 @@ /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen readers do not read off random characters that represent icons */ -.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } -.#{$fa-css-prefix}-music:before { content: $fa-var-music; } -.#{$fa-css-prefix}-search:before { content: $fa-var-search; } -.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } -.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } -.#{$fa-css-prefix}-star:before { content: $fa-var-star; } -.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } -.#{$fa-css-prefix}-user:before { content: $fa-var-user; } -.#{$fa-css-prefix}-film:before { content: $fa-var-film; } -.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } -.#{$fa-css-prefix}-th:before { content: $fa-var-th; } -.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } -.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-glass:before { + content: $fa-var-glass; +} +.#{$fa-css-prefix}-music:before { + content: $fa-var-music; +} +.#{$fa-css-prefix}-search:before { + content: $fa-var-search; +} +.#{$fa-css-prefix}-envelope-o:before { + content: $fa-var-envelope-o; +} +.#{$fa-css-prefix}-heart:before { + content: $fa-var-heart; +} +.#{$fa-css-prefix}-star:before { + content: $fa-var-star; +} +.#{$fa-css-prefix}-star-o:before { + content: $fa-var-star-o; +} +.#{$fa-css-prefix}-user:before { + content: $fa-var-user; +} +.#{$fa-css-prefix}-film:before { + content: $fa-var-film; +} +.#{$fa-css-prefix}-th-large:before { + content: $fa-var-th-large; +} +.#{$fa-css-prefix}-th:before { + content: $fa-var-th; +} +.#{$fa-css-prefix}-th-list:before { + content: $fa-var-th-list; +} +.#{$fa-css-prefix}-check:before { + content: $fa-var-check; +} .#{$fa-css-prefix}-remove:before, .#{$fa-css-prefix}-close:before, -.#{$fa-css-prefix}-times:before { content: $fa-var-times; } -.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } -.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } -.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } -.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-times:before { + content: $fa-var-times; +} +.#{$fa-css-prefix}-search-plus:before { + content: $fa-var-search-plus; +} +.#{$fa-css-prefix}-search-minus:before { + content: $fa-var-search-minus; +} +.#{$fa-css-prefix}-power-off:before { + content: $fa-var-power-off; +} +.#{$fa-css-prefix}-signal:before { + content: $fa-var-signal; +} .#{$fa-css-prefix}-gear:before, -.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } -.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } -.#{$fa-css-prefix}-home:before { content: $fa-var-home; } -.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } -.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } -.#{$fa-css-prefix}-road:before { content: $fa-var-road; } -.#{$fa-css-prefix}-download:before { content: $fa-var-download; } -.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } -.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } -.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } -.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-cog:before { + content: $fa-var-cog; +} +.#{$fa-css-prefix}-trash-o:before { + content: $fa-var-trash-o; +} +.#{$fa-css-prefix}-home:before { + content: $fa-var-home; +} +.#{$fa-css-prefix}-file-o:before { + content: $fa-var-file-o; +} +.#{$fa-css-prefix}-clock-o:before { + content: $fa-var-clock-o; +} +.#{$fa-css-prefix}-road:before { + content: $fa-var-road; +} +.#{$fa-css-prefix}-download:before { + content: $fa-var-download; +} +.#{$fa-css-prefix}-arrow-circle-o-down:before { + content: $fa-var-arrow-circle-o-down; +} +.#{$fa-css-prefix}-arrow-circle-o-up:before { + content: $fa-var-arrow-circle-o-up; +} +.#{$fa-css-prefix}-inbox:before { + content: $fa-var-inbox; +} +.#{$fa-css-prefix}-play-circle-o:before { + content: $fa-var-play-circle-o; +} .#{$fa-css-prefix}-rotate-right:before, -.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } -.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } -.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } -.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } -.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } -.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } -.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } -.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } -.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } -.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } -.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } -.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } -.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } -.#{$fa-css-prefix}-book:before { content: $fa-var-book; } -.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } -.#{$fa-css-prefix}-print:before { content: $fa-var-print; } -.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } -.#{$fa-css-prefix}-font:before { content: $fa-var-font; } -.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } -.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } -.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } -.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } -.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } -.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } -.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } -.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } -.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-repeat:before { + content: $fa-var-repeat; +} +.#{$fa-css-prefix}-refresh:before { + content: $fa-var-refresh; +} +.#{$fa-css-prefix}-list-alt:before { + content: $fa-var-list-alt; +} +.#{$fa-css-prefix}-lock:before { + content: $fa-var-lock; +} +.#{$fa-css-prefix}-flag:before { + content: $fa-var-flag; +} +.#{$fa-css-prefix}-headphones:before { + content: $fa-var-headphones; +} +.#{$fa-css-prefix}-volume-off:before { + content: $fa-var-volume-off; +} +.#{$fa-css-prefix}-volume-down:before { + content: $fa-var-volume-down; +} +.#{$fa-css-prefix}-volume-up:before { + content: $fa-var-volume-up; +} +.#{$fa-css-prefix}-qrcode:before { + content: $fa-var-qrcode; +} +.#{$fa-css-prefix}-barcode:before { + content: $fa-var-barcode; +} +.#{$fa-css-prefix}-tag:before { + content: $fa-var-tag; +} +.#{$fa-css-prefix}-tags:before { + content: $fa-var-tags; +} +.#{$fa-css-prefix}-book:before { + content: $fa-var-book; +} +.#{$fa-css-prefix}-bookmark:before { + content: $fa-var-bookmark; +} +.#{$fa-css-prefix}-print:before { + content: $fa-var-print; +} +.#{$fa-css-prefix}-camera:before { + content: $fa-var-camera; +} +.#{$fa-css-prefix}-font:before { + content: $fa-var-font; +} +.#{$fa-css-prefix}-bold:before { + content: $fa-var-bold; +} +.#{$fa-css-prefix}-italic:before { + content: $fa-var-italic; +} +.#{$fa-css-prefix}-text-height:before { + content: $fa-var-text-height; +} +.#{$fa-css-prefix}-text-width:before { + content: $fa-var-text-width; +} +.#{$fa-css-prefix}-align-left:before { + content: $fa-var-align-left; +} +.#{$fa-css-prefix}-align-center:before { + content: $fa-var-align-center; +} +.#{$fa-css-prefix}-align-right:before { + content: $fa-var-align-right; +} +.#{$fa-css-prefix}-align-justify:before { + content: $fa-var-align-justify; +} +.#{$fa-css-prefix}-list:before { + content: $fa-var-list; +} .#{$fa-css-prefix}-dedent:before, -.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } -.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } -.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-outdent:before { + content: $fa-var-outdent; +} +.#{$fa-css-prefix}-indent:before { + content: $fa-var-indent; +} +.#{$fa-css-prefix}-video-camera:before { + content: $fa-var-video-camera; +} .#{$fa-css-prefix}-photo:before, .#{$fa-css-prefix}-image:before, -.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } -.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } -.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } -.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } -.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-picture-o:before { + content: $fa-var-picture-o; +} +.#{$fa-css-prefix}-pencil:before { + content: $fa-var-pencil; +} +.#{$fa-css-prefix}-map-marker:before { + content: $fa-var-map-marker; +} +.#{$fa-css-prefix}-adjust:before { + content: $fa-var-adjust; +} +.#{$fa-css-prefix}-tint:before { + content: $fa-var-tint; +} .#{$fa-css-prefix}-edit:before, -.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } -.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } -.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } -.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } -.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } -.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } -.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } -.#{$fa-css-prefix}-play:before { content: $fa-var-play; } -.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } -.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } -.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } -.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } -.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } -.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } -.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } -.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } -.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } -.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } -.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } -.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } -.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } -.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } -.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } -.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } -.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } -.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } -.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } -.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } -.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } -.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-pencil-square-o:before { + content: $fa-var-pencil-square-o; +} +.#{$fa-css-prefix}-share-square-o:before { + content: $fa-var-share-square-o; +} +.#{$fa-css-prefix}-check-square-o:before { + content: $fa-var-check-square-o; +} +.#{$fa-css-prefix}-arrows:before { + content: $fa-var-arrows; +} +.#{$fa-css-prefix}-step-backward:before { + content: $fa-var-step-backward; +} +.#{$fa-css-prefix}-fast-backward:before { + content: $fa-var-fast-backward; +} +.#{$fa-css-prefix}-backward:before { + content: $fa-var-backward; +} +.#{$fa-css-prefix}-play:before { + content: $fa-var-play; +} +.#{$fa-css-prefix}-pause:before { + content: $fa-var-pause; +} +.#{$fa-css-prefix}-stop:before { + content: $fa-var-stop; +} +.#{$fa-css-prefix}-forward:before { + content: $fa-var-forward; +} +.#{$fa-css-prefix}-fast-forward:before { + content: $fa-var-fast-forward; +} +.#{$fa-css-prefix}-step-forward:before { + content: $fa-var-step-forward; +} +.#{$fa-css-prefix}-eject:before { + content: $fa-var-eject; +} +.#{$fa-css-prefix}-chevron-left:before { + content: $fa-var-chevron-left; +} +.#{$fa-css-prefix}-chevron-right:before { + content: $fa-var-chevron-right; +} +.#{$fa-css-prefix}-plus-circle:before { + content: $fa-var-plus-circle; +} +.#{$fa-css-prefix}-minus-circle:before { + content: $fa-var-minus-circle; +} +.#{$fa-css-prefix}-times-circle:before { + content: $fa-var-times-circle; +} +.#{$fa-css-prefix}-check-circle:before { + content: $fa-var-check-circle; +} +.#{$fa-css-prefix}-question-circle:before { + content: $fa-var-question-circle; +} +.#{$fa-css-prefix}-info-circle:before { + content: $fa-var-info-circle; +} +.#{$fa-css-prefix}-crosshairs:before { + content: $fa-var-crosshairs; +} +.#{$fa-css-prefix}-times-circle-o:before { + content: $fa-var-times-circle-o; +} +.#{$fa-css-prefix}-check-circle-o:before { + content: $fa-var-check-circle-o; +} +.#{$fa-css-prefix}-ban:before { + content: $fa-var-ban; +} +.#{$fa-css-prefix}-arrow-left:before { + content: $fa-var-arrow-left; +} +.#{$fa-css-prefix}-arrow-right:before { + content: $fa-var-arrow-right; +} +.#{$fa-css-prefix}-arrow-up:before { + content: $fa-var-arrow-up; +} +.#{$fa-css-prefix}-arrow-down:before { + content: $fa-var-arrow-down; +} .#{$fa-css-prefix}-mail-forward:before, -.#{$fa-css-prefix}-share:before { content: $fa-var-share; } -.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } -.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } -.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } -.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } -.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } -.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } -.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } -.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } -.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } -.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } -.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-share:before { + content: $fa-var-share; +} +.#{$fa-css-prefix}-expand:before { + content: $fa-var-expand; +} +.#{$fa-css-prefix}-compress:before { + content: $fa-var-compress; +} +.#{$fa-css-prefix}-plus:before { + content: $fa-var-plus; +} +.#{$fa-css-prefix}-minus:before { + content: $fa-var-minus; +} +.#{$fa-css-prefix}-asterisk:before { + content: $fa-var-asterisk; +} +.#{$fa-css-prefix}-exclamation-circle:before { + content: $fa-var-exclamation-circle; +} +.#{$fa-css-prefix}-gift:before { + content: $fa-var-gift; +} +.#{$fa-css-prefix}-leaf:before { + content: $fa-var-leaf; +} +.#{$fa-css-prefix}-fire:before { + content: $fa-var-fire; +} +.#{$fa-css-prefix}-eye:before { + content: $fa-var-eye; +} +.#{$fa-css-prefix}-eye-slash:before { + content: $fa-var-eye-slash; +} .#{$fa-css-prefix}-warning:before, -.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } -.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } -.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } -.#{$fa-css-prefix}-random:before { content: $fa-var-random; } -.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } -.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } -.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } -.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } -.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } -.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } -.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } -.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } -.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } -.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-exclamation-triangle:before { + content: $fa-var-exclamation-triangle; +} +.#{$fa-css-prefix}-plane:before { + content: $fa-var-plane; +} +.#{$fa-css-prefix}-calendar:before { + content: $fa-var-calendar; +} +.#{$fa-css-prefix}-random:before { + content: $fa-var-random; +} +.#{$fa-css-prefix}-comment:before { + content: $fa-var-comment; +} +.#{$fa-css-prefix}-magnet:before { + content: $fa-var-magnet; +} +.#{$fa-css-prefix}-chevron-up:before { + content: $fa-var-chevron-up; +} +.#{$fa-css-prefix}-chevron-down:before { + content: $fa-var-chevron-down; +} +.#{$fa-css-prefix}-retweet:before { + content: $fa-var-retweet; +} +.#{$fa-css-prefix}-shopping-cart:before { + content: $fa-var-shopping-cart; +} +.#{$fa-css-prefix}-folder:before { + content: $fa-var-folder; +} +.#{$fa-css-prefix}-folder-open:before { + content: $fa-var-folder-open; +} +.#{$fa-css-prefix}-arrows-v:before { + content: $fa-var-arrows-v; +} +.#{$fa-css-prefix}-arrows-h:before { + content: $fa-var-arrows-h; +} .#{$fa-css-prefix}-bar-chart-o:before, -.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; } -.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } -.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } -.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } -.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-bar-chart:before { + content: $fa-var-bar-chart; +} +.#{$fa-css-prefix}-twitter-square:before { + content: $fa-var-twitter-square; +} +.#{$fa-css-prefix}-facebook-square:before { + content: $fa-var-facebook-square; +} +.#{$fa-css-prefix}-camera-retro:before { + content: $fa-var-camera-retro; +} +.#{$fa-css-prefix}-key:before { + content: $fa-var-key; +} .#{$fa-css-prefix}-gears:before, -.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } -.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } -.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } -.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } -.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } -.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } -.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } -.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } -.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } -.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } -.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } -.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } -.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } -.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } -.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } -.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } -.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } -.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } -.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } -.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-cogs:before { + content: $fa-var-cogs; +} +.#{$fa-css-prefix}-comments:before { + content: $fa-var-comments; +} +.#{$fa-css-prefix}-thumbs-o-up:before { + content: $fa-var-thumbs-o-up; +} +.#{$fa-css-prefix}-thumbs-o-down:before { + content: $fa-var-thumbs-o-down; +} +.#{$fa-css-prefix}-star-half:before { + content: $fa-var-star-half; +} +.#{$fa-css-prefix}-heart-o:before { + content: $fa-var-heart-o; +} +.#{$fa-css-prefix}-sign-out:before { + content: $fa-var-sign-out; +} +.#{$fa-css-prefix}-linkedin-square:before { + content: $fa-var-linkedin-square; +} +.#{$fa-css-prefix}-thumb-tack:before { + content: $fa-var-thumb-tack; +} +.#{$fa-css-prefix}-external-link:before { + content: $fa-var-external-link; +} +.#{$fa-css-prefix}-sign-in:before { + content: $fa-var-sign-in; +} +.#{$fa-css-prefix}-trophy:before { + content: $fa-var-trophy; +} +.#{$fa-css-prefix}-github-square:before { + content: $fa-var-github-square; +} +.#{$fa-css-prefix}-upload:before { + content: $fa-var-upload; +} +.#{$fa-css-prefix}-lemon-o:before { + content: $fa-var-lemon-o; +} +.#{$fa-css-prefix}-phone:before { + content: $fa-var-phone; +} +.#{$fa-css-prefix}-square-o:before { + content: $fa-var-square-o; +} +.#{$fa-css-prefix}-bookmark-o:before { + content: $fa-var-bookmark-o; +} +.#{$fa-css-prefix}-phone-square:before { + content: $fa-var-phone-square; +} +.#{$fa-css-prefix}-twitter:before { + content: $fa-var-twitter; +} .#{$fa-css-prefix}-facebook-f:before, -.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } -.#{$fa-css-prefix}-github:before { content: $fa-var-github; } -.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } -.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-facebook:before { + content: $fa-var-facebook; +} +.#{$fa-css-prefix}-github:before { + content: $fa-var-github; +} +.#{$fa-css-prefix}-unlock:before { + content: $fa-var-unlock; +} +.#{$fa-css-prefix}-credit-card:before { + content: $fa-var-credit-card; +} .#{$fa-css-prefix}-feed:before, -.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } -.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } -.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } -.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } -.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } -.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } -.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } -.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } -.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } -.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } -.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } -.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } -.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } -.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } -.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } -.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } -.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } -.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } -.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-rss:before { + content: $fa-var-rss; +} +.#{$fa-css-prefix}-hdd-o:before { + content: $fa-var-hdd-o; +} +.#{$fa-css-prefix}-bullhorn:before { + content: $fa-var-bullhorn; +} +.#{$fa-css-prefix}-bell:before { + content: $fa-var-bell; +} +.#{$fa-css-prefix}-certificate:before { + content: $fa-var-certificate; +} +.#{$fa-css-prefix}-hand-o-right:before { + content: $fa-var-hand-o-right; +} +.#{$fa-css-prefix}-hand-o-left:before { + content: $fa-var-hand-o-left; +} +.#{$fa-css-prefix}-hand-o-up:before { + content: $fa-var-hand-o-up; +} +.#{$fa-css-prefix}-hand-o-down:before { + content: $fa-var-hand-o-down; +} +.#{$fa-css-prefix}-arrow-circle-left:before { + content: $fa-var-arrow-circle-left; +} +.#{$fa-css-prefix}-arrow-circle-right:before { + content: $fa-var-arrow-circle-right; +} +.#{$fa-css-prefix}-arrow-circle-up:before { + content: $fa-var-arrow-circle-up; +} +.#{$fa-css-prefix}-arrow-circle-down:before { + content: $fa-var-arrow-circle-down; +} +.#{$fa-css-prefix}-globe:before { + content: $fa-var-globe; +} +.#{$fa-css-prefix}-wrench:before { + content: $fa-var-wrench; +} +.#{$fa-css-prefix}-tasks:before { + content: $fa-var-tasks; +} +.#{$fa-css-prefix}-filter:before { + content: $fa-var-filter; +} +.#{$fa-css-prefix}-briefcase:before { + content: $fa-var-briefcase; +} +.#{$fa-css-prefix}-arrows-alt:before { + content: $fa-var-arrows-alt; +} .#{$fa-css-prefix}-group:before, -.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-users:before { + content: $fa-var-users; +} .#{$fa-css-prefix}-chain:before, -.#{$fa-css-prefix}-link:before { content: $fa-var-link; } -.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } -.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-link:before { + content: $fa-var-link; +} +.#{$fa-css-prefix}-cloud:before { + content: $fa-var-cloud; +} +.#{$fa-css-prefix}-flask:before { + content: $fa-var-flask; +} .#{$fa-css-prefix}-cut:before, -.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-scissors:before { + content: $fa-var-scissors; +} .#{$fa-css-prefix}-copy:before, -.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } -.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-files-o:before { + content: $fa-var-files-o; +} +.#{$fa-css-prefix}-paperclip:before { + content: $fa-var-paperclip; +} .#{$fa-css-prefix}-save:before, -.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } -.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-floppy-o:before { + content: $fa-var-floppy-o; +} +.#{$fa-css-prefix}-square:before { + content: $fa-var-square; +} .#{$fa-css-prefix}-navicon:before, .#{$fa-css-prefix}-reorder:before, -.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } -.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } -.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } -.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } -.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } -.#{$fa-css-prefix}-table:before { content: $fa-var-table; } -.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } -.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } -.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } -.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } -.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } -.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } -.#{$fa-css-prefix}-money:before { content: $fa-var-money; } -.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } -.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } -.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } -.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } -.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-bars:before { + content: $fa-var-bars; +} +.#{$fa-css-prefix}-list-ul:before { + content: $fa-var-list-ul; +} +.#{$fa-css-prefix}-list-ol:before { + content: $fa-var-list-ol; +} +.#{$fa-css-prefix}-strikethrough:before { + content: $fa-var-strikethrough; +} +.#{$fa-css-prefix}-underline:before { + content: $fa-var-underline; +} +.#{$fa-css-prefix}-table:before { + content: $fa-var-table; +} +.#{$fa-css-prefix}-magic:before { + content: $fa-var-magic; +} +.#{$fa-css-prefix}-truck:before { + content: $fa-var-truck; +} +.#{$fa-css-prefix}-pinterest:before { + content: $fa-var-pinterest; +} +.#{$fa-css-prefix}-pinterest-square:before { + content: $fa-var-pinterest-square; +} +.#{$fa-css-prefix}-google-plus-square:before { + content: $fa-var-google-plus-square; +} +.#{$fa-css-prefix}-google-plus:before { + content: $fa-var-google-plus; +} +.#{$fa-css-prefix}-money:before { + content: $fa-var-money; +} +.#{$fa-css-prefix}-caret-down:before { + content: $fa-var-caret-down; +} +.#{$fa-css-prefix}-caret-up:before { + content: $fa-var-caret-up; +} +.#{$fa-css-prefix}-caret-left:before { + content: $fa-var-caret-left; +} +.#{$fa-css-prefix}-caret-right:before { + content: $fa-var-caret-right; +} +.#{$fa-css-prefix}-columns:before { + content: $fa-var-columns; +} .#{$fa-css-prefix}-unsorted:before, -.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort:before { + content: $fa-var-sort; +} .#{$fa-css-prefix}-sort-down:before, -.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-sort-desc:before { + content: $fa-var-sort-desc; +} .#{$fa-css-prefix}-sort-up:before, -.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } -.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } -.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-sort-asc:before { + content: $fa-var-sort-asc; +} +.#{$fa-css-prefix}-envelope:before { + content: $fa-var-envelope; +} +.#{$fa-css-prefix}-linkedin:before { + content: $fa-var-linkedin; +} .#{$fa-css-prefix}-rotate-left:before, -.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-undo:before { + content: $fa-var-undo; +} .#{$fa-css-prefix}-legal:before, -.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-gavel:before { + content: $fa-var-gavel; +} .#{$fa-css-prefix}-dashboard:before, -.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } -.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } -.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-tachometer:before { + content: $fa-var-tachometer; +} +.#{$fa-css-prefix}-comment-o:before { + content: $fa-var-comment-o; +} +.#{$fa-css-prefix}-comments-o:before { + content: $fa-var-comments-o; +} .#{$fa-css-prefix}-flash:before, -.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } -.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } -.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-bolt:before { + content: $fa-var-bolt; +} +.#{$fa-css-prefix}-sitemap:before { + content: $fa-var-sitemap; +} +.#{$fa-css-prefix}-umbrella:before { + content: $fa-var-umbrella; +} .#{$fa-css-prefix}-paste:before, -.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } -.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } -.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } -.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } -.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } -.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } -.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } -.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } -.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } -.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } -.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } -.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } -.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } -.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } -.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } -.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } -.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } -.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } -.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } -.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } -.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } -.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } -.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } -.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } -.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } -.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } -.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } -.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } -.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } -.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } -.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-clipboard:before { + content: $fa-var-clipboard; +} +.#{$fa-css-prefix}-lightbulb-o:before { + content: $fa-var-lightbulb-o; +} +.#{$fa-css-prefix}-exchange:before { + content: $fa-var-exchange; +} +.#{$fa-css-prefix}-cloud-download:before { + content: $fa-var-cloud-download; +} +.#{$fa-css-prefix}-cloud-upload:before { + content: $fa-var-cloud-upload; +} +.#{$fa-css-prefix}-user-md:before { + content: $fa-var-user-md; +} +.#{$fa-css-prefix}-stethoscope:before { + content: $fa-var-stethoscope; +} +.#{$fa-css-prefix}-suitcase:before { + content: $fa-var-suitcase; +} +.#{$fa-css-prefix}-bell-o:before { + content: $fa-var-bell-o; +} +.#{$fa-css-prefix}-coffee:before { + content: $fa-var-coffee; +} +.#{$fa-css-prefix}-cutlery:before { + content: $fa-var-cutlery; +} +.#{$fa-css-prefix}-file-text-o:before { + content: $fa-var-file-text-o; +} +.#{$fa-css-prefix}-building-o:before { + content: $fa-var-building-o; +} +.#{$fa-css-prefix}-hospital-o:before { + content: $fa-var-hospital-o; +} +.#{$fa-css-prefix}-ambulance:before { + content: $fa-var-ambulance; +} +.#{$fa-css-prefix}-medkit:before { + content: $fa-var-medkit; +} +.#{$fa-css-prefix}-fighter-jet:before { + content: $fa-var-fighter-jet; +} +.#{$fa-css-prefix}-beer:before { + content: $fa-var-beer; +} +.#{$fa-css-prefix}-h-square:before { + content: $fa-var-h-square; +} +.#{$fa-css-prefix}-plus-square:before { + content: $fa-var-plus-square; +} +.#{$fa-css-prefix}-angle-double-left:before { + content: $fa-var-angle-double-left; +} +.#{$fa-css-prefix}-angle-double-right:before { + content: $fa-var-angle-double-right; +} +.#{$fa-css-prefix}-angle-double-up:before { + content: $fa-var-angle-double-up; +} +.#{$fa-css-prefix}-angle-double-down:before { + content: $fa-var-angle-double-down; +} +.#{$fa-css-prefix}-angle-left:before { + content: $fa-var-angle-left; +} +.#{$fa-css-prefix}-angle-right:before { + content: $fa-var-angle-right; +} +.#{$fa-css-prefix}-angle-up:before { + content: $fa-var-angle-up; +} +.#{$fa-css-prefix}-angle-down:before { + content: $fa-var-angle-down; +} +.#{$fa-css-prefix}-desktop:before { + content: $fa-var-desktop; +} +.#{$fa-css-prefix}-laptop:before { + content: $fa-var-laptop; +} +.#{$fa-css-prefix}-tablet:before { + content: $fa-var-tablet; +} .#{$fa-css-prefix}-mobile-phone:before, -.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } -.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } -.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } -.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } -.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } -.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mobile:before { + content: $fa-var-mobile; +} +.#{$fa-css-prefix}-circle-o:before { + content: $fa-var-circle-o; +} +.#{$fa-css-prefix}-quote-left:before { + content: $fa-var-quote-left; +} +.#{$fa-css-prefix}-quote-right:before { + content: $fa-var-quote-right; +} +.#{$fa-css-prefix}-spinner:before { + content: $fa-var-spinner; +} +.#{$fa-css-prefix}-circle:before { + content: $fa-var-circle; +} .#{$fa-css-prefix}-mail-reply:before, -.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } -.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } -.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } -.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } -.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } -.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } -.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } -.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } -.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } -.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } -.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } -.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } -.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-reply:before { + content: $fa-var-reply; +} +.#{$fa-css-prefix}-github-alt:before { + content: $fa-var-github-alt; +} +.#{$fa-css-prefix}-folder-o:before { + content: $fa-var-folder-o; +} +.#{$fa-css-prefix}-folder-open-o:before { + content: $fa-var-folder-open-o; +} +.#{$fa-css-prefix}-smile-o:before { + content: $fa-var-smile-o; +} +.#{$fa-css-prefix}-frown-o:before { + content: $fa-var-frown-o; +} +.#{$fa-css-prefix}-meh-o:before { + content: $fa-var-meh-o; +} +.#{$fa-css-prefix}-gamepad:before { + content: $fa-var-gamepad; +} +.#{$fa-css-prefix}-keyboard-o:before { + content: $fa-var-keyboard-o; +} +.#{$fa-css-prefix}-flag-o:before { + content: $fa-var-flag-o; +} +.#{$fa-css-prefix}-flag-checkered:before { + content: $fa-var-flag-checkered; +} +.#{$fa-css-prefix}-terminal:before { + content: $fa-var-terminal; +} +.#{$fa-css-prefix}-code:before { + content: $fa-var-code; +} .#{$fa-css-prefix}-mail-reply-all:before, -.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-reply-all:before { + content: $fa-var-reply-all; +} .#{$fa-css-prefix}-star-half-empty:before, .#{$fa-css-prefix}-star-half-full:before, -.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } -.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } -.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } -.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-star-half-o:before { + content: $fa-var-star-half-o; +} +.#{$fa-css-prefix}-location-arrow:before { + content: $fa-var-location-arrow; +} +.#{$fa-css-prefix}-crop:before { + content: $fa-var-crop; +} +.#{$fa-css-prefix}-code-fork:before { + content: $fa-var-code-fork; +} .#{$fa-css-prefix}-unlink:before, -.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } -.#{$fa-css-prefix}-question:before { content: $fa-var-question; } -.#{$fa-css-prefix}-info:before { content: $fa-var-info; } -.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } -.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } -.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } -.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } -.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } -.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } -.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } -.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } -.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } -.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } -.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } -.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } -.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } -.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } -.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } -.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } -.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } -.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } -.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } -.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } -.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } -.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } -.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } -.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } -.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } -.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } -.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } -.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } -.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } -.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } -.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } -.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } -.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } -.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } -.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-chain-broken:before { + content: $fa-var-chain-broken; +} +.#{$fa-css-prefix}-question:before { + content: $fa-var-question; +} +.#{$fa-css-prefix}-info:before { + content: $fa-var-info; +} +.#{$fa-css-prefix}-exclamation:before { + content: $fa-var-exclamation; +} +.#{$fa-css-prefix}-superscript:before { + content: $fa-var-superscript; +} +.#{$fa-css-prefix}-subscript:before { + content: $fa-var-subscript; +} +.#{$fa-css-prefix}-eraser:before { + content: $fa-var-eraser; +} +.#{$fa-css-prefix}-puzzle-piece:before { + content: $fa-var-puzzle-piece; +} +.#{$fa-css-prefix}-microphone:before { + content: $fa-var-microphone; +} +.#{$fa-css-prefix}-microphone-slash:before { + content: $fa-var-microphone-slash; +} +.#{$fa-css-prefix}-shield:before { + content: $fa-var-shield; +} +.#{$fa-css-prefix}-calendar-o:before { + content: $fa-var-calendar-o; +} +.#{$fa-css-prefix}-fire-extinguisher:before { + content: $fa-var-fire-extinguisher; +} +.#{$fa-css-prefix}-rocket:before { + content: $fa-var-rocket; +} +.#{$fa-css-prefix}-maxcdn:before { + content: $fa-var-maxcdn; +} +.#{$fa-css-prefix}-chevron-circle-left:before { + content: $fa-var-chevron-circle-left; +} +.#{$fa-css-prefix}-chevron-circle-right:before { + content: $fa-var-chevron-circle-right; +} +.#{$fa-css-prefix}-chevron-circle-up:before { + content: $fa-var-chevron-circle-up; +} +.#{$fa-css-prefix}-chevron-circle-down:before { + content: $fa-var-chevron-circle-down; +} +.#{$fa-css-prefix}-html5:before { + content: $fa-var-html5; +} +.#{$fa-css-prefix}-css3:before { + content: $fa-var-css3; +} +.#{$fa-css-prefix}-anchor:before { + content: $fa-var-anchor; +} +.#{$fa-css-prefix}-unlock-alt:before { + content: $fa-var-unlock-alt; +} +.#{$fa-css-prefix}-bullseye:before { + content: $fa-var-bullseye; +} +.#{$fa-css-prefix}-ellipsis-h:before { + content: $fa-var-ellipsis-h; +} +.#{$fa-css-prefix}-ellipsis-v:before { + content: $fa-var-ellipsis-v; +} +.#{$fa-css-prefix}-rss-square:before { + content: $fa-var-rss-square; +} +.#{$fa-css-prefix}-play-circle:before { + content: $fa-var-play-circle; +} +.#{$fa-css-prefix}-ticket:before { + content: $fa-var-ticket; +} +.#{$fa-css-prefix}-minus-square:before { + content: $fa-var-minus-square; +} +.#{$fa-css-prefix}-minus-square-o:before { + content: $fa-var-minus-square-o; +} +.#{$fa-css-prefix}-level-up:before { + content: $fa-var-level-up; +} +.#{$fa-css-prefix}-level-down:before { + content: $fa-var-level-down; +} +.#{$fa-css-prefix}-check-square:before { + content: $fa-var-check-square; +} +.#{$fa-css-prefix}-pencil-square:before { + content: $fa-var-pencil-square; +} +.#{$fa-css-prefix}-external-link-square:before { + content: $fa-var-external-link-square; +} +.#{$fa-css-prefix}-share-square:before { + content: $fa-var-share-square; +} +.#{$fa-css-prefix}-compass:before { + content: $fa-var-compass; +} .#{$fa-css-prefix}-toggle-down:before, -.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-caret-square-o-down:before { + content: $fa-var-caret-square-o-down; +} .#{$fa-css-prefix}-toggle-up:before, -.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-caret-square-o-up:before { + content: $fa-var-caret-square-o-up; +} .#{$fa-css-prefix}-toggle-right:before, -.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-caret-square-o-right:before { + content: $fa-var-caret-square-o-right; +} .#{$fa-css-prefix}-euro:before, -.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } -.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-eur:before { + content: $fa-var-eur; +} +.#{$fa-css-prefix}-gbp:before { + content: $fa-var-gbp; +} .#{$fa-css-prefix}-dollar:before, -.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-usd:before { + content: $fa-var-usd; +} .#{$fa-css-prefix}-rupee:before, -.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-inr:before { + content: $fa-var-inr; +} .#{$fa-css-prefix}-cny:before, .#{$fa-css-prefix}-rmb:before, .#{$fa-css-prefix}-yen:before, -.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-jpy:before { + content: $fa-var-jpy; +} .#{$fa-css-prefix}-ruble:before, .#{$fa-css-prefix}-rouble:before, -.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-rub:before { + content: $fa-var-rub; +} .#{$fa-css-prefix}-won:before, -.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-krw:before { + content: $fa-var-krw; +} .#{$fa-css-prefix}-bitcoin:before, -.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } -.#{$fa-css-prefix}-file:before { content: $fa-var-file; } -.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } -.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } -.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } -.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } -.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } -.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } -.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } -.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } -.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } -.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } -.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } -.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } -.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } -.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } -.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } -.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } -.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } -.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } -.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } -.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } -.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } -.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } -.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } -.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } -.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } -.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } -.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } -.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } -.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } -.#{$fa-css-prefix}-android:before { content: $fa-var-android; } -.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } -.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } -.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } -.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } -.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } -.#{$fa-css-prefix}-female:before { content: $fa-var-female; } -.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-btc:before { + content: $fa-var-btc; +} +.#{$fa-css-prefix}-file:before { + content: $fa-var-file; +} +.#{$fa-css-prefix}-file-text:before { + content: $fa-var-file-text; +} +.#{$fa-css-prefix}-sort-alpha-asc:before { + content: $fa-var-sort-alpha-asc; +} +.#{$fa-css-prefix}-sort-alpha-desc:before { + content: $fa-var-sort-alpha-desc; +} +.#{$fa-css-prefix}-sort-amount-asc:before { + content: $fa-var-sort-amount-asc; +} +.#{$fa-css-prefix}-sort-amount-desc:before { + content: $fa-var-sort-amount-desc; +} +.#{$fa-css-prefix}-sort-numeric-asc:before { + content: $fa-var-sort-numeric-asc; +} +.#{$fa-css-prefix}-sort-numeric-desc:before { + content: $fa-var-sort-numeric-desc; +} +.#{$fa-css-prefix}-thumbs-up:before { + content: $fa-var-thumbs-up; +} +.#{$fa-css-prefix}-thumbs-down:before { + content: $fa-var-thumbs-down; +} +.#{$fa-css-prefix}-youtube-square:before { + content: $fa-var-youtube-square; +} +.#{$fa-css-prefix}-youtube:before { + content: $fa-var-youtube; +} +.#{$fa-css-prefix}-xing:before { + content: $fa-var-xing; +} +.#{$fa-css-prefix}-xing-square:before { + content: $fa-var-xing-square; +} +.#{$fa-css-prefix}-youtube-play:before { + content: $fa-var-youtube-play; +} +.#{$fa-css-prefix}-dropbox:before { + content: $fa-var-dropbox; +} +.#{$fa-css-prefix}-stack-overflow:before { + content: $fa-var-stack-overflow; +} +.#{$fa-css-prefix}-instagram:before { + content: $fa-var-instagram; +} +.#{$fa-css-prefix}-flickr:before { + content: $fa-var-flickr; +} +.#{$fa-css-prefix}-adn:before { + content: $fa-var-adn; +} +.#{$fa-css-prefix}-bitbucket:before { + content: $fa-var-bitbucket; +} +.#{$fa-css-prefix}-bitbucket-square:before { + content: $fa-var-bitbucket-square; +} +.#{$fa-css-prefix}-tumblr:before { + content: $fa-var-tumblr; +} +.#{$fa-css-prefix}-tumblr-square:before { + content: $fa-var-tumblr-square; +} +.#{$fa-css-prefix}-long-arrow-down:before { + content: $fa-var-long-arrow-down; +} +.#{$fa-css-prefix}-long-arrow-up:before { + content: $fa-var-long-arrow-up; +} +.#{$fa-css-prefix}-long-arrow-left:before { + content: $fa-var-long-arrow-left; +} +.#{$fa-css-prefix}-long-arrow-right:before { + content: $fa-var-long-arrow-right; +} +.#{$fa-css-prefix}-apple:before { + content: $fa-var-apple; +} +.#{$fa-css-prefix}-windows:before { + content: $fa-var-windows; +} +.#{$fa-css-prefix}-android:before { + content: $fa-var-android; +} +.#{$fa-css-prefix}-linux:before { + content: $fa-var-linux; +} +.#{$fa-css-prefix}-dribbble:before { + content: $fa-var-dribbble; +} +.#{$fa-css-prefix}-skype:before { + content: $fa-var-skype; +} +.#{$fa-css-prefix}-foursquare:before { + content: $fa-var-foursquare; +} +.#{$fa-css-prefix}-trello:before { + content: $fa-var-trello; +} +.#{$fa-css-prefix}-female:before { + content: $fa-var-female; +} +.#{$fa-css-prefix}-male:before { + content: $fa-var-male; +} .#{$fa-css-prefix}-gittip:before, -.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; } -.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } -.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } -.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } -.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } -.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } -.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } -.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } -.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } -.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } -.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } -.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-gratipay:before { + content: $fa-var-gratipay; +} +.#{$fa-css-prefix}-sun-o:before { + content: $fa-var-sun-o; +} +.#{$fa-css-prefix}-moon-o:before { + content: $fa-var-moon-o; +} +.#{$fa-css-prefix}-archive:before { + content: $fa-var-archive; +} +.#{$fa-css-prefix}-bug:before { + content: $fa-var-bug; +} +.#{$fa-css-prefix}-vk:before { + content: $fa-var-vk; +} +.#{$fa-css-prefix}-weibo:before { + content: $fa-var-weibo; +} +.#{$fa-css-prefix}-renren:before { + content: $fa-var-renren; +} +.#{$fa-css-prefix}-pagelines:before { + content: $fa-var-pagelines; +} +.#{$fa-css-prefix}-stack-exchange:before { + content: $fa-var-stack-exchange; +} +.#{$fa-css-prefix}-arrow-circle-o-right:before { + content: $fa-var-arrow-circle-o-right; +} +.#{$fa-css-prefix}-arrow-circle-o-left:before { + content: $fa-var-arrow-circle-o-left; +} .#{$fa-css-prefix}-toggle-left:before, -.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } -.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } -.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } -.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-caret-square-o-left:before { + content: $fa-var-caret-square-o-left; +} +.#{$fa-css-prefix}-dot-circle-o:before { + content: $fa-var-dot-circle-o; +} +.#{$fa-css-prefix}-wheelchair:before { + content: $fa-var-wheelchair; +} +.#{$fa-css-prefix}-vimeo-square:before { + content: $fa-var-vimeo-square; +} .#{$fa-css-prefix}-turkish-lira:before, -.#{$fa-css-prefix}-try:before { content: $fa-var-try; } -.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } -.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; } -.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; } -.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; } -.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; } -.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; } +.#{$fa-css-prefix}-try:before { + content: $fa-var-try; +} +.#{$fa-css-prefix}-plus-square-o:before { + content: $fa-var-plus-square-o; +} +.#{$fa-css-prefix}-space-shuttle:before { + content: $fa-var-space-shuttle; +} +.#{$fa-css-prefix}-slack:before { + content: $fa-var-slack; +} +.#{$fa-css-prefix}-envelope-square:before { + content: $fa-var-envelope-square; +} +.#{$fa-css-prefix}-wordpress:before { + content: $fa-var-wordpress; +} +.#{$fa-css-prefix}-openid:before { + content: $fa-var-openid; +} .#{$fa-css-prefix}-institution:before, .#{$fa-css-prefix}-bank:before, -.#{$fa-css-prefix}-university:before { content: $fa-var-university; } +.#{$fa-css-prefix}-university:before { + content: $fa-var-university; +} .#{$fa-css-prefix}-mortar-board:before, -.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; } -.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; } -.#{$fa-css-prefix}-google:before { content: $fa-var-google; } -.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; } -.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; } -.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; } -.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; } -.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; } -.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; } -.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; } -.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; } -.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; } -.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; } -.#{$fa-css-prefix}-language:before { content: $fa-var-language; } -.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; } -.#{$fa-css-prefix}-building:before { content: $fa-var-building; } -.#{$fa-css-prefix}-child:before { content: $fa-var-child; } -.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; } -.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; } -.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; } -.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; } -.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; } -.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; } -.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; } -.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; } -.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; } +.#{$fa-css-prefix}-graduation-cap:before { + content: $fa-var-graduation-cap; +} +.#{$fa-css-prefix}-yahoo:before { + content: $fa-var-yahoo; +} +.#{$fa-css-prefix}-google:before { + content: $fa-var-google; +} +.#{$fa-css-prefix}-reddit:before { + content: $fa-var-reddit; +} +.#{$fa-css-prefix}-reddit-square:before { + content: $fa-var-reddit-square; +} +.#{$fa-css-prefix}-stumbleupon-circle:before { + content: $fa-var-stumbleupon-circle; +} +.#{$fa-css-prefix}-stumbleupon:before { + content: $fa-var-stumbleupon; +} +.#{$fa-css-prefix}-delicious:before { + content: $fa-var-delicious; +} +.#{$fa-css-prefix}-digg:before { + content: $fa-var-digg; +} +.#{$fa-css-prefix}-pied-piper-pp:before { + content: $fa-var-pied-piper-pp; +} +.#{$fa-css-prefix}-pied-piper-alt:before { + content: $fa-var-pied-piper-alt; +} +.#{$fa-css-prefix}-drupal:before { + content: $fa-var-drupal; +} +.#{$fa-css-prefix}-joomla:before { + content: $fa-var-joomla; +} +.#{$fa-css-prefix}-language:before { + content: $fa-var-language; +} +.#{$fa-css-prefix}-fax:before { + content: $fa-var-fax; +} +.#{$fa-css-prefix}-building:before { + content: $fa-var-building; +} +.#{$fa-css-prefix}-child:before { + content: $fa-var-child; +} +.#{$fa-css-prefix}-paw:before { + content: $fa-var-paw; +} +.#{$fa-css-prefix}-spoon:before { + content: $fa-var-spoon; +} +.#{$fa-css-prefix}-cube:before { + content: $fa-var-cube; +} +.#{$fa-css-prefix}-cubes:before { + content: $fa-var-cubes; +} +.#{$fa-css-prefix}-behance:before { + content: $fa-var-behance; +} +.#{$fa-css-prefix}-behance-square:before { + content: $fa-var-behance-square; +} +.#{$fa-css-prefix}-steam:before { + content: $fa-var-steam; +} +.#{$fa-css-prefix}-steam-square:before { + content: $fa-var-steam-square; +} +.#{$fa-css-prefix}-recycle:before { + content: $fa-var-recycle; +} .#{$fa-css-prefix}-automobile:before, -.#{$fa-css-prefix}-car:before { content: $fa-var-car; } +.#{$fa-css-prefix}-car:before { + content: $fa-var-car; +} .#{$fa-css-prefix}-cab:before, -.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; } -.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; } -.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; } -.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; } -.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; } -.#{$fa-css-prefix}-database:before { content: $fa-var-database; } -.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; } -.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; } -.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; } -.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; } +.#{$fa-css-prefix}-taxi:before { + content: $fa-var-taxi; +} +.#{$fa-css-prefix}-tree:before { + content: $fa-var-tree; +} +.#{$fa-css-prefix}-spotify:before { + content: $fa-var-spotify; +} +.#{$fa-css-prefix}-deviantart:before { + content: $fa-var-deviantart; +} +.#{$fa-css-prefix}-soundcloud:before { + content: $fa-var-soundcloud; +} +.#{$fa-css-prefix}-database:before { + content: $fa-var-database; +} +.#{$fa-css-prefix}-file-pdf-o:before { + content: $fa-var-file-pdf-o; +} +.#{$fa-css-prefix}-file-word-o:before { + content: $fa-var-file-word-o; +} +.#{$fa-css-prefix}-file-excel-o:before { + content: $fa-var-file-excel-o; +} +.#{$fa-css-prefix}-file-powerpoint-o:before { + content: $fa-var-file-powerpoint-o; +} .#{$fa-css-prefix}-file-photo-o:before, .#{$fa-css-prefix}-file-picture-o:before, -.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; } +.#{$fa-css-prefix}-file-image-o:before { + content: $fa-var-file-image-o; +} .#{$fa-css-prefix}-file-zip-o:before, -.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; } +.#{$fa-css-prefix}-file-archive-o:before { + content: $fa-var-file-archive-o; +} .#{$fa-css-prefix}-file-sound-o:before, -.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; } +.#{$fa-css-prefix}-file-audio-o:before { + content: $fa-var-file-audio-o; +} .#{$fa-css-prefix}-file-movie-o:before, -.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; } -.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; } -.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; } -.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; } -.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; } +.#{$fa-css-prefix}-file-video-o:before { + content: $fa-var-file-video-o; +} +.#{$fa-css-prefix}-file-code-o:before { + content: $fa-var-file-code-o; +} +.#{$fa-css-prefix}-vine:before { + content: $fa-var-vine; +} +.#{$fa-css-prefix}-codepen:before { + content: $fa-var-codepen; +} +.#{$fa-css-prefix}-jsfiddle:before { + content: $fa-var-jsfiddle; +} .#{$fa-css-prefix}-life-bouy:before, .#{$fa-css-prefix}-life-buoy:before, .#{$fa-css-prefix}-life-saver:before, .#{$fa-css-prefix}-support:before, -.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; } -.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; } +.#{$fa-css-prefix}-life-ring:before { + content: $fa-var-life-ring; +} +.#{$fa-css-prefix}-circle-o-notch:before { + content: $fa-var-circle-o-notch; +} .#{$fa-css-prefix}-ra:before, .#{$fa-css-prefix}-resistance:before, -.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; } +.#{$fa-css-prefix}-rebel:before { + content: $fa-var-rebel; +} .#{$fa-css-prefix}-ge:before, -.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } -.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } -.#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-empire:before { + content: $fa-var-empire; +} +.#{$fa-css-prefix}-git-square:before { + content: $fa-var-git-square; +} +.#{$fa-css-prefix}-git:before { + content: $fa-var-git; +} .#{$fa-css-prefix}-y-combinator-square:before, .#{$fa-css-prefix}-yc-square:before, -.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } -.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } -.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } +.#{$fa-css-prefix}-hacker-news:before { + content: $fa-var-hacker-news; +} +.#{$fa-css-prefix}-tencent-weibo:before { + content: $fa-var-tencent-weibo; +} +.#{$fa-css-prefix}-qq:before { + content: $fa-var-qq; +} .#{$fa-css-prefix}-wechat:before, -.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; } +.#{$fa-css-prefix}-weixin:before { + content: $fa-var-weixin; +} .#{$fa-css-prefix}-send:before, -.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; } +.#{$fa-css-prefix}-paper-plane:before { + content: $fa-var-paper-plane; +} .#{$fa-css-prefix}-send-o:before, -.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; } -.#{$fa-css-prefix}-history:before { content: $fa-var-history; } -.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; } -.#{$fa-css-prefix}-header:before { content: $fa-var-header; } -.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; } -.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; } -.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; } -.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; } -.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; } +.#{$fa-css-prefix}-paper-plane-o:before { + content: $fa-var-paper-plane-o; +} +.#{$fa-css-prefix}-history:before { + content: $fa-var-history; +} +.#{$fa-css-prefix}-circle-thin:before { + content: $fa-var-circle-thin; +} +.#{$fa-css-prefix}-header:before { + content: $fa-var-header; +} +.#{$fa-css-prefix}-paragraph:before { + content: $fa-var-paragraph; +} +.#{$fa-css-prefix}-sliders:before { + content: $fa-var-sliders; +} +.#{$fa-css-prefix}-share-alt:before { + content: $fa-var-share-alt; +} +.#{$fa-css-prefix}-share-alt-square:before { + content: $fa-var-share-alt-square; +} +.#{$fa-css-prefix}-bomb:before { + content: $fa-var-bomb; +} .#{$fa-css-prefix}-soccer-ball-o:before, -.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; } -.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; } -.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; } -.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; } -.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; } -.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; } -.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; } -.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; } -.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; } -.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; } -.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; } -.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; } -.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; } -.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; } -.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; } -.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; } -.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; } -.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; } -.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; } -.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; } -.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; } -.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; } -.#{$fa-css-prefix}-at:before { content: $fa-var-at; } -.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; } -.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; } -.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; } -.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; } -.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; } -.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; } -.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; } -.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; } -.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; } -.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; } -.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; } -.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; } -.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; } -.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; } -.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; } +.#{$fa-css-prefix}-futbol-o:before { + content: $fa-var-futbol-o; +} +.#{$fa-css-prefix}-tty:before { + content: $fa-var-tty; +} +.#{$fa-css-prefix}-binoculars:before { + content: $fa-var-binoculars; +} +.#{$fa-css-prefix}-plug:before { + content: $fa-var-plug; +} +.#{$fa-css-prefix}-slideshare:before { + content: $fa-var-slideshare; +} +.#{$fa-css-prefix}-twitch:before { + content: $fa-var-twitch; +} +.#{$fa-css-prefix}-yelp:before { + content: $fa-var-yelp; +} +.#{$fa-css-prefix}-newspaper-o:before { + content: $fa-var-newspaper-o; +} +.#{$fa-css-prefix}-wifi:before { + content: $fa-var-wifi; +} +.#{$fa-css-prefix}-calculator:before { + content: $fa-var-calculator; +} +.#{$fa-css-prefix}-paypal:before { + content: $fa-var-paypal; +} +.#{$fa-css-prefix}-google-wallet:before { + content: $fa-var-google-wallet; +} +.#{$fa-css-prefix}-cc-visa:before { + content: $fa-var-cc-visa; +} +.#{$fa-css-prefix}-cc-mastercard:before { + content: $fa-var-cc-mastercard; +} +.#{$fa-css-prefix}-cc-discover:before { + content: $fa-var-cc-discover; +} +.#{$fa-css-prefix}-cc-amex:before { + content: $fa-var-cc-amex; +} +.#{$fa-css-prefix}-cc-paypal:before { + content: $fa-var-cc-paypal; +} +.#{$fa-css-prefix}-cc-stripe:before { + content: $fa-var-cc-stripe; +} +.#{$fa-css-prefix}-bell-slash:before { + content: $fa-var-bell-slash; +} +.#{$fa-css-prefix}-bell-slash-o:before { + content: $fa-var-bell-slash-o; +} +.#{$fa-css-prefix}-trash:before { + content: $fa-var-trash; +} +.#{$fa-css-prefix}-copyright:before { + content: $fa-var-copyright; +} +.#{$fa-css-prefix}-at:before { + content: $fa-var-at; +} +.#{$fa-css-prefix}-eyedropper:before { + content: $fa-var-eyedropper; +} +.#{$fa-css-prefix}-paint-brush:before { + content: $fa-var-paint-brush; +} +.#{$fa-css-prefix}-birthday-cake:before { + content: $fa-var-birthday-cake; +} +.#{$fa-css-prefix}-area-chart:before { + content: $fa-var-area-chart; +} +.#{$fa-css-prefix}-pie-chart:before { + content: $fa-var-pie-chart; +} +.#{$fa-css-prefix}-line-chart:before { + content: $fa-var-line-chart; +} +.#{$fa-css-prefix}-lastfm:before { + content: $fa-var-lastfm; +} +.#{$fa-css-prefix}-lastfm-square:before { + content: $fa-var-lastfm-square; +} +.#{$fa-css-prefix}-toggle-off:before { + content: $fa-var-toggle-off; +} +.#{$fa-css-prefix}-toggle-on:before { + content: $fa-var-toggle-on; +} +.#{$fa-css-prefix}-bicycle:before { + content: $fa-var-bicycle; +} +.#{$fa-css-prefix}-bus:before { + content: $fa-var-bus; +} +.#{$fa-css-prefix}-ioxhost:before { + content: $fa-var-ioxhost; +} +.#{$fa-css-prefix}-angellist:before { + content: $fa-var-angellist; +} +.#{$fa-css-prefix}-cc:before { + content: $fa-var-cc; +} .#{$fa-css-prefix}-shekel:before, .#{$fa-css-prefix}-sheqel:before, -.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; } -.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; } -.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; } -.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; } -.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; } -.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; } -.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; } -.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; } -.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; } -.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; } -.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; } -.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; } -.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; } -.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; } -.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; } -.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; } -.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; } -.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; } -.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; } -.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; } -.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; } -.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; } +.#{$fa-css-prefix}-ils:before { + content: $fa-var-ils; +} +.#{$fa-css-prefix}-meanpath:before { + content: $fa-var-meanpath; +} +.#{$fa-css-prefix}-buysellads:before { + content: $fa-var-buysellads; +} +.#{$fa-css-prefix}-connectdevelop:before { + content: $fa-var-connectdevelop; +} +.#{$fa-css-prefix}-dashcube:before { + content: $fa-var-dashcube; +} +.#{$fa-css-prefix}-forumbee:before { + content: $fa-var-forumbee; +} +.#{$fa-css-prefix}-leanpub:before { + content: $fa-var-leanpub; +} +.#{$fa-css-prefix}-sellsy:before { + content: $fa-var-sellsy; +} +.#{$fa-css-prefix}-shirtsinbulk:before { + content: $fa-var-shirtsinbulk; +} +.#{$fa-css-prefix}-simplybuilt:before { + content: $fa-var-simplybuilt; +} +.#{$fa-css-prefix}-skyatlas:before { + content: $fa-var-skyatlas; +} +.#{$fa-css-prefix}-cart-plus:before { + content: $fa-var-cart-plus; +} +.#{$fa-css-prefix}-cart-arrow-down:before { + content: $fa-var-cart-arrow-down; +} +.#{$fa-css-prefix}-diamond:before { + content: $fa-var-diamond; +} +.#{$fa-css-prefix}-ship:before { + content: $fa-var-ship; +} +.#{$fa-css-prefix}-user-secret:before { + content: $fa-var-user-secret; +} +.#{$fa-css-prefix}-motorcycle:before { + content: $fa-var-motorcycle; +} +.#{$fa-css-prefix}-street-view:before { + content: $fa-var-street-view; +} +.#{$fa-css-prefix}-heartbeat:before { + content: $fa-var-heartbeat; +} +.#{$fa-css-prefix}-venus:before { + content: $fa-var-venus; +} +.#{$fa-css-prefix}-mars:before { + content: $fa-var-mars; +} +.#{$fa-css-prefix}-mercury:before { + content: $fa-var-mercury; +} .#{$fa-css-prefix}-intersex:before, -.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; } -.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; } -.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; } -.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; } -.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; } -.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; } -.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; } -.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; } -.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; } -.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; } -.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; } -.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; } -.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; } -.#{$fa-css-prefix}-server:before { content: $fa-var-server; } -.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; } -.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; } +.#{$fa-css-prefix}-transgender:before { + content: $fa-var-transgender; +} +.#{$fa-css-prefix}-transgender-alt:before { + content: $fa-var-transgender-alt; +} +.#{$fa-css-prefix}-venus-double:before { + content: $fa-var-venus-double; +} +.#{$fa-css-prefix}-mars-double:before { + content: $fa-var-mars-double; +} +.#{$fa-css-prefix}-venus-mars:before { + content: $fa-var-venus-mars; +} +.#{$fa-css-prefix}-mars-stroke:before { + content: $fa-var-mars-stroke; +} +.#{$fa-css-prefix}-mars-stroke-v:before { + content: $fa-var-mars-stroke-v; +} +.#{$fa-css-prefix}-mars-stroke-h:before { + content: $fa-var-mars-stroke-h; +} +.#{$fa-css-prefix}-neuter:before { + content: $fa-var-neuter; +} +.#{$fa-css-prefix}-genderless:before { + content: $fa-var-genderless; +} +.#{$fa-css-prefix}-facebook-official:before { + content: $fa-var-facebook-official; +} +.#{$fa-css-prefix}-pinterest-p:before { + content: $fa-var-pinterest-p; +} +.#{$fa-css-prefix}-whatsapp:before { + content: $fa-var-whatsapp; +} +.#{$fa-css-prefix}-server:before { + content: $fa-var-server; +} +.#{$fa-css-prefix}-user-plus:before { + content: $fa-var-user-plus; +} +.#{$fa-css-prefix}-user-times:before { + content: $fa-var-user-times; +} .#{$fa-css-prefix}-hotel:before, -.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; } -.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; } -.#{$fa-css-prefix}-train:before { content: $fa-var-train; } -.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; } -.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; } +.#{$fa-css-prefix}-bed:before { + content: $fa-var-bed; +} +.#{$fa-css-prefix}-viacoin:before { + content: $fa-var-viacoin; +} +.#{$fa-css-prefix}-train:before { + content: $fa-var-train; +} +.#{$fa-css-prefix}-subway:before { + content: $fa-var-subway; +} +.#{$fa-css-prefix}-medium:before { + content: $fa-var-medium; +} .#{$fa-css-prefix}-yc:before, -.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; } -.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; } -.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; } -.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; } +.#{$fa-css-prefix}-y-combinator:before { + content: $fa-var-y-combinator; +} +.#{$fa-css-prefix}-optin-monster:before { + content: $fa-var-optin-monster; +} +.#{$fa-css-prefix}-opencart:before { + content: $fa-var-opencart; +} +.#{$fa-css-prefix}-expeditedssl:before { + content: $fa-var-expeditedssl; +} .#{$fa-css-prefix}-battery-4:before, .#{$fa-css-prefix}-battery:before, -.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; } +.#{$fa-css-prefix}-battery-full:before { + content: $fa-var-battery-full; +} .#{$fa-css-prefix}-battery-3:before, -.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; } +.#{$fa-css-prefix}-battery-three-quarters:before { + content: $fa-var-battery-three-quarters; +} .#{$fa-css-prefix}-battery-2:before, -.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; } +.#{$fa-css-prefix}-battery-half:before { + content: $fa-var-battery-half; +} .#{$fa-css-prefix}-battery-1:before, -.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; } +.#{$fa-css-prefix}-battery-quarter:before { + content: $fa-var-battery-quarter; +} .#{$fa-css-prefix}-battery-0:before, -.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; } -.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; } -.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; } -.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; } -.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; } -.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; } -.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; } -.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; } -.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; } -.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; } -.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; } -.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; } +.#{$fa-css-prefix}-battery-empty:before { + content: $fa-var-battery-empty; +} +.#{$fa-css-prefix}-mouse-pointer:before { + content: $fa-var-mouse-pointer; +} +.#{$fa-css-prefix}-i-cursor:before { + content: $fa-var-i-cursor; +} +.#{$fa-css-prefix}-object-group:before { + content: $fa-var-object-group; +} +.#{$fa-css-prefix}-object-ungroup:before { + content: $fa-var-object-ungroup; +} +.#{$fa-css-prefix}-sticky-note:before { + content: $fa-var-sticky-note; +} +.#{$fa-css-prefix}-sticky-note-o:before { + content: $fa-var-sticky-note-o; +} +.#{$fa-css-prefix}-cc-jcb:before { + content: $fa-var-cc-jcb; +} +.#{$fa-css-prefix}-cc-diners-club:before { + content: $fa-var-cc-diners-club; +} +.#{$fa-css-prefix}-clone:before { + content: $fa-var-clone; +} +.#{$fa-css-prefix}-balance-scale:before { + content: $fa-var-balance-scale; +} +.#{$fa-css-prefix}-hourglass-o:before { + content: $fa-var-hourglass-o; +} .#{$fa-css-prefix}-hourglass-1:before, -.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; } +.#{$fa-css-prefix}-hourglass-start:before { + content: $fa-var-hourglass-start; +} .#{$fa-css-prefix}-hourglass-2:before, -.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; } +.#{$fa-css-prefix}-hourglass-half:before { + content: $fa-var-hourglass-half; +} .#{$fa-css-prefix}-hourglass-3:before, -.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; } -.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; } +.#{$fa-css-prefix}-hourglass-end:before { + content: $fa-var-hourglass-end; +} +.#{$fa-css-prefix}-hourglass:before { + content: $fa-var-hourglass; +} .#{$fa-css-prefix}-hand-grab-o:before, -.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; } +.#{$fa-css-prefix}-hand-rock-o:before { + content: $fa-var-hand-rock-o; +} .#{$fa-css-prefix}-hand-stop-o:before, -.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; } -.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; } -.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; } -.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; } -.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; } -.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; } -.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; } -.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; } -.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; } -.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; } -.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; } -.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; } -.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; } -.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; } -.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; } -.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; } -.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; } -.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; } -.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; } -.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; } -.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; } +.#{$fa-css-prefix}-hand-paper-o:before { + content: $fa-var-hand-paper-o; +} +.#{$fa-css-prefix}-hand-scissors-o:before { + content: $fa-var-hand-scissors-o; +} +.#{$fa-css-prefix}-hand-lizard-o:before { + content: $fa-var-hand-lizard-o; +} +.#{$fa-css-prefix}-hand-spock-o:before { + content: $fa-var-hand-spock-o; +} +.#{$fa-css-prefix}-hand-pointer-o:before { + content: $fa-var-hand-pointer-o; +} +.#{$fa-css-prefix}-hand-peace-o:before { + content: $fa-var-hand-peace-o; +} +.#{$fa-css-prefix}-trademark:before { + content: $fa-var-trademark; +} +.#{$fa-css-prefix}-registered:before { + content: $fa-var-registered; +} +.#{$fa-css-prefix}-creative-commons:before { + content: $fa-var-creative-commons; +} +.#{$fa-css-prefix}-gg:before { + content: $fa-var-gg; +} +.#{$fa-css-prefix}-gg-circle:before { + content: $fa-var-gg-circle; +} +.#{$fa-css-prefix}-tripadvisor:before { + content: $fa-var-tripadvisor; +} +.#{$fa-css-prefix}-odnoklassniki:before { + content: $fa-var-odnoklassniki; +} +.#{$fa-css-prefix}-odnoklassniki-square:before { + content: $fa-var-odnoklassniki-square; +} +.#{$fa-css-prefix}-get-pocket:before { + content: $fa-var-get-pocket; +} +.#{$fa-css-prefix}-wikipedia-w:before { + content: $fa-var-wikipedia-w; +} +.#{$fa-css-prefix}-safari:before { + content: $fa-var-safari; +} +.#{$fa-css-prefix}-chrome:before { + content: $fa-var-chrome; +} +.#{$fa-css-prefix}-firefox:before { + content: $fa-var-firefox; +} +.#{$fa-css-prefix}-opera:before { + content: $fa-var-opera; +} +.#{$fa-css-prefix}-internet-explorer:before { + content: $fa-var-internet-explorer; +} .#{$fa-css-prefix}-tv:before, -.#{$fa-css-prefix}-television:before { content: $fa-var-television; } -.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; } -.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; } -.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; } -.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; } -.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; } -.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; } -.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; } -.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; } -.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; } -.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; } -.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; } -.#{$fa-css-prefix}-map:before { content: $fa-var-map; } -.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; } -.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; } -.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; } -.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; } -.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; } -.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; } -.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; } -.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; } -.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; } -.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; } -.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; } -.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; } -.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; } -.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; } -.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; } -.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; } -.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; } -.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; } -.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; } -.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; } -.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; } -.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; } -.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; } -.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; } -.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; } -.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; } -.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; } -.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; } -.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; } -.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; } -.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; } -.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; } -.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; } -.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; } -.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; } -.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; } -.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; } -.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; } +.#{$fa-css-prefix}-television:before { + content: $fa-var-television; +} +.#{$fa-css-prefix}-contao:before { + content: $fa-var-contao; +} +.#{$fa-css-prefix}-500px:before { + content: $fa-var-500px; +} +.#{$fa-css-prefix}-amazon:before { + content: $fa-var-amazon; +} +.#{$fa-css-prefix}-calendar-plus-o:before { + content: $fa-var-calendar-plus-o; +} +.#{$fa-css-prefix}-calendar-minus-o:before { + content: $fa-var-calendar-minus-o; +} +.#{$fa-css-prefix}-calendar-times-o:before { + content: $fa-var-calendar-times-o; +} +.#{$fa-css-prefix}-calendar-check-o:before { + content: $fa-var-calendar-check-o; +} +.#{$fa-css-prefix}-industry:before { + content: $fa-var-industry; +} +.#{$fa-css-prefix}-map-pin:before { + content: $fa-var-map-pin; +} +.#{$fa-css-prefix}-map-signs:before { + content: $fa-var-map-signs; +} +.#{$fa-css-prefix}-map-o:before { + content: $fa-var-map-o; +} +.#{$fa-css-prefix}-map:before { + content: $fa-var-map; +} +.#{$fa-css-prefix}-commenting:before { + content: $fa-var-commenting; +} +.#{$fa-css-prefix}-commenting-o:before { + content: $fa-var-commenting-o; +} +.#{$fa-css-prefix}-houzz:before { + content: $fa-var-houzz; +} +.#{$fa-css-prefix}-vimeo:before { + content: $fa-var-vimeo; +} +.#{$fa-css-prefix}-black-tie:before { + content: $fa-var-black-tie; +} +.#{$fa-css-prefix}-fonticons:before { + content: $fa-var-fonticons; +} +.#{$fa-css-prefix}-reddit-alien:before { + content: $fa-var-reddit-alien; +} +.#{$fa-css-prefix}-edge:before { + content: $fa-var-edge; +} +.#{$fa-css-prefix}-credit-card-alt:before { + content: $fa-var-credit-card-alt; +} +.#{$fa-css-prefix}-codiepie:before { + content: $fa-var-codiepie; +} +.#{$fa-css-prefix}-modx:before { + content: $fa-var-modx; +} +.#{$fa-css-prefix}-fort-awesome:before { + content: $fa-var-fort-awesome; +} +.#{$fa-css-prefix}-usb:before { + content: $fa-var-usb; +} +.#{$fa-css-prefix}-product-hunt:before { + content: $fa-var-product-hunt; +} +.#{$fa-css-prefix}-mixcloud:before { + content: $fa-var-mixcloud; +} +.#{$fa-css-prefix}-scribd:before { + content: $fa-var-scribd; +} +.#{$fa-css-prefix}-pause-circle:before { + content: $fa-var-pause-circle; +} +.#{$fa-css-prefix}-pause-circle-o:before { + content: $fa-var-pause-circle-o; +} +.#{$fa-css-prefix}-stop-circle:before { + content: $fa-var-stop-circle; +} +.#{$fa-css-prefix}-stop-circle-o:before { + content: $fa-var-stop-circle-o; +} +.#{$fa-css-prefix}-shopping-bag:before { + content: $fa-var-shopping-bag; +} +.#{$fa-css-prefix}-shopping-basket:before { + content: $fa-var-shopping-basket; +} +.#{$fa-css-prefix}-hashtag:before { + content: $fa-var-hashtag; +} +.#{$fa-css-prefix}-bluetooth:before { + content: $fa-var-bluetooth; +} +.#{$fa-css-prefix}-bluetooth-b:before { + content: $fa-var-bluetooth-b; +} +.#{$fa-css-prefix}-percent:before { + content: $fa-var-percent; +} +.#{$fa-css-prefix}-gitlab:before { + content: $fa-var-gitlab; +} +.#{$fa-css-prefix}-wpbeginner:before { + content: $fa-var-wpbeginner; +} +.#{$fa-css-prefix}-wpforms:before { + content: $fa-var-wpforms; +} +.#{$fa-css-prefix}-envira:before { + content: $fa-var-envira; +} +.#{$fa-css-prefix}-universal-access:before { + content: $fa-var-universal-access; +} +.#{$fa-css-prefix}-wheelchair-alt:before { + content: $fa-var-wheelchair-alt; +} +.#{$fa-css-prefix}-question-circle-o:before { + content: $fa-var-question-circle-o; +} +.#{$fa-css-prefix}-blind:before { + content: $fa-var-blind; +} +.#{$fa-css-prefix}-audio-description:before { + content: $fa-var-audio-description; +} +.#{$fa-css-prefix}-volume-control-phone:before { + content: $fa-var-volume-control-phone; +} +.#{$fa-css-prefix}-braille:before { + content: $fa-var-braille; +} +.#{$fa-css-prefix}-assistive-listening-systems:before { + content: $fa-var-assistive-listening-systems; +} .#{$fa-css-prefix}-asl-interpreting:before, -.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; } +.#{$fa-css-prefix}-american-sign-language-interpreting:before { + content: $fa-var-american-sign-language-interpreting; +} .#{$fa-css-prefix}-deafness:before, .#{$fa-css-prefix}-hard-of-hearing:before, -.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; } -.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; } -.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; } +.#{$fa-css-prefix}-deaf:before { + content: $fa-var-deaf; +} +.#{$fa-css-prefix}-glide:before { + content: $fa-var-glide; +} +.#{$fa-css-prefix}-glide-g:before { + content: $fa-var-glide-g; +} .#{$fa-css-prefix}-signing:before, -.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; } -.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; } -.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; } -.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; } -.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; } -.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; } -.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; } -.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } -.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; } -.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; } -.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; } +.#{$fa-css-prefix}-sign-language:before { + content: $fa-var-sign-language; +} +.#{$fa-css-prefix}-low-vision:before { + content: $fa-var-low-vision; +} +.#{$fa-css-prefix}-viadeo:before { + content: $fa-var-viadeo; +} +.#{$fa-css-prefix}-viadeo-square:before { + content: $fa-var-viadeo-square; +} +.#{$fa-css-prefix}-snapchat:before { + content: $fa-var-snapchat; +} +.#{$fa-css-prefix}-snapchat-ghost:before { + content: $fa-var-snapchat-ghost; +} +.#{$fa-css-prefix}-snapchat-square:before { + content: $fa-var-snapchat-square; +} +.#{$fa-css-prefix}-pied-piper:before { + content: $fa-var-pied-piper; +} +.#{$fa-css-prefix}-first-order:before { + content: $fa-var-first-order; +} +.#{$fa-css-prefix}-yoast:before { + content: $fa-var-yoast; +} +.#{$fa-css-prefix}-themeisle:before { + content: $fa-var-themeisle; +} .#{$fa-css-prefix}-google-plus-circle:before, -.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; } +.#{$fa-css-prefix}-google-plus-official:before { + content: $fa-var-google-plus-official; +} .#{$fa-css-prefix}-fa:before, -.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; } -.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; } -.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; } -.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; } -.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; } -.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; } -.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; } +.#{$fa-css-prefix}-font-awesome:before { + content: $fa-var-font-awesome; +} +.#{$fa-css-prefix}-handshake-o:before { + content: $fa-var-handshake-o; +} +.#{$fa-css-prefix}-envelope-open:before { + content: $fa-var-envelope-open; +} +.#{$fa-css-prefix}-envelope-open-o:before { + content: $fa-var-envelope-open-o; +} +.#{$fa-css-prefix}-linode:before { + content: $fa-var-linode; +} +.#{$fa-css-prefix}-address-book:before { + content: $fa-var-address-book; +} +.#{$fa-css-prefix}-address-book-o:before { + content: $fa-var-address-book-o; +} .#{$fa-css-prefix}-vcard:before, -.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; } +.#{$fa-css-prefix}-address-card:before { + content: $fa-var-address-card; +} .#{$fa-css-prefix}-vcard-o:before, -.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; } -.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; } -.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; } -.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; } -.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; } +.#{$fa-css-prefix}-address-card-o:before { + content: $fa-var-address-card-o; +} +.#{$fa-css-prefix}-user-circle:before { + content: $fa-var-user-circle; +} +.#{$fa-css-prefix}-user-circle-o:before { + content: $fa-var-user-circle-o; +} +.#{$fa-css-prefix}-user-o:before { + content: $fa-var-user-o; +} +.#{$fa-css-prefix}-id-badge:before { + content: $fa-var-id-badge; +} .#{$fa-css-prefix}-drivers-license:before, -.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; } +.#{$fa-css-prefix}-id-card:before { + content: $fa-var-id-card; +} .#{$fa-css-prefix}-drivers-license-o:before, -.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; } -.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; } -.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; } -.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; } +.#{$fa-css-prefix}-id-card-o:before { + content: $fa-var-id-card-o; +} +.#{$fa-css-prefix}-quora:before { + content: $fa-var-quora; +} +.#{$fa-css-prefix}-free-code-camp:before { + content: $fa-var-free-code-camp; +} +.#{$fa-css-prefix}-telegram:before { + content: $fa-var-telegram; +} .#{$fa-css-prefix}-thermometer-4:before, .#{$fa-css-prefix}-thermometer:before, -.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; } +.#{$fa-css-prefix}-thermometer-full:before { + content: $fa-var-thermometer-full; +} .#{$fa-css-prefix}-thermometer-3:before, -.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; } +.#{$fa-css-prefix}-thermometer-three-quarters:before { + content: $fa-var-thermometer-three-quarters; +} .#{$fa-css-prefix}-thermometer-2:before, -.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; } +.#{$fa-css-prefix}-thermometer-half:before { + content: $fa-var-thermometer-half; +} .#{$fa-css-prefix}-thermometer-1:before, -.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; } +.#{$fa-css-prefix}-thermometer-quarter:before { + content: $fa-var-thermometer-quarter; +} .#{$fa-css-prefix}-thermometer-0:before, -.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; } -.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; } +.#{$fa-css-prefix}-thermometer-empty:before { + content: $fa-var-thermometer-empty; +} +.#{$fa-css-prefix}-shower:before { + content: $fa-var-shower; +} .#{$fa-css-prefix}-bathtub:before, .#{$fa-css-prefix}-s15:before, -.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; } -.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; } -.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; } -.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; } -.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; } +.#{$fa-css-prefix}-bath:before { + content: $fa-var-bath; +} +.#{$fa-css-prefix}-podcast:before { + content: $fa-var-podcast; +} +.#{$fa-css-prefix}-window-maximize:before { + content: $fa-var-window-maximize; +} +.#{$fa-css-prefix}-window-minimize:before { + content: $fa-var-window-minimize; +} +.#{$fa-css-prefix}-window-restore:before { + content: $fa-var-window-restore; +} .#{$fa-css-prefix}-times-rectangle:before, -.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; } +.#{$fa-css-prefix}-window-close:before { + content: $fa-var-window-close; +} .#{$fa-css-prefix}-times-rectangle-o:before, -.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; } -.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; } -.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; } -.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; } -.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; } -.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; } -.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; } -.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; } -.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; } -.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; } -.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; } -.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; } +.#{$fa-css-prefix}-window-close-o:before { + content: $fa-var-window-close-o; +} +.#{$fa-css-prefix}-bandcamp:before { + content: $fa-var-bandcamp; +} +.#{$fa-css-prefix}-grav:before { + content: $fa-var-grav; +} +.#{$fa-css-prefix}-etsy:before { + content: $fa-var-etsy; +} +.#{$fa-css-prefix}-imdb:before { + content: $fa-var-imdb; +} +.#{$fa-css-prefix}-ravelry:before { + content: $fa-var-ravelry; +} +.#{$fa-css-prefix}-eercast:before { + content: $fa-var-eercast; +} +.#{$fa-css-prefix}-microchip:before { + content: $fa-var-microchip; +} +.#{$fa-css-prefix}-snowflake-o:before { + content: $fa-var-snowflake-o; +} +.#{$fa-css-prefix}-superpowers:before { + content: $fa-var-superpowers; +} +.#{$fa-css-prefix}-wpexplorer:before { + content: $fa-var-wpexplorer; +} +.#{$fa-css-prefix}-meetup:before { + content: $fa-var-meetup; +} diff --git a/public/sass/base/font-awesome/_larger.scss b/public/sass/base/font-awesome/_larger.scss index 41e9a8184aa..5d7bebcda14 100644 --- a/public/sass/base/font-awesome/_larger.scss +++ b/public/sass/base/font-awesome/_larger.scss @@ -7,7 +7,15 @@ line-height: (3em / 4); vertical-align: -15%; } -.#{$fa-css-prefix}-2x { font-size: 2em; } -.#{$fa-css-prefix}-3x { font-size: 3em; } -.#{$fa-css-prefix}-4x { font-size: 4em; } -.#{$fa-css-prefix}-5x { font-size: 5em; } +.#{$fa-css-prefix}-2x { + font-size: 2em !important; +} +.#{$fa-css-prefix}-3x { + font-size: 3em; +} +.#{$fa-css-prefix}-4x { + font-size: 4em; +} +.#{$fa-css-prefix}-5x { + font-size: 5em; +} diff --git a/public/sass/base/font-awesome/_list.scss b/public/sass/base/font-awesome/_list.scss index 7d1e4d54d6c..9e30bee7447 100644 --- a/public/sass/base/font-awesome/_list.scss +++ b/public/sass/base/font-awesome/_list.scss @@ -5,7 +5,9 @@ padding-left: 0; margin-left: $fa-li-width; list-style-type: none; - > li { position: relative; } + > li { + position: relative; + } } .#{$fa-css-prefix}-li { position: absolute; diff --git a/public/sass/base/font-awesome/_mixins.scss b/public/sass/base/font-awesome/_mixins.scss index c3bbd5745d3..19771009107 100644 --- a/public/sass/base/font-awesome/_mixins.scss +++ b/public/sass/base/font-awesome/_mixins.scss @@ -3,29 +3,28 @@ @mixin fa-icon() { display: inline-block; - font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} + FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - } @mixin fa-icon-rotate($degrees, $rotation) { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; -webkit-transform: rotate($degrees); - -ms-transform: rotate($degrees); - transform: rotate($degrees); + -ms-transform: rotate($degrees); + transform: rotate($degrees); } @mixin fa-icon-flip($horiz, $vert, $rotation) { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; -webkit-transform: scale($horiz, $vert); - -ms-transform: scale($horiz, $vert); - transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); } - // Only display content to screen readers. A la Bootstrap 4. // // See: http://a11yproject.com/posts/how-to-hide-content/ @@ -37,7 +36,7 @@ padding: 0; margin: -1px; overflow: hidden; - clip: rect(0,0,0,0); + clip: rect(0, 0, 0, 0); border: 0; } diff --git a/public/sass/base/font-awesome/_path.scss b/public/sass/base/font-awesome/_path.scss index bb457c23a8e..0316afa161d 100644 --- a/public/sass/base/font-awesome/_path.scss +++ b/public/sass/base/font-awesome/_path.scss @@ -2,14 +2,19 @@ * -------------------------- */ @font-face { - font-family: 'FontAwesome'; - src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); - src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), - url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), - url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), - url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), - url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); -// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-family: "FontAwesome"; + src: url("#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}"); + src: url("#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}") + format("embedded-opentype"), + url("#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}") + format("woff2"), + url("#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}") + format("woff"), + url("#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}") + format("truetype"), + url("#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular") + format("svg"); + // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts font-weight: normal; font-style: normal; } diff --git a/public/sass/base/font-awesome/_rotated-flipped.scss b/public/sass/base/font-awesome/_rotated-flipped.scss index a3558fd09ca..07c11a8b299 100644 --- a/public/sass/base/font-awesome/_rotated-flipped.scss +++ b/public/sass/base/font-awesome/_rotated-flipped.scss @@ -1,12 +1,22 @@ // Rotated & Flipped Icons // ------------------------- -.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } -.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } -.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } +.#{$fa-css-prefix}-rotate-90 { + @include fa-icon-rotate(90deg, 1); +} +.#{$fa-css-prefix}-rotate-180 { + @include fa-icon-rotate(180deg, 2); +} +.#{$fa-css-prefix}-rotate-270 { + @include fa-icon-rotate(270deg, 3); +} -.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } -.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } +.#{$fa-css-prefix}-flip-horizontal { + @include fa-icon-flip(-1, 1, 0); +} +.#{$fa-css-prefix}-flip-vertical { + @include fa-icon-flip(1, -1, 2); +} // Hook for IE8-9 // ------------------------- diff --git a/public/sass/base/font-awesome/_screen-reader.scss b/public/sass/base/font-awesome/_screen-reader.scss index 637426f0da6..e3bff899ed9 100644 --- a/public/sass/base/font-awesome/_screen-reader.scss +++ b/public/sass/base/font-awesome/_screen-reader.scss @@ -1,5 +1,9 @@ // Screen Readers // ------------------------- -.sr-only { @include sr-only(); } -.sr-only-focusable { @include sr-only-focusable(); } +.sr-only { + @include sr-only(); +} +.sr-only-focusable { + @include sr-only-focusable(); +} diff --git a/public/sass/base/font-awesome/_stacked.scss b/public/sass/base/font-awesome/_stacked.scss index aef7403660c..33fbe76979c 100644 --- a/public/sass/base/font-awesome/_stacked.scss +++ b/public/sass/base/font-awesome/_stacked.scss @@ -9,12 +9,19 @@ line-height: 2em; vertical-align: middle; } -.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { +.#{$fa-css-prefix}-stack-1x, +.#{$fa-css-prefix}-stack-2x { position: absolute; left: 0; width: 100%; text-align: center; } -.#{$fa-css-prefix}-stack-1x { line-height: inherit; } -.#{$fa-css-prefix}-stack-2x { font-size: 2em; } -.#{$fa-css-prefix}-inverse { color: $fa-inverse; } +.#{$fa-css-prefix}-stack-1x { + line-height: inherit; +} +.#{$fa-css-prefix}-stack-2x { + font-size: 2em; +} +.#{$fa-css-prefix}-inverse { + color: $fa-inverse; +} diff --git a/public/sass/base/font-awesome/_variables.scss b/public/sass/base/font-awesome/_variables.scss index 498fc4a087c..a4bd3cd87b9 100644 --- a/public/sass/base/font-awesome/_variables.scss +++ b/public/sass/base/font-awesome/_variables.scss @@ -1,15 +1,15 @@ // Variables // -------------------------- -$fa-font-path: "../fonts" !default; -$fa-font-size-base: 14px !default; +$fa-font-path: "../fonts" !default; +$fa-font-size-base: 14px !default; $fa-line-height-base: 1 !default; //$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly -$fa-css-prefix: fa !default; -$fa-version: "4.7.0" !default; -$fa-border-color: #eee !default; -$fa-inverse: #fff !default; -$fa-li-width: (30em / 14) !default; +$fa-css-prefix: fa !default; +$fa-version: "4.7.0" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; $fa-var-500px: "\f26e"; $fa-var-address-book: "\f2b9"; @@ -797,4 +797,3 @@ $fa-var-yoast: "\f2b1"; $fa-var-youtube: "\f167"; $fa-var-youtube-play: "\f16a"; $fa-var-youtube-square: "\f166"; - diff --git a/public/sass/components/_alerts.scss b/public/sass/components/_alerts.scss index afc83a1024d..3420dcfdfaf 100644 --- a/public/sass/components/_alerts.scss +++ b/public/sass/components/_alerts.scss @@ -2,18 +2,17 @@ // Alerts // -------------------------------------------------- - // Base styles // ------------------------- .alert { padding: 1.25rem 2rem 1.25rem 1.5rem; margin-bottom: $line-height-base; - text-shadow: 0 2px 0 rgba(255,255,255,.5); + text-shadow: 0 2px 0 rgba(255, 255, 255, 0.5); background: $alert-error-bg; position: relative; color: $white; - text-shadow: 0 1px 0 rgba(0,0,0,.2); + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); border-radius: 2px; display: flex; flex-direction: row; @@ -57,7 +56,7 @@ .fa { align-self: flex-end; font-size: 1.5rem; - color: rgba(255,255,255,.75) + color: rgba(255, 255, 255, 0.75); } } diff --git a/public/sass/components/_buttons.scss b/public/sass/components/_buttons.scss index 4be896d8ec0..c21ed30b0f4 100644 --- a/public/sass/components/_buttons.scss +++ b/public/sass/components/_buttons.scss @@ -14,7 +14,7 @@ text-align: center; vertical-align: middle; cursor: pointer; - border: $input-btn-border-width solid transparent; + border: none; @include button-size($btn-padding-y, $btn-padding-x, $font-size-base, $btn-border-radius); @@ -44,17 +44,28 @@ &[disabled], &:disabled { cursor: $cursor-disabled; - opacity: .65; + opacity: 0.65; @include box-shadow(none); } } // Button Sizes // -------------------------------------------------- +// XLarge +.btn-xlarge { + @include button-size($btn-padding-y-xl, $btn-padding-x-xl, $font-size-lg, $btn-border-radius); + font-weight: normal; + padding-bottom: $btn-padding-y-xl - 3; + .gicon { + font-size: 31px; + margin-right: 1rem; + } +} // Large .btn-large { @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $font-size-lg, $btn-border-radius); + font-weight: normal; } .btn-small { @@ -81,6 +92,7 @@ .btn-warning { @include buttonBackground($btn-warning-bg, $btn-warning-bg-hl); } + // Danger and error appear as red .btn-danger { @include buttonBackground($btn-danger-bg, $btn-danger-bg-hl); @@ -95,12 +107,16 @@ } // Inverse appears as dark gray .btn-inverse { - @include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color); + @include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color, $btn-inverse-text-shadow); //background: $card-background; box-shadow: $card-shadow; //border: 1px solid $tight-form-func-highlight-bg; } +.btn-transparent { + background-color: transparent; +} + .btn-outline-primary { @include button-outline-variant($btn-primary-bg); } @@ -124,11 +140,67 @@ @include box-shadow(none); cursor: default; - &:hover, &:active, &:active:hover, &:focus { + &:hover, + &:active, + &:active:hover, + &:focus { color: $gray-1; background-color: transparent; - border-color: $gray-1; + border-color: $gray-1; } } +// Extra padding +.btn-p-x-2 { + padding-left: 20px; + padding-right: 20px; +} +// External services +// Usage: +// + +$btn-service-icon-width: 35px; +.btn-service { + position: relative; +} + +@each $service, $data in $external-services { + $serviceBgColor: map-get($data, bgColor); + $serviceBorderColor: map-get($data, borderColor); + + .btn-service--#{$service} { + background-color: $serviceBgColor; + border: 1px solid $serviceBorderColor; + + .btn-service-icon { + font-size: 24px; // Override + border-right: 1px solid $serviceBorderColor; + } + } +} + +.btn-service-icon { + position: absolute; + left: 0; + height: 100%; + top: 0; + padding-left: 0.5rem; + padding-right: 0.5rem; + width: $btn-service-icon-width; + text-align: center; + + &::before { + position: relative; + top: 4px; + } +} + +.btn-service--grafanacom { + .btn-service-icon { + background-image: url(/public/img/grafana_mask_icon_white.svg); + background-repeat: no-repeat; + background-position: 50%; + background-size: 60%; + } +} diff --git a/public/sass/components/_cards.scss b/public/sass/components/_cards.scss index 6dba94494b1..11a8abb7640 100644 --- a/public/sass/components/_cards.scss +++ b/public/sass/components/_cards.scss @@ -1,10 +1,8 @@ .layout-selector { @include clearfix(); + margin-left: $spacer; text-align: right; - margin: 0 $spacer*1.5 $spacer; - position: relative; - top: -0.5rem; button { background: $input-label-bg; @@ -27,7 +25,7 @@ &:nth-child(2) { border-radius: 3px 0 0 3px; - border-right: 1px solid $panel-border; + border-right: $panel-border; } &:nth-child(1) { @@ -97,7 +95,7 @@ color: $text-color-weak; text-transform: uppercase; font-size: $font-size-sm; - font-weight: bold; + font-weight: $font-weight-semi-bold; } .card-item-notice { @@ -127,7 +125,6 @@ } .card-list-layout-grid { - .card-item-type { display: inline-block; } @@ -144,7 +141,7 @@ .card-item-wrapper { width: 100%; - padding: 0 1.5rem 1.5rem 0rem; + padding: 0 1rem 1rem 0rem; } .card-item-wrapper--clickable { @@ -158,6 +155,11 @@ img { width: 6rem; } + .fa, + .icon-gf, + .gicon { + font-size: 3.5rem; + } } .card-item-name { @@ -186,7 +188,6 @@ } .card-list-layout-list { - .card-item-wrapper { padding: 0; width: 100%; @@ -197,9 +198,8 @@ } .card-item { - border-bottom: .2rem solid $page-bg; - border-radius: 0; - box-shadow: none; + border-bottom: 3px solid $page-bg; + border-radius: 2px; } .card-item-header { diff --git a/public/sass/components/_code_editor.scss b/public/sass/components/_code_editor.scss index c9a6e94cf9c..79203e7898c 100644 --- a/public/sass/components/_code_editor.scss +++ b/public/sass/components/_code_editor.scss @@ -1,5 +1,5 @@ .gf-code-editor { - min-height: 2.60rem; + min-height: 2.6rem; min-width: 20rem; flex-grow: 1; margin-right: 0.25rem; @@ -7,7 +7,7 @@ &.ace_editor { @include font-family-monospace(); font-size: 1rem; - min-height: 2.60rem; + min-height: 2.6rem; @include border-radius($input-border-radius-sm); border: $input-btn-border-width solid $input-border-color; @@ -26,7 +26,9 @@ width: 550px !important; .ace_scroller { - .ace_selected, .ace_active-line, .ace_line-hover { + .ace_selected, + .ace_active-line, + .ace_line-hover { color: $dropdownLinkColorHover; background-color: $dropdownLinkBackgroundHover !important; } diff --git a/public/sass/components/_color_picker.scss b/public/sass/components/_color_picker.scss index 22c96398160..c0643342307 100644 --- a/public/sass/components/_color_picker.scss +++ b/public/sass/components/_color_picker.scss @@ -1,4 +1,3 @@ - .sp-replacer { background: inherit; border: none; @@ -6,7 +5,8 @@ padding: 0; } -.sp-replacer:hover, .sp-replacer.sp-active { +.sp-replacer:hover, +.sp-replacer.sp-active { border-color: inherit; color: inherit; } @@ -18,7 +18,8 @@ padding: 0; } -.sp-palette-container, .sp-picker-container { +.sp-palette-container, +.sp-picker-container { border: none; } diff --git a/public/sass/components/_dashboard_grid.scss b/public/sass/components/_dashboard_grid.scss new file mode 100644 index 00000000000..dd81a210409 --- /dev/null +++ b/public/sass/components/_dashboard_grid.scss @@ -0,0 +1,70 @@ +@import '~react-grid-layout-grafana/css/styles.css'; +@import '~react-resizable/css/styles.css'; + +.panel-in-fullscreen { + .react-grid-layout { + height: 100% !important; + } + + .react-grid-item { + display: none !important; + transition-property: none !important; + } + + .panel--fullscreen { + display: block !important; + position: unset !important; + width: 100% !important; + height: 100% !important; + transform: translate(0px, 0px) !important; + } +} + +@include media-breakpoint-down(sm) { + .react-grid-layout { + height: 100% !important; + } + + .react-grid-item { + display: none; + transition-property: none !important; + } + + .panel { + display: block !important; + position: unset !important; + width: 100% !important; + transform: translate(0px, 0px) !important; + margin-bottom: 1rem; + } +} + +.theme-dark { + .react-grid-item > .react-resizable-handle::after { + border-right: 2px solid $gray-1; + border-bottom: 2px solid $gray-1; + } +} + +.theme-light { + .react-grid-item > .react-resizable-handle::after { + border-right: 2px solid $gray-3; + border-bottom: 2px solid $gray-3; + } +} + +// Hack for preventing panel menu overlapping. +.react-grid-item.resizing.panel, +.react-grid-item.panel.dropdown-menu-open, +.react-grid-item.react-draggable-dragging.panel { + z-index: $zindex-dropdown; +} + +// Disable animation on initial rendering and enable it when component has been mounted. +.react-grid-item.cssTransforms.panel { + transition-property: none; +} + +.animated .react-grid-item.cssTransforms.panel { + transition-property: transform; +} diff --git a/public/sass/components/_dashboard_list.scss b/public/sass/components/_dashboard_list.scss new file mode 100644 index 00000000000..51603862db7 --- /dev/null +++ b/public/sass/components/_dashboard_list.scss @@ -0,0 +1,32 @@ +.dashboard-list { + .search-results-container { + padding: 5px 0 0 0; + } +} + +.search-results { + margin-top: 2rem; +} + +.search-results-filter-row { + height: 35px; + display: flex; + justify-content: space-between; + + .gf-form-button-row { + padding-top: 0; + + button:last-child { + margin-right: 0; + } + } +} + +.search-results-filter-row__filters { + display: flex; +} + +.search-results-filter-row__filters-item { + width: 150px; + margin-right: 0; +} diff --git a/public/sass/components/_dashboard_settings.scss b/public/sass/components/_dashboard_settings.scss new file mode 100644 index 00000000000..11d943eb13c --- /dev/null +++ b/public/sass/components/_dashboard_settings.scss @@ -0,0 +1,82 @@ +.dashboard-settings { + opacity: 0; + height: 100%; + display: flex; + flex-direction: row; +} + +.dashboard-page--settings-opening { + .dashboard-container { + display: none; + } +} + +.dashboard-page--settings-open { + .dashboard-settings { + opacity: 1; + transition: opacity 300ms ease-in-out; + } +} + +.dashboard-settings__content { + flex-grow: 1; + min-width: 0; + height: 100%; + padding: 30px; + max-width: 1100px; +} + +.dashboard-settings__aside { + padding: 27px 0 0 30px; + background: $panel-bg; + display: flex; + flex-direction: column; +} + +.dashboard-settings__aside-header { + color: $text-muted; + font-size: $font-size-h3; + padding-right: 60px; + white-space: nowrap; + margin-bottom: $spacer; + + i { + font-size: 25px; + position: relative; + top: 1px; + padding-right: 5px; + } +} + +.dashboard-settings__header { + font-size: $font-size-h3; + margin-bottom: $spacer*2; +} + +.dashboard-settings__nav-item { + padding: 7px 12px; + color: $text-color; + font-size: $font-size-md; + @include left-brand-border; + + &.active { + @include left-brand-border-gradient(); + background: $page-bg; + } + + i { + padding-right: 5px; + } +} + +.dashboard-settings__aside-actions { + display: flex; + flex-direction: column; + height: 100%; + flex-grow: 1; + margin: $spacer*3 $spacer*2 0 0; + + button { + margin-bottom: 10px; + } +} diff --git a/public/sass/components/_description-picker.scss b/public/sass/components/_description-picker.scss new file mode 100644 index 00000000000..30ca80cf18d --- /dev/null +++ b/public/sass/components/_description-picker.scss @@ -0,0 +1,11 @@ +.description-picker-option__button { + position: relative; + text-align: left; + width: 100%; + display: block; + border-radius: 0; + white-space: normal; + i.fa-check { + padding-left: 2px; + } +} diff --git a/public/sass/components/_drop.scss b/public/sass/components/_drop.scss index c1441bd31cb..6568414ed88 100644 --- a/public/sass/components/_drop.scss +++ b/public/sass/components/_drop.scss @@ -3,7 +3,7 @@ $color: inherit; $color: $text-color; $useDropShadow: false; $attachmentOffset: 0%; -$easing: cubic-bezier(0, 0, 0.265, 1.00); +$easing: cubic-bezier(0, 0, 0.265, 1); @include drop-theme("error", $popover-error-bg, $popover-color); @include drop-theme("popover", $popover-bg, $popover-color, $popover-border-color); @@ -22,9 +22,10 @@ $easing: cubic-bezier(0, 0, 0.265, 1.00); &.drop-open { display: block; } - } +} -.drop-element, .drop-element * { +.drop-element, +.drop-element * { box-sizing: border-box; } diff --git a/public/sass/components/_dropdown.scss b/public/sass/components/_dropdown.scss index 6031c05db3f..cc94a379e07 100644 --- a/public/sass/components/_dropdown.scss +++ b/public/sass/components/_dropdown.scss @@ -2,7 +2,6 @@ // Dropdown menus // -------------------------------------------------- - // Use the .menu class on any
  • element within the topbar or ul.tabs and you'll get some superfancy dropdowns .dropup, .dropdown { @@ -18,7 +17,7 @@ position: relative; top: -3px; width: 250px; - font-size: 80%; + font-size: $font-size-sm; margin-left: 22px; color: $gray-2; white-space: normal; @@ -31,10 +30,10 @@ width: 0; height: 0; vertical-align: top; - border-top: 4px solid $black; + border-top: 4px solid $text-color-weak; border-right: 4px solid transparent; - border-left: 4px solid transparent; - content: ""; + border-left: 4px solid transparent; + content: ''; } // Place the caret @@ -58,6 +57,7 @@ background-color: $dropdownBackground; border: 1px solid #ccc; // Fallback for IE7-8 border: 1px solid $dropdownBorder; + text-align: left; // Aligns the dropdown menu to right &.pull-right { @@ -85,11 +85,56 @@ white-space: nowrap; i { - padding-right: 5px; + display: inline-block; + margin-right: 10px; color: $link-color-disabled; + position: relative; + top: 3px; + } + + .gicon { + opacity: 0.9; } } } + + &--navbar { + top: 100%; + min-width: 100%; + } + + &--menu, + &--navbar, + &--sidemenu { + background: $menu-dropdown-bg; + box-shadow: $menu-dropdown-shadow; + margin-top: 0px; + border: none; + + > li > a { + display: flex; + padding: 5px 10px; + border-left: 2px solid transparent; + + &:hover { + @include left-brand-border-gradient(); + color: $link-hover-color; + background: $menu-dropdown-hover-bg !important; + } + } + } + + &--sidemenu { + li.sidemenu-org-switcher { + > a { + padding: 8px 10px 8px 15px; + } + } + } +} + +.dropdown-item-text { + flex-grow: 1; } // Hover/Focus state @@ -173,12 +218,12 @@ .caret { border-top: 0; border-bottom: 4px solid $black; - content: ""; + content: ''; } // Different positioning for bottom up menu .dropdown-menu { top: auto; - bottom: 100%; + bottom: 0; margin-bottom: 1px; } } @@ -192,7 +237,7 @@ .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; - margin-top: -6px; + margin-top: 0px; margin-left: -1px; @include border-radius(0 6px 6px 6px); } @@ -212,16 +257,16 @@ // Caret to indicate there is a submenu .dropdown-submenu > a::after { display: block; - content: " "; + content: ' '; float: right; width: 0; height: 0; border-color: transparent; border-style: solid; border-width: 5px 0 5px 5px; - border-left-color: darken($dropdownBackground, 20%); + border-left-color: $text-color-weak; margin-top: 5px; - margin-right: -10px; + margin-right: -4px; } .dropdown-submenu:hover > a::after { border-left-color: $dropdownLinkColorHover; @@ -252,26 +297,40 @@ // Typeahead // --------- .typeahead { - z-index: 1051; + z-index: $zindex-typeahead; margin-top: 2px; // give it some space to breathe } -.dropdown-menu-item-with-shortcut { - a { - min-width: 12rem; - } -} - .dropdown-menu-item-shortcut { display: block; - float: right; + margin-left: $spacer; color: $text-muted; + min-width: 47px; &::before { font-family: FontAwesome; width: 2rem; display: inline-block; text-align: center; - content: "\f11c"; + content: '\f11c'; + } +} + +.dropdown-menu.dropdown-menu--new { + li a { + padding: $spacer/2 $spacer; + border-left: 2px solid $side-menu-bg; + background: $side-menu-bg; + + i { + display: inline-block; + padding-right: 21px; + } + + &:hover { + @include left-brand-border-gradient(); + color: $link-hover-color; + background: $input-label-bg; + } } } diff --git a/public/sass/components/_empty_list_cta.scss b/public/sass/components/_empty_list_cta.scss new file mode 100644 index 00000000000..9c33cfb32d5 --- /dev/null +++ b/public/sass/components/_empty_list_cta.scss @@ -0,0 +1,24 @@ +.empty-list-cta { + background-color: $empty-list-cta-bg; + text-align: center; + padding: $spacer*2; + border-radius: $border-radius; + + .grafana-info-box { + max-width: 700px; + margin: 0 auto; + } +} + +.empty-list-cta__title { + padding-bottom: $spacer*3; + font-style: italic; +} + +.empty-list-cta__button { + margin-bottom: $spacer*3; +} + +.empty-list-cta__pro-tip-link { + margin-left: 5px; +} diff --git a/public/sass/components/_filter-controls.scss b/public/sass/components/_filter-controls.scss index 287bebe3757..f95e54b6abe 100644 --- a/public/sass/components/_filter-controls.scss +++ b/public/sass/components/_filter-controls.scss @@ -2,8 +2,6 @@ // FILTER CONTROLS // ========================================================================== - - // Filters // -------------------------------------------------------------------------- @@ -16,8 +14,6 @@ margin-top: 20px; } - - // Actions // -------------------------------------------------------------------------- diff --git a/public/sass/components/_filter-list.scss b/public/sass/components/_filter-list.scss index 045f4115dbc..7713aa05ac2 100644 --- a/public/sass/components/_filter-list.scss +++ b/public/sass/components/_filter-list.scss @@ -2,8 +2,6 @@ // FILTER LIST // ========================================================================== - - // List // -------------------------------------------------------------------------- @@ -23,8 +21,6 @@ } } - - // Card // -------------------------------------------------------------------------- @@ -57,7 +53,6 @@ padding: 5px 50px 5px 5px; } - .filter-list-card-status { color: #777; font-size: 12px; @@ -72,17 +67,17 @@ text-transform: uppercase; &.online { - background-image: url('/img/online.svg'); + background-image: url("/img/online.svg"); color: $online; } &.warn { - background-image: url('/img/warn-tiny.svg'); + background-image: url("/img/warn-tiny.svg"); color: $warn; } &.critical { - background-image: url('/img/critical.svg'); + background-image: url("/img/critical.svg"); color: $critical; } } diff --git a/public/sass/components/_filter-table.scss b/public/sass/components/_filter-table.scss index 65ca43cc6a9..00f9b93dcfd 100644 --- a/public/sass/components/_filter-table.scss +++ b/public/sass/components/_filter-table.scss @@ -2,8 +2,6 @@ // FILTER TABLE // ========================================================================== - - // Table // -------------------------------------------------------------------------- @@ -13,44 +11,77 @@ .filter-table { width: 100%; - border-collapse: collapse; - // table-layout: fixed; -} + border-collapse: separate; -.filter-table tr { - background: $grafanaListBackground; - border-bottom: 3px solid $page-bg; -} + tbody { + tr:nth-child(odd) { + background: $table-bg-odd; + } + } -.filter-table th { - width: auto; - padding: $table-cell-padding; - text-align: left; -} + th { + width: auto; + padding: $table-cell-padding; + text-align: left; + line-height: 30px; + height: 30px; + white-space: nowrap; + } -.filter-table td { - padding: $table-cell-padding; + td { + padding: $table-cell-padding; + line-height: 30px; + height: 30px; + white-space: nowrap; - &.filter-table__switch-cell { + &.filter-table__switch-cell { + padding: 0; + border-right: 3px solid $page-bg; + } + } + + .link-td { padding: 0; - border-right: 3px solid $page-bg; + line-height: 30px; + height: 30px; + white-space: nowrap; + + &.filter-table__switch-cell { + padding: 0; + border-right: 3px solid $page-bg; + } + + a { + display: block; + padding: $table-cell-padding; + } + } + + .ellipsis { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .expanded { + border-color: $panel-bg; + } + + .expanded > td { + padding-bottom: 0; + } + + .filter-table__avatar { + width: 25px; + height: 25px; + border-radius: 50%; + } + + &--hover { + tbody tr:hover { + background: $table-bg-hover; + } } } - -.filter-table .ellipsis { - display: block; - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.filter-table .expanded { - border-color: $panel-bg; -} - -.filter-table .expanded > td { - padding-bottom: 0; -} - - diff --git a/public/sass/components/_footer.scss b/public/sass/components/_footer.scss index 79c0e0178df..8b7d64e47fe 100644 --- a/public/sass/components/_footer.scss +++ b/public/sass/components/_footer.scss @@ -1,12 +1,13 @@ .page-dashboard .footer { - display: none; + display: none; } .footer { color: $footer-link-color; padding: 5rem 0 1rem 0; - font-size: $font-size-xs; - width: 98%; /* was causing horiz scrollbars - need to examine */ + font-size: $font-size-sm; + position: relative; + width: 98%; /* was causing horiz scrollbars - need to examine */ a { color: $footer-link-color; @@ -24,7 +25,7 @@ display: inline-block; padding-right: 2px; &::after { - content: ' | '; + content: " | "; padding-left: 2px; } } @@ -32,7 +33,14 @@ li:last-child { &::after { padding-left: 0; - content: ''; + content: ""; } } } + +.login-page { + .footer { + position: absolute; + bottom: $spacer; + } +} diff --git a/public/sass/components/_form_select_box.scss b/public/sass/components/_form_select_box.scss new file mode 100644 index 00000000000..beee2db15ab --- /dev/null +++ b/public/sass/components/_form_select_box.scss @@ -0,0 +1,106 @@ +$select-input-height: 35px; +$select-menu-max-height: 300px; +$select-item-font-size: $font-size-base; +$select-item-bg: $dropdownBackground; +$select-item-fg: $input-color; +$select-option-bg: $dropdownBackground; +$select-option-color: $input-color; +$select-noresults-color: $text-color; +$select-input-bg: $input-bg; +$select-input-border-color: $input-border-color; +$select-menu-box-shadow: $menu-dropdown-shadow; +$select-text-color: $text-color; +$select-input-bg-disabled: $input-bg-disabled; +$select-option-selected-bg: $dropdownLinkBackgroundActive; + +@import '../../../node_modules/react-select/scss/default.scss'; + +@mixin select-control() { + width: 100%; + margin-right: $gf-form-margin; + @include border-radius($input-border-radius-sm); + background-color: $input-bg; +} + +@mixin select-control-focus() { + border-color: $input-border-focus; + outline: none; + $shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px $input-box-shadow-focus; + @include box-shadow($shadow); +} + +// react-select tweaks +.gf-form-input--form-dropdown { + padding: 0; + border: 0; + overflow: visible; + + .Select-placeholder { + color: $input-color-placeholder; + } + + > .Select-control { + @include select-control(); + border-color: $dark-3; + + input { + min-width: 1rem; + } + + .Select-clear, + .Select-arrow { + margin-right: 8px; + } + + .Select-value { + display: inline-block; + padding: $input-padding-y $input-padding-x; + font-size: $font-size-md; + line-height: $input-line-height; + vertical-align: baseline; + white-space: nowrap; + } + } + + &.is-open > .Select-control { + background: transparent; + border-color: $dark-3; + } + + &.is-focused > .Select-control { + background-color: $input-bg; + @include select-control-focus(); + } + + &.is-focused:not(.is-open) > .Select-control { + background-color: $input-bg; + @include select-control-focus(); + } + + .Select-menu-outer { + border: 0; + width: auto; + } + + .Select-option.is-focused { + background-color: $dropdownLinkBackgroundHover; + color: $dropdownLinkColorHover; + + &::before { + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 2px; + display: block; + content: ''; + background-image: linear-gradient(to bottom, #ffd500 0%, #ff4400 99%, #ff4400 100%); + } + } +} + +.gf-form-input--form-dropdown-right { + .Select-menu-outer { + right: 0; + } +} diff --git a/public/sass/components/_gf-form.scss b/public/sass/components/_gf-form.scss index f11ddc3adcf..6603cfa072b 100644 --- a/public/sass/components/_gf-form.scss +++ b/public/sass/components/_gf-form.scss @@ -1,4 +1,5 @@ -$gf-form-margin: 0.25rem; +$gf-form-margin: 3px; +$input-border: 1px solid $input-border-color; .gf-form { margin-bottom: $gf-form-margin; @@ -7,7 +8,6 @@ $gf-form-margin: 0.25rem; align-items: center; text-align: left; position: relative; - font-size: $font-size-sm; &--offset-1 { margin-left: $spacer; @@ -20,12 +20,51 @@ $gf-form-margin: 0.25rem; &--flex-end { justify-content: flex-end; } + + &--alt { + flex-direction: column; + align-items: flex-start; + + .gf-form-label { + padding: 4px 0; + } + } +} + +.gf-form--has-input-icon { + position: relative; + margin-right: $gf-form-margin; + + .gf-form-input-icon { + position: absolute; + top: 50%; + margin-top: -9px; + font-size: $font-size-lg; + left: 10px; + color: $input-color-placeholder; + } + + > input { + padding-left: 35px; + + &:focus + .gf-form-input-icon { + color: $text-muted; + } + } + + .Select--multi .Select-multi-value-wrapper, + .Select-placeholder { + padding-left: 30px; + } } .gf-form-disabled { color: $text-color-weak; - .query-keyword, + .gf-form-select-wrapper::after { + color: $text-color-weak; + } + a, .gf-form-input { color: $text-color-weak; @@ -41,45 +80,58 @@ $gf-form-margin: 0.25rem; flex-direction: row; flex-wrap: wrap; align-content: flex-start; + + .gf-form + .gf-form { + margin-right: $gf-form-margin; + } } .gf-form-button-row { padding-top: $spacer * 1.5; - a, button { + a, + button { margin-right: $spacer; } } .gf-form-label { padding: $input-padding-y $input-padding-x; - margin-right: $gf-form-margin; flex-shrink: 0; + font-weight: $font-weight-semi-bold; + font-size: $font-size-sm; background-color: $input-label-bg; display: block; - font-size: $font-size-sm; - - border: $input-btn-border-width solid transparent; - @include border-radius($label-border-radius-sm); + border: $input-btn-border-width solid $input-label-border-color; + border-right: none; + border-radius: $label-border-radius; &--grow { flex-grow: 1; - min-height: 2.60rem; + min-height: 2.6rem; } &--error { color: $critical; } + + &:disabled { + color: $text-color-weak; + } +} + +.gf-form-label + .gf-form-label { + margin-right: $gf-form-margin; } .gf-form-pre { display: block; flex-grow: 1; - font-size: $font-size-sm; margin: 0; margin-right: $gf-form-margin; border: $input-btn-border-width solid transparent; + border-left: none; @include border-radius($label-border-radius-sm); } @@ -105,14 +157,14 @@ $gf-form-margin: 0.25rem; width: 100%; padding: $input-padding-y $input-padding-x; margin-right: $gf-form-margin; - font-size: $font-size-base; + font-size: $font-size-md; line-height: $input-line-height; color: $input-color; background-color: $input-bg; background-image: none; background-clip: padding-box; - border: $input-btn-border-width solid $input-border-color; - @include border-radius($input-border-radius-sm); + border: $input-border; + border-radius: $input-border-radius; @include box-shadow($input-box-shadow); white-space: nowrap; overflow: hidden; @@ -156,17 +208,20 @@ $gf-form-margin: 0.25rem; cursor: $cursor-disabled; } - &.gf-size-auto { width: auto; } + &.gf-size-auto { + width: auto; + } &--dropdown { padding-right: $input-padding-x*2; &::after { position: absolute; - top: 35%; - right: $input-padding-x; + top: 36%; + right: 11px; + font-size: 11px; background-color: transparent; - color: $input-color; + color: $text-color; font: normal normal normal $font-size-sm/1 FontAwesome; content: '\f0d7'; pointer-events: none; @@ -178,6 +233,10 @@ $gf-form-margin: 0.25rem; padding-bottom: 4px; font-size: $font-size-sm; } + + &--plaintext { + white-space: unset; + } } .gf-form-hint { @@ -195,12 +254,34 @@ $gf-form-margin: 0.25rem; position: relative; background-color: $input-bg; + .gf-form-select-icon { + position: absolute; + z-index: 1; + left: $input-padding-x; + top: 50%; + margin-top: -7px; + + & + .gf-form-input { + position: relative; + z-index: 2; + padding-left: $input-padding-x*3; + background-color: transparent; + + option { + // Firefox + color: $black; + } + } + } + + .gf-form-input { + margin-right: 0; + } + select.gf-form-input { - text-indent: .01px; + text-indent: 0.01px; text-overflow: ''; - padding-right: $input-padding-x*2; - -webkit-appearance: none; - -moz-appearance: menulist-text; // was set to "window" and caused odd display on windos and linux. + padding-right: $input-padding-x*3; appearance: none; &:-moz-focusring { @@ -216,13 +297,14 @@ $gf-form-margin: 0.25rem; &::after { position: absolute; - top: 35%; - right: $input-padding-x/2; + top: 36%; + right: 11px; background-color: transparent; - color: $input-color; + color: $text-color; font: normal normal normal $font-size-sm/1 FontAwesome; content: '\f0d7'; pointer-events: none; + font-size: 11px; } &--has-help-icon { @@ -241,15 +323,13 @@ $gf-form-margin: 0.25rem; margin-right: $gf-form-margin; line-height: $input-line-height; font-size: $font-size-sm; - box-shadow: none; - border: $input-btn-border-width solid transparent; flex-shrink: 0; flex-grow: 0; } .natural-language-input { - &input[type="number"] { + &input[type='number'] { font-size: $font-size-base; line-height: $input-line-height; margin: -6px -5px 0 5px; @@ -262,6 +342,8 @@ $gf-form-margin: 0.25rem; position: relative; background-color: $input-bg; padding-right: $input-padding-x; + border: $input-border; + border-radius: $input-border-radius; &::after { position: absolute; @@ -273,6 +355,10 @@ $gf-form-margin: 0.25rem; content: '\f0d7'; pointer-events: none; } + + .gf-form-input { + border: none; + } } .gf-form-help-icon { @@ -296,7 +382,7 @@ $gf-form-margin: 0.25rem; } &--header { - margin-bottom: $gf-form-margin + margin-bottom: $gf-form-margin; } } @@ -310,3 +396,17 @@ select.gf-form-input ~ .gf-form-help-icon { top: 10px; color: $text-muted; } + +.cta-form { + position: relative; + padding: 1rem; + background-color: $empty-list-cta-bg; + margin-bottom: 1rem; + border-top: 3px solid $green; +} + +.cta-form__close { + position: absolute; + right: 0; + top: 0; +} diff --git a/public/sass/components/_icon-picker.scss b/public/sass/components/_icon-picker.scss deleted file mode 100644 index 796f3f95db5..00000000000 --- a/public/sass/components/_icon-picker.scss +++ /dev/null @@ -1,26 +0,0 @@ -.gf-icon-picker { - width: 400px; - height: 450px; - - .icon-filter { - padding-bottom: 10px; - margin: auto; - width: 50%; - } - - .icon-container { - max-height: 350px; - overflow: auto; - - .gf-event-icon { - margin: 0.4rem; - height: 1.5rem; - } - } -} - -.gf-icon-picker-button { - .gf-event-icon { - height: 1.2rem; - } -} diff --git a/public/sass/components/_infobox.scss b/public/sass/components/_infobox.scss index 0d3cbcd52b8..9a6a2e78a4f 100644 --- a/public/sass/components/_infobox.scss +++ b/public/sass/components/_infobox.scss @@ -1,13 +1,3 @@ -// .grafana-info-box::before { -// content: "\f05a"; -// font-family:'FontAwesome'; -// position: absolute; -// top: -13px; -// left: -8px; -// font-size: 20px; -// color: $text-color; -// } - .grafana-info-box { position: relative; background: $info-box-background; @@ -17,6 +7,10 @@ margin-bottom: $spacer; margin-right: $gf-form-margin; flex-grow: 1; + color: $info-box-color; + h5 { + color: $info-box-color; + } h5 { margin-bottom: $spacer; diff --git a/public/sass/components/_json_explorer.scss b/public/sass/components/_json_explorer.scss index 37c610b2002..2b1be8bd4f5 100644 --- a/public/sass/components/_json_explorer.scss +++ b/public/sass/components/_json_explorer.scss @@ -1,8 +1,9 @@ - .json-formatter-row { font-family: monospace; - &, a, a:hover { + &, + a, + a:hover { color: $json-explorer-default-color; text-decoration: none; } @@ -16,9 +17,15 @@ opacity: 0.5; margin-left: 1rem; - &::after { display: none; } - &.json-formatter-object::after { content: "No properties"; } - &.json-formatter-array::after { content: "[]"; } + &::after { + display: none; + } + &.json-formatter-object::after { + content: "No properties"; + } + &.json-formatter-array::after { + content: "[]"; + } } } @@ -27,19 +34,33 @@ white-space: normal; word-wrap: break-word; } - .json-formatter-number { color: $json-explorer-number-color; } - .json-formatter-boolean { color: $json-explorer-boolean-color; } - .json-formatter-null { color: $json-explorer-null-color; } - .json-formatter-undefined { color: $json-explorer-undefined-color; } - .json-formatter-function { color: $json-explorer-function-color; } - .json-formatter-date { background-color: fade($json-explorer-default-color, 5%); } + .json-formatter-number { + color: $json-explorer-number-color; + } + .json-formatter-boolean { + color: $json-explorer-boolean-color; + } + .json-formatter-null { + color: $json-explorer-null-color; + } + .json-formatter-undefined { + color: $json-explorer-undefined-color; + } + .json-formatter-function { + color: $json-explorer-function-color; + } + .json-formatter-date { + background-color: fade($json-explorer-default-color, 5%); + } .json-formatter-url { text-decoration: underline; color: $json-explorer-url-color; cursor: pointer; } - .json-formatter-bracket { color: $json-explorer-bracket-color; } + .json-formatter-bracket { + color: $json-explorer-bracket-color; + } .json-formatter-key { color: $json-explorer-key-color; cursor: pointer; @@ -51,7 +72,9 @@ cursor: pointer; } - .json-formatter-array-comma { margin-right: 4px; } + .json-formatter-array-comma { + margin-right: 4px; + } .json-formatter-toggler { line-height: 1.2rem; @@ -71,7 +94,7 @@ // Inline preview on hover (optional) > a > .json-formatter-preview-text { opacity: 0; - transition: opacity .15s ease-in; + transition: opacity 0.15s ease-in; font-style: italic; } @@ -81,7 +104,7 @@ // Open state &.json-formatter-open { - > .json-formatter-toggler-link .json-formatter-toggler::after{ + > .json-formatter-toggler-link .json-formatter-toggler::after { transform: rotate(90deg); } > .json-formatter-children::after { @@ -95,4 +118,3 @@ } } } - diff --git a/public/sass/components/_jsontree.scss b/public/sass/components/_jsontree.scss index 011566f8731..665deda0f12 100644 --- a/public/sass/components/_jsontree.scss +++ b/public/sass/components/_jsontree.scss @@ -8,7 +8,8 @@ json-tree { &::before { pointer-events: none; } - &::before, & > .json-tree-key { + &::before, + & > .json-tree-key { cursor: pointer; } } @@ -23,7 +24,8 @@ json-tree { ul { padding-left: $spacer; } - li, ul { + li, + ul { list-style: none; } li { @@ -33,22 +35,23 @@ json-tree { color: $variable; padding: 5px 10px 5px 15px; &::after { - content: ':'; + content: ":"; } } json-node.expandable { &::before { - content: '\25b6'; + content: "\25b6"; position: absolute; left: 0px; font-size: 8px; - transition: transform .1s ease; + transition: transform 0.1s ease; } &.expanded::before { transform: rotate(90deg); } } - .json-tree-leaf-value, .json-tree-branch-preview { + .json-tree-leaf-value, + .json-tree-branch-preview { word-break: break-all; } .json-tree-branch-preview { @@ -56,6 +59,6 @@ json-tree { font-style: italic; max-width: 40%; height: 1.5em; - opacity: .7; + opacity: 0.7; } } diff --git a/public/sass/components/_modals.scss b/public/sass/components/_modals.scss index 42953f1d6a1..260c1c9fc4d 100644 --- a/public/sass/components/_modals.scss +++ b/public/sass/components/_modals.scss @@ -10,7 +10,7 @@ bottom: 0; left: 0; z-index: $zindex-modal-backdrop; - background-color: $black; + background-color: $modal-backdrop-bg; } .modal-backdrop, @@ -21,10 +21,9 @@ // Base modal .modal { position: fixed; - overflow: hidden; z-index: $zindex-modal; width: 100%; - background-color: $panel-bg; + background: $page-bg; @include box-shadow(0 3px 7px rgba(0,0,0,0.3)); @include background-clip(padding-box); outline: none; @@ -38,36 +37,41 @@ } .modal-header { - background-color: $body-bg; - @include brand-bottom-border(); - @include clearfix(); - - .gf-tabs-link.active { - background-color: $panel-bg; - } + background: $page-header-bg; + box-shadow: $page-header-shadow; + border-bottom: 1px solid $page-header-border-color; + @include clearfix(); } .modal-header-title { - font-style: italic; font-size: $font-size-h3; float: left; padding-top: $spacer * 0.75; margin: 0 $spacer*3 0 $spacer*1.5; + + .gicon { + position: relative; + top: -2px; + } } .modal-header-close { float: right; - padding: 0.75rem $spacer; + padding: 9px $spacer; } // Body (where all modal content resides) .modal-body { position: relative; - overflow-y: auto; } .modal-content { padding: $spacer*2; + + &--has-scroll { + max-height: calc(100vh - 400px); + position: relative; + } } // Remove bottom margin if need be @@ -78,7 +82,7 @@ // Footer (for actions) .modal-footer { padding: 14px 15px 15px; - border-top: 1px solid $panel-bg; + border-top: 1px solid $panel-bg; background-color: $panel-bg; text-align: right; // right align buttons @include clearfix(); // clear it in case folks use .pull-* classes on buttons @@ -140,7 +144,8 @@ .share-modal-big-icon { margin-bottom: 10px; margin-right: 2rem; - .fa, .icon-gf { + .fa, + .icon-gf { font-size: 50px; } } @@ -174,5 +179,3 @@ text-overflow: ellipsis; } } - - diff --git a/public/sass/components/_navbar.scss b/public/sass/components/_navbar.scss index 238e6111f87..1a453b15069 100644 --- a/public/sass/components/_navbar.scss +++ b/public/sass/components/_navbar.scss @@ -1,198 +1,167 @@ - .navbar { - display: block; - overflow: visible; position: relative; - z-index: 110; -} - -.navbar-inner { - min-height: $navbarHeight; + padding-left: 40px; + z-index: $zindex-navbar-fixed; + height: $navbarHeight; padding-right: $spacer; - background-color: $navbarBackground; + display: flex; + flex-grow: 1; + border-bottom: 1px solid transparent; + transition-duration: 350ms; + transition-timing-function: ease-in-out; + transition-property: box-shadow, border-bottom; +} + +@mixin navbar-alt-look() { + background: $page-header-bg; + box-shadow: $search-shadow; border-bottom: $navbarBorder; - @include clearfix(); } -.navbar .nav { - position: relative; - left: 0; - float: left; -} - -.navbar .nav.pull-right { - float: right; // redeclare due to specificity - margin-right: 0; // remove margin on float right nav -} - -.navbar .nav > li { - float: left; -} - -// Links -.navbar .nav > li > a { - float: none; - padding: 17px 13px 13px; - color: $navbarLinkColor; - text-decoration: none; - - .fa { font-size: 115%; } -} - -// Hover/focus -.navbar .nav > li > a:focus, -.navbar .nav > li > a:hover { - color: $navbarLinkColorHover; - text-decoration: none; -} - -// Active nav items -.navbar .nav > .active > a, -.navbar .nav > .active > a:hover, -.navbar .nav > .active > a:focus { - color: $navbarLinkColorActive; - text-decoration: none; - background-color: $navbarLinkBackgroundActive; -} - -.navbar-brand-btn { - display: block; - position: relative; - float: left; - margin: 0; - border-right: 1px solid $tight-form-border; - background-color: $navbarButtonBackground; - padding: 0.4rem 1.0rem 0.4rem 1rem; - min-height: $navbarHeight; - - .fa-caret-down { - font-size: 70%; +.dashboard-page--settings-open { + .navbar { + @include navbar-alt-look(); } - .fa-chevron-left{ + .navbar-button--add-panel, + .navbar-button--star, + .navbar-button--save, + .navbar-button--share, + .navbar-button--settings, + .navbar-page-btn .fa-caret-down, + .gf-timepicker-nav { display: none; } - &:hover { - background: $navbarButtonBackgroundHighlight; + .navbar-buttons--close { + display: flex; + } +} + +.panel-in-fullscreen { + .navbar { + @include navbar-alt-look(); } - img { - width: 30px; - position: relative; - top: -1px; - } - - .navbar-brand-btn-background { - display: inline-block; - border: 1px solid $body-bg; - padding: 4px; - border-radius: 50%; - background: $iconContainerBackground; - width: 40px; - height: 40px; - } - - .icon-gf-grafana_wordmark { - font-size: 21px; - position: relative; - top: 6px; - padding-left: 5px; + .navbar-button--add-panel, + .navbar-button--star, + .navbar-page-btn .fa-caret-down { display: none; } + + .navbar-buttons--close { + display: flex; + } } .navbar-page-btn { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; - float: left; display: block; margin: 0; - font-size: 1.4rem; - border-right: 1px solid $tight-form-border; color: darken($link-color, 5%); - background-color: $navbarButtonBackground; font-size: $font-size-lg; - padding: 1rem 1rem 0.75rem 1rem; + padding-left: 1rem; min-height: $navbarHeight; - - &:hover, &.active { - background: $navbarButtonBackgroundHighlight; - } + line-height: $navbarHeight; .fa-caret-down { font-size: 60%; padding-left: 0.2rem; } - .icon-gf { - position: relative; - top: 2px; - font-size: 20px; - line-height: 8px; - } - - > img { - max-width: 27px; - max-height: 27px; - } - &--search { padding: 1rem 1.5rem 0.75rem 1.5rem; } + + .gicon { + position: relative; + top: -1px; + font-size: 19px; + line-height: 8px; + opacity: 0.75; + margin-right: 8px; + // icon hidden on smaller screens + display: none; + } } -.navbar-page-btn-wrapper { +.navbar-buttons { + height: $navbarHeight; + display: flex; + align-items: center; + justify-content: flex-end; + margin-right: $spacer; + + &--close { + display: none; + margin-right: 0; + } +} + +.navbar__spacer { + flex-grow: 1; +} + +.navbar-button { + @include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color, $btn-inverse-text-shadow); + display: inline-block; - position: relative; -} + font-weight: $btn-font-weight; + padding: 6px 11px; + line-height: 16px; + color: $text-muted; + border: 1px solid $navbar-button-border; + margin-right: 3px; + white-space: nowrap; -.dropdown-menu.dropdown-menu--navbar { - top: 100%; - min-width: 100%; - margin-top: 0px; + .gicon { + font-size: 16px; + } - li a { - padding: $spacer/2 $spacer; - border-left: 2px solid $side-menu-bg; - background: $side-menu-bg; + .fa { + font-size: 16px; + } - i { - display: inline-block; - padding-right: 21px; - } + &--add-panel { + padding: 3px 10px; - &:hover { - @include left-brand-border-gradient(); - color: $link-hover-color; - background: $input-label-bg; + .gicon { + font-size: 22px; } } -} -.sidemenu-pinned { - .navbar-brand-btn { - width: $side-menu-width; + &--tight { + padding: 7px 4px; - .icon-gf-grafana_wordmark { - display: inline-block; - } - - .fa-caret-down { - display: none; - } - - &:hover .fa-chevron-left { - display: inline-block; - color: $text-color-weak; + .fa { + font-size: 14px; position: relative; - left: 1.3rem; + top: 2px; } } + + &--primary { + @include buttonBackground($btn-secondary-bg, $btn-secondary-bg-hl); + } } -.navbar-section-wrapper { - position: relative; - float: left; +@include media-breakpoint-up(sm) { + .navbar { + padding-left: 50px; + } + + .sidemenu-open { + .navbar { + padding-left: 15px; + margin-left: 0; + } + } + + .navbar-page-btn { + .gicon { + display: inline-block; + } + } } diff --git a/public/sass/components/_navs.scss b/public/sass/components/_navs.scss index abbb4ba5042..796e84fc124 100644 --- a/public/sass/components/_navs.scss +++ b/public/sass/components/_navs.scss @@ -2,7 +2,6 @@ // Navs // -------------------------------------------------- - // BASE CLASS // ---------- @@ -55,7 +54,7 @@ // Actual tabs (as links) .nav-tabs > li > a { - padding: 0.40rem 1rem 0.35rem 1rem; + padding: 0.4rem 1rem 0.35rem 1rem; margin-right: $spacer/2; line-height: $line-height-base; border: 1px solid transparent; diff --git a/public/sass/components/_old_stuff.scss b/public/sass/components/_old_stuff.scss index ccc56377748..80f2b96dc0d 100644 --- a/public/sass/components/_old_stuff.scss +++ b/public/sass/components/_old_stuff.scss @@ -1,4 +1,3 @@ - .editor-row { vertical-align: top; } diff --git a/public/sass/components/_page_header.scss b/public/sass/components/_page_header.scss new file mode 100644 index 00000000000..a7380327bd0 --- /dev/null +++ b/public/sass/components/_page_header.scss @@ -0,0 +1,171 @@ +.page-header-canvas { + background: $page-header-bg; + box-shadow: $page-header-shadow; + border-bottom: 1px solid $page-header-border-color; +} + +.page-header { + padding: 2.5rem 0 0 0; + + .btn { + float: right; + margin-left: 1rem; + + // better align icons + .fa { + position: relative; + top: 1px; + } + } +} + +.page-header__inner { + flex-grow: 1; + display: flex; + margin-bottom: 2.5rem; +} + +.page-header__title { + font-size: $font-size-h2; + margin-bottom: 1px; + padding-top: $spacer; +} + +.page-header__img { + position: relative; + top: 10px; + height: 50px; +} + +.page-header__icon { + font-size: 50px; + width: 50px; + height: 50px; + position: relative; + + &.fa { + top: 10px; + } + + &.gicon { + top: 10px; + } + + &.icon-gf { + top: 3px; + } +} + +.page-header__logo { + margin: 0 $spacer; +} + +.page-header__sub-title { + color: $text-muted; +} + +.page-header-stamps-type { + color: $link-color-disabled; + text-transform: uppercase; +} + +.page-header__select-nav { + margin-bottom: 10px; + max-width: 100%; + + @include media-breakpoint-up(lg) { + display: none; + } +} + +.page-header__tabs { + display: none; + @include media-breakpoint-up(lg) { + display: block; + } +} + +.page-breadcrumbs { + display: flex; + padding: 10px 0; + line-height: 0.5; +} + +.breadcrumb { + display: inline-block; + box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.35); + overflow: hidden; + border-radius: 5px; + counter-reset: flag; +} + +.breadcrumb-item { + @include gradientBar($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color); + + text-decoration: none; + outline: none; + display: block; + float: left; + font-size: 12px; + line-height: 30px; + padding: 0 7px 0 37px; + position: relative; + box-shadow: $card-shadow; + + &:first-child { + padding-left: 10px; + border-radius: 5px 0 0 5px; /*to match with the parent's radius*/ + font-size: 18px; + } + + &:first-child::before { + left: 14px; + } + + &:last-child { + border-radius: 0 5px 5px 0; /*this was to prevent glitches on hover*/ + padding-right: 20px; + } + + &.active, + &:hover { + background: #333; + background: linear-gradient(#333, #000); + } + + &.active::after, + &:hover::after { + background: #333; + background: linear-gradient(135deg, #333, #000); + } + + &::after { + content: ''; + position: absolute; + top: 0; + right: -14px; // half of square's length + + // same dimension as the line-height of .breadcrumb-item + width: 30px; + height: 30px; + + transform: scale(0.707) rotate(45deg); + // we need to prevent the arrows from getting buried under the next link + z-index: 1; + + // background same as links but the gradient will be rotated to compensate with the transform applied + background: linear-gradient(135deg, $btn-inverse-bg, $btn-inverse-bg-hl); + + // stylish arrow design using box shadow + box-shadow: 2px -2px 0 2px rgb(35, 31, 31), 3px -3px 0 2px rgba(255, 255, 255, 0.1); + + // 5px - for rounded arrows and + // 50px - to prevent hover glitches on the border created using shadows*/ + border-radius: 0 5px 0 50px; + } + + // we dont need an arrow after the last link + &:last-child::after { + content: none; + } +} diff --git a/public/sass/components/_panel_add_panel.scss b/public/sass/components/_panel_add_panel.scss new file mode 100644 index 00000000000..51754a54d92 --- /dev/null +++ b/public/sass/components/_panel_add_panel.scss @@ -0,0 +1,79 @@ +.add-panel { + height: 100%; +} + +.add-panel__header { + padding: 5px 15px; + display: flex; + align-items: center; + + .gicon { + font-size: 30px; + margin-right: $spacer; + } +} + +.add-panel__close { + margin-left: auto; + background-color: transparent; + border: 0; + font-size: 16px; + margin-right: -10px; +} + +.add-panel__title { + font-size: $font-size-md; + margin-right: $spacer/2; +} + +.add-panel__sub-title { + font-style: italic; + color: $text-muted; + position: relative; + top: 1px; +} + +.add-panel__items { + padding: 3px 8px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + overflow: auto; + height: calc(100% - 43px); + align-content: flex-start; + justify-content: space-around; + position: relative; +} + +.add-panel__item { + background: $card-background; + box-shadow: $card-shadow; + + border-radius: 3px; + padding: $spacer/3 $spacer; + width: 31%; + height: 60px; + text-align: center; + margin: $gf-form-margin; + cursor: pointer; + + &.active, + &:hover { + background: $card-background-hover; + } +} + +.add-panel__item-name { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + font-size: $font-size-sm; +} + +.add-panel__item-img { + height: calc(100% - 15px); +} + +.add-panel__item-icon { + padding: 2px; +} diff --git a/public/sass/components/_panel_alertlist.scss b/public/sass/components/_panel_alertlist.scss index f124c0c4b8c..c5d76c2f3b1 100644 --- a/public/sass/components/_panel_alertlist.scss +++ b/public/sass/components/_panel_alertlist.scss @@ -9,4 +9,3 @@ width: 100%; height: calc(100% - 30px); } - diff --git a/public/sass/components/_panel_dashlist.scss b/public/sass/components/_panel_dashlist.scss index 40b78166b1e..193484db713 100644 --- a/public/sass/components/_panel_dashlist.scss +++ b/public/sass/components/_panel_dashlist.scss @@ -5,26 +5,21 @@ .dashlist-section { margin-bottom: $spacer; + padding-top: 3px; } .dashlist-link { - display: block; - margin: 5px; - padding: 7px; - background-color: $tight-form-bg; + @include list-item(); + .fa { padding-top: 3px; } + .dashlist-star { float: right; } + .fa-star { color: $orange; } - - &:hover { - background-color: $tight-form-func-bg; - } } - - diff --git a/public/sass/components/_panel_gettingstarted.scss b/public/sass/components/_panel_gettingstarted.scss index d5a231a220c..1fb3eda1834 100644 --- a/public/sass/components/_panel_gettingstarted.scss +++ b/public/sass/components/_panel_gettingstarted.scss @@ -1,19 +1,17 @@ - // Colours -$progress-color-dark: $panel-bg !default; -$progress-color: $panel-bg !default; -$progress-color-light: $panel-bg !default; +$progress-color-dark: $panel-bg !default; +$progress-color: $panel-bg !default; +$progress-color-light: $panel-bg !default; $progress-color-grey-light: $body-bg !default; -$progress-color-shadow: $panel-border !default; -$progress-color-grey: $iconContainerBackground !default; -$progress-color-grey-dark: $iconContainerBackground !default; +$progress-color-shadow: $panel-border !default; +$progress-color-grey: $iconContainerBackground !default; +$progress-color-grey-dark: $iconContainerBackground !default; // Sizing -$marker-size: 60px !default; -$marker-size-half: ($marker-size / 2); -$path-height: 2px !default; -$path-position: $marker-size-half - ($path-height / 2); - +$marker-size: 60px !default; +$marker-size-half: ($marker-size / 2); +$path-height: 2px !default; +$path-position: $marker-size-half - ($path-height / 2); .dashlist-cta-close-btn { color: $text-color-weak; @@ -35,7 +33,7 @@ $path-position: $marker-size-half - ($path-height / 2); // Container element .progress-tracker { display: flex; - margin: 20px auto; + margin: 0 auto; padding: 0; list-style: none; } @@ -52,9 +50,9 @@ $path-position: $marker-size-half - ($path-height / 2); // For a flexbox bug in firefox that wont allow the text overflow on the text min-width: $marker-size; - &::after { + &::after { right: -50%; - content: ''; + content: ""; display: block; position: absolute; z-index: 1; @@ -96,7 +94,7 @@ $path-position: $marker-size-half - ($path-height / 2); -webkit-text-fill-color: transparent; background: $brand-gradient; -webkit-background-clip: text; - text-decoration:none; + text-decoration: none; } } } @@ -154,17 +152,18 @@ $path-position: $marker-size-half - ($path-height / 2); .progress-marker { color: $text-color-weak; - text-decoration:none; + text-decoration: none; font-size: 35px; vertical-align: sub; } a.progress-link { &:hover { - .progress-marker, .progress-text { + .progress-marker, + .progress-text { color: $link-hover-color; } - &:hover .progress-marker.completed { + &:hover .progress-marker.completed { color: $online; } } diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index c92e5a0d3d0..716778096d6 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -1,10 +1,35 @@ -.graph-canvas-wrapper { - position: relative; - cursor: crosshair; +.graph-panel { + display: flex; + flex-direction: column; + height: 100%; + + &--legend-right { + flex-direction: row; + + .graph-legend { + flex: 0 1 10px; + max-height: 100%; + } + + .graph-legend-series { + display: block; + padding-left: 0px; + } + + .graph-legend-table { + width: auto; + } + + .graph-legend-table .graph-legend-series { + display: table-row; + } + } } -.histogram-chart { +.graph-panel__chart { position: relative; + cursor: crosshair; + flex-grow: 1; } .datapoints-warning { @@ -22,11 +47,12 @@ } .graph-legend { - @include clearfix(); - margin: 0 $spacer; + flex: 0 1 auto; + max-height: 30%; + margin: 0; text-align: center; - width: calc(100% - $spacer); padding-top: 6px; + position: relative; .popover-content { padding: 0; @@ -48,19 +74,19 @@ font-size: 85%; text-align: left; &.current::before { - content: "Current: " + content: 'Current: '; } &.max::before { - content: "Max: " + content: 'Max: '; } &.min::before { - content: "Min: " + content: 'Min: '; } &.total::before { - content: "Total: " + content: 'Total: '; } &.avg::before { - content: "Avg: " + content: 'Avg: '; } } @@ -84,12 +110,24 @@ padding-left: 6px; } +// fix for phantomjs +.body--phantomjs { + .graph-panel--legend-right { + .graph-legend-table { + display: table; + } + } +} + .graph-legend-table { tbody { display: block; overflow-y: auto; overflow-x: hidden; + height: 100%; padding-bottom: 1px; + padding-right: 5px; + padding-left: 5px; } .graph-legend-series { @@ -107,8 +145,10 @@ } } - - td, .graph-legend-alias, .graph-legend-icon, .graph-legend-value { + td, + .graph-legend-alias, + .graph-legend-icon, + .graph-legend-value { float: none; display: table-cell; white-space: nowrap; @@ -125,7 +165,7 @@ } } - .graph-legend-value { + .graph-legend-value { padding-left: 15px; } @@ -139,11 +179,15 @@ } .graph-legend-series:nth-child(odd) { - background-color: $grafanaListAccent; + background: $table-bg-accent; } .graph-legend-value { - &.current, &.max, &.min, &.total, &.avg { + &.current, + &.max, + &.min, + &.total, + &.avg { &::before { content: ''; } @@ -160,40 +204,6 @@ } } -.graph-legend-rightside { - - &.graph-wrapper { - display: table; - width: 100%; - } - - .graph-canvas-wrapper { - display: table-cell; - width: 100%; - position: relative; - } - - .graph-legend-wrapper { - display: table-cell; - vertical-align: top; - position: relative; - left: 4px; - } - - .graph-legend { - margin: 0 0 0 1rem; - } - - .graph-legend-series { - display: block; - padding-left: 0px; - } - - .graph-legend-table .graph-legend-series { - display: table-row; - } -} - .graph-legend-series-hidden { .graph-legend-value, .graph-legend-alias { @@ -202,7 +212,7 @@ } .graph-legend-popover { - width: 200px; + width: 210px; label { display: inline-block; } @@ -261,7 +271,7 @@ max-width: 650px; text-overflow: ellipsis; overflow: hidden; - } + } .graph-tooltip-value { display: table-cell; @@ -272,7 +282,6 @@ } .graph-annotation { - .label-tag { margin-right: 4px; margin-top: 8px; @@ -405,7 +414,7 @@ } } - &--T0{ + &--T0 { right: -104px; width: 129px; @@ -428,10 +437,10 @@ position: relative; &--critical { - background-color: rgba(237, 46, 24, 0.60); + background-color: rgba(237, 46, 24, 0.6); } &--warning { - background-color: rgba(247, 149, 32, 0.60); + background-color: rgba(247, 149, 32, 0.6); } } } diff --git a/public/sass/components/_panel_heatmap.scss b/public/sass/components/_panel_heatmap.scss index 134186f25a2..279b9392caa 100644 --- a/public/sass/components/_panel_heatmap.scss +++ b/public/sass/components/_panel_heatmap.scss @@ -1,3 +1,5 @@ +$font-size-heatmap-tick: 11px; + .heatmap-canvas-wrapper { // position: relative; cursor: crosshair; @@ -10,7 +12,7 @@ text { fill: $text-color; color: $text-color; - font-size: $font-size-sm; + font-size: $font-size-heatmap-tick; } line { @@ -42,7 +44,7 @@ .heatmap-crosshair { line { - stroke: darken($red,15%); + stroke: darken($red, 15%); stroke-width: 1; } } @@ -56,12 +58,12 @@ .heatmap-legend-wrapper { @include clearfix(); margin: 0 $spacer; - padding-top: 10px; + padding-top: 4px; svg { width: 100%; max-width: 300px; - height: 33px; + height: 18px; float: left; white-space: nowrap; padding-left: 10px; @@ -75,7 +77,7 @@ text { fill: $text-color; color: $text-color; - font-size: $font-size-sm; + font-size: $font-size-heatmap-tick; } line { diff --git a/public/sass/components/_panel_pluginlist.scss b/public/sass/components/_panel_pluginlist.scss index 605e1afdb6a..a51748a984d 100644 --- a/public/sass/components/_panel_pluginlist.scss +++ b/public/sass/components/_panel_pluginlist.scss @@ -8,14 +8,7 @@ } .pluginlist-link { - display: block; - margin: 5px; - padding: 7px; - background-color: $tight-form-bg; - - &:hover { - background-color: $tight-form-func-bg; - } + @include list-item(); } .pluginlist-icon { @@ -25,7 +18,7 @@ } .pluginlist-image { - width: 20px; + width: 17px; } .pluginlist-title { @@ -43,14 +36,14 @@ } .pluginlist-message--update { - &:hover { + &:hover { border-bottom: 1px solid $text-color; } } -.pluginlist-message--enable{ +.pluginlist-message--enable { color: $external-link-color; - &:hover { + &:hover { border-bottom: 1px solid $external-link-color; } } diff --git a/public/sass/components/_panel_singlestat.scss b/public/sass/components/_panel_singlestat.scss index 48d0a29f4b8..33a956a0244 100644 --- a/public/sass/components/_panel_singlestat.scss +++ b/public/sass/components/_panel_singlestat.scss @@ -2,9 +2,11 @@ position: relative; display: table; width: 100%; + height: 100%; } .singlestat-panel-value-container { + line-height: 1; display: table-cell; vertical-align: middle; text-align: center; @@ -18,37 +20,6 @@ padding-right: 20px; } -.singlestat-panel-table { - width: 100%; - td { - padding: 5px 10px; - white-space: nowrap; - text-align: right; - border-bottom: 1px solid $grafanaListBorderBottom; - } - - th { - text-align: right; - padding: 5px 10px; - font-weight: bold; - color: $blue - } - - td:first-child { - text-align: left; - } - - tr:nth-child(odd) td { - background-color: $grafanaListAccent; - } - - tr:last-child td { - border: none; - } -} - #flotGagueValue0 { font-weight: bold; //please dont hurt me for this! } - - diff --git a/public/sass/components/_panel_table.scss b/public/sass/components/_panel_table.scss index 77652bc634d..f120fcc8b35 100644 --- a/public/sass/components/_panel_table.scss +++ b/public/sass/components/_panel_table.scss @@ -27,9 +27,11 @@ margin-left: 0; margin-bottom: 0; } + ul > li { display: inline; // Remove list-style and block-level defaults } + ul > li > a { float: left; // Collapse white-space padding: 4px 12px; @@ -109,10 +111,10 @@ } .table-panel-header-bg { - background: $grafanaListAccent; + background: $list-item-bg; border-top: 2px solid $body-bg; border-bottom: 2px solid $body-bg; - height: 2.0em; + height: 2em; position: absolute; top: 0; right: 0; diff --git a/public/sass/components/_popper.scss b/public/sass/components/_popper.scss new file mode 100644 index 00000000000..0b28d5b21f4 --- /dev/null +++ b/public/sass/components/_popper.scss @@ -0,0 +1,86 @@ +.popper { + position: absolute; + z-index: $zindex-tooltip; + background: $tooltipBackground; + color: $tooltipColor; + max-width: 400px; + border-radius: 3px; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); + padding: 10px; + text-align: center; +} + +.popper .popper__arrow { + width: 0; + height: 0; + border-style: solid; + position: absolute; + margin: 5px; +} + +.popper .popper__arrow { + border-color: $tooltipBackground; +} + +.popper[data-placement^='top'] { + margin-bottom: 5px; +} + +.popper[data-placement^='top'] .popper__arrow { + border-width: 5px 5px 0 5px; + border-left-color: transparent; + border-right-color: transparent; + border-bottom-color: transparent; + bottom: -5px; + left: calc(50% - 5px); + margin-top: 0; + margin-bottom: 0; +} + +.popper[data-placement^='bottom'] { + margin-top: 5px; +} + +.popper[data-placement^='bottom'] .popper__arrow { + border-width: 0 5px 5px 5px; + border-left-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + top: -5px; + left: calc(50% - 5px); + margin-top: 0; + margin-bottom: 0; +} +.popper[data-placement^='right'] { + margin-left: 5px; +} +.popper[data-placement^='right'] .popper__arrow { + border-width: 5px 5px 5px 0; + border-left-color: transparent; + border-top-color: transparent; + border-bottom-color: transparent; + left: -5px; + top: calc(50% - 5px); + margin-left: 0; + margin-right: 0; +} + +.popper[data-placement^='left'] { + margin-right: 5px; +} + +.popper[data-placement^='left'] .popper__arrow { + border-width: 5px 0 5px 5px; + border-top-color: transparent; + border-right-color: transparent; + border-bottom-color: transparent; + right: -5px; + top: calc(50% - 5px); + margin-left: 0; + margin-right: 0; +} + +.popper__target, +.popper__manager { + display: inline-block; +} diff --git a/public/sass/components/_query_editor.scss b/public/sass/components/_query_editor.scss index 2442505b5b6..6b2860d57bf 100644 --- a/public/sass/components/_query_editor.scss +++ b/public/sass/components/_query_editor.scss @@ -1,6 +1,12 @@ .query-keyword { - font-weight: bold; - color: $blue; + font-weight: $font-weight-semi-bold; + color: $query-blue; +} + +.gf-form-disabled { + .query-keyword { + color: darken($query-blue, 20%); + } } .query-segment-operator { @@ -27,6 +33,10 @@ .gf-form-label { margin-right: 2px; } + + .gf-form + .gf-form { + margin-right: 0; + } } .gf-form-query-content { @@ -53,7 +63,7 @@ } .gf-form-query-letter-cell-letter { font-weight: bold; - color: $blue; + color: $query-blue; } .gf-form-query-letter-cell-ds { color: $text-color-weak; @@ -79,7 +89,8 @@ } } -input[type="text"].tight-form-func-param { +input[type='text'].tight-form-func-param { + font-size: 0.875rem; background: transparent; border: none; margin: 0; @@ -119,32 +130,6 @@ input[type="text"].tight-form-func-param { } } -input[type="text"].tight-form-func-param { - background: transparent; - border: none; - margin: 0; - padding: 0; -} - -.tight-form-func-controls { - display: none; - text-align: center; - - .fa-arrow-left { - float: left; - position: relative; - top: 2px; - } - .fa-arrow-right { - float: right; - position: relative; - top: 2px; - } - .fa-remove { - margin-left: 10px; - } -} - .query-troubleshooter { font-size: $font-size-sm; margin: $gf-form-margin; @@ -166,3 +151,34 @@ input[type="text"].tight-form-func-param { .query-troubleshooter__body { padding: $spacer 0; } + +.rst-text::before { + content: ' '; +} + +.rst-unknown.rst-directive { + font-family: monospace; + margin-bottom: 1rem; +} + +.rst-interpreted_text { + font-family: monospace; + display: inline; +} + +.rst-bullet-list { + padding-left: 1.5rem; + margin-bottom: 1rem; +} + +.rst-paragraph:last-child { + margin-bottom: 0; +} + +.drop-element.drop-popover.drop-function-def .drop-content { + max-width: 30rem; +} + +.rst-literal-block .rst-text { + display: block; +} diff --git a/public/sass/components/_query_part.scss b/public/sass/components/_query_part.scss index 1e2fb9622c2..e5ad043788f 100644 --- a/public/sass/components/_query_part.scss +++ b/public/sass/components/_query_part.scss @@ -1,11 +1,17 @@ - .query-part { - background-color: $input-bg !important; + background-color: lighten($input-label-bg, 5%); &.show-function-controls { padding-top: 5px; min-width: 100px; text-align: center; } -} + .query-part__last { + display: none; + } + + &:hover .query-part__last { + display: inline; + } +} diff --git a/public/sass/components/_row.scss b/public/sass/components/_row.scss index 0cdc3428f3e..3c1465a30bc 100644 --- a/public/sass/components/_row.scss +++ b/public/sass/components/_row.scss @@ -1,167 +1,78 @@ - -.dash-row { - display: block; +.dashboard-row { display: flex; - flex-direction: column; - position: relative; + align-items: center; - &--collapse { - .dash-row-header { - background: $panel-bg; - border: $panel-border; - margin-bottom: $panel-margin*2; - } - } -} + height: 100%; -.dash-row-header { - position: relative; - display: flex; - flex-direction: row; - margin-right: $panel-margin; - margin-left: 0; + &--collapsed { + background: $panel-bg; - .h1 { font-size: 2.7rem; font-style: normal; line-height: 4rem; font-weight: 300; } - .h2 { font-size: 2.4rem; line-height: 3.5rem; font-weight: 300; } - .h3 { font-size: 2.0rem; line-height: 3rem; font-weight: 300;} - .h4 { font-size: 1.7rem; font-weight: 300;} - .h5 { font-size: 1.4rem; font-weight: 300;} - .h6 { font-size: 1rem; font-weight: 300; } -} - -.dash-row-header-title { - padding: 0.6rem; - flex-grow: 1; - - .dash-row-collapse-toggle { - padding: 0 2px; - font-size: $font-size-xs; - color: $text-muted; - position: relative; - left: -3px; - top: -1px; - } - - &:hover { - .dash-row-collapse-toggle { - color: $link-color; - } - } -} - -.panels-wrapper { - flex-grow: 1; - position: relative; -} - -.dash-row-dropview { - position: relative; - background: $panel-bg; - border: $panel-border; - margin: 0 $panel-margin $panel-margin*2 $panel-margin; - padding: $panel-margin*2; - display: flex; - flex-direction: row; -} - -.dash-row-dropview-close { - position: absolute; - right: -12px; - top: -10px; - width: 20px; - height: 20px; -} - -.add-panel-panels { - display: flex; - flex-direction: row; - flex-wrap: wrap; -} - -.add-panel-item { - background: $input-label-bg; - border: $panel-border; - padding: $spacer/3 $spacer; - min-width: 9rem; - max-width: 9rem; - text-align: center; - margin: $gf-form-margin; - cursor: pointer; - - &.active, - &:hover { - box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 1px rgba(82,168,236,5.8) - } -} - -.add-panel-item-name { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - font-size: $font-size-sm; -} - -.add-panel-item-img { - width: 2rem; -} - -$dash-row-menu-animation-speed: 0.20s; - -.dash-row-menu-container { - position: absolute; - top: 0px; - width: 138px; - min-height: 100%; - transform: translate(-131px, 0); - transition: 0.1s ease-out 0.4s; - z-index: 99; - display: flex; - flex-direction: row; - - &:hover { - transform: translate(-$panel-margin, 0); - transition: $dash-row-menu-animation-speed ease-in 0.05s; - z-index: 101; - - .dash-row-menu-grip { - opacity: 0; - transition: $dash-row-menu-animation-speed ease-in 0.05s; - } - } -} - -.dash-row-menu { - list-style: none; - flex-grow: 1; - box-shadow: $search-shadow; - background: $side-menu-bg; - - li a { - display: block; - white-space: nowrap; - color: $text-muted; - font-size: $font-size-sm; - padding: $spacer/2 $spacer; - border-left: 2px solid $side-menu-bg; - i { + .dashboard-row__panel_count { display: inline-block; - padding-right: $spacer/2; } + .dashboard-row__drag, + .dashboard-row__actions { + visibility: visible; + opacity: 1; + } + } + + &:hover { + .dashboard-row__actions { + visibility: visible; + opacity: 1; + } + } +} + +.dashboard-row__title { + flex-grow: 0; + font-size: 1.15rem; + font-weight: $font-weight-semi-bold; + color: $text-color; + + .fa { + color: $text-muted; + font-size: $font-size-xs; + padding: 0 0.5rem; + } +} + +.dashboard-row__actions { + color: $text-muted; + visibility: hidden; + opacity: 0; + flex-grow: 1; + transition: 200ms opacity ease-in 200ms; + + a { + color: $text-color-weak; + padding-left: $spacer; + &:hover { - @include left-brand-border-gradient(); - color: $link-color; - background: $input-label-bg; + color: $link-hover-color; } } } -.dash-row-menu-grip { - text-align: center; - font-size: 130%; - color: $text-color-faint; - opacity: 1; - transition: $dash-row-menu-animation-speed ease-out 0.5s; - width: 1rem; +.dashboard-row__panel_count { + padding-left: $spacer; + color: $text-color-weak; + font-style: italic; + font-size: $font-size-sm; + font-weight: normal; + display: none; } +.dashboard-row__drag { + cursor: move; + width: 1rem; + height: 100%; + background: url("../img/grab_dark.svg") no-repeat 50% 50%; + background-size: 8px; + visibility: hidden; + position: absolute; + top: 0; + right: 0; +} diff --git a/public/sass/components/_scrollbar.scss b/public/sass/components/_scrollbar.scss index 85227625a8d..42818e786f6 100644 --- a/public/sass/components/_scrollbar.scss +++ b/public/sass/components/_scrollbar.scss @@ -1,4 +1,106 @@ -// +/* + * Container style + */ +.ps { + overflow: hidden !important; + overflow-anchor: none; + -ms-overflow-style: none; + touch-action: auto; + -ms-touch-action: auto; +} + +/* + * Scrollbar rail styles + */ +.ps__rail-x { + display: none; + opacity: 0; + transition: background-color 0.2s linear, opacity 0.2s linear; + -webkit-transition: background-color 0.2s linear, opacity 0.2s linear; + height: 15px; + /* there must be 'bottom' or 'top' for ps__rail-x */ + bottom: 0px; + /* please don't change 'position' */ + position: absolute; +} + +.ps__rail-y { + display: none; + opacity: 0; + transition: background-color 0.2s linear, opacity 0.2s linear; + -webkit-transition: background-color 0.2s linear, opacity 0.2s linear; + width: 15px; + /* there must be 'right' or 'left' for ps__rail-y */ + right: 0; + /* please don't change 'position' */ + position: absolute; +} + +.ps--active-x > .ps__rail-x, +.ps--active-y > .ps__rail-y { + display: block; + background-color: transparent; +} + +.ps--focus > .ps__rail-x, +.ps--focus > .ps__rail-y, +.ps--scrolling-x > .ps__rail-x, +.ps--scrolling-y > .ps__rail-y { + opacity: 0.6; +} + +.ps__rail-x:hover, +.ps__rail-y:hover, +.ps__rail-x:focus, +.ps__rail-y:focus { + background-color: transparent; + opacity: 0.9; +} + +/* + * Scrollbar thumb styles + */ +.ps__thumb-x { + background-color: #aaa; + border-radius: 6px; + height: 6px; + /* there must be 'bottom' for ps__thumb-x */ + bottom: 2px; + /* please don't change 'position' */ + position: absolute; +} + +.ps__thumb-y { + @include gradient-vertical($scrollbarBackground, $scrollbarBackground2); + border-radius: 6px; + width: 6px; + /* there must be 'right' for ps__thumb-y */ + right: 0px; + /* please don't change 'position' */ + position: absolute; +} + +/* MS supports */ +@supports (-ms-overflow-style: none) { + .ps { + overflow: auto !important; + } +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .ps { + overflow: auto !important; + } +} + +.ps__rail-x:hover, +.ps__rail-y:hover, +.ps__rail-x:focus, +.ps__rail-y:focus { + background-color: transparent; + opacity: 0.9; +} + // Srollbars // @@ -12,20 +114,46 @@ } ::-webkit-scrollbar-button:start:decrement, -::-webkit-scrollbar-button:end:increment { display: none; } -::-webkit-scrollbar-button:horizontal:decrement { display: none; } -::-webkit-scrollbar-button:horizontal:increment { display: none; } -::-webkit-scrollbar-button:vertical:decrement { display: none; } -::-webkit-scrollbar-button:vertical:increment { display: none; } -::-webkit-scrollbar-button:horizontal:decrement:active { background-image: none; } -::-webkit-scrollbar-button:horizontal:increment:active { background-image: none; } -::-webkit-scrollbar-button:vertical:decrement:active { background-image: none; } -::-webkit-scrollbar-button:vertical:increment:active {background-image: none; } -::-webkit-scrollbar-track-piece { background-color: transparent; } +::-webkit-scrollbar-button:end:increment { + display: none; +} +::-webkit-scrollbar-button:horizontal:decrement { + display: none; +} +::-webkit-scrollbar-button:horizontal:increment { + display: none; +} +::-webkit-scrollbar-button:vertical:decrement { + display: none; +} +::-webkit-scrollbar-button:vertical:increment { + display: none; +} +::-webkit-scrollbar-button:horizontal:decrement:active { + background-image: none; +} +::-webkit-scrollbar-button:horizontal:increment:active { + background-image: none; +} +::-webkit-scrollbar-button:vertical:decrement:active { + background-image: none; +} +::-webkit-scrollbar-button:vertical:increment:active { + background-image: none; +} +::-webkit-scrollbar-track-piece { + background-color: transparent; +} ::-webkit-scrollbar-thumb:vertical { height: 50px; - background: -webkit-gradient(linear, left top, right top, color-stop(0%, $scrollbarBackground), color-stop(100%, $scrollbarBackground2)); + background: -webkit-gradient( + linear, + left top, + right top, + color-stop(0%, $scrollbarBackground), + color-stop(100%, $scrollbarBackground2) + ); border: 1px solid $scrollbarBorder; border-top: 1px solid $scrollbarBorder; border-left: 1px solid $scrollbarBorder; @@ -33,9 +161,14 @@ ::-webkit-scrollbar-thumb:horizontal { width: 50px; - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, $scrollbarBackground), color-stop(100%, $scrollbarBackground2)); + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0%, $scrollbarBackground), + color-stop(100%, $scrollbarBackground2) + ); border: 1px solid $scrollbarBorder; border-top: 1px solid $scrollbarBorder; border-left: 1px solid $scrollbarBorder; } - diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index e35bf4e6b6e..47d4a926968 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -1,12 +1,12 @@ .search-backdrop { position: fixed; right: 0; - bottom: 0; left: 0; + bottom: 0; top: $navbarHeight; z-index: $zindex-modal-backdrop; background-color: $black; - @include opacity(70); + @include opacity(75); } .search-container { @@ -16,21 +16,17 @@ bottom: 0; z-index: ($zindex-modal-backdrop + 10); position: fixed; - - .label-tag { - margin-left: 6px; - font-size: 11px; - padding: 2px 6px; - } } // Search .search-field-wrapper { width: 100%; display: flex; - background-color: $navbarButtonBackground; + background-color: $navbarBackground; + box-shadow: $navbarShadow; + position: relative; - input { + & > input { max-width: 653px; //padding: 0.5rem 1.5rem 0.5rem 0; padding: 1rem 1rem 0.75rem 1rem; @@ -48,12 +44,6 @@ flex-grow: 1; } -.search-switches { - flex-grow: 1; - padding: 1rem 1rem 0.75rem 1rem; - white-space: nowrap; -} - .search-field-icon { font-size: $font-size-lg; padding: 1rem 1rem 0.75rem 1.5rem; @@ -62,107 +52,224 @@ .search-dropdown { display: flex; flex-direction: column; - max-width: 1100px; - visibility: none; - opacity: 0; - height: 100%; + height: calc(100% - #{$navbarHeight}); +} - &--fade-in { - visibility: visible; - opacity: 1; - transition: opacity 0.3s; +.search-dropdown__col_1 { + background: $page-bg; + max-width: 700px; + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.search-dropdown__col_2 { + flex-grow: 1; + height: 100%; + padding-top: 16px; + display: none; + flex-direction: column; +} + +.search-filter-box { + background: $search-filter-box-bg; + border-radius: 2px; + padding: $spacer*1.5; + min-width: 340px; + margin-bottom: $spacer * 1.5; +} + +.search-filter-box__header { + border-bottom: 1px solid $dark-5; + margin-bottom: $spacer * 1.5; +} + +.search-filter-box-link { + display: block; + margin-bottom: 16px; + + &:last-child { + margin-bottom: 0; + } + + i, + img { + font-size: 20px; + margin-right: 5px; } } .search-results-container { - height: 90%; - overflow: auto; + height: 100%; display: block; - line-height: 28px; padding: $spacer; - background: $panel-bg; + position: relative; flex-grow: 10; + margin-bottom: 1rem; + + .label-tag { + margin-left: 6px; + font-size: 11px; + padding: 2px 6px; + } .selected { .search-result-tag { - opacity: 0.70; + opacity: 0.7; color: white; } } +} - .fa-star, .fa-star-o { - padding-left: 13px; +.search-section { + background: $panel-bg; + border: $panel-border; + padding: 0px 4px 4px 4px; + margin-bottom: 3px; + border-radius: 5px; +} + +.search-section__header { + font-size: $font-size-h6; + padding: 7px 4px 3px 0; + color: $text-color-weak; + display: flex; + flex-grow: 1; + + &:hover, + &.selected { + color: $text-color; } - .fa-star { - color: $orange; - } - - .search-result-link { - color: $grafanaListMainLinkColor; - .fa { - padding-right: 10px; + &:hover { + .search-section__header__link { + opacity: 1; } } - - .search-item { - word-wrap: break-word; - display: block; - padding: 3px 10px; - white-space: nowrap; - background-color: $tight-form-bg; - margin-bottom: 4px; - @include left-brand-border(); - - .search-result-icon::before { - content: "\f009"; - } - - &.search-item-dash-home .search-result-icon::before { - content: "\f015"; - } - - &:hover, - &.selected { - background-color: $tight-form-func-bg; - @include left-brand-border-gradient(); - } - } - - .search-result-tags { - float: right; - } - - .search-result-actions { - float: right; - padding-left: 20px; - } } +.search-section__header__icon { + padding: 5px 0px; + width: 43px; + text-align: center; +} + +.search-section__header__toggle { + padding: 5px; +} + +.search-section__header__text { + flex-grow: 1; + line-height: 24px; +} + +.search-section__header__link { + padding: 2px 10px 0; + color: $text-muted; + opacity: 0; + transition: opacity 150ms ease-in-out; +} + +.search-item { + @include list-item(); + + display: flex; + flex-grow: 1; + height: 37px; + white-space: nowrap; + padding: 0px; + + &:hover, + &.selected { + background: $list-item-hover-bg; + } +} + +.search-item__body { + flex: 1 1 auto; + overflow: hidden; + display: flex; + flex-direction: column; + justify-content: center; + padding: 0 10px; +} + +.search-item__body-title { + color: $list-item-link-color; +} + +.search-item__icon { + padding: 5px; + flex: 0 0 auto; + font-size: 19px; + padding: 5px 2px 5px 10px; +} + +.search-item__tags { + display: none; + padding: 10px; +} + +.search-item__actions { + flex: 0 0 auto; + padding: 0 10px 0 0; +} + +.search-item__actions__item { + display: inline-block; + opacity: 0; + width: 0; + transition: all 0.2s ease-in-out; + .fa-star, + .fa-star-o { + color: $orange; + line-height: 37px; + } +} + +.search-item:hover { + .search-item__actions__item { + width: 15px; + opacity: 1; + } +} .search-button-row { - padding: $spacer*2; - display: flex; - flex-direction: row; - align-items: flex-start; - justify-content: space-around; - height: 30%; + text-align: center; + padding: $spacer*2 $spacer; + background: $panel-bg; +} - button, a { - margin-bottom: $spacer; +@include media-breakpoint-up(sm) { + .search-container { + left: $side-menu-width; } - .search-button-row-explore-link { - color: $gray-3; - font-size: $font-size-sm; - position: relative; - top: 1.0rem; - &:hover { - color: $link-hover-color; - } - img { - vertical-align: text-bottom; - } + .search-item__tags { + display: block; + } + + .search-dropdown__col_2 { + display: flex; + margin-bottom: 1rem; + } +} + +@include media-breakpoint-up(md) { + .search-dropdown__col_2 { + flex-direction: row; + justify-content: space-between; + max-width: 700px; + height: 260px; + align-items: flex-start; + } + + .search-dropdown__col_1 { + height: 100%; + } + + .search-filter-box { + margin: 0; } } @@ -170,14 +277,13 @@ .search-dropdown { flex-direction: row; } - .search-button-row { - flex-direction: column; - justify-content: flex-start; - } -} -@include media-breakpoint-up(md) { - .search-container { - left: 78px; + .search-dropdown__col_2 { + flex-direction: column; + } + + .search-filter-box { + margin-left: $spacer * 1.5; + margin-bottom: $spacer * 1.5; } } diff --git a/public/sass/components/_settings_permissions.scss b/public/sass/components/_settings_permissions.scss new file mode 100644 index 00000000000..5864c58679e --- /dev/null +++ b/public/sass/components/_settings_permissions.scss @@ -0,0 +1,32 @@ +.permissionlist { + .permissionlist__section { + margin-bottom: $spacer*2; + } + + .permissionlist__section-header { + margin-bottom: $spacer; + display: flex; + } + + .permissionlist__section-header h6 { + margin: auto 5px; + color: $text-color-weak; + } + + .permissionlist__section-header__add-button { + margin-left: auto; + width: 105px; + } + + .permissionlist__item { + background-color: $tight-form-bg; + + &:hover { + background-color: $tight-form-func-bg; + } + } + + .permissionlist__item-buttons { + margin-left: auto; + } +} diff --git a/public/sass/components/_shortcuts.scss b/public/sass/components/_shortcuts.scss index 1dedb062183..b5f61872585 100644 --- a/public/sass/components/_shortcuts.scss +++ b/public/sass/components/_shortcuts.scss @@ -1,4 +1,3 @@ - .shortcut-category { float: left; font-size: $font-size-sm; @@ -11,7 +10,6 @@ .shortcut-table-category-header { font-weight: normal; font-size: $font-size-h6; - font-style: italic; text-align: left; } @@ -45,4 +43,3 @@ color: $btn-inverse-text-color; box-shadow: inset 0 -1px 0 $btn-inverse-bg-hl; } - diff --git a/public/sass/components/_sidemenu.scss b/public/sass/components/_sidemenu.scss index 0e5402403e5..5f21bbc8cd0 100644 --- a/public/sass/components/_sidemenu.scss +++ b/public/sass/components/_sidemenu.scss @@ -1,229 +1,272 @@ -.sidemenu-canvas { - position: relative; -} - -.sidemenu-wrapper { - position: absolute; - top: 52px; - left: 0; +.sidemenu { + position: fixed; + display: flex; + flex-flow: column; + flex-direction: column; width: $side-menu-width; - background-color: rgba($side-menu-bg,$side-menu-opacity); - z-index: 1000; - opacity: 0; - visibility: hidden; - + z-index: $zindex-sidemenu; a:focus { text-decoration: none; } -} -.sidemenu-open { - .sidemenu-wrapper { - visibility: visible; - //transform: translate3d(0, 0, 0); - opacity: 1; - transition: opacity 0.3s; + .sidemenu__logo_small_breakpoint { + display: none; + } + + .sidemenu__close { + display: none; } } -.sidemenu-pinned { - .sidemenu-wrapper { - min-height: calc(100% - 54px); - } - .dashboard-container { - padding-left: $side-menu-width + 0.5rem; - } - .page-container { - margin-left: $side-menu-width; - } - .search-container { - left: $side-menu-width; +// body class that hides sidemenu +.sidemenu-hidden { + .sidemenu { + display: none; } } -.sidemenu { - list-style: none; - margin: 0; - padding: 0; +@include media-breakpoint-up(sm) { + .sidemenu-open { + .sidemenu { + background: $side-menu-bg; + position: initial; + height: auto; + box-shadow: $side-menu-shadow; + position: relative; + z-index: $zindex-sidemenu; + } + .sidemenu__top, + .sidemenu__bottom { + display: block; + } + } +} - > li { - position: relative; - @include left-brand-border(); +.sidemenu__top { + padding-top: 3rem; + flex-grow: 1; + display: none; +} +.sidemenu__bottom { + padding-bottom: $spacer; + display: none; +} + +.sidemenu-item { + position: relative; + @include left-brand-border(); + + @include media-breakpoint-up(sm) { &.active, &:hover { background-color: $side-menu-item-hover-bg; @include left-brand-border-gradient(); .dropdown-menu { + margin: 0; display: block; opacity: 0; top: 0px; // important to overlap it otherwise it can be hidden // again by the mouse getting outside the hover space - left: $side-menu-width - 0.2rem; - background-color: rgba($side-menu-bg,$side-menu-opacity); - @include animation('dropdown-anim 150ms ease-in-out 100ms forwards'); - z-index: -9999; + left: $side-menu-width - 2px; + @include animation("dropdown-anim 150ms ease-in-out 100ms forwards"); + z-index: $zindex-sidemenu; } } } } +.dropup.sidemenu-item:hover .dropdown-menu { + top: auto !important; +} + +.sidemenu-link { + color: $link-color; + line-height: 42px; + padding: 0px 10px 0px 10px; + display: block; + position: relative; + font-size: 16px; + border: 1px solid transparent; + text-align: center; + + img { + border-radius: 50%; + width: 28px; + height: 28px; + box-shadow: 0 0 14px 2px rgba(255, 255, 255, 0.05); + } +} + @include keyframes(dropdown-anim) { 0% { opacity: 0; - transform: translate3d(-5%,0,0); + //transform: translate3d(-5%,0,0); } 100% { opacity: 1; - transform: translate3d(0,0,0); + //transform: translate3d(0,0,0); } } -.sidemenu-main-link { - font-size: 16px; -} - -.sidemenu-item-text { - width: 110px; - display: inline-block; - vertical-align: middle; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - .icon-circle { - width: 40px; - height: 40px; + width: 35px; + height: 35px; display: inline-block; - i { - color: $link-color; - opacity: .7; + + .fa, + .icon-gf, + .gicon { + color: $side-menu-link-color; position: relative; - left: 7px; + opacity: 0.7; + font-size: 130%; + } + + .fa { + top: 2px; + position: relative; + } + + .icon-gf { top: 5px; - font-size: 150%; } + img { - left: 7px; position: relative; } } -.sidemenu-item { - color: $link-color; - line-height: 47px; - padding: 0px 10px 0px 10px; +.side-menu-header { + padding: 10px 10px 10px 20px; + white-space: nowrap; + background-color: $side-menu-item-hover-bg; + font-size: 17px; + color: #ebedf2; +} + +li.sidemenu-org-switcher { + border-bottom: 1px solid $dropdownDividerBottom; +} + +.sidemenu-org-switcher__org-name { + font-size: $font-size-base; +} + +.sidemenu-org-switcher__org-current { + font-size: $font-size-xs; + color: $text-color-weak; + position: relative; + top: -2px; +} + +.sidemenu-org-switcher__switch { + font-size: $font-size-sm; + padding-left: 1.5rem; + display: flex; + align-items: center; + > i.fa.fa-random { + margin-right: 4px; + top: 1px; + } +} + +.sidemenu__logo { display: block; - border-left: 1px solid transparent; + padding: 0.4rem 1rem 0.4rem 0.65rem; + min-height: $navbarHeight; + position: relative; - - .sidemenu-item-text { - padding-left: 11px; + &:hover { + background: $navbarButtonBackgroundHighlight; } img { - border-radius: 50%; - width: 28px; - height: 28px; - box-shadow: 0 0 14px 2px rgba(255,255,255, 0.05); + width: 30px; + position: relative; + top: 5px; + left: 4px; } } -.sidemenu-section-tagline { - font-style: italic; - line-height: 10px; -} +@include media-breakpoint-down(xs) { + .sidemenu-open--xs { + .sidemenu { + width: 100%; + background: $side-menu-bg; + position: initial; + height: auto; + box-shadow: $side-menu-shadow; + position: relative; + z-index: $zindex-sidemenu; + } -.sidemenu-section-text-wrapper { - padding-top: 4px; -} + .sidemenu__close { + display: block; + font-size: $font-size-md; + position: relative; + top: -3px; + } -.sidemenu-org-section .dropdown-menu-title { - margin: 0 10px 0 6px; - padding: 7px 0 7px; - overflow: hidden; - color: $dropdownTitle; -} + .sidemenu__top, + .sidemenu__bottom { + display: block; + } + } -.sidemenu-org-section .dropdown-menu-title > span { - display: inline-block; - position: relative; + .sidemenu { + .sidemenu__logo { + display: none; + } - &::after { - display: block; - position: absolute; - top: 50%; - right: 0; - left: 100%; - width: 200px; - height: 1px; - margin-left: 5px; - background: $dropdownDivider; - content: ''; + .sidemenu__logo_small_breakpoint { + padding: 16px 10px 26px; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: baseline; + + .fa-bars { + font-size: 25px; + } + } + + .sidemenu__top { + padding-top: 0rem; + } + + .side-menu-header { + padding-left: 10px; + } + + .sidemenu-link { + text-align: left; + } + + .sidemenu-icon { + display: none; + } + + .dropdown-menu--sidemenu { + display: block; + position: unset; + width: 100%; + float: none; + margin-top: 0.5rem; + margin-bottom: 0.5rem; + + > li > a { + padding-left: 15px; + } + } + + .sidemenu__bottom { + .dropdown-menu--sidemenu { + display: flex; + flex-direction: column-reverse; + } + } } } - -.sidemenu-org { - padding: 17px 10px 15px 14px; - box-sizing: border-box; - cursor: pointer; - display: table; - position: relative; - width: 100%; -} - -.sidemenu .fa-caret-right { - position: absolute; - top: 38%; - right: 6px; - font-size: 14px; - color: $text-color-faint; -} - -.sidemenu-org-avatar, -.sidemenu-org-details { - display: table-cell; - vertical-align: top; -} - -.sidemenu-org-avatar { - width: 40px; - height: 40px; - background-color: $gray-2; - border-radius: 50%; - text-align: center; - - >img { - position: absolute; - width: 40px; - height: 40px; - border-radius: 50%; - left: 14px; - } -} - -.sidemenu-org-avatar--missing { - color: $gray-4; - text-shadow: 0 1px 0 $dark-1; - line-height: 40px; - font-size: $font-size-lg; -} - -.sidemenu-org-details { - padding-left: 10px; - color: $link-color; -} - -.sidemenu-org-name { - display: block; - font-size: 13px; - color: $link-color-disabled; -} - -.sidemenu-org-user { - display: block; -} - diff --git a/public/sass/components/_submenu.scss b/public/sass/components/_submenu.scss index 878058bd1c4..0027e0b1999 100644 --- a/public/sass/components/_submenu.scss +++ b/public/sass/components/_submenu.scss @@ -5,10 +5,11 @@ align-content: flex-start; align-items: flex-start; - margin: 0 $panel-margin ($panel-margin*2) $panel-margin; + margin: 0 0 $panel-margin 0; } -.annotation-disabled, .annotation-disabled a { +.annotation-disabled, +.annotation-disabled a { color: $link-color-disabled; } @@ -38,7 +39,11 @@ .variable-value-link { padding-right: 10px; - padding: 8px 7px; + padding: $input-padding-y $input-padding-x; + background-color: $input-bg; + border: 1px solid $input-border-color; + border-radius: $input-border-radius; + color: $input-color; box-sizing: content-box; display: inline-block; color: $text-color; @@ -48,18 +53,9 @@ } } -.variable-link-wrapper { +.variable-link-wrapper { display: inline-block; position: relative; - - .hidden-input { - padding: 8px 7px; - border: none; - margin: 0px; - background: transparent; - border-radius: 0; - border-right: 1px solid $tight-form-border; - } } .variable-value-dropdown { @@ -71,28 +67,28 @@ overflow-y: auto; overflow-x: hidden; background-color: $dropdownBackground; - box-shadow: 0 0 25px 0 rgba(0,0,0,0.4); - z-index: 1000; + box-shadow: 0 0 25px 0 rgba(0, 0, 0, 0.4); + z-index: $zindex-typeahead; font-size: $font-size-base; border-radius: 3px 3px 0 0; border: 1px solid $tight-form-func-bg; &.multi { - .selected { - .variable-option-icon{ - background: url($checkboxImageUrl) 0px -18px no-repeat; - } - } - } + .selected { + .variable-option-icon { + background: url($checkboxImageUrl) 0px -18px no-repeat; + } + } + } - &.single { - .variable-option-icon { - display: none; - } - .selected { - background-color: $tight-form-func-highlight-bg; - } - } + &.single { + .variable-option-icon { + display: none; + } + .selected { + background-color: $tight-form-func-highlight-bg; + } + } } .variable-options-wrapper { @@ -140,7 +136,8 @@ } .variable-option { - &:hover, &.highlighted { + &:hover, + &.highlighted { background-color: $blue-dark; } } diff --git a/public/sass/components/_switch.scss b/public/sass/components/_switch.scss index f09e83f8908..c7eb1914103 100644 --- a/public/sass/components/_switch.scss +++ b/public/sass/components/_switch.scss @@ -1,7 +1,3 @@ -$switch-border-radius: 1rem; -$switch-width: 3.5rem; -$switch-height: 1.5rem; - /* ============================================================ SWITCH 3 - YES NO ============================================================ */ @@ -10,7 +6,7 @@ $switch-height: 1.5rem; position: relative; max-width: 4.5rem; flex-grow: 1; - min-width: 4.0rem; + min-width: 4rem; margin-right: $gf-form-margin; input { @@ -27,11 +23,15 @@ $switch-height: 1.5rem; outline: none; user-select: none; width: 100%; - height: 2.65rem; - background-color: $page-bg; + height: 37px; + background: $input-bg; + border: 1px solid $input-border-color; + border-left: none; + border-radius: $input-border-radius; } - input + label::before, input + label::after { + input + label::before, + input + label::after { @include buttonBackground($input-bg, $input-bg); display: block; @@ -61,11 +61,10 @@ $switch-height: 1.5rem; color: lighten($orange, 10%); text-shadow: $text-shadow-strong; } - } input + label::before { - font-family: 'FontAwesome'; + font-family: "FontAwesome"; content: "\f096"; // square-o color: $text-color-weak; transition: transform 0.4s; @@ -78,7 +77,7 @@ $switch-height: 1.5rem; color: $orange; text-shadow: $text-shadow-strong; - font-family: 'FontAwesome'; + font-family: "FontAwesome"; transition: transform 0.4s; transform: rotateY(180deg); backface-visibility: hidden; @@ -102,7 +101,55 @@ $switch-height: 1.5rem; } } -gf-form-switch[disabled] { +.gf-form-switch--transparent { + input + label { + background: transparent; + border: none; + } + + input + label::before, + input + label::after { + background: transparent; + border: none; + } + + &:hover { + input + label::before { + background: transparent; + } + + input + label::after { + background: transparent; + } + } +} + +.gf-form-switch--search-result__section { + min-width: 3.05rem; + margin-right: -0.3rem; + + input + label { + height: 1.7rem; + } +} + +.gf-form-switch--search-result__item { + min-width: 2.7rem; + + input + label { + height: 2.7rem; + } +} + +.gf-form-switch--search-result-filter-row__checkbox { + min-width: 3.75rem; + + input + label { + height: 2.5rem; + } +} + +gf-form-switch[disabled] { .gf-form-label, .gf-form-switch input + label { cursor: default; diff --git a/public/sass/components/_tabbed_view.scss b/public/sass/components/_tabbed_view.scss index 6cc04f259d6..dfd760753fe 100644 --- a/public/sass/components/_tabbed_view.scss +++ b/public/sass/components/_tabbed_view.scss @@ -1,42 +1,43 @@ .tabbed-view { - background-color: $page-bg; - background-image: $page-gradient; - margin: (-$panel-margin*2) (-$panel-margin); - margin-bottom: $spacer*2; padding: $spacer*3; + margin-bottom: $dashboard-padding; &.tabbed-view--panel-edit { padding: 0; .tabbed-view-header { - background-color: $body-bg; - padding: 1.5em 1rem 0 1rem; - } - .gf-tabs-link.active { - background-color: $panel-bg; + padding: 0px 25px; + background: none; } } } .tabbed-view-header { + background: $page-header-bg; + box-shadow: $page-header-shadow; + border-bottom: 1px solid $page-header-border-color; @include clearfix(); - @include brand-bottom-border(); } .tabbed-view-title { float: left; - font-style: italic; padding-top: 0.5rem; margin: 0 $spacer*3 0 $spacer*1; } +.tabbed-view-panel-title { + float: left; + padding-top: 9px; + margin: 0 2rem 0 0; +} + .tabbed-view-close-btn { float: right; padding: 0; margin: 0; background-color: transparent; border: none; - padding: ($tabs-padding-top + $tabs-top-margin) $spacer $tabs-padding-bottom; + padding: $tabs-padding; color: $text-color; i { font-size: 120%; @@ -48,7 +49,11 @@ .tabbed-view-body { padding: $spacer*2 $spacer; - min-height: 250px; + + &--small { + min-height: 0px; + padding-bottom: 0px; + } } .section-heading { diff --git a/public/sass/components/_tables_lists.scss b/public/sass/components/_tables_lists.scss index 6787ef2869e..43be08eac33 100644 --- a/public/sass/components/_tables_lists.scss +++ b/public/sass/components/_tables_lists.scss @@ -8,7 +8,7 @@ } tr td { - background-color: $grafanaListBackground; + background-color: $list-item-bg; padding: 5px 10px; white-space: nowrap; border-bottom: 4px solid $panel-bg; @@ -37,7 +37,7 @@ display: block; padding: 1px 10px; line-height: 34px; - background-color: $tight-form-bg; + background-color: $list-item-bg; margin-bottom: 4px; cursor: pointer; } diff --git a/public/sass/components/_tabs.scss b/public/sass/components/_tabs.scss index 32e395c4d73..197d5892652 100644 --- a/public/sass/components/_tabs.scss +++ b/public/sass/components/_tabs.scss @@ -1,41 +1,8 @@ -.nav-tabs-alt { - & > li > a { - color: darken($link-color, 20%); - } - - li > a:hover { - border-bottom: none; - } - - li.active > a, - li.active > a:focus, - li.active > a:hover { - @include border-radius(3px); - border: 1px solid $divider-border-color; - background-color: transparent; - border-bottom: 1px solid $page-bg; - color: $link-color; - } - - li.disabled > a { - color: $text-color; - } - - .open .dropdown-toggle { - background-color: #060606; - border-color: transparent; - } - - .tab-content { - padding: 10px; - background-color: $panel-bg; - } -} - .gf-tabs { @include clearfix(); float: left; - margin: $tabs-top-margin 0 0 0; + position: relative; + top: 1px; } .gf-tabs-item { @@ -44,13 +11,23 @@ } .gf-tabs-link { - padding: $tabs-padding-top $spacer $tabs-padding-bottom $spacer; + padding: $tabs-padding; margin-right: $spacer/2; - border: 1px solid transparent; position: relative; display: block; + border: solid transparent; + border-width: 0 1px 1px; + border-radius: 3px 3px 0 0; + color: $text-color; - @include border-radius(2px 2px 0 0); + i { + margin-right: 5px; + } + + .gicon { + position: relative; + top: -2px; + } &:hover, &:focus { @@ -60,20 +37,25 @@ &.active, &.active:hover, &.active:focus { - @include border-radius(3px); - border-color: rgba(216, 131, 40, 0.77); - border-bottom: 2px solid $panel-bg; + border-color: $orange $tab-border-color transparent; + background: $page-bg; color: $link-color; - position: relative; - top: 1px; + overflow: hidden; + + &::before { + display: block; + content: " "; + position: absolute; + left: 0; + right: 0; + height: 2px; + top: 0; + background-image: linear-gradient( + to right, + #ffd500 0%, + #ff4400 99%, + #ff4400 100% + ); + } } } - -.form-tabs-wrapper { - @include brand-bottom-border(); - @include clearfix(); -} - -.form-tabs-content { - padding: $spacer*2 $spacer; -} diff --git a/public/sass/components/_tags.scss b/public/sass/components/_tags.scss index c00328c49c4..9d015f952fe 100644 --- a/public/sass/components/_tags.scss +++ b/public/sass/components/_tags.scss @@ -3,17 +3,16 @@ .badge { display: inline-block; padding: 2px 4px; - font-size: $font-size-base * .846; + font-size: $font-size-base * 0.846; font-weight: bold; line-height: 14px; // ensure proper line-height if floated color: $white; vertical-align: baseline; white-space: nowrap; - text-shadow: 0 -1px 0 rgba(0,0,0,.25); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: $gray-1; } - // Labels & Badges .label-tag { background-color: $purple; @@ -22,10 +21,10 @@ border-radius: 3px; text-shadow: none; font-size: 13px; - padding: 2px 6px; + padding: 3px 6px 1px 6px; border-width: 1px; border-style: solid; - box-shadow: 0 0 1px rgba($white,.2); + box-shadow: 0 0 1px rgba($white, 0.2); .icon-tag { position: relative; top: 1px; @@ -34,8 +33,6 @@ } .label-tag:hover { - opacity: 0.85; + opacity: 0.85; background-color: darken($purple, 10%); } - - diff --git a/public/sass/components/_tagsinput.scss b/public/sass/components/_tagsinput.scss index 0753f045a61..915a0f6d480 100644 --- a/public/sass/components/_tagsinput.scss +++ b/public/sass/components/_tagsinput.scss @@ -9,7 +9,6 @@ input { display: inline-block; border: none; - border-right: 1px solid $tight-form-border; margin: 0px; border-radius: 0; padding: 8px 6px; @@ -22,19 +21,67 @@ margin-right: 2px; color: white; - [data-role="remove"] { - margin-left:8px; - cursor:pointer; - &::after{ - content: "x"; - padding:0px 2px; + [data-role='remove'] { + margin-left: 8px; + cursor: pointer; + &::after { + content: 'x'; + padding: 0px 2px; } &:hover { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); &:active { - box-shadow: inset 0 3px 5px rgba(0,0,0,0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } } } } } + +.tag-filter { + line-height: 22px; + flex-grow: 1; + + .label-tag { + margin-left: 6px; + font-size: 11px; + cursor: pointer; + + .fa.fa-remove { + margin-right: 3px; + } + } + + .tag-filter-option { + position: relative; + text-align: left; + width: 100%; + display: block; + border-radius: 0; + } + + .tag-count-label { + margin-left: 3px; + } + + .gf-form-input--form-dropdown { + .Select-menu-outer { + border: 0; + width: 100%; + } + } +} + +.tag-filter-values { + display: inline; + + .label-tag { + margin: 6px 6px 0px 0px; + font-size: 11px; + cursor: pointer; + + .fa.fa-remove { + margin-right: 3px; + } + } +} diff --git a/public/sass/components/_timepicker.scss b/public/sass/components/_timepicker.scss index a5f311cdb46..2d7a12c3d01 100644 --- a/public/sass/components/_timepicker.scss +++ b/public/sass/components/_timepicker.scss @@ -1,29 +1,30 @@ -.nav.gf-timepicker-nav { - margin-right: 0; -} - .timepicker-timestring { font-weight: normal; } +.gf-timepicker-nav { + flex-wrap: nowrap; + display: flex; +} + .gf-timepicker-nav-btn { - overflow: hidden; text-overflow: ellipsis; - white-space: nowrap; + overflow: hidden; } .gf-timepicker-dropdown { - margin: -8px -10px 10px 5px; + position: absolute; + top: $navbarHeight; + right: 0; padding: 10px 20px; - float: right; - background-color: $panel-bg; - @include box-shadow($navbarDropdownShadow); + background-color: $page-bg; + border-radius: 0 0 0 4px; + box-shadow: $search-shadow; } .gf-timepicker-absolute-section { width: 290px; float: left; - border-right: 1px solid $divider-border-color; padding: 0 10px; select { width: 183px; @@ -41,7 +42,7 @@ font-size: 75%; padding: 3px; border-radius: 2px; - font-weight: bold; + font-weight: 500; margin-left: 4px; } @@ -59,7 +60,7 @@ li.active { border-bottom: 1px solid $blue; margin: 3px 0; - font-weight: bold; + font-weight: 500; } } } @@ -89,7 +90,7 @@ } .input-datetime-format { - color: $link-color-disabled + color: $link-color-disabled; } .fa { @@ -117,15 +118,3 @@ @extend .fa; @extend .fa-chevron-left; } - -.gf-timepicker-time-control { - font-size: $font-size-sm; - a { - padding: 18px 7px 13px !important; - } -} - -.dashnav-move-timeframe { - position: relative; - top: 1px; -} diff --git a/public/sass/components/_tooltip.scss b/public/sass/components/_tooltip.scss index f710dc68931..b5799e49301 100644 --- a/public/sass/components/_tooltip.scss +++ b/public/sass/components/_tooltip.scss @@ -11,11 +11,25 @@ font-size: 11px; line-height: 1.4; @include opacity(0); - &.in { @include opacity(100); } - &.top { margin-top: -3px; padding: 5px 0; } - &.right { margin-left: 3px; padding: 0 5px; } - &.bottom { margin-top: 3px; padding: 5px 0; } - &.left { margin-left: -3px; padding: 0 5px; } + &.in { + @include opacity(100); + } + &.top { + margin-top: -3px; + padding: 5px 0; + } + &.right { + margin-left: 3px; + padding: 0 5px; + } + &.bottom { + margin-top: 3px; + padding: 5px 0; + } + &.left { + margin-left: -3px; + padding: 0 5px; + } } // Wrapper for the tooltip content @@ -70,13 +84,13 @@ } .grafana-tooltip { - position : absolute; + position: absolute; top: -1000; left: 0; color: $tooltipColor; padding: 10px; font-size: 11pt; - font-weight : 200; + font-weight: 200; background-color: $tooltipBackground; border-radius: 5px; z-index: 9999; @@ -92,4 +106,3 @@ .grafana-tip { padding-left: 5px; } - diff --git a/public/sass/components/_typeahead.scss b/public/sass/components/_typeahead.scss index efa4f3459ed..84b6dc552d2 100644 --- a/public/sass/components/_typeahead.scss +++ b/public/sass/components/_typeahead.scss @@ -1,4 +1,3 @@ - // typeahead max height .typeahead { max-height: 300px; @@ -8,4 +7,3 @@ .typeahead strong { color: $yellow; } - diff --git a/public/sass/components/_user-picker.scss b/public/sass/components/_user-picker.scss new file mode 100644 index 00000000000..35a2a242746 --- /dev/null +++ b/public/sass/components/_user-picker.scss @@ -0,0 +1,12 @@ +.user-picker-option__button { + position: relative; + text-align: left; + width: 100%; + display: block; + border-radius: 0; +} +.user-picker-option__avatar { + width: 20px; + display: inline-block; + margin-right: 10px; +} diff --git a/public/sass/components/_view_states.scss b/public/sass/components/_view_states.scss index a1ed89f9888..b1fa47d0c0a 100644 --- a/public/sass/components/_view_states.scss +++ b/public/sass/components/_view_states.scss @@ -1,75 +1,45 @@ -@mixin hide-controls() { - .add-row-panel-hint, - .dash-row-menu-container { - display: none; - } - .resize-panel-handle, - .panel-drop-zone { - visibility: hidden; - } -} - -.hide-controls { - @include hide-controls(); -} - .page-kiosk-mode { - @include hide-controls(); - dashnav { + .sidemenu, + .navbar { display: none; } + .scroll-canvas--dashboard { + height: 100%; + } } .playlist-active, .user-activity-low { - .add-row-panel-hint, + .react-resizable-handle .add-row-panel-hint, .dash-row-menu-container, - .resize-panel-handle, - .panel-drop-zone - .dashnav-refresh-action, - .dashnav-zoom-out, - .dashnav-action-icons, + .navbar-button--refresh, + .navbar-buttons--zoom, + .navbar-buttons--actions, + .panel-menu-container, .panel-info-corner--info, - .panel-info-corner--links, - .dashnav-move-timeframe { + .panel-info-corner--links { opacity: 0; - transition: all 1.5s ease-in-out 1s; } - // navbar buttons - .navbar-brand-btn, - .navbar-inner { - border-color: transparent; + .navbar { + box-shadow: none; background: transparent; - transition: all 1.5s ease-in-out 1s; - .fa { - opacity: 0; - transition: all 1.5s ease-in-out 1s; - } } .navbar-page-btn { border-color: transparent; background: transparent; - transform: translate3d(-50px, 0, 0); - transition: all 1.5s ease-in-out 1s; - .icon-gf { + transform: translate3d(-40px, 0, 0); + i { opacity: 0; - transition: all 1.5s ease-in-out 1s; } } + .sidemenu { + display: none; + } + .gf-timepicker-nav-btn { transform: translate3d(40px, 0, 0); - transition: transform 1.5s ease-in-out 1s; - } -} - -.playlist-active { - .dash-playlist-actions { - .fa { - opacity: 1; - color: $text-color-faint !important; - } } } diff --git a/public/sass/components/edit_sidemenu.scss b/public/sass/components/edit_sidemenu.scss index e84ae2c1914..87d90f18162 100644 --- a/public/sass/components/edit_sidemenu.scss +++ b/public/sass/components/edit_sidemenu.scss @@ -1,4 +1,3 @@ - .edit-tab-with-sidemenu { display: flex; flex-direction: row; @@ -29,7 +28,6 @@ } } - @include media-breakpoint-down(sm) { .edit-tab-with-sidemenu { flex-direction: column; diff --git a/public/sass/grafana.dark.scss b/public/sass/grafana.dark.scss index 858d6ace336..53193d213e6 100644 --- a/public/sass/grafana.dark.scss +++ b/public/sass/grafana.dark.scss @@ -1,4 +1,3 @@ @import "variables"; @import "variables.dark"; @import "grafana"; - diff --git a/public/sass/icons.json b/public/sass/icons.json index 4c87042fe02..7e1bc712bf4 100644 --- a/public/sass/icons.json +++ b/public/sass/icons.json @@ -1,52 +1,52 @@ [ - "grafana_wordmark", - "worldping", - "raintank_wordmark", - "raintank_r-icn", - "check-alt", - "check", - "collector", - "dashboard", - "panel", - "datasources", - "endpoint-tiny", - "endpoint", - "page", - "filter", - "status", - "monitoring", - "monitoring-tiny", - "jump-to-dashboard", - "warning", - "nodata", - "critical", - "crit", - "online", - "event-error", - "event", - "sadface", - "private-collector", - "alert-disabled", - "refresh", - "save", - "share", - "star", - "search", - "remove", - "video", - "bulk_action", - "grabber", - "users", - "globe", - "snapshot", - "play-grafana-icon", - "grafana-icon", - "email", - "stopwatch", - "skull", - "probe", - "apps", - "scale", - "pending", - "verified" -] \ No newline at end of file + "grafana_wordmark", + "worldping", + "raintank_wordmark", + "raintank_r-icn", + "check-alt", + "check", + "collector", + "dashboard", + "panel", + "datasources", + "endpoint-tiny", + "endpoint", + "page", + "filter", + "status", + "monitoring", + "monitoring-tiny", + "jump-to-dashboard", + "warning", + "nodata", + "critical", + "crit", + "online", + "event-error", + "event", + "sadface", + "private-collector", + "alert-disabled", + "refresh", + "save", + "share", + "star", + "search", + "remove", + "video", + "bulk_action", + "grabber", + "users", + "globe", + "snapshot", + "play-grafana-icon", + "grafana-icon", + "email", + "stopwatch", + "skull", + "probe", + "apps", + "scale", + "pending", + "verified" +] diff --git a/public/sass/layout/_lists.scss b/public/sass/layout/_lists.scss index 3333e8d937b..63201f5fd98 100644 --- a/public/sass/layout/_lists.scss +++ b/public/sass/layout/_lists.scss @@ -1,4 +1,3 @@ - .ui-list { margin: 0; padding: 0; diff --git a/public/sass/layout/_page.scss b/public/sass/layout/_page.scss index 5702a1aa260..03941a47408 100644 --- a/public/sass/layout/_page.scss +++ b/public/sass/layout/_page.scss @@ -1,22 +1,75 @@ .grafana-app { - display: block; + display: flex; + align-items: stretch; + position: absolute; + width: 100%; height: 100%; + top: 0; + left: 0; } .main-view { - // height: 100%; REMOVED FOR FOOTER TRW + position: relative; + flex-grow: 1; + background: $page-gradient; } .page-container { - background-color: $page-bg; - padding: ($spacer * 2) ($spacer * 4); - max-width: 1060px; - min-height: calc(100% - 54px); - padding-bottom: $spacer * 5; - background-image: linear-gradient(60deg, transparent 70%, darken($page-bg, 4%) 98%) + margin-left: auto; + margin-right: auto; + padding-left: $spacer*2; + padding-right: $spacer*2; + max-width: 980px; + @include clearfix(); +} + +.scroll-canvas { + position: absolute; + width: 100%; + overflow: auto; + height: 100%; + + &--dashboard { + height: calc(100% - 56px); + } } .page-body { + padding-top: $spacer*2; + min-height: 500px; +} + +.page-heading { + font-size: 1.25rem; + margin-top: 0; + margin-bottom: $spacer * 0.7; +} + +.page-action-bar { + margin-bottom: $spacer * 2; + display: flex; + align-items: flex-start; + + > a, + > button { + margin-left: $spacer; + } +} + +.page-action-bar--narrow { + margin-bottom: 0; +} + +.page-action-bar__spacer { + width: $spacer * 2; + flex-grow: 1; +} + +.sidebar-content { + width: calc(100% - #{$page-sidebar-width + $page-sidebar-margin}); // sidebar width + margin +} + +.sidebar-container { @include media-breakpoint-up(md) { display: flex; flex-direction: row; @@ -24,10 +77,6 @@ } } -.page-content-with-sidebar { - width: calc(100% - #{$page-sidebar-width + $page-sidebar-margin}); // sidebar width + margin -} - .page-sidebar { @include media-breakpoint-up(md) { width: $page-sidebar-width; @@ -35,42 +84,14 @@ } } -.page-header { - padding: $spacer 0 0 0; - margin-bottom: 2rem; - @include brand-bottom-border(); - @include clearfix(); - - h1 { - flex-grow: 1; - display: inline-block; - margin-bottom: $spacer*1.5; - } - - button, a { - float: right; - margin-left: $spacer; - } +.page-sub-heading { + margin-bottom: $spacer; } -.page-heading { - font-size: 1.25rem; - margin-top: 0; - margin-bottom: $spacer * 0.7; -} - -.admin-page { - max-width: 800px; - margin-left: 10px; - h2 { - margin-left: 15px; - margin-bottom: 0px; - font-size: $font-size-lg; - color: $text-color; - i { - padding-right: 6px; - } - } +.page-sub-heading-icon { + margin-left: $spacer; + vertical-align: 6px; + font-size: 13px; } .page-sidebar { diff --git a/public/sass/mixins/_animations.scss b/public/sass/mixins/_animations.scss index 853dd34048e..18d9b6db456 100644 --- a/public/sass/mixins/_animations.scss +++ b/public/sass/mixins/_animations.scss @@ -1,19 +1,19 @@ @mixin keyframes($animation-name) { - @-webkit-keyframes #{$animation-name} { - @content; - } - @-moz-keyframes #{$animation-name} { - @content; - } - @-ms-keyframes #{$animation-name} { - @content; - } - @-o-keyframes #{$animation-name} { - @content; - } - @keyframes #{$animation-name} { - @content; - } + @-webkit-keyframes #{$animation-name} { + @content; + } + @-moz-keyframes #{$animation-name} { + @content; + } + @-ms-keyframes #{$animation-name} { + @content; + } + @-o-keyframes #{$animation-name} { + @content; + } + @keyframes #{$animation-name} { + @content; + } } @mixin animation($str) { diff --git a/public/sass/mixins/_buttons.scss b/public/sass/mixins/_buttons.scss index f77adc859c3..8561a03d02b 100644 --- a/public/sass/mixins/_buttons.scss +++ b/public/sass/mixins/_buttons.scss @@ -1,19 +1,22 @@ - // Button backgrounds // ------------------ -@mixin buttonBackground($startColor, $endColor, $text-color: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,.25)) { +@mixin buttonBackground($startColor, $endColor, $text-color: #fff, $textShadow: 0px 1px 0 rgba(0,0,0,0.1)) { // gradientBar will set the background to a pleasing blend of these, to support IE<=9 @include gradientBar($startColor, $endColor, $text-color, $textShadow); // in these cases the gradient won't cover the background, so we override - &:hover, &:focus, &:active, &.active, &.disabled, &[disabled] { + &:hover, + &:focus, + &:active, + &.active, + &.disabled, + &[disabled] { color: $text-color; background-image: none; background-color: $startColor; } } - // Button sizes @mixin button-size($padding-y, $padding-x, $font-size, $border-radius) { padding: $padding-y $padding-x; @@ -32,14 +35,14 @@ @include hover { color: #fff; background-color: $color; - border-color: $color; + border-color: $color; } &:focus, &.focus { color: #fff; background-color: $color; - border-color: $color; + border-color: $color; } &:active, @@ -47,14 +50,14 @@ .open > &.dropdown-toggle { color: #fff; background-color: $color; - border-color: $color; + border-color: $color; &:hover, &:focus, &.focus { color: #fff; background-color: darken($color, 17%); - border-color: darken($color, 25%); + border-color: darken($color, 25%); } } diff --git a/public/sass/mixins/_drop_element.scss b/public/sass/mixins/_drop_element.scss index f1bb69efd98..e7e53382e0e 100644 --- a/public/sass/mixins/_drop_element.scss +++ b/public/sass/mixins/_drop_element.scss @@ -1,4 +1,3 @@ - @mixin drop-theme($themeName, $theme-bg, $theme-color, $border-color: $theme-bg) { .drop-element.drop-#{$themeName} { max-width: 100%; @@ -11,7 +10,6 @@ background: $theme-bg; color: $theme-color; padding: 0.65rem; - font-size: $font-size-sm; word-wrap: break-word; max-width: 20rem; border: 1px solid $border-color; @@ -90,7 +88,8 @@ left: $popover-arrow-size * 2; } - &.drop-element-attached-top.drop-element-attached-left.drop-target-attached-middle .drop-content { + &.drop-element-attached-top.drop-element-attached-left.drop-target-attached-middle + .drop-content { margin-top: $popover-arrow-size; &:before { @@ -100,7 +99,8 @@ } } - &.drop-element-attached-top.drop-element-attached-right.drop-target-attached-middle .drop-content { + &.drop-element-attached-top.drop-element-attached-right.drop-target-attached-middle + .drop-content { margin-top: $popover-arrow-size; &:before { @@ -110,7 +110,8 @@ } } - &.drop-element-attached-bottom.drop-element-attached-left.drop-target-attached-middle .drop-content { + &.drop-element-attached-bottom.drop-element-attached-left.drop-target-attached-middle + .drop-content { margin-bottom: $popover-arrow-size; &:before { @@ -120,7 +121,8 @@ } } - &.drop-element-attached-bottom.drop-element-attached-right.drop-target-attached-middle .drop-content { + &.drop-element-attached-bottom.drop-element-attached-right.drop-target-attached-middle + .drop-content { margin-bottom: $popover-arrow-size; &:before { @@ -131,7 +133,8 @@ } // Top and bottom corners - &.drop-element-attached-top.drop-element-attached-left.drop-target-attached-bottom .drop-content { + &.drop-element-attached-top.drop-element-attached-left.drop-target-attached-bottom + .drop-content { margin-top: $popover-arrow-size; &:before { @@ -141,7 +144,8 @@ } } - &.drop-element-attached-top.drop-element-attached-right.drop-target-attached-bottom .drop-content { + &.drop-element-attached-top.drop-element-attached-right.drop-target-attached-bottom + .drop-content { margin-top: $popover-arrow-size; &:before { @@ -151,7 +155,8 @@ } } - &.drop-element-attached-bottom.drop-element-attached-left.drop-target-attached-top .drop-content { + &.drop-element-attached-bottom.drop-element-attached-left.drop-target-attached-top + .drop-content { margin-bottom: $popover-arrow-size; &:before { @@ -161,7 +166,8 @@ } } - &.drop-element-attached-bottom.drop-element-attached-right.drop-target-attached-top .drop-content { + &.drop-element-attached-bottom.drop-element-attached-right.drop-target-attached-top + .drop-content { margin-bottom: $popover-arrow-size; &:before { @@ -172,7 +178,8 @@ } // Side corners - &.drop-element-attached-top.drop-element-attached-right.drop-target-attached-left .drop-content { + &.drop-element-attached-top.drop-element-attached-right.drop-target-attached-left + .drop-content { margin-right: $popover-arrow-size; &:before { @@ -182,7 +189,8 @@ } } - &.drop-element-attached-top.drop-element-attached-left.drop-target-attached-right .drop-content { + &.drop-element-attached-top.drop-element-attached-left.drop-target-attached-right + .drop-content { margin-left: $popover-arrow-size; &:before { @@ -192,7 +200,8 @@ } } - &.drop-element-attached-bottom.drop-element-attached-right.drop-target-attached-left .drop-content { + &.drop-element-attached-bottom.drop-element-attached-right.drop-target-attached-left + .drop-content { margin-right: $popover-arrow-size; &:before { @@ -202,7 +211,8 @@ } } - &.drop-element-attached-bottom.drop-element-attached-left.drop-target-attached-right .drop-content { + &.drop-element-attached-bottom.drop-element-attached-left.drop-target-attached-right + .drop-content { margin-left: $popover-arrow-size; &:before { @@ -237,44 +247,55 @@ } } // Centers and middles - &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-center .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-center + .#{$themePrefix}-content { transform-origin: 50% calc(100% + #{$attachmentOffset}); } - &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-center .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-center + .#{$themePrefix}-content { transform-origin: 50% (-$attachmentOffset); } - &.#{$themePrefix}-element-attached-right.#{$themePrefix}-element-attached-middle .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-right.#{$themePrefix}-element-attached-middle + .#{$themePrefix}-content { transform-origin: calc(100% + #{$attachmentOffset}) 50%; } - &.#{$themePrefix}-element-attached-left.#{$themePrefix}-element-attached-middle .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-left.#{$themePrefix}-element-attached-middle + .#{$themePrefix}-content { transform-origin: -($attachmentOffset 50%); } // Top and bottom corners - &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-bottom .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-bottom + .#{$themePrefix}-content { transform-origin: 0 (-$attachmentOffset); } - &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-bottom .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-bottom + .#{$themePrefix}-content { transform-origin: 100% (-$attachmentOffset); } - &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-top .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-top + .#{$themePrefix}-content { transform-origin: 0 calc(100% + #{$attachmentOffset}); } - &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-top .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-top + .#{$themePrefix}-content { transform-origin: 100% calc(100% + #{$attachmentOffset}); } // Side corners - &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-left .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-left + .#{$themePrefix}-content { transform-origin: calc(100% + #{$attachmentOffset}) 0; } - &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-right .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-top.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-right + .#{$themePrefix}-content { transform-origin: (-$attachmentOffset) 0; } - &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-left .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-right.#{$themePrefix}-target-attached-left + .#{$themePrefix}-content { transform-origin: calc(100% + #{$attachmentOffset}) 100%; } - &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-right .#{$themePrefix}-content { + &.#{$themePrefix}-element-attached-bottom.#{$themePrefix}-element-attached-left.#{$themePrefix}-target-attached-right + .#{$themePrefix}-content { transform-origin: (-$attachmentOffset) 100%; } } } - diff --git a/public/sass/mixins/_forms.scss b/public/sass/mixins/_forms.scss index 5138cdf0a99..ce488f0f636 100644 --- a/public/sass/mixins/_forms.scss +++ b/public/sass/mixins/_forms.scss @@ -41,7 +41,8 @@ &:focus { border-color: $input-border-focus; outline: none; - $shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $input-box-shadow-focus; + $shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), + 0 0 5px $input-box-shadow-focus; @include box-shadow($shadow); } } diff --git a/public/sass/mixins/_grid-framework.scss b/public/sass/mixins/_grid-framework.scss index 15d1e6bdf86..c14671f6628 100644 --- a/public/sass/mixins/_grid-framework.scss +++ b/public/sass/mixins/_grid-framework.scss @@ -16,7 +16,7 @@ max-width: 100%; min-height: 1px; padding-right: ($grid-gutter-width / 2); - padding-left: ($grid-gutter-width / 2); + padding-left: ($grid-gutter-width / 2); } } @@ -29,16 +29,17 @@ @each $modifier in (pull, push) { @for $i from 0 through $columns { .#{$modifier}-#{$breakpoint}-#{$i} { - @include make-col-modifier($modifier, $i, $columns) + @include make-col-modifier($modifier, $i, $columns); } } } // `$columns - 1` because offsetting by the width of an entire row isn't possible @for $i from 0 through ($columns - 1) { - @if $breakpoint-counter != 1 or $i != 0 { // Avoid emitting useless .col-xs-offset-0 + @if $breakpoint-counter != 1 or $i != 0 { + // Avoid emitting useless .col-xs-offset-0 .offset-#{$breakpoint}-#{$i} { - @include make-col-modifier(offset, $i, $columns) + @include make-col-modifier(offset, $i, $columns); } } } diff --git a/public/sass/mixins/_grid.scss b/public/sass/mixins/_grid.scss index 6e67f92cd39..abfc28ab61c 100644 --- a/public/sass/mixins/_grid.scss +++ b/public/sass/mixins/_grid.scss @@ -5,14 +5,13 @@ @mixin make-container($gutter: $grid-gutter-width) { margin-left: auto; margin-right: auto; - padding-left: ($gutter / 2); + padding-left: ($gutter / 2); padding-right: ($gutter / 2); @if not $enable-flex { @include clearfix(); } } - // For each breakpoint, define the maximum width of the container in a media query @mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) { @each $breakpoint, $container-max-width in $max-widths { @@ -29,7 +28,7 @@ } @else { @include clearfix(); } - margin-left: ($gutter / -2); + margin-left: ($gutter / -2); margin-right: ($gutter / -2); } @@ -37,7 +36,7 @@ position: relative; min-height: 1px; padding-right: ($grid-gutter-width / 2); - padding-left: ($grid-gutter-width / 2); + padding-left: ($grid-gutter-width / 2); @if $enable-flex { flex: 0 0 percentage($size / $columns); diff --git a/public/sass/mixins/_hover.scss b/public/sass/mixins/_hover.scss index 3a11254e847..2f2c0c1e43f 100644 --- a/public/sass/mixins/_hover.scss +++ b/public/sass/mixins/_hover.scss @@ -3,23 +3,29 @@ // See Media Queries Level 4: http://drafts.csswg.org/mediaqueries/#hover // Currently shimmed by https://github.com/twbs/mq4-hover-shim @media (hover: hover) { - &:hover { @content } + &:hover { + @content; + } + } + } @else { + &:hover { + @content; } - } - @else { - &:hover { @content } } } @mixin hover-focus { @if $enable-hover-media-query { - &:focus { @content } - @include hover { @content } - } - @else { + &:focus { + @content; + } + @include hover { + @content; + } + } @else { &:focus, &:hover { - @content + @content; } } } @@ -28,15 +34,16 @@ @if $enable-hover-media-query { &, &:focus { - @content + @content; } - @include hover { @content } - } - @else { + @include hover { + @content; + } + } @else { &, &:focus, &:hover { - @content + @content; } } } @@ -45,15 +52,16 @@ @if $enable-hover-media-query { &:focus, &:active { - @content + @content; } - @include hover { @content } - } - @else { + @include hover { + @content; + } + } @else { &:focus, &:active, &:hover { - @content + @content; } } } diff --git a/public/sass/mixins/_mixins.scss b/public/sass/mixins/_mixins.scss index 78f9d3fca08..f3be6af56ba 100644 --- a/public/sass/mixins/_mixins.scss +++ b/public/sass/mixins/_mixins.scss @@ -1,4 +1,3 @@ - @mixin clearfix() { &::after { content: ""; @@ -73,7 +72,6 @@ border: 0; } - // FONTS // -------------------------------------------------- @@ -110,7 +108,6 @@ @include font-shorthand($size, $weight, $lineHeight); } - // FORMS // -------------------------------------------------- @@ -122,7 +119,6 @@ @include box-sizing(border-box); // Makes inputs behave like true block-level elements } - // CSS3 PROPERTIES // -------------------------------------------------- @@ -146,13 +142,13 @@ } @mixin border-bottom-right-radius($radius) { -webkit-border-bottom-right-radius: $radius; - -moz-border-radius-bottomright: $radius; - border-bottom-right-radius: $radius; + -moz-border-radius-bottomright: $radius; + border-bottom-right-radius: $radius; } @mixin border-bottom-left-radius($radius) { -webkit-border-bottom-left-radius: $radius; - -moz-border-radius-bottomleft: $radius; - border-bottom-left-radius: $radius; + -moz-border-radius-bottomleft: $radius; + border-bottom-left-radius: $radius; } // Single Side Border Radius @@ -241,21 +237,21 @@ // CSS3 Content Columns @mixin content-columns($columnCount, $columnGap: $gridGutterWidth) { -webkit-column-count: $columnCount; - -moz-column-count: $columnCount; - column-count: $columnCount; + -moz-column-count: $columnCount; + column-count: $columnCount; -webkit-column-gap: $columnGap; - -moz-column-gap: $columnGap; - column-gap: $columnGap; + -moz-column-gap: $columnGap; + column-gap: $columnGap; } // Optional hyphenation @mixin hyphens($mode: auto) { word-wrap: break-word; -webkit-hyphens: $mode; - -moz-hyphens: $mode; - -ms-hyphens: $mode; - -o-hyphens: $mode; - hyphens: $mode; + -moz-hyphens: $mode; + -ms-hyphens: $mode; + -o-hyphens: $mode; + hyphens: $mode; } // Opacity @@ -269,16 +265,26 @@ // Add an alphatransparency value to any background or border color (via Elyse Holladay) #translucent { @mixin background($color: $white, $alpha: 1) { - background-color: hsla(hue($color), saturation($color), lightness($color), $alpha); + background-color: hsla( + hue($color), + saturation($color), + lightness($color), + $alpha + ); } @mixin border($color: $white, $alpha: 1) { - border-color: hsla(hue($color), saturation($color), lightness($color), $alpha); + border-color: hsla( + hue($color), + saturation($color), + lightness($color), + $alpha + ); @include background-clip(padding-box); } } // Gradient Bar Colors for buttons and alerts -@mixin gradientBar($primaryColor, $secondaryColor, $text-color: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,.25)) { +@mixin gradientBar($primaryColor, $secondaryColor, $text-color: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,0.25)) { color: $text-color; text-shadow: $textShadow; @include gradient-vertical($primaryColor, $secondaryColor); @@ -288,37 +294,66 @@ // Gradients @mixin gradient-horizontal($startColor: #555, $endColor: #333) { background-color: $endColor; - background-image: linear-gradient(to right, $startColor, $endColor); // Standard, IE10 + background-image: linear-gradient( + to right, + $startColor, + $endColor + ); // Standard, IE10 background-repeat: repeat-x; } @mixin gradient-vertical($startColor: #555, $endColor: #333) { background-color: mix($startColor, $endColor, 60%); - background-image: linear-gradient(to bottom, $startColor, $endColor); // Standard, IE10 + background-image: linear-gradient( + to bottom, + $startColor, + $endColor + ); // Standard, IE10 background-repeat: repeat-x; } @mixin gradient-directional($startColor: #555, $endColor: #333, $deg: 45deg) { background-color: $endColor; background-repeat: repeat-x; - background-image: linear-gradient($deg, $startColor, $endColor); // Standard, IE10 + background-image: linear-gradient( + $deg, + $startColor, + $endColor + ); // Standard, IE10 } @mixin gradient-horizontal-three-colors($startColor: #00b3ee, $midColor: #7a43b6, $colorStop: 50%, $endColor: #c3325f) { background-color: mix($midColor, $endColor, 80%); - background-image: linear-gradient(to right, $startColor, $midColor $colorStop, $endColor); + background-image: linear-gradient( + to right, + $startColor, + $midColor $colorStop, + $endColor + ); background-repeat: no-repeat; } @mixin gradient-vertical-three-colors($startColor: #00b3ee, $midColor: #7a43b6, $colorStop: 50%, $endColor: #c3325f) { background-color: mix($midColor, $endColor, 80%); - background-image: linear-gradient($startColor, $midColor $colorStop, $endColor); + background-image: linear-gradient( + $startColor, + $midColor $colorStop, + $endColor + ); background-repeat: no-repeat; } @mixin gradient-radial($innerColor: #555, $outerColor: #333) { background-color: $outerColor; - background-image: -webkit-gradient(radial, center center, 0, center center, 460, from($innerColor), to($outerColor)); + background-image: -webkit-gradient( + radial, + center center, + 0, + center center, + 460, + from($innerColor), + to($outerColor) + ); background-image: -webkit-radial-gradient(circle, $innerColor, $outerColor); background-image: -moz-radial-gradient(circle, $innerColor, $outerColor); background-image: -o-radial-gradient(circle, $innerColor, $outerColor); @@ -327,16 +362,29 @@ @mixin striped($color: #555, $angle: 45deg) { background-color: $color; - background-image: linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: linear-gradient( + $angle, + rgba(255, 255, 255, 0.15) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, 0.15) 50%, + rgba(255, 255, 255, 0.15) 75%, + transparent 75%, + transparent + ); } -@mixin left-brand-border() { - border-left: 2px solid transparent; +@mixin left-brand-border($color: transparent) { + border-left: 2px solid $color; } @mixin left-brand-border-gradient() { border: none; - border-image: linear-gradient(rgba(255,213,0,1) 0%, rgba(255,68,0,1) 99%, rgba(255,68,0,1) 100%); + border-image: linear-gradient( + rgba(255, 213, 0, 1) 0%, + rgba(255, 68, 0, 1) 99%, + rgba(255, 68, 0, 1) 100% + ); border-image-slice: 1; border-style: solid; border-top: 0; @@ -355,4 +403,16 @@ border-bottom-width: 1px; } +@mixin list-item() { + display: block; + margin: 3px; + padding: 7px; + background: $list-item-bg; + box-shadow: $list-item-shadow; + color: $list-item-link-color; + &:hover { + background: $list-item-hover-bg; + color: $list-item-link-color; + } +} diff --git a/public/sass/pages/_admin.scss b/public/sass/pages/_admin.scss index b2be062849d..32f47212131 100644 --- a/public/sass/pages/_admin.scss +++ b/public/sass/pages/_admin.scss @@ -1,4 +1,3 @@ - .admin-settings-section { color: $variable; font-weight: bold; diff --git a/public/sass/pages/_alerting.scss b/public/sass/pages/_alerting.scss index 6db3470f3ea..f44e26d5c20 100644 --- a/public/sass/pages/_alerting.scss +++ b/public/sass/pages/_alerting.scss @@ -28,72 +28,9 @@ border: 0; } -// Alert List - -.alert-list { - display: flex; - flex-direction: row; - justify-content: space-between; -} - -.alert-list-icon { - font-weight: bold; - display: flex; - justify-content: center; - align-items: center; - .icon-gf, .fa { - font-size: 200%; - position: relative; - top: 2px; - } -} - -.alert-list-body { - display: flex; -} - -.alert-list-main { - padding: 0 2rem; - display: flex; - flex-direction: column; - justify-content: center; -} - -.alert-list-title { - font-size: $font-size-base; - margin: 0; - font-weight: 600; -} - -.alert-list-state { - font-weight: bold; -} - -.alert-list-text { - font-size: $font-size-sm; - margin: 0; - line-height: 1.5rem; - color: $text-color-weak; -} - -.alert-list-info { - color: $text-color; -} - -.alert-list-info-left { - padding-left: 2rem; -} - -.alert-list-footer { - display: flex; - justify-content: space-between; - flex-direction: column; - align-items: flex-end; -} - .panel-has-alert { .panel-alert-icon:before { - content: "\e611"; + content: '\e611'; position: relative; top: 1px; left: -3px; @@ -102,12 +39,12 @@ .panel-alert-state { &--alerting { - box-shadow: 0 0 10px rgba($critical,0.5); + box-shadow: 0 0 10px rgba($critical, 0.5); position: relative; .panel-alert-icon:before { color: $critical; - content: "\e610"; + content: '\e610'; } } @@ -118,16 +55,15 @@ z-index: -1; width: 100%; height: 100%; - box-shadow: 0 0 10px rgba($critical,1); + box-shadow: 0 0 10px rgba($critical, 1); opacity: 0; - animation: alerting-panel 1.6s cubic-bezier(1,.1,.73,1) 0s infinite alternate; + animation: alerting-panel 1.6s cubic-bezier(1, 0.1, 0.73, 1) 0s infinite alternate; } - &--ok { .panel-alert-icon:before { color: $online; - content: "\e611"; + content: '\e611'; } } } @@ -137,3 +73,94 @@ opacity: 1; } } + +// Alert List +// Alert List + +.alert-rule-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + list-style-type: none; +} + +.alert-rule-item { + display: flex; + width: 100%; + height: 100%; + background: $card-background; + box-shadow: $card-shadow; + padding: 4px 8px; + border-radius: 4px; + margin-bottom: 4px; +} + +.alert-rule-item__body { + display: flex; + flex-direction: column; + flex-grow: 1; + overflow: hidden; +} + +.alert-rule-item__icon { + display: flex; + justify-content: center; + align-items: center; + width: 40px; + padding: 0 28px 0 16px; + .icon-gf, + .fa { + font-size: 200%; + position: relative; + top: 2px; + } +} + +.alert-rule-item__header { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.alert-rule-item__name { + font-size: $font-size-base; + margin: 0; + font-weight: $font-weight-semi-bold; +} + +.alert-list__btn { + margin: 0 2px; + display: flex; + align-items: center; + justify-content: center; +} + +.alert-rule-item__text { + font-weight: bold; + font-size: $font-size-sm; + margin: 0; +} + +.alert-rule-item__time { + color: $text-color-weak; + font-weight: normal; + white-space: nowrap; +} + +.alert-rule-item__info { + //color: $text-color; + font-weight: normal; + flex-grow: 2; + display: flex; + align-items: flex-end; +} + +.alert-rule-item__actions { + display: flex; + align-items: center; +} + +.alert-tesint { + display: flex; +} diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index 7aacbce4f6b..871db4dfc2d 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -1,47 +1,39 @@ .dashboard-container { padding: $dashboard-padding; width: 100%; -} - -.page-dashboard { - .main-view { - background-image: none; - } + min-height: 100%; } .template-variable { color: $variable; } - - div.flot-text { color: $text-color !important; } .panel { - display: inline-block; - float: left; + height: 100%; &--solo { - .resize-panel-handle { - display: none; - } .panel-container { border: none; + z-index: $zindex-sidemenu + 1; } } } -.panel-margin { - margin: 0 0.4rem 0.8rem 0.4rem; +.panel-height-helper { display: block; + height: 100%; } .panel-container { background-color: $panel-bg; - position: relative; border: $panel-border; + position: relative; + border-radius: 3px; + height: 100%; &.panel-transparent { background-color: transparent; @@ -50,36 +42,82 @@ div.flot-text { } .panel-content { - padding: 0px 10px 5px 10px; + padding: $panel-padding; + height: calc(100% - 27px); + position: relative; + overflow: hidden; } .panel-title-container { min-height: 9px; - padding-top: 4px; - cursor: pointer; + cursor: move; word-wrap: break-word; + display: block; } .panel-title { border: 0px; font-weight: $font-weight-semi-bold; position: relative; - cursor: pointer; width: 100%; display: block; + padding-bottom: 2px; +} + +.panel-title-text { + cursor: pointer; + font-weight: $font-weight-semi-bold; + + &:hover { + color: $link-hover-color; + } +} + +.panel-menu-container { + width: 1px; + height: 19px; + display: inline-block; +} + +.panel-menu-toggle { + color: $text-color-weak; + cursor: pointer; + padding: 3px 5px; + visibility: hidden; + opacity: 0; + position: absolute; + width: 16px; + height: 16px; + left: 1px; + top: 4px; + + &:hover { + color: $link-hover-color; + } } .panel-loading { - position:absolute; + position: absolute; top: -3px; right: 0px; z-index: 800; + font-size: $font-size-sm; + color: $text-color-weak; } .panel-header { text-align: center; + + &:hover { + transition: background-color 0.1s ease-in-out; + background-color: $panel-header-hover-bg; + } } +.panel-menu { + top: 25px; + left: -100px; +} .panel-info-corner-inner { width: 0; @@ -106,21 +144,21 @@ div.flot-text { width: 27px; height: 27px; top: 0; - z-index: 10; + z-index: 1; .fa { position: relative; top: -4px; left: -6px; font-size: 75%; - z-index: 1000; + z-index: 1; } &--info { display: block; @include panel-corner-color(lighten($panel-bg, 4%)); .fa:before { - content: "\f129"; + content: '\f129'; } } @@ -131,7 +169,7 @@ div.flot-text { left: -5px; } .fa:before { - content: "\f08e"; + content: '\f08e'; } } @@ -140,78 +178,16 @@ div.flot-text { color: $text-color; @include panel-corner-color($popover-error-bg); .fa:before { - content: "\f12a"; + content: '\f12a'; } } } -.panel-full-edit { - margin-top: 20px; - margin-bottom: 20px; -} - -.panel-menu { - z-index: 500; - position: absolute; - background: $tight-form-func-bg; - border: $panel-menu-border; - - .panel-menu-row { - white-space: nowrap; - border-bottom: $panel-menu-border; - &:last-child { - border-bottom: none; - } - } - - .panel-menu-link, .panel-menu-icon { - padding: 5px 10px; - } - - .panel-menu-link { - display: inline-block; - border-right: $panel-menu-border; - &:last-child { - border: none; - } - } - - .dropdown-menu { - text-align: left; - } -} - -.panel-highlight { - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 5px rgba(82,168,236,10.8) -} - -// .panel-hover-highlight { -// box-shadow: inset 0 1px 1px rgba(0,0,0,0.025), 0 0 1px rgba(82,168,236,0.5) -// } - -.on-drag-hover { - .panel-container { - box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 5px rgba(82,168,236,10.8) - } -} - -.panel-drop-zone { - display: none; - .panel-container { - border: $panel-border; - display: flex; - justify-content: center; - flex-direction: column; - text-align: center; - color: $text-color-faint; - font-weight: bold; - background: $panel-drop-zone-bg; - } -} - -.panel-in-fullscreen { - .panel-drop-zone { - display: none !important; +.panel-hover-highlight { + .panel-menu-toggle { + visibility: visible; + transition: opacity 0.1s ease-in 0.2s; + opacity: 1; } } @@ -222,45 +198,24 @@ div.flot-text { color: $blue; font-size: 85%; position: absolute; - top: 0; + top: 4px; right: 0; } -.resize-panel-handle { - cursor: nwse-resize; - position: absolute; - font-size: 10px; - bottom: 0; - right: 0; - width: 15px; - height: 15px; - display: block; - color: $text-color-faint; - - &:before { - left: initial; - right: -1px; - bottom: 0px; - position: absolute; - } -} - .dashboard-header { font-family: $headings-font-family; font-size: $font-size-h3; text-align: center; + overflow: hidden; + position: relative; + top: -10px; span { display: inline-block; @include brand-bottom-border(); - padding: 0.5rem .5rem .2rem .5rem; + padding: 0.5rem 0.5rem 0.2rem 0.5rem; } } -.dash-edit-view { - opacity: 0; - - &--open{ - opacity: 1; - transition: opacity 200ms ease-in-out; - } +.panel-full-edit { + margin: $dashboard-padding (-$dashboard-padding) 0 (-$dashboard-padding); } diff --git a/public/sass/pages/_errorpage.scss b/public/sass/pages/_errorpage.scss index e18306ea05a..51aba412f86 100644 --- a/public/sass/pages/_errorpage.scss +++ b/public/sass/pages/_errorpage.scss @@ -1,60 +1,106 @@ - // // Layout // +.error-container { + display: flex; + flex-direction: row; +} + .error-row { - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; } .error-column { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } -.error-space-between {justify-content: space-between;} +.error-space-between { + justify-content: space-between; +} .graph-box { - width: 62%; - padding: 2rem 1rem; + width: 62%; + padding: 2rem 1rem; } .info-box { - width: 38%; - padding: 2rem 1rem 6rem; + width: 38%; + padding: 2rem 1rem 2rem; } -.graph-percentage {padding: 0 0 1.5rem;} +.graph-percentage { + padding: 0 0 1.5rem; +} -.image-box {padding: .5rem} +.image-box { + padding: 0.5rem; +} -.left-margin{padding: 0 0 0 5rem;} +.left-margin { + padding: 0 0 0 5rem; +} -.current-box {justify-content: flex-end;} +.current-box { + justify-content: flex-end; +} // // Text // .current-text { - color: $blue; - font-weight: bold; - line-height: 1rem; + color: $blue; + font-weight: bold; + line-height: 1rem; } -.error-link {color: $orange;} +.error-link { + color: $orange; +} .error-minus { - color: #7eb26d; - padding: 0 .5rem; - line-height: 1.5rem; + color: #7eb26d; + padding: 0 0.5rem; + line-height: 1.5rem; } .graph-percentage p { - text-align: right; - margin: 0; - line-height: 1rem; + text-align: right; + margin: 0; + line-height: 1rem; } -.graph-text {margin: 0;} +.graph-text { + margin: 0; +} + +@include media-breakpoint-down(sm) { + .graph-box { + width: 50%; + } + + .info-box { + width: 50%; + } +} + +@include media-breakpoint-down(xs) { + .error-container { + flex-direction: column; + } + + .graph-box { + width: 100%; + } + + .info-box { + width: 100%; + } + + .error-full-width { + width: 100%; + } +} diff --git a/public/sass/pages/_history.scss b/public/sass/pages/_history.scss index 707a3a40545..ea845b78445 100644 --- a/public/sass/pages/_history.scss +++ b/public/sass/pages/_history.scss @@ -29,10 +29,13 @@ white-space: nowrap; position: relative; - &:before, &:after { + &:before, + &:after { } - &:after { left: -40px; } + &:after { + left: -40px; + } } .diff-line-number { @@ -44,7 +47,9 @@ width: 30px; } -.diff-line-number-hide { visibility: hidden; } +.diff-line-number-hide { + visibility: hidden; +} .diff-line-icon { color: $diff-json-icon; @@ -58,28 +63,49 @@ .diff-json-new, .diff-json-old, .diff-json-deleted, -.diff-json-added, { +.diff-json-added { color: $diff-json-changed-fg; - & .diff-line-number { color: $diff-json-changed-num; } + & .diff-line-number { + color: $diff-json-changed-num; + } } -.diff-json-new { background-color: $diff-json-new; } -.diff-json-old { background-color: $diff-json-old; } -.diff-json-added { background-color: $diff-json-added; } -.diff-json-deleted { background-color: $diff-json-deleted; } +.diff-json-new { + background-color: $diff-json-new; +} +.diff-json-old { + background-color: $diff-json-old; +} +.diff-json-added { + background-color: $diff-json-added; +} +.diff-json-deleted { + background-color: $diff-json-deleted; +} .diff-value { user-select: all; } // Basic -.diff-circle { margin-right: .5em; } -.diff-circle-changed { color: #f59433; } -.diff-circle-added { color: #29D761; } -.diff-circle-deleted { color: #fd474a; } +.diff-circle { + margin-right: 0.5em; +} +.diff-circle-changed { + color: #f59433; +} +.diff-circle-added { + color: #29d761; +} +.diff-circle-deleted { + color: #fd474a; +} -.diff-item-added, .diff-item-deleted { list-style: none; } +.diff-item-added, +.diff-item-deleted { + list-style: none; +} .diff-group { background: $diff-group-bg; @@ -88,7 +114,9 @@ padding: 10px 15px; margin: 1rem 0; - & .diff-group { padding: 0 5px; } + & .diff-group { + padding: 0 5px; + } } .diff-group-name { @@ -100,20 +128,24 @@ } .diff-summary-key { - padding-left: .25em; + padding-left: 0.25em; } .diff-list { padding-left: 40px; - & .diff-list { padding-left: 0; } + & .diff-list { + padding-left: 0; + } } .diff-item { color: $gray-2; line-height: 2.5; - & > div { display: inline; } + & > div { + display: inline; + } } .diff-item-changeset { @@ -125,7 +157,7 @@ border-radius: 3px; color: $diff-label-fg; display: inline; - font-size: .95rem; + font-size: 0.95rem; margin: 0 5px; padding: 3px 8px; } @@ -160,7 +192,7 @@ .diff-change-group { width: 100%; - color: rgba(223,224,225, .6); + color: rgba(223, 224, 225, 0.6); margin-bottom: 14px; } diff --git a/public/sass/pages/_login.scss b/public/sass/pages/_login.scss index 2b3426b45b5..8622eec4e99 100644 --- a/public/sass/pages/_login.scss +++ b/public/sass/pages/_login.scss @@ -1,42 +1,113 @@ -.login-container { - background-position: left; - background-size: 60%; +$login-border: #8daac5; + +.login { + background-position: center; + min-height: 85vh; background-repeat: no-repeat; min-width: 100%; margin-left: 0; - margin-top: -26px; /* BAD HACK - experiement to see how it looks */ - padding-top: $spacer * 5; /* BAD HACK - experiement to see how it looks */ + background-color: $black; + display: flex; + align-items: center; + justify-content: center; + background-image: url(../img/heatmap_bg_test.svg); + background-size: cover; +} + +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +input:-webkit-autofill, +textarea:-webkit-autofill, +textarea:-webkit-autofill:hover, +textarea:-webkit-autofill:focus, +select:-webkit-autofill, +select:-webkit-autofill:hover, +select:-webkit-autofill:focus { + -webkit-box-shadow: 0 0 0px 1000px $black inset; + -webkit-text-fill-color: $gray-7 !important; +} + +.login-form-group { + display: flex; + flex-direction: column; + width: 100%; + align-items: center; + margin-bottom: 1rem; } .login-form { - display: inline-block; - max-width: 24rem; + margin-bottom: 1rem; + width: 100%; } -.login-box { - max-width: 700px; - margin: 0 auto; /* was $spacer * 2 auto 0 auto; */ -} +.login-form-input { + border: 1px solid $login-border; + border-radius: 4px; + opacity: 0.6; -.login-box-logo { - text-align: center; - margin-bottom: $spacer * 2; - img { - width: 6rem; + &:focus { + border: 1px solid $login-border; } +} + +.login-button-group { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + width: 100%; + margin-top: 0.5rem; +} + +.login-button-forgot-password { + padding-top: 1rem; +} + +.login-text { + font-size: $font-size-sm; +} + +.login-content { + max-width: 700px; + display: flex; + align-items: stretch; + flex-direction: column; + position: relative; + z-index: 1; +} + +.login-branding { + width: 100%; + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + flex-grow: 0; + + .logo-icon { + width: 70px; + margin-bottom: 15px; + } + .icon-gf-grafana_wordmark { color: $link-color; position: relative; - top: -4.5rem; - font-size: 2.5rem; - text-shadow: 3px 3px 5px black; + font-size: 2rem; + text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); } } .login-inner-box { - background: $panel-bg; text-align: center; - padding-bottom: 3rem; + padding: 2rem 4rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex-grow: 1; + max-width: 415px; } .login-tab-header { @@ -45,6 +116,12 @@ margin-bottom: 3rem; } +.btn-signup { + color: $white; + border: 1px solid $login-border; + background-color: $btn-semi-transparent; +} + .btn-login-tab { background: transparent; border: none; @@ -98,30 +175,7 @@ } .login-oauth { - - .btn { - margin: 5px; - } - - .btn-google { - background: #dd4b39; - color: white; - } - - .btn-github { - background: #555; - color: white; - } - - .btn-grafana-com { - @include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl, $btn-inverse-text-color); - box-shadow: $card-shadow; - - img { - width: 19px; - vertical-align: sub; - } - } + width: 100%; } .password-recovery { @@ -134,13 +188,15 @@ .login-divider { float: left; - width: 50%; - margin: 5px 25% 25px 25%; + width: 100%; + margin: 0 25% 1rem 25%; + display: flex; + justify-content: space-between; .login-divider-line { - width: 100%; + width: 110px; height: 10px; - border-bottom: 1px solid $gray-1; + border-bottom: 1px solid $login-border; .login-divider-text { background-color: $panel-bg; @@ -150,6 +206,25 @@ } } +.login-signup-box { + display: flex; + align-items: center; + justify-content: flex-end; + width: 100%; + margin-top: 1rem; +} + +.login-signup-title { + justify-self: flex-start; + flex: 1; + text-align: left; +} + +.login-btn { + width: 100%; + margin: 0 0 1rem; +} + .signup-page-background { position: fixed; top: 0; @@ -190,14 +265,135 @@ } } -@include media-breakpoint-up(md) { - .login-box-logo { - img { - width: 125px; - } - .icon-gf-grafana_wordmark { - top: -5px; - font-size: 3rem; +@include media-breakpoint-up(sm) { + .login-content { + flex-direction: row; + } + + .login-branding { + width: 35%; + padding: 4rem 2rem; + border-right: 1px solid $login-border; + justify-content: flex-start; + } + + .login-inner-box { + width: 65%; + padding: 1rem 2rem; + } + + .login-branding { + .logo-icon { + width: 80px; } } } + +@include media-breakpoint-up(md) { + .login-branding { + width: 45%; + padding: 2rem 4rem; + + .logo-icon { + width: 130px; + } + + .icon-gf-grafana_wordmark { + font-size: 3.2rem; + } + } + + .login-inner-box { + width: 55%; + padding: 1rem 4rem; + } + + .login-button-group { + flex-direction: row; + } + + .login-button-forgot-password { + padding-top: 0; + padding-left: 10px; + } +} + +@include media-breakpoint-up(lg) { + .login { + min-height: 100vh; + } + + .login-form-input { + min-width: 300px; + } +} + +.login-bg { + position: absolute; + top: 0; + left: 0; + right: 0; + perspective: 1000px; + display: flex; + flex-wrap: wrap; + z-index: 0; + flex-direction: column; + justify-content: stretch; + justify-items: stretch; + height: 100%; + + .login-bg__row { + display: flex; + flex-grow: 1; + height: 10px; + justify-content: stretch; + } + + .login-bg__item { + width: 4%; + height: 100%; + flex-grow: 1; + // background: hotpink; + // border:1px solid #0F1926; + transition: 1s ease-in-out; + z-index: 1; + transform-style: preserve-3d; + + &.login-bg-flip { + transform: rotateY(180deg); + } + + &:before, + &:after { + backface-visibility: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 100%; + content: ""; + display: block; + } + + &:after { + transform: rotateY(180deg); + background-color: rgb(25, 50, 80); + } + } +} + +.login-bg-fx { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 100%; + background-image: -webkit-radial-gradient( + center center, + ellipse farthest-corner, + transparent 0%, + transparent 10%, + rgba(18, 22, 29, 1) 100% + ); + z-index: 2; +} diff --git a/public/sass/pages/_playlist.scss b/public/sass/pages/_playlist.scss index d0d8f04f130..5dd1c92cbd2 100644 --- a/public/sass/pages/_playlist.scss +++ b/public/sass/pages/_playlist.scss @@ -27,7 +27,6 @@ margin-bottom: 15px; } - .playlist-search-field-wrapper { input { width: 100%; @@ -50,18 +49,20 @@ display: block; line-height: 28px; - .search-item:hover, .search-item.selected { - background-color: $grafanaListHighlight; + .search-item:hover, + .search-item.selected { + background-color: $list-item-hover-bg; } .selected { .search-result-tag { - opacity: 0.70; + opacity: 0.7; color: white; } } - .fa-star, .fa-star-o { + .fa-star, + .fa-star-o { padding-left: 13px; } @@ -70,7 +71,7 @@ } .search-result-link { - color: $grafanaListMainLinkColor; + color: $list-item-link-color; .fa { padding-right: 10px; } @@ -80,7 +81,7 @@ display: block; padding: 3px 10px; white-space: nowrap; - background-color: $grafanaListBackground; + background-color: $list-item-bg; margin-bottom: 4px; .search-result-icon:before { content: "\f009"; diff --git a/public/sass/pages/_plugins.scss b/public/sass/pages/_plugins.scss index c93d94f40b5..15149dd0d35 100644 --- a/public/sass/pages/_plugins.scss +++ b/public/sass/pages/_plugins.scss @@ -1,42 +1,3 @@ -.plugin-header { - @include clearfix(); - - padding: $spacer 0 $spacer/2 0; - margin-bottom: 2rem; -} - -.plugin-header-logo { - float: left; - width: 7rem; - img { - width: 7rem; - } - margin-right: $spacer; -} - -.plugin-header-info-block { - float: left; -} - -.plugin-header-author { -} - -.plugin-header-stamps-type { - color: $link-color-disabled; - text-transform: uppercase; -} - -.plugin-info-list-item { - img { - width: 16px; - } - - white-space: nowrap; - max-width: $page-sidebar-width; - text-overflow: ellipsis; - overflow: hidden; -} - .get-more-plugins-link { color: $gray-3; font-size: $font-size-sm; @@ -55,3 +16,14 @@ display: none; } } + +.plugin-info-list-item { + img { + width: 16px; + } + + white-space: nowrap; + max-width: $page-sidebar-width; + text-overflow: ellipsis; + overflow: hidden; +} diff --git a/public/sass/pages/_signup.scss b/public/sass/pages/_signup.scss index 7b2b0b0e84a..2c9d50ebc5d 100644 --- a/public/sass/pages/_signup.scss +++ b/public/sass/pages/_signup.scss @@ -15,3 +15,8 @@ } } +.signup__password-strength { + position: absolute; + margin-left: 9rem; + width: 194px; +} diff --git a/public/sass/pages/_styleguide.scss b/public/sass/pages/_styleguide.scss index ada2f533eca..ef4af9e4930 100644 --- a/public/sass/pages/_styleguide.scss +++ b/public/sass/pages/_styleguide.scss @@ -9,9 +9,15 @@ font-size: $font-size-sm; } -.color-card-body-bg { background-color: $body-bg; } -.color-card-page-bg { background-color: $page-bg; } -.color-card-gray { background-color: $gray-1; } +.color-card-body-bg { + background-color: $body-bg; +} +.color-card-page-bg { + background-color: $page-bg; +} +.color-card-gray { + background-color: $gray-1; +} .style-guide-button-list { padding: $spacer; @@ -25,4 +31,3 @@ font-size: 1.8em; text-align: center; } - diff --git a/public/sass/utils/_angular.scss b/public/sass/utils/_angular.scss index 1519b249920..53ea1573245 100644 --- a/public/sass/utils/_angular.scss +++ b/public/sass/utils/_angular.scss @@ -1,7 +1,5 @@ - - -[ng\:cloak], [ng-cloak], .ng-cloak { +[ng\:cloak], +[ng-cloak], +.ng-cloak { display: none !important; } - - diff --git a/public/sass/utils/_flex.scss b/public/sass/utils/_flex.scss index bcf2c2fa2a5..f1e115528a7 100644 --- a/public/sass/utils/_flex.scss +++ b/public/sass/utils/_flex.scss @@ -2,31 +2,57 @@ @each $breakpoint in map-keys($grid-breakpoints) { // Flex column reordering @include media-breakpoint-up($breakpoint) { - .flex-#{$breakpoint}-first { order: -1; } - .flex-#{$breakpoint}-last { order: 1; } + .flex-#{$breakpoint}-first { + order: -1; + } + .flex-#{$breakpoint}-last { + order: 1; + } } // Alignment for every item @include media-breakpoint-up($breakpoint) { - .flex-items-#{$breakpoint}-top { align-items: flex-start; } - .flex-items-#{$breakpoint}-middle { align-items: center; } - .flex-items-#{$breakpoint}-bottom { align-items: flex-end; } + .flex-items-#{$breakpoint}-top { + align-items: flex-start; + } + .flex-items-#{$breakpoint}-middle { + align-items: center; + } + .flex-items-#{$breakpoint}-bottom { + align-items: flex-end; + } } // Alignment per item @include media-breakpoint-up($breakpoint) { - .flex-#{$breakpoint}-top { align-self: flex-start; } - .flex-#{$breakpoint}-middle { align-self: center; } - .flex-#{$breakpoint}-bottom { align-self: flex-end; } + .flex-#{$breakpoint}-top { + align-self: flex-start; + } + .flex-#{$breakpoint}-middle { + align-self: center; + } + .flex-#{$breakpoint}-bottom { + align-self: flex-end; + } } // Horizontal alignment of item @include media-breakpoint-up($breakpoint) { - .flex-items-#{$breakpoint}-left { justify-content: flex-start; } - .flex-items-#{$breakpoint}-center { justify-content: center; } - .flex-items-#{$breakpoint}-right { justify-content: flex-end; } - .flex-items-#{$breakpoint}-around { justify-content: space-around; } - .flex-items-#{$breakpoint}-between { justify-content: space-between; } + .flex-items-#{$breakpoint}-left { + justify-content: flex-start; + } + .flex-items-#{$breakpoint}-center { + justify-content: center; + } + .flex-items-#{$breakpoint}-right { + justify-content: flex-end; + } + .flex-items-#{$breakpoint}-around { + justify-content: space-around; + } + .flex-items-#{$breakpoint}-between { + justify-content: space-between; + } } } } diff --git a/public/sass/utils/_spacings.scss b/public/sass/utils/_spacings.scss index f106c0d826a..57f931ff2d7 100644 --- a/public/sass/utils/_spacings.scss +++ b/public/sass/utils/_spacings.scss @@ -2,33 +2,42 @@ .m-x-auto { margin-right: auto !important; - margin-left: auto !important; + margin-left: auto !important; } @each $prop, $abbrev in (margin: m, padding: p) { @each $size, $lengths in $spacers { - $length-x: map-get($lengths, x); - $length-y: map-get($lengths, y); + $length-x: map-get($lengths, x); + $length-y: map-get($lengths, y); - .#{$abbrev}-a-#{$size} { #{$prop}: $length-y $length-x !important; } // a = All sides - .#{$abbrev}-t-#{$size} { #{$prop}-top: $length-y !important; } - .#{$abbrev}-r-#{$size} { #{$prop}-right: $length-x !important; } - .#{$abbrev}-b-#{$size} { #{$prop}-bottom: $length-y !important; } - .#{$abbrev}-l-#{$size} { #{$prop}-left: $length-x !important; } + .#{$abbrev}-a-#{$size} { + #{$prop}: $length-y $length-x !important; + } // a = All sides + .#{$abbrev}-t-#{$size} { + #{$prop}-top: $length-y !important; + } + .#{$abbrev}-r-#{$size} { + #{$prop}-right: $length-x !important; + } + .#{$abbrev}-b-#{$size} { + #{$prop}-bottom: $length-y !important; + } + .#{$abbrev}-l-#{$size} { + #{$prop}-left: $length-x !important; + } // Axes .#{$abbrev}-x-#{$size} { - #{$prop}-right: $length-x !important; - #{$prop}-left: $length-x !important; + #{$prop}-right: $length-x !important; + #{$prop}-left: $length-x !important; } .#{$abbrev}-y-#{$size} { - #{$prop}-top: $length-y !important; + #{$prop}-top: $length-y !important; #{$prop}-bottom: $length-y !important; } } } - // Positioning .pos-f-t { diff --git a/public/sass/utils/_utils.scss b/public/sass/utils/_utils.scss index 39e4edfe7ed..3121a6f0c00 100644 --- a/public/sass/utils/_utils.scss +++ b/public/sass/utils/_utils.scss @@ -21,7 +21,7 @@ font-weight: bold; line-height: $line-height-base; color: $black; - text-shadow: 0 1px 0 rgba(255,255,255,1); + text-shadow: 0 1px 0 rgba(255, 255, 255, 1); &:hover, &:focus { @@ -47,7 +47,6 @@ button.close { // Utility classes // -------------------------------------------------- - // Quick floats .pull-right { float: right !important; @@ -75,3 +74,7 @@ button.close { .affix { position: fixed; } + +.d-inline-block { + display: inline-block; +} diff --git a/public/sass/utils/_validation.scss b/public/sass/utils/_validation.scss index c0dd44d59a0..86b7c008bfd 100644 --- a/public/sass/utils/_validation.scss +++ b/public/sass/utils/_validation.scss @@ -1,10 +1,7 @@ -input[type=text].ng-dirty.ng-invalid { +input[type="text"].ng-dirty.ng-invalid { } input.validation-error, input.ng-dirty.ng-invalid { box-shadow: inset 0 0px 5px $red; } - - - diff --git a/public/sass/utils/_widths.scss b/public/sass/utils/_widths.scss index cf324b35c72..2000982f08d 100644 --- a/public/sass/utils/_widths.scss +++ b/public/sass/utils/_widths.scss @@ -1,7 +1,9 @@ - - -.max-width { width: 100%; } -.width-auto { width: auto; } +.max-width { + width: 100%; +} +.width-auto { + width: auto; +} // widths @for $i from 1 through 30 { @@ -22,4 +24,3 @@ margin-left: ($spacer * $i) !important; } } - diff --git a/public/test/mocks/backend_srv.ts b/public/test/mocks/backend_srv.ts new file mode 100644 index 00000000000..666de593722 --- /dev/null +++ b/public/test/mocks/backend_srv.ts @@ -0,0 +1,8 @@ +export class BackendSrvMock { + search: any; + + constructor() { + } + +} + diff --git a/public/test/mocks/common.ts b/public/test/mocks/common.ts new file mode 100644 index 00000000000..1531f2ed176 --- /dev/null +++ b/public/test/mocks/common.ts @@ -0,0 +1,19 @@ +export const backendSrv = { + get: jest.fn(), + getDashboard: jest.fn(), + getDashboardByUid: jest.fn(), + getFolderByUid: jest.fn(), + post: jest.fn(), +}; + +export function createNavTree(...args) { + let root = []; + let node = root; + for (let arg of args) { + let child = { id: arg, url: `/url/${arg}`, text: `${arg}-Text`, children: [] }; + node.push(child); + node = child.children; + } + + return root; +} diff --git a/public/test/specs/helpers.d.ts b/public/test/specs/helpers.d.ts deleted file mode 100644 index 4b64bd79031..00000000000 --- a/public/test/specs/helpers.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare let helpers: any; -export default helpers; - - diff --git a/public/test/specs/helpers.js b/public/test/specs/helpers.js deleted file mode 100644 index eae57be7115..00000000000 --- a/public/test/specs/helpers.js +++ /dev/null @@ -1,182 +0,0 @@ -define([ - 'lodash', - 'app/core/config', - 'app/core/utils/datemath', -], function(_, config, dateMath) { - 'use strict'; - - config = config.default; - - function ControllerTestContext() { - var self = this; - - this.datasource = {}; - this.$element = {}; - this.annotationsSrv = {}; - this.timeSrv = new TimeSrvStub(); - this.templateSrv = new TemplateSrvStub(); - this.datasourceSrv = { - getMetricSources: function() {}, - get: function() { - return { - then: function(callback) { - callback(self.datasource); - } - }; - } - }; - - this.providePhase = function(mocks) { - return window.module(function($provide) { - $provide.value('datasourceSrv', self.datasourceSrv); - $provide.value('annotationsSrv', self.annotationsSrv); - $provide.value('timeSrv', self.timeSrv); - $provide.value('templateSrv', self.templateSrv); - $provide.value('$element', self.$element); - _.each(mocks, function(value, key) { - $provide.value(key, value); - }); - }); - }; - - this.createPanelController = function(Ctrl) { - return window.inject(function($controller, $rootScope, $q, $location, $browser) { - self.scope = $rootScope.$new(); - self.$location = $location; - self.$browser = $browser; - self.$q = $q; - self.panel = {type: 'test'}; - self.dashboard = {meta: {}}; - - $rootScope.appEvent = sinon.spy(); - $rootScope.onAppEvent = sinon.spy(); - $rootScope.colors = []; - - for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); } - - config.panels['test'] = {info: {}}; - self.ctrl = $controller(Ctrl, {$scope: self.scope}, { - panel: self.panel, dashboard: self.dashboard, row: {} - }); - }); - }; - - this.createControllerPhase = function(controllerName) { - return window.inject(function($controller, $rootScope, $q, $location, $browser) { - self.scope = $rootScope.$new(); - self.$location = $location; - self.$browser = $browser; - self.scope.contextSrv = {}; - self.scope.panel = {}; - self.scope.row = { panels:[] }; - self.scope.dashboard = {meta: {}}; - self.scope.dashboardMeta = {}; - self.scope.dashboardViewState = new DashboardViewStateStub(); - self.scope.appEvent = sinon.spy(); - self.scope.onAppEvent = sinon.spy(); - - $rootScope.colors = []; - for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); } - - self.$q = $q; - self.scope.skipDataOnInit = true; - self.scope.skipAutoInit = true; - self.controller = $controller(controllerName, { - $scope: self.scope - }); - }); - }; - } - - function ServiceTestContext() { - var self = this; - self.templateSrv = new TemplateSrvStub(); - self.timeSrv = new TimeSrvStub(); - self.datasourceSrv = {}; - self.backendSrv = {}; - self.$routeParams = {}; - - this.providePhase = function(mocks) { - return window.module(function($provide) { - _.each(mocks, function(key) { - $provide.value(key, self[key]); - }); - }); - }; - - this.createService = function(name) { - return window.inject(function($q, $rootScope, $httpBackend, $injector, $location, $timeout) { - self.$q = $q; - self.$rootScope = $rootScope; - self.$httpBackend = $httpBackend; - self.$location = $location; - - self.$rootScope.onAppEvent = function() {}; - self.$rootScope.appEvent = function() {}; - self.$timeout = $timeout; - - self.service = $injector.get(name); - }); - }; - } - - function DashboardViewStateStub() { - this.registerPanel = function() { - }; - } - - function TimeSrvStub() { - this.init = sinon.spy(); - this.time = { from:'now-1h', to: 'now'}; - this.timeRange = function(parse) { - if (parse === false) { - return this.time; - } - return { - from : dateMath.parse(this.time.from, false), - to : dateMath.parse(this.time.to, true) - }; - }; - - this.replace = function(target) { - return target; - }; - - this.setTime = function(time) { - this.time = time; - }; - } - - function ContextSrvStub() { - this.hasRole = function() { - return true; - }; - } - - function TemplateSrvStub() { - this.variables = []; - this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g }; - this.data = {}; - this.replace = function(text) { - return _.template(text, this.templateSettings)(this.data); - }; - this.init = function() {}; - this.getAdhocFilters = function() { return []; }; - this.fillVariableValuesForUrl = function() {}; - this.updateTemplateData = function() { }; - this.variableExists = function() { return false; }; - this.variableInitialized = function() { }; - this.highlightVariablesAsHtml = function(str) { return str; }; - this.setGrafanaVariable = function(name, value) { - this.data[name] = value; - }; - } - - return { - ControllerTestContext: ControllerTestContext, - TimeSrvStub: TimeSrvStub, - ContextSrvStub: ContextSrvStub, - ServiceTestContext: ServiceTestContext - }; - -}); diff --git a/public/test/specs/helpers.ts b/public/test/specs/helpers.ts new file mode 100644 index 00000000000..8e83915362f --- /dev/null +++ b/public/test/specs/helpers.ts @@ -0,0 +1,195 @@ +import _ from 'lodash'; +import config from 'app/core/config'; +import * as dateMath from 'app/core/utils/datemath'; +import {angularMocks, sinon} from '../lib/common'; +import {PanelModel} from 'app/features/dashboard/panel_model'; + +export function ControllerTestContext() { + var self = this; + + this.datasource = {}; + this.$element = {}; + this.annotationsSrv = {}; + this.timeSrv = new TimeSrvStub(); + this.templateSrv = new TemplateSrvStub(); + this.datasourceSrv = { + getMetricSources: function() {}, + get: function() { + return { + then: function(callback) { + callback(self.datasource); + }, + }; + }, + }; + + this.providePhase = function(mocks) { + return angularMocks.module(function($provide) { + $provide.value('datasourceSrv', self.datasourceSrv); + $provide.value('annotationsSrv', self.annotationsSrv); + $provide.value('timeSrv', self.timeSrv); + $provide.value('templateSrv', self.templateSrv); + $provide.value('$element', self.$element); + _.each(mocks, function(value, key) { + $provide.value(key, value); + }); + }); + }; + + this.createPanelController = function(Ctrl) { + return angularMocks.inject(function($controller, $rootScope, $q, $location, $browser) { + self.scope = $rootScope.$new(); + self.$location = $location; + self.$browser = $browser; + self.$q = $q; + self.panel = new PanelModel({type: 'test'}); + self.dashboard = {meta: {}}; + + $rootScope.appEvent = sinon.spy(); + $rootScope.onAppEvent = sinon.spy(); + $rootScope.colors = []; + + for (var i = 0; i < 50; i++) { + $rootScope.colors.push('#' + i); + } + + config.panels['test'] = {info: {}}; + self.ctrl = $controller( + Ctrl, + {$scope: self.scope}, + { + panel: self.panel, + dashboard: self.dashboard, + }, + ); + }); + }; + + this.createControllerPhase = function(controllerName) { + return angularMocks.inject(function($controller, $rootScope, $q, $location, $browser) { + self.scope = $rootScope.$new(); + self.$location = $location; + self.$browser = $browser; + self.scope.contextSrv = {}; + self.scope.panel = {}; + self.scope.dashboard = {meta: {}}; + self.scope.dashboardMeta = {}; + self.scope.dashboardViewState = new DashboardViewStateStub(); + self.scope.appEvent = sinon.spy(); + self.scope.onAppEvent = sinon.spy(); + + $rootScope.colors = []; + for (var i = 0; i < 50; i++) { + $rootScope.colors.push('#' + i); + } + + self.$q = $q; + self.scope.skipDataOnInit = true; + self.scope.skipAutoInit = true; + self.controller = $controller(controllerName, { + $scope: self.scope, + }); + }); + }; +} + +export function ServiceTestContext() { + var self = this; + self.templateSrv = new TemplateSrvStub(); + self.timeSrv = new TimeSrvStub(); + self.datasourceSrv = {}; + self.backendSrv = {}; + self.$routeParams = {}; + + this.providePhase = function(mocks) { + return angularMocks.module(function($provide) { + _.each(mocks, function(key) { + $provide.value(key, self[key]); + }); + }); + }; + + this.createService = function(name) { + return angularMocks.inject(function($q, $rootScope, $httpBackend, $injector, $location, $timeout) { + self.$q = $q; + self.$rootScope = $rootScope; + self.$httpBackend = $httpBackend; + self.$location = $location; + + self.$rootScope.onAppEvent = function() {}; + self.$rootScope.appEvent = function() {}; + self.$timeout = $timeout; + + self.service = $injector.get(name); + }); + }; +} + +export function DashboardViewStateStub() { + this.registerPanel = function() {}; +} + +export function TimeSrvStub() { + this.init = sinon.spy(); + this.time = {from: 'now-1h', to: 'now'}; + this.timeRange = function(parse) { + if (parse === false) { + return this.time; + } + return { + from: dateMath.parse(this.time.from, false), + to: dateMath.parse(this.time.to, true), + }; + }; + + this.replace = function(target) { + return target; + }; + + this.setTime = function(time) { + this.time = time; + }; +} + +export function ContextSrvStub() { + this.hasRole = function() { + return true; + }; +} + +export function TemplateSrvStub() { + this.variables = []; + this.templateSettings = {interpolate: /\[\[([\s\S]+?)\]\]/g}; + this.data = {}; + this.replace = function(text) { + return _.template(text, this.templateSettings)(this.data); + }; + this.init = function() {}; + this.getAdhocFilters = function() { + return []; + }; + this.fillVariableValuesForUrl = function() {}; + this.updateTemplateData = function() {}; + this.variableExists = function() { + return false; + }; + this.variableInitialized = function() {}; + this.highlightVariablesAsHtml = function(str) { + return str; + }; + this.setGrafanaVariable = function(name, value) { + this.data[name] = value; + }; +} + +var allDeps = { + ContextSrvStub: ContextSrvStub, + TemplateSrvStub: TemplateSrvStub, + TimeSrvStub: TimeSrvStub, + ControllerTestContext: ControllerTestContext, + ServiceTestContext: ServiceTestContext, + DashboardViewStateStub: DashboardViewStateStub +}; + +// for legacy +export default allDeps; diff --git a/public/vendor/jquery-ui/custom.js b/public/vendor/jquery-ui/custom.js new file mode 100644 index 00000000000..aa3e5d8b6ba --- /dev/null +++ b/public/vendor/jquery-ui/custom.js @@ -0,0 +1,4034 @@ +/*! jQuery UI - v1.12.1 - 2017-06-13 +* http://jqueryui.com +* Includes: widget.js, data.js, disable-selection.js, scroll-parent.js, widgets/draggable.js, widgets/droppable.js, widgets/resizable.js, widgets/mouse.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ "jquery" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function( $ ) { + +$.ui = $.ui || {}; + +var version = $.ui.version = "1.12.1"; + + +/*! + * jQuery UI Widget 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: Widget +//>>group: Core +//>>description: Provides a factory for creating stateful widgets with a common API. +//>>docs: http://api.jqueryui.com/jQuery.widget/ +//>>demos: http://jqueryui.com/widget/ + + + +var widgetUuid = 0; +var widgetSlice = Array.prototype.slice; + +$.cleanData = ( function( orig ) { + return function( elems ) { + var events, elem, i; + for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { + try { + + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } + + // Http://bugs.jquery.com/ticket/8235 + } catch ( e ) {} + } + orig( elems ); + }; +} )( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var existingConstructor, constructor, basePrototype; + + // ProxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + var proxiedPrototype = {}; + + var namespace = name.split( "." )[ 0 ]; + name = name.split( "." )[ 1 ]; + var fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + if ( $.isArray( prototype ) ) { + prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); + } + + // Create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + + // Allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // Allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + // Extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + + // Copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + + // Track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + } ); + + basePrototype = new base(); + + // We need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = ( function() { + function _super() { + return base.prototype[ prop ].apply( this, arguments ); + } + + function _superApply( args ) { + return base.prototype[ prop ].apply( this, args ); + } + + return function() { + var __super = this._super; + var __superApply = this._superApply; + var returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + } )(); + } ); + constructor.prototype = $.widget.extend( basePrototype, { + + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + } ); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // Redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, + child._proto ); + } ); + + // Remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widgetSlice.call( arguments, 1 ); + var inputIndex = 0; + var inputLength = input.length; + var key; + var value; + + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string"; + var args = widgetSlice.call( arguments, 1 ); + var returnValue = this; + + if ( isMethodCall ) { + + // If this is an empty collection, we need to have the instance method + // return undefined instead of the jQuery instance + if ( !this.length && options === "instance" ) { + returnValue = undefined; + } else { + this.each( function() { + var methodValue; + var instance = $.data( this, fullName ); + + if ( options === "instance" ) { + returnValue = instance; + return false; + } + + if ( !instance ) { + return $.error( "cannot call methods on " + name + + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + + if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + + " widget instance" ); + } + + methodValue = instance[ options ].apply( instance, args ); + + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + } ); + } + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat( args ) ); + } + + this.each( function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + } ); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
    ", + + options: { + classes: {}, + disabled: false, + + // Callbacks + create: null + }, + + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widgetUuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + this.classesElementLookup = {}; + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + } ); + this.document = $( element.style ? + + // Element within the document + element.ownerDocument : + + // Element is window or document + element.document || element ); + this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); + } + + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this._create(); + + if ( this.options.disabled ) { + this._setOptionDisabled( this.options.disabled ); + } + + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + + _getCreateOptions: function() { + return {}; + }, + + _getCreateEventData: $.noop, + + _create: $.noop, + + _init: $.noop, + + destroy: function() { + var that = this; + + this._destroy(); + $.each( this.classesElementLookup, function( key, value ) { + that._removeClass( value, key ); + } ); + + // We can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .off( this.eventNamespace ) + .removeData( this.widgetFullName ); + this.widget() + .off( this.eventNamespace ) + .removeAttr( "aria-disabled" ); + + // Clean up events and states + this.bindings.off( this.eventNamespace ); + }, + + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key; + var parts; + var curOption; + var i; + + if ( arguments.length === 0 ) { + + // Don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + + // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + + _setOption: function( key, value ) { + if ( key === "classes" ) { + this._setOptionClasses( value ); + } + + this.options[ key ] = value; + + if ( key === "disabled" ) { + this._setOptionDisabled( value ); + } + + return this; + }, + + _setOptionClasses: function( value ) { + var classKey, elements, currentElements; + + for ( classKey in value ) { + currentElements = this.classesElementLookup[ classKey ]; + if ( value[ classKey ] === this.options.classes[ classKey ] || + !currentElements || + !currentElements.length ) { + continue; + } + + // We are doing this to create a new jQuery object because the _removeClass() call + // on the next line is going to destroy the reference to the current elements being + // tracked. We need to save a copy of this collection so that we can add the new classes + // below. + elements = $( currentElements.get() ); + this._removeClass( currentElements, classKey ); + + // We don't use _addClass() here, because that uses this.options.classes + // for generating the string of classes. We want to use the value passed in from + // _setOption(), this is the new value of the classes option which was passed to + // _setOption(). We pass this value directly to _classes(). + elements.addClass( this._classes( { + element: elements, + keys: classKey, + classes: value, + add: true + } ) ); + } + }, + + _setOptionDisabled: function( value ) { + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this._removeClass( this.hoverable, null, "ui-state-hover" ); + this._removeClass( this.focusable, null, "ui-state-focus" ); + } + }, + + enable: function() { + return this._setOptions( { disabled: false } ); + }, + + disable: function() { + return this._setOptions( { disabled: true } ); + }, + + _classes: function( options ) { + var full = []; + var that = this; + + options = $.extend( { + element: this.element, + classes: this.options.classes || {} + }, options ); + + function processClassString( classes, checkOption ) { + var current, i; + for ( i = 0; i < classes.length; i++ ) { + current = that.classesElementLookup[ classes[ i ] ] || $(); + if ( options.add ) { + current = $( $.unique( current.get().concat( options.element.get() ) ) ); + } else { + current = $( current.not( options.element ).get() ); + } + that.classesElementLookup[ classes[ i ] ] = current; + full.push( classes[ i ] ); + if ( checkOption && options.classes[ classes[ i ] ] ) { + full.push( options.classes[ classes[ i ] ] ); + } + } + } + + this._on( options.element, { + "remove": "_untrackClassesElement" + } ); + + if ( options.keys ) { + processClassString( options.keys.match( /\S+/g ) || [], true ); + } + if ( options.extra ) { + processClassString( options.extra.match( /\S+/g ) || [] ); + } + + return full.join( " " ); + }, + + _untrackClassesElement: function( event ) { + var that = this; + $.each( that.classesElementLookup, function( key, value ) { + if ( $.inArray( event.target, value ) !== -1 ) { + that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); + } + } ); + }, + + _removeClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, false ); + }, + + _addClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, true ); + }, + + _toggleClass: function( element, keys, extra, add ) { + add = ( typeof add === "boolean" ) ? add : extra; + var shift = ( typeof element === "string" || element === null ), + options = { + extra: shift ? keys : extra, + keys: shift ? element : keys, + element: shift ? this.element : element, + add: add + }; + options.element.toggleClass( this._classes( options ), add ); + return this; + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement; + var instance = this; + + // No suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // No element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + + // Allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // Copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ); + var eventName = match[ 1 ] + instance.eventNamespace; + var selector = match[ 2 ]; + + if ( selector ) { + delegateElement.on( eventName, selector, handlerProxy ); + } else { + element.on( eventName, handlerProxy ); + } + } ); + }, + + _off: function( element, eventName ) { + eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; + element.off( eventName ).off( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); + }, + mouseleave: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); + } + } ); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); + }, + focusout: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); + } + } ); + }, + + _trigger: function( type, event, data ) { + var prop, orig; + var callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + + // The original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // Copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + + var hasOptions; + var effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + + if ( options.delay ) { + element.delay( options.delay ); + } + + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue( function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + } ); + } + }; +} ); + +var widget = $.widget; + + +/*! + * jQuery UI :data 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: :data Selector +//>>group: Core +//>>description: Selects elements which have data stored under the specified key. +//>>docs: http://api.jqueryui.com/data-selector/ + + +var data = $.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo( function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + } ) : + + // Support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + } +} ); + +/*! + * jQuery UI Disable Selection 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: disableSelection +//>>group: Core +//>>description: Disable selection of text content within the set of matched elements. +//>>docs: http://api.jqueryui.com/disableSelection/ + +// This file is deprecated + + +var disableSelection = $.fn.extend( { + disableSelection: ( function() { + var eventType = "onselectstart" in document.createElement( "div" ) ? + "selectstart" : + "mousedown"; + + return function() { + return this.on( eventType + ".ui-disableSelection", function( event ) { + event.preventDefault(); + } ); + }; + } )(), + + enableSelection: function() { + return this.off( ".ui-disableSelection" ); + } +} ); + + +/*! + * jQuery UI Scroll Parent 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: scrollParent +//>>group: Core +//>>description: Get the closest ancestor element that is scrollable. +//>>docs: http://api.jqueryui.com/scrollParent/ + + + +var scrollParent = $.fn.scrollParent = function( includeHidden ) { + var position = this.css( "position" ), + excludeStaticParent = position === "absolute", + overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, + scrollParent = this.parents().filter( function() { + var parent = $( this ); + if ( excludeStaticParent && parent.css( "position" ) === "static" ) { + return false; + } + return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + + parent.css( "overflow-x" ) ); + } ).eq( 0 ); + + return position === "fixed" || !scrollParent.length ? + $( this[ 0 ].ownerDocument || document ) : + scrollParent; +}; + + + + +// This file is deprecated +var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +/*! + * jQuery UI Mouse 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: Mouse +//>>group: Widgets +//>>description: Abstracts mouse-based interactions to assist in creating certain widgets. +//>>docs: http://api.jqueryui.com/mouse/ + + + +var mouseHandled = false; +$( document ).on( "mouseup", function() { + mouseHandled = false; +} ); + +var widgetsMouse = $.widget( "ui.mouse", { + version: "1.12.1", + options: { + cancel: "input, textarea, button, select, option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .on( "mousedown." + this.widgetName, function( event ) { + return that._mouseDown( event ); + } ) + .on( "click." + this.widgetName, function( event ) { + if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { + $.removeData( event.target, that.widgetName + ".preventClickEvent" ); + event.stopImmediatePropagation(); + return false; + } + } ); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.off( "." + this.widgetName ); + if ( this._mouseMoveDelegate ) { + this.document + .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); + } + }, + + _mouseDown: function( event ) { + + // don't let more than one widget handle mouseStart + if ( mouseHandled ) { + return; + } + + this._mouseMoved = false; + + // We may have missed mouseup (out of window) + ( this._mouseStarted && this._mouseUp( event ) ); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = ( event.which === 1 ), + + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ? + $( event.target ).closest( this.options.cancel ).length : false ); + if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if ( !this.mouseDelayMet ) { + this._mouseDelayTimer = setTimeout( function() { + that.mouseDelayMet = true; + }, this.options.delay ); + } + + if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { + this._mouseStarted = ( this._mouseStart( event ) !== false ); + if ( !this._mouseStarted ) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { + $.removeData( event.target, this.widgetName + ".preventClickEvent" ); + } + + // These delegates are required to keep context + this._mouseMoveDelegate = function( event ) { + return that._mouseMove( event ); + }; + this._mouseUpDelegate = function( event ) { + return that._mouseUp( event ); + }; + + this.document + .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function( event ) { + + // Only check for mouseups outside the document if you've moved inside the document + // at least once. This prevents the firing of mouseup in the case of IE<9, which will + // fire a mousemove event if content is placed under the cursor. See #7778 + // Support: IE <9 + if ( this._mouseMoved ) { + + // IE mouseup check - mouseup happened when mouse was out of window + if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && + !event.button ) { + return this._mouseUp( event ); + + // Iframe mouseup check - mouseup occurred in another document + } else if ( !event.which ) { + + // Support: Safari <=8 - 9 + // Safari sets which to 0 if you press any of the following keys + // during a drag (#14461) + if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || + event.originalEvent.metaKey || event.originalEvent.shiftKey ) { + this.ignoreMissingWhich = true; + } else if ( !this.ignoreMissingWhich ) { + return this._mouseUp( event ); + } + } + } + + if ( event.which || event.button ) { + this._mouseMoved = true; + } + + if ( this._mouseStarted ) { + this._mouseDrag( event ); + return event.preventDefault(); + } + + if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { + this._mouseStarted = + ( this._mouseStart( this._mouseDownEvent, event ) !== false ); + ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) ); + } + + return !this._mouseStarted; + }, + + _mouseUp: function( event ) { + this.document + .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) + .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); + + if ( this._mouseStarted ) { + this._mouseStarted = false; + + if ( event.target === this._mouseDownEvent.target ) { + $.data( event.target, this.widgetName + ".preventClickEvent", true ); + } + + this._mouseStop( event ); + } + + if ( this._mouseDelayTimer ) { + clearTimeout( this._mouseDelayTimer ); + delete this._mouseDelayTimer; + } + + this.ignoreMissingWhich = false; + mouseHandled = false; + event.preventDefault(); + }, + + _mouseDistanceMet: function( event ) { + return ( Math.max( + Math.abs( this._mouseDownEvent.pageX - event.pageX ), + Math.abs( this._mouseDownEvent.pageY - event.pageY ) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function( /* event */ ) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function( /* event */ ) {}, + _mouseDrag: function( /* event */ ) {}, + _mouseStop: function( /* event */ ) {}, + _mouseCapture: function( /* event */ ) { return true; } +} ); + + + + +// $.ui.plugin is deprecated. Use $.widget() extensions instead. +var plugin = $.ui.plugin = { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args, allowDisconnected ) { + var i, + set = instance.plugins[ name ]; + + if ( !set ) { + return; + } + + if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || + instance.element[ 0 ].parentNode.nodeType === 11 ) ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } +}; + + + +var safeActiveElement = $.ui.safeActiveElement = function( document ) { + var activeElement; + + // Support: IE 9 only + // IE9 throws an "Unspecified error" accessing document.activeElement from an - - - [[end]] +
    +
    +
    + + +
    +
    + + + [[if .GoogleTagManagerId]] + + + + + + [[end]] + + - diff --git a/scripts/build/Dockerfile b/scripts/build/Dockerfile index 6e48b42c8e8..8fde9eb1dcd 100644 --- a/scripts/build/Dockerfile +++ b/scripts/build/Dockerfile @@ -21,7 +21,7 @@ RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A170311380 RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash - && \ yum install -y nodejs --nogpgcheck -ENV GOLANG_VERSION 1.9.2 +ENV GOLANG_VERSION 1.9.3 RUN wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo && \ yum install -y yarn --nogpgcheck && \ diff --git a/scripts/grunt/default_task.js b/scripts/grunt/default_task.js index a96e4fdb377..719f0ab4e95 100644 --- a/scripts/grunt/default_task.js +++ b/scripts/grunt/default_task.js @@ -9,7 +9,6 @@ module.exports = function(grunt) { ]); grunt.registerTask('test', [ - 'clean:build', 'jscs', 'jshint', 'sasslint', @@ -20,6 +19,8 @@ module.exports = function(grunt) { ]); grunt.registerTask('precommit', [ + 'jscs', + 'jshint', 'sasslint', 'exec:tslint', 'no-only-tests' diff --git a/scripts/grunt/options/phantomjs.js b/scripts/grunt/options/phantomjs.js index af7deff305c..8c4e8dbd254 100644 --- a/scripts/grunt/options/phantomjs.js +++ b/scripts/grunt/options/phantomjs.js @@ -3,7 +3,7 @@ module.exports = function(config,grunt) { grunt.registerTask('phantomjs', 'Copy phantomjs binary to vendor/', function() { - var dest = './vendor/phantomjs/phantomjs'; + var dest = './tools/phantomjs/phantomjs'; var confDir = './node_modules/phantomjs-prebuilt/lib/'; if (process.platform === "win32") { diff --git a/scripts/grunt/release_task.js b/scripts/grunt/release_task.js index 28208ed0086..4fbc41cfb08 100644 --- a/scripts/grunt/release_task.js +++ b/scripts/grunt/release_task.js @@ -26,7 +26,7 @@ module.exports = function(grunt) { }); grunt.config('copy.backend_files', { expand: true, - src: ['conf/**', 'vendor/phantomjs/*', 'scripts/*'], + src: ['conf/**', 'tools/phantomjs/*', 'scripts/*'], options: { mode: true}, dest: '<%= tempDir %>' }); diff --git a/scripts/webpack/webpack.dev.js b/scripts/webpack/webpack.dev.js index 037212c26de..195ef54c5cc 100644 --- a/scripts/webpack/webpack.dev.js +++ b/scripts/webpack/webpack.dev.js @@ -10,7 +10,7 @@ const WebpackCleanupPlugin = require('webpack-cleanup-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = merge(common, { - devtool: "eval-source-map", + devtool: "cheap-module-source-map", entry: { dark: './public/sass/grafana.dark.scss', @@ -21,7 +21,7 @@ module.exports = merge(common, { module: { rules: [ require('./sass.rule.js')({ - sourceMap: true, minimize: false + sourceMap: false, minimize: false }) ] }, @@ -29,6 +29,7 @@ module.exports = merge(common, { plugins: [ new ExtractTextPlugin({ // define where to save the file filename: 'grafana.[name].css', + allChunks: true, }), new HtmlWebpackPlugin({ filename: path.resolve(__dirname, '../../public/views/index.html'), diff --git a/scripts/webpack/webpack.test.js b/scripts/webpack/webpack.test.js index 8983541a612..f30c7876185 100644 --- a/scripts/webpack/webpack.test.js +++ b/scripts/webpack/webpack.test.js @@ -3,7 +3,7 @@ const merge = require('webpack-merge'); const common = require('./webpack.common.js'); config = merge(common, { - devtool: 'inline-source-map', + devtool: 'cheap-module-source-map', externals: { 'react/addons': true, 'react/lib/ExecutionEnvironment': true, diff --git a/tests/api/clearState.test.ts b/tests/api/clearState.test.ts new file mode 100644 index 00000000000..8c5e5c1422b --- /dev/null +++ b/tests/api/clearState.test.ts @@ -0,0 +1,7 @@ +import * as setup from './setup'; + +describe.skip('clear state', () => { + it('will clear state', () => { + return setup.clearState(); + }); +}); diff --git a/tests/api/client.ts b/tests/api/client.ts new file mode 100644 index 00000000000..2e2f9ed67fd --- /dev/null +++ b/tests/api/client.ts @@ -0,0 +1,30 @@ +const axios = require('axios'); + +export function getClient(options) { + return axios.create({ + baseURL: 'http://localhost:3000', + timeout: 1000, + auth: { + username: options.username, + password: options.password, + }, + }); +} + +export function getAdminClient() { + return getClient({ + username: 'admin', + password: 'admin', + }); +} + +let client = getAdminClient(); + +client.callAs = function(user) { + return getClient({ + username: user.login, + password: 'password', + }); +}; + +export default client; diff --git a/tests/api/dashboard.test.ts b/tests/api/dashboard.test.ts new file mode 100644 index 00000000000..55beaffecb0 --- /dev/null +++ b/tests/api/dashboard.test.ts @@ -0,0 +1,45 @@ +import client from './client'; +import * as setup from './setup'; + +describe('/api/dashboards', () => { + let state: any = {}; + + beforeAll(async () => { + state = await setup.ensureState({ + orgName: 'api-test-org', + users: [ + { user: setup.admin, role: 'Admin' }, + { user: setup.editor, role: 'Editor' }, + { user: setup.viewer, role: 'Viewer' }, + ], + admin: setup.admin, + dashboards: [ + { + title: 'aaa', + uid: 'aaa', + }, + { + title: 'bbb', + uid: 'bbb', + }, + ], + }); + }); + + describe('With admin user', () => { + it('can delete dashboard', async () => { + let rsp = await client.callAs(setup.admin).delete(`/api/dashboards/uid/aaa`); + expect(rsp.data.title).toBe('aaa'); + }); + }); + + describe('With viewer user', () => { + it('Cannot delete dashboard', async () => { + let rsp = await setup.expectError(() => { + return client.callAs(setup.viewer).delete(`/api/dashboards/uid/bbb`); + }); + + expect(rsp.response.status).toBe(403); + }); + }); +}); diff --git a/tests/api/folder.test.ts b/tests/api/folder.test.ts new file mode 100644 index 00000000000..0d40972aa6d --- /dev/null +++ b/tests/api/folder.test.ts @@ -0,0 +1,78 @@ +import client from './client'; +import * as setup from './setup'; + +describe('/api/folders', () => { + let state: any = {}; + + beforeAll(async () => { + state = await setup.ensureState({ + orgName: 'api-test-org', + users: [ + { user: setup.admin, role: 'Admin' }, + { user: setup.editor, role: 'Editor' }, + { user: setup.viewer, role: 'Viewer' }, + ], + admin: setup.admin, + folders: [ + { + title: 'Folder 1', + uid: 'f-01', + }, + { + title: 'Folder 2', + uid: 'f-02', + }, + { + title: 'Folder 3', + uid: 'f-03', + }, + ], + }); + }); + + describe('With admin user', () => { + it('can delete folder', async () => { + let rsp = await client.callAs(setup.admin).delete(`/api/folders/f-01`); + expect(rsp.data.title).toBe('Folder 1'); + }); + + it('can update folder', async () => { + let rsp = await client.callAs(setup.admin).put(`/api/folders/f-02`, { + uid: 'f-02', + title: 'Folder 2 upd', + overwrite: true, + }); + expect(rsp.data.title).toBe('Folder 2 upd'); + }); + + it('can update folder uid', async () => { + let rsp = await client.callAs(setup.admin).put(`/api/folders/f-03`, { + uid: 'f-03-upd', + title: 'Folder 3 upd', + overwrite: true, + }); + expect(rsp.data.uid).toBe('f-03-upd'); + expect(rsp.data.title).toBe('Folder 3 upd'); + }); + }); + + describe('With viewer user', () => { + it('Cannot delete folder', async () => { + let rsp = await setup.expectError(() => { + return client.callAs(setup.viewer).delete(`/api/folders/f-02`); + }); + expect(rsp.response.status).toBe(403); + }); + + it('Cannot update folder', async () => { + let rsp = await setup.expectError(() => { + return client.callAs(setup.viewer).put(`/api/folders/f-02`, { + uid: 'f-02', + title: 'Folder 2 upd', + overwrite: true, + }); + }); + expect(rsp.response.status).toBe(403); + }); + }); +}); diff --git a/tests/api/jest.js b/tests/api/jest.js new file mode 100644 index 00000000000..b32573115b7 --- /dev/null +++ b/tests/api/jest.js @@ -0,0 +1,19 @@ +module.exports = { + verbose: true, + "globals": { + "ts-jest": { + "tsConfigFile": "tsconfig.json" + } + }, + "transform": { + "^.+\\.tsx?$": "/../../node_modules/ts-jest/preprocessor.js" + }, + "moduleDirectories": ["node_modules"], + "testRegex": "(\\.|/)(test)\\.ts$", + "testEnvironment": "node", + "moduleFileExtensions": [ + "ts", + "js", + "json" + ], +}; diff --git a/tests/api/search.test.ts b/tests/api/search.test.ts new file mode 100644 index 00000000000..91d1ebf0d35 --- /dev/null +++ b/tests/api/search.test.ts @@ -0,0 +1,27 @@ +import client from './client'; +import * as setup from './setup'; + +describe('GET /api/search', () => { + const state = {}; + + beforeAll(async () => { + state = await setup.ensureState({ + orgName: 'api-test-org', + users: [{ user: setup.admin, role: 'Admin' }], + admin: setup.admin, + dashboards: [ + { + title: 'Dashboard in root no permissions', + uid: 'AAA', + }, + ], + }); + }); + + describe('With admin user', () => { + it('should return all dashboards', async () => { + let rsp = await client.callAs(state.admin).get('/api/search'); + expect(rsp.data).toHaveLength(1); + }); + }); +}); diff --git a/tests/api/setup.ts b/tests/api/setup.ts new file mode 100644 index 00000000000..94b0b20b8b8 --- /dev/null +++ b/tests/api/setup.ts @@ -0,0 +1,123 @@ +import client from './client'; +import _ from 'lodash;'; + +export const editor = { + email: 'api-test-editor@grafana.com', + login: 'api-test-editor', + password: 'password', + name: 'Api Test Editor', +}; + +export const admin = { + email: 'api-test-admin@grafana.com', + login: 'api-test-admin', + password: 'password', + name: 'Api Test Super', +}; + +export const viewer = { + email: 'api-test-viewer@grafana.com', + login: 'api-test-viewer', + password: 'password', + name: 'Api Test Viewer', +}; + +export async function expectError(callback) { + try { + let rsp = await callback(); + return rsp; + } catch (err) { + return err; + } + + return rsp; +} + +// deletes org if it's already there +export async function getOrg(orgName) { + try { + const rsp = await client.get(`/api/orgs/name/${orgName}`); + await client.delete(`/api/orgs/${rsp.data.id}`); + } catch {} + + const rsp = await client.post(`/api/orgs`, { name: orgName }); + return { name: orgName, id: rsp.data.orgId }; +} + +export async function getUser(user) { + const search = await client.get('/api/users/search', { + params: { query: user.login }, + }); + + if (search.data.totalCount === 1) { + user.id = search.data.users[0].id; + return user; + } + + const rsp = await client.post('/api/admin/users', user); + user.id = rsp.data.id; + + return user; +} + +export async function addUserToOrg(org, user, role) { + const rsp = await client.post(`/api/orgs/${org.id}/users`, { + loginOrEmail: user.login, + role: role, + }); + + return rsp.data; +} + +export async function clearState() { + const admin = await getUser(adminUser); + const rsp = await client.delete(`/api/admin/users/${admin.id}`); + return rsp.data; +} + +export async function setUsingOrg(user, org) { + await client.callAs(user).post(`/api/user/using/${org.id}`); +} + +export async function createDashboard(user, dashboard) { + const rsp = await client.callAs(user).post(`/api/dashboards/db`, { + dashboard: dashboard, + overwrite: true, + }); + dashboard.id = rsp.data.id; + dashboard.url = rsp.data.url; + + return dashboard; +} + +export async function createFolder(user, folder) { + const rsp = await client.callAs(user).post(`/api/folders`, { + uid: folder.uid, + title: folder.title, + overwrite: true, + }); + folder.id = rsp.id; + folder.url = rsp.url; + + return folder; +} + +export async function ensureState(state) { + const org = await getOrg(state.orgName); + + for (let orgUser of state.users) { + const user = await getUser(orgUser.user); + await addUserToOrg(org, user, orgUser.role); + await setUsingOrg(user, org); + } + + for (let dashboard of state.dashboards || []) { + await createDashboard(state.admin, dashboard); + } + + for (let folder of state.folders || []) { + await createFolder(state.admin, folder); + } + + return state; +} diff --git a/tests/api/tsconfig.json b/tests/api/tsconfig.json new file mode 100644 index 00000000000..3dd8c94d7d0 --- /dev/null +++ b/tests/api/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "target": "es6", + "lib": ["es6"], + "module": "commonjs", + "declaration": false, + "allowSyntheticDefaultImports": true, + "inlineSourceMap": false, + "sourceMap": true, + "noEmitOnError": false, + "emitDecoratorMetadata": false, + "experimentalDecorators": true, + "noImplicitReturns": true, + "noImplicitThis": false, + "noImplicitUseStrict":false, + "noImplicitAny": false, + "noUnusedLocals": true + }, + "include": [ + "*.ts", + "**/*.ts" + ] +} diff --git a/tests/api/user.test.ts b/tests/api/user.test.ts new file mode 100644 index 00000000000..ef1c927c69e --- /dev/null +++ b/tests/api/user.test.ts @@ -0,0 +1,22 @@ +import client from './client'; +import * as setup from './setup'; + +describe('GET /api/user', () => { + it('should return current authed user', async () => { + let rsp = await client.get('/api/user'); + expect(rsp.data.login).toBe('admin'); + }); +}); + +describe('PUT /api/user', () => { + it('should update current authed user', async () => { + const user = await setup.getUser(setup.editor); + user.name = 'Updated via test'; + + const rsp = await client.callAs(user).put('/api/user', user); + expect(rsp.data.message).toBe('User updated'); + + const updated = await client.callAs(user).get('/api/user'); + expect(updated.data.name).toBe('Updated via test'); + }); +}); diff --git a/tests/test-app/dashboards/connections.json b/tests/test-app/dashboards/connections.json index cc189d2d113..042dc4baec5 100644 --- a/tests/test-app/dashboards/connections.json +++ b/tests/test-app/dashboards/connections.json @@ -7,6 +7,7 @@ } ], + "uid": "1MHHlVjzz", "title": "Nginx Connections", "revision": 25, "schemaVersion": 11, diff --git a/tests/test-app/dashboards/connections_result.json b/tests/test-app/dashboards/connections_result.json index 4bf0570ac1e..2d2bc8de238 100644 --- a/tests/test-app/dashboards/connections_result.json +++ b/tests/test-app/dashboards/connections_result.json @@ -16,5 +16,6 @@ ], "schemaVersion": 11, "title": "Nginx Connections", + "uid": "1MHHlVjzz", "version": 0 } diff --git a/tools/phantomjs/render.js b/tools/phantomjs/render.js new file mode 100644 index 00000000000..77527585589 --- /dev/null +++ b/tools/phantomjs/render.js @@ -0,0 +1,86 @@ +(function() { + 'use strict'; + + var page = require('webpage').create(); + var args = require('system').args; + var params = {}; + var regexp = /^([^=]+)=([^$]+)/; + + args.forEach(function(arg) { + var parts = arg.match(regexp); + if (!parts) { return; } + params[parts[1]] = parts[2]; + }); + + var usage = "url= png= width= height= renderKey="; + + if (!params.url || !params.png || !params.renderKey || !params.domain) { + console.log(usage); + phantom.exit(); + } + + phantom.addCookie({ + 'name': 'renderKey', + 'value': params.renderKey, + 'domain': params.domain, + }); + + page.viewportSize = { + width: params.width || '800', + height: params.height || '400' + }; + + var timeoutMs = (parseInt(params.timeout) || 10) * 1000; + var waitBetweenReadyCheckMs = 50; + var totalWaitMs = 0; + + page.open(params.url, function (status) { + console.log('Loading a web page: ' + params.url + ' status: ' + status, timeoutMs); + + page.onError = function(msg, trace) { + var msgStack = ['ERROR: ' + msg]; + if (trace && trace.length) { + msgStack.push('TRACE:'); + trace.forEach(function(t) { + msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : '')); + }); + } + console.error(msgStack.join('\n')); + }; + + function checkIsReady() { + var panelsRendered = page.evaluate(function() { + if (!window.angular) { return false; } + var body = window.angular.element(document.body); + if (!body.injector) { return false; } + if (!body.injector()) { return false; } + + var rootScope = body.injector().get('$rootScope'); + if (!rootScope) {return false;} + var panels = angular.element('div.panel:visible').length; + return rootScope.panelsRendered >= panels; + }); + + if (panelsRendered || totalWaitMs > timeoutMs) { + var bb = page.evaluate(function () { + return document.getElementsByClassName("main-view")[0].getBoundingClientRect(); + }); + + page.clipRect = { + top: bb.top, + left: bb.left, + width: bb.width, + height: bb.height + }; + + page.render(params.png); + phantom.exit(); + } else { + totalWaitMs += waitBetweenReadyCheckMs; + setTimeout(checkIsReady, waitBetweenReadyCheckMs); + } + } + + setTimeout(checkIsReady, waitBetweenReadyCheckMs); + }); + })(); diff --git a/tsconfig.json b/tsconfig.json index bc9222ac87d..3596930a62f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "sourceMap": true, "noEmitOnError": false, "emitDecoratorMetadata": false, - "experimentalDecorators": false, + "experimentalDecorators": true, "noImplicitReturns": true, "noImplicitThis": false, "noImplicitUseStrict":false, diff --git a/tslint.json b/tslint.json index 789e83975db..e7a51295701 100644 --- a/tslint.json +++ b/tslint.json @@ -14,7 +14,7 @@ "forin": false, "indent": [true, "spaces", 2], "label-position": true, - "max-line-length": [true, 140], + "max-line-length": [true, 150], "member-access": false, "no-arg": true, "no-bitwise": false, diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS new file mode 100644 index 00000000000..c364af1da09 --- /dev/null +++ b/vendor/cloud.google.com/go/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of cloud authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. + +Filippo Valsorda +Google Inc. +Ingo Oeser +Palm Stone Games, Inc. +Paweł Knap +Péter Szilágyi +Tyler Treat diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS new file mode 100644 index 00000000000..eb55275bf0d --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTORS @@ -0,0 +1,39 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name + +# Keep the list alphabetically sorted. + +Alexis Hunt +Andreas Litt +Andrew Gerrand +Brad Fitzpatrick +Burcu Dogan +Dave Day +David Sansome +David Symonds +Filippo Valsorda +Glenn Lewis +Ingo Oeser +Johan Euphrosine +Jonathan Amsterdam +Kunpei Sakai +Luna Duclos +Magnus Hiie +Mario Castro +Michael McGreevy +Omar Jarjur +Paweł Knap +Péter Szilágyi +Sarah Adams +Thanatat Tamtan +Toby Burress +Tuo Shan +Tyler Treat diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE index a4c5efd822f..d6456956733 100644 --- a/vendor/cloud.google.com/go/LICENSE +++ b/vendor/cloud.google.com/go/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014 Google Inc. + 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. diff --git a/vendor/cloud.google.com/go/iam/iam.go b/vendor/cloud.google.com/go/iam/iam.go deleted file mode 100644 index 8722ee8838f..00000000000 --- a/vendor/cloud.google.com/go/iam/iam.go +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 iam supports the resource-specific operations of Google Cloud -// IAM (Identity and Access Management) for the Google Cloud Libraries. -// See https://cloud.google.com/iam for more about IAM. -// -// Users of the Google Cloud Libraries will typically not use this package -// directly. Instead they will begin with some resource that supports IAM, like -// a pubsub topic, and call its IAM method to get a Handle for that resource. -package iam - -import ( - "golang.org/x/net/context" - pb "google.golang.org/genproto/googleapis/iam/v1" - "google.golang.org/grpc" -) - -// client abstracts the IAMPolicy API to allow multiple implementations. -type client interface { - Get(ctx context.Context, resource string) (*pb.Policy, error) - Set(ctx context.Context, resource string, p *pb.Policy) error - Test(ctx context.Context, resource string, perms []string) ([]string, error) -} - -// grpcClient implements client for the standard gRPC-based IAMPolicy service. -type grpcClient struct { - c pb.IAMPolicyClient -} - -func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) { - proto, err := g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource}) - if err != nil { - return nil, err - } - return proto, nil -} -func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error { - _, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{ - Resource: resource, - Policy: p, - }) - return err -} - -func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) { - res, err := g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{ - Resource: resource, - Permissions: perms, - }) - if err != nil { - return nil, err - } - return res.Permissions, nil -} - -// A Handle provides IAM operations for a resource. -type Handle struct { - c client - resource string -} - -// InternalNewHandle is for use by the Google Cloud Libraries only. -// -// InternalNewHandle returns a Handle for resource. -// The conn parameter refers to a server that must support the IAMPolicy service. -func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle { - return InternalNewHandleClient(&grpcClient{c: pb.NewIAMPolicyClient(conn)}, resource) -} - -// InternalNewHandleClient is for use by the Google Cloud Libraries only. -// -// InternalNewHandleClient returns a Handle for resource using the given -// client implementation. -func InternalNewHandleClient(c client, resource string) *Handle { - return &Handle{ - c: c, - resource: resource, - } -} - -// Policy retrieves the IAM policy for the resource. -func (h *Handle) Policy(ctx context.Context) (*Policy, error) { - proto, err := h.c.Get(ctx, h.resource) - if err != nil { - return nil, err - } - return &Policy{InternalProto: proto}, nil -} - -// SetPolicy replaces the resource's current policy with the supplied Policy. -// -// If policy was created from a prior call to Get, then the modification will -// only succeed if the policy has not changed since the Get. -func (h *Handle) SetPolicy(ctx context.Context, policy *Policy) error { - return h.c.Set(ctx, h.resource, policy.InternalProto) -} - -// TestPermissions returns the subset of permissions that the caller has on the resource. -func (h *Handle) TestPermissions(ctx context.Context, permissions []string) ([]string, error) { - return h.c.Test(ctx, h.resource, permissions) -} - -// A RoleName is a name representing a collection of permissions. -type RoleName string - -// Common role names. -const ( - Owner RoleName = "roles/owner" - Editor RoleName = "roles/editor" - Viewer RoleName = "roles/viewer" -) - -const ( - // AllUsers is a special member that denotes all users, even unauthenticated ones. - AllUsers = "allUsers" - - // AllAuthenticatedUsers is a special member that denotes all authenticated users. - AllAuthenticatedUsers = "allAuthenticatedUsers" -) - -// A Policy is a list of Bindings representing roles -// granted to members. -// -// The zero Policy is a valid policy with no bindings. -type Policy struct { - // TODO(jba): when type aliases are available, put Policy into an internal package - // and provide an exported alias here. - - // This field is exported for use by the Google Cloud Libraries only. - // It may become unexported in a future release. - InternalProto *pb.Policy -} - -// Members returns the list of members with the supplied role. -// The return value should not be modified. Use Add and Remove -// to modify the members of a role. -func (p *Policy) Members(r RoleName) []string { - b := p.binding(r) - if b == nil { - return nil - } - return b.Members -} - -// HasRole reports whether member has role r. -func (p *Policy) HasRole(member string, r RoleName) bool { - return memberIndex(member, p.binding(r)) >= 0 -} - -// Add adds member member to role r if it is not already present. -// A new binding is created if there is no binding for the role. -func (p *Policy) Add(member string, r RoleName) { - b := p.binding(r) - if b == nil { - if p.InternalProto == nil { - p.InternalProto = &pb.Policy{} - } - p.InternalProto.Bindings = append(p.InternalProto.Bindings, &pb.Binding{ - Role: string(r), - Members: []string{member}, - }) - return - } - if memberIndex(member, b) < 0 { - b.Members = append(b.Members, member) - return - } -} - -// Remove removes member from role r if it is present. -func (p *Policy) Remove(member string, r RoleName) { - bi := p.bindingIndex(r) - if bi < 0 { - return - } - bindings := p.InternalProto.Bindings - b := bindings[bi] - mi := memberIndex(member, b) - if mi < 0 { - return - } - // Order doesn't matter for bindings or members, so to remove, move the last item - // into the removed spot and shrink the slice. - if len(b.Members) == 1 { - // Remove binding. - last := len(bindings) - 1 - bindings[bi] = bindings[last] - bindings[last] = nil - p.InternalProto.Bindings = bindings[:last] - return - } - // Remove member. - // TODO(jba): worry about multiple copies of m? - last := len(b.Members) - 1 - b.Members[mi] = b.Members[last] - b.Members[last] = "" - b.Members = b.Members[:last] -} - -// Roles returns the names of all the roles that appear in the Policy. -func (p *Policy) Roles() []RoleName { - if p.InternalProto == nil { - return nil - } - var rns []RoleName - for _, b := range p.InternalProto.Bindings { - rns = append(rns, RoleName(b.Role)) - } - return rns -} - -// binding returns the Binding for the suppied role, or nil if there isn't one. -func (p *Policy) binding(r RoleName) *pb.Binding { - i := p.bindingIndex(r) - if i < 0 { - return nil - } - return p.InternalProto.Bindings[i] -} - -func (p *Policy) bindingIndex(r RoleName) int { - if p.InternalProto == nil { - return -1 - } - for i, b := range p.InternalProto.Bindings { - if b.Role == string(r) { - return i - } - } - return -1 -} - -// memberIndex returns the index of m in b's Members, or -1 if not found. -func memberIndex(m string, b *pb.Binding) int { - if b == nil { - return -1 - } - for i, mm := range b.Members { - if mm == m { - return i - } - } - return -1 -} diff --git a/vendor/cloud.google.com/go/internal/optional/optional.go b/vendor/cloud.google.com/go/internal/optional/optional.go deleted file mode 100644 index f9102f36516..00000000000 --- a/vendor/cloud.google.com/go/internal/optional/optional.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 optional provides versions of primitive types that can -// be nil. These are useful in methods that update some of an API object's -// fields. -package optional - -import ( - "fmt" - "strings" -) - -type ( - // Bool is either a bool or nil. - Bool interface{} - - // String is either a string or nil. - String interface{} - - // Int is either an int or nil. - Int interface{} - - // Uint is either a uint or nil. - Uint interface{} - - // Float64 is either a float64 or nil. - Float64 interface{} -) - -// ToBool returns its argument as a bool. -// It panics if its argument is nil or not a bool. -func ToBool(v Bool) bool { - x, ok := v.(bool) - if !ok { - doPanic("Bool", v) - } - return x -} - -// ToString returns its argument as a string. -// It panics if its argument is nil or not a string. -func ToString(v String) string { - x, ok := v.(string) - if !ok { - doPanic("String", v) - } - return x -} - -// ToInt returns its argument as an int. -// It panics if its argument is nil or not an int. -func ToInt(v Int) int { - x, ok := v.(int) - if !ok { - doPanic("Int", v) - } - return x -} - -// ToUint returns its argument as a uint. -// It panics if its argument is nil or not a uint. -func ToUint(v Uint) uint { - x, ok := v.(uint) - if !ok { - doPanic("Uint", v) - } - return x -} - -// ToFloat64 returns its argument as a float64. -// It panics if its argument is nil or not a float64. -func ToFloat64(v Float64) float64 { - x, ok := v.(float64) - if !ok { - doPanic("Float64", v) - } - return x -} - -func doPanic(capType string, v interface{}) { - panic(fmt.Sprintf("optional.%s value should be %s, got %T", capType, strings.ToLower(capType), v)) -} diff --git a/vendor/cloud.google.com/go/internal/retry.go b/vendor/cloud.google.com/go/internal/retry.go deleted file mode 100644 index f554fbf8f79..00000000000 --- a/vendor/cloud.google.com/go/internal/retry.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 internal - -import ( - "fmt" - "time" - - gax "github.com/googleapis/gax-go" - - "golang.org/x/net/context" -) - -// Retry calls the supplied function f repeatedly according to the provided -// backoff parameters. It returns when one of the following occurs: -// When f's first return value is true, Retry immediately returns with f's second -// return value. -// When the provided context is done, Retry returns with an error that -// includes both ctx.Error() and the last error returned by f. -func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error { - return retry(ctx, bo, f, gax.Sleep) -} - -func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error), - sleep func(context.Context, time.Duration) error) error { - var lastErr error - for { - stop, err := f() - if stop { - return err - } - // Remember the last "real" error from f. - if err != nil && err != context.Canceled && err != context.DeadlineExceeded { - lastErr = err - } - p := bo.Pause() - if cerr := sleep(ctx, p); cerr != nil { - if lastErr != nil { - return fmt.Errorf("%v; last function err: %v", cerr, lastErr) - } - return cerr - } - } -} diff --git a/vendor/cloud.google.com/go/internal/version/update_version.sh b/vendor/cloud.google.com/go/internal/version/update_version.sh deleted file mode 100755 index fecf1f03fde..00000000000 --- a/vendor/cloud.google.com/go/internal/version/update_version.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -today=$(date +%Y%m%d) - -sed -i -r -e 's/const Repo = "([0-9]{8})"/const Repo = "'$today'"/' $GOFILE - diff --git a/vendor/cloud.google.com/go/internal/version/version.go b/vendor/cloud.google.com/go/internal/version/version.go deleted file mode 100644 index 5eb06bac550..00000000000 --- a/vendor/cloud.google.com/go/internal/version/version.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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. - -//go:generate ./update_version.sh - -// Package version contains version information for Google Cloud Client -// Libraries for Go, as reported in request headers. -package version - -import ( - "runtime" - "strings" - "unicode" -) - -// Repo is the current version of the client libraries in this -// repo. It should be a date in YYYYMMDD format. -const Repo = "20170621" - -// Go returns the Go runtime version. The returned string -// has no whitespace. -func Go() string { - return goVersion -} - -var goVersion = goVer(runtime.Version()) - -const develPrefix = "devel +" - -func goVer(s string) string { - if strings.HasPrefix(s, develPrefix) { - s = s[len(develPrefix):] - if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { - s = s[:p] - } - return s - } - - if strings.HasPrefix(s, "go1") { - s = s[2:] - var prerelease string - if p := strings.IndexFunc(s, notSemverRune); p >= 0 { - s, prerelease = s[:p], s[p:] - } - if strings.HasSuffix(s, ".") { - s += "0" - } else if strings.Count(s, ".") < 2 { - s += ".0" - } - if prerelease != "" { - s += "-" + prerelease - } - return s - } - return "" -} - -func notSemverRune(r rune) bool { - return strings.IndexRune("0123456789.", r) < 0 -} diff --git a/vendor/cloud.google.com/go/storage/acl.go b/vendor/cloud.google.com/go/storage/acl.go deleted file mode 100644 index a1b2b6d3ddd..00000000000 --- a/vendor/cloud.google.com/go/storage/acl.go +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "fmt" - "net/http" - "reflect" - - "golang.org/x/net/context" - "google.golang.org/api/googleapi" - raw "google.golang.org/api/storage/v1" -) - -// ACLRole is the level of access to grant. -type ACLRole string - -const ( - RoleOwner ACLRole = "OWNER" - RoleReader ACLRole = "READER" - RoleWriter ACLRole = "WRITER" -) - -// ACLEntity refers to a user or group. -// They are sometimes referred to as grantees. -// -// It could be in the form of: -// "user-", "user-", "group-", "group-", -// "domain-" and "project-team-". -// -// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers. -type ACLEntity string - -const ( - AllUsers ACLEntity = "allUsers" - AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers" -) - -// ACLRule represents a grant for a role to an entity (user, group or team) for a Google Cloud Storage object or bucket. -type ACLRule struct { - Entity ACLEntity - Role ACLRole -} - -// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object. -type ACLHandle struct { - c *Client - bucket string - object string - isDefault bool - userProject string // for requester-pays buckets -} - -// Delete permanently deletes the ACL entry for the given entity. -func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) error { - if a.object != "" { - return a.objectDelete(ctx, entity) - } - if a.isDefault { - return a.bucketDefaultDelete(ctx, entity) - } - return a.bucketDelete(ctx, entity) -} - -// Set sets the permission level for the given entity. -func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) error { - if a.object != "" { - return a.objectSet(ctx, entity, role, false) - } - if a.isDefault { - return a.objectSet(ctx, entity, role, true) - } - return a.bucketSet(ctx, entity, role) -} - -// List retrieves ACL entries. -func (a *ACLHandle) List(ctx context.Context) ([]ACLRule, error) { - if a.object != "" { - return a.objectList(ctx) - } - if a.isDefault { - return a.bucketDefaultList(ctx) - } - return a.bucketList(ctx) -} - -func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.ObjectAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.DefaultObjectAccessControls.List(a.bucket) - a.configureCall(req, ctx) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, fmt.Errorf("storage: error listing default object ACL for bucket %q: %v", a.bucket, err) - } - return toACLRules(acls.Items), nil -} - -func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error { - err := runWithRetry(ctx, func() error { - req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity)) - a.configureCall(req, ctx) - return req.Do() - }) - if err != nil { - return fmt.Errorf("storage: error deleting default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) - } - return nil -} - -func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.BucketAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.List(a.bucket) - a.configureCall(req, ctx) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, fmt.Errorf("storage: error listing bucket ACL for bucket %q: %v", a.bucket, err) - } - r := make([]ACLRule, len(acls.Items)) - for i, v := range acls.Items { - r[i].Entity = ACLEntity(v.Entity) - r[i].Role = ACLRole(v.Role) - } - return r, nil -} - -func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error { - acl := &raw.BucketAccessControl{ - Bucket: a.bucket, - Entity: string(entity), - Role: string(role), - } - err := runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl) - a.configureCall(req, ctx) - _, err := req.Do() - return err - }) - if err != nil { - return fmt.Errorf("storage: error updating bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) - } - return nil -} - -func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error { - err := runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity)) - a.configureCall(req, ctx) - return req.Do() - }) - if err != nil { - return fmt.Errorf("storage: error deleting bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) - } - return nil -} - -func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.ObjectAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object) - a.configureCall(req, ctx) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, fmt.Errorf("storage: error listing object ACL for bucket %q, file %q: %v", a.bucket, a.object, err) - } - return toACLRules(acls.Items), nil -} - -func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error { - type setRequest interface { - Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) - Header() http.Header - } - - acl := &raw.ObjectAccessControl{ - Bucket: a.bucket, - Entity: string(entity), - Role: string(role), - } - var req setRequest - if isBucketDefault { - req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl) - } else { - req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl) - } - a.configureCall(req, ctx) - err := runWithRetry(ctx, func() error { - _, err := req.Do() - return err - }) - if err != nil { - if isBucketDefault { - return fmt.Errorf("storage: error updating default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) - } else { - return fmt.Errorf("storage: error updating object ACL entry for bucket %q, object %q, entity %q: %v", a.bucket, a.object, entity, err) - } - } - return nil -} - -func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error { - err := runWithRetry(ctx, func() error { - req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity)) - a.configureCall(req, ctx) - return req.Do() - }) - if err != nil { - return fmt.Errorf("storage: error deleting object ACL entry for bucket %q, file %q, entity %q: %v", a.bucket, a.object, entity, err) - } - return nil -} - -func (a *ACLHandle) configureCall(call interface { - Header() http.Header -}, ctx context.Context) { - vc := reflect.ValueOf(call) - vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)}) - if a.userProject != "" { - vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)}) - } - setClientHeader(call.Header()) -} - -func toACLRules(items []*raw.ObjectAccessControl) []ACLRule { - r := make([]ACLRule, 0, len(items)) - for _, item := range items { - r = append(r, ACLRule{Entity: ACLEntity(item.Entity), Role: ACLRole(item.Role)}) - } - return r -} diff --git a/vendor/cloud.google.com/go/storage/bucket.go b/vendor/cloud.google.com/go/storage/bucket.go deleted file mode 100644 index 68f298e843c..00000000000 --- a/vendor/cloud.google.com/go/storage/bucket.go +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "fmt" - "net/http" - "reflect" - "time" - - "cloud.google.com/go/internal/optional" - "golang.org/x/net/context" - "google.golang.org/api/googleapi" - "google.golang.org/api/iterator" - raw "google.golang.org/api/storage/v1" -) - -// BucketHandle provides operations on a Google Cloud Storage bucket. -// Use Client.Bucket to get a handle. -type BucketHandle struct { - c *Client - name string - acl ACLHandle - defaultObjectACL ACLHandle - conds *BucketConditions - userProject string // project for requester-pays buckets -} - -// Bucket returns a BucketHandle, which provides operations on the named bucket. -// This call does not perform any network operations. -// -// The supplied name must contain only lowercase letters, numbers, dashes, -// underscores, and dots. The full specification for valid bucket names can be -// found at: -// https://cloud.google.com/storage/docs/bucket-naming -func (c *Client) Bucket(name string) *BucketHandle { - return &BucketHandle{ - c: c, - name: name, - acl: ACLHandle{ - c: c, - bucket: name, - }, - defaultObjectACL: ACLHandle{ - c: c, - bucket: name, - isDefault: true, - }, - } -} - -// Create creates the Bucket in the project. -// If attrs is nil the API defaults will be used. -func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) error { - var bkt *raw.Bucket - if attrs != nil { - bkt = attrs.toRawBucket() - } else { - bkt = &raw.Bucket{} - } - bkt.Name = b.name - req := b.c.raw.Buckets.Insert(projectID, bkt) - setClientHeader(req.Header()) - return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err }) -} - -// Delete deletes the Bucket. -func (b *BucketHandle) Delete(ctx context.Context) error { - req, err := b.newDeleteCall() - if err != nil { - return err - } - return runWithRetry(ctx, func() error { return req.Context(ctx).Do() }) -} - -func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) { - req := b.c.raw.Buckets.Delete(b.name) - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil -} - -// ACL returns an ACLHandle, which provides access to the bucket's access control list. -// This controls who can list, create or overwrite the objects in a bucket. -// This call does not perform any network operations. -func (b *BucketHandle) ACL() *ACLHandle { - return &b.acl -} - -// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs. -// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL. -// This call does not perform any network operations. -func (b *BucketHandle) DefaultObjectACL() *ACLHandle { - return &b.defaultObjectACL -} - -// Object returns an ObjectHandle, which provides operations on the named object. -// This call does not perform any network operations. -// -// name must consist entirely of valid UTF-8-encoded runes. The full specification -// for valid object names can be found at: -// https://cloud.google.com/storage/docs/bucket-naming -func (b *BucketHandle) Object(name string) *ObjectHandle { - return &ObjectHandle{ - c: b.c, - bucket: b.name, - object: name, - acl: ACLHandle{ - c: b.c, - bucket: b.name, - object: name, - userProject: b.userProject, - }, - gen: -1, - userProject: b.userProject, - } -} - -// Attrs returns the metadata for the bucket. -func (b *BucketHandle) Attrs(ctx context.Context) (*BucketAttrs, error) { - req, err := b.newGetCall() - if err != nil { - return nil, err - } - var resp *raw.Bucket - err = runWithRetry(ctx, func() error { - resp, err = req.Context(ctx).Do() - return err - }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrBucketNotExist - } - if err != nil { - return nil, err - } - return newBucket(resp), nil -} - -func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) { - req := b.c.raw.Buckets.Get(b.name).Projection("full") - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil -} - -func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (*BucketAttrs, error) { - req, err := b.newPatchCall(&uattrs) - if err != nil { - return nil, err - } - // TODO(jba): retry iff metagen is set? - rb, err := req.Context(ctx).Do() - if err != nil { - return nil, err - } - return newBucket(rb), nil -} - -func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) { - rb := uattrs.toRawBucket() - req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full") - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil -} - -// BucketAttrs represents the metadata for a Google Cloud Storage bucket. -type BucketAttrs struct { - // Name is the name of the bucket. - Name string - - // ACL is the list of access control rules on the bucket. - ACL []ACLRule - - // DefaultObjectACL is the list of access controls to - // apply to new objects when no object ACL is provided. - DefaultObjectACL []ACLRule - - // Location is the location of the bucket. It defaults to "US". - Location string - - // MetaGeneration is the metadata generation of the bucket. - MetaGeneration int64 - - // StorageClass is the default storage class of the bucket. This defines - // how objects in the bucket are stored and determines the SLA - // and the cost of storage. Typical values are "MULTI_REGIONAL", - // "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and - // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which - // is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on - // the bucket's location settings. - StorageClass string - - // Created is the creation time of the bucket. - Created time.Time - - // VersioningEnabled reports whether this bucket has versioning enabled. - // This field is read-only. - VersioningEnabled bool - - // Labels are the bucket's labels. - Labels map[string]string - - // RequesterPays reports whether the bucket is a Requester Pays bucket. - RequesterPays bool -} - -func newBucket(b *raw.Bucket) *BucketAttrs { - if b == nil { - return nil - } - bucket := &BucketAttrs{ - Name: b.Name, - Location: b.Location, - MetaGeneration: b.Metageneration, - StorageClass: b.StorageClass, - Created: convertTime(b.TimeCreated), - VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled, - Labels: b.Labels, - RequesterPays: b.Billing != nil && b.Billing.RequesterPays, - } - acl := make([]ACLRule, len(b.Acl)) - for i, rule := range b.Acl { - acl[i] = ACLRule{ - Entity: ACLEntity(rule.Entity), - Role: ACLRole(rule.Role), - } - } - bucket.ACL = acl - objACL := make([]ACLRule, len(b.DefaultObjectAcl)) - for i, rule := range b.DefaultObjectAcl { - objACL[i] = ACLRule{ - Entity: ACLEntity(rule.Entity), - Role: ACLRole(rule.Role), - } - } - bucket.DefaultObjectACL = objACL - return bucket -} - -// toRawBucket copies the editable attribute from b to the raw library's Bucket type. -func (b *BucketAttrs) toRawBucket() *raw.Bucket { - var acl []*raw.BucketAccessControl - if len(b.ACL) > 0 { - acl = make([]*raw.BucketAccessControl, len(b.ACL)) - for i, rule := range b.ACL { - acl[i] = &raw.BucketAccessControl{ - Entity: string(rule.Entity), - Role: string(rule.Role), - } - } - } - dACL := toRawObjectACL(b.DefaultObjectACL) - // Copy label map. - var labels map[string]string - if len(b.Labels) > 0 { - labels = make(map[string]string, len(b.Labels)) - for k, v := range b.Labels { - labels[k] = v - } - } - // Ignore VersioningEnabled if it is false. This is OK because - // we only call this method when creating a bucket, and by default - // new buckets have versioning off. - var v *raw.BucketVersioning - if b.VersioningEnabled { - v = &raw.BucketVersioning{Enabled: true} - } - var bb *raw.BucketBilling - if b.RequesterPays { - bb = &raw.BucketBilling{RequesterPays: true} - } - return &raw.Bucket{ - Name: b.Name, - DefaultObjectAcl: dACL, - Location: b.Location, - StorageClass: b.StorageClass, - Acl: acl, - Versioning: v, - Labels: labels, - Billing: bb, - } -} - -type BucketAttrsToUpdate struct { - // VersioningEnabled, if set, updates whether the bucket uses versioning. - VersioningEnabled optional.Bool - - // RequesterPays, if set, updates whether the bucket is a Requester Pays bucket. - RequesterPays optional.Bool - - setLabels map[string]string - deleteLabels map[string]bool -} - -// SetLabel causes a label to be added or modified when ua is used -// in a call to Bucket.Update. -func (ua *BucketAttrsToUpdate) SetLabel(name, value string) { - if ua.setLabels == nil { - ua.setLabels = map[string]string{} - } - ua.setLabels[name] = value -} - -// DeleteLabel causes a label to be deleted when ua is used in a -// call to Bucket.Update. -func (ua *BucketAttrsToUpdate) DeleteLabel(name string) { - if ua.deleteLabels == nil { - ua.deleteLabels = map[string]bool{} - } - ua.deleteLabels[name] = true -} - -func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { - rb := &raw.Bucket{} - if ua.VersioningEnabled != nil { - rb.Versioning = &raw.BucketVersioning{ - Enabled: optional.ToBool(ua.VersioningEnabled), - ForceSendFields: []string{"Enabled"}, - } - } - if ua.RequesterPays != nil { - rb.Billing = &raw.BucketBilling{ - RequesterPays: optional.ToBool(ua.RequesterPays), - ForceSendFields: []string{"RequesterPays"}, - } - } - if ua.setLabels != nil || ua.deleteLabels != nil { - rb.Labels = map[string]string{} - for k, v := range ua.setLabels { - rb.Labels[k] = v - } - if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 { - rb.ForceSendFields = append(rb.ForceSendFields, "Labels") - } - for l := range ua.deleteLabels { - rb.NullFields = append(rb.NullFields, "Labels."+l) - } - } - return rb -} - -// If returns a new BucketHandle that applies a set of preconditions. -// Preconditions already set on the BucketHandle are ignored. -// Operations on the new handle will only occur if the preconditions are -// satisfied. The only valid preconditions for buckets are MetagenerationMatch -// and MetagenerationNotMatch. -func (b *BucketHandle) If(conds BucketConditions) *BucketHandle { - b2 := *b - b2.conds = &conds - return &b2 -} - -// BucketConditions constrain bucket methods to act on specific metagenerations. -// -// The zero value is an empty set of constraints. -type BucketConditions struct { - // MetagenerationMatch specifies that the bucket must have the given - // metageneration for the operation to occur. - // If MetagenerationMatch is zero, it has no effect. - MetagenerationMatch int64 - - // MetagenerationNotMatch specifies that the bucket must not have the given - // metageneration for the operation to occur. - // If MetagenerationNotMatch is zero, it has no effect. - MetagenerationNotMatch int64 -} - -func (c *BucketConditions) validate(method string) error { - if *c == (BucketConditions{}) { - return fmt.Errorf("storage: %s: empty conditions", method) - } - if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 { - return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method) - } - return nil -} - -// UserProject returns a new BucketHandle that passes the project ID as the user -// project for all subsequent calls. A user project is required for all operations -// on requester-pays buckets. -func (b *BucketHandle) UserProject(projectID string) *BucketHandle { - b2 := *b - b2.userProject = projectID - b2.acl.userProject = projectID - b2.defaultObjectACL.userProject = projectID - return &b2 -} - -// applyBucketConds modifies the provided call using the conditions in conds. -// call is something that quacks like a *raw.WhateverCall. -func applyBucketConds(method string, conds *BucketConditions, call interface{}) error { - if conds == nil { - return nil - } - if err := conds.validate(method); err != nil { - return err - } - cval := reflect.ValueOf(call) - switch { - case conds.MetagenerationMatch != 0: - if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) - } - case conds.MetagenerationNotMatch != 0: - if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) - } - } - return nil -} - -// Objects returns an iterator over the objects in the bucket that match the Query q. -// If q is nil, no filtering is done. -func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator { - it := &ObjectIterator{ - ctx: ctx, - bucket: b, - } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.items) }, - func() interface{} { b := it.items; it.items = nil; return b }) - if q != nil { - it.query = *q - } - return it -} - -// An ObjectIterator is an iterator over ObjectAttrs. -type ObjectIterator struct { - ctx context.Context - bucket *BucketHandle - query Query - pageInfo *iterator.PageInfo - nextFunc func() error - items []*ObjectAttrs -} - -// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. -func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } - -// Next returns the next result. Its second return value is iterator.Done if -// there are no more results. Once Next returns iterator.Done, all subsequent -// calls will return iterator.Done. -// -// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will -// have a non-empty Prefix field, and a zero value for all other fields. These -// represent prefixes. -func (it *ObjectIterator) Next() (*ObjectAttrs, error) { - if err := it.nextFunc(); err != nil { - return nil, err - } - item := it.items[0] - it.items = it.items[1:] - return item, nil -} - -func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) { - req := it.bucket.c.raw.Objects.List(it.bucket.name) - setClientHeader(req.Header()) - req.Projection("full") - req.Delimiter(it.query.Delimiter) - req.Prefix(it.query.Prefix) - req.Versions(it.query.Versions) - req.PageToken(pageToken) - if it.bucket.userProject != "" { - req.UserProject(it.bucket.userProject) - } - if pageSize > 0 { - req.MaxResults(int64(pageSize)) - } - var resp *raw.Objects - var err error - err = runWithRetry(it.ctx, func() error { - resp, err = req.Context(it.ctx).Do() - return err - }) - if err != nil { - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - err = ErrBucketNotExist - } - return "", err - } - for _, item := range resp.Items { - it.items = append(it.items, newObject(item)) - } - for _, prefix := range resp.Prefixes { - it.items = append(it.items, &ObjectAttrs{Prefix: prefix}) - } - return resp.NextPageToken, nil -} - -// TODO(jbd): Add storage.buckets.update. - -// Buckets returns an iterator over the buckets in the project. You may -// optionally set the iterator's Prefix field to restrict the list to buckets -// whose names begin with the prefix. By default, all buckets in the project -// are returned. -func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator { - it := &BucketIterator{ - ctx: ctx, - client: c, - projectID: projectID, - } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.buckets) }, - func() interface{} { b := it.buckets; it.buckets = nil; return b }) - return it -} - -// A BucketIterator is an iterator over BucketAttrs. -type BucketIterator struct { - // Prefix restricts the iterator to buckets whose names begin with it. - Prefix string - - ctx context.Context - client *Client - projectID string - buckets []*BucketAttrs - pageInfo *iterator.PageInfo - nextFunc func() error -} - -// Next returns the next result. Its second return value is iterator.Done if -// there are no more results. Once Next returns iterator.Done, all subsequent -// calls will return iterator.Done. -func (it *BucketIterator) Next() (*BucketAttrs, error) { - if err := it.nextFunc(); err != nil { - return nil, err - } - b := it.buckets[0] - it.buckets = it.buckets[1:] - return b, nil -} - -// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. -func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } - -func (it *BucketIterator) fetch(pageSize int, pageToken string) (string, error) { - req := it.client.raw.Buckets.List(it.projectID) - setClientHeader(req.Header()) - req.Projection("full") - req.Prefix(it.Prefix) - req.PageToken(pageToken) - if pageSize > 0 { - req.MaxResults(int64(pageSize)) - } - var resp *raw.Buckets - var err error - err = runWithRetry(it.ctx, func() error { - resp, err = req.Context(it.ctx).Do() - return err - }) - if err != nil { - return "", err - } - for _, item := range resp.Items { - it.buckets = append(it.buckets, newBucket(item)) - } - return resp.NextPageToken, nil -} diff --git a/vendor/cloud.google.com/go/storage/copy.go b/vendor/cloud.google.com/go/storage/copy.go deleted file mode 100644 index d0a999c1b2f..00000000000 --- a/vendor/cloud.google.com/go/storage/copy.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "errors" - "fmt" - - "golang.org/x/net/context" - raw "google.golang.org/api/storage/v1" -) - -// CopierFrom creates a Copier that can copy src to dst. -// You can immediately call Run on the returned Copier, or -// you can configure it first. -// -// For Requester Pays buckets, the user project of dst is billed, unless it is empty, -// in which case the user project of src is billed. -func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier { - return &Copier{dst: dst, src: src} -} - -// A Copier copies a source object to a destination. -type Copier struct { - // ObjectAttrs are optional attributes to set on the destination object. - // Any attributes must be initialized before any calls on the Copier. Nil - // or zero-valued attributes are ignored. - ObjectAttrs - - // RewriteToken can be set before calling Run to resume a copy - // operation. After Run returns a non-nil error, RewriteToken will - // have been updated to contain the value needed to resume the copy. - RewriteToken string - - // ProgressFunc can be used to monitor the progress of a multi-RPC copy - // operation. If ProgressFunc is not nil and copying requires multiple - // calls to the underlying service (see - // https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then - // ProgressFunc will be invoked after each call with the number of bytes of - // content copied so far and the total size in bytes of the source object. - // - // ProgressFunc is intended to make upload progress available to the - // application. For example, the implementation of ProgressFunc may update - // a progress bar in the application's UI, or log the result of - // float64(copiedBytes)/float64(totalBytes). - // - // ProgressFunc should return quickly without blocking. - ProgressFunc func(copiedBytes, totalBytes uint64) - - dst, src *ObjectHandle -} - -// Run performs the copy. -func (c *Copier) Run(ctx context.Context) (*ObjectAttrs, error) { - if err := c.src.validate(); err != nil { - return nil, err - } - if err := c.dst.validate(); err != nil { - return nil, err - } - // Convert destination attributes to raw form, omitting the bucket. - // If the bucket is included but name or content-type aren't, the service - // returns a 400 with "Required" as the only message. Omitting the bucket - // does not cause any problems. - rawObject := c.ObjectAttrs.toRawObject("") - for { - res, err := c.callRewrite(ctx, rawObject) - if err != nil { - return nil, err - } - if c.ProgressFunc != nil { - c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize)) - } - if res.Done { // Finished successfully. - return newObject(res.Resource), nil - } - } -} - -func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) { - call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj) - - call.Context(ctx).Projection("full") - if c.RewriteToken != "" { - call.RewriteToken(c.RewriteToken) - } - if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil { - return nil, err - } - if c.dst.userProject != "" { - call.UserProject(c.dst.userProject) - } else if c.src.userProject != "" { - call.UserProject(c.src.userProject) - } - if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil { - return nil, err - } - if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { - return nil, err - } - if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil { - return nil, err - } - var res *raw.RewriteResponse - var err error - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { res, err = call.Do(); return err }) - if err != nil { - return nil, err - } - c.RewriteToken = res.RewriteToken - return res, nil -} - -// ComposerFrom creates a Composer that can compose srcs into dst. -// You can immediately call Run on the returned Composer, or you can -// configure it first. -// -// The encryption key for the destination object will be used to decrypt all -// source objects and encrypt the destination object. It is an error -// to specify an encryption key for any of the source objects. -func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer { - return &Composer{dst: dst, srcs: srcs} -} - -// A Composer composes source objects into a destination object. -// -// For Requester Pays buckets, the user project of dst is billed. -type Composer struct { - // ObjectAttrs are optional attributes to set on the destination object. - // Any attributes must be initialized before any calls on the Composer. Nil - // or zero-valued attributes are ignored. - ObjectAttrs - - dst *ObjectHandle - srcs []*ObjectHandle -} - -// Run performs the compose operation. -func (c *Composer) Run(ctx context.Context) (*ObjectAttrs, error) { - if err := c.dst.validate(); err != nil { - return nil, err - } - if len(c.srcs) == 0 { - return nil, errors.New("storage: at least one source object must be specified") - } - - req := &raw.ComposeRequest{} - // Compose requires a non-empty Destination, so we always set it, - // even if the caller-provided ObjectAttrs is the zero value. - req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket) - for _, src := range c.srcs { - if err := src.validate(); err != nil { - return nil, err - } - if src.bucket != c.dst.bucket { - return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket) - } - if src.encryptionKey != nil { - return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object) - } - srcObj := &raw.ComposeRequestSourceObjects{ - Name: src.object, - } - if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil { - return nil, err - } - req.SourceObjects = append(req.SourceObjects, srcObj) - } - - call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx) - if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil { - return nil, err - } - if c.dst.userProject != "" { - call.UserProject(c.dst.userProject) - } - if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - var err error - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if err != nil { - return nil, err - } - return newObject(obj), nil -} diff --git a/vendor/cloud.google.com/go/storage/doc.go b/vendor/cloud.google.com/go/storage/doc.go deleted file mode 100644 index 951391f5489..00000000000 --- a/vendor/cloud.google.com/go/storage/doc.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 storage provides an easy way to work with Google Cloud Storage. -Google Cloud Storage stores data in named objects, which are grouped into buckets. - -More information about Google Cloud Storage is available at -https://cloud.google.com/storage/docs. - -All of the methods of this package use exponential backoff to retry calls -that fail with certain errors, as described in -https://cloud.google.com/storage/docs/exponential-backoff. - -Note: This package is in beta. Some backwards-incompatible changes may occur. - - -Creating a Client - -To start working with this package, create a client: - - ctx := context.Background() - client, err := storage.NewClient(ctx) - if err != nil { - // TODO: Handle error. - } - -Buckets - -A Google Cloud Storage bucket is a collection of objects. To work with a -bucket, make a bucket handle: - - bkt := client.Bucket(bucketName) - -A handle is a reference to a bucket. You can have a handle even if the -bucket doesn't exist yet. To create a bucket in Google Cloud Storage, -call Create on the handle: - - if err := bkt.Create(ctx, projectID, nil); err != nil { - // TODO: Handle error. - } - -Note that although buckets are associated with projects, bucket names are -global across all projects. - -Each bucket has associated metadata, represented in this package by -BucketAttrs. The third argument to BucketHandle.Create allows you to set -the intial BucketAttrs of a bucket. To retrieve a bucket's attributes, use -Attrs: - - attrs, err := bkt.Attrs(ctx) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n", - attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass) - -Objects - -An object holds arbitrary data as a sequence of bytes, like a file. You -refer to objects using a handle, just as with buckets. You can use the -standard Go io.Reader and io.Writer interfaces to read and write -object data: - - obj := bkt.Object("data") - // Write something to obj. - // w implements io.Writer. - w := obj.NewWriter(ctx) - // Write some text to obj. This will overwrite whatever is there. - if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil { - // TODO: Handle error. - } - // Close, just like writing a file. - if err := w.Close(); err != nil { - // TODO: Handle error. - } - - // Read it back. - r, err := obj.NewReader(ctx) - if err != nil { - // TODO: Handle error. - } - defer r.Close() - if _, err := io.Copy(os.Stdout, r); err != nil { - // TODO: Handle error. - } - // Prints "This object contains text." - -Objects also have attributes, which you can fetch with Attrs: - - objAttrs, err := obj.Attrs(ctx) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("object %s has size %d and can be read using %s\n", - objAttrs.Name, objAttrs.Size, objAttrs.MediaLink) - -ACLs - -Both objects and buckets have ACLs (Access Control Lists). An ACL is a list of -ACLRules, each of which specifies the role of a user, group or project. ACLs -are suitable for fine-grained control, but you may prefer using IAM to control -access at the project level (see -https://cloud.google.com/storage/docs/access-control/iam). - -To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method: - - acls, err := obj.ACL().List(ctx) - if err != nil { - // TODO: Handle error. - } - for _, rule := range acls { - fmt.Printf("%s has role %s\n", rule.Entity, rule.Role) - } - -You can also set and delete ACLs. - -Conditions - -Every object has a generation and a metageneration. The generation changes -whenever the content changes, and the metageneration changes whenever the -metadata changes. Conditions let you check these values before an operation; -the operation only executes if the conditions match. You can use conditions to -prevent race conditions in read-modify-write operations. - -For example, say you've read an object's metadata into objAttrs. Now -you want to write to that object, but only if its contents haven't changed -since you read it. Here is how to express that: - - w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx) - // Proceed with writing as above. - -Signed URLs - -You can obtain a URL that lets anyone read or write an object for a limited time. -You don't need to create a client to do this. See the documentation of -SignedURL for details. - - url, err := storage.SignedURL(bucketName, "shared-object", opts) - if err != nil { - // TODO: Handle error. - } - fmt.Println(url) - -Authentication - -See examples of authorization and authentication at -https://godoc.org/cloud.google.com/go#pkg-examples. -*/ -package storage // import "cloud.google.com/go/storage" diff --git a/vendor/cloud.google.com/go/storage/go17.go b/vendor/cloud.google.com/go/storage/go17.go deleted file mode 100644 index 982db4e1a16..00000000000 --- a/vendor/cloud.google.com/go/storage/go17.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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. - -// +build go1.7 - -package storage - -import ( - "context" - "net/http" -) - -func withContext(r *http.Request, ctx context.Context) *http.Request { - return r.WithContext(ctx) -} diff --git a/vendor/cloud.google.com/go/storage/iam.go b/vendor/cloud.google.com/go/storage/iam.go deleted file mode 100644 index 6607d8cc2c0..00000000000 --- a/vendor/cloud.google.com/go/storage/iam.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "cloud.google.com/go/iam" - "golang.org/x/net/context" - raw "google.golang.org/api/storage/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" -) - -// IAM provides access to IAM access control for the bucket. -func (b *BucketHandle) IAM() *iam.Handle { - return iam.InternalNewHandleClient(&iamClient{raw: b.c.raw}, b.name) -} - -// iamClient implements the iam.client interface. -type iamClient struct { - raw *raw.Service -} - -func (c *iamClient) Get(ctx context.Context, resource string) (*iampb.Policy, error) { - req := c.raw.Buckets.GetIamPolicy(resource) - setClientHeader(req.Header()) - var rp *raw.Policy - var err error - err = runWithRetry(ctx, func() error { - rp, err = req.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return iamFromStoragePolicy(rp), nil -} - -func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) error { - rp := iamToStoragePolicy(p) - req := c.raw.Buckets.SetIamPolicy(resource, rp) - setClientHeader(req.Header()) - return runWithRetry(ctx, func() error { - _, err := req.Context(ctx).Do() - return err - }) -} - -func (c *iamClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) { - req := c.raw.Buckets.TestIamPermissions(resource, perms) - setClientHeader(req.Header()) - var res *raw.TestIamPermissionsResponse - var err error - err = runWithRetry(ctx, func() error { - res, err = req.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return res.Permissions, nil -} - -func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy { - return &raw.Policy{ - Bindings: iamToStorageBindings(ip.Bindings), - Etag: string(ip.Etag), - } -} - -func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings { - var rbs []*raw.PolicyBindings - for _, ib := range ibs { - rbs = append(rbs, &raw.PolicyBindings{ - Role: ib.Role, - Members: ib.Members, - }) - } - return rbs -} - -func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy { - return &iampb.Policy{ - Bindings: iamFromStorageBindings(rp.Bindings), - Etag: []byte(rp.Etag), - } -} - -func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding { - var ibs []*iampb.Binding - for _, rb := range rbs { - ibs = append(ibs, &iampb.Binding{ - Role: rb.Role, - Members: rb.Members, - }) - } - return ibs -} diff --git a/vendor/cloud.google.com/go/storage/invoke.go b/vendor/cloud.google.com/go/storage/invoke.go deleted file mode 100644 index e8fc924eade..00000000000 --- a/vendor/cloud.google.com/go/storage/invoke.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "cloud.google.com/go/internal" - gax "github.com/googleapis/gax-go" - "golang.org/x/net/context" - "google.golang.org/api/googleapi" -) - -// runWithRetry calls the function until it returns nil or a non-retryable error, or -// the context is done. -func runWithRetry(ctx context.Context, call func() error) error { - return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { - err = call() - if err == nil { - return true, nil - } - e, ok := err.(*googleapi.Error) - if !ok { - return true, err - } - // Retry on 429 and 5xx, according to - // https://cloud.google.com/storage/docs/exponential-backoff. - if e.Code == 429 || (e.Code >= 500 && e.Code < 600) { - return false, nil - } - return true, err - }) -} diff --git a/vendor/cloud.google.com/go/storage/not_go17.go b/vendor/cloud.google.com/go/storage/not_go17.go deleted file mode 100644 index 1f6f7ae95cf..00000000000 --- a/vendor/cloud.google.com/go/storage/not_go17.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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. - -// +build !go1.7 - -package storage - -import ( - "net/http" -) - -func withContext(r *http.Request, _ interface{}) *http.Request { - // In Go 1.6 and below, ignore the context. - return r -} diff --git a/vendor/cloud.google.com/go/storage/reader.go b/vendor/cloud.google.com/go/storage/reader.go deleted file mode 100644 index aa103c17574..00000000000 --- a/vendor/cloud.google.com/go/storage/reader.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "fmt" - "hash/crc32" - "io" -) - -var crc32cTable = crc32.MakeTable(crc32.Castagnoli) - -// Reader reads a Cloud Storage object. -// It implements io.Reader. -type Reader struct { - body io.ReadCloser - remain, size int64 - contentType string - checkCRC bool // should we check the CRC? - wantCRC uint32 // the CRC32c value the server sent in the header - gotCRC uint32 // running crc -} - -// Close closes the Reader. It must be called when done reading. -func (r *Reader) Close() error { - return r.body.Close() -} - -func (r *Reader) Read(p []byte) (int, error) { - n, err := r.body.Read(p) - if r.remain != -1 { - r.remain -= int64(n) - } - if r.checkCRC { - r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, p[:n]) - // Check CRC here. It would be natural to check it in Close, but - // everybody defers Close on the assumption that it doesn't return - // anything worth looking at. - if r.remain == 0 && r.gotCRC != r.wantCRC { - return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d", - r.gotCRC, r.wantCRC) - } - } - return n, err -} - -// Size returns the size of the object in bytes. -// The returned value is always the same and is not affected by -// calls to Read or Close. -func (r *Reader) Size() int64 { - return r.size -} - -// Remain returns the number of bytes left to read, or -1 if unknown. -func (r *Reader) Remain() int64 { - return r.remain -} - -// ContentType returns the content type of the object. -func (r *Reader) ContentType() string { - return r.contentType -} diff --git a/vendor/cloud.google.com/go/storage/storage.go b/vendor/cloud.google.com/go/storage/storage.go deleted file mode 100644 index fd6c0455ebf..00000000000 --- a/vendor/cloud.google.com/go/storage/storage.go +++ /dev/null @@ -1,1117 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "bytes" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "strconv" - "strings" - "time" - "unicode/utf8" - - "google.golang.org/api/option" - htransport "google.golang.org/api/transport/http" - - "cloud.google.com/go/internal/optional" - "cloud.google.com/go/internal/version" - "golang.org/x/net/context" - "google.golang.org/api/googleapi" - raw "google.golang.org/api/storage/v1" -) - -var ( - ErrBucketNotExist = errors.New("storage: bucket doesn't exist") - ErrObjectNotExist = errors.New("storage: object doesn't exist") -) - -const userAgent = "gcloud-golang-storage/20151204" - -const ( - // ScopeFullControl grants permissions to manage your - // data and permissions in Google Cloud Storage. - ScopeFullControl = raw.DevstorageFullControlScope - - // ScopeReadOnly grants permissions to - // view your data in Google Cloud Storage. - ScopeReadOnly = raw.DevstorageReadOnlyScope - - // ScopeReadWrite grants permissions to manage your - // data in Google Cloud Storage. - ScopeReadWrite = raw.DevstorageReadWriteScope -) - -var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo) - -func setClientHeader(headers http.Header) { - headers.Set("x-goog-api-client", xGoogHeader) -} - -// Client is a client for interacting with Google Cloud Storage. -// -// Clients should be reused instead of created as needed. -// The methods of Client are safe for concurrent use by multiple goroutines. -type Client struct { - hc *http.Client - raw *raw.Service -} - -// NewClient creates a new Google Cloud Storage client. -// The default scope is ScopeFullControl. To use a different scope, like ScopeReadOnly, use option.WithScopes. -func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { - o := []option.ClientOption{ - option.WithScopes(ScopeFullControl), - option.WithUserAgent(userAgent), - } - opts = append(o, opts...) - hc, ep, err := htransport.NewClient(ctx, opts...) - if err != nil { - return nil, fmt.Errorf("dialing: %v", err) - } - rawService, err := raw.New(hc) - if err != nil { - return nil, fmt.Errorf("storage client: %v", err) - } - if ep != "" { - rawService.BasePath = ep - } - return &Client{ - hc: hc, - raw: rawService, - }, nil -} - -// Close closes the Client. -// -// Close need not be called at program exit. -func (c *Client) Close() error { - c.hc = nil - return nil -} - -// SignedURLOptions allows you to restrict the access to the signed URL. -type SignedURLOptions struct { - // GoogleAccessID represents the authorizer of the signed URL generation. - // It is typically the Google service account client email address from - // the Google Developers Console in the form of "xxx@developer.gserviceaccount.com". - // Required. - GoogleAccessID string - - // PrivateKey is the Google service account private key. It is obtainable - // from the Google Developers Console. - // At https://console.developers.google.com/project//apiui/credential, - // create a service account client ID or reuse one of your existing service account - // credentials. Click on the "Generate new P12 key" to generate and download - // a new private key. Once you download the P12 file, use the following command - // to convert it into a PEM file. - // - // $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes - // - // Provide the contents of the PEM file as a byte slice. - // Exactly one of PrivateKey or SignBytes must be non-nil. - PrivateKey []byte - - // SignBytes is a function for implementing custom signing. - // If your application is running on Google App Engine, you can use appengine's internal signing function: - // ctx := appengine.NewContext(request) - // acc, _ := appengine.ServiceAccount(ctx) - // url, err := SignedURL("bucket", "object", &SignedURLOptions{ - // GoogleAccessID: acc, - // SignBytes: func(b []byte) ([]byte, error) { - // _, signedBytes, err := appengine.SignBytes(ctx, b) - // return signedBytes, err - // }, - // // etc. - // }) - // - // Exactly one of PrivateKey or SignBytes must be non-nil. - SignBytes func([]byte) ([]byte, error) - - // Method is the HTTP method to be used with the signed URL. - // Signed URLs can be used with GET, HEAD, PUT, and DELETE requests. - // Required. - Method string - - // Expires is the expiration time on the signed URL. It must be - // a datetime in the future. - // Required. - Expires time.Time - - // ContentType is the content type header the client must provide - // to use the generated signed URL. - // Optional. - ContentType string - - // Headers is a list of extention headers the client must provide - // in order to use the generated signed URL. - // Optional. - Headers []string - - // MD5 is the base64 encoded MD5 checksum of the file. - // If provided, the client should provide the exact value on the request - // header in order to use the signed URL. - // Optional. - MD5 string -} - -// SignedURL returns a URL for the specified object. Signed URLs allow -// the users access to a restricted resource for a limited time without having a -// Google account or signing in. For more information about the signed -// URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs. -func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) { - if opts == nil { - return "", errors.New("storage: missing required SignedURLOptions") - } - if opts.GoogleAccessID == "" { - return "", errors.New("storage: missing required GoogleAccessID") - } - if (opts.PrivateKey == nil) == (opts.SignBytes == nil) { - return "", errors.New("storage: exactly one of PrivateKey or SignedBytes must be set") - } - if opts.Method == "" { - return "", errors.New("storage: missing required method option") - } - if opts.Expires.IsZero() { - return "", errors.New("storage: missing required expires option") - } - if opts.MD5 != "" { - md5, err := base64.StdEncoding.DecodeString(opts.MD5) - if err != nil || len(md5) != 16 { - return "", errors.New("storage: invalid MD5 checksum") - } - } - - signBytes := opts.SignBytes - if opts.PrivateKey != nil { - key, err := parseKey(opts.PrivateKey) - if err != nil { - return "", err - } - signBytes = func(b []byte) ([]byte, error) { - sum := sha256.Sum256(b) - return rsa.SignPKCS1v15( - rand.Reader, - key, - crypto.SHA256, - sum[:], - ) - } - } - - u := &url.URL{ - Path: fmt.Sprintf("/%s/%s", bucket, name), - } - - buf := &bytes.Buffer{} - fmt.Fprintf(buf, "%s\n", opts.Method) - fmt.Fprintf(buf, "%s\n", opts.MD5) - fmt.Fprintf(buf, "%s\n", opts.ContentType) - fmt.Fprintf(buf, "%d\n", opts.Expires.Unix()) - if len(opts.Headers) > 0 { - fmt.Fprintf(buf, "%s\n", strings.Join(opts.Headers, "\n")) - } - fmt.Fprintf(buf, "%s", u.String()) - - b, err := signBytes(buf.Bytes()) - if err != nil { - return "", err - } - encoded := base64.StdEncoding.EncodeToString(b) - u.Scheme = "https" - u.Host = "storage.googleapis.com" - q := u.Query() - q.Set("GoogleAccessId", opts.GoogleAccessID) - q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix())) - q.Set("Signature", string(encoded)) - u.RawQuery = q.Encode() - return u.String(), nil -} - -// ObjectHandle provides operations on an object in a Google Cloud Storage bucket. -// Use BucketHandle.Object to get a handle. -type ObjectHandle struct { - c *Client - bucket string - object string - acl ACLHandle - gen int64 // a negative value indicates latest - conds *Conditions - encryptionKey []byte // AES-256 key - userProject string // for requester-pays buckets -} - -// ACL provides access to the object's access control list. -// This controls who can read and write this object. -// This call does not perform any network operations. -func (o *ObjectHandle) ACL() *ACLHandle { - return &o.acl -} - -// Generation returns a new ObjectHandle that operates on a specific generation -// of the object. -// By default, the handle operates on the latest generation. Not -// all operations work when given a specific generation; check the API -// endpoints at https://cloud.google.com/storage/docs/json_api/ for details. -func (o *ObjectHandle) Generation(gen int64) *ObjectHandle { - o2 := *o - o2.gen = gen - return &o2 -} - -// If returns a new ObjectHandle that applies a set of preconditions. -// Preconditions already set on the ObjectHandle are ignored. -// Operations on the new handle will only occur if the preconditions are -// satisfied. See https://cloud.google.com/storage/docs/generations-preconditions -// for more details. -func (o *ObjectHandle) If(conds Conditions) *ObjectHandle { - o2 := *o - o2.conds = &conds - return &o2 -} - -// Key returns a new ObjectHandle that uses the supplied encryption -// key to encrypt and decrypt the object's contents. -// -// Encryption key must be a 32-byte AES-256 key. -// See https://cloud.google.com/storage/docs/encryption for details. -func (o *ObjectHandle) Key(encryptionKey []byte) *ObjectHandle { - o2 := *o - o2.encryptionKey = encryptionKey - return &o2 -} - -// Attrs returns meta information about the object. -// ErrObjectNotExist will be returned if the object is not found. -func (o *ObjectHandle) Attrs(ctx context.Context) (*ObjectAttrs, error) { - if err := o.validate(); err != nil { - return nil, err - } - call := o.c.raw.Objects.Get(o.bucket, o.object).Projection("full").Context(ctx) - if err := applyConds("Attrs", o.gen, o.conds, call); err != nil { - return nil, err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - var err error - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrObjectNotExist - } - if err != nil { - return nil, err - } - return newObject(obj), nil -} - -// Update updates an object with the provided attributes. -// All zero-value attributes are ignored. -// ErrObjectNotExist will be returned if the object is not found. -func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (*ObjectAttrs, error) { - if err := o.validate(); err != nil { - return nil, err - } - var attrs ObjectAttrs - // Lists of fields to send, and set to null, in the JSON. - var forceSendFields, nullFields []string - if uattrs.ContentType != nil { - attrs.ContentType = optional.ToString(uattrs.ContentType) - forceSendFields = append(forceSendFields, "ContentType") - } - if uattrs.ContentLanguage != nil { - attrs.ContentLanguage = optional.ToString(uattrs.ContentLanguage) - // For ContentLanguage It's an error to send the empty string. - // Instead we send a null. - if attrs.ContentLanguage == "" { - nullFields = append(nullFields, "ContentLanguage") - } else { - forceSendFields = append(forceSendFields, "ContentLanguage") - } - } - if uattrs.ContentEncoding != nil { - attrs.ContentEncoding = optional.ToString(uattrs.ContentEncoding) - forceSendFields = append(forceSendFields, "ContentEncoding") - } - if uattrs.ContentDisposition != nil { - attrs.ContentDisposition = optional.ToString(uattrs.ContentDisposition) - forceSendFields = append(forceSendFields, "ContentDisposition") - } - if uattrs.CacheControl != nil { - attrs.CacheControl = optional.ToString(uattrs.CacheControl) - forceSendFields = append(forceSendFields, "CacheControl") - } - if uattrs.Metadata != nil { - attrs.Metadata = uattrs.Metadata - if len(attrs.Metadata) == 0 { - // Sending the empty map is a no-op. We send null instead. - nullFields = append(nullFields, "Metadata") - } else { - forceSendFields = append(forceSendFields, "Metadata") - } - } - if uattrs.ACL != nil { - attrs.ACL = uattrs.ACL - // It's an error to attempt to delete the ACL, so - // we don't append to nullFields here. - forceSendFields = append(forceSendFields, "Acl") - } - rawObj := attrs.toRawObject(o.bucket) - rawObj.ForceSendFields = forceSendFields - rawObj.NullFields = nullFields - call := o.c.raw.Objects.Patch(o.bucket, o.object, rawObj).Projection("full").Context(ctx) - if err := applyConds("Update", o.gen, o.conds, call); err != nil { - return nil, err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - var err error - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrObjectNotExist - } - if err != nil { - return nil, err - } - return newObject(obj), nil -} - -// ObjectAttrsToUpdate is used to update the attributes of an object. -// Only fields set to non-nil values will be updated. -// Set a field to its zero value to delete it. -// -// For example, to change ContentType and delete ContentEncoding and -// Metadata, use -// ObjectAttrsToUpdate{ -// ContentType: "text/html", -// ContentEncoding: "", -// Metadata: map[string]string{}, -// } -type ObjectAttrsToUpdate struct { - ContentType optional.String - ContentLanguage optional.String - ContentEncoding optional.String - ContentDisposition optional.String - CacheControl optional.String - Metadata map[string]string // set to map[string]string{} to delete - ACL []ACLRule -} - -// Delete deletes the single specified object. -func (o *ObjectHandle) Delete(ctx context.Context) error { - if err := o.validate(); err != nil { - return err - } - call := o.c.raw.Objects.Delete(o.bucket, o.object).Context(ctx) - if err := applyConds("Delete", o.gen, o.conds, call); err != nil { - return err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - // Encryption doesn't apply to Delete. - setClientHeader(call.Header()) - err := runWithRetry(ctx, func() error { return call.Do() }) - switch e := err.(type) { - case nil: - return nil - case *googleapi.Error: - if e.Code == http.StatusNotFound { - return ErrObjectNotExist - } - } - return err -} - -// NewReader creates a new Reader to read the contents of the -// object. -// ErrObjectNotExist will be returned if the object is not found. -// -// The caller must call Close on the returned Reader when done reading. -func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) { - return o.NewRangeReader(ctx, 0, -1) -} - -// NewRangeReader reads part of an object, reading at most length bytes -// starting at the given offset. If length is negative, the object is read -// until the end. -func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (*Reader, error) { - if err := o.validate(); err != nil { - return nil, err - } - if offset < 0 { - return nil, fmt.Errorf("storage: invalid offset %d < 0", offset) - } - if o.conds != nil { - if err := o.conds.validate("NewRangeReader"); err != nil { - return nil, err - } - } - u := &url.URL{ - Scheme: "https", - Host: "storage.googleapis.com", - Path: fmt.Sprintf("/%s/%s", o.bucket, o.object), - RawQuery: conditionsQuery(o.gen, o.conds), - } - verb := "GET" - if length == 0 { - verb = "HEAD" - } - req, err := http.NewRequest(verb, u.String(), nil) - if err != nil { - return nil, err - } - req = withContext(req, ctx) - if length < 0 && offset > 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) - } else if length > 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+length-1)) - } - if o.userProject != "" { - req.Header.Set("X-Goog-User-Project", o.userProject) - } - if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil { - return nil, err - } - var res *http.Response - err = runWithRetry(ctx, func() error { - res, err = o.c.hc.Do(req) - if err != nil { - return err - } - if res.StatusCode == http.StatusNotFound { - res.Body.Close() - return ErrObjectNotExist - } - if res.StatusCode < 200 || res.StatusCode > 299 { - body, _ := ioutil.ReadAll(res.Body) - res.Body.Close() - return &googleapi.Error{ - Code: res.StatusCode, - Header: res.Header, - Body: string(body), - } - } - if offset > 0 && length != 0 && res.StatusCode != http.StatusPartialContent { - res.Body.Close() - return errors.New("storage: partial request not satisfied") - } - return nil - }) - if err != nil { - return nil, err - } - - var size int64 // total size of object, even if a range was requested. - if res.StatusCode == http.StatusPartialContent { - cr := strings.TrimSpace(res.Header.Get("Content-Range")) - if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") { - return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) - } - size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64) - if err != nil { - return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) - } - } else { - size = res.ContentLength - } - - remain := res.ContentLength - body := res.Body - if length == 0 { - remain = 0 - body.Close() - body = emptyBody - } - var ( - checkCRC bool - crc uint32 - ) - // Even if there is a CRC header, we can't compute the hash on partial data. - if remain == size { - crc, checkCRC = parseCRC32c(res) - } - return &Reader{ - body: body, - size: size, - remain: remain, - contentType: res.Header.Get("Content-Type"), - wantCRC: crc, - checkCRC: checkCRC, - }, nil -} - -func parseCRC32c(res *http.Response) (uint32, bool) { - const prefix = "crc32c=" - for _, spec := range res.Header["X-Goog-Hash"] { - if strings.HasPrefix(spec, prefix) { - c, err := decodeUint32(spec[len(prefix):]) - if err == nil { - return c, true - } - } - } - return 0, false -} - -var emptyBody = ioutil.NopCloser(strings.NewReader("")) - -// NewWriter returns a storage Writer that writes to the GCS object -// associated with this ObjectHandle. -// -// A new object will be created unless an object with this name already exists. -// Otherwise any previous object with the same name will be replaced. -// The object will not be available (and any previous object will remain) -// until Close has been called. -// -// Attributes can be set on the object by modifying the returned Writer's -// ObjectAttrs field before the first call to Write. If no ContentType -// attribute is specified, the content type will be automatically sniffed -// using net/http.DetectContentType. -// -// It is the caller's responsibility to call Close when writing is done. -func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer { - return &Writer{ - ctx: ctx, - o: o, - donec: make(chan struct{}), - ObjectAttrs: ObjectAttrs{Name: o.object}, - ChunkSize: googleapi.DefaultUploadChunkSize, - } -} - -func (o *ObjectHandle) validate() error { - if o.bucket == "" { - return errors.New("storage: bucket name is empty") - } - if o.object == "" { - return errors.New("storage: object name is empty") - } - if !utf8.ValidString(o.object) { - return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object) - } - return nil -} - -// parseKey converts the binary contents of a private key file -// to an *rsa.PrivateKey. It detects whether the private key is in a -// PEM container or not. If so, it extracts the the private key -// from PEM container before conversion. It only supports PEM -// containers with no passphrase. -func parseKey(key []byte) (*rsa.PrivateKey, error) { - if block, _ := pem.Decode(key); block != nil { - key = block.Bytes - } - parsedKey, err := x509.ParsePKCS8PrivateKey(key) - if err != nil { - parsedKey, err = x509.ParsePKCS1PrivateKey(key) - if err != nil { - return nil, err - } - } - parsed, ok := parsedKey.(*rsa.PrivateKey) - if !ok { - return nil, errors.New("oauth2: private key is invalid") - } - return parsed, nil -} - -func toRawObjectACL(oldACL []ACLRule) []*raw.ObjectAccessControl { - var acl []*raw.ObjectAccessControl - if len(oldACL) > 0 { - acl = make([]*raw.ObjectAccessControl, len(oldACL)) - for i, rule := range oldACL { - acl[i] = &raw.ObjectAccessControl{ - Entity: string(rule.Entity), - Role: string(rule.Role), - } - } - } - return acl -} - -// toRawObject copies the editable attributes from o to the raw library's Object type. -func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object { - acl := toRawObjectACL(o.ACL) - return &raw.Object{ - Bucket: bucket, - Name: o.Name, - ContentType: o.ContentType, - ContentEncoding: o.ContentEncoding, - ContentLanguage: o.ContentLanguage, - CacheControl: o.CacheControl, - ContentDisposition: o.ContentDisposition, - StorageClass: o.StorageClass, - Acl: acl, - Metadata: o.Metadata, - } -} - -// ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object. -type ObjectAttrs struct { - // Bucket is the name of the bucket containing this GCS object. - // This field is read-only. - Bucket string - - // Name is the name of the object within the bucket. - // This field is read-only. - Name string - - // ContentType is the MIME type of the object's content. - ContentType string - - // ContentLanguage is the content language of the object's content. - ContentLanguage string - - // CacheControl is the Cache-Control header to be sent in the response - // headers when serving the object data. - CacheControl string - - // ACL is the list of access control rules for the object. - ACL []ACLRule - - // Owner is the owner of the object. This field is read-only. - // - // If non-zero, it is in the form of "user-". - Owner string - - // Size is the length of the object's content. This field is read-only. - Size int64 - - // ContentEncoding is the encoding of the object's content. - ContentEncoding string - - // ContentDisposition is the optional Content-Disposition header of the object - // sent in the response headers. - ContentDisposition string - - // MD5 is the MD5 hash of the object's content. This field is read-only. - MD5 []byte - - // CRC32C is the CRC32 checksum of the object's content using - // the Castagnoli93 polynomial. This field is read-only. - CRC32C uint32 - - // MediaLink is an URL to the object's content. This field is read-only. - MediaLink string - - // Metadata represents user-provided metadata, in key/value pairs. - // It can be nil if no metadata is provided. - Metadata map[string]string - - // Generation is the generation number of the object's content. - // This field is read-only. - Generation int64 - - // Metageneration is the version of the metadata for this - // object at this generation. This field is used for preconditions - // and for detecting changes in metadata. A metageneration number - // is only meaningful in the context of a particular generation - // of a particular object. This field is read-only. - Metageneration int64 - - // StorageClass is the storage class of the object. - // This value defines how objects in the bucket are stored and - // determines the SLA and the cost of storage. Typical values are - // "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" - // and "DURABLE_REDUCED_AVAILABILITY". - // It defaults to "STANDARD", which is equivalent to "MULTI_REGIONAL" - // or "REGIONAL" depending on the bucket's location settings. - StorageClass string - - // Created is the time the object was created. This field is read-only. - Created time.Time - - // Deleted is the time the object was deleted. - // If not deleted, it is the zero value. This field is read-only. - Deleted time.Time - - // Updated is the creation or modification time of the object. - // For buckets with versioning enabled, changing an object's - // metadata does not change this property. This field is read-only. - Updated time.Time - - // CustomerKeySHA256 is the base64-encoded SHA-256 hash of the - // customer-supplied encryption key for the object. It is empty if there is - // no customer-supplied encryption key. - // See // https://cloud.google.com/storage/docs/encryption for more about - // encryption in Google Cloud Storage. - CustomerKeySHA256 string - - // Prefix is set only for ObjectAttrs which represent synthetic "directory - // entries" when iterating over buckets using Query.Delimiter. See - // ObjectIterator.Next. When set, no other fields in ObjectAttrs will be - // populated. - Prefix string -} - -// convertTime converts a time in RFC3339 format to time.Time. -// If any error occurs in parsing, the zero-value time.Time is silently returned. -func convertTime(t string) time.Time { - var r time.Time - if t != "" { - r, _ = time.Parse(time.RFC3339, t) - } - return r -} - -func newObject(o *raw.Object) *ObjectAttrs { - if o == nil { - return nil - } - acl := make([]ACLRule, len(o.Acl)) - for i, rule := range o.Acl { - acl[i] = ACLRule{ - Entity: ACLEntity(rule.Entity), - Role: ACLRole(rule.Role), - } - } - owner := "" - if o.Owner != nil { - owner = o.Owner.Entity - } - md5, _ := base64.StdEncoding.DecodeString(o.Md5Hash) - crc32c, _ := decodeUint32(o.Crc32c) - var sha256 string - if o.CustomerEncryption != nil { - sha256 = o.CustomerEncryption.KeySha256 - } - return &ObjectAttrs{ - Bucket: o.Bucket, - Name: o.Name, - ContentType: o.ContentType, - ContentLanguage: o.ContentLanguage, - CacheControl: o.CacheControl, - ACL: acl, - Owner: owner, - ContentEncoding: o.ContentEncoding, - Size: int64(o.Size), - MD5: md5, - CRC32C: crc32c, - MediaLink: o.MediaLink, - Metadata: o.Metadata, - Generation: o.Generation, - Metageneration: o.Metageneration, - StorageClass: o.StorageClass, - CustomerKeySHA256: sha256, - Created: convertTime(o.TimeCreated), - Deleted: convertTime(o.TimeDeleted), - Updated: convertTime(o.Updated), - } -} - -// Decode a uint32 encoded in Base64 in big-endian byte order. -func decodeUint32(b64 string) (uint32, error) { - d, err := base64.StdEncoding.DecodeString(b64) - if err != nil { - return 0, err - } - if len(d) != 4 { - return 0, fmt.Errorf("storage: %q does not encode a 32-bit value", d) - } - return uint32(d[0])<<24 + uint32(d[1])<<16 + uint32(d[2])<<8 + uint32(d[3]), nil -} - -// Encode a uint32 as Base64 in big-endian byte order. -func encodeUint32(u uint32) string { - b := []byte{byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)} - return base64.StdEncoding.EncodeToString(b) -} - -// Query represents a query to filter objects from a bucket. -type Query struct { - // Delimiter returns results in a directory-like fashion. - // Results will contain only objects whose names, aside from the - // prefix, do not contain delimiter. Objects whose names, - // aside from the prefix, contain delimiter will have their name, - // truncated after the delimiter, returned in prefixes. - // Duplicate prefixes are omitted. - // Optional. - Delimiter string - - // Prefix is the prefix filter to query objects - // whose names begin with this prefix. - // Optional. - Prefix string - - // Versions indicates whether multiple versions of the same - // object will be included in the results. - Versions bool -} - -// contentTyper implements ContentTyper to enable an -// io.ReadCloser to specify its MIME type. -type contentTyper struct { - io.Reader - t string -} - -func (c *contentTyper) ContentType() string { - return c.t -} - -// Conditions constrain methods to act on specific generations of -// objects. -// -// The zero value is an empty set of constraints. Not all conditions or -// combinations of conditions are applicable to all methods. -// See https://cloud.google.com/storage/docs/generations-preconditions -// for details on how these operate. -type Conditions struct { - // Generation constraints. - // At most one of the following can be set to a non-zero value. - - // GenerationMatch specifies that the object must have the given generation - // for the operation to occur. - // If GenerationMatch is zero, it has no effect. - // Use DoesNotExist to specify that the object does not exist in the bucket. - GenerationMatch int64 - - // GenerationNotMatch specifies that the object must not have the given - // generation for the operation to occur. - // If GenerationNotMatch is zero, it has no effect. - GenerationNotMatch int64 - - // DoesNotExist specifies that the object must not exist in the bucket for - // the operation to occur. - // If DoesNotExist is false, it has no effect. - DoesNotExist bool - - // Metadata generation constraints. - // At most one of the following can be set to a non-zero value. - - // MetagenerationMatch specifies that the object must have the given - // metageneration for the operation to occur. - // If MetagenerationMatch is zero, it has no effect. - MetagenerationMatch int64 - - // MetagenerationNotMatch specifies that the object must not have the given - // metageneration for the operation to occur. - // If MetagenerationNotMatch is zero, it has no effect. - MetagenerationNotMatch int64 -} - -func (c *Conditions) validate(method string) error { - if *c == (Conditions{}) { - return fmt.Errorf("storage: %s: empty conditions", method) - } - if !c.isGenerationValid() { - return fmt.Errorf("storage: %s: multiple conditions specified for generation", method) - } - if !c.isMetagenerationValid() { - return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method) - } - return nil -} - -func (c *Conditions) isGenerationValid() bool { - n := 0 - if c.GenerationMatch != 0 { - n++ - } - if c.GenerationNotMatch != 0 { - n++ - } - if c.DoesNotExist { - n++ - } - return n <= 1 -} - -func (c *Conditions) isMetagenerationValid() bool { - return c.MetagenerationMatch == 0 || c.MetagenerationNotMatch == 0 -} - -// applyConds modifies the provided call using the conditions in conds. -// call is something that quacks like a *raw.WhateverCall. -func applyConds(method string, gen int64, conds *Conditions, call interface{}) error { - cval := reflect.ValueOf(call) - if gen >= 0 { - if !setConditionField(cval, "Generation", gen) { - return fmt.Errorf("storage: %s: generation not supported", method) - } - } - if conds == nil { - return nil - } - if err := conds.validate(method); err != nil { - return err - } - switch { - case conds.GenerationMatch != 0: - if !setConditionField(cval, "IfGenerationMatch", conds.GenerationMatch) { - return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method) - } - case conds.GenerationNotMatch != 0: - if !setConditionField(cval, "IfGenerationNotMatch", conds.GenerationNotMatch) { - return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method) - } - case conds.DoesNotExist: - if !setConditionField(cval, "IfGenerationMatch", int64(0)) { - return fmt.Errorf("storage: %s: DoesNotExist not supported", method) - } - } - switch { - case conds.MetagenerationMatch != 0: - if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) - } - case conds.MetagenerationNotMatch != 0: - if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) { - return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) - } - } - return nil -} - -func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall) error { - if gen >= 0 { - call.SourceGeneration(gen) - } - if conds == nil { - return nil - } - if err := conds.validate("CopyTo source"); err != nil { - return err - } - switch { - case conds.GenerationMatch != 0: - call.IfSourceGenerationMatch(conds.GenerationMatch) - case conds.GenerationNotMatch != 0: - call.IfSourceGenerationNotMatch(conds.GenerationNotMatch) - case conds.DoesNotExist: - call.IfSourceGenerationMatch(0) - } - switch { - case conds.MetagenerationMatch != 0: - call.IfSourceMetagenerationMatch(conds.MetagenerationMatch) - case conds.MetagenerationNotMatch != 0: - call.IfSourceMetagenerationNotMatch(conds.MetagenerationNotMatch) - } - return nil -} - -// setConditionField sets a field on a *raw.WhateverCall. -// We can't use anonymous interfaces because the return type is -// different, since the field setters are builders. -func setConditionField(call reflect.Value, name string, value interface{}) bool { - m := call.MethodByName(name) - if !m.IsValid() { - return false - } - m.Call([]reflect.Value{reflect.ValueOf(value)}) - return true -} - -// conditionsQuery returns the generation and conditions as a URL query -// string suitable for URL.RawQuery. It assumes that the conditions -// have been validated. -func conditionsQuery(gen int64, conds *Conditions) string { - // URL escapes are elided because integer strings are URL-safe. - var buf []byte - - appendParam := func(s string, n int64) { - if len(buf) > 0 { - buf = append(buf, '&') - } - buf = append(buf, s...) - buf = strconv.AppendInt(buf, n, 10) - } - - if gen >= 0 { - appendParam("generation=", gen) - } - if conds == nil { - return string(buf) - } - switch { - case conds.GenerationMatch != 0: - appendParam("ifGenerationMatch=", conds.GenerationMatch) - case conds.GenerationNotMatch != 0: - appendParam("ifGenerationNotMatch=", conds.GenerationNotMatch) - case conds.DoesNotExist: - appendParam("ifGenerationMatch=", 0) - } - switch { - case conds.MetagenerationMatch != 0: - appendParam("ifMetagenerationMatch=", conds.MetagenerationMatch) - case conds.MetagenerationNotMatch != 0: - appendParam("ifMetagenerationNotMatch=", conds.MetagenerationNotMatch) - } - return string(buf) -} - -// composeSourceObj wraps a *raw.ComposeRequestSourceObjects, but adds the methods -// that modifyCall searches for by name. -type composeSourceObj struct { - src *raw.ComposeRequestSourceObjects -} - -func (c composeSourceObj) Generation(gen int64) { - c.src.Generation = gen -} - -func (c composeSourceObj) IfGenerationMatch(gen int64) { - // It's safe to overwrite ObjectPreconditions, since its only field is - // IfGenerationMatch. - c.src.ObjectPreconditions = &raw.ComposeRequestSourceObjectsObjectPreconditions{ - IfGenerationMatch: gen, - } -} - -func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) error { - if key == nil { - return nil - } - // TODO(jbd): Ask the API team to return a more user-friendly error - // and avoid doing this check at the client level. - if len(key) != 32 { - return errors.New("storage: not a 32-byte AES-256 key") - } - var cs string - if copySource { - cs = "copy-source-" - } - headers.Set("x-goog-"+cs+"encryption-algorithm", "AES256") - headers.Set("x-goog-"+cs+"encryption-key", base64.StdEncoding.EncodeToString(key)) - keyHash := sha256.Sum256(key) - headers.Set("x-goog-"+cs+"encryption-key-sha256", base64.StdEncoding.EncodeToString(keyHash[:])) - return nil -} - -// TODO(jbd): Add storage.objects.watch. diff --git a/vendor/cloud.google.com/go/storage/writer.go b/vendor/cloud.google.com/go/storage/writer.go deleted file mode 100644 index 19f4f0e1059..00000000000 --- a/vendor/cloud.google.com/go/storage/writer.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 storage - -import ( - "encoding/base64" - "errors" - "fmt" - "io" - "unicode/utf8" - - "golang.org/x/net/context" - "google.golang.org/api/googleapi" - raw "google.golang.org/api/storage/v1" -) - -// A Writer writes a Cloud Storage object. -type Writer struct { - // ObjectAttrs are optional attributes to set on the object. Any attributes - // must be initialized before the first Write call. Nil or zero-valued - // attributes are ignored. - ObjectAttrs - - // SendCRC specifies whether to transmit a CRC32C field. It should be set - // to true in addition to setting the Writer's CRC32C field, because zero - // is a valid CRC and normally a zero would not be transmitted. - SendCRC32C bool - - // ChunkSize controls the maximum number of bytes of the object that the - // Writer will attempt to send to the server in a single request. Objects - // smaller than the size will be sent in a single request, while larger - // objects will be split over multiple requests. The size will be rounded up - // to the nearest multiple of 256K. If zero, chunking will be disabled and - // the object will be uploaded in a single request. - // - // ChunkSize will default to a reasonable value. Any custom configuration - // must be done before the first Write call. - ChunkSize int - - // ProgressFunc can be used to monitor the progress of a large write. - // operation. If ProgressFunc is not nil and writing requires multiple - // calls to the underlying service (see - // https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload), - // then ProgressFunc will be invoked after each call with the number of bytes of - // content copied so far. - // - // ProgressFunc should return quickly without blocking. - ProgressFunc func(int64) - - ctx context.Context - o *ObjectHandle - - opened bool - pw *io.PipeWriter - - donec chan struct{} // closed after err and obj are set. - err error - obj *ObjectAttrs -} - -func (w *Writer) open() error { - attrs := w.ObjectAttrs - // Check the developer didn't change the object Name (this is unfortunate, but - // we don't want to store an object under the wrong name). - if attrs.Name != w.o.object { - return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object) - } - if !utf8.ValidString(attrs.Name) { - return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name) - } - pr, pw := io.Pipe() - w.pw = pw - w.opened = true - - if w.ChunkSize < 0 { - return errors.New("storage: Writer.ChunkSize must non-negative") - } - mediaOpts := []googleapi.MediaOption{ - googleapi.ChunkSize(w.ChunkSize), - } - if c := attrs.ContentType; c != "" { - mediaOpts = append(mediaOpts, googleapi.ContentType(c)) - } - - go func() { - defer close(w.donec) - - rawObj := attrs.toRawObject(w.o.bucket) - if w.SendCRC32C { - rawObj.Crc32c = encodeUint32(attrs.CRC32C) - } - if w.MD5 != nil { - rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5) - } - call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj). - Media(pr, mediaOpts...). - Projection("full"). - Context(w.ctx) - if w.ProgressFunc != nil { - call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) }) - } - if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil { - w.err = err - pr.CloseWithError(w.err) - return - } - var resp *raw.Object - err := applyConds("NewWriter", w.o.gen, w.o.conds, call) - if err == nil { - if w.o.userProject != "" { - call.UserProject(w.o.userProject) - } - setClientHeader(call.Header()) - // We will only retry here if the initial POST, which obtains a URI for - // the resumable upload, fails with a retryable error. The upload itself - // has its own retry logic. - err = runWithRetry(w.ctx, func() error { - var err2 error - resp, err2 = call.Do() - return err2 - }) - } - if err != nil { - w.err = err - pr.CloseWithError(w.err) - return - } - w.obj = newObject(resp) - }() - return nil -} - -// Write appends to w. It implements the io.Writer interface. -// -// Since writes happen asynchronously, Write may return a nil -// error even though the write failed (or will fail). Always -// use the error returned from Writer.Close to determine if -// the upload was successful. -func (w *Writer) Write(p []byte) (n int, err error) { - if w.err != nil { - return 0, w.err - } - if !w.opened { - if err := w.open(); err != nil { - return 0, err - } - } - return w.pw.Write(p) -} - -// Close completes the write operation and flushes any buffered data. -// If Close doesn't return an error, metadata about the written object -// can be retrieved by calling Attrs. -func (w *Writer) Close() error { - if !w.opened { - if err := w.open(); err != nil { - return err - } - } - if err := w.pw.Close(); err != nil { - return err - } - <-w.donec - return w.err -} - -// CloseWithError aborts the write operation with the provided error. -// CloseWithError always returns nil. -func (w *Writer) CloseWithError(err error) error { - if !w.opened { - return nil - } - return w.pw.CloseWithError(err) -} - -// Attrs returns metadata about a successfully-written object. -// It's only valid to call it after Close returns nil. -func (w *Writer) Attrs() *ObjectAttrs { - return w.obj -} diff --git a/vendor/github.com/BurntSushi/toml/.gitignore b/vendor/github.com/BurntSushi/toml/.gitignore deleted file mode 100644 index 0cd3800377d..00000000000 --- a/vendor/github.com/BurntSushi/toml/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -TAGS -tags -.*.swp -tomlcheck/tomlcheck -toml.test diff --git a/vendor/github.com/BurntSushi/toml/.travis.yml b/vendor/github.com/BurntSushi/toml/.travis.yml deleted file mode 100644 index 43caf6d0211..00000000000 --- a/vendor/github.com/BurntSushi/toml/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go -go: - - 1.1 - - 1.2 - - tip -install: - - go install ./... - - go get github.com/BurntSushi/toml-test -script: - - export PATH="$PATH:$HOME/gopath/bin" - - make test - diff --git a/vendor/github.com/BurntSushi/toml/COMPATIBLE b/vendor/github.com/BurntSushi/toml/COMPATIBLE deleted file mode 100644 index 21e0938caef..00000000000 --- a/vendor/github.com/BurntSushi/toml/COMPATIBLE +++ /dev/null @@ -1,3 +0,0 @@ -Compatible with TOML version -[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md) - diff --git a/vendor/github.com/BurntSushi/toml/Makefile b/vendor/github.com/BurntSushi/toml/Makefile deleted file mode 100644 index 3600848d331..00000000000 --- a/vendor/github.com/BurntSushi/toml/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -install: - go install ./... - -test: install - go test -v - toml-test toml-test-decoder - toml-test -encoder toml-test-encoder - -fmt: - gofmt -w *.go */*.go - colcheck *.go */*.go - -tags: - find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS - -push: - git push origin master - git push github master - diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md deleted file mode 100644 index 5a5df637094..00000000000 --- a/vendor/github.com/BurntSushi/toml/README.md +++ /dev/null @@ -1,220 +0,0 @@ -## TOML parser and encoder for Go with reflection - -TOML stands for Tom's Obvious, Minimal Language. This Go package provides a -reflection interface similar to Go's standard library `json` and `xml` -packages. This package also supports the `encoding.TextUnmarshaler` and -`encoding.TextMarshaler` interfaces so that you can define custom data -representations. (There is an example of this below.) - -Spec: https://github.com/mojombo/toml - -Compatible with TOML version -[v0.2.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.2.0.md) - -Documentation: http://godoc.org/github.com/BurntSushi/toml - -Installation: - -```bash -go get github.com/BurntSushi/toml -``` - -Try the toml validator: - -```bash -go get github.com/BurntSushi/toml/cmd/tomlv -tomlv some-toml-file.toml -``` - -[![Build status](https://api.travis-ci.org/BurntSushi/toml.png)](https://travis-ci.org/BurntSushi/toml) - - -### Testing - -This package passes all tests in -[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder -and the encoder. - -### Examples - -This package works similarly to how the Go standard library handles `XML` -and `JSON`. Namely, data is loaded into Go values via reflection. - -For the simplest example, consider some TOML file as just a list of keys -and values: - -```toml -Age = 25 -Cats = [ "Cauchy", "Plato" ] -Pi = 3.14 -Perfection = [ 6, 28, 496, 8128 ] -DOB = 1987-07-05T05:45:00Z -``` - -Which could be defined in Go as: - -```go -type Config struct { - Age int - Cats []string - Pi float64 - Perfection []int - DOB time.Time // requires `import time` -} -``` - -And then decoded with: - -```go -var conf Config -if _, err := toml.Decode(tomlData, &conf); err != nil { - // handle error -} -``` - -You can also use struct tags if your struct field name doesn't map to a TOML -key value directly: - -```toml -some_key_NAME = "wat" -``` - -```go -type TOML struct { - ObscureKey string `toml:"some_key_NAME"` -} -``` - -### Using the `encoding.TextUnmarshaler` interface - -Here's an example that automatically parses duration strings into -`time.Duration` values: - -```toml -[[song]] -name = "Thunder Road" -duration = "4m49s" - -[[song]] -name = "Stairway to Heaven" -duration = "8m03s" -``` - -Which can be decoded with: - -```go -type song struct { - Name string - Duration duration -} -type songs struct { - Song []song -} -var favorites songs -if _, err := toml.Decode(blob, &favorites); err != nil { - log.Fatal(err) -} - -for _, s := range favorites.Song { - fmt.Printf("%s (%s)\n", s.Name, s.Duration) -} -``` - -And you'll also need a `duration` type that satisfies the -`encoding.TextUnmarshaler` interface: - -```go -type duration struct { - time.Duration -} - -func (d *duration) UnmarshalText(text []byte) error { - var err error - d.Duration, err = time.ParseDuration(string(text)) - return err -} -``` - -### More complex usage - -Here's an example of how to load the example from the official spec page: - -```toml -# This is a TOML document. Boom. - -title = "TOML Example" - -[owner] -name = "Tom Preston-Werner" -organization = "GitHub" -bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." -dob = 1979-05-27T07:32:00Z # First class dates? Why not? - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # You can indent as you please. Tabs or spaces. TOML don't care. - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it - -# Line breaks are OK when inside arrays -hosts = [ - "alpha", - "omega" -] -``` - -And the corresponding Go types are: - -```go -type tomlConfig struct { - Title string - Owner ownerInfo - DB database `toml:"database"` - Servers map[string]server - Clients clients -} - -type ownerInfo struct { - Name string - Org string `toml:"organization"` - Bio string - DOB time.Time -} - -type database struct { - Server string - Ports []int - ConnMax int `toml:"connection_max"` - Enabled bool -} - -type server struct { - IP string - DC string -} - -type clients struct { - Data [][]interface{} - Hosts []string -} -``` - -Note that a case insensitive match will be tried if an exact match can't be -found. - -A working example of the above can be found in `_examples/example.{go,toml}`. - diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md deleted file mode 100644 index 24421eb7034..00000000000 --- a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Implements the TOML test suite interface - -This is an implementation of the interface expected by -[toml-test](https://github.com/BurntSushi/toml-test) for my -[toml parser written in Go](https://github.com/BurntSushi/toml). -In particular, it maps TOML data on `stdin` to a JSON format on `stdout`. - - -Compatible with TOML version -[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md) - -Compatible with `toml-test` version -[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0) - diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go b/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go deleted file mode 100644 index 14e7557005d..00000000000 --- a/vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go +++ /dev/null @@ -1,90 +0,0 @@ -// Command toml-test-decoder satisfies the toml-test interface for testing -// TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout. -package main - -import ( - "encoding/json" - "flag" - "fmt" - "log" - "os" - "path" - "time" - - "github.com/BurntSushi/toml" -) - -func init() { - log.SetFlags(0) - - flag.Usage = usage - flag.Parse() -} - -func usage() { - log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0])) - flag.PrintDefaults() - - os.Exit(1) -} - -func main() { - if flag.NArg() != 0 { - flag.Usage() - } - - var tmp interface{} - if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil { - log.Fatalf("Error decoding TOML: %s", err) - } - - typedTmp := translate(tmp) - if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil { - log.Fatalf("Error encoding JSON: %s", err) - } -} - -func translate(tomlData interface{}) interface{} { - switch orig := tomlData.(type) { - case map[string]interface{}: - typed := make(map[string]interface{}, len(orig)) - for k, v := range orig { - typed[k] = translate(v) - } - return typed - case []map[string]interface{}: - typed := make([]map[string]interface{}, len(orig)) - for i, v := range orig { - typed[i] = translate(v).(map[string]interface{}) - } - return typed - case []interface{}: - typed := make([]interface{}, len(orig)) - for i, v := range orig { - typed[i] = translate(v) - } - - // We don't really need to tag arrays, but let's be future proof. - // (If TOML ever supports tuples, we'll need this.) - return tag("array", typed) - case time.Time: - return tag("datetime", orig.Format("2006-01-02T15:04:05Z")) - case bool: - return tag("bool", fmt.Sprintf("%v", orig)) - case int64: - return tag("integer", fmt.Sprintf("%d", orig)) - case float64: - return tag("float", fmt.Sprintf("%v", orig)) - case string: - return tag("string", orig) - } - - panic(fmt.Sprintf("Unknown type: %T", tomlData)) -} - -func tag(typeName string, data interface{}) map[string]interface{} { - return map[string]interface{}{ - "type": typeName, - "value": data, - } -} diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md deleted file mode 100644 index 45a603f2980..00000000000 --- a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Implements the TOML test suite interface for TOML encoders - -This is an implementation of the interface expected by -[toml-test](https://github.com/BurntSushi/toml-test) for the -[TOML encoder](https://github.com/BurntSushi/toml). -In particular, it maps JSON data on `stdin` to a TOML format on `stdout`. - - -Compatible with TOML version -[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md) - -Compatible with `toml-test` version -[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0) - diff --git a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go b/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go deleted file mode 100644 index 092cc684496..00000000000 --- a/vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go +++ /dev/null @@ -1,131 +0,0 @@ -// Command toml-test-encoder satisfies the toml-test interface for testing -// TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout. -package main - -import ( - "encoding/json" - "flag" - "log" - "os" - "path" - "strconv" - "time" - - "github.com/BurntSushi/toml" -) - -func init() { - log.SetFlags(0) - - flag.Usage = usage - flag.Parse() -} - -func usage() { - log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0])) - flag.PrintDefaults() - - os.Exit(1) -} - -func main() { - if flag.NArg() != 0 { - flag.Usage() - } - - var tmp interface{} - if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil { - log.Fatalf("Error decoding JSON: %s", err) - } - - tomlData := translate(tmp) - if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil { - log.Fatalf("Error encoding TOML: %s", err) - } -} - -func translate(typedJson interface{}) interface{} { - switch v := typedJson.(type) { - case map[string]interface{}: - if len(v) == 2 && in("type", v) && in("value", v) { - return untag(v) - } - m := make(map[string]interface{}, len(v)) - for k, v2 := range v { - m[k] = translate(v2) - } - return m - case []interface{}: - tabArray := make([]map[string]interface{}, len(v)) - for i := range v { - if m, ok := translate(v[i]).(map[string]interface{}); ok { - tabArray[i] = m - } else { - log.Fatalf("JSON arrays may only contain objects. This " + - "corresponds to only tables being allowed in " + - "TOML table arrays.") - } - } - return tabArray - } - log.Fatalf("Unrecognized JSON format '%T'.", typedJson) - panic("unreachable") -} - -func untag(typed map[string]interface{}) interface{} { - t := typed["type"].(string) - v := typed["value"] - switch t { - case "string": - return v.(string) - case "integer": - v := v.(string) - n, err := strconv.Atoi(v) - if err != nil { - log.Fatalf("Could not parse '%s' as integer: %s", v, err) - } - return n - case "float": - v := v.(string) - f, err := strconv.ParseFloat(v, 64) - if err != nil { - log.Fatalf("Could not parse '%s' as float64: %s", v, err) - } - return f - case "datetime": - v := v.(string) - t, err := time.Parse("2006-01-02T15:04:05Z", v) - if err != nil { - log.Fatalf("Could not parse '%s' as a datetime: %s", v, err) - } - return t - case "bool": - v := v.(string) - switch v { - case "true": - return true - case "false": - return false - } - log.Fatalf("Could not parse '%s' as a boolean.", v) - case "array": - v := v.([]interface{}) - array := make([]interface{}, len(v)) - for i := range v { - if m, ok := v[i].(map[string]interface{}); ok { - array[i] = untag(m) - } else { - log.Fatalf("Arrays may only contain other arrays or "+ - "primitive values, but found a '%T'.", m) - } - } - return array - } - log.Fatalf("Unrecognized tag type '%s'.", t) - panic("unreachable") -} - -func in(key string, m map[string]interface{}) bool { - _, ok := m[key] - return ok -} diff --git a/vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md b/vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md deleted file mode 100644 index 5df0dc32bbf..00000000000 --- a/vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# TOML Validator - -If Go is installed, it's simple to try it out: - -```bash -go get github.com/BurntSushi/toml/cmd/tomlv -tomlv some-toml-file.toml -``` - -You can see the types of every key in a TOML file with: - -```bash -tomlv -types some-toml-file.toml -``` - -At the moment, only one error message is reported at a time. Error messages -include line numbers. No output means that the files given are valid TOML, or -there is a bug in `tomlv`. - -Compatible with TOML version -[v0.1.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.1.0.md) - diff --git a/vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go b/vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go deleted file mode 100644 index c7d689a7e91..00000000000 --- a/vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go +++ /dev/null @@ -1,61 +0,0 @@ -// Command tomlv validates TOML documents and prints each key's type. -package main - -import ( - "flag" - "fmt" - "log" - "os" - "path" - "strings" - "text/tabwriter" - - "github.com/BurntSushi/toml" -) - -var ( - flagTypes = false -) - -func init() { - log.SetFlags(0) - - flag.BoolVar(&flagTypes, "types", flagTypes, - "When set, the types of every defined key will be shown.") - - flag.Usage = usage - flag.Parse() -} - -func usage() { - log.Printf("Usage: %s toml-file [ toml-file ... ]\n", - path.Base(os.Args[0])) - flag.PrintDefaults() - - os.Exit(1) -} - -func main() { - if flag.NArg() < 1 { - flag.Usage() - } - for _, f := range flag.Args() { - var tmp interface{} - md, err := toml.DecodeFile(f, &tmp) - if err != nil { - log.Fatalf("Error in '%s': %s", f, err) - } - if flagTypes { - printTypes(md) - } - } -} - -func printTypes(md toml.MetaData) { - tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - for _, key := range md.Keys() { - fmt.Fprintf(tabw, "%s%s\t%s\n", - strings.Repeat(" ", len(key)-1), key, md.Type(key...)) - } - tabw.Flush() -} diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go index 6c7d398b89a..b0fd51d5b6e 100644 --- a/vendor/github.com/BurntSushi/toml/decode.go +++ b/vendor/github.com/BurntSushi/toml/decode.go @@ -10,7 +10,9 @@ import ( "time" ) -var e = fmt.Errorf +func e(format string, args ...interface{}) error { + return fmt.Errorf("toml: "+format, args...) +} // Unmarshaler is the interface implemented by objects that can unmarshal a // TOML description of themselves. @@ -103,6 +105,13 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { // This decoder will not handle cyclic types. If a cyclic type is passed, // `Decode` will not terminate. func Decode(data string, v interface{}) (MetaData, error) { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr { + return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v)) + } + if rv.IsNil() { + return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v)) + } p, err := parse(data) if err != nil { return MetaData{}, err @@ -111,7 +120,7 @@ func Decode(data string, v interface{}) (MetaData, error) { p.mapping, p.types, p.ordered, make(map[string]bool, len(p.ordered)), nil, } - return md, md.unify(p.mapping, rvalue(v)) + return md, md.unify(p.mapping, indirect(rv)) } // DecodeFile is just like Decode, except it will automatically read the @@ -211,7 +220,7 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error { case reflect.Interface: // we only support empty interfaces. if rv.NumMethod() > 0 { - return e("Unsupported type '%s'.", rv.Kind()) + return e("unsupported type %s", rv.Type()) } return md.unifyAnything(data, rv) case reflect.Float32: @@ -219,13 +228,17 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error { case reflect.Float64: return md.unifyFloat64(data, rv) } - return e("Unsupported type '%s'.", rv.Kind()) + return e("unsupported type %s", rv.Kind()) } func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { tmap, ok := mapping.(map[string]interface{}) if !ok { - return mismatch(rv, "map", mapping) + if mapping == nil { + return nil + } + return e("type mismatch for %s: expected table but found %T", + rv.Type().String(), mapping) } for key, datum := range tmap { @@ -250,14 +263,13 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { md.decoded[md.context.add(key).String()] = true md.context = append(md.context, key) if err := md.unify(datum, subv); err != nil { - return e("Type mismatch for '%s.%s': %s", - rv.Type().String(), f.name, err) + return err } md.context = md.context[0 : len(md.context)-1] } else if f.name != "" { // Bad user! No soup for you! - return e("Field '%s.%s' is unexported, and therefore cannot "+ - "be loaded with reflection.", rv.Type().String(), f.name) + return e("cannot write unexported field %s.%s", + rv.Type().String(), f.name) } } } @@ -267,6 +279,9 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { tmap, ok := mapping.(map[string]interface{}) if !ok { + if tmap == nil { + return nil + } return badtype("map", mapping) } if rv.IsNil() { @@ -292,6 +307,9 @@ func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { datav := reflect.ValueOf(data) if datav.Kind() != reflect.Slice { + if !datav.IsValid() { + return nil + } return badtype("slice", data) } sliceLen := datav.Len() @@ -305,12 +323,16 @@ func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { datav := reflect.ValueOf(data) if datav.Kind() != reflect.Slice { + if !datav.IsValid() { + return nil + } return badtype("slice", data) } - sliceLen := datav.Len() - if rv.IsNil() { - rv.Set(reflect.MakeSlice(rv.Type(), sliceLen, sliceLen)) + n := datav.Len() + if rv.IsNil() || rv.Cap() < n { + rv.Set(reflect.MakeSlice(rv.Type(), n, n)) } + rv.SetLen(n) return md.unifySliceArray(datav, rv) } @@ -365,15 +387,15 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { // No bounds checking necessary. case reflect.Int8: if num < math.MinInt8 || num > math.MaxInt8 { - return e("Value '%d' is out of range for int8.", num) + return e("value %d is out of range for int8", num) } case reflect.Int16: if num < math.MinInt16 || num > math.MaxInt16 { - return e("Value '%d' is out of range for int16.", num) + return e("value %d is out of range for int16", num) } case reflect.Int32: if num < math.MinInt32 || num > math.MaxInt32 { - return e("Value '%d' is out of range for int32.", num) + return e("value %d is out of range for int32", num) } } rv.SetInt(num) @@ -384,15 +406,15 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { // No bounds checking necessary. case reflect.Uint8: if num < 0 || unum > math.MaxUint8 { - return e("Value '%d' is out of range for uint8.", num) + return e("value %d is out of range for uint8", num) } case reflect.Uint16: if num < 0 || unum > math.MaxUint16 { - return e("Value '%d' is out of range for uint16.", num) + return e("value %d is out of range for uint16", num) } case reflect.Uint32: if num < 0 || unum > math.MaxUint32 { - return e("Value '%d' is out of range for uint32.", num) + return e("value %d is out of range for uint32", num) } } rv.SetUint(unum) @@ -458,7 +480,7 @@ func rvalue(v interface{}) reflect.Value { // interest to us (like encoding.TextUnmarshaler). func indirect(v reflect.Value) reflect.Value { if v.Kind() != reflect.Ptr { - if v.CanAddr() { + if v.CanSet() { pv := v.Addr() if _, ok := pv.Interface().(TextUnmarshaler); ok { return pv @@ -483,10 +505,5 @@ func isUnifiable(rv reflect.Value) bool { } func badtype(expected string, data interface{}) error { - return e("Expected %s but found '%T'.", expected, data) -} - -func mismatch(user reflect.Value, expected string, data interface{}) error { - return e("Type mismatch for %s. Expected %s but found '%T'.", - user.Type().String(), expected, data) + return e("cannot load TOML value of type %T into a Go %s", data, expected) } diff --git a/vendor/github.com/BurntSushi/toml/decode_meta.go b/vendor/github.com/BurntSushi/toml/decode_meta.go index ef6f545fa1b..b9914a6798c 100644 --- a/vendor/github.com/BurntSushi/toml/decode_meta.go +++ b/vendor/github.com/BurntSushi/toml/decode_meta.go @@ -77,9 +77,8 @@ func (k Key) maybeQuoted(i int) string { } if quote { return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" - } else { - return k[i] } + return k[i] } func (k Key) add(piece string) Key { diff --git a/vendor/github.com/BurntSushi/toml/decode_test.go b/vendor/github.com/BurntSushi/toml/decode_test.go deleted file mode 100644 index 3805931f2d3..00000000000 --- a/vendor/github.com/BurntSushi/toml/decode_test.go +++ /dev/null @@ -1,950 +0,0 @@ -package toml - -import ( - "fmt" - "log" - "reflect" - "testing" - "time" -) - -func init() { - log.SetFlags(0) -} - -func TestDecodeSimple(t *testing.T) { - var testSimple = ` -age = 250 -andrew = "gallant" -kait = "brady" -now = 1987-07-05T05:45:00Z -yesOrNo = true -pi = 3.14 -colors = [ - ["red", "green", "blue"], - ["cyan", "magenta", "yellow", "black"], -] - -[My.Cats] -plato = "cat 1" -cauchy = "cat 2" -` - - type cats struct { - Plato string - Cauchy string - } - type simple struct { - Age int - Colors [][]string - Pi float64 - YesOrNo bool - Now time.Time - Andrew string - Kait string - My map[string]cats - } - - var val simple - _, err := Decode(testSimple, &val) - if err != nil { - t.Fatal(err) - } - - now, err := time.Parse("2006-01-02T15:04:05", "1987-07-05T05:45:00") - if err != nil { - panic(err) - } - var answer = simple{ - Age: 250, - Andrew: "gallant", - Kait: "brady", - Now: now, - YesOrNo: true, - Pi: 3.14, - Colors: [][]string{ - {"red", "green", "blue"}, - {"cyan", "magenta", "yellow", "black"}, - }, - My: map[string]cats{ - "Cats": cats{Plato: "cat 1", Cauchy: "cat 2"}, - }, - } - if !reflect.DeepEqual(val, answer) { - t.Fatalf("Expected\n-----\n%#v\n-----\nbut got\n-----\n%#v\n", - answer, val) - } -} - -func TestDecodeEmbedded(t *testing.T) { - type Dog struct{ Name string } - type Age int - - tests := map[string]struct { - input string - decodeInto interface{} - wantDecoded interface{} - }{ - "embedded struct": { - input: `Name = "milton"`, - decodeInto: &struct{ Dog }{}, - wantDecoded: &struct{ Dog }{Dog{"milton"}}, - }, - "embedded non-nil pointer to struct": { - input: `Name = "milton"`, - decodeInto: &struct{ *Dog }{}, - wantDecoded: &struct{ *Dog }{&Dog{"milton"}}, - }, - "embedded nil pointer to struct": { - input: ``, - decodeInto: &struct{ *Dog }{}, - wantDecoded: &struct{ *Dog }{nil}, - }, - "embedded int": { - input: `Age = -5`, - decodeInto: &struct{ Age }{}, - wantDecoded: &struct{ Age }{-5}, - }, - } - - for label, test := range tests { - _, err := Decode(test.input, test.decodeInto) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(test.wantDecoded, test.decodeInto) { - t.Errorf("%s: want decoded == %+v, got %+v", - label, test.wantDecoded, test.decodeInto) - } - } -} - -func TestTableArrays(t *testing.T) { - var tomlTableArrays = ` -[[albums]] -name = "Born to Run" - - [[albums.songs]] - name = "Jungleland" - - [[albums.songs]] - name = "Meeting Across the River" - -[[albums]] -name = "Born in the USA" - - [[albums.songs]] - name = "Glory Days" - - [[albums.songs]] - name = "Dancing in the Dark" -` - - type Song struct { - Name string - } - - type Album struct { - Name string - Songs []Song - } - - type Music struct { - Albums []Album - } - - expected := Music{[]Album{ - {"Born to Run", []Song{{"Jungleland"}, {"Meeting Across the River"}}}, - {"Born in the USA", []Song{{"Glory Days"}, {"Dancing in the Dark"}}}, - }} - var got Music - if _, err := Decode(tomlTableArrays, &got); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, got) { - t.Fatalf("\n%#v\n!=\n%#v\n", expected, got) - } -} - -// Case insensitive matching tests. -// A bit more comprehensive than needed given the current implementation, -// but implementations change. -// Probably still missing demonstrations of some ugly corner cases regarding -// case insensitive matching and multiple fields. -func TestCase(t *testing.T) { - var caseToml = ` -tOpString = "string" -tOpInt = 1 -tOpFloat = 1.1 -tOpBool = true -tOpdate = 2006-01-02T15:04:05Z -tOparray = [ "array" ] -Match = "i should be in Match only" -MatcH = "i should be in MatcH only" -once = "just once" -[nEst.eD] -nEstedString = "another string" -` - - type InsensitiveEd struct { - NestedString string - } - - type InsensitiveNest struct { - Ed InsensitiveEd - } - - type Insensitive struct { - TopString string - TopInt int - TopFloat float64 - TopBool bool - TopDate time.Time - TopArray []string - Match string - MatcH string - Once string - OncE string - Nest InsensitiveNest - } - - tme, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5]) - if err != nil { - panic(err) - } - expected := Insensitive{ - TopString: "string", - TopInt: 1, - TopFloat: 1.1, - TopBool: true, - TopDate: tme, - TopArray: []string{"array"}, - MatcH: "i should be in MatcH only", - Match: "i should be in Match only", - Once: "just once", - OncE: "", - Nest: InsensitiveNest{ - Ed: InsensitiveEd{NestedString: "another string"}, - }, - } - var got Insensitive - if _, err := Decode(caseToml, &got); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, got) { - t.Fatalf("\n%#v\n!=\n%#v\n", expected, got) - } -} - -func TestPointers(t *testing.T) { - type Object struct { - Type string - Description string - } - - type Dict struct { - NamedObject map[string]*Object - BaseObject *Object - Strptr *string - Strptrs []*string - } - s1, s2, s3 := "blah", "abc", "def" - expected := &Dict{ - Strptr: &s1, - Strptrs: []*string{&s2, &s3}, - NamedObject: map[string]*Object{ - "foo": {"FOO", "fooooo!!!"}, - "bar": {"BAR", "ba-ba-ba-ba-barrrr!!!"}, - }, - BaseObject: &Object{"BASE", "da base"}, - } - - ex1 := ` -Strptr = "blah" -Strptrs = ["abc", "def"] - -[NamedObject.foo] -Type = "FOO" -Description = "fooooo!!!" - -[NamedObject.bar] -Type = "BAR" -Description = "ba-ba-ba-ba-barrrr!!!" - -[BaseObject] -Type = "BASE" -Description = "da base" -` - dict := new(Dict) - _, err := Decode(ex1, dict) - if err != nil { - t.Errorf("Decode error: %v", err) - } - if !reflect.DeepEqual(expected, dict) { - t.Fatalf("\n%#v\n!=\n%#v\n", expected, dict) - } -} - -type sphere struct { - Center [3]float64 - Radius float64 -} - -func TestDecodeSimpleArray(t *testing.T) { - var s1 sphere - if _, err := Decode(`center = [0.0, 1.5, 0.0]`, &s1); err != nil { - t.Fatal(err) - } -} - -func TestDecodeArrayWrongSize(t *testing.T) { - var s1 sphere - if _, err := Decode(`center = [0.1, 2.3]`, &s1); err == nil { - t.Fatal("Expected array type mismatch error") - } -} - -func TestDecodeLargeIntoSmallInt(t *testing.T) { - type table struct { - Value int8 - } - var tab table - if _, err := Decode(`value = 500`, &tab); err == nil { - t.Fatal("Expected integer out-of-bounds error.") - } -} - -func TestDecodeSizedInts(t *testing.T) { - type table struct { - U8 uint8 - U16 uint16 - U32 uint32 - U64 uint64 - U uint - I8 int8 - I16 int16 - I32 int32 - I64 int64 - I int - } - answer := table{1, 1, 1, 1, 1, -1, -1, -1, -1, -1} - toml := ` - u8 = 1 - u16 = 1 - u32 = 1 - u64 = 1 - u = 1 - i8 = -1 - i16 = -1 - i32 = -1 - i64 = -1 - i = -1 - ` - var tab table - if _, err := Decode(toml, &tab); err != nil { - t.Fatal(err.Error()) - } - if answer != tab { - t.Fatalf("Expected %#v but got %#v", answer, tab) - } -} - -func TestUnmarshaler(t *testing.T) { - - var tomlBlob = ` -[dishes.hamboogie] -name = "Hamboogie with fries" -price = 10.99 - -[[dishes.hamboogie.ingredients]] -name = "Bread Bun" - -[[dishes.hamboogie.ingredients]] -name = "Lettuce" - -[[dishes.hamboogie.ingredients]] -name = "Real Beef Patty" - -[[dishes.hamboogie.ingredients]] -name = "Tomato" - -[dishes.eggsalad] -name = "Egg Salad with rice" -price = 3.99 - -[[dishes.eggsalad.ingredients]] -name = "Egg" - -[[dishes.eggsalad.ingredients]] -name = "Mayo" - -[[dishes.eggsalad.ingredients]] -name = "Rice" -` - m := &menu{} - if _, err := Decode(tomlBlob, m); err != nil { - log.Fatal(err) - } - - if len(m.Dishes) != 2 { - t.Log("two dishes should be loaded with UnmarshalTOML()") - t.Errorf("expected %d but got %d", 2, len(m.Dishes)) - } - - eggSalad := m.Dishes["eggsalad"] - if _, ok := interface{}(eggSalad).(dish); !ok { - t.Errorf("expected a dish") - } - - if eggSalad.Name != "Egg Salad with rice" { - t.Errorf("expected the dish to be named 'Egg Salad with rice'") - } - - if len(eggSalad.Ingredients) != 3 { - t.Log("dish should be loaded with UnmarshalTOML()") - t.Errorf("expected %d but got %d", 3, len(eggSalad.Ingredients)) - } - - found := false - for _, i := range eggSalad.Ingredients { - if i.Name == "Rice" { - found = true - break - } - } - if !found { - t.Error("Rice was not loaded in UnmarshalTOML()") - } - - // test on a value - must be passed as * - o := menu{} - if _, err := Decode(tomlBlob, &o); err != nil { - log.Fatal(err) - } - -} - -type menu struct { - Dishes map[string]dish -} - -func (m *menu) UnmarshalTOML(p interface{}) error { - m.Dishes = make(map[string]dish) - data, _ := p.(map[string]interface{}) - dishes := data["dishes"].(map[string]interface{}) - for n, v := range dishes { - if d, ok := v.(map[string]interface{}); ok { - nd := dish{} - nd.UnmarshalTOML(d) - m.Dishes[n] = nd - } else { - return fmt.Errorf("not a dish") - } - } - return nil -} - -type dish struct { - Name string - Price float32 - Ingredients []ingredient -} - -func (d *dish) UnmarshalTOML(p interface{}) error { - data, _ := p.(map[string]interface{}) - d.Name, _ = data["name"].(string) - d.Price, _ = data["price"].(float32) - ingredients, _ := data["ingredients"].([]map[string]interface{}) - for _, e := range ingredients { - n, _ := interface{}(e).(map[string]interface{}) - name, _ := n["name"].(string) - i := ingredient{name} - d.Ingredients = append(d.Ingredients, i) - } - return nil -} - -type ingredient struct { - Name string -} - -func ExampleMetaData_PrimitiveDecode() { - var md MetaData - var err error - - var tomlBlob = ` -ranking = ["Springsteen", "J Geils"] - -[bands.Springsteen] -started = 1973 -albums = ["Greetings", "WIESS", "Born to Run", "Darkness"] - -[bands."J Geils"] -started = 1970 -albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"] -` - - type band struct { - Started int - Albums []string - } - type classics struct { - Ranking []string - Bands map[string]Primitive - } - - // Do the initial decode. Reflection is delayed on Primitive values. - var music classics - if md, err = Decode(tomlBlob, &music); err != nil { - log.Fatal(err) - } - - // MetaData still includes information on Primitive values. - fmt.Printf("Is `bands.Springsteen` defined? %v\n", - md.IsDefined("bands", "Springsteen")) - - // Decode primitive data into Go values. - for _, artist := range music.Ranking { - // A band is a primitive value, so we need to decode it to get a - // real `band` value. - primValue := music.Bands[artist] - - var aBand band - if err = md.PrimitiveDecode(primValue, &aBand); err != nil { - log.Fatal(err) - } - fmt.Printf("%s started in %d.\n", artist, aBand.Started) - } - // Check to see if there were any fields left undecoded. - // Note that this won't be empty before decoding the Primitive value! - fmt.Printf("Undecoded: %q\n", md.Undecoded()) - - // Output: - // Is `bands.Springsteen` defined? true - // Springsteen started in 1973. - // J Geils started in 1970. - // Undecoded: [] -} - -func ExampleDecode() { - var tomlBlob = ` -# Some comments. -[alpha] -ip = "10.0.0.1" - - [alpha.config] - Ports = [ 8001, 8002 ] - Location = "Toronto" - Created = 1987-07-05T05:45:00Z - -[beta] -ip = "10.0.0.2" - - [beta.config] - Ports = [ 9001, 9002 ] - Location = "New Jersey" - Created = 1887-01-05T05:55:00Z -` - - type serverConfig struct { - Ports []int - Location string - Created time.Time - } - - type server struct { - IP string `toml:"ip"` - Config serverConfig `toml:"config"` - } - - type servers map[string]server - - var config servers - if _, err := Decode(tomlBlob, &config); err != nil { - log.Fatal(err) - } - - for _, name := range []string{"alpha", "beta"} { - s := config[name] - fmt.Printf("Server: %s (ip: %s) in %s created on %s\n", - name, s.IP, s.Config.Location, - s.Config.Created.Format("2006-01-02")) - fmt.Printf("Ports: %v\n", s.Config.Ports) - } - - // Output: - // Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05 - // Ports: [8001 8002] - // Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05 - // Ports: [9001 9002] -} - -type duration struct { - time.Duration -} - -func (d *duration) UnmarshalText(text []byte) error { - var err error - d.Duration, err = time.ParseDuration(string(text)) - return err -} - -// Example Unmarshaler shows how to decode TOML strings into your own -// custom data type. -func Example_unmarshaler() { - blob := ` -[[song]] -name = "Thunder Road" -duration = "4m49s" - -[[song]] -name = "Stairway to Heaven" -duration = "8m03s" -` - type song struct { - Name string - Duration duration - } - type songs struct { - Song []song - } - var favorites songs - if _, err := Decode(blob, &favorites); err != nil { - log.Fatal(err) - } - - // Code to implement the TextUnmarshaler interface for `duration`: - // - // type duration struct { - // time.Duration - // } - // - // func (d *duration) UnmarshalText(text []byte) error { - // var err error - // d.Duration, err = time.ParseDuration(string(text)) - // return err - // } - - for _, s := range favorites.Song { - fmt.Printf("%s (%s)\n", s.Name, s.Duration) - } - // Output: - // Thunder Road (4m49s) - // Stairway to Heaven (8m3s) -} - -// Example StrictDecoding shows how to detect whether there are keys in the -// TOML document that weren't decoded into the value given. This is useful -// for returning an error to the user if they've included extraneous fields -// in their configuration. -func Example_strictDecoding() { - var blob = ` -key1 = "value1" -key2 = "value2" -key3 = "value3" -` - type config struct { - Key1 string - Key3 string - } - - var conf config - md, err := Decode(blob, &conf) - if err != nil { - log.Fatal(err) - } - fmt.Printf("Undecoded keys: %q\n", md.Undecoded()) - // Output: - // Undecoded keys: ["key2"] -} - -// Example UnmarshalTOML shows how to implement a struct type that knows how to -// unmarshal itself. The struct must take full responsibility for mapping the -// values passed into the struct. The method may be used with interfaces in a -// struct in cases where the actual type is not known until the data is -// examined. -func Example_unmarshalTOML() { - - var blob = ` -[[parts]] -type = "valve" -id = "valve-1" -size = 1.2 -rating = 4 - -[[parts]] -type = "valve" -id = "valve-2" -size = 2.1 -rating = 5 - -[[parts]] -type = "pipe" -id = "pipe-1" -length = 2.1 -diameter = 12 - -[[parts]] -type = "cable" -id = "cable-1" -length = 12 -rating = 3.1 -` - o := &order{} - err := Unmarshal([]byte(blob), o) - if err != nil { - log.Fatal(err) - } - - fmt.Println(len(o.parts)) - - for _, part := range o.parts { - fmt.Println(part.Name()) - } - - // Code to implement UmarshalJSON. - - // type order struct { - // // NOTE `order.parts` is a private slice of type `part` which is an - // // interface and may only be loaded from toml using the - // // UnmarshalTOML() method of the Umarshaler interface. - // parts parts - // } - - // func (o *order) UnmarshalTOML(data interface{}) error { - - // // NOTE the example below contains detailed type casting to show how - // // the 'data' is retrieved. In operational use, a type cast wrapper - // // may be prefered e.g. - // // - // // func AsMap(v interface{}) (map[string]interface{}, error) { - // // return v.(map[string]interface{}) - // // } - // // - // // resulting in: - // // d, _ := AsMap(data) - // // - - // d, _ := data.(map[string]interface{}) - // parts, _ := d["parts"].([]map[string]interface{}) - - // for _, p := range parts { - - // typ, _ := p["type"].(string) - // id, _ := p["id"].(string) - - // // detect the type of part and handle each case - // switch p["type"] { - // case "valve": - - // size := float32(p["size"].(float64)) - // rating := int(p["rating"].(int64)) - - // valve := &valve{ - // Type: typ, - // ID: id, - // Size: size, - // Rating: rating, - // } - - // o.parts = append(o.parts, valve) - - // case "pipe": - - // length := float32(p["length"].(float64)) - // diameter := int(p["diameter"].(int64)) - - // pipe := &pipe{ - // Type: typ, - // ID: id, - // Length: length, - // Diameter: diameter, - // } - - // o.parts = append(o.parts, pipe) - - // case "cable": - - // length := int(p["length"].(int64)) - // rating := float32(p["rating"].(float64)) - - // cable := &cable{ - // Type: typ, - // ID: id, - // Length: length, - // Rating: rating, - // } - - // o.parts = append(o.parts, cable) - - // } - // } - - // return nil - // } - - // type parts []part - - // type part interface { - // Name() string - // } - - // type valve struct { - // Type string - // ID string - // Size float32 - // Rating int - // } - - // func (v *valve) Name() string { - // return fmt.Sprintf("VALVE: %s", v.ID) - // } - - // type pipe struct { - // Type string - // ID string - // Length float32 - // Diameter int - // } - - // func (p *pipe) Name() string { - // return fmt.Sprintf("PIPE: %s", p.ID) - // } - - // type cable struct { - // Type string - // ID string - // Length int - // Rating float32 - // } - - // func (c *cable) Name() string { - // return fmt.Sprintf("CABLE: %s", c.ID) - // } - - // Output: - // 4 - // VALVE: valve-1 - // VALVE: valve-2 - // PIPE: pipe-1 - // CABLE: cable-1 - -} - -type order struct { - // NOTE `order.parts` is a private slice of type `part` which is an - // interface and may only be loaded from toml using the UnmarshalTOML() - // method of the Umarshaler interface. - parts parts -} - -func (o *order) UnmarshalTOML(data interface{}) error { - - // NOTE the example below contains detailed type casting to show how - // the 'data' is retrieved. In operational use, a type cast wrapper - // may be prefered e.g. - // - // func AsMap(v interface{}) (map[string]interface{}, error) { - // return v.(map[string]interface{}) - // } - // - // resulting in: - // d, _ := AsMap(data) - // - - d, _ := data.(map[string]interface{}) - parts, _ := d["parts"].([]map[string]interface{}) - - for _, p := range parts { - - typ, _ := p["type"].(string) - id, _ := p["id"].(string) - - // detect the type of part and handle each case - switch p["type"] { - case "valve": - - size := float32(p["size"].(float64)) - rating := int(p["rating"].(int64)) - - valve := &valve{ - Type: typ, - ID: id, - Size: size, - Rating: rating, - } - - o.parts = append(o.parts, valve) - - case "pipe": - - length := float32(p["length"].(float64)) - diameter := int(p["diameter"].(int64)) - - pipe := &pipe{ - Type: typ, - ID: id, - Length: length, - Diameter: diameter, - } - - o.parts = append(o.parts, pipe) - - case "cable": - - length := int(p["length"].(int64)) - rating := float32(p["rating"].(float64)) - - cable := &cable{ - Type: typ, - ID: id, - Length: length, - Rating: rating, - } - - o.parts = append(o.parts, cable) - - } - } - - return nil -} - -type parts []part - -type part interface { - Name() string -} - -type valve struct { - Type string - ID string - Size float32 - Rating int -} - -func (v *valve) Name() string { - return fmt.Sprintf("VALVE: %s", v.ID) -} - -type pipe struct { - Type string - ID string - Length float32 - Diameter int -} - -func (p *pipe) Name() string { - return fmt.Sprintf("PIPE: %s", p.ID) -} - -type cable struct { - Type string - ID string - Length int - Rating float32 -} - -func (c *cable) Name() string { - return fmt.Sprintf("CABLE: %s", c.ID) -} diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go index fe26800041b..b371f396edc 100644 --- a/vendor/github.com/BurntSushi/toml/doc.go +++ b/vendor/github.com/BurntSushi/toml/doc.go @@ -4,7 +4,7 @@ files via reflection. There is also support for delaying decoding with the Primitive type, and querying the set of keys in a TOML document with the MetaData type. -The specification implemented: https://github.com/mojombo/toml +The specification implemented: https://github.com/toml-lang/toml The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify whether a file is a valid TOML document. It can also be used to print the diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go index c7e227c7f4f..d905c21a246 100644 --- a/vendor/github.com/BurntSushi/toml/encode.go +++ b/vendor/github.com/BurntSushi/toml/encode.go @@ -16,17 +16,17 @@ type tomlEncodeError struct{ error } var ( errArrayMixedElementTypes = errors.New( - "can't encode array with mixed element types") + "toml: cannot encode array with mixed element types") errArrayNilElement = errors.New( - "can't encode array with nil element") + "toml: cannot encode array with nil element") errNonString = errors.New( - "can't encode a map with non-string key type") + "toml: cannot encode a map with non-string key type") errAnonNonStruct = errors.New( - "can't encode an anonymous field that is not a struct") + "toml: cannot encode an anonymous field that is not a struct") errArrayNoTable = errors.New( - "TOML array element can't contain a table") + "toml: TOML array element cannot contain a table") errNoKey = errors.New( - "top-level values must be a Go map or struct") + "toml: top-level values must be Go maps or structs") errAnything = errors.New("") // used in testing ) @@ -148,7 +148,7 @@ func (enc *Encoder) encode(key Key, rv reflect.Value) { case reflect.Struct: enc.eTable(key, rv) default: - panic(e("Unsupported type for key '%s': %s", key, k)) + panic(e("unsupported type for key '%s': %s", key, k)) } } @@ -160,7 +160,7 @@ func (enc *Encoder) eElement(rv reflect.Value) { // Special case time.Time as a primitive. Has to come before // TextMarshaler below because time.Time implements // encoding.TextMarshaler, but we need to always use UTC. - enc.wf(v.In(time.FixedZone("UTC", 0)).Format("2006-01-02T15:04:05Z")) + enc.wf(v.UTC().Format("2006-01-02T15:04:05Z")) return case TextMarshaler: // Special case. Use text marshaler if it's available for this value. @@ -191,7 +191,7 @@ func (enc *Encoder) eElement(rv reflect.Value) { case reflect.String: enc.writeQuoted(rv.String()) default: - panic(e("Unexpected primitive type: %s", rv.Kind())) + panic(e("unexpected primitive type: %s", rv.Kind())) } } @@ -241,7 +241,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { func (enc *Encoder) eTable(key Key, rv reflect.Value) { panicIfInvalidKey(key) if len(key) == 1 { - // Output an extra new line between top-level tables. + // Output an extra newline between top-level tables. // (The newline isn't written if nothing else has been written though.) enc.newline() } @@ -306,19 +306,36 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) { addFields = func(rt reflect.Type, rv reflect.Value, start []int) { for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) - // skip unexporded fields - if f.PkgPath != "" { + // skip unexported fields + if f.PkgPath != "" && !f.Anonymous { continue } frv := rv.Field(i) if f.Anonymous { - frv := eindirect(frv) - t := frv.Type() - if t.Kind() != reflect.Struct { - encPanic(errAnonNonStruct) + t := f.Type + switch t.Kind() { + case reflect.Struct: + // Treat anonymous struct fields with + // tag names as though they are not + // anonymous, like encoding/json does. + if getOptions(f.Tag).name == "" { + addFields(t, frv, f.Index) + continue + } + case reflect.Ptr: + if t.Elem().Kind() == reflect.Struct && + getOptions(f.Tag).name == "" { + if !frv.IsNil() { + addFields(t.Elem(), frv.Elem(), f.Index) + } + continue + } + // Fall through to the normal field encoding logic below + // for non-struct anonymous fields. } - addFields(t, frv, f.Index) - } else if typeIsHash(tomlTypeOfGo(frv)) { + } + + if typeIsHash(tomlTypeOfGo(frv)) { fieldsSub = append(fieldsSub, append(start, f.Index...)) } else { fieldsDirect = append(fieldsDirect, append(start, f.Index...)) @@ -336,18 +353,18 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) { continue } - keyName := sft.Tag.Get("toml") - if keyName == "-" { + opts := getOptions(sft.Tag) + if opts.skip { continue } - if keyName == "" { - keyName = sft.Name + keyName := sft.Name + if opts.name != "" { + keyName = opts.name } - - keyName, opts := getOptions(keyName) - if _, ok := opts["omitempty"]; ok && isEmpty(sf) { + if opts.omitempty && isEmpty(sf) { continue - } else if _, ok := opts["omitzero"]; ok && isZero(sf) { + } + if opts.omitzero && isZero(sf) { continue } @@ -382,9 +399,8 @@ func tomlTypeOfGo(rv reflect.Value) tomlType { case reflect.Array, reflect.Slice: if typeEqual(tomlHash, tomlArrayType(rv)) { return tomlArrayHash - } else { - return tomlArray } + return tomlArray case reflect.Ptr, reflect.Interface: return tomlTypeOfGo(rv.Elem()) case reflect.String: @@ -441,50 +457,51 @@ func tomlArrayType(rv reflect.Value) tomlType { return firstType } -func getOptions(keyName string) (string, map[string]struct{}) { - opts := make(map[string]struct{}) - ss := strings.Split(keyName, ",") - name := ss[0] - if len(ss) > 1 { - for _, opt := range ss { - opts[opt] = struct{}{} +type tagOptions struct { + skip bool // "-" + name string + omitempty bool + omitzero bool +} + +func getOptions(tag reflect.StructTag) tagOptions { + t := tag.Get("toml") + if t == "-" { + return tagOptions{skip: true} + } + var opts tagOptions + parts := strings.Split(t, ",") + opts.name = parts[0] + for _, s := range parts[1:] { + switch s { + case "omitempty": + opts.omitempty = true + case "omitzero": + opts.omitzero = true } } - - return name, opts + return opts } func isZero(rv reflect.Value) bool { switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if rv.Int() == 0 { - return true - } + return rv.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - if rv.Uint() == 0 { - return true - } + return rv.Uint() == 0 case reflect.Float32, reflect.Float64: - if rv.Float() == 0.0 { - return true - } + return rv.Float() == 0.0 } - return false } func isEmpty(rv reflect.Value) bool { switch rv.Kind() { - case reflect.String: - if len(strings.TrimSpace(rv.String())) == 0 { - return true - } - case reflect.Array, reflect.Slice, reflect.Map: - if rv.Len() == 0 { - return true - } + case reflect.Array, reflect.Slice, reflect.Map, reflect.String: + return rv.Len() == 0 + case reflect.Bool: + return !rv.Bool() } - return false } diff --git a/vendor/github.com/BurntSushi/toml/encode_test.go b/vendor/github.com/BurntSushi/toml/encode_test.go deleted file mode 100644 index 445ca8e2110..00000000000 --- a/vendor/github.com/BurntSushi/toml/encode_test.go +++ /dev/null @@ -1,542 +0,0 @@ -package toml - -import ( - "bytes" - "fmt" - "log" - "net" - "testing" - "time" -) - -func TestEncodeRoundTrip(t *testing.T) { - type Config struct { - Age int - Cats []string - Pi float64 - Perfection []int - DOB time.Time - Ipaddress net.IP - } - - var inputs = Config{ - 13, - []string{"one", "two", "three"}, - 3.145, - []int{11, 2, 3, 4}, - time.Now(), - net.ParseIP("192.168.59.254"), - } - - var firstBuffer bytes.Buffer - e := NewEncoder(&firstBuffer) - err := e.Encode(inputs) - if err != nil { - t.Fatal(err) - } - var outputs Config - if _, err := Decode(firstBuffer.String(), &outputs); err != nil { - log.Printf("Could not decode:\n-----\n%s\n-----\n", - firstBuffer.String()) - t.Fatal(err) - } - - // could test each value individually, but I'm lazy - var secondBuffer bytes.Buffer - e2 := NewEncoder(&secondBuffer) - err = e2.Encode(outputs) - if err != nil { - t.Fatal(err) - } - if firstBuffer.String() != secondBuffer.String() { - t.Error( - firstBuffer.String(), - "\n\n is not identical to\n\n", - secondBuffer.String()) - } -} - -// XXX(burntsushi) -// I think these tests probably should be removed. They are good, but they -// ought to be obsolete by toml-test. -func TestEncode(t *testing.T) { - type Embedded struct { - Int int `toml:"_int"` - } - type NonStruct int - - date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600)) - dateStr := "2014-05-11T19:30:40Z" - - tests := map[string]struct { - input interface{} - wantOutput string - wantError error - }{ - "bool field": { - input: struct { - BoolTrue bool - BoolFalse bool - }{true, false}, - wantOutput: "BoolTrue = true\nBoolFalse = false\n", - }, - "int fields": { - input: struct { - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - }{1, 2, 3, 4, 5}, - wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n", - }, - "uint fields": { - input: struct { - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - }{1, 2, 3, 4, 5}, - wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" + - "\nUint64 = 5\n", - }, - "float fields": { - input: struct { - Float32 float32 - Float64 float64 - }{1.5, 2.5}, - wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n", - }, - "string field": { - input: struct{ String string }{"foo"}, - wantOutput: "String = \"foo\"\n", - }, - "string field and unexported field": { - input: struct { - String string - unexported int - }{"foo", 0}, - wantOutput: "String = \"foo\"\n", - }, - "datetime field in UTC": { - input: struct{ Date time.Time }{date}, - wantOutput: fmt.Sprintf("Date = %s\n", dateStr), - }, - "datetime field as primitive": { - // Using a map here to fail if isStructOrMap() returns true for - // time.Time. - input: map[string]interface{}{ - "Date": date, - "Int": 1, - }, - wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr), - }, - "array fields": { - input: struct { - IntArray0 [0]int - IntArray3 [3]int - }{[0]int{}, [3]int{1, 2, 3}}, - wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n", - }, - "slice fields": { - input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{ - nil, []int{}, []int{1, 2, 3}, - }, - wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n", - }, - "datetime slices": { - input: struct{ DatetimeSlice []time.Time }{ - []time.Time{date, date}, - }, - wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n", - dateStr, dateStr), - }, - "nested arrays and slices": { - input: struct { - SliceOfArrays [][2]int - ArrayOfSlices [2][]int - SliceOfArraysOfSlices [][2][]int - ArrayOfSlicesOfArrays [2][][2]int - SliceOfMixedArrays [][2]interface{} - ArrayOfMixedSlices [2][]interface{} - }{ - [][2]int{{1, 2}, {3, 4}}, - [2][]int{{1, 2}, {3, 4}}, - [][2][]int{ - { - {1, 2}, {3, 4}, - }, - { - {5, 6}, {7, 8}, - }, - }, - [2][][2]int{ - { - {1, 2}, {3, 4}, - }, - { - {5, 6}, {7, 8}, - }, - }, - [][2]interface{}{ - {1, 2}, {"a", "b"}, - }, - [2][]interface{}{ - {1, 2}, {"a", "b"}, - }, - }, - wantOutput: `SliceOfArrays = [[1, 2], [3, 4]] -ArrayOfSlices = [[1, 2], [3, 4]] -SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] -ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] -SliceOfMixedArrays = [[1, 2], ["a", "b"]] -ArrayOfMixedSlices = [[1, 2], ["a", "b"]] -`, - }, - "empty slice": { - input: struct{ Empty []interface{} }{[]interface{}{}}, - wantOutput: "Empty = []\n", - }, - "(error) slice with element type mismatch (string and integer)": { - input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}}, - wantError: errArrayMixedElementTypes, - }, - "(error) slice with element type mismatch (integer and float)": { - input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}}, - wantError: errArrayMixedElementTypes, - }, - "slice with elems of differing Go types, same TOML types": { - input: struct { - MixedInts []interface{} - MixedFloats []interface{} - }{ - []interface{}{ - int(1), int8(2), int16(3), int32(4), int64(5), - uint(1), uint8(2), uint16(3), uint32(4), uint64(5), - }, - []interface{}{float32(1.5), float64(2.5)}, - }, - wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" + - "MixedFloats = [1.5, 2.5]\n", - }, - "(error) slice w/ element type mismatch (one is nested array)": { - input: struct{ Mixed []interface{} }{ - []interface{}{1, []interface{}{2}}, - }, - wantError: errArrayMixedElementTypes, - }, - "(error) slice with 1 nil element": { - input: struct{ NilElement1 []interface{} }{[]interface{}{nil}}, - wantError: errArrayNilElement, - }, - "(error) slice with 1 nil element (and other non-nil elements)": { - input: struct{ NilElement []interface{} }{ - []interface{}{1, nil}, - }, - wantError: errArrayNilElement, - }, - "simple map": { - input: map[string]int{"a": 1, "b": 2}, - wantOutput: "a = 1\nb = 2\n", - }, - "map with interface{} value type": { - input: map[string]interface{}{"a": 1, "b": "c"}, - wantOutput: "a = 1\nb = \"c\"\n", - }, - "map with interface{} value type, some of which are structs": { - input: map[string]interface{}{ - "a": struct{ Int int }{2}, - "b": 1, - }, - wantOutput: "b = 1\n\n[a]\n Int = 2\n", - }, - "nested map": { - input: map[string]map[string]int{ - "a": {"b": 1}, - "c": {"d": 2}, - }, - wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n", - }, - "nested struct": { - input: struct{ Struct struct{ Int int } }{ - struct{ Int int }{1}, - }, - wantOutput: "[Struct]\n Int = 1\n", - }, - "nested struct and non-struct field": { - input: struct { - Struct struct{ Int int } - Bool bool - }{struct{ Int int }{1}, true}, - wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n", - }, - "2 nested structs": { - input: struct{ Struct1, Struct2 struct{ Int int } }{ - struct{ Int int }{1}, struct{ Int int }{2}, - }, - wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n", - }, - "deeply nested structs": { - input: struct { - Struct1, Struct2 struct{ Struct3 *struct{ Int int } } - }{ - struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}}, - struct{ Struct3 *struct{ Int int } }{nil}, - }, - wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" + - "\n\n[Struct2]\n", - }, - "nested struct with nil struct elem": { - input: struct { - Struct struct{ Inner *struct{ Int int } } - }{ - struct{ Inner *struct{ Int int } }{nil}, - }, - wantOutput: "[Struct]\n", - }, - "nested struct with no fields": { - input: struct { - Struct struct{ Inner struct{} } - }{ - struct{ Inner struct{} }{struct{}{}}, - }, - wantOutput: "[Struct]\n [Struct.Inner]\n", - }, - "struct with tags": { - input: struct { - Struct struct { - Int int `toml:"_int"` - } `toml:"_struct"` - Bool bool `toml:"_bool"` - }{ - struct { - Int int `toml:"_int"` - }{1}, true, - }, - wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n", - }, - "embedded struct": { - input: struct{ Embedded }{Embedded{1}}, - wantOutput: "_int = 1\n", - }, - "embedded *struct": { - input: struct{ *Embedded }{&Embedded{1}}, - wantOutput: "_int = 1\n", - }, - "nested embedded struct": { - input: struct { - Struct struct{ Embedded } `toml:"_struct"` - }{struct{ Embedded }{Embedded{1}}}, - wantOutput: "[_struct]\n _int = 1\n", - }, - "nested embedded *struct": { - input: struct { - Struct struct{ *Embedded } `toml:"_struct"` - }{struct{ *Embedded }{&Embedded{1}}}, - wantOutput: "[_struct]\n _int = 1\n", - }, - "array of tables": { - input: struct { - Structs []*struct{ Int int } `toml:"struct"` - }{ - []*struct{ Int int }{{1}, {3}}, - }, - wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n", - }, - "array of tables order": { - input: map[string]interface{}{ - "map": map[string]interface{}{ - "zero": 5, - "arr": []map[string]int{ - map[string]int{ - "friend": 5, - }, - }, - }, - }, - wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n", - }, - "(error) top-level slice": { - input: []struct{ Int int }{{1}, {2}, {3}}, - wantError: errNoKey, - }, - "(error) slice of slice": { - input: struct { - Slices [][]struct{ Int int } - }{ - [][]struct{ Int int }{{{1}}, {{2}}, {{3}}}, - }, - wantError: errArrayNoTable, - }, - "(error) map no string key": { - input: map[int]string{1: ""}, - wantError: errNonString, - }, - "(error) anonymous non-struct": { - input: struct{ NonStruct }{5}, - wantError: errAnonNonStruct, - }, - "(error) empty key name": { - input: map[string]int{"": 1}, - wantError: errAnything, - }, - "(error) empty map name": { - input: map[string]interface{}{ - "": map[string]int{"v": 1}, - }, - wantError: errAnything, - }, - } - for label, test := range tests { - encodeExpected(t, label, test.input, test.wantOutput, test.wantError) - } -} - -func TestEncodeNestedTableArrays(t *testing.T) { - type song struct { - Name string `toml:"name"` - } - type album struct { - Name string `toml:"name"` - Songs []song `toml:"songs"` - } - type springsteen struct { - Albums []album `toml:"albums"` - } - value := springsteen{ - []album{ - {"Born to Run", - []song{{"Jungleland"}, {"Meeting Across the River"}}}, - {"Born in the USA", - []song{{"Glory Days"}, {"Dancing in the Dark"}}}, - }, - } - expected := `[[albums]] - name = "Born to Run" - - [[albums.songs]] - name = "Jungleland" - - [[albums.songs]] - name = "Meeting Across the River" - -[[albums]] - name = "Born in the USA" - - [[albums.songs]] - name = "Glory Days" - - [[albums.songs]] - name = "Dancing in the Dark" -` - encodeExpected(t, "nested table arrays", value, expected, nil) -} - -func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) { - type Alpha struct { - V int - } - type Beta struct { - V int - } - type Conf struct { - V int - A Alpha - B []Beta - } - - val := Conf{ - V: 1, - A: Alpha{2}, - B: []Beta{{3}}, - } - expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n" - encodeExpected(t, "array hash with normal hash order", val, expected, nil) -} - -func TestEncodeWithOmitEmpty(t *testing.T) { - type simple struct { - User string `toml:"user"` - Pass string `toml:"password,omitempty"` - } - - value := simple{"Testing", ""} - expected := fmt.Sprintf("user = %q\n", value.User) - encodeExpected(t, "simple with omitempty, is empty", value, expected, nil) - value.Pass = "some password" - expected = fmt.Sprintf("user = %q\npassword = %q\n", value.User, value.Pass) - encodeExpected(t, "simple with omitempty, not empty", value, expected, nil) -} - -func TestEncodeWithOmitZero(t *testing.T) { - type simple struct { - Number int `toml:"number,omitzero"` - Real float64 `toml:"real,omitzero"` - Unsigned uint `toml:"unsigned,omitzero"` - } - - value := simple{0, 0.0, uint(0)} - expected := "" - - encodeExpected(t, "simple with omitzero, all zero", value, expected, nil) - - value.Number = 10 - value.Real = 20 - value.Unsigned = 5 - expected = `number = 10 -real = 20.0 -unsigned = 5 -` - encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil) -} - -func encodeExpected( - t *testing.T, label string, val interface{}, wantStr string, wantErr error, -) { - var buf bytes.Buffer - enc := NewEncoder(&buf) - err := enc.Encode(val) - if err != wantErr { - if wantErr != nil { - if wantErr == errAnything && err != nil { - return - } - t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err) - } else { - t.Errorf("%s: Encode failed: %s", label, err) - } - } - if err != nil { - return - } - if got := buf.String(); wantStr != got { - t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n", - label, wantStr, got) - } -} - -func ExampleEncoder_Encode() { - date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC") - var config = map[string]interface{}{ - "date": date, - "counts": []int{1, 1, 2, 3, 5, 8}, - "hash": map[string]string{ - "key1": "val1", - "key2": "val2", - }, - } - buf := new(bytes.Buffer) - if err := NewEncoder(buf).Encode(config); err != nil { - log.Fatal(err) - } - fmt.Println(buf.String()) - - // Output: - // counts = [1, 1, 2, 3, 5, 8] - // date = 2010-03-14T18:00:00Z - // - // [hash] - // key1 = "val1" - // key2 = "val2" -} diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go index 219122857e3..6dee7fc7925 100644 --- a/vendor/github.com/BurntSushi/toml/lex.go +++ b/vendor/github.com/BurntSushi/toml/lex.go @@ -3,6 +3,7 @@ package toml import ( "fmt" "strings" + "unicode" "unicode/utf8" ) @@ -29,24 +30,28 @@ const ( itemArrayTableEnd itemKeyStart itemCommentStart + itemInlineTableStart + itemInlineTableEnd ) const ( - eof = 0 - tableStart = '[' - tableEnd = ']' - arrayTableStart = '[' - arrayTableEnd = ']' - tableSep = '.' - keySep = '=' - arrayStart = '[' - arrayEnd = ']' - arrayValTerm = ',' - commentStart = '#' - stringStart = '"' - stringEnd = '"' - rawStringStart = '\'' - rawStringEnd = '\'' + eof = 0 + comma = ',' + tableStart = '[' + tableEnd = ']' + arrayTableStart = '[' + arrayTableEnd = ']' + tableSep = '.' + keySep = '=' + arrayStart = '[' + arrayEnd = ']' + commentStart = '#' + stringStart = '"' + stringEnd = '"' + rawStringStart = '\'' + rawStringEnd = '\'' + inlineTableStart = '{' + inlineTableEnd = '}' ) type stateFn func(lx *lexer) stateFn @@ -55,11 +60,18 @@ type lexer struct { input string start int pos int - width int line int state stateFn items chan item + // Allow for backing up up to three runes. + // This is necessary because TOML contains 3-rune tokens (""" and '''). + prevWidths [3]int + nprev int // how many of prevWidths are in use + // If we emit an eof, we can still back up, but it is not OK to call + // next again. + atEOF bool + // A stack of state functions used to maintain context. // The idea is to reuse parts of the state machine in various places. // For example, values can appear at the top level or within arbitrarily @@ -87,7 +99,7 @@ func (lx *lexer) nextItem() item { func lex(input string) *lexer { lx := &lexer{ - input: input + "\n", + input: input, state: lexTop, line: 1, items: make(chan item, 10), @@ -102,7 +114,7 @@ func (lx *lexer) push(state stateFn) { func (lx *lexer) pop() stateFn { if len(lx.stack) == 0 { - return lx.errorf("BUG in lexer: no states to pop.") + return lx.errorf("BUG in lexer: no states to pop") } last := lx.stack[len(lx.stack)-1] lx.stack = lx.stack[0 : len(lx.stack)-1] @@ -124,16 +136,25 @@ func (lx *lexer) emitTrim(typ itemType) { } func (lx *lexer) next() (r rune) { + if lx.atEOF { + panic("next called after EOF") + } if lx.pos >= len(lx.input) { - lx.width = 0 + lx.atEOF = true return eof } if lx.input[lx.pos] == '\n' { lx.line++ } - r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:]) - lx.pos += lx.width + lx.prevWidths[2] = lx.prevWidths[1] + lx.prevWidths[1] = lx.prevWidths[0] + if lx.nprev < 3 { + lx.nprev++ + } + r, w := utf8.DecodeRuneInString(lx.input[lx.pos:]) + lx.prevWidths[0] = w + lx.pos += w return r } @@ -142,9 +163,20 @@ func (lx *lexer) ignore() { lx.start = lx.pos } -// backup steps back one rune. Can be called only once per call of next. +// backup steps back one rune. Can be called only twice between calls to next. func (lx *lexer) backup() { - lx.pos -= lx.width + if lx.atEOF { + lx.atEOF = false + return + } + if lx.nprev < 1 { + panic("backed up too far") + } + w := lx.prevWidths[0] + lx.prevWidths[0] = lx.prevWidths[1] + lx.prevWidths[1] = lx.prevWidths[2] + lx.nprev-- + lx.pos -= w if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { lx.line-- } @@ -166,9 +198,22 @@ func (lx *lexer) peek() rune { return r } +// skip ignores all input that matches the given predicate. +func (lx *lexer) skip(pred func(rune) bool) { + for { + r := lx.next() + if pred(r) { + continue + } + lx.backup() + lx.ignore() + return + } +} + // errorf stops all lexing by emitting an error and returning `nil`. // Note that any value that is a character is escaped if it's a special -// character (new lines, tabs, etc.). +// character (newlines, tabs, etc.). func (lx *lexer) errorf(format string, values ...interface{}) stateFn { lx.items <- item{ itemError, @@ -184,7 +229,6 @@ func lexTop(lx *lexer) stateFn { if isWhitespace(r) || isNL(r) { return lexSkip(lx, lexTop) } - switch r { case commentStart: lx.push(lexTop) @@ -193,7 +237,7 @@ func lexTop(lx *lexer) stateFn { return lexTableStart case eof: if lx.pos > lx.start { - return lx.errorf("Unexpected EOF.") + return lx.errorf("unexpected EOF") } lx.emit(itemEOF) return nil @@ -208,12 +252,12 @@ func lexTop(lx *lexer) stateFn { // lexTopEnd is entered whenever a top-level item has been consumed. (A value // or a table.) It must see only whitespace, and will turn back to lexTop -// upon a new line. If it sees EOF, it will quit the lexer successfully. +// upon a newline. If it sees EOF, it will quit the lexer successfully. func lexTopEnd(lx *lexer) stateFn { r := lx.next() switch { case r == commentStart: - // a comment will read to a new line for us. + // a comment will read to a newline for us. lx.push(lexTop) return lexCommentStart case isWhitespace(r): @@ -222,11 +266,11 @@ func lexTopEnd(lx *lexer) stateFn { lx.ignore() return lexTop case r == eof: - lx.ignore() - return lexTop + lx.emit(itemEOF) + return nil } - return lx.errorf("Expected a top-level item to end with a new line, "+ - "comment or EOF, but got %q instead.", r) + return lx.errorf("expected a top-level item to end with a newline, "+ + "comment, or EOF, but got %q instead", r) } // lexTable lexes the beginning of a table. Namely, it makes sure that @@ -253,50 +297,47 @@ func lexTableEnd(lx *lexer) stateFn { func lexArrayTableEnd(lx *lexer) stateFn { if r := lx.next(); r != arrayTableEnd { - return lx.errorf("Expected end of table array name delimiter %q, "+ - "but got %q instead.", arrayTableEnd, r) + return lx.errorf("expected end of table array name delimiter %q, "+ + "but got %q instead", arrayTableEnd, r) } lx.emit(itemArrayTableEnd) return lexTopEnd } func lexTableNameStart(lx *lexer) stateFn { + lx.skip(isWhitespace) switch r := lx.peek(); { case r == tableEnd || r == eof: - return lx.errorf("Unexpected end of table name. (Table names cannot " + - "be empty.)") + return lx.errorf("unexpected end of table name " + + "(table names cannot be empty)") case r == tableSep: - return lx.errorf("Unexpected table separator. (Table names cannot " + - "be empty.)") + return lx.errorf("unexpected table separator " + + "(table names cannot be empty)") case r == stringStart || r == rawStringStart: lx.ignore() lx.push(lexTableNameEnd) return lexValue // reuse string lexing - case isWhitespace(r): - return lexTableNameStart default: return lexBareTableName } } -// lexTableName lexes the name of a table. It assumes that at least one +// lexBareTableName lexes the name of a table. It assumes that at least one // valid character for the table has already been read. func lexBareTableName(lx *lexer) stateFn { - switch r := lx.next(); { - case isBareKeyChar(r): + r := lx.next() + if isBareKeyChar(r) { return lexBareTableName - case r == tableSep || r == tableEnd: - lx.backup() - lx.emitTrim(itemText) - return lexTableNameEnd - default: - return lx.errorf("Bare keys cannot contain %q.", r) } + lx.backup() + lx.emit(itemText) + return lexTableNameEnd } // lexTableNameEnd reads the end of a piece of a table name, optionally // consuming whitespace. func lexTableNameEnd(lx *lexer) stateFn { + lx.skip(isWhitespace) switch r := lx.next(); { case isWhitespace(r): return lexTableNameEnd @@ -306,8 +347,8 @@ func lexTableNameEnd(lx *lexer) stateFn { case r == tableEnd: return lx.pop() default: - return lx.errorf("Expected '.' or ']' to end table name, but got %q "+ - "instead.", r) + return lx.errorf("expected '.' or ']' to end table name, "+ + "but got %q instead", r) } } @@ -317,7 +358,7 @@ func lexKeyStart(lx *lexer) stateFn { r := lx.peek() switch { case r == keySep: - return lx.errorf("Unexpected key separator %q.", keySep) + return lx.errorf("unexpected key separator %q", keySep) case isWhitespace(r) || isNL(r): lx.next() return lexSkip(lx, lexKeyStart) @@ -340,14 +381,15 @@ func lexBareKey(lx *lexer) stateFn { case isBareKeyChar(r): return lexBareKey case isWhitespace(r): - lx.emitTrim(itemText) + lx.backup() + lx.emit(itemText) return lexKeyEnd case r == keySep: lx.backup() - lx.emitTrim(itemText) + lx.emit(itemText) return lexKeyEnd default: - return lx.errorf("Bare keys cannot contain %q.", r) + return lx.errorf("bare keys cannot contain %q", r) } } @@ -360,7 +402,7 @@ func lexKeyEnd(lx *lexer) stateFn { case isWhitespace(r): return lexSkip(lx, lexKeyEnd) default: - return lx.errorf("Expected key separator %q, but got %q instead.", + return lx.errorf("expected key separator %q, but got %q instead", keySep, r) } } @@ -369,20 +411,26 @@ func lexKeyEnd(lx *lexer) stateFn { // lexValue will ignore whitespace. // After a value is lexed, the last state on the next is popped and returned. func lexValue(lx *lexer) stateFn { - // We allow whitespace to precede a value, but NOT new lines. - // In array syntax, the array states are responsible for ignoring new - // lines. + // We allow whitespace to precede a value, but NOT newlines. + // In array syntax, the array states are responsible for ignoring newlines. r := lx.next() - if isWhitespace(r) { - return lexSkip(lx, lexValue) - } - switch { - case r == arrayStart: + case isWhitespace(r): + return lexSkip(lx, lexValue) + case isDigit(r): + lx.backup() // avoid an extra state and use the same as above + return lexNumberOrDateStart + } + switch r { + case arrayStart: lx.ignore() lx.emit(itemArray) return lexArrayValue - case r == stringStart: + case inlineTableStart: + lx.ignore() + lx.emit(itemInlineTableStart) + return lexInlineTableValue + case stringStart: if lx.accept(stringStart) { if lx.accept(stringStart) { lx.ignore() // Ignore """ @@ -392,7 +440,7 @@ func lexValue(lx *lexer) stateFn { } lx.ignore() // ignore the '"' return lexString - case r == rawStringStart: + case rawStringStart: if lx.accept(rawStringStart) { if lx.accept(rawStringStart) { lx.ignore() // Ignore """ @@ -402,23 +450,24 @@ func lexValue(lx *lexer) stateFn { } lx.ignore() // ignore the "'" return lexRawString - case r == 't': - return lexTrue - case r == 'f': - return lexFalse - case r == '-': + case '+', '-': return lexNumberStart - case isDigit(r): - lx.backup() // avoid an extra state and use the same as above - return lexNumberOrDateStart - case r == '.': // special error case, be kind to users - return lx.errorf("Floats must start with a digit, not '.'.") + case '.': // special error case, be kind to users + return lx.errorf("floats must start with a digit, not '.'") } - return lx.errorf("Expected value but found %q instead.", r) + if unicode.IsLetter(r) { + // Be permissive here; lexBool will give a nice error if the + // user wrote something like + // x = foo + // (i.e. not 'true' or 'false' but is something else word-like.) + lx.backup() + return lexBool + } + return lx.errorf("expected value but found %q instead", r) } // lexArrayValue consumes one value in an array. It assumes that '[' or ',' -// have already been consumed. All whitespace and new lines are ignored. +// have already been consumed. All whitespace and newlines are ignored. func lexArrayValue(lx *lexer) stateFn { r := lx.next() switch { @@ -427,10 +476,11 @@ func lexArrayValue(lx *lexer) stateFn { case r == commentStart: lx.push(lexArrayValue) return lexCommentStart - case r == arrayValTerm: - return lx.errorf("Unexpected array value terminator %q.", - arrayValTerm) + case r == comma: + return lx.errorf("unexpected comma") case r == arrayEnd: + // NOTE(caleb): The spec isn't clear about whether you can have + // a trailing comma or not, so we'll allow it. return lexArrayEnd } @@ -439,8 +489,9 @@ func lexArrayValue(lx *lexer) stateFn { return lexValue } -// lexArrayValueEnd consumes the cruft between values of an array. Namely, -// it ignores whitespace and expects either a ',' or a ']'. +// lexArrayValueEnd consumes everything between the end of an array value and +// the next value (or the end of the array): it ignores whitespace and newlines +// and expects either a ',' or a ']'. func lexArrayValueEnd(lx *lexer) stateFn { r := lx.next() switch { @@ -449,31 +500,88 @@ func lexArrayValueEnd(lx *lexer) stateFn { case r == commentStart: lx.push(lexArrayValueEnd) return lexCommentStart - case r == arrayValTerm: + case r == comma: lx.ignore() return lexArrayValue // move on to the next value case r == arrayEnd: return lexArrayEnd } - return lx.errorf("Expected an array value terminator %q or an array "+ - "terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r) + return lx.errorf( + "expected a comma or array terminator %q, but got %q instead", + arrayEnd, r, + ) } -// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has -// just been consumed. +// lexArrayEnd finishes the lexing of an array. +// It assumes that a ']' has just been consumed. func lexArrayEnd(lx *lexer) stateFn { lx.ignore() lx.emit(itemArrayEnd) return lx.pop() } +// lexInlineTableValue consumes one key/value pair in an inline table. +// It assumes that '{' or ',' have already been consumed. Whitespace is ignored. +func lexInlineTableValue(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexInlineTableValue) + case isNL(r): + return lx.errorf("newlines not allowed within inline tables") + case r == commentStart: + lx.push(lexInlineTableValue) + return lexCommentStart + case r == comma: + return lx.errorf("unexpected comma") + case r == inlineTableEnd: + return lexInlineTableEnd + } + lx.backup() + lx.push(lexInlineTableValueEnd) + return lexKeyStart +} + +// lexInlineTableValueEnd consumes everything between the end of an inline table +// key/value pair and the next pair (or the end of the table): +// it ignores whitespace and expects either a ',' or a '}'. +func lexInlineTableValueEnd(lx *lexer) stateFn { + r := lx.next() + switch { + case isWhitespace(r): + return lexSkip(lx, lexInlineTableValueEnd) + case isNL(r): + return lx.errorf("newlines not allowed within inline tables") + case r == commentStart: + lx.push(lexInlineTableValueEnd) + return lexCommentStart + case r == comma: + lx.ignore() + return lexInlineTableValue + case r == inlineTableEnd: + return lexInlineTableEnd + } + return lx.errorf("expected a comma or an inline table terminator %q, "+ + "but got %q instead", inlineTableEnd, r) +} + +// lexInlineTableEnd finishes the lexing of an inline table. +// It assumes that a '}' has just been consumed. +func lexInlineTableEnd(lx *lexer) stateFn { + lx.ignore() + lx.emit(itemInlineTableEnd) + return lx.pop() +} + // lexString consumes the inner contents of a string. It assumes that the // beginning '"' has already been consumed and ignored. func lexString(lx *lexer) stateFn { r := lx.next() switch { + case r == eof: + return lx.errorf("unexpected EOF") case isNL(r): - return lx.errorf("Strings cannot contain new lines.") + return lx.errorf("strings cannot contain newlines") case r == '\\': lx.push(lexString) return lexStringEscape @@ -490,11 +598,12 @@ func lexString(lx *lexer) stateFn { // lexMultilineString consumes the inner contents of a string. It assumes that // the beginning '"""' has already been consumed and ignored. func lexMultilineString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == '\\': + switch lx.next() { + case eof: + return lx.errorf("unexpected EOF") + case '\\': return lexMultilineStringEscape - case r == stringEnd: + case stringEnd: if lx.accept(stringEnd) { if lx.accept(stringEnd) { lx.backup() @@ -518,8 +627,10 @@ func lexMultilineString(lx *lexer) stateFn { func lexRawString(lx *lexer) stateFn { r := lx.next() switch { + case r == eof: + return lx.errorf("unexpected EOF") case isNL(r): - return lx.errorf("Strings cannot contain new lines.") + return lx.errorf("strings cannot contain newlines") case r == rawStringEnd: lx.backup() lx.emit(itemRawString) @@ -531,12 +642,13 @@ func lexRawString(lx *lexer) stateFn { } // lexMultilineRawString consumes a raw string. Nothing can be escaped in such -// a string. It assumes that the beginning "'" has already been consumed and +// a string. It assumes that the beginning "'''" has already been consumed and // ignored. func lexMultilineRawString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == rawStringEnd: + switch lx.next() { + case eof: + return lx.errorf("unexpected EOF") + case rawStringEnd: if lx.accept(rawStringEnd) { if lx.accept(rawStringEnd) { lx.backup() @@ -560,13 +672,11 @@ func lexMultilineRawString(lx *lexer) stateFn { func lexMultilineStringEscape(lx *lexer) stateFn { // Handle the special case first: if isNL(lx.next()) { - lx.next() return lexMultilineString - } else { - lx.backup() - lx.push(lexMultilineString) - return lexStringEscape(lx) } + lx.backup() + lx.push(lexMultilineString) + return lexStringEscape(lx) } func lexStringEscape(lx *lexer) stateFn { @@ -591,10 +701,9 @@ func lexStringEscape(lx *lexer) stateFn { case 'U': return lexLongUnicodeEscape } - return lx.errorf("Invalid escape character %q. Only the following "+ + return lx.errorf("invalid escape character %q; only the following "+ "escape characters are allowed: "+ - "\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+ - "\\uXXXX and \\UXXXXXXXX.", r) + `\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r) } func lexShortUnicodeEscape(lx *lexer) stateFn { @@ -602,8 +711,8 @@ func lexShortUnicodeEscape(lx *lexer) stateFn { for i := 0; i < 4; i++ { r = lx.next() if !isHexadecimal(r) { - return lx.errorf("Expected four hexadecimal digits after '\\u', "+ - "but got '%s' instead.", lx.current()) + return lx.errorf(`expected four hexadecimal digits after '\u', `+ + "but got %q instead", lx.current()) } } return lx.pop() @@ -614,40 +723,43 @@ func lexLongUnicodeEscape(lx *lexer) stateFn { for i := 0; i < 8; i++ { r = lx.next() if !isHexadecimal(r) { - return lx.errorf("Expected eight hexadecimal digits after '\\U', "+ - "but got '%s' instead.", lx.current()) + return lx.errorf(`expected eight hexadecimal digits after '\U', `+ + "but got %q instead", lx.current()) } } return lx.pop() } -// lexNumberOrDateStart consumes either a (positive) integer, float or -// datetime. It assumes that NO negative sign has been consumed. +// lexNumberOrDateStart consumes either an integer, a float, or datetime. func lexNumberOrDateStart(lx *lexer) stateFn { r := lx.next() - if !isDigit(r) { - if r == '.' { - return lx.errorf("Floats must start with a digit, not '.'.") - } else { - return lx.errorf("Expected a digit but got %q.", r) - } + if isDigit(r) { + return lexNumberOrDate } - return lexNumberOrDate + switch r { + case '_': + return lexNumber + case 'e', 'E': + return lexFloat + case '.': + return lx.errorf("floats must start with a digit, not '.'") + } + return lx.errorf("expected a digit but got %q", r) } -// lexNumberOrDate consumes either a (positive) integer, float or datetime. +// lexNumberOrDate consumes either an integer, float or datetime. func lexNumberOrDate(lx *lexer) stateFn { r := lx.next() - switch { - case r == '-': - if lx.pos-lx.start != 5 { - return lx.errorf("All ISO8601 dates must be in full Zulu form.") - } - return lexDateAfterYear - case isDigit(r): + if isDigit(r) { return lexNumberOrDate - case r == '.': - return lexFloatStart + } + switch r { + case '-': + return lexDatetime + case '_': + return lexNumber + case '.', 'e', 'E': + return lexFloat } lx.backup() @@ -655,46 +767,34 @@ func lexNumberOrDate(lx *lexer) stateFn { return lx.pop() } -// lexDateAfterYear consumes a full Zulu Datetime in ISO8601 format. -// It assumes that "YYYY-" has already been consumed. -func lexDateAfterYear(lx *lexer) stateFn { - formats := []rune{ - // digits are '0'. - // everything else is direct equality. - '0', '0', '-', '0', '0', - 'T', - '0', '0', ':', '0', '0', ':', '0', '0', - 'Z', +// lexDatetime consumes a Datetime, to a first approximation. +// The parser validates that it matches one of the accepted formats. +func lexDatetime(lx *lexer) stateFn { + r := lx.next() + if isDigit(r) { + return lexDatetime } - for _, f := range formats { - r := lx.next() - if f == '0' { - if !isDigit(r) { - return lx.errorf("Expected digit in ISO8601 datetime, "+ - "but found %q instead.", r) - } - } else if f != r { - return lx.errorf("Expected %q in ISO8601 datetime, "+ - "but found %q instead.", f, r) - } + switch r { + case '-', 'T', ':', '.', 'Z': + return lexDatetime } + + lx.backup() lx.emit(itemDatetime) return lx.pop() } -// lexNumberStart consumes either an integer or a float. It assumes that -// a negative sign has already been read, but that *no* digits have been -// consumed. lexNumberStart will move to the appropriate integer or float -// states. +// lexNumberStart consumes either an integer or a float. It assumes that a sign +// has already been read, but that *no* digits have been consumed. +// lexNumberStart will move to the appropriate integer or float states. func lexNumberStart(lx *lexer) stateFn { - // we MUST see a digit. Even floats have to start with a digit. + // We MUST see a digit. Even floats have to start with a digit. r := lx.next() if !isDigit(r) { if r == '.' { - return lx.errorf("Floats must start with a digit, not '.'.") - } else { - return lx.errorf("Expected a digit but got %q.", r) + return lx.errorf("floats must start with a digit, not '.'") } + return lx.errorf("expected a digit but got %q", r) } return lexNumber } @@ -702,11 +802,14 @@ func lexNumberStart(lx *lexer) stateFn { // lexNumber consumes an integer or a float after seeing the first digit. func lexNumber(lx *lexer) stateFn { r := lx.next() - switch { - case isDigit(r): + if isDigit(r) { return lexNumber - case r == '.': - return lexFloatStart + } + switch r { + case '_': + return lexNumber + case '.', 'e', 'E': + return lexFloat } lx.backup() @@ -714,60 +817,42 @@ func lexNumber(lx *lexer) stateFn { return lx.pop() } -// lexFloatStart starts the consumption of digits of a float after a '.'. -// Namely, at least one digit is required. -func lexFloatStart(lx *lexer) stateFn { - r := lx.next() - if !isDigit(r) { - return lx.errorf("Floats must have a digit after the '.', but got "+ - "%q instead.", r) - } - return lexFloat -} - -// lexFloat consumes the digits of a float after a '.'. -// Assumes that one digit has been consumed after a '.' already. +// lexFloat consumes the elements of a float. It allows any sequence of +// float-like characters, so floats emitted by the lexer are only a first +// approximation and must be validated by the parser. func lexFloat(lx *lexer) stateFn { r := lx.next() if isDigit(r) { return lexFloat } + switch r { + case '_', '.', '-', '+', 'e', 'E': + return lexFloat + } lx.backup() lx.emit(itemFloat) return lx.pop() } -// lexConst consumes the s[1:] in s. It assumes that s[0] has already been -// consumed. -func lexConst(lx *lexer, s string) stateFn { - for i := range s[1:] { - if r := lx.next(); r != rune(s[i+1]) { - return lx.errorf("Expected %q, but found %q instead.", s[:i+1], - s[:i]+string(r)) +// lexBool consumes a bool string: 'true' or 'false. +func lexBool(lx *lexer) stateFn { + var rs []rune + for { + r := lx.next() + if !unicode.IsLetter(r) { + lx.backup() + break } + rs = append(rs, r) } - return nil -} - -// lexTrue consumes the "rue" in "true". It assumes that 't' has already -// been consumed. -func lexTrue(lx *lexer) stateFn { - if fn := lexConst(lx, "true"); fn != nil { - return fn + s := string(rs) + switch s { + case "true", "false": + lx.emit(itemBool) + return lx.pop() } - lx.emit(itemBool) - return lx.pop() -} - -// lexFalse consumes the "alse" in "false". It assumes that 'f' has already -// been consumed. -func lexFalse(lx *lexer) stateFn { - if fn := lexConst(lx, "false"); fn != nil { - return fn - } - lx.emit(itemBool) - return lx.pop() + return lx.errorf("expected value but found %q instead", s) } // lexCommentStart begins the lexing of a comment. It will emit @@ -779,7 +864,7 @@ func lexCommentStart(lx *lexer) stateFn { } // lexComment lexes an entire comment. It assumes that '#' has been consumed. -// It will consume *up to* the first new line character, and pass control +// It will consume *up to* the first newline character, and pass control // back to the last state on the stack. func lexComment(lx *lexer) stateFn { r := lx.peek() @@ -837,13 +922,7 @@ func (itype itemType) String() string { return "EOF" case itemText: return "Text" - case itemString: - return "String" - case itemRawString: - return "String" - case itemMultilineString: - return "String" - case itemRawMultilineString: + case itemString, itemRawString, itemMultilineString, itemRawMultilineString: return "String" case itemBool: return "Bool" diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go index c6069be1f17..50869ef9266 100644 --- a/vendor/github.com/BurntSushi/toml/parse.go +++ b/vendor/github.com/BurntSushi/toml/parse.go @@ -2,7 +2,6 @@ package toml import ( "fmt" - "log" "strconv" "strings" "time" @@ -81,7 +80,7 @@ func (p *parser) next() item { } func (p *parser) bug(format string, v ...interface{}) { - log.Fatalf("BUG: %s\n\n", fmt.Sprintf(format, v...)) + panic(fmt.Sprintf("BUG: "+format+"\n\n", v...)) } func (p *parser) expect(typ itemType) item { @@ -179,10 +178,18 @@ func (p *parser) value(it item) (interface{}, tomlType) { } p.bug("Expected boolean value, but got '%s'.", it.val) case itemInteger: - num, err := strconv.ParseInt(it.val, 10, 64) + if !numUnderscoresOK(it.val) { + p.panicf("Invalid integer %q: underscores must be surrounded by digits", + it.val) + } + val := strings.Replace(it.val, "_", "", -1) + num, err := strconv.ParseInt(val, 10, 64) if err != nil { - // See comment below for floats describing why we make a - // distinction between a bug and a user error. + // Distinguish integer values. Normally, it'd be a bug if the lexer + // provides an invalid integer, but it's possible that the number is + // out of range of valid values (which the lexer cannot determine). + // So mark the former as a bug but the latter as a legitimate user + // error. if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { @@ -194,29 +201,57 @@ func (p *parser) value(it item) (interface{}, tomlType) { } return num, p.typeOfPrimitive(it) case itemFloat: - num, err := strconv.ParseFloat(it.val, 64) + parts := strings.FieldsFunc(it.val, func(r rune) bool { + switch r { + case '.', 'e', 'E': + return true + } + return false + }) + for _, part := range parts { + if !numUnderscoresOK(part) { + p.panicf("Invalid float %q: underscores must be "+ + "surrounded by digits", it.val) + } + } + if !numPeriodsOK(it.val) { + // As a special case, numbers like '123.' or '1.e2', + // which are valid as far as Go/strconv are concerned, + // must be rejected because TOML says that a fractional + // part consists of '.' followed by 1+ digits. + p.panicf("Invalid float %q: '.' must be followed "+ + "by one or more digits", it.val) + } + val := strings.Replace(it.val, "_", "", -1) + num, err := strconv.ParseFloat(val, 64) if err != nil { - // Distinguish float values. Normally, it'd be a bug if the lexer - // provides an invalid float, but it's possible that the float is - // out of range of valid values (which the lexer cannot determine). - // So mark the former as a bug but the latter as a legitimate user - // error. - // - // This is also true for integers. if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { p.panicf("Float '%s' is out of the range of 64-bit "+ "IEEE-754 floating-point numbers.", it.val) } else { - p.bug("Expected float value, but got '%s'.", it.val) + p.panicf("Invalid float value: %q", it.val) } } return num, p.typeOfPrimitive(it) case itemDatetime: - t, err := time.Parse("2006-01-02T15:04:05Z", it.val) - if err != nil { - p.bug("Expected Zulu formatted DateTime, but got '%s'.", it.val) + var t time.Time + var ok bool + var err error + for _, format := range []string{ + "2006-01-02T15:04:05Z07:00", + "2006-01-02T15:04:05", + "2006-01-02", + } { + t, err = time.ParseInLocation(format, it.val, time.Local) + if err == nil { + ok = true + break + } + } + if !ok { + p.panicf("Invalid TOML Datetime: %q.", it.val) } return t, p.typeOfPrimitive(it) case itemArray: @@ -234,11 +269,75 @@ func (p *parser) value(it item) (interface{}, tomlType) { types = append(types, typ) } return array, p.typeOfArray(types) + case itemInlineTableStart: + var ( + hash = make(map[string]interface{}) + outerContext = p.context + outerKey = p.currentKey + ) + + p.context = append(p.context, p.currentKey) + p.currentKey = "" + for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() { + if it.typ != itemKeyStart { + p.bug("Expected key start but instead found %q, around line %d", + it.val, p.approxLine) + } + if it.typ == itemCommentStart { + p.expect(itemText) + continue + } + + // retrieve key + k := p.next() + p.approxLine = k.line + kname := p.keyString(k) + + // retrieve value + p.currentKey = kname + val, typ := p.value(p.next()) + // make sure we keep metadata up to date + p.setType(kname, typ) + p.ordered = append(p.ordered, p.context.add(p.currentKey)) + hash[kname] = val + } + p.context = outerContext + p.currentKey = outerKey + return hash, tomlHash } p.bug("Unexpected value type: %s", it.typ) panic("unreachable") } +// numUnderscoresOK checks whether each underscore in s is surrounded by +// characters that are not underscores. +func numUnderscoresOK(s string) bool { + accept := false + for _, r := range s { + if r == '_' { + if !accept { + return false + } + accept = false + continue + } + accept = true + } + return accept +} + +// numPeriodsOK checks whether every period in s is followed by a digit. +func numPeriodsOK(s string) bool { + period := false + for _, r := range s { + if period && !isDigit(r) { + return false + } + period = r == '.' + } + return !period +} + // establishContext sets the current context of the parser, // where the context is either a hash or an array of hashes. Which one is // set depends on the value of the `array` parameter. @@ -401,7 +500,7 @@ func stripFirstNewline(s string) string { if len(s) == 0 || s[0] != '\n' { return s } - return s[1:len(s)] + return s[1:] } func stripEscapedWhitespace(s string) string { @@ -481,12 +580,7 @@ func (p *parser) asciiEscapeToUnicode(bs []byte) rune { p.bug("Could not parse '%s' as a hexadecimal number, but the "+ "lexer claims it's OK: %s", s, err) } - - // BUG(burntsushi) - // I honestly don't understand how this works. I can't seem - // to find a way to make this fail. I figured this would fail on invalid - // UTF-8 characters like U+DCFF, but it doesn't. - if !utf8.ValidString(string(rune(hex))) { + if !utf8.ValidRune(rune(hex)) { p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s) } return rune(hex) diff --git a/vendor/github.com/BurntSushi/toml/session.vim b/vendor/github.com/BurntSushi/toml/session.vim deleted file mode 100644 index 562164be060..00000000000 --- a/vendor/github.com/BurntSushi/toml/session.vim +++ /dev/null @@ -1 +0,0 @@ -au BufWritePost *.go silent!make tags > /dev/null 2>&1 diff --git a/vendor/github.com/BurntSushi/toml/type_fields.go b/vendor/github.com/BurntSushi/toml/type_fields.go index 7592f87a454..608997c22f6 100644 --- a/vendor/github.com/BurntSushi/toml/type_fields.go +++ b/vendor/github.com/BurntSushi/toml/type_fields.go @@ -92,11 +92,11 @@ func typeFields(t reflect.Type) []field { // Scan f.typ for fields to include. for i := 0; i < f.typ.NumField(); i++ { sf := f.typ.Field(i) - if sf.PkgPath != "" { // unexported + if sf.PkgPath != "" && !sf.Anonymous { // unexported continue } - name := sf.Tag.Get("toml") - if name == "-" { + opts := getOptions(sf.Tag) + if opts.skip { continue } index := make([]int, len(f.index)+1) @@ -110,8 +110,9 @@ func typeFields(t reflect.Type) []field { } // Record found field and index sequence. - if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { - tagged := name != "" + if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { + tagged := opts.name != "" + name := opts.name if name == "" { name = sf.Name } diff --git a/vendor/github.com/Unknwon/com/README.md b/vendor/github.com/Unknwon/com/README.md deleted file mode 100644 index 8d821abd65e..00000000000 --- a/vendor/github.com/Unknwon/com/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Common Functions -================ - -[![Build Status](https://travis-ci.org/Unknwon/com.svg)](https://travis-ci.org/Unknwon/com) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/Unknwon/com) - -This is an open source project for commonly used functions for the Go programming language. - -This package need >= **go 1.2** - -Code Convention: based on [Go Code Convention](https://github.com/Unknwon/go-code-convention). - -## Contribute - -Your contribute is welcome, but you have to check following steps after you added some functions and commit them: - -1. Make sure you wrote user-friendly comments for **all functions** . -2. Make sure you wrote test cases with any possible condition for **all functions** in file `*_test.go`. -3. Make sure you wrote benchmarks for **all functions** in file `*_test.go`. -4. Make sure you wrote useful examples for **all functions** in file `example_test.go`. -5. Make sure you ran `go test` and got **PASS** . diff --git a/vendor/github.com/Unknwon/com/convert.go b/vendor/github.com/Unknwon/com/convert.go index 25b3e0e5620..bf24aa8bc30 100644 --- a/vendor/github.com/Unknwon/com/convert.go +++ b/vendor/github.com/Unknwon/com/convert.go @@ -41,6 +41,11 @@ func (f StrTo) Int64() (int64, error) { return int64(v), err } +func (f StrTo) Float64() (float64, error) { + v, err := strconv.ParseFloat(f.String(), 64) + return float64(v), err +} + func (f StrTo) MustUint8() uint8 { v, _ := f.Uint8() return v @@ -56,6 +61,11 @@ func (f StrTo) MustInt64() int64 { return v } +func (f StrTo) MustFloat64() float64 { + v, _ := f.Float64() + return v +} + func (f StrTo) String() string { if f.Exist() { return string(f) diff --git a/vendor/github.com/Unknwon/com/testdata/SaveFile.txt b/vendor/github.com/Unknwon/com/testdata/SaveFile.txt deleted file mode 100644 index 0547fc82637..00000000000 --- a/vendor/github.com/Unknwon/com/testdata/SaveFile.txt +++ /dev/null @@ -1 +0,0 @@ -TestSaveFile \ No newline at end of file diff --git a/vendor/github.com/Unknwon/com/testdata/SaveFileS.txt b/vendor/github.com/Unknwon/com/testdata/SaveFileS.txt deleted file mode 100644 index dfc332539f7..00000000000 --- a/vendor/github.com/Unknwon/com/testdata/SaveFileS.txt +++ /dev/null @@ -1 +0,0 @@ -TestSaveFileS \ No newline at end of file diff --git a/vendor/github.com/Unknwon/com/testdata/sample_file.txt b/vendor/github.com/Unknwon/com/testdata/sample_file.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vendor/github.com/Unknwon/com/testdata/statDir/SaveFile.txt b/vendor/github.com/Unknwon/com/testdata/statDir/SaveFile.txt deleted file mode 100644 index 0547fc82637..00000000000 --- a/vendor/github.com/Unknwon/com/testdata/statDir/SaveFile.txt +++ /dev/null @@ -1 +0,0 @@ -TestSaveFile \ No newline at end of file diff --git a/vendor/github.com/Unknwon/com/testdata/statDir/SaveFileS.txt b/vendor/github.com/Unknwon/com/testdata/statDir/SaveFileS.txt deleted file mode 100644 index dfc332539f7..00000000000 --- a/vendor/github.com/Unknwon/com/testdata/statDir/SaveFileS.txt +++ /dev/null @@ -1 +0,0 @@ -TestSaveFileS \ No newline at end of file diff --git a/vendor/github.com/Unknwon/com/testdata/statDir/sample_file.txt b/vendor/github.com/Unknwon/com/testdata/statDir/sample_file.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/SaveFile.txt b/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/SaveFile.txt deleted file mode 100644 index 0547fc82637..00000000000 --- a/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/SaveFile.txt +++ /dev/null @@ -1 +0,0 @@ -TestSaveFile \ No newline at end of file diff --git a/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/SaveFileS.txt b/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/SaveFileS.txt deleted file mode 100644 index dfc332539f7..00000000000 --- a/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/SaveFileS.txt +++ /dev/null @@ -1 +0,0 @@ -TestSaveFileS \ No newline at end of file diff --git a/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/sample_file.txt b/vendor/github.com/Unknwon/com/testdata/statDir/secondLevel/sample_file.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vendor/github.com/apache/thrift/contrib/fb303/LICENSE b/vendor/github.com/apache/thrift/contrib/fb303/LICENSE new file mode 100644 index 00000000000..4eacb643179 --- /dev/null +++ b/vendor/github.com/apache/thrift/contrib/fb303/LICENSE @@ -0,0 +1,16 @@ +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. diff --git a/vendor/github.com/apache/thrift/debian/copyright b/vendor/github.com/apache/thrift/debian/copyright new file mode 100644 index 00000000000..850643c9aa4 --- /dev/null +++ b/vendor/github.com/apache/thrift/debian/copyright @@ -0,0 +1,129 @@ +This package was debianized by Thrift Developer's . + + +This package and the Debian packaging is licensed under the Apache License, +see `/usr/share/common-licenses/Apache-2.0'. + +The following information was copied from Apache Thrift LICENSE file. + +-------------------------------------------------- +SOFTWARE DISTRIBUTED WITH THRIFT: + +The Apache Thrift software includes a number of subcomponents with +separate copyright notices and license terms. Your use of the source +code for the these subcomponents is subject to the terms and +conditions of the following licenses. + +-------------------------------------------------- +Portions of the following files are licensed under the MIT License: + + lib/erl/src/Makefile.am + +Please see doc/otp-base-license.txt for the full terms of this license. + + +-------------------------------------------------- +The following files contain some portions of code contributed under +the Thrift Software License (see doc/old-thrift-license.txt), and relicensed +under the Apache 2.0 License: + + compiler/cpp/Makefile.am + compiler/cpp/src/generate/t_cocoa_generator.cc + compiler/cpp/src/generate/t_cpp_generator.cc + compiler/cpp/src/generate/t_csharp_generator.cc + compiler/cpp/src/generate/t_erl_generator.cc + compiler/cpp/src/generate/t_hs_generator.cc + compiler/cpp/src/generate/t_java_generator.cc + compiler/cpp/src/generate/t_ocaml_generator.cc + compiler/cpp/src/generate/t_perl_generator.cc + compiler/cpp/src/generate/t_php_generator.cc + compiler/cpp/src/generate/t_py_generator.cc + compiler/cpp/src/generate/t_rb_generator.cc + compiler/cpp/src/generate/t_st_generator.cc + compiler/cpp/src/generate/t_xsd_generator.cc + compiler/cpp/src/main.cc + compiler/cpp/src/parse/t_field.h + compiler/cpp/src/parse/t_program.h + compiler/cpp/src/platform.h + compiler/cpp/src/thriftl.ll + compiler/cpp/src/thrifty.yy + lib/csharp/src/Protocol/TBinaryProtocol.cs + lib/csharp/src/Protocol/TField.cs + lib/csharp/src/Protocol/TList.cs + lib/csharp/src/Protocol/TMap.cs + lib/csharp/src/Protocol/TMessage.cs + lib/csharp/src/Protocol/TMessageType.cs + lib/csharp/src/Protocol/TProtocol.cs + lib/csharp/src/Protocol/TProtocolException.cs + lib/csharp/src/Protocol/TProtocolFactory.cs + lib/csharp/src/Protocol/TProtocolUtil.cs + lib/csharp/src/Protocol/TSet.cs + lib/csharp/src/Protocol/TStruct.cs + lib/csharp/src/Protocol/TType.cs + lib/csharp/src/Server/TServer.cs + lib/csharp/src/Server/TSimpleServer.cs + lib/csharp/src/Server/TThreadPoolServer.cs + lib/csharp/src/TApplicationException.cs + lib/csharp/src/Thrift.csproj + lib/csharp/src/Thrift.sln + lib/csharp/src/TProcessor.cs + lib/csharp/src/Transport/TServerSocket.cs + lib/csharp/src/Transport/TServerTransport.cs + lib/csharp/src/Transport/TSocket.cs + lib/csharp/src/Transport/TStreamTransport.cs + lib/csharp/src/Transport/TTransport.cs + lib/csharp/src/Transport/TTransportException.cs + lib/csharp/src/Transport/TTransportFactory.cs + lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs + lib/csharp/ThriftMSBuildTask/ThriftBuild.cs + lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj + lib/rb/lib/thrift.rb + lib/st/README + lib/st/thrift.st + test/OptionalRequiredTest.cpp + test/OptionalRequiredTest.thrift + test/ThriftTest.thrift + +-------------------------------------------------- +For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components: + +# Copyright (c) 2007 Thomas Porschberg +# +# Copying and distribution of this file, with or without +# modification, are permitted in any medium without royalty provided +# the copyright notice and this notice are preserved. + +-------------------------------------------------- +For the compiler/cpp/src/md5.[ch] components: + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +--------------------------------------------------- +For the lib/rb/setup.rb: Copyright (c) 2000-2005 Minero Aoki, +lib/ocaml/OCamlMakefile and lib/ocaml/README-OCamlMakefile components: + Copyright (C) 1999 - 2007 Markus Mottl + +Licensed under the terms of the GNU Lesser General Public License 2.1 +(see doc/lgpl-2.1.txt for the full terms of this license) diff --git a/vendor/github.com/apache/thrift/lib/dart/LICENSE_HEADER b/vendor/github.com/apache/thrift/lib/dart/LICENSE_HEADER new file mode 100644 index 00000000000..4eacb643179 --- /dev/null +++ b/vendor/github.com/apache/thrift/lib/dart/LICENSE_HEADER @@ -0,0 +1,16 @@ +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. diff --git a/vendor/github.com/apache/thrift/lib/hs/LICENSE b/vendor/github.com/apache/thrift/lib/hs/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/vendor/github.com/apache/thrift/lib/hs/LICENSE @@ -0,0 +1,202 @@ + + 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. diff --git a/vendor/github.com/apache/thrift/tutorial/erl/client.sh b/vendor/github.com/apache/thrift/tutorial/erl/client.sh new file mode 120000 index 00000000000..a417e0da984 --- /dev/null +++ b/vendor/github.com/apache/thrift/tutorial/erl/client.sh @@ -0,0 +1 @@ +server.sh \ No newline at end of file diff --git a/vendor/github.com/aws/aws-sdk-go/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go/CHANGELOG.md deleted file mode 100644 index 5e57ef2ece2..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/CHANGELOG.md +++ /dev/null @@ -1,1536 +0,0 @@ -Release v1.10.18 (2017-07-27) -=== - -### Service Client Updates -* `service/ec2`: Updates service API and documentation - * The CreateDefaultVPC API enables you to create a new default VPC . You no longer need to contact AWS support, if your default VPC has been deleted. -* `service/kinesisanalytics`: Updates service API and documentation - * Added additional exception types and clarified documentation. - -Release v1.10.17 (2017-07-27) -=== - -### Service Client Updates -* `service/dynamodb`: Updates service documentation and examples - * Corrected a typo. -* `service/ec2`: Updates service API and documentation - * Amazon EC2 Elastic GPUs allow you to easily attach low-cost graphics acceleration to current generation EC2 instances. With Amazon EC2 Elastic GPUs, you can configure the right amount of graphics acceleration to your particular workload without being constrained by fixed hardware configurations and limited GPU selection. -* `service/monitoring`: Updates service documentation - * This release adds high resolution features to CloudWatch, with support for Custom Metrics down to 1 second and Alarms down to 10 seconds. - -Release v1.10.16 (2017-07-26) -=== - -### Service Client Updates -* `service/clouddirectory`: Updates service API and documentation - * Cloud Directory adds support for additional batch operations. -* `service/cloudformation`: Updates service API and documentation - * AWS CloudFormation StackSets enables you to manage stacks across multiple accounts and regions. - -### SDK Enhancements -* `aws/signer/v4`: Optimize V4 signer's header duplicate space stripping. [#1417](https://github.com/aws/aws-sdk-go/pull/1417) - -Release v1.10.15 (2017-07-24) -=== - -### Service Client Updates -* `service/appstream`: Updates service API, documentation, and waiters - * Amazon AppStream 2.0 image builders and fleets can now access applications and network resources that rely on Microsoft Active Directory (AD) for authentication and permissions. This new feature allows you to join your streaming instances to your AD, so you can use your existing AD user management tools. -* `service/ec2`: Updates service API and documentation - * Spot Fleet tagging capability allows customers to automatically tag instances launched by Spot Fleet. You can use this feature to label or distinguish instances created by distinct Spot Fleets. Tagging your EC2 instances also enables you to see instance cost allocation by tag in your AWS bill. - -### SDK Bugs -* `aws/signer/v4`: Fix out of bounds panic in stripExcessSpaces [#1412](https://github.com/aws/aws-sdk-go/pull/1412) - * Fixes the out of bands panic in stripExcessSpaces caused by an incorrect calculation of the stripToIdx value. Simplified to code also. - * Fixes [#1411](https://github.com/aws/aws-sdk-go/issues/1411) -Release v1.10.14 (2017-07-20) -=== - -### Service Client Updates -* `service/elasticmapreduce`: Updates service API and documentation - * Amazon EMR now includes the ability to use a custom Amazon Linux AMI and adjustable root volume size when launching a cluster. - -Release v1.10.13 (2017-07-19) -=== - -### Service Client Updates -* `service/budgets`: Updates service API and documentation - * Update budget Management API's to list/create/update RI_UTILIZATION type budget. Update budget Management API's to support DAILY timeUnit for RI_UTILIZATION type budget. - -### SDK Enhancements -* `service/s3`: Use interfaces assertions instead of ValuesAtPath for S3 field lookups. [#1401](https://github.com/aws/aws-sdk-go/pull/1401) - * Improves the performance across the board for all S3 API calls by removing the usage of `ValuesAtPath` being used for every S3 API call. - -### SDK Bugs -* `aws/request`: waiter test bug - * waiters_test.go file would sometimes fail due to travis hiccups. This occurs because a test would sometimes fail the cancel check and succeed the timeout. However, the timeout check should never occur in that test. This fix introduces a new field that dictates how waiters will sleep. -Release v1.10.12 (2017-07-17) -=== - -### Service Client Updates -* `service/cognito-idp`: Updates service API and documentation -* `service/lambda`: Updates service API and documentation - * Lambda@Edge lets you run code closer to your end users without provisioning or managing servers. With Lambda@Edge, your code runs in AWS edge locations, allowing you to respond to your end users at the lowest latency. Your code is triggered by Amazon CloudFront events, such as requests to and from origin servers and viewers, and it is ready to execute at every AWS edge location whenever a request for content is received. You just upload your Node.js code to AWS Lambda and Lambda takes care of everything required to run and scale your code with high availability. You only pay for the compute time you consume - there is no charge when your code is not running. - -Release v1.10.11 (2017-07-14) -=== - -### Service Client Updates -* `service/discovery`: Updates service API and documentation - * Adding feature to the Export API for Discovery Service to allow filters for the export task to allow export based on per agent id. -* `service/ec2`: Updates service API - * New EC2 GPU Graphics instance -* `service/marketplacecommerceanalytics`: Updates service documentation - * Update to Documentation Model For New Report Cadence / Reformat of Docs - -Release v1.10.10 (2017-07-13) -=== - -### Service Client Updates -* `service/apigateway`: Updates service API and documentation - * Adds support for management of gateway responses. -* `service/ec2`: Updates service API and documentation - * X-ENI (or Cross-Account ENI) is a new feature that allows the attachment or association of Elastic Network Interfaces (ENI) between VPCs in different AWS accounts located in the same availability zone. With this new capability, service providers and partners can deliver managed solutions in a variety of new architectural patterns where the provider and consumer of the service are in different AWS accounts. -* `service/lex-models`: Updates service documentation - -Release v1.10.9 (2017-07-12) -=== - -### Service Client Updates -* `service/autoscaling`: Updates service API and documentation - * Auto Scaling now supports a new type of scaling policy called target tracking scaling policies that you can use to set up dynamic scaling for your application. -* `service/swf`: Updates service API, documentation, paginators, and examples - * Added support for attaching control data to Lambda tasks. Control data lets you attach arbitrary strings to your decisions and history events. - -Release v1.10.8 (2017-07-06) -=== - -### Service Client Updates -* `service/ds`: Updates service API, documentation, and paginators - * You can now improve the resilience and performance of your Microsoft AD directory by deploying additional domain controllers. Added UpdateNumberofDomainControllers API that allows you to update the number of domain controllers you want for your directory, and DescribeDomainControllers API that allows you to describe the detailed information of each domain controller of your directory. Also added the 'DesiredNumberOfDomainControllers' field to the DescribeDirectories API output for Microsoft AD. -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/kinesis`: Updates service API and documentation - * You can now encrypt your data at rest within an Amazon Kinesis Stream using server-side encryption. Server-side encryption via AWS KMS makes it easy for customers to meet strict data management requirements by encrypting their data at rest within the Amazon Kinesis Streams, a fully managed real-time data processing service. -* `service/kms`: Updates service API and documentation - * This release of AWS Key Management Service introduces the ability to determine whether a key is AWS managed or customer managed. -* `service/ssm`: Updates service API and documentation - * Amazon EC2 Systems Manager now expands Patching support to Amazon Linux, Red Hat and Ubuntu in addition to the already supported Windows Server. - -Release v1.10.7 (2017-07-05) -=== - -### Service Client Updates -* `service/monitoring`: Updates service API and documentation - * We are excited to announce the availability of APIs and CloudFormation support for CloudWatch Dashboards. You can use the new dashboard APIs or CloudFormation templates to dynamically build and maintain dashboards to monitor your infrastructure and applications. There are four new dashboard APIs - PutDashboard, GetDashboard, DeleteDashboards, and ListDashboards APIs. PutDashboard is used to create a new dashboard or modify an existing one whereas GetDashboard is the API to get the details of a specific dashboard. ListDashboards and DeleteDashboards are used to get the names or delete multiple dashboards respectively. Getting started with dashboard APIs is similar to any other AWS APIs. The APIs can be accessed through AWS SDK or through CLI tools. -* `service/route53`: Updates service API and documentation - * Bug fix for InvalidChangeBatch exception. - -### SDK Enhancements -* `service/s3/s3manager`: adding cleanup function to batch objects [#1375](https://github.com/aws/aws-sdk-go/issues/1375) - * This enhancement will add an After field that will be called after each iteration of the batch operation. - -Release v1.10.6 (2017-06-30) -=== - -### Service Client Updates -* `service/marketplacecommerceanalytics`: Updates service documentation - * Documentation updates for AWS Marketplace Commerce Analytics. -* `service/s3`: Updates service API and documentation - * API Update for S3: Adding Object Tagging Header to MultipartUpload Initialization - -Release v1.10.5 (2017-06-29) -=== - -### Service Client Updates -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/events`: Updates service API and documentation - * CloudWatch Events now allows different AWS accounts to share events with each other through a new resource called event bus. Event buses accept events from AWS services, other AWS accounts and PutEvents API calls. Currently all AWS accounts have one default event bus. To send events to another account, customers simply write rules to match the events of interest and attach an event bus in the receiving account as the target to the rule. The PutTargets API has been updated to allow adding cross account event buses as targets. In addition, we have released two new APIs - PutPermission and RemovePermission - that enables customers to add/remove permissions to their default event bus. -* `service/gamelift`: Updates service API and documentation - * Allow developers to download GameLift fleet creation logs to assist with debugging. -* `service/ssm`: Updates service API and documentation - * Adding Resource Data Sync support to SSM Inventory. New APIs: * CreateResourceDataSync - creates a new resource data sync configuration, * ListResourceDataSync - lists existing resource data sync configurations, * DeleteResourceDataSync - deletes an existing resource data sync configuration. - -Release v1.10.4 (2017-06-27) -=== - -### Service Client Updates -* `service/servicecatalog`: Updates service API, documentation, and paginators - * Proper tagging of resources is critical to post-launch operations such as billing, cost allocation, and resource management. By using Service Catalog's TagOption Library, administrators can define a library of re-usable TagOptions that conform to company standards, and associate these with Service Catalog portfolios and products. Learn how to move your current tags to the new library, create new TagOptions, and view and associate your library items with portfolios and products. Understand how to ensure that the right tags are created on products launched through Service Catalog and how to provide users with defined selectable tags. - -### SDK Bugs -* `aws/signer/v4`: checking length on `stripExcessSpaces` [#1372](https://github.com/aws/aws-sdk-go/issues/1372) - * Fixes a bug where `stripExcessSpaces` did not check length against the slice. - * Fixes: [#1371](https://github.com/aws/aws-sdk-go/issues/1371) -Release v1.10.3 (2017-06-23) -=== - -### Service Client Updates -* `service/lambda`: Updates service API and documentation - * The Lambda Invoke API will now throw new exception InvalidRuntimeException (status code 502) for invokes with deprecated runtimes. - -Release v1.10.2 (2017-06-22) -=== - -### Service Client Updates -* `service/codepipeline`: Updates service API, documentation, and paginators - * A new API, ListPipelineExecutions, enables you to retrieve summary information about the most recent executions in a pipeline, including pipeline execution ID, status, start time, and last updated time. You can request information for a maximum of 100 executions. Pipeline execution data is available for the most recent 12 months of activity. -* `service/dms`: Updates service API and documentation - * Added tagging for DMS certificates. -* `service/elasticloadbalancing`: Updates service waiters -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/lightsail`: Updates service API and documentation - * This release adds a new nextPageToken property to the result of the GetOperationsForResource API. Developers can now get the next set of items in a list by making subsequent calls to GetOperationsForResource API with the token from the previous call. This release also deprecates the nextPageCount property, which previously returned null (use the nextPageToken property instead). This release also deprecates the customImageName property on the CreateInstancesRequest class, which was previously ignored by the API. -* `service/route53`: Updates service API and documentation - * This release reintroduces the HealthCheckInUse exception. - -Release v1.10.1 (2017-06-21) -=== - -### Service Client Updates -* `service/dax`: Adds new service - * Amazon DynamoDB Accelerator (DAX) is a fully managed, highly available, in-memory cache for DynamoDB that delivers up to a 10x performance improvement - from milliseconds to microseconds - even at millions of requests per second. DAX does all the heavy lifting required to add in-memory acceleration to your DynamoDB tables, without requiring developers to manage cache invalidation, data population, or cluster management. -* `service/route53`: Updates service API and documentation - * Amazon Route 53 now supports multivalue answers in response to DNS queries, which lets you route traffic approximately randomly to multiple resources, such as web servers. Create one multivalue answer record for each resource and, optionally, associate an Amazon Route 53 health check with each record, and Amazon Route 53 responds to DNS queries with up to eight healthy records. -* `service/ssm`: Updates service API, documentation, and paginators - * Adding hierarchy support to the SSM Parameter Store API. Added support tor tagging. New APIs: GetParameter - retrieves one parameter, DeleteParameters - deletes multiple parameters (max number 10), GetParametersByPath - retrieves parameters located in the hierarchy. Updated APIs: PutParameter - added ability to enforce parameter value by applying regex (AllowedPattern), DescribeParameters - modified to support Tag filtering. -* `service/waf`: Updates service API and documentation - * You can now create, edit, update, and delete a new type of WAF rule with a rate tracking component. -* `service/waf-regional`: Updates service API and documentation - -Release v1.10.0 (2017-06-20) -=== - -### Service Client Updates -* `service/workdocs`: Updates service API and documentation - * This release provides a new API to retrieve the activities performed by WorkDocs users. - -### SDK Features -* `aws/credentials/plugincreds`: Add support for Go plugin for credentials [#1320](https://github.com/aws/aws-sdk-go/pull/1320) - * Adds support for using plugins to retrieve credentials for API requests. This change adds a new package plugincreds under aws/credentials. See the `example/aws/credentials/plugincreds` folder in the SDK for example usage. - -Release v1.9.00 (2017-06-19) -=== - -### Service Client Updates -* `service/organizations`: Updates service API and documentation - * Improvements to Exception Modeling - -### SDK Features -* `service/s3/s3manager`: Adds batch operations to s3manager [#1333](https://github.com/aws/aws-sdk-go/pull/1333) - * Allows for batch upload, download, and delete of objects. Also adds the interface pattern to allow for easy traversal of objects. E.G `DownloadWithIterator`, `UploadWithIterator`, and `BatchDelete`. `BatchDelete` also contains a utility iterator using the `ListObjects` API to easily delete a list of objects. - -Release v1.8.44 (2017-06-16) -=== - -### Service Client Updates -* `service/xray`: Updates service API, documentation, and paginators - * Add a response time histogram to the services in response of GetServiceGraph API. - -Release v1.8.43 (2017-06-15) -=== - -### Service Client Updates -* `service/ec2`: Updates service API and documentation - * Adds API to describe Amazon FPGA Images (AFIs) available to customers, which includes public AFIs, private AFIs that you own, and AFIs owned by other AWS accounts for which you have load permissions. -* `service/ecs`: Updates service API and documentation - * Added support for cpu, memory, and memory reservation container overrides on the RunTask and StartTask APIs. -* `service/iot`: Updates service API and documentation - * Revert the last release: remove CertificatePem from DescribeCertificate API. -* `service/servicecatalog`: Updates service API, documentation, and paginators - * Added ProvisioningArtifactSummaries to DescribeProductAsAdmin's output to show the provisioning artifacts belong to the product. Allow filtering by SourceProductId in SearchProductsAsAdmin for AWS Marketplace products. Added a verbose option to DescribeProvisioningArtifact to display the CloudFormation template used to create the provisioning artifact.Added DescribeProvisionedProduct API. Changed the type of ProvisionedProduct's Status to be distinct from Record's Status. New ProvisionedProduct's Status are AVAILABLE, UNDER_CHANGE, TAINTED, ERROR. Changed Record's Status set of values to CREATED, IN_PROGRESS, IN_PROGRESS_IN_ERROR, SUCCEEDED, FAILED. - -### SDK Bugs -* `private/model/api`: Fix RESTXML support for XML Namespace [#1343](https://github.com/aws/aws-sdk-go/pull/1343) - * Fixes a bug with the SDK's generation of services using the REST XML protocol not annotating shape references with the XML Namespace attribute. - * Fixes [#1334](https://github.com/aws/aws-sdk-go/pull/1334) -Release v1.8.42 (2017-06-14) -=== - -### Service Client Updates -* `service/applicationautoscaling`: Updates service API and documentation -* `service/clouddirectory`: Updates service documentation - * Documentation update for Cloud Directory - -Release v1.8.41 (2017-06-13) -=== - -### Service Client Updates -* `service/configservice`: Updates service API - -Release v1.8.40 (2017-06-13) -=== - -### Service Client Updates -* `service/rds`: Updates service API and documentation - * API Update for RDS: this update enables copy-on-write, a new Aurora MySQL Compatible Edition feature that allows users to restore their database, and support copy of TDE enabled snapshot cross region. - -### SDK Bugs -* `aws/request`: Fix NewErrParamMinLen to use correct ParamMinLenErrCode [#1336](https://github.com/aws/aws-sdk-go/issues/1336) - * Fixes the `NewErrParamMinLen` function returning the wrong error code. `ParamMinLenErrCode` should be returned not `ParamMinValueErrCode`. - * Fixes [#1335](https://github.com/aws/aws-sdk-go/issues/1335) -Release v1.8.39 (2017-06-09) -=== - -### Service Client Updates -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/opsworks`: Updates service API and documentation - * Tagging Support for AWS OpsWorks Stacks - -Release v1.8.38 (2017-06-08) -=== - -### Service Client Updates -* `service/iot`: Updates service API and documentation - * In addition to using certificate ID, AWS IoT customers can now obtain the description of a certificate with the certificate PEM. -* `service/pinpoint`: Updates service API and documentation - * Starting today Amazon Pinpoint adds SMS Text and Email Messaging support in addition to Mobile Push Notifications, providing developers, product managers and marketers with multi-channel messaging capabilities to drive user engagement in their applications. Pinpoint also enables backend services and applications to message users directly and provides advanced user and app analytics to understand user behavior and messaging performance. -* `service/rekognition`: Updates service API and documentation - * API Update for AmazonRekognition: Adding RecognizeCelebrities API - -Release v1.8.37 (2017-06-07) -=== - -### Service Client Updates -* `service/codebuild`: Updates service API and documentation - * Add support to APIs for privileged containers. This change would allow performing privileged operations like starting the Docker daemon inside builds possible in custom docker images. -* `service/greengrass`: Adds new service - * AWS Greengrass is software that lets you run local compute, messaging, and device state synchronization for connected devices in a secure way. With AWS Greengrass, connected devices can run AWS Lambda functions, keep device data in sync, and communicate with other devices securely even when not connected to the Internet. Using AWS Lambda, Greengrass ensures your IoT devices can respond quickly to local events, operate with intermittent connections, and minimize the cost of transmitting IoT data to the cloud. - -Release v1.8.36 (2017-06-06) -=== - -### Service Client Updates -* `service/acm`: Updates service documentation - * Documentation update for AWS Certificate Manager. -* `service/cloudfront`: Updates service documentation - * Doc update to fix incorrect prefix in S3OriginConfig -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/iot`: Updates service API - * Update client side validation for SalesForce action. - -Release v1.8.35 (2017-06-05) -=== - -### Service Client Updates -* `service/appstream`: Updates service API and documentation - * AppStream 2.0 Custom Security Groups allows you to easily control what network resources your streaming instances and images have access to. You can assign up to 5 security groups per Fleet to control the inbound and outbound network access to your streaming instances to specific IP ranges, network protocols, or ports. -* `service/iot`: Updates service API, documentation, paginators, and examples - * Added Salesforce action to IoT Rules Engine. - -Release v1.8.34 (2017-06-02) -=== - -### Service Client Updates -* `service/kinesisanalytics`: Updates service API, documentation, and paginators - * Kinesis Analytics publishes error messages CloudWatch logs in case of application misconfigurations -* `service/workdocs`: Updates service API and documentation - * This release includes new APIs to manage tags and custom metadata on resources and also new APIs to add and retrieve comments at the document level. - -Release v1.8.33 (2017-06-01) -=== - -### Service Client Updates -* `service/codedeploy`: Updates service API and documentation - * AWS CodeDeploy has improved how it manages connections to GitHub accounts and repositories. You can now create and store up to 25 connections to GitHub accounts in order to associate AWS CodeDeploy applications with GitHub repositories. Each connection can support multiple repositories. You can create connections to up to 25 different GitHub accounts, or create more than one connection to a single account. The ListGitHubAccountTokenNames command has been introduced to retrieve the names of stored connections to GitHub accounts that you have created. The name of the connection to GitHub used for an AWS CodeDeploy application is also included in the ApplicationInfo structure. Two new fields, lastAttemptedDeployment and lastSuccessfulDeployment, have been added to DeploymentGroupInfo to improve the handling of deployment group information in the AWS CodeDeploy console. Information about these latest deployments can also be retrieved using the GetDeploymentGroup and BatchGetDeployment group requests. Also includes a region update (us-gov-west-1). -* `service/cognitoidentityprovider`: Updates service API, documentation, and paginators -* `service/elbv2`: Updates service API and documentation -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/lexmodelbuildingservice`: Updates service documentation and examples - -### SDK Enhancements -* `aws/defaults`: Exports shared credentials and config default filenames used by the SDK. [#1308](https://github.com/aws/aws-sdk-go/pull/1308) - * Adds SharedCredentialsFilename and SharedConfigFilename functions to defaults package. - -### SDK Bugs -* `aws/credentials`: Fixes shared credential provider's default filename on Windows. [#1308](https://github.com/aws/aws-sdk-go/pull/1308) - * The shared credentials provider would attempt to use the wrong filename on Windows if the `HOME` environment variable was defined. -* `service/s3/s3manager`: service/s3/s3manager: Fix Downloader ignoring Range get parameter [#1311](https://github.com/aws/aws-sdk-go/pull/1311) - * Fixes the S3 Download Manager ignoring the GetObjectInput's Range parameter. If this parameter is provided it will force the downloader to fallback to a single GetObject request disabling concurrency and automatic part size gets. - * Fixes [#1296](https://github.com/aws/aws-sdk-go/issues/1296) -Release v1.8.32 (2017-05-31) -=== - -### Service Client Updates -* `service/rds`: Updates service API and documentation - * Amazon RDS customers can now easily and quickly stop and start their DB instances. - -Release v1.8.31 (2017-05-30) -=== - -### Service Client Updates -* `service/clouddirectory`: Updates service API, documentation, and paginators - * Cloud Directory has launched support for Typed Links, enabling customers to create object-to-object relationships that are not hierarchical in nature. Typed Links enable customers to quickly query for data along these relationships. Customers can also enforce referential integrity using Typed Links, ensuring data in use is not inadvertently deleted. -* `service/s3`: Updates service paginators and examples - * New example snippets for Amazon S3. - -Release v1.8.30 (2017-05-25) -=== - -### Service Client Updates -* `service/appstream`: Updates service API and documentation - * Support added for persistent user storage, backed by S3. -* `service/rekognition`: Updates service API and documentation - * Updated the CompareFaces API response to include orientation information, unmatched faces, landmarks, pose, and quality of the compared faces. - -Release v1.8.29 (2017-05-24) -=== - -### Service Client Updates -* `service/iam`: Updates service API - * The unique ID and access key lengths were extended from 32 to 128 -* `service/storagegateway`: Updates service API and documentation - * Two Storage Gateway data types, Tape and TapeArchive, each have a new response element, TapeUsedInBytes. This element helps you manage your virtual tapes. By using TapeUsedInBytes, you can see the amount of data written to each virtual tape. -* `service/sts`: Updates service API, documentation, and paginators - * The unique ID and access key lengths were extended from 32 to 128. - -Release v1.8.28 (2017-05-23) -=== - -### Service Client Updates -* `service/databasemigrationservice`: Updates service API, documentation, paginators, and examples - * This release adds support for using Amazon S3 and Amazon DynamoDB as targets for database migration, and using MongoDB as a source for database migration. For more information, see the AWS Database Migration Service documentation. - -Release v1.8.27 (2017-05-22) -=== - -### Service Client Updates -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/resourcegroupstaggingapi`: Updates service API, documentation, and paginators - * You can now specify the number of resources returned per page in GetResources operation, as an optional parameter, to easily manage the list of resources returned by your queries. - -### SDK Bugs -* `aws/request`: Add support for PUT temporary redirects (307) [#1283](https://github.com/aws/aws-sdk-go/issues/1283) - * Adds support for Go 1.8's GetBody function allowing the SDK's http request using PUT and POST methods to be redirected with temporary redirects with 307 status code. - * Fixes: [#1267](https://github.com/aws/aws-sdk-go/issues/1267) -* `aws/request`: Add handling for retrying temporary errors during unmarshal [#1289](https://github.com/aws/aws-sdk-go/issues/1289) - * Adds support for retrying temporary errors that occur during unmarshaling of a request's response body. - * Fixes: [#1275](https://github.com/aws/aws-sdk-go/issues/1275) -Release v1.8.26 (2017-05-18) -=== - -### Service Client Updates -* `service/athena`: Adds new service - * This release adds support for Amazon Athena. Amazon Athena is an interactive query service that makes it easy to analyze data in Amazon S3 using standard SQL. Athena is serverless, so there is no infrastructure to manage, and you pay only for the queries that you run. -* `service/lightsail`: Updates service API, documentation, and paginators - * This release adds new APIs that make it easier to set network port configurations on Lightsail instances. Developers can now make a single request to both open and close public ports on an instance using the PutInstancePublicPorts operation. - -### SDK Bugs -* `aws/request`: Fix logging from reporting wrong retry request errors #1281 - * Fixes the SDK's retry request logging to report the the actual error that occurred, not a stubbed Unknown error message. - * Fixes the SDK's response logger to not output the response log multiple times per retry. -Release v1.8.25 (2017-05-17) -=== - -### Service Client Updates -* `service/autoscaling`: Updates service documentation, paginators, and examples - * Various Auto Scaling documentation updates -* `service/cloudwatchevents`: Updates service documentation - * Various CloudWatch Events documentation updates. -* `service/cloudwatchlogs`: Updates service documentation and paginators - * Various CloudWatch Logs documentation updates. -* `service/polly`: Updates service API - * Amazon Polly adds new German voice "Vicki" - -Release v1.8.24 (2017-05-16) -=== - -### Service Client Updates -* `service/codedeploy`: Updates service API and documentation - * This release introduces the previousRevision field in the responses to the GetDeployment and BatchGetDeployments actions. previousRevision provides information about the application revision that was deployed to the deployment group before the most recent successful deployment. Also, the fileExistsBehavior parameter has been added for CreateDeployment action requests. In the past, if the AWS CodeDeploy agent detected files in a target location that weren't part of the application revision from the most recent successful deployment, it would fail the current deployment by default. This new parameter provides options for how the agent handles these files: fail the deployment, retain the content, or overwrite the content. -* `service/gamelift`: Updates service API and documentation - * Allow developers to specify how metrics are grouped in CloudWatch for their GameLift fleets. Developers can also specify how many concurrent game sessions activate on a per-instance basis. -* `service/inspector`: Updates service API, documentation, paginators, and examples - * Adds ability to produce an assessment report that includes detailed and comprehensive results of a specified assessment run. -* `service/kms`: Updates service documentation - * Update documentation for KMS. - -Release v1.8.23 (2017-05-15) -=== - -### Service Client Updates -* `service/ssm`: Updates service API and documentation - * UpdateAssociation API now supports updating document name and targets of an association. GetAutomationExecution API can return FailureDetails as an optional field to the StepExecution Object, which contains failure type, failure stage as well as other failure related information for a failed step. - -### SDK Enhancements -* `aws/session`: SDK should be able to load multiple custom shared config files. [#1258](https://github.com/aws/aws-sdk-go/issues/1258) - * This change adds a `SharedConfigFiles` field to the `session.Options` type that allows you to specify the files, and their order, the SDK will use for loading shared configuration and credentials from when the `Session` is created. Use the `NewSessionWithOptions` Session constructor to specify these options. You'll also most likely want to enable support for the shared configuration file's additional attributes by setting `session.Option`'s `SharedConfigState` to `session.SharedConfigEnabled`. - -Release v1.8.22 (2017-05-11) -=== - -### Service Client Updates -* `service/elb`: Updates service API, documentation, and paginators -* `service/elbv2`: Updates service API and documentation -* `service/lexmodelbuildingservice`: Updates service API and documentation -* `service/organizations`: Updates service API, documentation, paginators, and examples - * AWS Organizations APIs that return an Account object now include the email address associated with the account’s root user. - -Release v1.8.21 (2017-05-09) -=== - -### Service Client Updates -* `service/codestar`: Updates service documentation - * Updated documentation for AWS CodeStar. -* `service/workspaces`: Updates service API, documentation, and paginators - * Doc-only Update for WorkSpaces - -Release v1.8.20 (2017-05-04) -=== - -### Service Client Updates -* `service/ecs`: Updates service API, documentation, and paginators - * Exposes container instance registration time in ECS:DescribeContainerInstances. -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/marketplaceentitlementservice`: Adds new service -* `service/lambda`: Updates service API and documentation - * Support for UpdateFunctionCode DryRun option - -Release v1.8.19 (2017-04-28) -=== - -### Service Client Updates -* `service/cloudformation`: Updates service waiters and paginators - * Adding back the removed waiters and paginators. - -Release v1.8.18 (2017-04-28) -=== - -### Service Client Updates -* `service/cloudformation`: Updates service API, documentation, waiters, paginators, and examples - * API update for CloudFormation: New optional parameter ClientRequestToken which can be used as an idempotency token to safely retry certain operations as well as tagging StackEvents. -* `service/rds`: Updates service API, documentation, and examples - * The DescribeDBClusterSnapshots API now returns a SourceDBClusterSnapshotArn field which identifies the source DB cluster snapshot of a copied snapshot. -* `service/rekognition`: Updates service API - * Fix for missing file type check -* `service/snowball`: Updates service API, documentation, and paginators - * The Snowball API has a new exception that can be thrown for list operation requests. -* `service/sqs`: Updates service API, documentation, and paginators - * Adding server-side encryption (SSE) support to SQS by integrating with AWS KMS; adding new queue attributes to SQS CreateQueue, SetQueueAttributes and GetQueueAttributes APIs to support SSE. - -Release v1.8.17 (2017-04-26) -=== - -### Service Client Updates -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/rds`: Updates service API and documentation - * With Amazon Relational Database Service (Amazon RDS) running MySQL or Amazon Aurora, you can now authenticate to your DB instance using IAM database authentication. - -Release v1.8.16 (2017-04-21) -=== - -### Service Client Updates -* `service/appstream`: Updates service API, documentation, and paginators - * The new feature named "Default Internet Access" will enable Internet access from AppStream 2.0 instances - image builders and fleet instances. Admins will check a flag either through AWS management console for AppStream 2.0 or through API while creating an image builder or while creating/updating a fleet. -* `service/kinesis`: Updates service API, documentation, waiters, and paginators - * Adds a new waiter, StreamNotExists, to Kinesis. - -### SDK Enhancements -* `aws/endpoints`: Add utilities improving endpoints lookup (#1218) - * Adds several utilities to the endpoints packages to make looking up partitions, regions, and services easier. - * Fixes #994 - -### SDK Bugs -* `private/protocol/xml/xmlutil`: Fix unmarshaling dropping errors (#1219) - * The XML unmarshaler would drop any serialization or body read error that occurred on the floor effectively hiding any errors that would occur. - * Fixes #1205 -Release v1.8.15 (2017-04-20) -=== - -### Service Client Updates -* `service/devicefarm`: Updates service API and documentation - * API Update for AWS Device Farm: Support for Deals and Promotions -* `service/directconnect`: Updates service documentation - * Documentation updates for AWS Direct Connect. -* `service/elbv2`: Updates service waiters -* `service/kms`: Updates service documentation and examples - * Doc-only update for Key Management Service (KMS): Update docs for GrantConstraints and GenerateRandom -* `service/route53`: Updates service documentation - * Release notes: SDK documentation now includes examples for ChangeResourceRecordSets for all types of resource record set, such as weighted, alias, and failover. -* `service/route53domains`: Updates service API, documentation, and paginators - * Adding examples and other documentation updates. - -### SDK Enhancements -* `service/s3`: Add utilities to make getting a bucket's region easier (#1207) - * Adds two features which make it easier to get a bucket's region, `s3.NormalizeBucketLocation` and `s3manager.GetBucketRegion`. - -### SDK Bugs -* `service/s3`: Fix HeadObject's incorrect documented error codes (#1213) - * The HeadObject's model incorrectly states that the operation can return the NoSuchKey error code. - * Fixes #1208 - -Release v1.8.14 (2017-04-19) -=== - -### Service Client Updates -* `service/apigateway`: Updates service API and documentation - * Add support for "embed" property. -* `service/codestar`: Adds new service - * AWS CodeStar is a cloud-based service for creating, managing, and working with software development projects on AWS. An AWS CodeStar project creates and integrates AWS services for your project development toolchain. AWS CodeStar also manages the permissions required for project users. -* `service/ec2`: Updates service API and documentation - * Adds support for creating an Amazon FPGA Image (AFI) from a specified design checkpoint (DCP). -* `service/iam`: Updates service API and documentation - * This changes introduces a new IAM role type, Service Linked Role, which works like a normal role but must be managed via services' control. -* `service/lambda`: Updates service API and documentation - * Lambda integration with CloudDebugger service to enable customers to enable tracing for the Lambda functions and send trace information to the CloudDebugger service. -* `service/lexmodelbuildingservice`: Adds new service -* `service/polly`: Updates service API, documentation, and paginators - * API Update for Amazon Polly: Add support for speech marks -* `service/rekognition`: Updates service API and documentation - * Given an image, the API detects explicit or suggestive adult content in the image and returns a list of corresponding labels with confidence scores, as well as a taxonomy (parent-child relation) for each label. - -Release v1.8.13 (2017-04-18) -=== - -### Service Client Updates -* `service/lambda`: Updates service API and documentation - * You can use tags to group and filter your Lambda functions, making it easier to analyze them for billing allocation purposes. For more information, see Tagging Lambda Functions. You can now write or upgrade your Lambda functions using Python version 3.6. For more information, see Programming Model for Authoring Lambda Functions in Python. Note: Features will be rolled out in the US regions on 4/19. - -### SDK Enhancements -* `aws/request`: add support for appengine's custom standard library (#1190) - * Remove syscall error checking on appengine platforms. - -Release v1.8.12 (2017-04-11) -=== - -### Service Client Updates -* `service/apigateway`: Updates service API and documentation - * API Gateway request validators -* `service/batch`: Updates service API and documentation - * API Update for AWS Batch: Customer provided AMI for MANAGED Compute Environment -* `service/gamelift`: Updates service API and documentation - * Allows developers to utilize an improved workflow when calling our Queues API and introduces a new feature that allows developers to specify a maximum allowable latency per Queue. -* `service/opsworks`: Updates service API, documentation, and paginators - * Cloudwatch Logs agent configuration can now be attached to OpsWorks Layers using CreateLayer and UpdateLayer. OpsWorks will then automatically install and manage the CloudWatch Logs agent on the instances part of the OpsWorks Layer. - -### SDK Bugs -* `aws/client`: Fix clients polluting handler list (#1197) - * Fixes the clients potentially polluting the passed in handler list with the client's customizations. This change ensures every client always works with a clean copy of the request handlers and it cannot pollute the handlers back upstream. - * Fixes #1184 -* `aws/request`: Fix waiter error match condition (#1195) - * Fixes the waiters's matching overwriting the request's err, effectively ignoring the error condition. This broke waiters with the FailureWaiterState matcher state. -Release v1.8.11 (2017-04-07) -=== - -### Service Client Updates -* `service/redshift`: Updates service API, documentation, and paginators - * This update adds the GetClusterCredentials API which is used to get temporary login credentials to the cluster. AccountWithRestoreAccess now has a new member AccountAlias, this is the identifier of the AWS support account authorized to restore the specified snapshot. This is added to support the feature where the customer can share their snapshot with the Amazon Redshift Support Account without having to manually specify the AWS Redshift Service account ID on the AWS Console/API. - -Release v1.8.10 (2017-04-06) -=== - -### Service Client Updates -* `service/elbv2`: Updates service documentation - -Release v1.8.9 (2017-04-05) -=== - -### Service Client Updates -* `service/elasticache`: Updates service API, documentation, paginators, and examples - * ElastiCache added support for testing the Elasticache Multi-AZ feature with Automatic Failover. - -Release v1.8.8 (2017-04-04) -=== - -### Service Client Updates -* `service/cloudwatch`: Updates service API, documentation, and paginators - * Amazon Web Services announced the immediate availability of two additional alarm configuration rules for Amazon CloudWatch Alarms. The first rule is for configuring missing data treatment. Customers have the options to treat missing data as alarm threshold breached, alarm threshold not breached, maintain alarm state and the current default treatment. The second rule is for alarms based on percentiles metrics that can trigger unnecassarily if the percentile is calculated from a small number of samples. The new rule can treat percentiles with low sample counts as same as missing data. If the first rule is enabled, the same treatment will be applied when an alarm encounters a percentile with low sample counts. - -Release v1.8.7 (2017-04-03) -=== - -### Service Client Updates -* `service/lexruntimeservice`: Updates service API and documentation - * Adds support to PostContent for speech input - -### SDK Enhancements -* `aws/request`: Improve handler copy, push back, push front performance (#1171) - * Minor optimization to the handler list's handling of copying and pushing request handlers to the handler list. -* Update codegen header to use Go std wording (#1172) - * Go recently accepted the proposal for standard generated file header wording in, https://golang.org/s/generatedcode. - -### SDK Bugs -* `service/dynamodb`: Fix DynamoDB using custom retryer (#1170) - * Fixes (#1139) the DynamoDB service client clobbering any custom retryer that was passed into the service client or Session's config. -Release v1.8.6 (2017-04-01) -=== - -### Service Client Updates -* `service/clouddirectory`: Updates service API and documentation - * ListObjectAttributes now supports filtering by facet. -* `aws/endpoints`: Updated Regions and Endpoints metadata. - -Release v1.8.5 (2017-03-30) -=== - -### Service Client Updates -* `service/cloudformation`: Updates service waiters and paginators - * Adding paginators for ListExports and ListImports -* `service/cloudfront`: Adds new service - * Amazon CloudFront now supports user configurable HTTP Read and Keep-Alive Idle Timeouts for your Custom Origin Servers -* `service/configservice`: Updates service documentation -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/resourcegroupstaggingapi`: Adds new service -* `service/storagegateway`: Updates service API and documentation - * File gateway mode in AWS Storage gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. Once a file share is created, any changes made externally to the S3 bucket will not be reflected by the gateway. Using the cache refresh feature in this update, the customer can trigger an on-demand scan of the keys in their S3 bucket and refresh the file namespace cached on the gateway. It takes as an input the fileShare ARN and refreshes the cache for only that file share. Additionally there is new functionality on file gateway that allows you configure what squash options they would like on their file share, this allows a customer to configure their gateway to not squash root permissions. This can be done by setting options in NfsOptions for CreateNfsFileShare and UpdateNfsFileShare APIs. - -Release v1.8.4 (2017-03-28) -=== - -### Service Client Updates -* `service/batch`: Updates service API, documentation, and paginators - * Customers can now provide a retryStrategy as part of the RegisterJobDefinition and SubmitJob API calls. The retryStrategy object has a number value for attempts. This is the number of non successful executions before a job is considered FAILED. In addition, the JobDetail object now has an attempts field and shows all execution attempts. -* `service/ec2`: Updates service API and documentation - * Customers can now tag their Amazon EC2 Instances and Amazon EBS Volumes at - the time of their creation. You can do this from the EC2 Instance launch - wizard or through the RunInstances or CreateVolume APIs. By tagging - resources at the time of creation, you can eliminate the need to run custom - tagging scripts after resource creation. In addition, you can now set - resource-level permissions on the CreateVolume, CreateTags, DeleteTags, and - the RunInstances APIs. This allows you to implement stronger security - policies by giving you more granular control over which users and groups - have access to these APIs. You can also enforce the use of tagging and - control what tag keys and values are set on your resources. When you combine - tag usage and resource-level IAM policies together, you can ensure your - instances and volumes are properly secured upon creation and achieve more - accurate cost allocation reporting. These new features are provided at no - additional cost. - -### SDK Enhancements -* `aws/request`: Add retry support for RequestTimeoutException (#1158) - * Adds support for retrying RequestTimeoutException error code that is returned by some services. - -### SDK Bugs -* `private/model/api`: Fix Waiter and Paginators panic on nil param inputs (#1157) - * Corrects the code generation for Paginators and waiters that caused a panic if nil input parameters were used with the operations. -Release v1.8.3 (2017-03-27) -=== - -## Service Client Updates -* `service/ssm`: Updates service API, documentation, and paginators - * Updated validation rules for SendCommand and RegisterTaskWithMaintenanceWindow APIs. -Release v1.8.2 (2017-03-24) -=== - -Service Client Updates ---- -* `service/applicationautoscaling`: Updates service API, documentation, and paginators - * Application AutoScaling is launching support for a new target resource (AppStream 2.0 Fleets) as a scalable target. -* `service/cloudtrail`: Updates service API and documentation - * Doc-only Update for CloudTrail: Add required parameters for GetEventSelectors and PutEventSelectors - -Release v1.8.1 (2017-03-23) -=== - -Service Client Updates ---- -* `service/applicationdiscoveryservice`: Updates service API, documentation, and paginators - * Adds export configuration options to the AWS Discovery Service API. -* `service/elbv2`: Updates waiters -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/lambda`: Updates service API and paginators - * Adds support for new runtime Node.js v6.10 for AWS Lambda service - -Release v1.8.0 (2017-03-22) -=== - -Service Client Updates ---- -* `service/codebuild`: Updates service documentation -* `service/directconnect`: Updates service API - * Deprecated DescribeConnectionLoa, DescribeInterconnectLoa, AllocateConnectionOnInterconnect and DescribeConnectionsOnInterconnect operations in favor of DescribeLoa, DescribeLoa, AllocateHostedConnection and DescribeHostedConnections respectively. -* `service/marketplacecommerceanalytics`: Updates service API, documentation, and paginators - * This update adds a new data set, us_sales_and_use_tax_records, which enables AWS Marketplace sellers to programmatically access to their U.S. Sales and Use Tax report data. -* `service/pinpoint`: Updates service API and documentation - * Amazon Pinpoint User Segmentation - * Added ability to segment endpoints by user attributes in addition to endpoint attributes. Amazon Pinpoint Event Stream Preview - * Added functionality to publish raw app analytics and campaign events data as events streams to Kinesis and Kinesis Firehose - * The feature provides developers with increased flexibility of exporting raw events to S3, Redshift, Elasticsearch using a Kinesis Firehose stream or enable real time event processing use cases using a Kinesis stream -* `service/rekognition`: Updates service documentation. - -SDK Features ---- -* `aws/request`: Add support for context.Context to SDK API operation requests (#1132) - * Adds support for context.Context to the SDK by adding `WithContext` methods for each API operation, Paginators and Waiters. e.g `PutObjectWithContext`. This change also adds the ability to provide request functional options to the method calls instead of requiring you to use the `Request` API operation method (e.g `PutObjectRequest`). - * Adds a `Complete` Request handler list that will be called ever time a request is completed. This includes both success and failure. Complete will only be called once per API operation request. - * `private/waiter` package moved from the private group to `aws/request/waiter` and made publicly available. - * Adds Context support to all API operations, Waiters(WaitUntil) and Paginators(Pages) methods. - * Adds Context support for s3manager and s3crypto clients. - -SDK Enhancements ---- -* `aws/signer/v4`: Adds support for unsigned payload signer config (#1130) - * Adds configuration option to the v4.Signer to specify the request's body should not be signed. This will only correclty function on services that support unsigned payload. e.g. S3, Glacier. - -SDK Bug Fixes ---- -* `service/s3`: Fix S3 HostID to be available in S3 request error message (#1131) - * Adds a new type s3.RequestFailure which exposes the S3 HostID value from a S3 API operation response. This is helpful when you have an error with S3, and need to contact support. Both RequestID and HostID are needed. -* `private/model/api`: Do not return a link if uid is empty (#1133) - * Fixes SDK's doc generation to not generate API reference doc links if the SDK us unable to create a valid link. -* `aws/request`: Optimization to handler list copy to prevent multiple alloc calls. (#1134) -Release v1.7.9 (2017-03-13) -=== - -Service Client Updates ---- -* `service/devicefarm`: Updates service API, documentation, paginators, and examples - * Network shaping allows users to simulate network connections and conditions while testing their Android, iOS, and web apps with AWS Device Farm. -* `service/cloudwatchevents`: Updates service API, documentation, and examples - -SDK Enhancement -=== -* `aws/session`: Add support for side loaded CA bundles (#1117) - * Adds supports for side loading Certificate Authority bundle files to the SDK using AWS_CA_BUNDLE environment variable or CustomCABundle session option. -* `service/s3/s3crypto`: Add support for AES/CBC/PKCS5Padding (#1124) - -SDK Bug -=== -* `service/rds`: Fixing issue when not providing `SourceRegion` on cross -region operations (#1127) -* `service/rds`: Enables cross region for `CopyDBClusterSnapshot` and -`CreateDBCluster` (#1128) - -Release v1.7.8 (2017-03-10) -=== - -Service Client Updates ---- -* `service/codedeploy`: Updates service paginators - * Add paginators for Codedeploy -* `service/emr`: Updates service API, documentation, and paginators - * This release includes support for instance fleets in Amazon EMR. - -Release v1.7.7 (2017-03-09) -=== - -Service Client Updates ---- -* `service/apigateway`: Updates service API, documentation, and paginators - * API Gateway has added support for ACM certificates on custom domain names. Both Amazon-issued certificates and uploaded third-part certificates are supported. -* `service/clouddirectory`: Updates service API, documentation, and paginators - * Introduces a new Cloud Directory API that enables you to retrieve all available parent paths for any type of object (a node, leaf node, policy node, and index node) in a hierarchy. - -Release v1.7.6 (2017-03-09) -=== - -Service Client Updates ---- -* `service/organizations`: Updates service documentation and examples - * Doc-only Update for Organizations: Add SDK Code Snippets -* `service/workdocs`: Adds new service - * The Administrative SDKs for Amazon WorkDocs provides full administrator level access to WorkDocs site resources, allowing developers to integrate their applications to manage WorkDocs users, content and permissions programmatically - -Release v1.7.5 (2017-03-08) -=== - -Service Client Updates ---- -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/rds`: Updates service API and documentation - * Add support to using encrypted clusters as cross-region replication masters. Update CopyDBClusterSnapshot API to support encrypted cross region copy of Aurora cluster snapshots. - -Release v1.7.4 (2017-03-06) -=== - -Service Client Updates ---- -* `service/budgets`: Updates service API and paginators - * When creating or editing a budget via the AWS Budgets API you can define notifications that are sent to subscribers when the actual or forecasted value for cost or usage exceeds the notificationThreshold associated with the budget notification object. Starting today, the maximum allowed value for the notificationThreshold was raised from 100 to 300. This change was made to give you more flexibility when setting budget notifications. -* `service/cloudtrail`: Updates service documentation and paginators - * Doc-only update for AWSCloudTrail: Updated links/descriptions -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/opsworkscm`: Updates service API, documentation, and paginators - * OpsWorks for Chef Automate has added a new field "AssociatePublicIpAddress" to the CreateServer request, "CloudFormationStackArn" to the Server model and "TERMINATED" server state. - - -Release v1.7.3 (2017-02-28) -=== - -Service Client Updates ---- -* `service/mturk`: Renaming service - * service/mechanicalturkrequesterservice was renamed to service/mturk. Be sure to change any references of the old client to the new. - -Release v1.7.2 (2017-02-28) -=== - -Service Client Updates ---- -* `service/dynamodb`: Updates service API and documentation - * Release notes: Time to Live (TTL) is a feature that allows you to define when items in a table expire and can be purged from the database, so that you don't have to track expired data and delete it manually. With TTL enabled on a DynamoDB table, you can set a timestamp for deletion on a per-item basis, allowing you to limit storage usage to only those records that are relevant. -* `service/iam`: Updates service API, documentation, and paginators - * This release adds support for AWS Organizations service control policies (SCPs) to SimulatePrincipalPolicy operation. If there are SCPs associated with the simulated user's account, their effect on the result is captured in the OrganizationDecisionDetail element in the EvaluationResult. -* `service/mechanicalturkrequesterservice`: Adds new service - * Amazon Mechanical Turk is a web service that provides an on-demand, scalable, human workforce to complete jobs that humans can do better than computers, for example, recognizing objects in photos. -* `service/organizations`: Adds new service - * AWS Organizations is a web service that enables you to consolidate your multiple AWS accounts into an organization and centrally manage your accounts and their resources. -* `service/dynamodbstreams`: Updates service API, documentation, and paginators -* `service/waf`: Updates service API, documentation, and paginators - * Aws WAF - For GetSampledRequests action, changed max number of samples from 100 to 500. -* `service/wafregional`: Updates service API, documentation, and paginators - -Release v1.7.1 (2017-02-24) -=== - -Service Client Updates ---- -* `service/elasticsearchservice`: Updates service API, documentation, paginators, and examples - * Added three new API calls to existing Amazon Elasticsearch service to expose Amazon Elasticsearch imposed limits to customers. - -Release v1.7.0 (2017-02-23) -=== - -Service Client Updates ---- -* `service/ec2`: Updates service API - * New EC2 I3 instance type - -SDK Bug ---- -* `service/s3/s3manager`: Adding support for SSE (#1097) - * Fixes SSE fields not being applied to a part during multi part upload. - -SDK Feature ---- -* `aws/session`: Add support for AssumeRoles with MFA (#1088) - * Adds support for assuming IAM roles with MFA enabled. A TokenProvider func was added to stscreds.AssumeRoleProvider that will be called each time the role's credentials need to be refreshed. A basic token provider that sources the MFA token from stdin as stscreds.StdinTokenProvider. -* `aws/session`: Update SDK examples and docs to use session.Must (#1099) - * Updates the SDK's example and docs to use session.Must where possible to highlight its usage as apposed to session error checking that is most cases errors will be terminal to the application anyways. -Release v1.6.27 (2017-02-22) -=== - -Service Client Updates ---- -* `service/clouddirectory`: Updates service documentation - * ListObjectAttributes documentation updated based on forum feedback -* `service/elasticbeanstalk`: Updates service API, documentation, and paginators - * Elastic Beanstalk adds support for creating and managing custom platform. -* `service/gamelift`: Updates service API, documentation, and paginators - * Allow developers to configure global queues for creating GameSessions. Allow PlayerData on PlayerSessions to store player-specific data. -* `service/route53`: Updates service API, documentation, and examples - * Added support for operations CreateVPCAssociationAuthorization and DeleteVPCAssociationAuthorization to throw a ConcurrentModification error when a conflicting modification occurs in parallel to the authorizations in place for a given hosted zone. - -Release v1.6.26 (2017-02-21) -=== - -Service Client Updates ---- -* `service/ec2`: Updates service API and documentation - * Added the billingProduct parameter to the RegisterImage API. - -Release v1.6.25 (2017-02-17) -=== - -Service Client Updates ---- -* `service/directconnect`: Updates service API, documentation, and paginators - * This update will introduce the ability for Direct Connect customers to take advantage of Link Aggregation (LAG). This allows you to bundle many individual physical interfaces into a single logical interface, referred to as a LAG. This makes administration much simpler as the majority of configuration is done on the LAG while you are free to add or remove physical interfaces from the bundle as bandwidth demand increases or decreases. A concrete example of the simplification added by LAG is that customers need only a single BGP session as opposed to one session per physical connection. - -Release v1.6.24 (2017-02-16) -=== - -Service Client Updates ---- -* `service/cognitoidentity`: Updates service API, documentation, and paginators - * Allow createIdentityPool and updateIdentityPool API to set server side token check value on identity pool -* `service/configservice`: Updates service API and documentation - * AWS Config now supports a new test mode for the PutEvaluations API. Set the TestMode parameter to true in your custom rule to verify whether your AWS Lambda function will deliver evaluation results to AWS Config. No updates occur to your existing evaluations, and evaluation results are not sent to AWS Config. - -Release v1.6.23 (2017-02-15) -=== - -Service Client Updates ---- -* `service/kms`: Updates service API, documentation, paginators, and examples - * his release of AWS Key Management Service introduces the ability to tag keys. Tagging keys can help you organize your keys and track your KMS costs in the cost allocation report. This release also increases the maximum length of a key ID to accommodate ARNs that include a long key alias. - -Release v1.6.22 (2017-02-14) -=== - -Service Client Updates ---- -* `service/ec2`: Updates service API, documentation, and paginators - * Adds support for the new Modify Volumes apis. - -Release v1.6.21 (2017-02-11) -=== - -Service Client Updates ---- -* `service/storagegateway`: Updates service API, documentation, and paginators - * File gateway mode in AWS Storage gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. This is done by creating Nfs file shares using existing APIs CreateNfsFileShare. Using the feature in this update, the customer can restrict the clients that have read/write access to the gateway by specifying the list of clients as a list of IP addresses or CIDR blocks. This list can be specified using the API CreateNfsFileShare while creating new file shares, or UpdateNfsFileShare while update existing file shares. To find out the list of clients that have access, the existing API DescribeNfsFileShare will now output the list of clients that have access. - -Release v1.6.20 (2017-02-09) -=== - -Service Client Updates ---- -* `service/ec2`: Updates service API and documentation - * This feature allows customers to associate an IAM profile to running instances that do not have any. -* `service/rekognition`: Updates service API and documentation - * DetectFaces and IndexFaces operations now return an estimate of the age of the face as an age range. - -SDK Features ---- -* `aws/endpoints`: Add option to resolve unknown endpoints (#1074) -Release v1.6.19 (2017-02-08) -=== - -Service Client Updates ---- -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/glacier`: Updates service examples - * Doc Update -* `service/lexruntimeservice`: Adds new service - * Preview release - -SDK Bug Fixes ---- -* `private/protocol/json`: Fixes json to throw an error if a float number is (+/-)Inf and NaN (#1068) -* `private/model/api`: Fix documentation error listing (#1067) - -SDK Features ---- -* `private/model`: Add service response error code generation (#1061) - -Release v1.6.18 (2017-01-27) -=== - -Service Client Updates ---- -* `service/clouddirectory`: Adds new service - * Amazon Cloud Directory is a highly scalable, high performance, multi-tenant directory service in the cloud. Its web-based directories make it easy for you to organize and manage application resources such as users, groups, locations, devices, policies, and the rich relationships between them. -* `service/codedeploy`: Updates service API, documentation, and paginators - * This release of AWS CodeDeploy introduces support for blue/green deployments. In a blue/green deployment, the current set of instances in a deployment group is replaced by new instances that have the latest application revision installed on them. After traffic is rerouted behind a load balancer to the replacement instances, the original instances can be terminated automatically or kept running for other uses. -* `service/ec2`: Updates service API and documentation - * Adds instance health check functionality to replace unhealthy EC2 Spot fleet instances with fresh ones. -* `service/rds`: Updates service API and documentation - * Snapshot Engine Version Upgrade - -Release v1.6.17 (2017-01-25) -=== - -Service Client Updates ---- -* `service/elbv2`: Updates service API, documentation, and paginators - * Application Load Balancers now support native Internet Protocol version 6 (IPv6) in an Amazon Virtual Private Cloud (VPC). With this ability, clients can now connect to the Application Load Balancer in a dual-stack mode via either IPv4 or IPv6. -* `service/rds`: Updates service API and documentation - * Cross Region Read Replica Copying (CreateDBInstanceReadReplica) - -Release v1.6.16 (2017-01-24) -=== - -Service Client Updates ---- -* `service/codebuild`: Updates service documentation and paginators - * Documentation updates -* `service/codecommit`: Updates service API, documentation, and paginators - * AWS CodeCommit now includes the option to view the differences between a commit and its parent commit from within the console. You can view the differences inline (Unified view) or side by side (Split view). To view information about the differences between a commit and something other than its parent, you can use the AWS CLI and the get-differences and get-blob commands, or you can use the GetDifferences and GetBlob APIs. -* `service/ecs`: Updates service API and documentation - * Amazon ECS now supports a state for container instances that can be used to drain a container instance in preparation for maintenance or cluster scale down. - -Release v1.6.15 (2017-01-20) -=== - -Service Client Updates ---- -* `service/acm`: Updates service API, documentation, and paginators - * Update for AWS Certificate Manager: Updated response elements for DescribeCertificate API in support of managed renewal -* `service/health`: Updates service documentation - -Release v1.6.14 (2017-01-19) -=== - -Service Client Updates ---- -* `service/ec2`: Updates service API, documentation, and paginators - * Amazon EC2 Spot instances now support dedicated tenancy, providing the ability to run Spot instances single-tenant manner on physically isolated hardware within a VPC to satisfy security, privacy, or other compliance requirements. Dedicated Spot instances can be requested using RequestSpotInstances and RequestSpotFleet. - -Release v1.6.13 (2017-01-18) -=== - -Service Client Updates ---- -* `service/rds`: Updates service API, documentation, and paginators - -Release v1.6.12 (2017-01-17) -=== - -Service Client Updates ---- -* `service/dynamodb`: Updates service API, documentation, and paginators - * Tagging Support for Amazon DynamoDB Tables and Indexes -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/glacier`: Updates service API, paginators, and examples - * Doc-only Update for Glacier: Added code snippets -* `service/polly`: Updates service documentation and examples - * Doc-only update for Amazon Polly -- added snippets -* `service/rekognition`: Updates service documentation and paginators - * Added code samples to Rekognition reference topics. -* `service/route53`: Updates service API and paginators - * Add ca-central-1 and eu-west-2 enum values to CloudWatchRegion enum - -Release v1.6.11 (2017-01-16) -=== - -Service Client Updates ---- -* `service/configservice`: Updates service API, documentation, and paginators -* `service/costandusagereportservice`: Adds new service - * The AWS Cost and Usage Report Service API allows you to enable and disable the Cost & Usage report, as well as modify the report name, the data granularity, and the delivery preferences. -* `service/dynamodb`: Updates service API, documentation, and examples - * Snippets for the DynamoDB API. -* `service/elasticache`: Updates service API, documentation, and examples - * Adds new code examples. -* `aws/endpoints`: Updated Regions and Endpoints metadata. - -Release v1.6.10 (2017-01-04) -=== - -Service Client Updates ---- -* `service/configservice`: Updates service API and documentation - * AWSConfig is planning to add support for OversizedConfigurationItemChangeNotification message type in putConfigRule. After this release customers can use/write rules based on OversizedConfigurationItemChangeNotification mesage type. -* `service/efs`: Updates service API, documentation, and examples - * Doc-only Update for EFS: Added code snippets -* `service/iam`: Updates service documentation and examples -* `service/lambda`: Updates service documentation and examples - * Doc only updates for Lambda: Added code snippets -* `service/marketplacecommerceanalytics`: Updates service API and documentation - * Added support for data set disbursed_amount_by_instance_hours, with historical data available starting 2012-09-04. New data is published to this data set every 30 days. -* `service/rds`: Updates service documentation - * Updated documentation for CopyDBSnapshot. -* `service/rekognition`: Updates service documentation and examples - * Doc-only Update for Rekognition: Added code snippets -* `service/snowball`: Updates service examples -* `service/dynamodbstreams`: Updates service API and examples - * Doc-only Update for DynamoDB Streams: Added code snippets - -SDK Feature ---- -* `private/model/api`: Increasing the readability of code generated files. (#1024) -Release v1.6.9 (2016-12-30) -=== - -Service Client Updates ---- -* `service/codedeploy`: Updates service API and documentation - * CodeDeploy will support Iam Session Arns in addition to Iam User Arns for on premise host authentication. -* `service/ecs`: Updates service API and documentation - * Amazon EC2 Container Service (ECS) now supports the ability to customize the placement of tasks on container instances. -* `aws/endpoints`: Updated Regions and Endpoints metadata. - -Release v1.6.8 (2016-12-22) -=== - -Service Client Updates ---- -* `service/apigateway`: Updates service API and documentation - * Amazon API Gateway is adding support for generating SDKs in more languages. This update introduces two new operations used to dynamically discover these SDK types and what configuration each type accepts. -* `service/directoryservice`: Updates service documentation - * Added code snippets for the DS SDKs -* `service/elasticbeanstalk`: Updates service API and documentation -* `service/iam`: Updates service API and documentation - * Adds service-specific credentials to IAM service to make it easier to onboard CodeCommit customers. These are username/password credentials that work with a single service. -* `service/kms`: Updates service API, documentation, and examples - * Update docs and add SDK examples - -Release v1.6.7 (2016-12-22) -=== - -Service Client Updates ---- -* `service/ecr`: Updates service API and documentation -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/rds`: Updates service API and documentation - * Cross Region Encrypted Snapshot Copying (CopyDBSnapshot) - -Release v1.6.6 (2016-12-20) -=== - -Service Client Updates ---- -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/firehose`: Updates service API, documentation, and examples - * Processing feature enables users to process and modify records before Amazon Firehose delivers them to destinations. -* `service/route53`: Updates service API and documentation - * Enum updates for eu-west-2 and ca-central-1 -* `service/storagegateway`: Updates service API, documentation, and examples - * File gateway is a new mode in the AWS Storage Gateway that support a file interface into S3, alongside the current block-based volume and VTL storage. File gateway combines a service and virtual software appliance, enabling you to store and retrieve objects in Amazon S3 using industry standard file protocols such as NFS. The software appliance, or gateway, is deployed into your on-premises environment as a virtual machine (VM) running on VMware ESXi. The gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. - -Release v1.6.5 (2016-12-19) -=== - -Service Client Updates ---- -* `service/cloudformation`: Updates service documentation - * Minor doc update for CloudFormation. -* `service/cloudtrail`: Updates service paginators -* `service/cognitoidentity`: Updates service API and documentation - * We are adding Groups to Cognito user pools. Developers can perform CRUD operations on groups, add and remove users from groups, list users in groups, etc. We are adding fine-grained role-based access control for Cognito identity pools. Developers can configure an identity pool to get the IAM role from an authenticated user's token, or they can configure rules that will map a user to a different role -* `service/applicationdiscoveryservice`: Updates service API and documentation - * Adds new APIs to group discovered servers into Applications with get summary and neighbors. Includes additional filters for ListConfigurations and DescribeAgents API. -* `service/inspector`: Updates service API, documentation, and examples - * Doc-only Update for Inspector: Adding SDK code snippets for Inspector -* `service/sqs`: Updates service documentation - -SDK Bug Fixes ---- -* `aws/request`: Add PriorRequestNotComplete to throttle retry codes (#1011) - * Fixes: Not retrying when PriorRequestNotComplete #1009 - -SDK Feature ---- -* `private/model/api`: Adds crosslinking to service documentation (#1010) - -Release v1.6.4 (2016-12-15) -=== - -Service Client Updates ---- -* `service/cognitoidentityprovider`: Updates service API and documentation -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/ssm`: Updates service API and documentation - * This will provide customers with access to the Patch Baseline and Patch Compliance APIs. - -SDK Bug Fixes ---- -* `service/route53`: Fix URL path cleaning for Route53 API requests (#1006) - * Fixes: SerializationError when using Route53 ChangeResourceRecordSets #1005 -* `aws/request`: Add PriorRequestNotComplete to throttle retry codes (#1002) - * Fixes: Not retrying when PriorRequestNotComplete #1001 - -Release v1.6.3 (2016-12-14) -=== - -Service Client Updates ---- -* `service/batch`: Adds new service - * AWS Batch is a batch computing service that lets customers define queues and compute environments and then submit work as batch jobs. -* `service/databasemigrationservice`: Updates service API and documentation - * Adds support for SSL enabled Oracle endpoints and task modification. -* `service/elasticbeanstalk`: Updates service documentation -* `aws/endpoints`: Updated Regions and Endpoints metadata. -* `service/cloudwatchlogs`: Updates service API and documentation - * Add support for associating LogGroups with AWSTagris tags -* `service/marketplacecommerceanalytics`: Updates service API and documentation - * Add new enum to DataSetType: sales_compensation_billed_revenue -* `service/rds`: Updates service documentation - * Doc-only Update for RDS: New versions available in CreateDBInstance -* `service/sts`: Updates service documentation - * Adding Code Snippet Examples for SDKs for STS - -SDK Bug Fixes ---- -* `aws/request`: Fix retrying timeout requests (#981) - * Fixes: Requests Retrying is broken if the error was caused due to a client timeout #947 -* `aws/request`: Fix for Go 1.8 request incorrectly sent with body (#991) - * Fixes: service/route53: ListHostedZones hangs and then fails with go1.8 #984 -* private/protocol/rest: Use RawPath instead of Opaque (#993) - * Fixes: HTTP2 request failing with REST protocol services, e.g AWS X-Ray -* private/model/api: Generate REST-JSON JSONVersion correctly (#998) - * Fixes: REST-JSON protocol service code missing JSONVersion metadata. - -Release v1.6.2 (2016-12-08) -=== - -Service Client Updates ---- -* `service/cloudfront`: Add lambda function associations to cache behaviors -* `service/codepipeline`: This is a doc-only update request to incorporate some recent minor revisions to the doc content. -* `service/rds`: Updates service API and documentation -* `service/wafregional`: With this new feature, customers can use AWS WAF directly on Application Load Balancers in a VPC within available regions to protect their websites and web services from malicious attacks such as SQL injection, Cross Site Scripting, bad bots, etc. - -Release v1.6.1 (2016-12-07) -=== - -Service Client Updates ---- -* `service/config`: Updates service API -* `service/s3`: Updates service API -* `service/sqs`: Updates service API and documentation - -Release v1.6.0 (2016-12-06) -=== - -Service Client Updates ---- -* `service/config`: Updates service API and documentation -* `service/ec2`: Updates service API -* `service/sts`: Updates service API, documentation, and examples - -SDK Bug Fixes ---- -* private/protocol/xml/xmlutil: Fix SDK XML unmarshaler #975 - * Fixes GetBucketACL Grantee required type always nil. #916 - -SDK Feature ---- -* aws/endpoints: Add endpoint metadata to SDK #961 - * Adds Region and Endpoint metadata to the SDK. This allows you to enumerate regions and endpoint metadata based on a defined model embedded in the SDK. - -Release v1.5.13 (2016-12-01) -=== - -Service Client Updates ---- -* `service/apigateway`: Updates service API and documentation -* `service/appstream`: Adds new service -* `service/codebuild`: Adds new service -* `service/directconnect`: Updates service API and documentation -* `service/ec2`: Adds new service -* `service/elasticbeanstalk`: Updates service API and documentation -* `service/health`: Adds new service -* `service/lambda`: Updates service API and documentation -* `service/opsworkscm`: Adds new service -* `service/pinpoint`: Adds new service -* `service/shield`: Adds new service -* `service/ssm`: Updates service API and documentation -* `service/states`: Adds new service -* `service/xray`: Adds new service - -Release v1.5.12 (2016-11-30) -=== - -Service Client Updates ---- -* `service/lightsail`: Adds new service -* `service/polly`: Adds new service -* `service/rekognition`: Adds new service -* `service/snowball`: Updates service API and documentation - -Release v1.5.11 (2016-11-29) -=== - -Service Client Updates ---- -`service/s3`: Updates service API and documentation - -Release v1.5.10 (2016-11-22) -=== - -Service Client Updates ---- -* `service/cloudformation`: Updates service API and documentation -* `service/glacier`: Updates service API, documentation, and examples -* `service/route53`: Updates service API and documentation -* `service/s3`: Updates service API and documentation - -SDK Bug Fixes ---- -* `private/protocol/xml/xmlutil`: Fixes xml marshaler to unmarshal properly -into tagged fields -[#916](https://github.com/aws/aws-sdk-go/issues/916) - -Release v1.5.9 (2016-11-22) -=== - -Service Client Updates ---- -* `service/cloudtrail`: Updates service API and documentation -* `service/ecs`: Updates service API and documentation - -Release v1.5.8 (2016-11-18) -=== - -Service Client Updates ---- -* `service/application-autoscaling`: Updates service API and documentation -* `service/elasticmapreduce`: Updates service API and documentation -* `service/elastictranscoder`: Updates service API, documentation, and examples -* `service/gamelift`: Updates service API and documentation -* `service/lambda`: Updates service API and documentation - -Release v1.5.7 (2016-11-18) -=== - -Service Client Updates ---- -* `service/apigateway`: Updates service API and documentation -* `service/meteringmarketplace`: Updates service API and documentation -* `service/monitoring`: Updates service API and documentation -* `service/sqs`: Updates service API, documentation, and examples - -Release v1.5.6 (2016-11-16) -=== - -Service Client Updates ---- -`service/route53`: Updates service API and documentation -`service/servicecatalog`: Updates service API and documentation - -Release v1.5.5 (2016-11-15) -=== - -Service Client Updates ---- -* `service/ds`: Updates service API and documentation -* `service/elasticache`: Updates service API and documentation -* `service/kinesis`: Updates service API and documentation - -Release v1.5.4 (2016-11-15) -=== - -Service Client Updates ---- -* `service/cognito-idp`: Updates service API and documentation - -Release v1.5.3 (2016-11-11) -=== - -Service Client Updates ---- -* `service/cloudformation`: Updates service documentation and examples -* `service/logs`: Updates service API and documentation - -Release v1.5.2 (2016-11-03) -=== - -Service Client Updates ---- -* `service/directconnect`: Updates service API and documentation - -Release v1.5.1 (2016-11-02) -=== - -Service Client Updates ---- -* `service/email`: Updates service API and documentation - -Release v1.5.0 (2016-11-01) -=== - -Service Client Updates ---- -* `service/cloudformation`: Updates service API and documentation -* `service/ecr`: Updates service paginators - -SDK Feature Updates ---- -* `private/model/api`: Add generated setters for API parameters (#918) - * Adds setters to the SDK's API parameter types, and are a convenience method that reduce the need to use `aws.String` and like utility. - -Release v1.4.22 (2016-10-25) -=== - -Service Client Updates ---- -* `service/elasticloadbalancingv2`: Updates service documentation. -* `service/autoscaling`: Updates service documentation. - -Release v1.4.21 (2016-10-24) -=== - -Service Client Updates ---- -* `service/sms`: AWS Server Migration Service (SMS) is an agentless service which makes it easier and faster for you to migrate thousands of on-premises workloads to AWS. AWS SMS allows you to automate, schedule, and track incremental replications of live server volumes, making it easier for you to coordinate large-scale server migrations. -* `service/ecs`: Updates documentation. - -SDK Feature Updates ---- -* `private/models/api`: Improve code generation of documentation. - -Release v1.4.20 (2016-10-20) -=== - -Service Client Updates ---- -* `service/budgets`: Adds new service, AWS Budgets. -* `service/waf`: Updates service documentation. - -Release v1.4.19 (2016-10-18) -=== - -Service Client Updates ---- -* `service/cloudfront`: Updates service API and documentation. - * Ability to use Amazon CloudFront to deliver your content both via IPv6 and IPv4 using HTTP/HTTPS. -* `service/configservice`: Update service API and documentation. -* `service/iot`: Updates service API and documentation. -* `service/kinesisanalytics`: Updates service API and documentation. - * Whenever Amazon Kinesis Analytics is not able to detect schema for the given streaming source on DiscoverInputSchema API, we would return the raw records that was sampled to detect the schema. -* `service/rds`: Updates service API and documentation. - * Amazon Aurora integrates with other AWS services to allow you to extend your Aurora DB cluster to utilize other capabilities in the AWS cloud. Permission to access other AWS services is granted by creating an IAM role with the necessary permissions, and then associating the role with your DB cluster. - -SDK Feature Updates ---- -* `service/dynamodb/dynamodbattribute`: Add UnmarshalListOfMaps #897 - * Adds support for unmarshaling a list of maps. This is useful for unmarshaling the DynamoDB AttributeValue list of maps returned by APIs like Query and Scan. - -Release v1.4.18 (2016-10-17) -=== - -Service Model Updates ---- -* `service/route53`: Updates service API and documentation. - -Release v1.4.17 -=== - -Service Model Updates ---- -* `service/acm`: Update service API, and documentation. - * This change allows users to import third-party SSL/TLS certificates into ACM. -* `service/elasticbeanstalk`: Update service API, documentation, and pagination. - * Elastic Beanstalk DescribeApplicationVersions API is being updated to support pagination. -* `service/gamelift`: Update service API, and documentation. - * New APIs to protect game developer resource (builds, alias, fleets, instances, game sessions and player sessions) against abuse. - -SDK Features ---- -* `service/s3`: Add support for accelerate with dualstack [#887](https://github.com/aws/aws-sdk-go/issues/887) - -Release v1.4.16 (2016-10-13) -=== - -Service Model Updates ---- -* `service/ecr`: Update Amazon EC2 Container Registry service model - * DescribeImages is a new api used to expose image metadata which today includes image size and image creation timestamp. -* `service/elasticache`: Update Amazon ElastiCache service model - * Elasticache is launching a new major engine release of Redis, 3.2 (providing stability updates and new command sets over 2.8), as well as ElasticSupport for enabling Redis Cluster in 3.2, which provides support for multiple node groups to horizontally scale data, as well as superior engine failover capabilities - -SDK Bug Fixes ---- -* `aws/session`: Skip shared config on read errors [#883](https://github.com/aws/aws-sdk-go/issues/883) -* `aws/signer/v4`: Add support for URL.EscapedPath to signer [#885](https://github.com/aws/aws-sdk-go/issues/885) - -SDK Features ---- -* `private/model/api`: Add docs for errors to API operations [#881](https://github.com/aws/aws-sdk-go/issues/881) -* `private/model/api`: Improve field and waiter doc strings [#879](https://github.com/aws/aws-sdk-go/issues/879) -* `service/dynamodb/dynamodbattribute`: Allow multiple struct tag elements [#886](https://github.com/aws/aws-sdk-go/issues/886) -* Add build tags to internal SDK tools [#880](https://github.com/aws/aws-sdk-go/issues/880) - -Release v1.4.15 (2016-10-06) -=== - -Service Model Updates ---- -* `service/cognitoidentityprovider`: Update Amazon Cognito Identity Provider service model -* `service/devicefarm`: Update AWS Device Farm documentation -* `service/opsworks`: Update AWS OpsWorks service model -* `service/s3`: Update Amazon Simple Storage Service model -* `service/waf`: Update AWS WAF service model - -SDK Bug Fixes ---- -* `aws/request`: Fix HTTP Request Body race condition [#874](https://github.com/aws/aws-sdk-go/issues/874) - -SDK Feature Updates ---- -* `aws/ec2metadata`: Add support for EC2 User Data [#872](https://github.com/aws/aws-sdk-go/issues/872) -* `aws/signer/v4`: Remove logic determining if request needs to be resigned [#876](https://github.com/aws/aws-sdk-go/issues/876) - -Release v1.4.14 (2016-09-29) -=== -* `service/ec2`: api, documentation, and paginators updates. -* `service/s3`: api and documentation updates. - -Release v1.4.13 (2016-09-27) -=== -* `service/codepipeline`: documentation updates. -* `service/cloudformation`: api and documentation updates. -* `service/kms`: documentation updates. -* `service/elasticfilesystem`: documentation updates. -* `service/snowball`: documentation updates. diff --git a/vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md b/vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md deleted file mode 100644 index 8a1927a39ca..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md +++ /dev/null @@ -1,5 +0,0 @@ -### SDK Features - -### SDK Enhancements - -### SDK Bugs diff --git a/vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md b/vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md deleted file mode 100644 index 7c0186f0c9e..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md +++ /dev/null @@ -1,127 +0,0 @@ -Contributing to the AWS SDK for Go - -We work hard to provide a high-quality and useful SDK, and we greatly value -feedback and contributions from our community. Whether it's a bug report, -new feature, correction, or additional documentation, we welcome your issues -and pull requests. Please read through this document before submitting any -issues or pull requests to ensure we have all the necessary information to -effectively respond to your bug report or contribution. - - -## Filing Bug Reports - -You can file bug reports against the SDK on the [GitHub issues][issues] page. - -If you are filing a report for a bug or regression in the SDK, it's extremely -helpful to provide as much information as possible when opening the original -issue. This helps us reproduce and investigate the possible bug without having -to wait for this extra information to be provided. Please read the following -guidelines prior to filing a bug report. - -1. Search through existing [issues][] to ensure that your specific issue has - not yet been reported. If it is a common issue, it is likely there is - already a bug report for your problem. - -2. Ensure that you have tested the latest version of the SDK. Although you - may have an issue against an older version of the SDK, we cannot provide - bug fixes for old versions. It's also possible that the bug may have been - fixed in the latest release. - -3. Provide as much information about your environment, SDK version, and - relevant dependencies as possible. For example, let us know what version - of Go you are using, which and version of the operating system, and the - the environment your code is running in. e.g Container. - -4. Provide a minimal test case that reproduces your issue or any error - information you related to your problem. We can provide feedback much - more quickly if we know what operations you are calling in the SDK. If - you cannot provide a full test case, provide as much code as you can - to help us diagnose the problem. Any relevant information should be provided - as well, like whether this is a persistent issue, or if it only occurs - some of the time. - - -## Submitting Pull Requests - -We are always happy to receive code and documentation contributions to the SDK. -Please be aware of the following notes prior to opening a pull request: - -1. The SDK is released under the [Apache license][license]. Any code you submit - will be released under that license. For substantial contributions, we may - ask you to sign a [Contributor License Agreement (CLA)][cla]. - -2. If you would like to implement support for a significant feature that is not - yet available in the SDK, please talk to us beforehand to avoid any - duplication of effort. - -3. Wherever possible, pull requests should contain tests as appropriate. - Bugfixes should contain tests that exercise the corrected behavior (i.e., the - test should fail without the bugfix and pass with it), and new features - should be accompanied by tests exercising the feature. - -4. Pull requests that contain failing tests will not be merged until the test - failures are addressed. Pull requests that cause a significant drop in the - SDK's test coverage percentage are unlikely to be merged until tests have - been added. - -5. The JSON files under the SDK's `models` folder are sourced from outside the SDK. - Such as `models/apis/ec2/2016-11-15/api.json`. We will not accept pull requests - directly on these models. If you discover an issue with the models please - create a Github [issue](issues) describing the issue. - -### Testing - -To run the tests locally, running the `make unit` command will `go get` the -SDK's testing dependencies, and run vet, link and unit tests for the SDK. - -``` -make unit -``` - -Standard go testing functionality is supported as well. To test SDK code that -is tagged with `codegen` you'll need to set the build tag in the go test -command. The `make unit` command will do this automatically. - -``` -go test -tags codegen ./private/... -``` - -See the `Makefile` for additional testing tags that can be used in testing. - -To test on multiple platform the SDK includes several DockerFiles under the -`awstesting/sandbox` folder, and associated make recipes to to execute -unit testing within environments configured for specific Go versions. - -``` -make sandbox-test-go18 -``` - -To run all sandbox environments use the following make recipe - -``` -# Optionally update the Go tip that will be used during the batch testing -make update-aws-golang-tip - -# Run all SDK tests for supported Go versions in sandboxes -make sandbox-test -``` - -In addition the sandbox environment include make recipes for interactive modes -so you can run command within the Docker container and context of the SDK. - -``` -make sandbox-go18 -``` - -### Changelog - -You can see all release changes in the `CHANGELOG.md` file at the root of the -repository. The release notes added to this file will contain service client -updates, and major SDK changes. - -[issues]: https://github.com/aws/aws-sdk-go/issues -[pr]: https://github.com/aws/aws-sdk-go/pulls -[license]: http://aws.amazon.com/apache2.0/ -[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement -[releasenotes]: https://github.com/aws/aws-sdk-go/releases - diff --git a/vendor/github.com/aws/aws-sdk-go/Makefile b/vendor/github.com/aws/aws-sdk-go/Makefile deleted file mode 100644 index df9803c2a2b..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/Makefile +++ /dev/null @@ -1,180 +0,0 @@ -LINTIGNOREDOT='awstesting/integration.+should not use dot imports' -LINTIGNOREDOC='service/[^/]+/(api|service|waiters)\.go:.+(comment on exported|should have comment or be unexported)' -LINTIGNORECONST='service/[^/]+/(api|service|waiters)\.go:.+(type|struct field|const|func) ([^ ]+) should be ([^ ]+)' -LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)' -LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be ' -LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be ' -LINTIGNOREDEPS='vendor/.+\.go' -LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form' -UNIT_TEST_TAGS="example codegen awsinclude" - -SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src") -SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/") -SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/") -SDK_GO_1_4=$(shell go version | grep "go1.4") -SDK_GO_1_5=$(shell go version | grep "go1.5") -SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''') - -all: get-deps generate unit - -help: - @echo "Please use \`make ' where is one of" - @echo " api_info to print a list of services and versions" - @echo " docs to build SDK documentation" - @echo " build to go build the SDK" - @echo " unit to run unit tests" - @echo " integration to run integration tests" - @echo " performance to run performance tests" - @echo " verify to verify tests" - @echo " lint to lint the SDK" - @echo " vet to vet the SDK" - @echo " generate to go generate and make services" - @echo " gen-test to generate protocol tests" - @echo " gen-services to generate services" - @echo " get-deps to go get the SDK dependencies" - @echo " get-deps-tests to get the SDK's test dependencies" - @echo " get-deps-verify to get the SDK's verification dependencies" - -generate: gen-test gen-endpoints gen-services - -gen-test: gen-protocol-test - -gen-services: - go generate ./service - -gen-protocol-test: - go generate ./private/protocol/... - -gen-endpoints: - go generate ./models/endpoints/ - -build: - @echo "go build SDK and vendor packages" - @go build ${SDK_ONLY_PKGS} - -unit: get-deps-tests build verify - @echo "go test SDK and vendor packages" - @go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS) - -unit-with-race-cover: get-deps-tests build verify - @echo "go test SDK and vendor packages" - @go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS) - -integration: get-deps-tests integ-custom smoke-tests performance - -integ-custom: - go test -tags "integration" ./awstesting/integration/customizations/... - -cleanup-integ: - go run -tags "integration" ./awstesting/cmd/bucket_cleanup/main.go "aws-sdk-go-integration" - -smoke-tests: get-deps-tests - gucumber -go-tags "integration" ./awstesting/integration/smoke - -performance: get-deps-tests - AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance - -sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-gotip - -sandbox-build-go15: - docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" . -sandbox-go15: sandbox-build-go15 - docker run -i -t aws-sdk-go-1.5 bash -sandbox-test-go15: sandbox-build-go15 - docker run -t aws-sdk-go-1.5 - -sandbox-build-go15-novendorexp: - docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5-novendorexp -t "aws-sdk-go-1.5-novendorexp" . -sandbox-go15-novendorexp: sandbox-build-go15-novendorexp - docker run -i -t aws-sdk-go-1.5-novendorexp bash -sandbox-test-go15-novendorexp: sandbox-build-go15-novendorexp - docker run -t aws-sdk-go-1.5-novendorexp - -sandbox-build-go16: - docker build -f ./awstesting/sandbox/Dockerfile.test.go1.6 -t "aws-sdk-go-1.6" . -sandbox-go16: sandbox-build-go16 - docker run -i -t aws-sdk-go-1.6 bash -sandbox-test-go16: sandbox-build-go16 - docker run -t aws-sdk-go-1.6 - -sandbox-build-go17: - docker build -f ./awstesting/sandbox/Dockerfile.test.go1.7 -t "aws-sdk-go-1.7" . -sandbox-go17: sandbox-build-go17 - docker run -i -t aws-sdk-go-1.7 bash -sandbox-test-go17: sandbox-build-go17 - docker run -t aws-sdk-go-1.7 - -sandbox-build-go18: - docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.8" . -sandbox-go18: sandbox-build-go18 - docker run -i -t aws-sdk-go-1.8 bash -sandbox-test-go18: sandbox-build-go18 - docker run -t aws-sdk-go-1.8 - -sandbox-build-gotip: - @echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container" - docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" . -sandbox-gotip: sandbox-build-gotip - docker run -i -t aws-sdk-go-tip bash -sandbox-test-gotip: sandbox-build-gotip - docker run -t aws-sdk-go-tip - -update-aws-golang-tip: - docker build --no-cache=true -f ./awstesting/sandbox/Dockerfile.golang-tip -t "aws-golang:tip" . - -verify: get-deps-verify lint vet - -lint: - @echo "go lint SDK and vendor packages" - @lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \ - lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD} -e ${LINTIGNOREPKGCOMMENT}`; \ - echo "$$lint"; \ - if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi - -SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate) -ifneq (,$(findstring go1.4, ${SDK_GO_VERSION})) - GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION} -else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION})) - GO_VET_CMD=go tool vet --all -shadow -example=false -else - GO_VET_CMD=go tool vet --all -shadow -endif - -vet: - ${GO_VET_CMD} ${SDK_BASE_FOLDERS} - -get-deps: get-deps-tests get-deps-verify - @echo "go get SDK dependencies" - @go get -v $(SDK_ONLY_PKGS) - -get-deps-tests: - @echo "go get SDK testing dependencies" - go get github.com/gucumber/gucumber/cmd/gucumber - go get github.com/stretchr/testify - go get github.com/smartystreets/goconvey - go get golang.org/x/net/html - go get golang.org/x/net/http2 - -get-deps-verify: - @echo "go get SDK verification utilities" - @if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi - -bench: - @echo "go bench SDK packages" - @go test -run NONE -bench . -benchmem -tags 'bench' $(SDK_ONLY_PKGS) - -bench-protocol: - @echo "go bench SDK protocol marshallers" - @go test -run NONE -bench . -benchmem -tags 'bench' ./private/protocol/... - -docs: - @echo "generate SDK docs" - @# This env variable, DOCS, is for internal use - @if [ -z ${AWS_DOC_GEN_TOOL} ]; then\ - rm -rf doc && bundle install && bundle exec yard;\ - else\ - $(AWS_DOC_GEN_TOOL) `pwd`;\ - fi - -api_info: - @go run private/model/cli/api-info/api-info.go diff --git a/vendor/github.com/aws/aws-sdk-go/README.md b/vendor/github.com/aws/aws-sdk-go/README.md deleted file mode 100644 index 559697f66b9..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/README.md +++ /dev/null @@ -1,449 +0,0 @@ -[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt) - -# AWS SDK for Go - -aws-sdk-go is the official AWS SDK for the Go programming language. - -Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK. - -## Installing - -If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder. - - go get -u github.com/aws/aws-sdk-go - -Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`. - - go get -u github.com/aws/aws-sdk-go/aws/... - go get -u github.com/aws/aws-sdk-go/service/... - -If you're looking to retrieve just the SDK without any dependencies use the following command. - - go get -d github.com/aws/aws-sdk-go/ - -These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment. - - rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor - -## Getting Help - -Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests. - -* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag. -* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go). -* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html). -* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new). - -## Opening Issues - -If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate. - -The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner. - -## Reference Documentation - -[`Getting Started Guide`](https://aws.amazon.com/sdk-for-go/) - This document is a general introduction how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The [Service Developer Guide](https://aws.amazon.com/documentation/) will help you get started using specific AWS services. - -[`SDK API Reference Documentation`](https://docs.aws.amazon.com/sdk-for-go/api/) - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters. - -[`Service Developer Guide`](https://aws.amazon.com/documentation/) - Use this documentation to learn how to interface with an AWS service. These are great guides both, if you're getting started with a service, or looking for more information on a service. You should not need this document for coding, though in some cases, services may supply helpful samples that you might want to look out for. - -[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services. - -## Overview of SDK's Packages - -The SDK is composed of two main components, SDK core, and service clients. -The SDK core packages are all available under the aws package at the root of -the SDK. Each client for a supported AWS service is available within its own -package under the service folder at the root of the SDK. - - * aws - SDK core, provides common shared types such as Config, Logger, - and utilities to make working with API parameters easier. - - * awserr - Provides the error interface that the SDK will use for all - errors that occur in the SDK's processing. This includes service API - response errors as well. The Error type is made up of a code and message. - Cast the SDK's returned error type to awserr.Error and call the Code - method to compare returned error to specific error codes. See the package's - documentation for additional values that can be extracted such as RequestID. - - * credentials - Provides the types and built in credentials providers - the SDK will use to retrieve AWS credentials to make API requests with. - Nested under this folder are also additional credentials providers such as - stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles. - - * endpoints - Provides the AWS Regions and Endpoints metadata for the SDK. - Use this to lookup AWS service endpoint information such as which services - are in a region, and what regions a service is in. Constants are also provided - for all region identifiers, e.g UsWest2RegionID for "us-west-2". - - * session - Provides initial default configuration, and load - configuration from external sources such as environment and shared - credentials file. - - * request - Provides the API request sending, and retry logic for the SDK. - This package also includes utilities for defining your own request - retryer, and configuring how the SDK processes the request. - - * service - Clients for AWS services. All services supported by the SDK are - available under this folder. - -## How to Use the SDK's AWS Service Clients - -The SDK includes the Go types and utilities you can use to make requests to -AWS service APIs. Within the service folder at the root of the SDK you'll find -a package for each AWS service the SDK supports. All service clients follows -a common pattern of creation and usage. - -When creating a client for an AWS service you'll first need to have a Session -value constructed. The Session provides shared configuration that can be shared -between your service clients. When service clients are created you can pass -in additional configuration via the aws.Config type to override configuration -provided by in the Session to create service client instances with custom -configuration. - -Once the service's client is created you can use it to make API requests the -AWS service. These clients are safe to use concurrently. - -## Configuring the SDK - -In the AWS SDK for Go, you can configure settings for service clients, such -as the log level and maximum number of retries. Most settings are optional; -however, for each service client, you must specify a region and your credentials. -The SDK uses these values to send requests to the correct AWS region and sign -requests with the correct credentials. You can specify these values as part -of a session or as environment variables. - -See the SDK's [configuration guide][config_guide] for more information. - -See the [session][session_pkg] package documentation for more information on how to use Session -with the SDK. - -See the [Config][config_typ] type in the [aws][aws_pkg] package for more information on configuration -options. - -[config_guide]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html -[session_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ -[config_typ]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config -[aws_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/ - -### Configuring Credentials - -When using the SDK you'll generally need your AWS credentials to authenticate -with AWS services. The SDK supports multiple methods of supporting these -credentials. By default the SDK will source credentials automatically from -its default credential chain. See the session package for more information -on this chain, and how to configure it. The common items in the credential -chain are the following: - - * Environment Credentials - Set of environment variables that are useful - when sub processes are created for specific roles. - - * Shared Credentials file (~/.aws/credentials) - This file stores your - credentials based on a profile name and is useful for local development. - - * EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials - to application running on an EC2 instance. This removes the need to manage - credential files in production. - -Credentials can be configured in code as well by setting the Config's Credentials -value to a custom provider or using one of the providers included with the -SDK to bypass the default credential chain and use a custom one. This is -helpful when you want to instruct the SDK to only use a specific set of -credentials or providers. - -This example creates a credential provider for assuming an IAM role, "myRoleARN" -and configures the S3 service client to use that role for API requests. - -```go - // Initial credentials loaded from SDK's default credential chain. Such as - // the environment, shared credentials (~/.aws/credentials), or EC2 Instance - // Role. These credentials will be used to to make the STS Assume Role API. - sess := session.Must(session.NewSession()) - - // Create the credentials from AssumeRoleProvider to assume the role - // referenced by the "myRoleARN" ARN. - creds := stscreds.NewCredentials(sess, "myRoleArn") - - // Create service client value configured for credentials - // from assumed role. - svc := s3.New(sess, &aws.Config{Credentials: creds})/ -``` - -See the [credentials][credentials_pkg] package documentation for more information on credential -providers included with the SDK, and how to customize the SDK's usage of -credentials. - -The SDK has support for the shared configuration file (~/.aws/config). This -support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1", -or enabling the feature in code when creating a Session via the -Option's SharedConfigState parameter. - -```go - sess := session.Must(session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, - })) -``` - -[credentials_pkg]: ttps://docs.aws.amazon.com/sdk-for-go/api/aws/credentials - -### Configuring AWS Region - -In addition to the credentials you'll need to specify the region the SDK -will use to make AWS API requests to. In the SDK you can specify the region -either with an environment variable, or directly in code when a Session or -service client is created. The last value specified in code wins if the region -is specified multiple ways. - -To set the region via the environment variable set the "AWS_REGION" to the -region you want to the SDK to use. Using this method to set the region will -allow you to run your application in multiple regions without needing additional -code in the application to select the region. - - AWS_REGION=us-west-2 - -The endpoints package includes constants for all regions the SDK knows. The -values are all suffixed with RegionID. These values are helpful, because they -reduce the need to type the region string manually. - -To set the region on a Session use the aws package's Config struct parameter -Region to the AWS region you want the service clients created from the session to -use. This is helpful when you want to create multiple service clients, and -all of the clients make API requests to the same region. - -```go - sess := session.Must(session.NewSession(&aws.Config{ - Region: aws.String(endpoints.UsWest2RegionID), - })) -``` - -See the [endpoints][endpoints_pkg] package for the AWS Regions and Endpoints metadata. - -In addition to setting the region when creating a Session you can also set -the region on a per service client bases. This overrides the region of a -Session. This is helpful when you want to create service clients in specific -regions different from the Session's region. - -```go - svc := s3.New(sess, &aws.Config{ - Region: aws.String(endpoints.UsWest2RegionID), - }) -``` - -See the [Config][config_typ] type in the [aws][aws_pkg] package for more information and additional -options such as setting the Endpoint, and other service client configuration options. - -[endpoints_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/ - -## Making API Requests - -Once the client is created you can make an API request to the service. -Each API method takes a input parameter, and returns the service response -and an error. The SDK provides methods for making the API call in multiple ways. - -In this list we'll use the S3 ListObjects API as an example for the different -ways of making API requests. - - * ListObjects - Base API operation that will make the API request to the service. - - * ListObjectsRequest - API methods suffixed with Request will construct the - API request, but not send it. This is also helpful when you want to get a - presigned URL for a request, and share the presigned URL instead of your - application making the request directly. - - * ListObjectsPages - Same as the base API operation, but uses a callback to - automatically handle pagination of the API's response. - - * ListObjectsWithContext - Same as base API operation, but adds support for - the Context pattern. This is helpful for controlling the canceling of in - flight requests. See the Go standard library context package for more - information. This method also takes request package's Option functional - options as the variadic argument for modifying how the request will be - made, or extracting information from the raw HTTP response. - - * ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for - the Context pattern. Similar to ListObjectsWithContext this method also - takes the request package's Option function option types as the variadic - argument. - -In addition to the API operations the SDK also includes several higher level -methods that abstract checking for and waiting for an AWS resource to be in -a desired state. In this list we'll use WaitUntilBucketExists to demonstrate -the different forms of waiters. - - * WaitUntilBucketExists. - Method to make API request to query an AWS service for - a resource's state. Will return successfully when that state is accomplished. - - * WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds - support for the Context pattern. In addition these methods take request - package's WaiterOptions to configure the waiter, and how underlying request - will be made by the SDK. - -The API method will document which error codes the service might return for -the operation. These errors will also be available as const strings prefixed -with "ErrCode" in the service client's package. If there are no errors listed -in the API's SDK documentation you'll need to consult the AWS service's API -documentation for the errors that could be returned. - -```go - ctx := context.Background() - - result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{ - Bucket: aws.String("my-bucket"), - Key: aws.String("my-key"), - }) - if err != nil { - // Cast err to awserr.Error to handle specific error codes. - aerr, ok := err.(awserr.Error) - if ok && aerr.Code() == s3.ErrCodeNoSuchKey { - // Specific error code handling - } - return err - } - - // Make sure to close the body when done with it for S3 GetObject APIs or - // will leak connections. - defer result.Body.Close() - - fmt.Println("Object Size:", aws.StringValue(result.ContentLength)) -``` - -### API Request Pagination and Resource Waiters - -Pagination helper methods are suffixed with "Pages", and provide the -functionality needed to round trip API page requests. Pagination methods -take a callback function that will be called for each page of the API's response. - -```go - objects := []string{} - err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{ - Bucket: aws.String(myBucket), - }, func(p *s3.ListObjectsOutput, lastPage bool) bool { - for _, o := range p.Contents { - objects = append(objects, aws.StringValue(o.Key)) - } - return true // continue paging - }) - if err != nil { - panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err)) - } - - fmt.Println("Objects in bucket:", objects) -``` - -Waiter helper methods provide the functionality to wait for an AWS resource -state. These methods abstract the logic needed to to check the state of an -AWS resource, and wait until that resource is in a desired state. The waiter -will block until the resource is in the state that is desired, an error occurs, -or the waiter times out. If a resource times out the error code returned will -be request.WaiterResourceNotReadyErrorCode. - -```go - err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{ - Bucket: aws.String(myBucket), - }) - if err != nil { - aerr, ok := err.(awserr.Error) - if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode { - fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist") - } - panic(fmt.Errorf("failed to wait for bucket to exist, %v", err)) - } - fmt.Println("Bucket", myBucket, "exists") -``` - -## Complete SDK Example - -This example shows a complete working Go file which will upload a file to S3 -and use the Context pattern to implement timeout logic that will cancel the -request if it takes too long. This example highlights how to use sessions, -create a service client, make a request, handle the error, and process the -response. - -```go - package main - - import ( - "context" - "flag" - "fmt" - "os" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - ) - - // Uploads a file to S3 given a bucket and object key. Also takes a duration - // value to terminate the update if it doesn't complete within that time. - // - // The AWS Region needs to be provided in the AWS shared config or on the - // environment variable as `AWS_REGION`. Credentials also must be provided - // Will default to shared config file, but can load from environment if provided. - // - // Usage: - // # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail - // go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt - func main() { - var bucket, key string - var timeout time.Duration - - flag.StringVar(&bucket, "b", "", "Bucket name.") - flag.StringVar(&key, "k", "", "Object key name.") - flag.DurationVar(&timeout, "d", 0, "Upload timeout.") - flag.Parse() - - // All clients require a Session. The Session provides the client with - // shared configuration such as region, endpoint, and credentials. A - // Session should be shared where possible to take advantage of - // configuration and credential caching. See the session package for - // more information. - sess := session.Must(session.NewSession()) - - // Create a new instance of the service's client with a Session. - // Optional aws.Config values can also be provided as variadic arguments - // to the New function. This option allows you to provide service - // specific configuration. - svc := s3.New(sess) - - // Create a context with a timeout that will abort the upload if it takes - // more than the passed in timeout. - ctx := context.Background() - var cancelFn func() - if timeout > 0 { - ctx, cancelFn = context.WithTimeout(ctx, timeout) - } - // Ensure the context is canceled to prevent leaking. - // See context package for more information, https://golang.org/pkg/context/ - defer cancelFn() - - // Uploads the object to S3. The Context will interrupt the request if the - // timeout expires. - _, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), - Body: os.Stdin, - }) - if err != nil { - if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode { - // If the SDK can determine the request or retry delay was canceled - // by a context the CanceledErrorCode error code will be returned. - fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err) - } else { - fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err) - } - os.Exit(1) - } - - fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key) - } -``` - -## License - -This SDK is distributed under the -[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0), -see LICENSE.txt and NOTICE.txt for more information. diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go b/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go index e25a460fbaa..63d2df67c63 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go @@ -2,6 +2,7 @@ package client import ( "math/rand" + "strconv" "sync" "time" @@ -38,14 +39,18 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration { minTime := 30 throttle := d.shouldThrottle(r) if throttle { + if delay, ok := getRetryDelay(r); ok { + return delay + } + minTime = 500 } retryCount := r.RetryCount - if retryCount > 13 { - retryCount = 13 - } else if throttle && retryCount > 8 { + if throttle && retryCount > 8 { retryCount = 8 + } else if retryCount > 13 { + retryCount = 13 } delay := (1 << uint(retryCount)) * (seededRand.Intn(minTime) + minTime) @@ -68,12 +73,49 @@ func (d DefaultRetryer) ShouldRetry(r *request.Request) bool { // ShouldThrottle returns true if the request should be throttled. func (d DefaultRetryer) shouldThrottle(r *request.Request) bool { - if r.HTTPResponse.StatusCode == 502 || - r.HTTPResponse.StatusCode == 503 || - r.HTTPResponse.StatusCode == 504 { - return true + switch r.HTTPResponse.StatusCode { + case 429: + case 502: + case 503: + case 504: + default: + return r.IsErrorThrottle() } - return r.IsErrorThrottle() + + return true +} + +// This will look in the Retry-After header, RFC 7231, for how long +// it will wait before attempting another request +func getRetryDelay(r *request.Request) (time.Duration, bool) { + if !canUseRetryAfterHeader(r) { + return 0, false + } + + delayStr := r.HTTPResponse.Header.Get("Retry-After") + if len(delayStr) == 0 { + return 0, false + } + + delay, err := strconv.Atoi(delayStr) + if err != nil { + return 0, false + } + + return time.Duration(delay) * time.Second, true +} + +// Will look at the status code to see if the retry header pertains to +// the status code. +func canUseRetryAfterHeader(r *request.Request) bool { + switch r.HTTPResponse.StatusCode { + case 429: + case 503: + default: + return false + } + + return true } // lockedSource is a thread-safe implementation of rand.Source diff --git a/vendor/github.com/aws/aws-sdk-go/aws/config.go b/vendor/github.com/aws/aws-sdk-go/aws/config.go index ae3a286960d..4fd0d072474 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/config.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/config.go @@ -168,7 +168,7 @@ type Config struct { // EC2MetadataDisableTimeoutOverride *bool - // Instructs the endpiont to be generated for a service client to + // Instructs the endpoint to be generated for a service client to // be the dual stack endpoint. The dual stack endpoint will support // both IPv4 and IPv6 addressing. // diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go b/vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go index e8cf93d2699..8fdda530338 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go @@ -4,9 +4,9 @@ package aws import "time" -// An emptyCtx is a copy of the the Go 1.7 context.emptyCtx type. This -// is copied to provide a 1.6 and 1.5 safe version of context that is compatible -// with Go 1.7's Context. +// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to +// provide a 1.6 and 1.5 safe version of context that is compatible with Go +// 1.7's Context. // // An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. diff --git a/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go b/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go index 3b73a7da7f9..ff5d58e0683 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/convert_types.go @@ -311,6 +311,24 @@ func TimeValue(v *time.Time) time.Time { return time.Time{} } +// SecondsTimeValue converts an int64 pointer to a time.Time value +// representing seconds since Epoch or time.Time{} if the pointer is nil. +func SecondsTimeValue(v *int64) time.Time { + if v != nil { + return time.Unix((*v / 1000), 0) + } + return time.Time{} +} + +// MillisecondsTimeValue converts an int64 pointer to a time.Time value +// representing milliseconds sinch Epoch or time.Time{} if the pointer is nil. +func MillisecondsTimeValue(v *int64) time.Time { + if v != nil { + return time.Unix(0, (*v * 1000000)) + } + return time.Time{} +} + // TimeUnixMilli returns a Unix timestamp in milliseconds from "January 1, 1970 UTC". // The result is undefined if the Unix time cannot be represented by an int64. // Which includes calling TimeUnixMilli on a zero Time is undefined. diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini b/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini deleted file mode 100644 index 7fc91d9d204..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini +++ /dev/null @@ -1,12 +0,0 @@ -[default] -aws_access_key_id = accessKey -aws_secret_access_key = secret -aws_session_token = token - -[no_token] -aws_access_key_id = accessKey -aws_secret_access_key = secret - -[with_colon] -aws_access_key_id: accessKey -aws_secret_access_key: secret diff --git a/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go index 07afe3b8e6d..2cb08182fb0 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go @@ -9,6 +9,7 @@ package defaults import ( "fmt" + "net" "net/http" "net/url" "os" @@ -118,14 +119,43 @@ func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.P return ec2RoleProvider(cfg, handlers) } +var lookupHostFn = net.LookupHost + +func isLoopbackHost(host string) (bool, error) { + ip := net.ParseIP(host) + if ip != nil { + return ip.IsLoopback(), nil + } + + // Host is not an ip, perform lookup + addrs, err := lookupHostFn(host) + if err != nil { + return false, err + } + for _, addr := range addrs { + if !net.ParseIP(addr).IsLoopback() { + return false, nil + } + } + + return true, nil +} + func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider { var errMsg string parsed, err := url.Parse(u) if err != nil { errMsg = fmt.Sprintf("invalid URL, %v", err) - } else if host := aws.URLHostname(parsed); !(host == "localhost" || host == "127.0.0.1") { - errMsg = fmt.Sprintf("invalid host address, %q, only localhost and 127.0.0.1 are valid.", host) + } else { + host := aws.URLHostname(parsed) + if len(host) == 0 { + errMsg = "unable to parse host from local HTTP cred provider URL" + } else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil { + errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr) + } else if !isLoopback { + errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host) + } } if len(errMsg) > 0 { diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index ba0c07b25b1..5470a8c080f 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -24,6 +24,7 @@ const ( EuCentral1RegionID = "eu-central-1" // EU (Frankfurt). EuWest1RegionID = "eu-west-1" // EU (Ireland). EuWest2RegionID = "eu-west-2" // EU (London). + EuWest3RegionID = "eu-west-3" // EU (Paris). SaEast1RegionID = "sa-east-1" // South America (Sao Paulo). UsEast1RegionID = "us-east-1" // US East (N. Virginia). UsEast2RegionID = "us-east-2" // US East (Ohio). @@ -33,7 +34,8 @@ const ( // AWS China partition's regions. const ( - CnNorth1RegionID = "cn-north-1" // China (Beijing). + CnNorth1RegionID = "cn-north-1" // China (Beijing). + CnNorthwest1RegionID = "cn-northwest-1" // China (Ningxia). ) // AWS GovCloud (US) partition's regions. @@ -44,6 +46,7 @@ const ( // Service identifiers const ( AcmServiceID = "acm" // Acm. + ApiPricingServiceID = "api.pricing" // ApiPricing. ApigatewayServiceID = "apigateway" // Apigateway. ApplicationAutoscalingServiceID = "application-autoscaling" // ApplicationAutoscaling. Appstream2ServiceID = "appstream2" // Appstream2. @@ -55,6 +58,7 @@ const ( CloudformationServiceID = "cloudformation" // Cloudformation. CloudfrontServiceID = "cloudfront" // Cloudfront. CloudhsmServiceID = "cloudhsm" // Cloudhsm. + Cloudhsmv2ServiceID = "cloudhsmv2" // Cloudhsmv2. CloudsearchServiceID = "cloudsearch" // Cloudsearch. CloudtrailServiceID = "cloudtrail" // Cloudtrail. CodebuildServiceID = "codebuild" // Codebuild. @@ -68,6 +72,7 @@ const ( ConfigServiceID = "config" // Config. CurServiceID = "cur" // Cur. DatapipelineServiceID = "datapipeline" // Datapipeline. + DaxServiceID = "dax" // Dax. DevicefarmServiceID = "devicefarm" // Devicefarm. DirectconnectServiceID = "directconnect" // Directconnect. DiscoveryServiceID = "discovery" // Discovery. @@ -91,6 +96,7 @@ const ( FirehoseServiceID = "firehose" // Firehose. GameliftServiceID = "gamelift" // Gamelift. GlacierServiceID = "glacier" // Glacier. + GlueServiceID = "glue" // Glue. GreengrassServiceID = "greengrass" // Greengrass. HealthServiceID = "health" // Health. IamServiceID = "iam" // Iam. @@ -106,6 +112,7 @@ const ( MachinelearningServiceID = "machinelearning" // Machinelearning. MarketplacecommerceanalyticsServiceID = "marketplacecommerceanalytics" // Marketplacecommerceanalytics. MeteringMarketplaceServiceID = "metering.marketplace" // MeteringMarketplace. + MghServiceID = "mgh" // Mgh. MobileanalyticsServiceID = "mobileanalytics" // Mobileanalytics. ModelsLexServiceID = "models.lex" // ModelsLex. MonitoringServiceID = "monitoring" // Monitoring. @@ -217,6 +224,9 @@ var awsPartition = partition{ "eu-west-2": region{ Description: "EU (London)", }, + "eu-west-3": region{ + Description: "EU (Paris)", + }, "sa-east-1": region{ Description: "South America (Sao Paulo)", }, @@ -246,6 +256,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -253,6 +264,17 @@ var awsPartition = partition{ "us-west-2": endpoint{}, }, }, + "api.pricing": service{ + Defaults: endpoint{ + CredentialScope: credentialScope{ + Service: "pricing", + }, + }, + Endpoints: endpoints{ + "ap-south-1": endpoint{}, + "us-east-1": endpoint{}, + }, + }, "apigateway": service{ Endpoints: endpoints{ @@ -265,6 +287,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -290,6 +313,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -316,6 +340,8 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -336,6 +362,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -347,6 +374,7 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, + "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, @@ -393,6 +421,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -429,6 +458,22 @@ var awsPartition = partition{ "us-west-2": endpoint{}, }, }, + "cloudhsmv2": service{ + + Endpoints: endpoints{ + "ap-northeast-1": endpoint{}, + "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "ca-central-1": endpoint{}, + "eu-central-1": endpoint{}, + "eu-west-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, + }, + }, "cloudsearch": service{ Endpoints: endpoints{ @@ -456,6 +501,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -467,6 +513,7 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, @@ -510,6 +557,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -521,6 +569,8 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, @@ -537,10 +587,17 @@ var awsPartition = partition{ "codestar": service{ Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, + "ap-northeast-1": endpoint{}, + "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "ca-central-1": endpoint{}, + "eu-central-1": endpoint{}, + "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, }, }, "cognito-identity": service{ @@ -549,6 +606,7 @@ var awsPartition = partition{ "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, @@ -564,6 +622,7 @@ var awsPartition = partition{ "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, @@ -579,6 +638,7 @@ var awsPartition = partition{ "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, @@ -600,6 +660,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -623,6 +684,18 @@ var awsPartition = partition{ "us-west-2": endpoint{}, }, }, + "dax": service{ + + Endpoints: endpoints{ + "ap-northeast-1": endpoint{}, + "ap-south-1": endpoint{}, + "eu-west-1": endpoint{}, + "sa-east-1": endpoint{}, + "us-east-1": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, + }, + }, "devicefarm": service{ Endpoints: endpoints{ @@ -641,6 +714,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -666,6 +740,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -678,14 +753,17 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, + "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, @@ -703,6 +781,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "local": endpoint{ Hostname: "localhost:8000", Protocols: []string{"http"}, @@ -731,6 +810,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -753,12 +833,16 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, + "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, "us-west-1": endpoint{}, @@ -769,12 +853,16 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, + "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, "us-west-1": endpoint{}, @@ -793,6 +881,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -812,6 +901,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -823,6 +913,7 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-southeast-2": endpoint{}, + "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -831,7 +922,7 @@ var awsPartition = partition{ }, "elasticloadbalancing": service{ Defaults: endpoint{ - Protocols: []string{"http", "https"}, + Protocols: []string{"https"}, }, Endpoints: endpoints{ "ap-northeast-1": endpoint{}, @@ -843,6 +934,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -867,6 +959,7 @@ var awsPartition = partition{ }, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{ SSLCommonName: "{service}.{region}.{dnsSuffix}", @@ -919,6 +1012,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -938,6 +1032,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -948,9 +1043,15 @@ var awsPartition = partition{ "firehose": service{ Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-west-2": endpoint{}, + "ap-northeast-1": endpoint{}, + "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "eu-central-1": endpoint{}, + "eu-west-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, }, }, "gamelift": service{ @@ -960,10 +1061,15 @@ var awsPartition = partition{ "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, @@ -975,23 +1081,36 @@ var awsPartition = partition{ "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, + "glue": service{ + + Endpoints: endpoints{ + "ap-northeast-1": endpoint{}, + "eu-west-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, + }, + }, "greengrass": service{ IsRegionalized: boxedTrue, Defaults: endpoint{ Protocols: []string{"https"}, }, Endpoints: endpoints{ + "ap-northeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "us-east-1": endpoint{}, @@ -1039,6 +1158,7 @@ var awsPartition = partition{ "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-2": endpoint{}, + "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "us-east-1": endpoint{}, "us-west-1": endpoint{}, @@ -1076,6 +1196,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1103,6 +1224,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1122,6 +1244,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1156,6 +1279,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1199,6 +1323,12 @@ var awsPartition = partition{ "us-west-2": endpoint{}, }, }, + "mgh": service{ + + Endpoints: endpoints{ + "us-west-2": endpoint{}, + }, + }, "mobileanalytics": service{ Endpoints: endpoints{ @@ -1229,6 +1359,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1257,6 +1388,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1298,10 +1430,21 @@ var awsPartition = partition{ "polly": service{ Endpoints: endpoints{ - "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, + "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "ca-central-1": endpoint{}, + "eu-central-1": endpoint{}, + "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, + "sa-east-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, }, }, "rds": service{ @@ -1316,6 +1459,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{ SSLCommonName: "{service}.{dnsSuffix}", @@ -1337,6 +1481,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1349,6 +1494,7 @@ var awsPartition = partition{ Endpoints: endpoints{ "eu-west-1": endpoint{}, "us-east-1": endpoint{}, + "us-east-2": endpoint{}, "us-west-2": endpoint{}, }, }, @@ -1378,6 +1524,7 @@ var awsPartition = partition{ }, }, Endpoints: endpoints{ + "eu-west-1": endpoint{}, "us-east-1": endpoint{}, }, }, @@ -1393,26 +1540,27 @@ var awsPartition = partition{ }, Endpoints: endpoints{ "ap-northeast-1": endpoint{ - Hostname: "s3-ap-northeast-1.amazonaws.com", + Hostname: "s3.ap-northeast-1.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, "ap-northeast-2": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{ - Hostname: "s3-ap-southeast-1.amazonaws.com", + Hostname: "s3.ap-southeast-1.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, "ap-southeast-2": endpoint{ - Hostname: "s3-ap-southeast-2.amazonaws.com", + Hostname: "s3.ap-southeast-2.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{ - Hostname: "s3-eu-west-1.amazonaws.com", + Hostname: "s3.eu-west-1.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "s3-external-1": endpoint{ Hostname: "s3-external-1.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, @@ -1421,7 +1569,7 @@ var awsPartition = partition{ }, }, "sa-east-1": endpoint{ - Hostname: "s3-sa-east-1.amazonaws.com", + Hostname: "s3.sa-east-1.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, "us-east-1": endpoint{ @@ -1430,11 +1578,11 @@ var awsPartition = partition{ }, "us-east-2": endpoint{}, "us-west-1": endpoint{ - Hostname: "s3-us-west-1.amazonaws.com", + Hostname: "s3.us-west-1.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, "us-west-2": endpoint{ - Hostname: "s3-us-west-2.amazonaws.com", + Hostname: "s3.us-west-2.amazonaws.com", SignatureVersions: []string{"s3", "s3v4"}, }, }, @@ -1461,14 +1609,19 @@ var awsPartition = partition{ Endpoints: endpoints{ "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, + "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, + "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, @@ -1492,19 +1645,24 @@ var awsPartition = partition{ "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-3": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, + "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, "snowball": service{ Endpoints: endpoints{ + "ap-northeast-1": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, + "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, "us-west-1": endpoint{}, @@ -1525,6 +1683,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1547,6 +1706,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{ SSLCommonName: "queue.{dnsSuffix}", @@ -1568,6 +1728,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1582,6 +1743,7 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, "us-west-2": endpoint{}, @@ -1599,6 +1761,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1623,6 +1786,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "local": endpoint{ Hostname: "localhost:8000", Protocols: []string{"http"}, @@ -1661,6 +1825,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-1-fips": endpoint{ @@ -1710,6 +1875,7 @@ var awsPartition = partition{ "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, "sa-east-1": endpoint{}, "us-east-1": endpoint{}, "us-east-2": endpoint{}, @@ -1755,6 +1921,7 @@ var awsPartition = partition{ "ap-northeast-1": endpoint{}, "eu-west-1": endpoint{}, "us-east-1": endpoint{}, + "us-west-1": endpoint{}, "us-west-2": endpoint{}, }, }, @@ -1777,6 +1944,7 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, "us-east-1": endpoint{}, "us-west-2": endpoint{}, }, @@ -1827,30 +1995,62 @@ var awscnPartition = partition{ "cn-north-1": region{ Description: "China (Beijing)", }, + "cn-northwest-1": region{ + Description: "China (Ningxia)", + }, }, Services: services{ + "apigateway": service{ + + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + }, + }, + "application-autoscaling": service{ + Defaults: endpoint{ + Hostname: "autoscaling.{region}.amazonaws.com", + Protocols: []string{"http", "https"}, + CredentialScope: credentialScope{ + Service: "application-autoscaling", + }, + }, + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, "autoscaling": service{ Defaults: endpoint{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "cloudformation": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "cloudtrail": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "codedeploy": service{ + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, + "cognito-identity": service{ + Endpoints: endpoints{ "cn-north-1": endpoint{}, }, @@ -1858,13 +2058,15 @@ var awscnPartition = partition{ "config": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "directconnect": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "dynamodb": service{ @@ -1872,7 +2074,8 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "ec2": service{ @@ -1880,7 +2083,8 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "ec2metadata": service{ @@ -1909,21 +2113,24 @@ var awscnPartition = partition{ "elasticache": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "elasticbeanstalk": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "elasticloadbalancing": service{ Defaults: endpoint{ - Protocols: []string{"http", "https"}, + Protocols: []string{"https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "elasticmapreduce": service{ @@ -1931,13 +2138,21 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, + "es": service{ + + Endpoints: endpoints{ + "cn-northwest-1": endpoint{}, }, }, "events": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "glacier": service{ @@ -1945,7 +2160,8 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "iam": service{ @@ -1961,8 +2177,25 @@ var awscnPartition = partition{ }, }, }, + "iot": service{ + Defaults: endpoint{ + CredentialScope: credentialScope{ + Service: "execute-api", + }, + }, + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + }, + }, "kinesis": service{ + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, + "lambda": service{ + Endpoints: endpoints{ "cn-north-1": endpoint{}, }, @@ -1970,7 +2203,8 @@ var awscnPartition = partition{ "logs": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "monitoring": service{ @@ -1978,19 +2212,22 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "rds": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "redshift": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "s3": service{ @@ -1998,6 +2235,13 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, SignatureVersions: []string{"s3v4"}, }, + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, + "snowball": service{ + Endpoints: endpoints{ "cn-north-1": endpoint{}, }, @@ -2007,7 +2251,8 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "sqs": service{ @@ -2016,13 +2261,15 @@ var awscnPartition = partition{ Protocols: []string{"http", "https"}, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "ssm": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "storagegateway": service{ @@ -2039,19 +2286,22 @@ var awscnPartition = partition{ }, }, Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "sts": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "swf": service{ Endpoints: endpoints{ - "cn-north-1": endpoint{}, + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, }, }, "tagging": service{ @@ -2089,6 +2339,18 @@ var awsusgovPartition = partition{ }, }, Services: services{ + "acm": service{ + + Endpoints: endpoints{ + "us-gov-west-1": endpoint{}, + }, + }, + "apigateway": service{ + + Endpoints: endpoints{ + "us-gov-west-1": endpoint{}, + }, + }, "autoscaling": service{ Endpoints: endpoints{ @@ -2133,10 +2395,22 @@ var awsusgovPartition = partition{ "us-gov-west-1": endpoint{}, }, }, + "dms": service{ + + Endpoints: endpoints{ + "us-gov-west-1": endpoint{}, + }, + }, "dynamodb": service{ Endpoints: endpoints{ "us-gov-west-1": endpoint{}, + "us-gov-west-1-fips": endpoint{ + Hostname: "dynamodb.us-gov-west-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-gov-west-1", + }, + }, }, }, "ec2": service{ @@ -2162,6 +2436,12 @@ var awsusgovPartition = partition{ "us-gov-west-1": endpoint{}, }, }, + "elasticbeanstalk": service{ + + Endpoints: endpoints{ + "us-gov-west-1": endpoint{}, + }, + }, "elasticloadbalancing": service{ Endpoints: endpoints{ @@ -2265,7 +2545,7 @@ var awsusgovPartition = partition{ }, }, "us-gov-west-1": endpoint{ - Hostname: "s3-us-gov-west-1.amazonaws.com", + Hostname: "s3.us-gov-west-1.amazonaws.com", Protocols: []string{"http", "https"}, }, }, @@ -2313,6 +2593,12 @@ var awsusgovPartition = partition{ }, Endpoints: endpoints{ "us-gov-west-1": endpoint{}, + "us-gov-west-1-fips": endpoint{ + Hostname: "dynamodb.us-gov-west-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-gov-west-1", + }, + }, }, }, "sts": service{ diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request.go index 299dc379d1b..5c7db4982c9 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/request.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request.go @@ -24,10 +24,14 @@ const ( // ErrCodeRead is an error that is returned during HTTP reads. ErrCodeRead = "ReadError" - // ErrCodeResponseTimeout is the connection timeout error that is recieved + // ErrCodeResponseTimeout is the connection timeout error that is received // during body reads. ErrCodeResponseTimeout = "ResponseTimeout" + // ErrCodeInvalidPresignExpire is returned when the expire time provided to + // presign is invalid + ErrCodeInvalidPresignExpire = "InvalidPresignExpireError" + // CanceledErrorCode is the error code that will be returned by an // API request that was canceled. Requests given a aws.Context may // return this error when canceled. @@ -42,7 +46,6 @@ type Request struct { Retryer Time time.Time - ExpireTime time.Duration Operation *Operation HTTPRequest *http.Request HTTPResponse *http.Response @@ -60,6 +63,11 @@ type Request struct { LastSignedAt time.Time DisableFollowRedirects bool + // A value greater than 0 instructs the request to be signed as Presigned URL + // You should not set this field directly. Instead use Request's + // Presign or PresignRequest methods. + ExpireTime time.Duration + context aws.Context built bool @@ -104,6 +112,8 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers, err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err) } + SanitizeHostForHeader(httpReq) + r := &Request{ Config: cfg, ClientInfo: clientInfo, @@ -250,34 +260,59 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) { // Presign returns the request's signed URL. Error will be returned // if the signing fails. -func (r *Request) Presign(expireTime time.Duration) (string, error) { - r.ExpireTime = expireTime +// +// It is invalid to create a presigned URL with a expire duration 0 or less. An +// error is returned if expire duration is 0 or less. +func (r *Request) Presign(expire time.Duration) (string, error) { + r = r.copy() + + // Presign requires all headers be hoisted. There is no way to retrieve + // the signed headers not hoisted without this. Making the presigned URL + // useless. r.NotHoist = false + u, _, err := getPresignedURL(r, expire) + return u, err +} + +// PresignRequest behaves just like presign, with the addition of returning a +// set of headers that were signed. +// +// It is invalid to create a presigned URL with a expire duration 0 or less. An +// error is returned if expire duration is 0 or less. +// +// Returns the URL string for the API operation with signature in the query string, +// and the HTTP headers that were included in the signature. These headers must +// be included in any HTTP request made with the presigned URL. +// +// To prevent hoisting any headers to the query string set NotHoist to true on +// this Request value prior to calling PresignRequest. +func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, error) { + r = r.copy() + return getPresignedURL(r, expire) +} + +func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) { + if expire <= 0 { + return "", nil, awserr.New( + ErrCodeInvalidPresignExpire, + "presigned URL requires an expire duration greater than 0", + nil, + ) + } + + r.ExpireTime = expire + if r.Operation.BeforePresignFn != nil { - r = r.copy() - err := r.Operation.BeforePresignFn(r) - if err != nil { - return "", err + if err := r.Operation.BeforePresignFn(r); err != nil { + return "", nil, err } } - r.Sign() - if r.Error != nil { - return "", r.Error + if err := r.Sign(); err != nil { + return "", nil, err } - return r.HTTPRequest.URL.String(), nil -} -// PresignRequest behaves just like presign, but hoists all headers and signs them. -// Also returns the signed hash back to the user -func (r *Request) PresignRequest(expireTime time.Duration) (string, http.Header, error) { - r.ExpireTime = expireTime - r.NotHoist = true - r.Sign() - if r.Error != nil { - return "", nil, r.Error - } return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil } @@ -573,3 +608,72 @@ func shouldRetryCancel(r *Request) bool { errStr != "net/http: request canceled while waiting for connection") } + +// SanitizeHostForHeader removes default port from host and updates request.Host +func SanitizeHostForHeader(r *http.Request) { + host := getHost(r) + port := portOnly(host) + if port != "" && isDefaultPort(r.URL.Scheme, port) { + r.Host = stripPort(host) + } +} + +// Returns host from request +func getHost(r *http.Request) string { + if r.Host != "" { + return r.Host + } + + return r.URL.Host +} + +// Hostname returns u.Host, without any port number. +// +// If Host is an IPv6 literal with a port number, Hostname returns the +// IPv6 literal without the square brackets. IPv6 literals may include +// a zone identifier. +// +// Copied from the Go 1.8 standard library (net/url) +func stripPort(hostport string) string { + colon := strings.IndexByte(hostport, ':') + if colon == -1 { + return hostport + } + if i := strings.IndexByte(hostport, ']'); i != -1 { + return strings.TrimPrefix(hostport[:i], "[") + } + return hostport[:colon] +} + +// Port returns the port part of u.Host, without the leading colon. +// If u.Host doesn't contain a port, Port returns an empty string. +// +// Copied from the Go 1.8 standard library (net/url) +func portOnly(hostport string) string { + colon := strings.IndexByte(hostport, ':') + if colon == -1 { + return "" + } + if i := strings.Index(hostport, "]:"); i != -1 { + return hostport[i+len("]:"):] + } + if strings.Contains(hostport, "]") { + return "" + } + return hostport[colon+len(":"):] +} + +// Returns true if the specified URI is using the standard port +// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs) +func isDefaultPort(scheme, port string) bool { + if port == "" { + return true + } + + lowerCaseScheme := strings.ToLower(scheme) + if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") { + return true + } + + return false +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go b/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go index 2c05dbdc2e1..f35fef213ed 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go @@ -70,8 +70,8 @@ func isCodeExpiredCreds(code string) bool { } var validParentCodes = map[string]struct{}{ - ErrCodeSerialization: struct{}{}, - ErrCodeRead: struct{}{}, + ErrCodeSerialization: {}, + ErrCodeRead: {}, } type temporaryError interface { diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go b/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go index 7357e545acd..f1adcf48198 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go @@ -7,6 +7,9 @@ import ( "github.com/aws/aws-sdk-go/aws/credentials" ) +// EnvProviderName provides a name of the provider when config is loaded from environment. +const EnvProviderName = "EnvConfigCredentials" + // envConfig is a collection of environment values the SDK will read // setup config from. All environment values are optional. But some values // such as credentials require multiple values to be complete or the values @@ -76,7 +79,7 @@ type envConfig struct { SharedConfigFile string // Sets the path to a custom Credentials Authroity (CA) Bundle PEM file - // that the SDK will use instead of the the system's root CA bundle. + // that the SDK will use instead of the system's root CA bundle. // Only use this if you want to configure the SDK to use a custom set // of CAs. // @@ -157,7 +160,7 @@ func envConfigLoad(enableSharedConfig bool) envConfig { if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 { cfg.Creds = credentials.Value{} } else { - cfg.Creds.ProviderName = "EnvConfigCredentials" + cfg.Creds.ProviderName = EnvProviderName } regionKeys := regionEnvKeys diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config b/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config deleted file mode 100644 index e41fe213779..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config +++ /dev/null @@ -1,60 +0,0 @@ -[default] -s3 = - unsupported_key=123 - other_unsupported=abc - -region = default_region - -[profile alt_profile_name] -region = alt_profile_name_region - -[short_profile_name_first] -region = short_profile_name_first_short - -[profile short_profile_name_first] -region = short_profile_name_first_alt - -[partial_creds] -aws_access_key_id = partial_creds_akid - -[complete_creds] -aws_access_key_id = complete_creds_akid -aws_secret_access_key = complete_creds_secret - -[complete_creds_with_token] -aws_access_key_id = complete_creds_with_token_akid -aws_secret_access_key = complete_creds_with_token_secret -aws_session_token = complete_creds_with_token_token - -[full_profile] -aws_access_key_id = full_profile_akid -aws_secret_access_key = full_profile_secret -region = full_profile_region - -[config_file_load_order] -region = shared_config_region -aws_access_key_id = shared_config_akid -aws_secret_access_key = shared_config_secret - -[partial_assume_role] -role_arn = partial_assume_role_role_arn - -[assume_role] -role_arn = assume_role_role_arn -source_profile = complete_creds - -[assume_role_invalid_source_profile] -role_arn = assume_role_invalid_source_profile_role_arn -source_profile = profile_not_exists - -[assume_role_w_creds] -role_arn = assume_role_w_creds_role_arn -source_profile = assume_role_w_creds -external_id = 1234 -role_session_name = assume_role_w_creds_session_name -aws_access_key_id = assume_role_w_creds_akid -aws_secret_access_key = assume_role_w_creds_secret - -[assume_role_wo_creds] -role_arn = assume_role_wo_creds_role_arn -source_profile = assume_role_wo_creds diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_invalid_ini b/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_invalid_ini deleted file mode 100644 index 4db038952af..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_invalid_ini +++ /dev/null @@ -1 +0,0 @@ -[profile_nam diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_other b/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_other deleted file mode 100644 index 615831b1afa..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_other +++ /dev/null @@ -1,17 +0,0 @@ -[default] -region = default_region - -[partial_creds] -aws_access_key_id = AKID - -[profile alt_profile_name] -region = alt_profile_name_region - -[creds_from_credentials] -aws_access_key_id = creds_from_config_akid -aws_secret_access_key = creds_from_config_secret - -[config_file_load_order] -region = shared_config_other_region -aws_access_key_id = shared_config_other_akid -aws_secret_access_key = shared_config_other_secret diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go index d68905acbb1..ccc88b4ac1c 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go @@ -268,7 +268,7 @@ type signingCtx struct { // "X-Amz-Content-Sha256" header with a precomputed value. The signer will // only compute the hash if the request header value is empty. func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) { - return v4.signWithBody(r, body, service, region, 0, signTime) + return v4.signWithBody(r, body, service, region, 0, false, signTime) } // Presign signs AWS v4 requests with the provided body, service name, region @@ -302,10 +302,10 @@ func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region strin // presigned request's signature you can set the "X-Amz-Content-Sha256" // HTTP header and that will be included in the request's signature. func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) { - return v4.signWithBody(r, body, service, region, exp, signTime) + return v4.signWithBody(r, body, service, region, exp, true, signTime) } -func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) { +func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, isPresign bool, signTime time.Time) (http.Header, error) { currentTimeFn := v4.currentTimeFn if currentTimeFn == nil { currentTimeFn = time.Now @@ -317,7 +317,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi Query: r.URL.Query(), Time: signTime, ExpireTime: exp, - isPresign: exp != 0, + isPresign: isPresign, ServiceName: service, Region: region, DisableURIPathEscaping: v4.DisableURIPathEscaping, @@ -339,6 +339,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi return http.Header{}, err } + ctx.sanitizeHostForHeader() ctx.assignAmzQueryValues() ctx.build(v4.DisableHeaderHoisting) @@ -363,6 +364,10 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi return ctx.SignedHeaderVals, nil } +func (ctx *signingCtx) sanitizeHostForHeader() { + request.SanitizeHostForHeader(ctx.Request) +} + func (ctx *signingCtx) handlePresignRemoval() { if !ctx.isPresign { return @@ -467,7 +472,7 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time } signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(), - name, region, req.ExpireTime, signingTime, + name, region, req.ExpireTime, req.ExpireTime > 0, signingTime, ) if err != nil { req.Error = err @@ -502,6 +507,8 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) { ctx.buildTime() // no depends ctx.buildCredentialString() // no depends + ctx.buildBodyDigest() + unsignedHeaders := ctx.Request.Header if ctx.isPresign { if !disableHeaderHoisting { @@ -513,7 +520,6 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) { } } - ctx.buildBodyDigest() ctx.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders) ctx.buildCanonicalString() // depends on canon headers / signed headers ctx.buildStringToSign() // depends on canon string diff --git a/vendor/github.com/aws/aws-sdk-go/aws/version.go b/vendor/github.com/aws/aws-sdk-go/aws/version.go index 971b08bcd06..73ac333a79c 100644 --- a/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.10.18" +const SDKVersion = "1.12.67" diff --git a/vendor/github.com/aws/aws-sdk-go/doc.go b/vendor/github.com/aws/aws-sdk-go/doc.go deleted file mode 100644 index 3e077e51da9..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/doc.go +++ /dev/null @@ -1,405 +0,0 @@ -// Package sdk is the official AWS SDK for the Go programming language. -// -// The AWS SDK for Go provides APIs and utilities that developers can use to -// build Go applications that use AWS services, such as Amazon Elastic Compute -// Cloud (Amazon EC2) and Amazon Simple Storage Service (Amazon S3). -// -// The SDK removes the complexity of coding directly against a web service -// interface. It hides a lot of the lower-level plumbing, such as authentication, -// request retries, and error handling. -// -// The SDK also includes helpful utilities on top of the AWS APIs that add additional -// capabilities and functionality. For example, the Amazon S3 Download and Upload -// Manager will automatically split up large objects into multiple parts and -// transfer them concurrently. -// -// See the s3manager package documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/ -// -// Getting More Information -// -// Checkout the Getting Started Guide and API Reference Docs detailed the SDK's -// components and details on each AWS client the SDK supports. -// -// The Getting Started Guide provides examples and detailed description of how -// to get setup with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/welcome.html -// -// The API Reference Docs include a detailed breakdown of the SDK's components -// such as utilities and AWS clients. Use this as a reference of the Go types -// included with the SDK, such as AWS clients, API operations, and API parameters. -// https://docs.aws.amazon.com/sdk-for-go/api/ -// -// Overview of SDK's Packages -// -// The SDK is composed of two main components, SDK core, and service clients. -// The SDK core packages are all available under the aws package at the root of -// the SDK. Each client for a supported AWS service is available within its own -// package under the service folder at the root of the SDK. -// -// * aws - SDK core, provides common shared types such as Config, Logger, -// and utilities to make working with API parameters easier. -// -// * awserr - Provides the error interface that the SDK will use for all -// errors that occur in the SDK's processing. This includes service API -// response errors as well. The Error type is made up of a code and message. -// Cast the SDK's returned error type to awserr.Error and call the Code -// method to compare returned error to specific error codes. See the package's -// documentation for additional values that can be extracted such as RequestId. -// -// * credentials - Provides the types and built in credentials providers -// the SDK will use to retrieve AWS credentials to make API requests with. -// Nested under this folder are also additional credentials providers such as -// stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles. -// -// * endpoints - Provides the AWS Regions and Endpoints metadata for the SDK. -// Use this to lookup AWS service endpoint information such as which services -// are in a region, and what regions a service is in. Constants are also provided -// for all region identifiers, e.g UsWest2RegionID for "us-west-2". -// -// * session - Provides initial default configuration, and load -// configuration from external sources such as environment and shared -// credentials file. -// -// * request - Provides the API request sending, and retry logic for the SDK. -// This package also includes utilities for defining your own request -// retryer, and configuring how the SDK processes the request. -// -// * service - Clients for AWS services. All services supported by the SDK are -// available under this folder. -// -// How to Use the SDK's AWS Service Clients -// -// The SDK includes the Go types and utilities you can use to make requests to -// AWS service APIs. Within the service folder at the root of the SDK you'll find -// a package for each AWS service the SDK supports. All service clients follows -// a common pattern of creation and usage. -// -// When creating a client for an AWS service you'll first need to have a Session -// value constructed. The Session provides shared configuration that can be shared -// between your service clients. When service clients are created you can pass -// in additional configuration via the aws.Config type to override configuration -// provided by in the Session to create service client instances with custom -// configuration. -// -// Once the service's client is created you can use it to make API requests the -// AWS service. These clients are safe to use concurrently. -// -// Configuring the SDK -// -// In the AWS SDK for Go, you can configure settings for service clients, such -// as the log level and maximum number of retries. Most settings are optional; -// however, for each service client, you must specify a region and your credentials. -// The SDK uses these values to send requests to the correct AWS region and sign -// requests with the correct credentials. You can specify these values as part -// of a session or as environment variables. -// -// See the SDK's configuration guide for more information. -// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html -// -// See the session package documentation for more information on how to use Session -// with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ -// -// See the Config type in the aws package for more information on configuration -// options. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config -// -// Configuring Credentials -// -// When using the SDK you'll generally need your AWS credentials to authenticate -// with AWS services. The SDK supports multiple methods of supporting these -// credentials. By default the SDK will source credentials automatically from -// its default credential chain. See the session package for more information -// on this chain, and how to configure it. The common items in the credential -// chain are the following: -// -// * Environment Credentials - Set of environment variables that are useful -// when sub processes are created for specific roles. -// -// * Shared Credentials file (~/.aws/credentials) - This file stores your -// credentials based on a profile name and is useful for local development. -// -// * EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials -// to application running on an EC2 instance. This removes the need to manage -// credential files in production. -// -// Credentials can be configured in code as well by setting the Config's Credentials -// value to a custom provider or using one of the providers included with the -// SDK to bypass the default credential chain and use a custom one. This is -// helpful when you want to instruct the SDK to only use a specific set of -// credentials or providers. -// -// This example creates a credential provider for assuming an IAM role, "myRoleARN" -// and configures the S3 service client to use that role for API requests. -// -// // Initial credentials loaded from SDK's default credential chain. Such as -// // the environment, shared credentials (~/.aws/credentials), or EC2 Instance -// // Role. These credentials will be used to to make the STS Assume Role API. -// sess := session.Must(session.NewSession()) -// -// // Create the credentials from AssumeRoleProvider to assume the role -// // referenced by the "myRoleARN" ARN. -// creds := stscreds.NewCredentials(sess, "myRoleArn") -// -// // Create service client value configured for credentials -// // from assumed role. -// svc := s3.New(sess, &aws.Config{Credentials: creds})/ -// -// See the credentials package documentation for more information on credential -// providers included with the SDK, and how to customize the SDK's usage of -// credentials. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials -// -// The SDK has support for the shared configuration file (~/.aws/config). This -// support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1", -// or enabling the feature in code when creating a Session via the -// Option's SharedConfigState parameter. -// -// sess := session.Must(session.NewSessionWithOptions(session.Options{ -// SharedConfigState: session.SharedConfigEnable, -// })) -// -// Configuring AWS Region -// -// In addition to the credentials you'll need to specify the region the SDK -// will use to make AWS API requests to. In the SDK you can specify the region -// either with an environment variable, or directly in code when a Session or -// service client is created. The last value specified in code wins if the region -// is specified multiple ways. -// -// To set the region via the environment variable set the "AWS_REGION" to the -// region you want to the SDK to use. Using this method to set the region will -// allow you to run your application in multiple regions without needing additional -// code in the application to select the region. -// -// AWS_REGION=us-west-2 -// -// The endpoints package includes constants for all regions the SDK knows. The -// values are all suffixed with RegionID. These values are helpful, because they -// reduce the need to type the region string manually. -// -// To set the region on a Session use the aws package's Config struct parameter -// Region to the AWS region you want the service clients created from the session to -// use. This is helpful when you want to create multiple service clients, and -// all of the clients make API requests to the same region. -// -// sess := session.Must(session.NewSession(&aws.Config{ -// Region: aws.String(endpoints.UsWest2RegionID), -// })) -// -// See the endpoints package for the AWS Regions and Endpoints metadata. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/ -// -// In addition to setting the region when creating a Session you can also set -// the region on a per service client bases. This overrides the region of a -// Session. This is helpful when you want to create service clients in specific -// regions different from the Session's region. -// -// svc := s3.New(sess, &aws.Config{ -// Region: aws.String(ednpoints.UsWest2RegionID), -// }) -// -// See the Config type in the aws package for more information and additional -// options such as setting the Endpoint, and other service client configuration options. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config -// -// Making API Requests -// -// Once the client is created you can make an API request to the service. -// Each API method takes a input parameter, and returns the service response -// and an error. The SDK provides methods for making the API call in multiple ways. -// -// In this list we'll use the S3 ListObjects API as an example for the different -// ways of making API requests. -// -// * ListObjects - Base API operation that will make the API request to the service. -// -// * ListObjectsRequest - API methods suffixed with Request will construct the -// API request, but not send it. This is also helpful when you want to get a -// presigned URL for a request, and share the presigned URL instead of your -// application making the request directly. -// -// * ListObjectsPages - Same as the base API operation, but uses a callback to -// automatically handle pagination of the API's response. -// -// * ListObjectsWithContext - Same as base API operation, but adds support for -// the Context pattern. This is helpful for controlling the canceling of in -// flight requests. See the Go standard library context package for more -// information. This method also takes request package's Option functional -// options as the variadic argument for modifying how the request will be -// made, or extracting information from the raw HTTP response. -// -// * ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for -// the Context pattern. Similar to ListObjectsWithContext this method also -// takes the request package's Option function option types as the variadic -// argument. -// -// In addition to the API operations the SDK also includes several higher level -// methods that abstract checking for and waiting for an AWS resource to be in -// a desired state. In this list we'll use WaitUntilBucketExists to demonstrate -// the different forms of waiters. -// -// * WaitUntilBucketExists. - Method to make API request to query an AWS service for -// a resource's state. Will return successfully when that state is accomplished. -// -// * WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds -// support for the Context pattern. In addition these methods take request -// package's WaiterOptions to configure the waiter, and how underlying request -// will be made by the SDK. -// -// The API method will document which error codes the service might return for -// the operation. These errors will also be available as const strings prefixed -// with "ErrCode" in the service client's package. If there are no errors listed -// in the API's SDK documentation you'll need to consult the AWS service's API -// documentation for the errors that could be returned. -// -// ctx := context.Background() -// -// result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{ -// Bucket: aws.String("my-bucket"), -// Key: aws.String("my-key"), -// }) -// if err != nil { -// // Cast err to awserr.Error to handle specific error codes. -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == s3.ErrCodeNoSuchKey { -// // Specific error code handling -// } -// return err -// } -// -// // Make sure to close the body when done with it for S3 GetObject APIs or -// // will leak connections. -// defer result.Body.Close() -// -// fmt.Println("Object Size:", aws.StringValue(result.ContentLength)) -// -// API Request Pagination and Resource Waiters -// -// Pagination helper methods are suffixed with "Pages", and provide the -// functionality needed to round trip API page requests. Pagination methods -// take a callback function that will be called for each page of the API's response. -// -// objects := []string{} -// err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{ -// Bucket: aws.String(myBucket), -// }, func(p *s3.ListObjectsOutput, lastPage bool) bool { -// for _, o := range p.Contents { -// objects = append(objects, aws.StringValue(o.Key)) -// } -// return true // continue paging -// }) -// if err != nil { -// panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err)) -// } -// -// fmt.Println("Objects in bucket:", objects) -// -// Waiter helper methods provide the functionality to wait for an AWS resource -// state. These methods abstract the logic needed to to check the state of an -// AWS resource, and wait until that resource is in a desired state. The waiter -// will block until the resource is in the state that is desired, an error occurs, -// or the waiter times out. If a resource times out the error code returned will -// be request.WaiterResourceNotReadyErrorCode. -// -// err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{ -// Bucket: aws.String(myBucket), -// }) -// if err != nil { -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode { -// fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist") -// } -// panic(fmt.Errorf("failed to wait for bucket to exist, %v", err)) -// } -// fmt.Println("Bucket", myBucket, "exists") -// -// Complete SDK Example -// -// This example shows a complete working Go file which will upload a file to S3 -// and use the Context pattern to implement timeout logic that will cancel the -// request if it takes too long. This example highlights how to use sessions, -// create a service client, make a request, handle the error, and process the -// response. -// -// package main -// -// import ( -// "context" -// "flag" -// "fmt" -// "os" -// "time" -// -// "github.com/aws/aws-sdk-go/aws" -// "github.com/aws/aws-sdk-go/aws/awserr" -// "github.com/aws/aws-sdk-go/aws/request" -// "github.com/aws/aws-sdk-go/aws/session" -// "github.com/aws/aws-sdk-go/service/s3" -// ) -// -// // Uploads a file to S3 given a bucket and object key. Also takes a duration -// // value to terminate the update if it doesn't complete within that time. -// // -// // The AWS Region needs to be provided in the AWS shared config or on the -// // environment variable as `AWS_REGION`. Credentials also must be provided -// // Will default to shared config file, but can load from environment if provided. -// // -// // Usage: -// // # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail -// // go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt -// func main() { -// var bucket, key string -// var timeout time.Duration -// -// flag.StringVar(&bucket, "b", "", "Bucket name.") -// flag.StringVar(&key, "k", "", "Object key name.") -// flag.DurationVar(&timeout, "d", 0, "Upload timeout.") -// flag.Parse() -// -// // All clients require a Session. The Session provides the client with -// // shared configuration such as region, endpoint, and credentials. A -// // Session should be shared where possible to take advantage of -// // configuration and credential caching. See the session package for -// // more information. -// sess := session.Must(session.NewSession()) -// -// // Create a new instance of the service's client with a Session. -// // Optional aws.Config values can also be provided as variadic arguments -// // to the New function. This option allows you to provide service -// // specific configuration. -// svc := s3.New(sess) -// -// // Create a context with a timeout that will abort the upload if it takes -// // more than the passed in timeout. -// ctx := context.Background() -// var cancelFn func() -// if timeout > 0 { -// ctx, cancelFn = context.WithTimeout(ctx, timeout) -// } -// // Ensure the context is canceled to prevent leaking. -// // See context package for more information, https://golang.org/pkg/context/ -// defer cancelFn() -// -// // Uploads the object to S3. The Context will interrupt the request if the -// // timeout expires. -// _, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{ -// Bucket: aws.String(bucket), -// Key: aws.String(key), -// Body: os.Stdin, -// }) -// if err != nil { -// if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode { -// // If the SDK can determine the request or retry delay was canceled -// // by a context the CanceledErrorCode error code will be returned. -// fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err) -// } else { -// fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err) -// } -// os.Exit(1) -// } -// -// fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key) -// } -package sdk diff --git a/vendor/github.com/aws/aws-sdk-go/private/README.md b/vendor/github.com/aws/aws-sdk-go/private/README.md deleted file mode 100644 index 5bdb4c50ac2..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/README.md +++ /dev/null @@ -1,4 +0,0 @@ -## AWS SDK for Go Private packages ## -`private` is a collection of packages used internally by the SDK, and is subject to have breaking changes. This package is not `internal` so that if you really need to use its functionality, and understand breaking changes will be made, you are able to. - -These packages will be refactored in the future so that the API generator and model parsers are exposed cleanly on their own. Making it easier for you to generate your own code based on the API models. diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/api.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/api.go deleted file mode 100644 index 46e54f859b3..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/api.go +++ /dev/null @@ -1,800 +0,0 @@ -// +build codegen - -// Package api represents API abstractions for rendering service generated files. -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "path" - "path/filepath" - "regexp" - "sort" - "strings" - "text/template" -) - -// An API defines a service API's definition. and logic to serialize the definition. -type API struct { - Metadata Metadata - Operations map[string]*Operation - Shapes map[string]*Shape - Waiters []Waiter - Documentation string - Examples Examples - - // Set to true to avoid removing unused shapes - NoRemoveUnusedShapes bool - - // Set to true to avoid renaming to 'Input/Output' postfixed shapes - NoRenameToplevelShapes bool - - // Set to true to ignore service/request init methods (for testing) - NoInitMethods bool - - // Set to true to ignore String() and GoString methods (for generated tests) - NoStringerMethods bool - - // Set to true to not generate API service name constants - NoConstServiceNames bool - - // Set to true to not generate validation shapes - NoValidataShapeMethods bool - - // Set to true to not generate struct field accessors - NoGenStructFieldAccessors bool - - SvcClientImportPath string - - initialized bool - imports map[string]bool - name string - path string - - BaseCrosslinkURL string -} - -// A Metadata is the metadata about an API's definition. -type Metadata struct { - APIVersion string - EndpointPrefix string - SigningName string - ServiceAbbreviation string - ServiceFullName string - SignatureVersion string - JSONVersion string - TargetPrefix string - Protocol string - UID string - EndpointsID string - - NoResolveEndpoint bool -} - -var serviceAliases map[string]string - -func Bootstrap() error { - b, err := ioutil.ReadFile(filepath.Join("..", "models", "customizations", "service-aliases.json")) - if err != nil { - return err - } - - return json.Unmarshal(b, &serviceAliases) -} - -// PackageName name of the API package -func (a *API) PackageName() string { - return strings.ToLower(a.StructName()) -} - -// InterfacePackageName returns the package name for the interface. -func (a *API) InterfacePackageName() string { - return a.PackageName() + "iface" -} - -var nameRegex = regexp.MustCompile(`^Amazon|AWS\s*|\(.*|\s+|\W+`) - -// StructName returns the struct name for a given API. -func (a *API) StructName() string { - if a.name == "" { - name := a.Metadata.ServiceAbbreviation - if name == "" { - name = a.Metadata.ServiceFullName - } - - name = nameRegex.ReplaceAllString(name, "") - - a.name = name - if name, ok := serviceAliases[strings.ToLower(name)]; ok { - a.name = name - } - } - return a.name -} - -// UseInitMethods returns if the service's init method should be rendered. -func (a *API) UseInitMethods() bool { - return !a.NoInitMethods -} - -// NiceName returns the human friendly API name. -func (a *API) NiceName() string { - if a.Metadata.ServiceAbbreviation != "" { - return a.Metadata.ServiceAbbreviation - } - return a.Metadata.ServiceFullName -} - -// ProtocolPackage returns the package name of the protocol this API uses. -func (a *API) ProtocolPackage() string { - switch a.Metadata.Protocol { - case "json": - return "jsonrpc" - case "ec2": - return "ec2query" - default: - return strings.Replace(a.Metadata.Protocol, "-", "", -1) - } -} - -// OperationNames returns a slice of API operations supported. -func (a *API) OperationNames() []string { - i, names := 0, make([]string, len(a.Operations)) - for n := range a.Operations { - names[i] = n - i++ - } - sort.Strings(names) - return names -} - -// OperationList returns a slice of API operation pointers -func (a *API) OperationList() []*Operation { - list := make([]*Operation, len(a.Operations)) - for i, n := range a.OperationNames() { - list[i] = a.Operations[n] - } - return list -} - -// OperationHasOutputPlaceholder returns if any of the API operation input -// or output shapes are place holders. -func (a *API) OperationHasOutputPlaceholder() bool { - for _, op := range a.Operations { - if op.OutputRef.Shape.Placeholder { - return true - } - } - return false -} - -// ShapeNames returns a slice of names for each shape used by the API. -func (a *API) ShapeNames() []string { - i, names := 0, make([]string, len(a.Shapes)) - for n := range a.Shapes { - names[i] = n - i++ - } - sort.Strings(names) - return names -} - -// ShapeList returns a slice of shape pointers used by the API. -// -// Will exclude error shapes from the list of shapes returned. -func (a *API) ShapeList() []*Shape { - list := make([]*Shape, 0, len(a.Shapes)) - for _, n := range a.ShapeNames() { - // Ignore error shapes in list - if s := a.Shapes[n]; !s.IsError { - list = append(list, s) - } - } - return list -} - -// ShapeListErrors returns a list of the errors defined by the API model -func (a *API) ShapeListErrors() []*Shape { - list := []*Shape{} - for _, n := range a.ShapeNames() { - // Ignore error shapes in list - if s := a.Shapes[n]; s.IsError { - list = append(list, s) - } - } - return list -} - -// resetImports resets the import map to default values. -func (a *API) resetImports() { - a.imports = map[string]bool{ - "github.com/aws/aws-sdk-go/aws": true, - } -} - -// importsGoCode returns the generated Go import code. -func (a *API) importsGoCode() string { - if len(a.imports) == 0 { - return "" - } - - corePkgs, extPkgs := []string{}, []string{} - for i := range a.imports { - if strings.Contains(i, ".") { - extPkgs = append(extPkgs, i) - } else { - corePkgs = append(corePkgs, i) - } - } - sort.Strings(corePkgs) - sort.Strings(extPkgs) - - code := "import (\n" - for _, i := range corePkgs { - code += fmt.Sprintf("\t%q\n", i) - } - if len(corePkgs) > 0 { - code += "\n" - } - for _, i := range extPkgs { - code += fmt.Sprintf("\t%q\n", i) - } - code += ")\n\n" - return code -} - -// A tplAPI is the top level template for the API -var tplAPI = template.Must(template.New("api").Parse(` -{{ range $_, $o := .OperationList }} -{{ $o.GoCode }} - -{{ end }} - -{{ range $_, $s := .ShapeList }} -{{ if and $s.IsInternal (eq $s.Type "structure") }}{{ $s.GoCode }}{{ end }} - -{{ end }} - -{{ range $_, $s := .ShapeList }} -{{ if $s.IsEnum }}{{ $s.GoCode }}{{ end }} - -{{ end }} -`)) - -// APIGoCode renders the API in Go code. Returning it as a string -func (a *API) APIGoCode() string { - a.resetImports() - a.imports["github.com/aws/aws-sdk-go/aws/awsutil"] = true - a.imports["github.com/aws/aws-sdk-go/aws/request"] = true - if a.OperationHasOutputPlaceholder() { - a.imports["github.com/aws/aws-sdk-go/private/protocol/"+a.ProtocolPackage()] = true - a.imports["github.com/aws/aws-sdk-go/private/protocol"] = true - } - - for _, op := range a.Operations { - if op.AuthType == "none" { - a.imports["github.com/aws/aws-sdk-go/aws/credentials"] = true - break - } - } - - var buf bytes.Buffer - err := tplAPI.Execute(&buf, a) - if err != nil { - panic(err) - } - - code := a.importsGoCode() + strings.TrimSpace(buf.String()) - return code -} - -var noCrossLinkServices = map[string]struct{}{ - "apigateway": struct{}{}, - "budgets": struct{}{}, - "cloudsearch": struct{}{}, - "cloudsearchdomain": struct{}{}, - "discovery": struct{}{}, - "elastictranscoder": struct{}{}, - "es": struct{}{}, - "glacier": struct{}{}, - "importexport": struct{}{}, - "iot": struct{}{}, - "iot-data": struct{}{}, - "lambda": struct{}{}, - "machinelearning": struct{}{}, - "rekognition": struct{}{}, - "sdb": struct{}{}, - "swf": struct{}{}, -} - -func GetCrosslinkURL(baseURL, name, uid string, params ...string) string { - _, ok := noCrossLinkServices[strings.ToLower(name)] - if uid != "" && baseURL != "" && !ok { - return strings.Join(append([]string{baseURL, "goto", "WebAPI", uid}, params...), "/") - } - return "" -} - -func (a *API) APIName() string { - return a.name -} - -var tplServiceDoc = template.Must(template.New("service docs").Funcs(template.FuncMap{ - "GetCrosslinkURL": GetCrosslinkURL, -}). - Parse(` -// Package {{ .PackageName }} provides the client and types for making API -// requests to {{ .Metadata.ServiceFullName }}. -{{ if .Documentation -}} -// -{{ .Documentation }} -{{ end -}} -{{ $crosslinkURL := GetCrosslinkURL $.BaseCrosslinkURL $.APIName $.Metadata.UID -}} -{{ if $crosslinkURL -}} -// -// See {{ $crosslinkURL }} for more information on this service. -{{ end -}} -// -// See {{ .PackageName }} package documentation for more information. -// https://docs.aws.amazon.com/sdk-for-go/api/service/{{ .PackageName }}/ -// -// Using the Client -// -// To use the client for {{ .Metadata.ServiceFullName }} you will first need -// to create a new instance of it. -// -// When creating a client for an AWS service you'll first need to have a Session -// already created. The Session provides configuration that can be shared -// between multiple service clients. Additional configuration can be applied to -// the Session and service's client when they are constructed. The aws package's -// Config type contains several fields such as Region for the AWS Region the -// client should make API requests too. The optional Config value can be provided -// as the variadic argument for Sessions and client creation. -// -// Once the service's client is created you can use it to make API requests the -// AWS service. These clients are safe to use concurrently. -// -// // Create a session to share configuration, and load external configuration. -// sess := session.Must(session.NewSession()) -// -// // Create the service's client with the session. -// svc := {{ .PackageName }}.New(sess) -// -// See the SDK's documentation for more information on how to use service clients. -// https://docs.aws.amazon.com/sdk-for-go/api/ -// -// See aws package's Config type for more information on configuration options. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config -// -// See the {{ .Metadata.ServiceFullName }} client {{ .StructName }} for more -// information on creating the service's client. -// https://docs.aws.amazon.com/sdk-for-go/api/service/{{ .PackageName }}/#New -// -{{ $opts := .OperationNames -}} -{{ $optName := index $opts 0 -}} -{{ $opt := index .Operations $optName -}} -{{ $optInputName := $opt.InputRef.GoTypeWithPkgName -}} -// Once the client is created you can make an API request to the service. -// Each API method takes a input parameter, and returns the service response -// and an error. -// -// The API method will document which error codes the service can be returned -// by the operation if the service models the API operation's errors. These -// errors will also be available as const strings prefixed with "ErrCode". -// -// result, err := svc.{{ $opt.ExportedName }}(params) -// if err != nil { -// // Cast err to awserr.Error to handle specific error codes. -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == { -// // Specific error code handling -// } -// return err -// } -// -// fmt.Println("{{ $optName }} result:") -// fmt.Println(result) -// -// Using the Client with Context -// -// The service's client also provides methods to make API requests with a Context -// value. This allows you to control the timeout, and cancellation of pending -// requests. These methods also take request Option as variadic parameter to apply -// additional configuration to the API request. -// -// ctx := context.Background() -// -// result, err := svc.{{ $opt.ExportedName }}WithContext(ctx, params) -// -// See the request package documentation for more information on using Context pattern -// with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/ -`)) - -// A tplService defines the template for the service generated code. -var tplService = template.Must(template.New("service").Funcs(template.FuncMap{ - "ServiceNameValue": func(a *API) string { - if a.NoConstServiceNames { - return fmt.Sprintf("%q", a.Metadata.EndpointPrefix) - } - return "ServiceName" - }, - "EndpointsIDConstValue": func(a *API) string { - if a.NoConstServiceNames { - return fmt.Sprintf("%q", a.Metadata.EndpointPrefix) - } - if a.Metadata.EndpointPrefix == a.Metadata.EndpointsID { - return "ServiceName" - } - return fmt.Sprintf("%q", a.Metadata.EndpointsID) - }, - "EndpointsIDValue": func(a *API) string { - if a.NoConstServiceNames { - return fmt.Sprintf("%q", a.Metadata.EndpointPrefix) - } - - return "EndpointsID" - }, -}).Parse(` -// {{ .StructName }} provides the API operation methods for making requests to -// {{ .Metadata.ServiceFullName }}. See this package's package overview docs -// for details on the service. -// -// {{ .StructName }} methods are safe to use concurrently. It is not safe to -// modify mutate any of the struct's properties though. -type {{ .StructName }} struct { - *client.Client -} - -{{ if .UseInitMethods }}// Used for custom client initialization logic -var initClient func(*client.Client) - -// Used for custom request initialization logic -var initRequest func(*request.Request) -{{ end }} - - -{{ if not .NoConstServiceNames -}} -// Service information constants -const ( - ServiceName = "{{ .Metadata.EndpointPrefix }}" // Service endpoint prefix API calls made to. - EndpointsID = {{ EndpointsIDConstValue . }} // Service ID for Regions and Endpoints metadata. -) -{{- end }} - -// New creates a new instance of the {{ .StructName }} client with a session. -// If additional configuration is needed for the client instance use the optional -// aws.Config parameter to add your extra config. -// -// Example: -// // Create a {{ .StructName }} client from just a session. -// svc := {{ .PackageName }}.New(mySession) -// -// // Create a {{ .StructName }} client with additional configuration -// svc := {{ .PackageName }}.New(mySession, aws.NewConfig().WithRegion("us-west-2")) -func New(p client.ConfigProvider, cfgs ...*aws.Config) *{{ .StructName }} { - {{ if .Metadata.NoResolveEndpoint -}} - var c client.Config - if v, ok := p.(client.ConfigNoResolveEndpointProvider); ok { - c = v.ClientConfigNoResolveEndpoint(cfgs...) - } else { - c = p.ClientConfig({{ EndpointsIDValue . }}, cfgs...) - } - {{- else -}} - c := p.ClientConfig({{ EndpointsIDValue . }}, cfgs...) - {{- end }} - return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) -} - -// newClient creates, initializes and returns a new service client instance. -func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *{{ .StructName }} { - {{- if .Metadata.SigningName }} - if len(signingName) == 0 { - signingName = "{{ .Metadata.SigningName }}" - } - {{- end }} - svc := &{{ .StructName }}{ - Client: client.New( - cfg, - metadata.ClientInfo{ - ServiceName: {{ ServiceNameValue . }}, - SigningName: signingName, - SigningRegion: signingRegion, - Endpoint: endpoint, - APIVersion: "{{ .Metadata.APIVersion }}", - {{ if .Metadata.JSONVersion -}} - JSONVersion: "{{ .Metadata.JSONVersion }}", - {{- end }} - {{ if .Metadata.TargetPrefix -}} - TargetPrefix: "{{ .Metadata.TargetPrefix }}", - {{- end }} - }, - handlers, - ), - } - - // Handlers - svc.Handlers.Sign.PushBackNamed({{if eq .Metadata.SignatureVersion "v2"}}v2{{else}}v4{{end}}.SignRequestHandler) - {{- if eq .Metadata.SignatureVersion "v2" }} - svc.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) - {{- end }} - svc.Handlers.Build.PushBackNamed({{ .ProtocolPackage }}.BuildHandler) - svc.Handlers.Unmarshal.PushBackNamed({{ .ProtocolPackage }}.UnmarshalHandler) - svc.Handlers.UnmarshalMeta.PushBackNamed({{ .ProtocolPackage }}.UnmarshalMetaHandler) - svc.Handlers.UnmarshalError.PushBackNamed({{ .ProtocolPackage }}.UnmarshalErrorHandler) - - {{ if .UseInitMethods }}// Run custom client initialization if present - if initClient != nil { - initClient(svc.Client) - } - {{ end }} - - return svc -} - -// newRequest creates a new request for a {{ .StructName }} operation and runs any -// custom request initialization. -func (c *{{ .StructName }}) newRequest(op *request.Operation, params, data interface{}) *request.Request { - req := c.NewRequest(op, params, data) - - {{ if .UseInitMethods }}// Run custom request initialization if present - if initRequest != nil { - initRequest(req) - } - {{ end }} - - return req -} -`)) - -// ServicePackageDoc generates the contents of the doc file for the service. -// -// Will also read in the custom doc templates for the service if found. -func (a *API) ServicePackageDoc() string { - a.imports = map[string]bool{} - - var buf bytes.Buffer - if err := tplServiceDoc.Execute(&buf, a); err != nil { - panic(err) - } - - return buf.String() -} - -// ServiceGoCode renders service go code. Returning it as a string. -func (a *API) ServiceGoCode() string { - a.resetImports() - a.imports["github.com/aws/aws-sdk-go/aws/client"] = true - a.imports["github.com/aws/aws-sdk-go/aws/client/metadata"] = true - a.imports["github.com/aws/aws-sdk-go/aws/request"] = true - if a.Metadata.SignatureVersion == "v2" { - a.imports["github.com/aws/aws-sdk-go/private/signer/v2"] = true - a.imports["github.com/aws/aws-sdk-go/aws/corehandlers"] = true - } else { - a.imports["github.com/aws/aws-sdk-go/aws/signer/v4"] = true - } - a.imports["github.com/aws/aws-sdk-go/private/protocol/"+a.ProtocolPackage()] = true - - var buf bytes.Buffer - err := tplService.Execute(&buf, a) - if err != nil { - panic(err) - } - - code := a.importsGoCode() + buf.String() - return code -} - -// ExampleGoCode renders service example code. Returning it as a string. -func (a *API) ExampleGoCode() string { - exs := []string{} - imports := map[string]bool{} - for _, o := range a.OperationList() { - o.imports = map[string]bool{} - exs = append(exs, o.Example()) - for k, v := range o.imports { - imports[k] = v - } - } - - code := fmt.Sprintf("import (\n%q\n%q\n%q\n\n%q\n%q\n%q\n", - "bytes", - "fmt", - "time", - "github.com/aws/aws-sdk-go/aws", - "github.com/aws/aws-sdk-go/aws/session", - path.Join(a.SvcClientImportPath, a.PackageName()), - ) - for k, _ := range imports { - code += fmt.Sprintf("%q\n", k) - } - code += ")\n\n" - code += "var _ time.Duration\nvar _ bytes.Buffer\n\n" - code += strings.Join(exs, "\n\n") - return code -} - -// A tplInterface defines the template for the service interface type. -var tplInterface = template.Must(template.New("interface").Parse(` -// {{ .StructName }}API provides an interface to enable mocking the -// {{ .PackageName }}.{{ .StructName }} service client's API operation, -// paginators, and waiters. This make unit testing your code that calls out -// to the SDK's service client's calls easier. -// -// The best way to use this interface is so the SDK's service client's calls -// can be stubbed out for unit testing your code with the SDK without needing -// to inject custom request handlers into the the SDK's request pipeline. -// -// // myFunc uses an SDK service client to make a request to -// // {{.Metadata.ServiceFullName}}. {{ $opts := .OperationList }}{{ $opt := index $opts 0 }} -// func myFunc(svc {{ .InterfacePackageName }}.{{ .StructName }}API) bool { -// // Make svc.{{ $opt.ExportedName }} request -// } -// -// func main() { -// sess := session.New() -// svc := {{ .PackageName }}.New(sess) -// -// myFunc(svc) -// } -// -// In your _test.go file: -// -// // Define a mock struct to be used in your unit tests of myFunc. -// type mock{{ .StructName }}Client struct { -// {{ .InterfacePackageName }}.{{ .StructName }}API -// } -// func (m *mock{{ .StructName }}Client) {{ $opt.ExportedName }}(input {{ $opt.InputRef.GoTypeWithPkgName }}) ({{ $opt.OutputRef.GoTypeWithPkgName }}, error) { -// // mock response/functionality -// } -// -// func TestMyFunc(t *testing.T) { -// // Setup Test -// mockSvc := &mock{{ .StructName }}Client{} -// -// myfunc(mockSvc) -// -// // Verify myFunc's functionality -// } -// -// It is important to note that this interface will have breaking changes -// when the service model is updated and adds new API operations, paginators, -// and waiters. Its suggested to use the pattern above for testing, or using -// tooling to generate mocks to satisfy the interfaces. -type {{ .StructName }}API interface { - {{ range $_, $o := .OperationList }} - {{ $o.InterfaceSignature }} - {{ end }} - {{ range $_, $w := .Waiters }} - {{ $w.InterfaceSignature }} - {{ end }} -} - -var _ {{ .StructName }}API = (*{{ .PackageName }}.{{ .StructName }})(nil) -`)) - -// InterfaceGoCode returns the go code for the service's API operations as an -// interface{}. Assumes that the interface is being created in a different -// package than the service API's package. -func (a *API) InterfaceGoCode() string { - a.resetImports() - a.imports = map[string]bool{ - "github.com/aws/aws-sdk-go/aws": true, - "github.com/aws/aws-sdk-go/aws/request": true, - path.Join(a.SvcClientImportPath, a.PackageName()): true, - } - - var buf bytes.Buffer - err := tplInterface.Execute(&buf, a) - - if err != nil { - panic(err) - } - - code := a.importsGoCode() + strings.TrimSpace(buf.String()) - return code -} - -// NewAPIGoCodeWithPkgName returns a string of instantiating the API prefixed -// with its package name. Takes a string depicting the Config. -func (a *API) NewAPIGoCodeWithPkgName(cfg string) string { - return fmt.Sprintf("%s.New(%s)", a.PackageName(), cfg) -} - -// computes the validation chain for all input shapes -func (a *API) addShapeValidations() { - for _, o := range a.Operations { - resolveShapeValidations(o.InputRef.Shape) - } -} - -// Updates the source shape and all nested shapes with the validations that -// could possibly be needed. -func resolveShapeValidations(s *Shape, ancestry ...*Shape) { - for _, a := range ancestry { - if a == s { - return - } - } - - children := []string{} - for _, name := range s.MemberNames() { - ref := s.MemberRefs[name] - - if s.IsRequired(name) && !s.Validations.Has(ref, ShapeValidationRequired) { - s.Validations = append(s.Validations, ShapeValidation{ - Name: name, Ref: ref, Type: ShapeValidationRequired, - }) - } - - if ref.Shape.Min != 0 && !s.Validations.Has(ref, ShapeValidationMinVal) { - s.Validations = append(s.Validations, ShapeValidation{ - Name: name, Ref: ref, Type: ShapeValidationMinVal, - }) - } - - switch ref.Shape.Type { - case "map", "list", "structure": - children = append(children, name) - } - } - - ancestry = append(ancestry, s) - for _, name := range children { - ref := s.MemberRefs[name] - // Since this is a grab bag we will just continue since - // we can't validate because we don't know the valued shape. - if ref.JSONValue { - continue - } - - nestedShape := ref.Shape.NestedShape() - - var v *ShapeValidation - if len(nestedShape.Validations) > 0 { - v = &ShapeValidation{ - Name: name, Ref: ref, Type: ShapeValidationNested, - } - } else { - resolveShapeValidations(nestedShape, ancestry...) - if len(nestedShape.Validations) > 0 { - v = &ShapeValidation{ - Name: name, Ref: ref, Type: ShapeValidationNested, - } - } - } - - if v != nil && !s.Validations.Has(v.Ref, v.Type) { - s.Validations = append(s.Validations, *v) - } - } - ancestry = ancestry[:len(ancestry)-1] -} - -// A tplAPIErrors is the top level template for the API -var tplAPIErrors = template.Must(template.New("api").Parse(` -const ( -{{ range $_, $s := $.ShapeListErrors }} - // {{ $s.ErrorCodeName }} for service response error code - // {{ printf "%q" $s.ErrorName }}. - {{ if $s.Docstring -}} - // - {{ $s.Docstring }} - {{ end -}} - {{ $s.ErrorCodeName }} = {{ printf "%q" $s.ErrorName }} -{{ end }} -) -`)) - -func (a *API) APIErrorsGoCode() string { - var buf bytes.Buffer - err := tplAPIErrors.Execute(&buf, a) - - if err != nil { - panic(err) - } - - return strings.TrimSpace(buf.String()) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/customization_passes.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/customization_passes.go deleted file mode 100644 index 9a441a3163f..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/customization_passes.go +++ /dev/null @@ -1,172 +0,0 @@ -// +build codegen - -package api - -import ( - "io/ioutil" - "path/filepath" - "strings" -) - -type service struct { - srcName string - dstName string - - serviceVersion string -} - -var mergeServices = map[string]service{ - "dynamodbstreams": service{ - dstName: "dynamodb", - srcName: "streams.dynamodb", - }, - "wafregional": service{ - dstName: "waf", - srcName: "waf-regional", - serviceVersion: "2015-08-24", - }, -} - -// customizationPasses Executes customization logic for the API by package name. -func (a *API) customizationPasses() { - var svcCustomizations = map[string]func(*API){ - "s3": s3Customizations, - "cloudfront": cloudfrontCustomizations, - "rds": rdsCustomizations, - - // Disable endpoint resolving for services that require customer - // to provide endpoint them selves. - "cloudsearchdomain": disableEndpointResolving, - "iotdataplane": disableEndpointResolving, - } - - for k, _ := range mergeServices { - svcCustomizations[k] = mergeServicesCustomizations - } - - if fn := svcCustomizations[a.PackageName()]; fn != nil { - fn(a) - } -} - -// s3Customizations customizes the API generation to replace values specific to S3. -func s3Customizations(a *API) { - var strExpires *Shape - - for name, s := range a.Shapes { - // Remove ContentMD5 members - if _, ok := s.MemberRefs["ContentMD5"]; ok { - delete(s.MemberRefs, "ContentMD5") - } - - for _, refName := range []string{"Bucket", "SSECustomerKey", "CopySourceSSECustomerKey"} { - if ref, ok := s.MemberRefs[refName]; ok { - ref.GenerateGetter = true - } - } - - // Expires should be a string not time.Time since the format is not - // enforced by S3, and any value can be set to this field outside of the SDK. - if strings.HasSuffix(name, "Output") { - if ref, ok := s.MemberRefs["Expires"]; ok { - if strExpires == nil { - newShape := *ref.Shape - strExpires = &newShape - strExpires.Type = "string" - strExpires.refs = []*ShapeRef{} - } - ref.Shape.removeRef(ref) - ref.Shape = strExpires - ref.Shape.refs = append(ref.Shape.refs, &s.MemberRef) - } - } - } - s3CustRemoveHeadObjectModeledErrors(a) -} - -// S3 HeadObject API call incorrect models NoSuchKey as valid -// error code that can be returned. This operation does not -// return error codes, all error codes are derived from HTTP -// status codes. -// -// aws/aws-sdk-go#1208 -func s3CustRemoveHeadObjectModeledErrors(a *API) { - op, ok := a.Operations["HeadObject"] - if !ok { - return - } - op.Documentation += ` -// -// See http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#RESTErrorResponses -// for more information on returned errors.` - op.ErrorRefs = []ShapeRef{} -} - -// cloudfrontCustomizations customized the API generation to replace values -// specific to CloudFront. -func cloudfrontCustomizations(a *API) { - // MaxItems members should always be integers - for _, s := range a.Shapes { - if ref, ok := s.MemberRefs["MaxItems"]; ok { - ref.ShapeName = "Integer" - ref.Shape = a.Shapes["Integer"] - } - } -} - -// mergeServicesCustomizations references any duplicate shapes from DynamoDB -func mergeServicesCustomizations(a *API) { - info := mergeServices[a.PackageName()] - - p := strings.Replace(a.path, info.srcName, info.dstName, -1) - - if info.serviceVersion != "" { - index := strings.LastIndex(p, "/") - files, _ := ioutil.ReadDir(p[:index]) - if len(files) > 1 { - panic("New version was introduced") - } - p = p[:index] + "/" + info.serviceVersion - } - - file := filepath.Join(p, "api-2.json") - - serviceAPI := API{} - serviceAPI.Attach(file) - serviceAPI.Setup() - - for n := range a.Shapes { - if _, ok := serviceAPI.Shapes[n]; ok { - a.Shapes[n].resolvePkg = "github.com/aws/aws-sdk-go/service/" + info.dstName - } - } -} - -// rdsCustomizations are customization for the service/rds. This adds non-modeled fields used for presigning. -func rdsCustomizations(a *API) { - inputs := []string{ - "CopyDBSnapshotInput", - "CreateDBInstanceReadReplicaInput", - "CopyDBClusterSnapshotInput", - "CreateDBClusterInput", - } - for _, input := range inputs { - if ref, ok := a.Shapes[input]; ok { - ref.MemberRefs["SourceRegion"] = &ShapeRef{ - Documentation: docstring(`SourceRegion is the source region where the resource exists. This is not sent over the wire and is only used for presigning. This value should always have the same region as the source ARN.`), - ShapeName: "String", - Shape: a.Shapes["String"], - Ignore: true, - } - ref.MemberRefs["DestinationRegion"] = &ShapeRef{ - Documentation: docstring(`DestinationRegion is used for presigning the request to a given region.`), - ShapeName: "String", - Shape: a.Shapes["String"], - } - } - } -} - -func disableEndpointResolving(a *API) { - a.Metadata.NoResolveEndpoint = true -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/docstring.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/docstring.go deleted file mode 100644 index ae0c692b1ac..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/docstring.go +++ /dev/null @@ -1,411 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "html" - "os" - "regexp" - "strings" - - xhtml "golang.org/x/net/html" -) - -type apiDocumentation struct { - *API - Operations map[string]string - Service string - Shapes map[string]shapeDocumentation -} - -type shapeDocumentation struct { - Base string - Refs map[string]string -} - -// AttachDocs attaches documentation from a JSON filename. -func (a *API) AttachDocs(filename string) { - d := apiDocumentation{API: a} - - f, err := os.Open(filename) - defer f.Close() - if err != nil { - panic(err) - } - err = json.NewDecoder(f).Decode(&d) - if err != nil { - panic(err) - } - - d.setup() - -} - -func (d *apiDocumentation) setup() { - d.API.Documentation = docstring(d.Service) - - for op, doc := range d.Operations { - d.API.Operations[op].Documentation = docstring(doc) - } - - for shape, info := range d.Shapes { - if sh := d.API.Shapes[shape]; sh != nil { - sh.Documentation = docstring(info.Base) - } - - for ref, doc := range info.Refs { - if doc == "" { - continue - } - - parts := strings.Split(ref, "$") - if len(parts) != 2 { - fmt.Fprintf(os.Stderr, "Shape Doc %s has unexpected reference format, %q\n", shape, ref) - continue - } - if sh := d.API.Shapes[parts[0]]; sh != nil { - if m := sh.MemberRefs[parts[1]]; m != nil { - m.Documentation = docstring(doc) - } - } - } - } -} - -var reNewline = regexp.MustCompile(`\r?\n`) -var reMultiSpace = regexp.MustCompile(`\s+`) -var reComments = regexp.MustCompile(``) -var reFullnameBlock = regexp.MustCompile(`(.+?)<\/fullname>`) -var reFullname = regexp.MustCompile(`(.*?)`) -var reExamples = regexp.MustCompile(`.+?<\/examples?>`) -var reEndNL = regexp.MustCompile(`\n+$`) - -// docstring rewrites a string to insert godocs formatting. -func docstring(doc string) string { - doc = strings.TrimSpace(doc) - if doc == "" { - return "" - } - - doc = reNewline.ReplaceAllString(doc, "") - doc = reMultiSpace.ReplaceAllString(doc, " ") - doc = reComments.ReplaceAllString(doc, "") - - var fullname string - parts := reFullnameBlock.FindStringSubmatch(doc) - if len(parts) > 1 { - fullname = parts[1] - } - // Remove full name block from doc string - doc = reFullname.ReplaceAllString(doc, "") - - doc = reExamples.ReplaceAllString(doc, "") - doc = generateDoc(doc) - doc = reEndNL.ReplaceAllString(doc, "") - doc = html.UnescapeString(doc) - - // Replace doc with full name if doc is empty. - doc = strings.TrimSpace(doc) - if len(doc) == 0 { - doc = fullname - } - - return commentify(doc) -} - -const ( - indent = " " -) - -// style is what we want to prefix a string with. -// For instance,
  • Foo
  • Bar
  • , will generate -// * Foo -// * Bar -var style = map[string]string{ - "ul": indent + "* ", - "li": indent + "* ", - "code": indent, - "pre": indent, -} - -// commentify converts a string to a Go comment -func commentify(doc string) string { - if len(doc) == 0 { - return "" - } - - lines := strings.Split(doc, "\n") - out := make([]string, 0, len(lines)) - for i := 0; i < len(lines); i++ { - line := lines[i] - - if i > 0 && line == "" && lines[i-1] == "" { - continue - } - out = append(out, line) - } - - if len(out) > 0 { - out[0] = "// " + out[0] - return strings.Join(out, "\n// ") - } - return "" -} - -// wrap returns a rewritten version of text to have line breaks -// at approximately length characters. Line breaks will only be -// inserted into whitespace. -func wrap(text string, length int, isIndented bool) string { - var buf bytes.Buffer - var last rune - var lastNL bool - var col int - - for _, c := range text { - switch c { - case '\r': // ignore this - continue // and also don't track `last` - case '\n': // ignore this too, but reset col - if col >= length || last == '\n' { - buf.WriteString("\n") - } - buf.WriteString("\n") - col = 0 - case ' ', '\t': // opportunity to split - if col >= length { - buf.WriteByte('\n') - col = 0 - if isIndented { - buf.WriteString(indent) - col += 3 - } - } else { - // We only want to write a leading space if the col is greater than zero. - // This will provide the proper spacing for documentation. - buf.WriteRune(c) - col++ // count column - } - default: - buf.WriteRune(c) - col++ - } - lastNL = c == '\n' - _ = lastNL - last = c - } - return buf.String() -} - -type tagInfo struct { - tag string - key string - val string - txt string - raw string - closingTag bool -} - -// generateDoc will generate the proper doc string for html encoded or plain text doc entries. -func generateDoc(htmlSrc string) string { - tokenizer := xhtml.NewTokenizer(strings.NewReader(htmlSrc)) - tokens := buildTokenArray(tokenizer) - scopes := findScopes(tokens) - return walk(scopes) -} - -func buildTokenArray(tokenizer *xhtml.Tokenizer) []tagInfo { - tokens := []tagInfo{} - for tt := tokenizer.Next(); tt != xhtml.ErrorToken; tt = tokenizer.Next() { - switch tt { - case xhtml.TextToken: - txt := string(tokenizer.Text()) - if len(tokens) == 0 { - info := tagInfo{ - raw: txt, - } - tokens = append(tokens, info) - } - tn, _ := tokenizer.TagName() - key, val, _ := tokenizer.TagAttr() - info := tagInfo{ - tag: string(tn), - key: string(key), - val: string(val), - txt: txt, - } - tokens = append(tokens, info) - case xhtml.StartTagToken: - tn, _ := tokenizer.TagName() - key, val, _ := tokenizer.TagAttr() - info := tagInfo{ - tag: string(tn), - key: string(key), - val: string(val), - } - tokens = append(tokens, info) - case xhtml.SelfClosingTagToken, xhtml.EndTagToken: - tn, _ := tokenizer.TagName() - key, val, _ := tokenizer.TagAttr() - info := tagInfo{ - tag: string(tn), - key: string(key), - val: string(val), - closingTag: true, - } - tokens = append(tokens, info) - } - } - return tokens -} - -// walk is used to traverse each scoped block. These scoped -// blocks will act as blocked text where we do most of our -// text manipulation. -func walk(scopes [][]tagInfo) string { - doc := "" - // Documentation will be chunked by scopes. - // Meaning, for each scope will be divided by one or more newlines. - for _, scope := range scopes { - indentStr, isIndented := priorityIndentation(scope) - block := "" - href := "" - after := false - level := 0 - lastTag := "" - for _, token := range scope { - if token.closingTag { - endl := closeTag(token, level) - block += endl - level-- - lastTag = "" - } else if token.txt == "" { - if token.val != "" { - href, after = formatText(token, "") - } - if level == 1 && isIndented { - block += indentStr - } - level++ - lastTag = token.tag - } else { - if token.txt != " " { - str, _ := formatText(token, lastTag) - block += str - if after { - block += href - after = false - } - } else { - fmt.Println(token.tag) - str, _ := formatText(tagInfo{}, lastTag) - block += str - } - } - } - if !isIndented { - block = strings.TrimPrefix(block, " ") - } - block = wrap(block, 72, isIndented) - doc += block - } - return doc -} - -// closeTag will divide up the blocks of documentation to be formated properly. -func closeTag(token tagInfo, level int) string { - switch token.tag { - case "pre", "li", "div": - return "\n" - case "p", "h1", "h2", "h3", "h4", "h5", "h6": - return "\n\n" - case "code": - // indented code is only at the 0th level. - if level == 0 { - return "\n" - } - } - return "" -} - -// formatText will format any sort of text based off of a tag. It will also return -// a boolean to add the string after the text token. -func formatText(token tagInfo, lastTag string) (string, bool) { - switch token.tag { - case "a": - if token.val != "" { - return fmt.Sprintf(" (%s)", token.val), true - } - } - - // We don't care about a single space nor no text. - if len(token.txt) == 0 || token.txt == " " { - return "", false - } - - // Here we want to indent code blocks that are newlines - if lastTag == "code" { - // Greater than one, because we don't care about newlines in the beginning - block := "" - if lines := strings.Split(token.txt, "\n"); len(lines) > 1 { - for _, line := range lines { - block += indent + line - } - block += "\n" - return block, false - } - } - return token.txt, false -} - -// This is a parser to check what type of indention is needed. -func priorityIndentation(blocks []tagInfo) (string, bool) { - if len(blocks) == 0 { - return "", false - } - - v, ok := style[blocks[0].tag] - return v, ok -} - -// Divides into scopes based off levels. -// For instance, -//

    Testing123

    • Foo
    -// This has 2 scopes, the

    and

      -func findScopes(tokens []tagInfo) [][]tagInfo { - level := 0 - scope := []tagInfo{} - scopes := [][]tagInfo{} - for _, token := range tokens { - // we will clear empty tagged tokens from the array - txt := strings.TrimSpace(token.txt) - tag := strings.TrimSpace(token.tag) - if len(txt) == 0 && len(tag) == 0 { - continue - } - - scope = append(scope, token) - - // If it is a closing tag then we check what level - // we are on. If it is 0, then that means we have found a - // scoped block. - if token.closingTag { - level-- - if level == 0 { - scopes = append(scopes, scope) - scope = []tagInfo{} - } - // Check opening tags and increment the level - } else if token.txt == "" { - level++ - } - } - // In this case, we did not run into a closing tag. This would mean - // we have plaintext for documentation. - if len(scopes) == 0 { - scopes = append(scopes, scope) - } - return scopes -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/example.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/example.go deleted file mode 100644 index ad790399076..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/example.go +++ /dev/null @@ -1,318 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "sort" - "strings" - "text/template" - - "github.com/aws/aws-sdk-go/private/util" -) - -type Examples map[string][]Example - -// ExamplesDefinition is the structural representation of the examples-1.json file -type ExamplesDefinition struct { - *API `json:"-"` - Examples Examples `json:"examples"` -} - -// Example is a single entry within the examples-1.json file. -type Example struct { - API *API `json:"-"` - Operation *Operation `json:"-"` - OperationName string `json:"-"` - Index string `json:"-"` - Builder examplesBuilder `json:"-"` - VisitedErrors map[string]struct{} `json:"-"` - Title string `json:"title"` - Description string `json:"description"` - ID string `json:"id"` - Comments Comments `json:"comments"` - Input map[string]interface{} `json:"input"` - Output map[string]interface{} `json:"output"` -} - -type Comments struct { - Input map[string]interface{} `json:"input"` - Output map[string]interface{} `json:"output"` -} - -var exampleFuncMap = template.FuncMap{ - "commentify": commentify, - "wrap": wrap, - "generateExampleInput": generateExampleInput, - "generateTypes": generateTypes, -} - -var exampleCustomizations = map[string]template.FuncMap{} - -var exampleTmpls = template.Must(template.New("example").Funcs(exampleFuncMap).Parse(` -{{ generateTypes . }} -{{ commentify (wrap .Title 80 false) }} -// -{{ commentify (wrap .Description 80 false) }} -func Example{{ .API.StructName }}_{{ .MethodName }}() { - svc := {{ .API.PackageName }}.New(session.New()) - input := &{{ .Operation.InputRef.Shape.GoTypeWithPkgNameElem }} { - {{ generateExampleInput . -}} - } - - result, err := svc.{{ .OperationName }}(input) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - {{ range $_, $ref := .Operation.ErrorRefs -}} - {{ if not ($.HasVisitedError $ref) -}} - case {{ .API.PackageName }}.{{ $ref.Shape.ErrorCodeName }}: - fmt.Println({{ .API.PackageName }}.{{ $ref.Shape.ErrorCodeName }}, aerr.Error()) - {{ end -}} - {{ end -}} - default: - fmt.Println(aerr.Error()) - } - } else { - // Print the error, cast err to awserr.Error to get the Code and - // Message from an error. - fmt.Println(err.Error()) - } - return - } - - fmt.Println(result) -} -`)) - -// Names will return the name of the example. This will also be the name of the operation -// that is to be tested. -func (exs Examples) Names() []string { - names := make([]string, 0, len(exs)) - for k := range exs { - names = append(names, k) - } - - sort.Strings(names) - return names -} - -func (exs Examples) GoCode() string { - buf := bytes.NewBuffer(nil) - for _, opName := range exs.Names() { - examples := exs[opName] - for _, ex := range examples { - buf.WriteString(util.GoFmt(ex.GoCode())) - buf.WriteString("\n") - } - } - return buf.String() -} - -// ExampleCode will generate the example code for the given Example shape. -// TODO: Can delete -func (ex Example) GoCode() string { - var buf bytes.Buffer - m := exampleFuncMap - if fMap, ok := exampleCustomizations[ex.API.PackageName()]; ok { - m = fMap - } - tmpl := exampleTmpls.Funcs(m) - if err := tmpl.ExecuteTemplate(&buf, "example", &ex); err != nil { - panic(err) - } - - return strings.TrimSpace(buf.String()) -} - -func generateExampleInput(ex Example) string { - if ex.Operation.HasInput() { - return ex.Builder.BuildShape(&ex.Operation.InputRef, ex.Input, false) - } - return "" -} - -// generateTypes will generate no types for default examples, but customizations may -// require their own defined types. -func generateTypes(ex Example) string { - return "" -} - -// correctType will cast the value to the correct type when printing the string. -// This is due to the json decoder choosing numbers to be floats, but the shape may -// actually be an int. To counter this, we pass the shape's type and properly do the -// casting here. -func correctType(memName string, t string, value interface{}) string { - if value == nil { - return "" - } - - v := "" - switch value.(type) { - case string: - v = value.(string) - case int: - v = fmt.Sprintf("%d", value.(int)) - case float64: - if t == "integer" || t == "long" || t == "int64" { - v = fmt.Sprintf("%d", int(value.(float64))) - } else { - v = fmt.Sprintf("%f", value.(float64)) - } - case bool: - v = fmt.Sprintf("%t", value.(bool)) - } - - return convertToCorrectType(memName, t, v) -} - -func convertToCorrectType(memName, t, v string) string { - return fmt.Sprintf("%s: %s,\n", memName, getValue(t, v)) -} - -func getValue(t, v string) string { - if t[0] == '*' { - t = t[1:] - } - switch t { - case "string": - return fmt.Sprintf("aws.String(%q)", v) - case "integer", "long", "int64": - return fmt.Sprintf("aws.Int64(%s)", v) - case "float", "float64", "double": - return fmt.Sprintf("aws.Float64(%s)", v) - case "boolean": - return fmt.Sprintf("aws.Bool(%s)", v) - default: - panic("Unsupported type: " + t) - } -} - -// AttachExamples will create a new ExamplesDefinition from the examples file -// and reference the API object. -func (a *API) AttachExamples(filename string) { - p := ExamplesDefinition{API: a} - - f, err := os.Open(filename) - defer f.Close() - if err != nil { - panic(err) - } - err = json.NewDecoder(f).Decode(&p) - if err != nil { - panic(err) - } - - p.setup() -} - -var examplesBuilderCustomizations = map[string]examplesBuilder{ - "wafregional": wafregionalExamplesBuilder{}, -} - -func (p *ExamplesDefinition) setup() { - var builder examplesBuilder - ok := false - if builder, ok = examplesBuilderCustomizations[p.API.PackageName()]; !ok { - builder = defaultExamplesBuilder{} - } - - keys := p.Examples.Names() - for _, n := range keys { - examples := p.Examples[n] - for i, e := range examples { - n = p.ExportableName(n) - e.OperationName = n - e.API = p.API - e.Index = fmt.Sprintf("shared%02d", i) - - e.Builder = builder - - e.VisitedErrors = map[string]struct{}{} - op := p.API.Operations[e.OperationName] - e.OperationName = p.ExportableName(e.OperationName) - e.Operation = op - p.Examples[n][i] = e - } - } - - p.API.Examples = p.Examples -} - -var exampleHeader = template.Must(template.New("exampleHeader").Parse(` -import ( - {{ .Builder.Imports .API }} -) - -var _ time.Duration -var _ strings.Reader -var _ aws.Config - -func parseTime(layout, value string) *time.Time { - t, err := time.Parse(layout, value) - if err != nil { - panic(err) - } - return &t -} - -`)) - -type exHeader struct { - Builder examplesBuilder - API *API -} - -// ExamplesGoCode will return a code representation of the entry within the -// examples.json file. -func (a *API) ExamplesGoCode() string { - var buf bytes.Buffer - var builder examplesBuilder - ok := false - if builder, ok = examplesBuilderCustomizations[a.PackageName()]; !ok { - builder = defaultExamplesBuilder{} - } - - if err := exampleHeader.ExecuteTemplate(&buf, "exampleHeader", &exHeader{builder, a}); err != nil { - panic(err) - } - - code := a.Examples.GoCode() - if len(code) == 0 { - return "" - } - - buf.WriteString(code) - return buf.String() -} - -// TODO: In the operation docuentation where we list errors, this needs to be done -// there as well. -func (ex *Example) HasVisitedError(errRef *ShapeRef) bool { - errName := errRef.Shape.ErrorCodeName() - _, ok := ex.VisitedErrors[errName] - ex.VisitedErrors[errName] = struct{}{} - return ok -} - -func parseTimeString(ref *ShapeRef, memName, v string) string { - if ref.Location == "header" { - return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "Mon, 2 Jan 2006 15:04:05 GMT", v) - } else { - switch ref.API.Metadata.Protocol { - case "json", "rest-json": - return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "2006-01-02T15:04:05Z", v) - case "rest-xml", "ec2", "query": - return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "2006-01-02T15:04:05Z", v) - default: - panic("Unsupported time type: " + ref.API.Metadata.Protocol) - } - } -} - -func (ex *Example) MethodName() string { - return fmt.Sprintf("%s_%s", ex.OperationName, ex.Index) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/examples_builder.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/examples_builder.go deleted file mode 100644 index eece69c806d..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/examples_builder.go +++ /dev/null @@ -1,256 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "fmt" - "reflect" - "sort" - "strings" -) - -type examplesBuilder interface { - BuildShape(*ShapeRef, map[string]interface{}, bool) string - BuildList(string, string, *ShapeRef, []interface{}) string - BuildComplex(string, string, *ShapeRef, map[string]interface{}) string - Imports(*API) string -} - -type defaultExamplesBuilder struct{} - -// BuildShape will recursively build the referenced shape based on the json object -// provided. -// isMap will dictate how the field name is specified. If isMap is true, we will expect -// the member name to be quotes like "Foo". -func (builder defaultExamplesBuilder) BuildShape(ref *ShapeRef, shapes map[string]interface{}, isMap bool) string { - order := make([]string, len(shapes)) - for k := range shapes { - order = append(order, k) - } - sort.Strings(order) - - ret := "" - for _, name := range order { - if name == "" { - continue - } - shape := shapes[name] - - // If the shape isn't a map, we want to export the value, since every field - // defined in our shapes are exported. - if len(name) > 0 && !isMap && strings.ToLower(name[0:1]) == name[0:1] { - name = strings.Title(name) - } - - memName := name - if isMap { - memName = fmt.Sprintf("%q", memName) - } - - switch v := shape.(type) { - case map[string]interface{}: - ret += builder.BuildComplex(name, memName, ref, v) - case []interface{}: - ret += builder.BuildList(name, memName, ref, v) - default: - ret += builder.BuildScalar(name, memName, ref, v) - } - } - return ret -} - -// BuildList will construct a list shape based off the service's definition -// of that list. -func (builder defaultExamplesBuilder) BuildList(name, memName string, ref *ShapeRef, v []interface{}) string { - ret := "" - - if len(v) == 0 || ref == nil { - return "" - } - - t := "" - dataType := "" - format := "" - isComplex := false - passRef := ref - isMap := false - - if ref.Shape.MemberRefs[name] != nil { - t = builder.GoType(&ref.Shape.MemberRefs[name].Shape.MemberRef, false) - dataType = ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.Type - passRef = ref.Shape.MemberRefs[name] - if dataType == "map" { - t = fmt.Sprintf("map[string]%s", builder.GoType(&ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.ValueRef, false)) - passRef = &ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.ValueRef - isMap = true - } - } else if ref.Shape.MemberRef.Shape != nil && ref.Shape.MemberRef.Shape.MemberRefs[name] != nil { - t = builder.GoType(&ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef, false) - dataType = ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef.Shape.Type - passRef = &ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef - } else { - t = builder.GoType(&ref.Shape.MemberRef, false) - dataType = ref.Shape.MemberRef.Shape.Type - passRef = &ref.Shape.MemberRef - } - - switch v[0].(type) { - case string: - format = "%s" - case bool: - format = "%t" - case float64: - if dataType == "integer" || dataType == "int64" { - format = "%d" - } else { - format = "%f" - } - default: - if ref.Shape.MemberRefs[name] != nil { - } else { - passRef = ref.Shape.MemberRef.Shape.MemberRefs[name] - - // if passRef is nil that means we are either in a map or within a nested array - if passRef == nil { - passRef = &ref.Shape.MemberRef - } - } - isComplex = true - } - ret += fmt.Sprintf("%s: []%s {\n", memName, t) - for _, elem := range v { - if isComplex { - ret += fmt.Sprintf("{\n%s\n},\n", builder.BuildShape(passRef, elem.(map[string]interface{}), isMap)) - } else { - if dataType == "integer" || dataType == "int64" || dataType == "long" { - elem = int(elem.(float64)) - } - ret += fmt.Sprintf("%s,\n", getValue(t, fmt.Sprintf(format, elem))) - } - } - ret += "},\n" - return ret -} - -// BuildScalar will build atomic Go types. -func (builder defaultExamplesBuilder) BuildScalar(name, memName string, ref *ShapeRef, shape interface{}) string { - if ref == nil || ref.Shape == nil { - return "" - } else if ref.Shape.MemberRefs[name] == nil { - if ref.Shape.MemberRef.Shape != nil && ref.Shape.MemberRef.Shape.MemberRefs[name] != nil { - return correctType(memName, ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.Type, shape) - } - if ref.Shape.Type != "structure" && ref.Shape.Type != "map" { - return correctType(memName, ref.Shape.Type, shape) - } - return "" - } - - switch v := shape.(type) { - case bool: - return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%t", v)) - case int: - if ref.Shape.MemberRefs[name].Shape.Type == "timestamp" { - return parseTimeString(ref, memName, fmt.Sprintf("%d", v)) - } - return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%d", v)) - case float64: - dataType := ref.Shape.MemberRefs[name].Shape.Type - if dataType == "integer" || dataType == "int64" || dataType == "long" { - return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%d", int(shape.(float64)))) - } - return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%f", v)) - case string: - t := ref.Shape.MemberRefs[name].Shape.Type - switch t { - case "timestamp": - return parseTimeString(ref, memName, fmt.Sprintf("%s", v)) - case "blob": - if (ref.Shape.MemberRefs[name].Streaming || ref.Shape.MemberRefs[name].Shape.Streaming) && ref.Shape.Payload == name { - return fmt.Sprintf("%s: aws.ReadSeekCloser(strings.NewReader(%q)),\n", memName, v) - } - - return fmt.Sprintf("%s: []byte(%q),\n", memName, v) - default: - return convertToCorrectType(memName, t, v) - } - default: - panic(fmt.Errorf("Unsupported scalar type: %v", reflect.TypeOf(v))) - } - return "" -} - -func (builder defaultExamplesBuilder) BuildComplex(name, memName string, ref *ShapeRef, v map[string]interface{}) string { - t := "" - if ref == nil { - return builder.BuildShape(nil, v, true) - } - - member := ref.Shape.MemberRefs[name] - - if member != nil && member.Shape != nil { - t = ref.Shape.MemberRefs[name].Shape.Type - } else { - t = ref.Shape.Type - } - - switch t { - case "structure": - passRef := ref.Shape.MemberRefs[name] - // passRef will be nil if the entry is a map. In that case - // we want to pass the reference, because the previous call - // passed the value reference. - if passRef == nil { - passRef = ref - } - return fmt.Sprintf(`%s: &%s{ - %s - }, - `, memName, builder.GoType(passRef, true), builder.BuildShape(passRef, v, false)) - case "map": - return fmt.Sprintf(`%s: %s{ - %s - }, - `, name, builder.GoType(ref.Shape.MemberRefs[name], false), builder.BuildShape(&ref.Shape.MemberRefs[name].Shape.ValueRef, v, true)) - } - - return "" -} - -func (builder defaultExamplesBuilder) GoType(ref *ShapeRef, elem bool) string { - prefix := "" - if ref.Shape.Type == "list" { - ref = &ref.Shape.MemberRef - prefix = "[]*" - } - - name := ref.GoTypeWithPkgName() - if elem { - name = ref.GoTypeElem() - if !strings.Contains(name, ".") { - name = strings.Join([]string{ref.API.PackageName(), name}, ".") - } - } - - if ref.Shape.Type != "structure" && ref.Shape.Type != "list" { - return name - } - - return prefix + name -} - -func (builder defaultExamplesBuilder) Imports(a *API) string { - buf := bytes.NewBuffer(nil) - buf.WriteString(`"fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - `) - - buf.WriteString(fmt.Sprintf("\"%s/%s\"", "github.com/aws/aws-sdk-go/service", a.PackageName())) - return buf.String() -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/examples_builder_customizations.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/examples_builder_customizations.go deleted file mode 100644 index 058e999cb1f..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/examples_builder_customizations.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "fmt" -) - -type wafregionalExamplesBuilder struct { - defaultExamplesBuilder -} - -func (builder wafregionalExamplesBuilder) Imports(a *API) string { - buf := bytes.NewBuffer(nil) - buf.WriteString(`"fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/waf" - `) - - buf.WriteString(fmt.Sprintf("\"%s/%s\"", "github.com/aws/aws-sdk-go/service", a.PackageName())) - return buf.String() -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/exportable_name.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/exportable_name.go deleted file mode 100644 index 124e9008ea7..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/exportable_name.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build codegen - -package api - -import "strings" - -// ExportableName a name which is exportable as a value or name in Go code -func (a *API) ExportableName(name string) string { - if name == "" { - return name - } - - return strings.ToUpper(name[0:1]) + name[1:] -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/list_of_shame.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/list_of_shame.go deleted file mode 100644 index 08ba24257b8..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/list_of_shame.go +++ /dev/null @@ -1,495 +0,0 @@ -package api - -// shamelist is used to not rename certain operation's input and output shapes. -// We need to maintain backwards compatibility with pre-existing services. Since -// not generating unique input/output shapes is not desired, we will generate -// unique input/output shapes for new operations. -var shamelist = map[string]map[string]struct { - input bool - output bool -}{ - "APIGateway": { - "CreateApiKey": { - output: true, - }, - "CreateAuthorizer": { - output: true, - }, - "CreateBasePathMapping": { - output: true, - }, - "CreateDeployment": { - output: true, - }, - "CreateDocumentationPart": { - output: true, - }, - "CreateDocumentationVersion": { - output: true, - }, - "CreateDomainName": { - output: true, - }, - "CreateModel": { - output: true, - }, - "CreateResource": { - output: true, - }, - "CreateRestApi": { - output: true, - }, - "CreateStage": { - output: true, - }, - "CreateUsagePlan": { - output: true, - }, - "CreateUsagePlanKey": { - output: true, - }, - "GenerateClientCertificate": { - output: true, - }, - "GetAccount": { - output: true, - }, - "GetApiKey": { - output: true, - }, - "GetAuthorizer": { - output: true, - }, - "GetBasePathMapping": { - output: true, - }, - "GetClientCertificate": { - output: true, - }, - "GetDeployment": { - output: true, - }, - "GetDocumentationPart": { - output: true, - }, - "GetDocumentationVersion": { - output: true, - }, - "GetDomainName": { - output: true, - }, - "GetIntegration": { - output: true, - }, - "GetIntegrationResponse": { - output: true, - }, - "GetMethod": { - output: true, - }, - "GetMethodResponse": { - output: true, - }, - "GetModel": { - output: true, - }, - "GetResource": { - output: true, - }, - "GetRestApi": { - output: true, - }, - "GetSdkType": { - output: true, - }, - "GetStage": { - output: true, - }, - "GetUsage": { - output: true, - }, - "GetUsagePlan": { - output: true, - }, - "GetUsagePlanKey": { - output: true, - }, - "ImportRestApi": { - output: true, - }, - "PutIntegration": { - output: true, - }, - "PutIntegrationResponse": { - output: true, - }, - "PutMethod": { - output: true, - }, - "PutMethodResponse": { - output: true, - }, - "PutRestApi": { - output: true, - }, - "UpdateAccount": { - output: true, - }, - "UpdateApiKey": { - output: true, - }, - "UpdateAuthorizer": { - output: true, - }, - "UpdateBasePathMapping": { - output: true, - }, - "UpdateClientCertificate": { - output: true, - }, - "UpdateDeployment": { - output: true, - }, - "UpdateDocumentationPart": { - output: true, - }, - "UpdateDocumentationVersion": { - output: true, - }, - "UpdateDomainName": { - output: true, - }, - "UpdateIntegration": { - output: true, - }, - "UpdateIntegrationResponse": { - output: true, - }, - "UpdateMethod": { - output: true, - }, - "UpdateMethodResponse": { - output: true, - }, - "UpdateModel": { - output: true, - }, - "UpdateResource": { - output: true, - }, - "UpdateRestApi": { - output: true, - }, - "UpdateStage": { - output: true, - }, - "UpdateUsage": { - output: true, - }, - "UpdateUsagePlan": { - output: true, - }, - }, - "AutoScaling": { - "ResumeProcesses": { - input: true, - }, - "SuspendProcesses": { - input: true, - }, - }, - "CognitoIdentity": { - "CreateIdentityPool": { - output: true, - }, - "DescribeIdentity": { - output: true, - }, - "DescribeIdentityPool": { - output: true, - }, - "UpdateIdentityPool": { - input: true, - output: true, - }, - }, - "DirectConnect": { - "AllocateConnectionOnInterconnect": { - output: true, - }, - "AllocateHostedConnection": { - output: true, - }, - "AllocatePrivateVirtualInterface": { - output: true, - }, - "AllocatePublicVirtualInterface": { - output: true, - }, - "AssociateConnectionWithLag": { - output: true, - }, - "AssociateHostedConnection": { - output: true, - }, - "AssociateVirtualInterface": { - output: true, - }, - "CreateConnection": { - output: true, - }, - "CreateInterconnect": { - output: true, - }, - "CreateLag": { - output: true, - }, - "CreatePrivateVirtualInterface": { - output: true, - }, - "CreatePublicVirtualInterface": { - output: true, - }, - "DeleteConnection": { - output: true, - }, - "DeleteLag": { - output: true, - }, - "DescribeConnections": { - output: true, - }, - "DescribeConnectionsOnInterconnect": { - output: true, - }, - "DescribeHostedConnections": { - output: true, - }, - "DescribeLoa": { - output: true, - }, - "DisassociateConnectionFromLag": { - output: true, - }, - "UpdateLag": { - output: true, - }, - }, - "EC2": { - "AttachVolume": { - output: true, - }, - "CreateSnapshot": { - output: true, - }, - "CreateVolume": { - output: true, - }, - "DetachVolume": { - output: true, - }, - "RunInstances": { - output: true, - }, - }, - "EFS": { - "CreateFileSystem": { - output: true, - }, - "CreateMountTarget": { - output: true, - }, - }, - "ElastiCache": { - "AddTagsToResource": { - output: true, - }, - "ListTagsForResource": { - output: true, - }, - "ModifyCacheParameterGroup": { - output: true, - }, - "RemoveTagsFromResource": { - output: true, - }, - "ResetCacheParameterGroup": { - output: true, - }, - }, - "ElasticBeanstalk": { - "ComposeEnvironments": { - output: true, - }, - "CreateApplication": { - output: true, - }, - "CreateApplicationVersion": { - output: true, - }, - "CreateConfigurationTemplate": { - output: true, - }, - "CreateEnvironment": { - output: true, - }, - "DescribeEnvironments": { - output: true, - }, - "TerminateEnvironment": { - output: true, - }, - "UpdateApplication": { - output: true, - }, - "UpdateApplicationVersion": { - output: true, - }, - "UpdateConfigurationTemplate": { - output: true, - }, - "UpdateEnvironment": { - output: true, - }, - }, - "Glacier": { - "DescribeJob": { - output: true, - }, - "UploadArchive": { - output: true, - }, - "CompleteMultipartUpload": { - output: true, - }, - }, - "IAM": { - "GetContextKeysForCustomPolicy": { - output: true, - }, - "GetContextKeysForPrincipalPolicy": { - output: true, - }, - "SimulateCustomPolicy": { - output: true, - }, - "SimulatePrincipalPolicy": { - output: true, - }, - }, - "Kinesis": { - "DisableEnhancedMonitoring": { - output: true, - }, - "EnableEnhancedMonitoring": { - output: true, - }, - }, - "KMS": { - "ListGrants": { - output: true, - }, - "ListRetirableGrants": { - output: true, - }, - }, - "Lambda": { - "CreateAlias": { - output: true, - }, - "CreateEventSourceMapping": { - output: true, - }, - "CreateFunction": { - output: true, - }, - "DeleteEventSourceMapping": { - output: true, - }, - "GetAlias": { - output: true, - }, - "GetEventSourceMapping": { - output: true, - }, - "GetFunctionConfiguration": { - output: true, - }, - "PublishVersion": { - output: true, - }, - "UpdateAlias": { - output: true, - }, - "UpdateEventSourceMapping": { - output: true, - }, - "UpdateFunctionCode": { - output: true, - }, - "UpdateFunctionConfiguration": { - output: true, - }, - }, - "RDS": { - "ModifyDBClusterParameterGroup": { - output: true, - }, - "ModifyDBParameterGroup": { - output: true, - }, - "ResetDBClusterParameterGroup": { - output: true, - }, - "ResetDBParameterGroup": { - output: true, - }, - }, - "Redshift": { - "DescribeLoggingStatus": { - output: true, - }, - "DisableLogging": { - output: true, - }, - "EnableLogging": { - output: true, - }, - "ModifyClusterParameterGroup": { - output: true, - }, - "ResetClusterParameterGroup": { - output: true, - }, - }, - "S3": { - "GetBucketNotification": { - input: true, - output: true, - }, - "GetBucketNotificationConfiguration": { - input: true, - output: true, - }, - }, - "SWF": { - "CountClosedWorkflowExecutions": { - output: true, - }, - "CountOpenWorkflowExecutions": { - output: true, - }, - "CountPendingActivityTasks": { - output: true, - }, - "CountPendingDecisionTasks": { - output: true, - }, - "ListClosedWorkflowExecutions": { - output: true, - }, - "ListOpenWorkflowExecutions": { - output: true, - }, - }, -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/load.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/load.go deleted file mode 100644 index 5f3b9e20b63..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/load.go +++ /dev/null @@ -1,74 +0,0 @@ -// +build codegen - -package api - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" -) - -// Load takes a set of files for each filetype and returns an API pointer. -// The API will be initialized once all files have been loaded and parsed. -// -// Will panic if any failure opening the definition JSON files, or there -// are unrecognized exported names. -func Load(api, docs, paginators, waiters string) *API { - a := API{} - a.Attach(api) - a.Attach(docs) - a.Attach(paginators) - a.Attach(waiters) - a.Setup() - return &a -} - -// Attach opens a file by name, and unmarshal its JSON data. -// Will proceed to setup the API if not already done so. -func (a *API) Attach(filename string) { - a.path = filepath.Dir(filename) - f, err := os.Open(filename) - defer f.Close() - if err != nil { - panic(err) - } - if err := json.NewDecoder(f).Decode(a); err != nil { - panic(fmt.Errorf("failed to decode %s, err: %v", filename, err)) - } -} - -// AttachString will unmarshal a raw JSON string, and setup the -// API if not already done so. -func (a *API) AttachString(str string) { - json.Unmarshal([]byte(str), a) - - if !a.initialized { - a.Setup() - } -} - -// Setup initializes the API. -func (a *API) Setup() { - a.setMetadataEndpointsKey() - a.writeShapeNames() - a.resolveReferences() - a.fixStutterNames() - a.renameExportable() - if !a.NoRenameToplevelShapes { - a.renameToplevelShapes() - } - a.updateTopLevelShapeReferences() - a.createInputOutputShapes() - a.customizationPasses() - - if !a.NoRemoveUnusedShapes { - a.removeUnusedShapes() - } - - if !a.NoValidataShapeMethods { - a.addShapeValidations() - } - - a.initialized = true -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/operation.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/operation.go deleted file mode 100644 index 749b6e781fe..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/operation.go +++ /dev/null @@ -1,493 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "fmt" - "regexp" - "sort" - "strings" - "text/template" -) - -// An Operation defines a specific API Operation. -type Operation struct { - API *API `json:"-"` - ExportedName string - Name string - Documentation string - HTTP HTTPInfo - InputRef ShapeRef `json:"input"` - OutputRef ShapeRef `json:"output"` - ErrorRefs []ShapeRef `json:"errors"` - Paginator *Paginator - Deprecated bool `json:"deprecated"` - AuthType string `json:"authtype"` - imports map[string]bool -} - -// A HTTPInfo defines the method of HTTP request for the Operation. -type HTTPInfo struct { - Method string - RequestURI string - ResponseCode uint -} - -// HasInput returns if the Operation accepts an input paramater -func (o *Operation) HasInput() bool { - return o.InputRef.ShapeName != "" -} - -// HasOutput returns if the Operation accepts an output parameter -func (o *Operation) HasOutput() bool { - return o.OutputRef.ShapeName != "" -} - -func (o *Operation) GetSigner() string { - if o.AuthType == "v4-unsigned-body" { - o.API.imports["github.com/aws/aws-sdk-go/aws/signer/v4"] = true - } - - buf := bytes.NewBuffer(nil) - - switch o.AuthType { - case "none": - buf.WriteString("req.Config.Credentials = credentials.AnonymousCredentials") - case "v4-unsigned-body": - buf.WriteString("req.Handlers.Sign.Remove(v4.SignRequestHandler)\n") - buf.WriteString("handler := v4.BuildNamedHandler(\"v4.CustomSignerHandler\", v4.WithUnsignedPayload)\n") - buf.WriteString("req.Handlers.Sign.PushFrontNamed(handler)") - } - - buf.WriteString("\n") - return buf.String() -} - -// tplOperation defines a template for rendering an API Operation -var tplOperation = template.Must(template.New("operation").Funcs(template.FuncMap{ - "GetCrosslinkURL": GetCrosslinkURL, -}).Parse(` -const op{{ .ExportedName }} = "{{ .Name }}" - -// {{ .ExportedName }}Request generates a "aws/request.Request" representing the -// client's request for the {{ .ExportedName }} operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. -// -// See {{ .ExportedName }} for usage and error information. -// -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the {{ .ExportedName }} method directly -// instead. -// -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. -// -// // Example sending a request using the {{ .ExportedName }}Request method. -// req, resp := client.{{ .ExportedName }}Request(params) -// -// err := req.Send() -// if err == nil { // resp is now filled -// fmt.Println(resp) -// } -{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ExportedName -}} -{{ if ne $crosslinkURL "" -}} -// -// Please also see {{ $crosslinkURL }} -{{ end -}} -func (c *{{ .API.StructName }}) {{ .ExportedName }}Request(` + - `input {{ .InputRef.GoType }}) (req *request.Request, output {{ .OutputRef.GoType }}) { - {{ if (or .Deprecated (or .InputRef.Deprecated .OutputRef.Deprecated)) }}if c.Client.Config.Logger != nil { - c.Client.Config.Logger.Log("This operation, {{ .ExportedName }}, has been deprecated") - } - op := &request.Operation{ {{ else }} op := &request.Operation{ {{ end }} - Name: op{{ .ExportedName }}, - {{ if ne .HTTP.Method "" }}HTTPMethod: "{{ .HTTP.Method }}", - {{ end }}HTTPPath: {{ if ne .HTTP.RequestURI "" }}"{{ .HTTP.RequestURI }}"{{ else }}"/"{{ end }}, - {{ if .Paginator }}Paginator: &request.Paginator{ - InputTokens: {{ .Paginator.InputTokensString }}, - OutputTokens: {{ .Paginator.OutputTokensString }}, - LimitToken: "{{ .Paginator.LimitKey }}", - TruncationToken: "{{ .Paginator.MoreResults }}", - }, - {{ end }} - } - - if input == nil { - input = &{{ .InputRef.GoTypeElem }}{} - } - - output = &{{ .OutputRef.GoTypeElem }}{} - req = c.newRequest(op, input, output){{ if eq .OutputRef.Shape.Placeholder true }} - req.Handlers.Unmarshal.Remove({{ .API.ProtocolPackage }}.UnmarshalHandler) - req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler){{ end }} - {{ if ne .AuthType "" }}{{ .GetSigner }}{{ end -}} - return -} - -// {{ .ExportedName }} API operation for {{ .API.Metadata.ServiceFullName }}. -{{ if .Documentation -}} -// -{{ .Documentation }} -{{ end -}} -// -// Returns awserr.Error for service API and SDK errors. Use runtime type assertions -// with awserr.Error's Code and Message methods to get detailed information about -// the error. -// -// See the AWS API reference guide for {{ .API.Metadata.ServiceFullName }}'s -// API operation {{ .ExportedName }} for usage and error information. -{{ if .ErrorRefs -}} -// -// Returned Error Codes: -{{ range $_, $err := .ErrorRefs -}} -// * {{ $err.Shape.ErrorCodeName }} "{{ $err.Shape.ErrorName}}" -{{ if $err.Docstring -}} -{{ $err.IndentedDocstring }} -{{ end -}} -// -{{ end -}} -{{ end -}} -{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ExportedName -}} -{{ if ne $crosslinkURL "" -}} -// Please also see {{ $crosslinkURL }} -{{ end -}} -func (c *{{ .API.StructName }}) {{ .ExportedName }}(` + - `input {{ .InputRef.GoType }}) ({{ .OutputRef.GoType }}, error) { - req, out := c.{{ .ExportedName }}Request(input) - return out, req.Send() -} - -// {{ .ExportedName }}WithContext is the same as {{ .ExportedName }} with the addition of -// the ability to pass a context and additional request options. -// -// See {{ .ExportedName }} for details on how to use this API operation. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *{{ .API.StructName }}) {{ .ExportedName }}WithContext(` + - `ctx aws.Context, input {{ .InputRef.GoType }}, opts ...request.Option) ` + - `({{ .OutputRef.GoType }}, error) { - req, out := c.{{ .ExportedName }}Request(input) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return out, req.Send() -} - -{{ if .Paginator }} -// {{ .ExportedName }}Pages iterates over the pages of a {{ .ExportedName }} operation, -// calling the "fn" function with the response data for each page. To stop -// iterating, return false from the fn function. -// -// See {{ .ExportedName }} method for more information on how to use this operation. -// -// Note: This operation can generate multiple requests to a service. -// -// // Example iterating over at most 3 pages of a {{ .ExportedName }} operation. -// pageNum := 0 -// err := client.{{ .ExportedName }}Pages(params, -// func(page {{ .OutputRef.GoType }}, lastPage bool) bool { -// pageNum++ -// fmt.Println(page) -// return pageNum <= 3 -// }) -// -func (c *{{ .API.StructName }}) {{ .ExportedName }}Pages(` + - `input {{ .InputRef.GoType }}, fn func({{ .OutputRef.GoType }}, bool) bool) error { - return c.{{ .ExportedName }}PagesWithContext(aws.BackgroundContext(), input, fn) -} - -// {{ .ExportedName }}PagesWithContext same as {{ .ExportedName }}Pages except -// it takes a Context and allows setting request options on the pages. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *{{ .API.StructName }}) {{ .ExportedName }}PagesWithContext(` + - `ctx aws.Context, ` + - `input {{ .InputRef.GoType }}, ` + - `fn func({{ .OutputRef.GoType }}, bool) bool, ` + - `opts ...request.Option) error { - p := request.Pagination { - NewRequest: func() (*request.Request, error) { - var inCpy {{ .InputRef.GoType }} - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.{{ .ExportedName }}Request(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - cont := true - for p.Next() && cont { - cont = fn(p.Page().({{ .OutputRef.GoType }}), !p.HasNextPage()) - } - return p.Err() -} -{{ end }} -`)) - -// GoCode returns a string of rendered GoCode for this Operation -func (o *Operation) GoCode() string { - var buf bytes.Buffer - err := tplOperation.Execute(&buf, o) - if err != nil { - panic(err) - } - - return strings.TrimSpace(buf.String()) -} - -// tplInfSig defines the template for rendering an Operation's signature within an Interface definition. -var tplInfSig = template.Must(template.New("opsig").Parse(` -{{ .ExportedName }}({{ .InputRef.GoTypeWithPkgName }}) ({{ .OutputRef.GoTypeWithPkgName }}, error) -{{ .ExportedName }}WithContext(aws.Context, {{ .InputRef.GoTypeWithPkgName }}, ...request.Option) ({{ .OutputRef.GoTypeWithPkgName }}, error) -{{ .ExportedName }}Request({{ .InputRef.GoTypeWithPkgName }}) (*request.Request, {{ .OutputRef.GoTypeWithPkgName }}) - -{{ if .Paginator -}} -{{ .ExportedName }}Pages({{ .InputRef.GoTypeWithPkgName }}, func({{ .OutputRef.GoTypeWithPkgName }}, bool) bool) error -{{ .ExportedName }}PagesWithContext(aws.Context, {{ .InputRef.GoTypeWithPkgName }}, func({{ .OutputRef.GoTypeWithPkgName }}, bool) bool, ...request.Option) error -{{- end }} -`)) - -// InterfaceSignature returns a string representing the Operation's interface{} -// functional signature. -func (o *Operation) InterfaceSignature() string { - var buf bytes.Buffer - err := tplInfSig.Execute(&buf, o) - if err != nil { - panic(err) - } - - return strings.TrimSpace(buf.String()) -} - -// tplExample defines the template for rendering an Operation example -var tplExample = template.Must(template.New("operationExample").Parse(` -func Example{{ .API.StructName }}_{{ .ExportedName }}() { - sess := session.Must(session.NewSession()) - - svc := {{ .API.PackageName }}.New(sess) - - {{ .ExampleInput }} - resp, err := svc.{{ .ExportedName }}(params) - - if err != nil { - // Print the error, cast err to awserr.Error to get the Code and - // Message from an error. - fmt.Println(err.Error()) - return - } - - // Pretty-print the response data. - fmt.Println(resp) -} -`)) - -// Example returns a string of the rendered Go code for the Operation -func (o *Operation) Example() string { - var buf bytes.Buffer - err := tplExample.Execute(&buf, o) - if err != nil { - panic(err) - } - - return strings.TrimSpace(buf.String()) -} - -// ExampleInput return a string of the rendered Go code for an example's input parameters -func (o *Operation) ExampleInput() string { - if len(o.InputRef.Shape.MemberRefs) == 0 { - if strings.Contains(o.InputRef.GoTypeElem(), ".") { - o.imports["github.com/aws/aws-sdk-go/service/"+strings.Split(o.InputRef.GoTypeElem(), ".")[0]] = true - return fmt.Sprintf("var params *%s", o.InputRef.GoTypeElem()) - } - return fmt.Sprintf("var params *%s.%s", - o.API.PackageName(), o.InputRef.GoTypeElem()) - } - e := example{o, map[string]int{}} - return "params := " + e.traverseAny(o.InputRef.Shape, false, false) -} - -// A example provides -type example struct { - *Operation - visited map[string]int -} - -// traverseAny returns rendered Go code for the shape. -func (e *example) traverseAny(s *Shape, required, payload bool) string { - str := "" - e.visited[s.ShapeName]++ - - switch s.Type { - case "structure": - str = e.traverseStruct(s, required, payload) - case "list": - str = e.traverseList(s, required, payload) - case "map": - str = e.traverseMap(s, required, payload) - case "jsonvalue": - str = "aws.JSONValue{\"key\": \"value\"}" - if required { - str += " // Required" - } - default: - str = e.traverseScalar(s, required, payload) - } - - e.visited[s.ShapeName]-- - - return str -} - -var reType = regexp.MustCompile(`\b([A-Z])`) - -// traverseStruct returns rendered Go code for a structure type shape. -func (e *example) traverseStruct(s *Shape, required, payload bool) string { - var buf bytes.Buffer - - if s.resolvePkg != "" { - e.imports[s.resolvePkg] = true - buf.WriteString("&" + s.GoTypeElem() + "{") - } else { - buf.WriteString("&" + s.API.PackageName() + "." + s.GoTypeElem() + "{") - } - - if required { - buf.WriteString(" // Required") - } - buf.WriteString("\n") - - req := make([]string, len(s.Required)) - copy(req, s.Required) - sort.Strings(req) - - if e.visited[s.ShapeName] < 2 { - for _, n := range req { - m := s.MemberRefs[n].Shape - p := n == s.Payload && (s.MemberRefs[n].Streaming || m.Streaming) - buf.WriteString(n + ": " + e.traverseAny(m, true, p) + ",") - if m.Type != "list" && m.Type != "structure" && m.Type != "map" { - buf.WriteString(" // Required") - } - buf.WriteString("\n") - } - - for _, n := range s.MemberNames() { - if s.IsRequired(n) { - continue - } - m := s.MemberRefs[n].Shape - p := n == s.Payload && (s.MemberRefs[n].Streaming || m.Streaming) - buf.WriteString(n + ": " + e.traverseAny(m, false, p) + ",\n") - } - } else { - buf.WriteString("// Recursive values...\n") - } - - buf.WriteString("}") - return buf.String() -} - -// traverseMap returns rendered Go code for a map type shape. -func (e *example) traverseMap(s *Shape, required, payload bool) string { - var buf bytes.Buffer - - t := "" - if s.resolvePkg != "" { - e.imports[s.resolvePkg] = true - t = s.GoTypeElem() - } else { - t = reType.ReplaceAllString(s.GoTypeElem(), s.API.PackageName()+".$1") - } - buf.WriteString(t + "{") - if required { - buf.WriteString(" // Required") - } - buf.WriteString("\n") - - if e.visited[s.ShapeName] < 2 { - m := s.ValueRef.Shape - buf.WriteString("\"Key\": " + e.traverseAny(m, true, false) + ",") - if m.Type != "list" && m.Type != "structure" && m.Type != "map" { - buf.WriteString(" // Required") - } - buf.WriteString("\n// More values...\n") - } else { - buf.WriteString("// Recursive values...\n") - } - buf.WriteString("}") - - return buf.String() -} - -// traverseList returns rendered Go code for a list type shape. -func (e *example) traverseList(s *Shape, required, payload bool) string { - var buf bytes.Buffer - t := "" - if s.resolvePkg != "" { - e.imports[s.resolvePkg] = true - t = s.GoTypeElem() - } else { - t = reType.ReplaceAllString(s.GoTypeElem(), s.API.PackageName()+".$1") - } - - buf.WriteString(t + "{") - if required { - buf.WriteString(" // Required") - } - buf.WriteString("\n") - - if e.visited[s.ShapeName] < 2 { - m := s.MemberRef.Shape - buf.WriteString(e.traverseAny(m, true, false) + ",") - if m.Type != "list" && m.Type != "structure" && m.Type != "map" { - buf.WriteString(" // Required") - } - buf.WriteString("\n// More values...\n") - } else { - buf.WriteString("// Recursive values...\n") - } - buf.WriteString("}") - - return buf.String() -} - -// traverseScalar returns an AWS Type string representation initialized to a value. -// Will panic if s is an unsupported shape type. -func (e *example) traverseScalar(s *Shape, required, payload bool) string { - str := "" - switch s.Type { - case "integer", "long": - str = `aws.Int64(1)` - case "float", "double": - str = `aws.Float64(1.0)` - case "string", "character": - str = `aws.String("` + s.ShapeName + `")` - case "blob": - if payload { - str = `bytes.NewReader([]byte("PAYLOAD"))` - } else { - str = `[]byte("PAYLOAD")` - } - case "boolean": - str = `aws.Bool(true)` - case "timestamp": - str = `aws.Time(time.Now())` - default: - panic("unsupported shape " + s.Type) - } - - return str -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/pagination.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/pagination.go deleted file mode 100644 index 441a47529f4..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/pagination.go +++ /dev/null @@ -1,91 +0,0 @@ -// +build codegen - -package api - -import ( - "encoding/json" - "fmt" - "os" -) - -// Paginator keeps track of pagination configuration for an API operation. -type Paginator struct { - InputTokens interface{} `json:"input_token"` - OutputTokens interface{} `json:"output_token"` - LimitKey string `json:"limit_key"` - MoreResults string `json:"more_results"` -} - -// InputTokensString returns output tokens formatted as a list -func (p *Paginator) InputTokensString() string { - str := p.InputTokens.([]string) - return fmt.Sprintf("%#v", str) -} - -// OutputTokensString returns output tokens formatted as a list -func (p *Paginator) OutputTokensString() string { - str := p.OutputTokens.([]string) - return fmt.Sprintf("%#v", str) -} - -// used for unmarshaling from the paginators JSON file -type paginationDefinitions struct { - *API - Pagination map[string]Paginator -} - -// AttachPaginators attaches pagination configuration from filename to the API. -func (a *API) AttachPaginators(filename string) { - p := paginationDefinitions{API: a} - - f, err := os.Open(filename) - defer f.Close() - if err != nil { - panic(err) - } - err = json.NewDecoder(f).Decode(&p) - if err != nil { - panic(err) - } - - p.setup() -} - -// setup runs post-processing on the paginator configuration. -func (p *paginationDefinitions) setup() { - for n, e := range p.Pagination { - if e.InputTokens == nil || e.OutputTokens == nil { - continue - } - paginator := e - - switch t := paginator.InputTokens.(type) { - case string: - paginator.InputTokens = []string{t} - case []interface{}: - toks := []string{} - for _, e := range t { - s := e.(string) - toks = append(toks, s) - } - paginator.InputTokens = toks - } - switch t := paginator.OutputTokens.(type) { - case string: - paginator.OutputTokens = []string{t} - case []interface{}: - toks := []string{} - for _, e := range t { - s := e.(string) - toks = append(toks, s) - } - paginator.OutputTokens = toks - } - - if o, ok := p.Operations[n]; ok { - o.Paginator = &paginator - } else { - panic("unknown operation for paginator " + n) - } - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/param_filler.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/param_filler.go deleted file mode 100644 index eb3edb9d2a5..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/param_filler.go +++ /dev/null @@ -1,133 +0,0 @@ -// +build codegen - -package api - -import ( - "fmt" - "reflect" - "strings" - - "github.com/aws/aws-sdk-go/private/util" -) - -// A paramFiller provides string formatting for a shape and its types. -type paramFiller struct { - prefixPackageName bool -} - -// typeName returns the type name of a shape. -func (f paramFiller) typeName(shape *Shape) string { - if f.prefixPackageName && shape.Type == "structure" { - return "*" + shape.API.PackageName() + "." + shape.GoTypeElem() - } - return shape.GoType() -} - -// ParamsStructFromJSON returns a JSON string representation of a structure. -func ParamsStructFromJSON(value interface{}, shape *Shape, prefixPackageName bool) string { - f := paramFiller{prefixPackageName: prefixPackageName} - return util.GoFmt(f.paramsStructAny(value, shape)) -} - -// paramsStructAny returns the string representation of any value. -func (f paramFiller) paramsStructAny(value interface{}, shape *Shape) string { - if value == nil { - return "" - } - - switch shape.Type { - case "structure": - if value != nil { - vmap := value.(map[string]interface{}) - return f.paramsStructStruct(vmap, shape) - } - case "list": - vlist := value.([]interface{}) - return f.paramsStructList(vlist, shape) - case "map": - vmap := value.(map[string]interface{}) - return f.paramsStructMap(vmap, shape) - case "string", "character": - v := reflect.Indirect(reflect.ValueOf(value)) - if v.IsValid() { - return fmt.Sprintf("aws.String(%#v)", v.Interface()) - } - case "blob": - v := reflect.Indirect(reflect.ValueOf(value)) - if v.IsValid() && shape.Streaming { - return fmt.Sprintf("bytes.NewReader([]byte(%#v))", v.Interface()) - } else if v.IsValid() { - return fmt.Sprintf("[]byte(%#v)", v.Interface()) - } - case "boolean": - v := reflect.Indirect(reflect.ValueOf(value)) - if v.IsValid() { - return fmt.Sprintf("aws.Bool(%#v)", v.Interface()) - } - case "integer", "long": - v := reflect.Indirect(reflect.ValueOf(value)) - if v.IsValid() { - return fmt.Sprintf("aws.Int64(%v)", v.Interface()) - } - case "float", "double": - v := reflect.Indirect(reflect.ValueOf(value)) - if v.IsValid() { - return fmt.Sprintf("aws.Float64(%v)", v.Interface()) - } - case "timestamp": - v := reflect.Indirect(reflect.ValueOf(value)) - if v.IsValid() { - return fmt.Sprintf("aws.Time(time.Unix(%d, 0))", int(v.Float())) - } - default: - panic("Unhandled type " + shape.Type) - } - return "" -} - -// paramsStructStruct returns the string representation of a structure -func (f paramFiller) paramsStructStruct(value map[string]interface{}, shape *Shape) string { - out := "&" + f.typeName(shape)[1:] + "{\n" - for _, n := range shape.MemberNames() { - ref := shape.MemberRefs[n] - name := findParamMember(value, n) - - if val := f.paramsStructAny(value[name], ref.Shape); val != "" { - out += fmt.Sprintf("%s: %s,\n", n, val) - } - } - out += "}" - return out -} - -// paramsStructMap returns the string representation of a map of values -func (f paramFiller) paramsStructMap(value map[string]interface{}, shape *Shape) string { - out := f.typeName(shape) + "{\n" - keys := util.SortedKeys(value) - for _, k := range keys { - v := value[k] - out += fmt.Sprintf("%q: %s,\n", k, f.paramsStructAny(v, shape.ValueRef.Shape)) - } - out += "}" - return out -} - -// paramsStructList returns the string representation of slice of values -func (f paramFiller) paramsStructList(value []interface{}, shape *Shape) string { - out := f.typeName(shape) + "{\n" - for _, v := range value { - out += fmt.Sprintf("%s,\n", f.paramsStructAny(v, shape.MemberRef.Shape)) - } - out += "}" - return out -} - -// findParamMember searches a map for a key ignoring case. Returns the map key if found. -func findParamMember(value map[string]interface{}, key string) string { - for actualKey := range value { - if strings.ToLower(key) == strings.ToLower(actualKey) { - return actualKey - } - } - return "" -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/passes.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/passes.go deleted file mode 100644 index 03639425eb8..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/passes.go +++ /dev/null @@ -1,306 +0,0 @@ -// +build codegen - -package api - -import ( - "fmt" - "regexp" - "strings" -) - -// updateTopLevelShapeReferences moves resultWrapper, locationName, and -// xmlNamespace traits from toplevel shape references to the toplevel -// shapes for easier code generation -func (a *API) updateTopLevelShapeReferences() { - for _, o := range a.Operations { - // these are for REST-XML services - if o.InputRef.LocationName != "" { - o.InputRef.Shape.LocationName = o.InputRef.LocationName - } - if o.InputRef.Location != "" { - o.InputRef.Shape.Location = o.InputRef.Location - } - if o.InputRef.Payload != "" { - o.InputRef.Shape.Payload = o.InputRef.Payload - } - if o.InputRef.XMLNamespace.Prefix != "" { - o.InputRef.Shape.XMLNamespace.Prefix = o.InputRef.XMLNamespace.Prefix - } - if o.InputRef.XMLNamespace.URI != "" { - o.InputRef.Shape.XMLNamespace.URI = o.InputRef.XMLNamespace.URI - } - } - -} - -// writeShapeNames sets each shape's API and shape name values. Binding the -// shape to its parent API. -func (a *API) writeShapeNames() { - for n, s := range a.Shapes { - s.API = a - s.ShapeName = n - } -} - -func (a *API) resolveReferences() { - resolver := referenceResolver{API: a, visited: map[*ShapeRef]bool{}} - - for _, s := range a.Shapes { - resolver.resolveShape(s) - } - - for _, o := range a.Operations { - o.API = a // resolve parent reference - - resolver.resolveReference(&o.InputRef) - resolver.resolveReference(&o.OutputRef) - - // Resolve references for errors also - for i := range o.ErrorRefs { - resolver.resolveReference(&o.ErrorRefs[i]) - o.ErrorRefs[i].Shape.IsError = true - } - } -} - -// A referenceResolver provides a way to resolve shape references to -// shape definitions. -type referenceResolver struct { - *API - visited map[*ShapeRef]bool -} - -var jsonvalueShape = &Shape{ - ShapeName: "JSONValue", - Type: "jsonvalue", - ValueRef: ShapeRef{ - JSONValue: true, - }, -} - -// resolveReference updates a shape reference to reference the API and -// its shape definition. All other nested references are also resolved. -func (r *referenceResolver) resolveReference(ref *ShapeRef) { - if ref.ShapeName == "" { - return - } - - if shape, ok := r.API.Shapes[ref.ShapeName]; ok { - if ref.JSONValue { - ref.ShapeName = "JSONValue" - r.API.Shapes[ref.ShapeName] = jsonvalueShape - } - - ref.API = r.API // resolve reference back to API - ref.Shape = shape // resolve shape reference - - if r.visited[ref] { - return - } - r.visited[ref] = true - - shape.refs = append(shape.refs, ref) // register the ref - - // resolve shape's references, if it has any - r.resolveShape(shape) - } -} - -// resolveShape resolves a shape's Member Key Value, and nested member -// shape references. -func (r *referenceResolver) resolveShape(shape *Shape) { - r.resolveReference(&shape.MemberRef) - r.resolveReference(&shape.KeyRef) - r.resolveReference(&shape.ValueRef) - for _, m := range shape.MemberRefs { - r.resolveReference(m) - } -} - -// renameToplevelShapes renames all top level shapes of an API to their -// exportable variant. The shapes are also updated to include notations -// if they are Input or Outputs. -func (a *API) renameToplevelShapes() { - for _, v := range a.OperationList() { - if v.HasInput() { - name := v.ExportedName + "Input" - switch { - case a.Shapes[name] == nil: - if service, ok := shamelist[a.name]; ok { - if check, ok := service[v.Name]; ok && check.input { - break - } - } - v.InputRef.Shape.Rename(name) - } - } - if v.HasOutput() { - name := v.ExportedName + "Output" - switch { - case a.Shapes[name] == nil: - if service, ok := shamelist[a.name]; ok { - if check, ok := service[v.Name]; ok && check.output { - break - } - } - v.OutputRef.Shape.Rename(name) - } - } - v.InputRef.Payload = a.ExportableName(v.InputRef.Payload) - v.OutputRef.Payload = a.ExportableName(v.OutputRef.Payload) - } -} - -// fixStutterNames fixes all name struttering based on Go naming conventions. -// "Stuttering" is when the prefix of a structure or function matches the -// package name (case insensitive). -func (a *API) fixStutterNames() { - str, end := a.StructName(), "" - if len(str) > 1 { - l := len(str) - 1 - str, end = str[0:l], str[l:] - } - re := regexp.MustCompile(fmt.Sprintf(`\A(?i:%s)%s`, str, end)) - - for name, op := range a.Operations { - newName := re.ReplaceAllString(name, "") - if newName != name { - delete(a.Operations, name) - a.Operations[newName] = op - } - op.ExportedName = newName - } - - for k, s := range a.Shapes { - newName := re.ReplaceAllString(k, "") - if newName != s.ShapeName { - s.Rename(newName) - } - } -} - -// renameExportable renames all operation names to be exportable names. -// All nested Shape names are also updated to the exportable variant. -func (a *API) renameExportable() { - for name, op := range a.Operations { - newName := a.ExportableName(name) - if newName != name { - delete(a.Operations, name) - a.Operations[newName] = op - } - op.ExportedName = newName - } - - for k, s := range a.Shapes { - // FIXME SNS has lower and uppercased shape names with the same name, - // except the lowercased variant is used exclusively for string and - // other primitive types. Renaming both would cause a collision. - // We work around this by only renaming the structure shapes. - if s.Type == "string" { - continue - } - - for mName, member := range s.MemberRefs { - newName := a.ExportableName(mName) - if newName != mName { - delete(s.MemberRefs, mName) - s.MemberRefs[newName] = member - - // also apply locationName trait so we keep the old one - // but only if there's no locationName trait on ref or shape - if member.LocationName == "" && member.Shape.LocationName == "" { - member.LocationName = mName - } - } - - if newName == "_" { - panic("Shape " + s.ShapeName + " uses reserved member name '_'") - } - } - - newName := a.ExportableName(k) - if newName != s.ShapeName { - s.Rename(newName) - } - - s.Payload = a.ExportableName(s.Payload) - - // fix required trait names - for i, n := range s.Required { - s.Required[i] = a.ExportableName(n) - } - } - - for _, s := range a.Shapes { - // fix enum names - if s.IsEnum() { - s.EnumConsts = make([]string, len(s.Enum)) - for i := range s.Enum { - shape := s.ShapeName - shape = strings.ToUpper(shape[0:1]) + shape[1:] - s.EnumConsts[i] = shape + s.EnumName(i) - } - } - } -} - -// createInputOutputShapes creates toplevel input/output shapes if they -// have not been defined in the API. This normalizes all APIs to always -// have an input and output structure in the signature. -func (a *API) createInputOutputShapes() { - for _, op := range a.Operations { - if !op.HasInput() { - setAsPlacholderShape(&op.InputRef, op.ExportedName+"Input", a) - } - if !op.HasOutput() { - setAsPlacholderShape(&op.OutputRef, op.ExportedName+"Output", a) - } - } -} - -func setAsPlacholderShape(tgtShapeRef *ShapeRef, name string, a *API) { - shape := a.makeIOShape(name) - shape.Placeholder = true - *tgtShapeRef = ShapeRef{API: a, ShapeName: shape.ShapeName, Shape: shape} - shape.refs = append(shape.refs, tgtShapeRef) -} - -// makeIOShape returns a pointer to a new Shape initialized by the name provided. -func (a *API) makeIOShape(name string) *Shape { - shape := &Shape{ - API: a, ShapeName: name, Type: "structure", - MemberRefs: map[string]*ShapeRef{}, - } - a.Shapes[name] = shape - return shape -} - -// removeUnusedShapes removes shapes from the API which are not referenced by any -// other shape in the API. -func (a *API) removeUnusedShapes() { - for n, s := range a.Shapes { - if len(s.refs) == 0 { - delete(a.Shapes, n) - } - } -} - -// Represents the service package name to EndpointsID mapping -var custEndpointsKey = map[string]string{ - "applicationautoscaling": "application-autoscaling", -} - -// Sents the EndpointsID field of Metadata with the value of the -// EndpointPrefix if EndpointsID is not set. Also adds -// customizations for services if EndpointPrefix is not a valid key. -func (a *API) setMetadataEndpointsKey() { - if len(a.Metadata.EndpointsID) != 0 { - return - } - - if v, ok := custEndpointsKey[a.PackageName()]; ok { - a.Metadata.EndpointsID = v - } else { - a.Metadata.EndpointsID = a.Metadata.EndpointPrefix - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/shape.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/shape.go deleted file mode 100644 index dd0fbee55af..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/shape.go +++ /dev/null @@ -1,684 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "fmt" - "path" - "regexp" - "sort" - "strings" - "text/template" -) - -// A ShapeRef defines the usage of a shape within the API. -type ShapeRef struct { - API *API `json:"-"` - Shape *Shape `json:"-"` - Documentation string - ShapeName string `json:"shape"` - Location string - LocationName string - QueryName string - Flattened bool - Streaming bool - XMLAttribute bool - // Ignore, if set, will not be sent over the wire - Ignore bool - XMLNamespace XMLInfo - Payload string - IdempotencyToken bool `json:"idempotencyToken"` - JSONValue bool `json:"jsonvalue"` - Deprecated bool `json:"deprecated"` - - OrigShapeName string `json:"-"` - - GenerateGetter bool -} - -// ErrorInfo represents the error block of a shape's structure -type ErrorInfo struct { - Code string - HTTPStatusCode int -} - -// A XMLInfo defines URL and prefix for Shapes when rendered as XML -type XMLInfo struct { - Prefix string - URI string -} - -// A Shape defines the definition of a shape type -type Shape struct { - API *API `json:"-"` - ShapeName string - Documentation string - MemberRefs map[string]*ShapeRef `json:"members"` - MemberRef ShapeRef `json:"member"` - KeyRef ShapeRef `json:"key"` - ValueRef ShapeRef `json:"value"` - Required []string - Payload string - Type string - Exception bool - Enum []string - EnumConsts []string - Flattened bool - Streaming bool - Location string - LocationName string - IdempotencyToken bool `json:"idempotencyToken"` - XMLNamespace XMLInfo - Min float64 // optional Minimum length (string, list) or value (number) - Max float64 // optional Maximum length (string, list) or value (number) - - refs []*ShapeRef // References to this shape - resolvePkg string // use this package in the goType() if present - - OrigShapeName string `json:"-"` - - // Defines if the shape is a placeholder and should not be used directly - Placeholder bool - - Deprecated bool `json:"deprecated"` - - Validations ShapeValidations - - // Error information that is set if the shape is an error shape. - IsError bool - ErrorInfo ErrorInfo `json:"error"` -} - -// ErrorCodeName will return the error shape's name formated for -// error code const. -func (s *Shape) ErrorCodeName() string { - return "ErrCode" + s.ShapeName -} - -// ErrorName will return the shape's name or error code if available based -// on the API's protocol. This is the error code string returned by the service. -func (s *Shape) ErrorName() string { - name := s.ShapeName - switch s.API.Metadata.Protocol { - case "query", "ec2query", "rest-xml": - if len(s.ErrorInfo.Code) > 0 { - name = s.ErrorInfo.Code - } - } - - return name -} - -// GoTags returns the struct tags for a shape. -func (s *Shape) GoTags(root, required bool) string { - ref := &ShapeRef{ShapeName: s.ShapeName, API: s.API, Shape: s} - return ref.GoTags(root, required) -} - -// Rename changes the name of the Shape to newName. Also updates -// the associated API's reference to use newName. -func (s *Shape) Rename(newName string) { - for _, r := range s.refs { - r.OrigShapeName = r.ShapeName - r.ShapeName = newName - } - - delete(s.API.Shapes, s.ShapeName) - s.OrigShapeName = s.ShapeName - s.API.Shapes[newName] = s - s.ShapeName = newName -} - -// MemberNames returns a slice of struct member names. -func (s *Shape) MemberNames() []string { - i, names := 0, make([]string, len(s.MemberRefs)) - for n := range s.MemberRefs { - names[i] = n - i++ - } - sort.Strings(names) - return names -} - -// GoTypeWithPkgName returns a shape's type as a string with the package name in -// . format. Package naming only applies to structures. -func (s *Shape) GoTypeWithPkgName() string { - return goType(s, true) -} - -func (s *Shape) GoTypeWithPkgNameElem() string { - t := goType(s, true) - if strings.HasPrefix(t, "*") { - return t[1:] - } - return t -} - -// GenAccessors returns if the shape's reference should have setters generated. -func (s *ShapeRef) UseIndirection() bool { - switch s.Shape.Type { - case "map", "list", "blob", "structure", "jsonvalue": - return false - } - - if s.Streaming || s.Shape.Streaming { - return false - } - - if s.JSONValue { - return false - } - - return true -} - -// GoStructValueType returns the Shape's Go type value instead of a pointer -// for the type. -func (s *Shape) GoStructValueType(name string, ref *ShapeRef) string { - v := s.GoStructType(name, ref) - - if ref.UseIndirection() && v[0] == '*' { - return v[1:] - } - - return v -} - -// GoStructType returns the type of a struct field based on the API -// model definition. -func (s *Shape) GoStructType(name string, ref *ShapeRef) string { - if (ref.Streaming || ref.Shape.Streaming) && s.Payload == name { - rtype := "io.ReadSeeker" - if strings.HasSuffix(s.ShapeName, "Output") { - rtype = "io.ReadCloser" - } - - s.API.imports["io"] = true - return rtype - } - - if ref.JSONValue { - s.API.imports["github.com/aws/aws-sdk-go/aws"] = true - return "aws.JSONValue" - } - - for _, v := range s.Validations { - // TODO move this to shape validation resolution - if (v.Ref.Shape.Type == "map" || v.Ref.Shape.Type == "list") && v.Type == ShapeValidationNested { - s.API.imports["fmt"] = true - } - } - - return ref.GoType() -} - -// GoType returns a shape's Go type -func (s *Shape) GoType() string { - return goType(s, false) -} - -// GoType returns a shape ref's Go type. -func (ref *ShapeRef) GoType() string { - if ref.Shape == nil { - panic(fmt.Errorf("missing shape definition on reference for %#v", ref)) - } - - return ref.Shape.GoType() -} - -// GoTypeWithPkgName returns a shape's type as a string with the package name in -// . format. Package naming only applies to structures. -func (ref *ShapeRef) GoTypeWithPkgName() string { - if ref.Shape == nil { - panic(fmt.Errorf("missing shape definition on reference for %#v", ref)) - } - - return ref.Shape.GoTypeWithPkgName() -} - -// Returns a string version of the Shape's type. -// If withPkgName is true, the package name will be added as a prefix -func goType(s *Shape, withPkgName bool) string { - switch s.Type { - case "structure": - if withPkgName || s.resolvePkg != "" { - pkg := s.resolvePkg - if pkg != "" { - s.API.imports[pkg] = true - pkg = path.Base(pkg) - } else { - pkg = s.API.PackageName() - } - return fmt.Sprintf("*%s.%s", pkg, s.ShapeName) - } - return "*" + s.ShapeName - case "map": - return "map[string]" + goType(s.ValueRef.Shape, withPkgName) - case "jsonvalue": - return "aws.JSONValue" - case "list": - return "[]" + goType(s.MemberRef.Shape, withPkgName) - case "boolean": - return "*bool" - case "string", "character": - return "*string" - case "blob": - return "[]byte" - case "integer", "long": - return "*int64" - case "float", "double": - return "*float64" - case "timestamp": - s.API.imports["time"] = true - return "*time.Time" - default: - panic("Unsupported shape type: " + s.Type) - } -} - -// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just -// the type will be returned minus the pointer *. -func (s *Shape) GoTypeElem() string { - t := s.GoType() - if strings.HasPrefix(t, "*") { - return t[1:] - } - return t -} - -// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just -// the type will be returned minus the pointer *. -func (ref *ShapeRef) GoTypeElem() string { - if ref.Shape == nil { - panic(fmt.Errorf("missing shape definition on reference for %#v", ref)) - } - - return ref.Shape.GoTypeElem() -} - -// ShapeTag is a struct tag that will be applied to a shape's generated code -type ShapeTag struct { - Key, Val string -} - -// String returns the string representation of the shape tag -func (s ShapeTag) String() string { - return fmt.Sprintf(`%s:"%s"`, s.Key, s.Val) -} - -// ShapeTags is a collection of shape tags and provides serialization of the -// tags in an ordered list. -type ShapeTags []ShapeTag - -// Join returns an ordered serialization of the shape tags with the provided -// separator. -func (s ShapeTags) Join(sep string) string { - o := &bytes.Buffer{} - for i, t := range s { - o.WriteString(t.String()) - if i < len(s)-1 { - o.WriteString(sep) - } - } - - return o.String() -} - -// String is an alias for Join with the empty space separator. -func (s ShapeTags) String() string { - return s.Join(" ") -} - -// GoTags returns the rendered tags string for the ShapeRef -func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string { - tags := ShapeTags{} - - if ref.Location != "" { - tags = append(tags, ShapeTag{"location", ref.Location}) - } else if ref.Shape.Location != "" { - tags = append(tags, ShapeTag{"location", ref.Shape.Location}) - } - - if ref.LocationName != "" { - tags = append(tags, ShapeTag{"locationName", ref.LocationName}) - } else if ref.Shape.LocationName != "" { - tags = append(tags, ShapeTag{"locationName", ref.Shape.LocationName}) - } - - if ref.QueryName != "" { - tags = append(tags, ShapeTag{"queryName", ref.QueryName}) - } - if ref.Shape.MemberRef.LocationName != "" { - tags = append(tags, ShapeTag{"locationNameList", ref.Shape.MemberRef.LocationName}) - } - if ref.Shape.KeyRef.LocationName != "" { - tags = append(tags, ShapeTag{"locationNameKey", ref.Shape.KeyRef.LocationName}) - } - if ref.Shape.ValueRef.LocationName != "" { - tags = append(tags, ShapeTag{"locationNameValue", ref.Shape.ValueRef.LocationName}) - } - if ref.Shape.Min > 0 { - tags = append(tags, ShapeTag{"min", fmt.Sprintf("%v", ref.Shape.Min)}) - } - - if ref.Deprecated || ref.Shape.Deprecated { - tags = append(tags, ShapeTag{"deprecated", "true"}) - } - - // All shapes have a type - tags = append(tags, ShapeTag{"type", ref.Shape.Type}) - - // embed the timestamp type for easier lookups - if ref.Shape.Type == "timestamp" { - t := ShapeTag{Key: "timestampFormat"} - if ref.Location == "header" { - t.Val = "rfc822" - } else { - switch ref.API.Metadata.Protocol { - case "json", "rest-json": - t.Val = "unix" - case "rest-xml", "ec2", "query": - t.Val = "iso8601" - } - } - tags = append(tags, t) - } - - if ref.Shape.Flattened || ref.Flattened { - tags = append(tags, ShapeTag{"flattened", "true"}) - } - if ref.XMLAttribute { - tags = append(tags, ShapeTag{"xmlAttribute", "true"}) - } - if isRequired { - tags = append(tags, ShapeTag{"required", "true"}) - } - if ref.Shape.IsEnum() { - tags = append(tags, ShapeTag{"enum", ref.ShapeName}) - } - - if toplevel { - if ref.Shape.Payload != "" { - tags = append(tags, ShapeTag{"payload", ref.Shape.Payload}) - } - } - - if ref.XMLNamespace.Prefix != "" { - tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix}) - } else if ref.Shape.XMLNamespace.Prefix != "" { - tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix}) - } - - if ref.XMLNamespace.URI != "" { - tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI}) - } else if ref.Shape.XMLNamespace.URI != "" { - tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI}) - } - - if ref.IdempotencyToken || ref.Shape.IdempotencyToken { - tags = append(tags, ShapeTag{"idempotencyToken", "true"}) - } - - if ref.Ignore { - tags = append(tags, ShapeTag{"ignore", "true"}) - } - - return fmt.Sprintf("`%s`", tags) -} - -// Docstring returns the godocs formated documentation -func (ref *ShapeRef) Docstring() string { - if ref.Documentation != "" { - return strings.Trim(ref.Documentation, "\n ") - } - return ref.Shape.Docstring() -} - -// Docstring returns the godocs formated documentation -func (s *Shape) Docstring() string { - return strings.Trim(s.Documentation, "\n ") -} - -// IndentedDocstring is the indented form of the doc string. -func (ref *ShapeRef) IndentedDocstring() string { - doc := ref.Docstring() - return strings.Replace(doc, "// ", "// ", -1) -} - -var goCodeStringerTmpl = template.Must(template.New("goCodeStringerTmpl").Parse(` -// String returns the string representation -func (s {{ .ShapeName }}) String() string { - return awsutil.Prettify(s) -} -// GoString returns the string representation -func (s {{ .ShapeName }}) GoString() string { - return s.String() -} -`)) - -// GoCodeStringers renders the Stringers for API input/output shapes -func (s *Shape) GoCodeStringers() string { - w := bytes.Buffer{} - if err := goCodeStringerTmpl.Execute(&w, s); err != nil { - panic(fmt.Sprintln("Unexpected error executing GoCodeStringers template", err)) - } - - return w.String() -} - -var enumStrip = regexp.MustCompile(`[^a-zA-Z0-9_:\./-]`) -var enumDelims = regexp.MustCompile(`[-_:\./]+`) -var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`) - -// EnumName returns the Nth enum in the shapes Enum list -func (s *Shape) EnumName(n int) string { - enum := s.Enum[n] - enum = enumStrip.ReplaceAllLiteralString(enum, "") - enum = enumCamelCase.ReplaceAllString(enum, "$1-$2") - parts := enumDelims.Split(enum, -1) - for i, v := range parts { - v = strings.ToLower(v) - parts[i] = "" - if len(v) > 0 { - parts[i] = strings.ToUpper(v[0:1]) - } - if len(v) > 1 { - parts[i] += v[1:] - } - } - enum = strings.Join(parts, "") - enum = strings.ToUpper(enum[0:1]) + enum[1:] - return enum -} - -// NestedShape returns the shape pointer value for the shape which is nested -// under the current shape. If the shape is not nested nil will be returned. -// -// strucutures, the current shape is returned -// map: the value shape of the map is returned -// list: the element shape of the list is returned -func (s *Shape) NestedShape() *Shape { - var nestedShape *Shape - switch s.Type { - case "structure": - nestedShape = s - case "map": - nestedShape = s.ValueRef.Shape - case "list": - nestedShape = s.MemberRef.Shape - } - - return nestedShape -} - -var structShapeTmpl = template.Must(template.New("StructShape").Funcs(template.FuncMap{ - "GetCrosslinkURL": GetCrosslinkURL, -}).Parse(` -{{ .Docstring }} -{{ if ne $.OrigShapeName "" -}} -{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.OrigShapeName -}} -{{ if ne $crosslinkURL "" -}} -// Please also see {{ $crosslinkURL }} -{{ end -}} -{{ else -}} -{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ShapeName -}} -{{ if ne $crosslinkURL "" -}} -// Please also see {{ $crosslinkURL }} -{{ end -}} -{{ end -}} -{{ $context := . -}} -type {{ .ShapeName }} struct { - _ struct{} {{ .GoTags true false }} - - {{ range $_, $name := $context.MemberNames -}} - {{ $elem := index $context.MemberRefs $name -}} - {{ $isBlob := $context.WillRefBeBase64Encoded $name -}} - {{ $isRequired := $context.IsRequired $name -}} - {{ $doc := $elem.Docstring -}} - - {{ if $doc -}} - {{ $doc }} - {{ end -}} - {{ if $isBlob -}} - {{ if $doc -}} - // - {{ end -}} - // {{ $name }} is automatically base64 encoded/decoded by the SDK. - {{ end -}} - {{ if $isRequired -}} - {{ if or $doc $isBlob -}} - // - {{ end -}} - // {{ $name }} is a required field - {{ end -}} - {{ $name }} {{ $context.GoStructType $name $elem }} {{ $elem.GoTags false $isRequired }} - - {{ end }} -} -{{ if not .API.NoStringerMethods }} - {{ .GoCodeStringers }} -{{ end }} -{{ if not .API.NoValidataShapeMethods }} - {{ if .Validations -}} - {{ .Validations.GoCode . }} - {{ end }} -{{ end }} - -{{ if not .API.NoGenStructFieldAccessors }} - -{{ $builderShapeName := print .ShapeName -}} - -{{ range $_, $name := $context.MemberNames -}} - {{ $elem := index $context.MemberRefs $name -}} - -// Set{{ $name }} sets the {{ $name }} field's value. -func (s *{{ $builderShapeName }}) Set{{ $name }}(v {{ $context.GoStructValueType $name $elem }}) *{{ $builderShapeName }} { - {{ if $elem.UseIndirection -}} - s.{{ $name }} = &v - {{ else -}} - s.{{ $name }} = v - {{ end -}} - return s -} - -{{ if $elem.GenerateGetter -}} -func (s *{{ $builderShapeName }}) get{{ $name }}() (v {{ $context.GoStructValueType $name $elem }}) { - {{ if $elem.UseIndirection -}} - if s.{{ $name }} == nil { - return v - } - return *s.{{ $name }} - {{ else -}} - return s.{{ $name }} - {{ end -}} -} -{{- end }} - -{{ end }} -{{ end }} -`)) - -var enumShapeTmpl = template.Must(template.New("EnumShape").Parse(` -{{ .Docstring }} -const ( - {{ $context := . -}} - {{ range $index, $elem := .Enum -}} - {{ $name := index $context.EnumConsts $index -}} - // {{ $name }} is a {{ $context.ShapeName }} enum value - {{ $name }} = "{{ $elem }}" - - {{ end }} -) -`)) - -// GoCode returns the rendered Go code for the Shape. -func (s *Shape) GoCode() string { - b := &bytes.Buffer{} - - switch { - case s.Type == "structure": - if err := structShapeTmpl.Execute(b, s); err != nil { - panic(fmt.Sprintf("Failed to generate struct shape %s, %v\n", s.ShapeName, err)) - } - case s.IsEnum(): - if err := enumShapeTmpl.Execute(b, s); err != nil { - panic(fmt.Sprintf("Failed to generate enum shape %s, %v\n", s.ShapeName, err)) - } - default: - panic(fmt.Sprintln("Cannot generate toplevel shape for", s.Type)) - } - - return b.String() -} - -// IsEnum returns whether this shape is an enum list -func (s *Shape) IsEnum() bool { - return s.Type == "string" && len(s.Enum) > 0 -} - -// IsRequired returns if member is a required field. -func (s *Shape) IsRequired(member string) bool { - for _, n := range s.Required { - if n == member { - return true - } - } - return false -} - -// IsInternal returns whether the shape was defined in this package -func (s *Shape) IsInternal() bool { - return s.resolvePkg == "" -} - -// removeRef removes a shape reference from the list of references this -// shape is used in. -func (s *Shape) removeRef(ref *ShapeRef) { - r := s.refs - for i := 0; i < len(r); i++ { - if r[i] == ref { - j := i + 1 - copy(r[i:], r[j:]) - for k, n := len(r)-j+i, len(r); k < n; k++ { - r[k] = nil // free up the end of the list - } // for k - s.refs = r[:len(r)-j+i] - break - } - } -} - -func (s *Shape) WillRefBeBase64Encoded(refName string) bool { - payloadRefName := s.Payload - if payloadRefName == refName { - return false - } - - ref, ok := s.MemberRefs[refName] - if !ok { - panic(fmt.Sprintf("shape %s does not contain %q refName", s.ShapeName, refName)) - } - - return ref.Shape.Type == "blob" -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/shape_validation.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/shape_validation.go deleted file mode 100644 index 6f8abfd158c..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/shape_validation.go +++ /dev/null @@ -1,155 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "fmt" - "text/template" -) - -// A ShapeValidationType is the type of validation that a shape needs -type ShapeValidationType int - -const ( - // ShapeValidationRequired states the shape must be set - ShapeValidationRequired = iota - - // ShapeValidationMinVal states the shape must have at least a number of - // elements, or for numbers a minimum value - ShapeValidationMinVal - - // ShapeValidationNested states the shape has nested values that need - // to be validated - ShapeValidationNested -) - -// A ShapeValidation contains information about a shape and the type of validation -// that is needed -type ShapeValidation struct { - // Name of the shape to be validated - Name string - // Reference to the shape within the context the shape is referenced - Ref *ShapeRef - // Type of validation needed - Type ShapeValidationType -} - -var validationGoCodeTmpls = template.Must(template.New("validationGoCodeTmpls").Parse(` -{{ define "requiredValue" -}} - if s.{{ .Name }} == nil { - invalidParams.Add(request.NewErrParamRequired("{{ .Name }}")) - } -{{- end }} -{{ define "minLen" -}} - if s.{{ .Name }} != nil && len(s.{{ .Name }}) < {{ .Ref.Shape.Min }} { - invalidParams.Add(request.NewErrParamMinLen("{{ .Name }}", {{ .Ref.Shape.Min }})) - } -{{- end }} -{{ define "minLenString" -}} - if s.{{ .Name }} != nil && len(*s.{{ .Name }}) < {{ .Ref.Shape.Min }} { - invalidParams.Add(request.NewErrParamMinLen("{{ .Name }}", {{ .Ref.Shape.Min }})) - } -{{- end }} -{{ define "minVal" -}} - if s.{{ .Name }} != nil && *s.{{ .Name }} < {{ .Ref.Shape.Min }} { - invalidParams.Add(request.NewErrParamMinValue("{{ .Name }}", {{ .Ref.Shape.Min }})) - } -{{- end }} -{{ define "nestedMapList" -}} - if s.{{ .Name }} != nil { - for i, v := range s.{{ .Name }} { - if v == nil { continue } - if err := v.Validate(); err != nil { - invalidParams.AddNested(fmt.Sprintf("%s[%v]", "{{ .Name }}", i), err.(request.ErrInvalidParams)) - } - } - } -{{- end }} -{{ define "nestedStruct" -}} - if s.{{ .Name }} != nil { - if err := s.{{ .Name }}.Validate(); err != nil { - invalidParams.AddNested("{{ .Name }}", err.(request.ErrInvalidParams)) - } - } -{{- end }} -`)) - -// GoCode returns the generated Go code for the Shape with its validation type. -func (sv ShapeValidation) GoCode() string { - var err error - - w := &bytes.Buffer{} - switch sv.Type { - case ShapeValidationRequired: - err = validationGoCodeTmpls.ExecuteTemplate(w, "requiredValue", sv) - case ShapeValidationMinVal: - switch sv.Ref.Shape.Type { - case "list", "map", "blob": - err = validationGoCodeTmpls.ExecuteTemplate(w, "minLen", sv) - case "string": - err = validationGoCodeTmpls.ExecuteTemplate(w, "minLenString", sv) - case "integer", "long", "float", "double": - err = validationGoCodeTmpls.ExecuteTemplate(w, "minVal", sv) - default: - panic(fmt.Sprintf("ShapeValidation.GoCode, %s's type %s, no min value handling", - sv.Name, sv.Ref.Shape.Type)) - } - case ShapeValidationNested: - switch sv.Ref.Shape.Type { - case "map", "list": - err = validationGoCodeTmpls.ExecuteTemplate(w, "nestedMapList", sv) - default: - err = validationGoCodeTmpls.ExecuteTemplate(w, "nestedStruct", sv) - } - default: - panic(fmt.Sprintf("ShapeValidation.GoCode, %s's type %d, unknown validation type", - sv.Name, sv.Type)) - } - - if err != nil { - panic(fmt.Sprintf("ShapeValidation.GoCode failed, err: %v", err)) - } - - return w.String() -} - -// A ShapeValidations is a collection of shape validations needed nested within -// a parent shape -type ShapeValidations []ShapeValidation - -var validateShapeTmpl = template.Must(template.New("ValidateShape").Parse(` -// Validate inspects the fields of the type to determine if they are valid. -func (s *{{ .Shape.ShapeName }}) Validate() error { - invalidParams := request.ErrInvalidParams{Context: "{{ .Shape.ShapeName }}"} - {{ range $_, $v := .Validations -}} - {{ $v.GoCode }} - {{ end }} - if invalidParams.Len() > 0 { - return invalidParams - } - return nil -} -`)) - -// GoCode generates the Go code needed to perform validations for the -// shape and its nested fields. -func (vs ShapeValidations) GoCode(shape *Shape) string { - buf := &bytes.Buffer{} - validateShapeTmpl.Execute(buf, map[string]interface{}{ - "Shape": shape, - "Validations": vs, - }) - return buf.String() -} - -// Has returns true or false if the ShapeValidations already contains the -// the reference and validation type. -func (vs ShapeValidations) Has(ref *ShapeRef, typ ShapeValidationType) bool { - for _, v := range vs { - if v.Ref == ref && v.Type == typ { - return true - } - } - return false -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/api/waiters.go b/vendor/github.com/aws/aws-sdk-go/private/model/api/waiters.go deleted file mode 100644 index 796d40ecdfc..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/api/waiters.go +++ /dev/null @@ -1,189 +0,0 @@ -// +build codegen - -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "sort" - "strings" - "text/template" -) - -// WaiterAcceptor is the acceptors defined in the model the SDK will use -// to wait on resource states with. -type WaiterAcceptor struct { - State string - Matcher string - Argument string - Expected interface{} -} - -// ExpectedString returns the string that was expected by the WaiterAcceptor -func (a *WaiterAcceptor) ExpectedString() string { - switch a.Expected.(type) { - case string: - return fmt.Sprintf("%q", a.Expected) - default: - return fmt.Sprintf("%v", a.Expected) - } -} - -// A Waiter is an individual waiter definition. -type Waiter struct { - Name string - Delay int - MaxAttempts int - OperationName string `json:"operation"` - Operation *Operation - Acceptors []WaiterAcceptor -} - -// WaitersGoCode generates and returns Go code for each of the waiters of -// this API. -func (a *API) WaitersGoCode() string { - var buf bytes.Buffer - fmt.Fprintf(&buf, "import (\n%q\n\n%q\n%q\n)", - "time", - "github.com/aws/aws-sdk-go/aws", - "github.com/aws/aws-sdk-go/aws/request", - ) - - for _, w := range a.Waiters { - buf.WriteString(w.GoCode()) - } - return buf.String() -} - -// used for unmarshaling from the waiter JSON file -type waiterDefinitions struct { - *API - Waiters map[string]Waiter -} - -// AttachWaiters reads a file of waiter definitions, and adds those to the API. -// Will panic if an error occurs. -func (a *API) AttachWaiters(filename string) { - p := waiterDefinitions{API: a} - - f, err := os.Open(filename) - defer f.Close() - if err != nil { - panic(err) - } - err = json.NewDecoder(f).Decode(&p) - if err != nil { - panic(err) - } - - p.setup() -} - -func (p *waiterDefinitions) setup() { - p.API.Waiters = []Waiter{} - i, keys := 0, make([]string, len(p.Waiters)) - for k := range p.Waiters { - keys[i] = k - i++ - } - sort.Strings(keys) - - for _, n := range keys { - e := p.Waiters[n] - n = p.ExportableName(n) - e.Name = n - e.OperationName = p.ExportableName(e.OperationName) - e.Operation = p.API.Operations[e.OperationName] - if e.Operation == nil { - panic("unknown operation " + e.OperationName + " for waiter " + n) - } - p.API.Waiters = append(p.API.Waiters, e) - } -} - -var waiterTmpls = template.Must(template.New("waiterTmpls").Funcs( - template.FuncMap{ - "titleCase": func(v string) string { - return strings.Title(v) - }, - }, -).Parse(` -{{ define "waiter"}} -// WaitUntil{{ .Name }} uses the {{ .Operation.API.NiceName }} API operation -// {{ .OperationName }} to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will -// be returned. -func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}(input {{ .Operation.InputRef.GoType }}) error { - return c.WaitUntil{{ .Name }}WithContext(aws.BackgroundContext(), input) -} - -// WaitUntil{{ .Name }}WithContext is an extended version of WaitUntil{{ .Name }}. -// With the support for passing in a context and options to configure the -// Waiter and the underlying request options. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}WithContext(` + - `ctx aws.Context, input {{ .Operation.InputRef.GoType }}, opts ...request.WaiterOption) error { - w := request.Waiter{ - Name: "WaitUntil{{ .Name }}", - MaxAttempts: {{ .MaxAttempts }}, - Delay: request.ConstantWaiterDelay({{ .Delay }} * time.Second), - Acceptors: []request.WaiterAcceptor{ - {{ range $_, $a := .Acceptors }}{ - State: request.{{ titleCase .State }}WaiterState, - Matcher: request.{{ titleCase .Matcher }}WaiterMatch, - {{- if .Argument }}Argument: "{{ .Argument }}",{{ end }} - Expected: {{ .ExpectedString }}, - }, - {{ end }} - }, - Logger: c.Config.Logger, - NewRequest: func(opts []request.Option) (*request.Request, error) { - var inCpy {{ .Operation.InputRef.GoType }} - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.{{ .OperationName }}Request(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - w.ApplyOptions(opts...) - - return w.WaitWithContext(ctx) -} -{{- end }} - -{{ define "waiter interface" }} -WaitUntil{{ .Name }}({{ .Operation.InputRef.GoTypeWithPkgName }}) error -WaitUntil{{ .Name }}WithContext(aws.Context, {{ .Operation.InputRef.GoTypeWithPkgName }}, ...request.WaiterOption) error -{{- end }} -`)) - -// InterfaceSignature returns a string representing the Waiter's interface -// function signature. -func (w *Waiter) InterfaceSignature() string { - var buf bytes.Buffer - if err := waiterTmpls.ExecuteTemplate(&buf, "waiter interface", w); err != nil { - panic(err) - } - - return strings.TrimSpace(buf.String()) -} - -// GoCode returns the generated Go code for an individual waiter. -func (w *Waiter) GoCode() string { - var buf bytes.Buffer - if err := waiterTmpls.ExecuteTemplate(&buf, "waiter", w); err != nil { - panic(err) - } - - return buf.String() -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/cli/api-info/api-info.go b/vendor/github.com/aws/aws-sdk-go/private/model/cli/api-info/api-info.go deleted file mode 100644 index ee2b66d6492..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/cli/api-info/api-info.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build codegen - -package main - -import ( - "fmt" - "os" - "path/filepath" - "sort" - - "github.com/aws/aws-sdk-go/private/model/api" -) - -func main() { - dir, _ := os.Open(filepath.Join("models", "apis")) - names, _ := dir.Readdirnames(0) - for _, name := range names { - m, _ := filepath.Glob(filepath.Join("models", "apis", name, "*", "api-2.json")) - if len(m) == 0 { - continue - } - - sort.Strings(m) - f := m[len(m)-1] - a := api.API{} - a.Attach(f) - fmt.Printf("%s\t%s\n", a.Metadata.ServiceFullName, a.Metadata.APIVersion) - } -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/cli/gen-api/main.go b/vendor/github.com/aws/aws-sdk-go/private/model/cli/gen-api/main.go deleted file mode 100644 index 005a74d6adc..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/cli/gen-api/main.go +++ /dev/null @@ -1,303 +0,0 @@ -// +build codegen - -// Command aws-gen-gocli parses a JSON description of an AWS API and generates a -// Go file containing a client for the API. -// -// aws-gen-gocli apis/s3/2006-03-03/api-2.json -package main - -import ( - "flag" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "runtime/debug" - "sort" - "strings" - "sync" - - "github.com/aws/aws-sdk-go/private/model/api" - "github.com/aws/aws-sdk-go/private/util" -) - -type generateInfo struct { - *api.API - PackageDir string -} - -var excludeServices = map[string]struct{}{ - "importexport": {}, -} - -// newGenerateInfo initializes the service API's folder structure for a specific service. -// If the SERVICES environment variable is set, and this service is not apart of the list -// this service will be skipped. -func newGenerateInfo(modelFile, svcPath, svcImportPath string) *generateInfo { - g := &generateInfo{API: &api.API{SvcClientImportPath: svcImportPath, BaseCrosslinkURL: "https://docs.aws.amazon.com"}} - g.API.Attach(modelFile) - - if _, ok := excludeServices[g.API.PackageName()]; ok { - return nil - } - - paginatorsFile := strings.Replace(modelFile, "api-2.json", "paginators-1.json", -1) - if _, err := os.Stat(paginatorsFile); err == nil { - g.API.AttachPaginators(paginatorsFile) - } else if !os.IsNotExist(err) { - fmt.Println("api-2.json error:", err) - } - - docsFile := strings.Replace(modelFile, "api-2.json", "docs-2.json", -1) - if _, err := os.Stat(docsFile); err == nil { - g.API.AttachDocs(docsFile) - } else { - fmt.Println("docs-2.json error:", err) - } - - waitersFile := strings.Replace(modelFile, "api-2.json", "waiters-2.json", -1) - if _, err := os.Stat(waitersFile); err == nil { - g.API.AttachWaiters(waitersFile) - } else if !os.IsNotExist(err) { - fmt.Println("waiters-2.json error:", err) - } - - examplesFile := strings.Replace(modelFile, "api-2.json", "examples-1.json", -1) - if _, err := os.Stat(examplesFile); err == nil { - g.API.AttachExamples(examplesFile) - } else if !os.IsNotExist(err) { - fmt.Println("examples-1.json error:", err) - } - - // pkgDocAddonsFile := strings.Replace(modelFile, "api-2.json", "go-pkg-doc.gotmpl", -1) - // if _, err := os.Stat(pkgDocAddonsFile); err == nil { - // g.API.AttachPackageDocAddons(pkgDocAddonsFile) - // } else if !os.IsNotExist(err) { - // fmt.Println("go-pkg-doc.gotmpl error:", err) - // } - - g.API.Setup() - - if svc := os.Getenv("SERVICES"); svc != "" { - svcs := strings.Split(svc, ",") - - included := false - for _, s := range svcs { - if s == g.API.PackageName() { - included = true - break - } - } - if !included { - // skip this non-included service - return nil - } - } - - // ensure the directory exists - pkgDir := filepath.Join(svcPath, g.API.PackageName()) - os.MkdirAll(pkgDir, 0775) - os.MkdirAll(filepath.Join(pkgDir, g.API.InterfacePackageName()), 0775) - - g.PackageDir = pkgDir - - return g -} - -// Generates service api, examples, and interface from api json definition files. -// -// Flags: -// -path alternative service path to write generated files to for each service. -// -// Env: -// SERVICES comma separated list of services to generate. -func main() { - var svcPath, sessionPath, svcImportPath string - flag.StringVar(&svcPath, "path", "service", "directory to generate service clients in") - flag.StringVar(&sessionPath, "sessionPath", filepath.Join("aws", "session"), "generate session service client factories") - flag.StringVar(&svcImportPath, "svc-import-path", "github.com/aws/aws-sdk-go/service", "namespace to generate service client Go code import path under") - flag.Parse() - api.Bootstrap() - - files := []string{} - for i := 0; i < flag.NArg(); i++ { - file := flag.Arg(i) - if strings.Contains(file, "*") { - paths, _ := filepath.Glob(file) - files = append(files, paths...) - } else { - files = append(files, file) - } - } - - for svcName := range excludeServices { - if strings.Contains(os.Getenv("SERVICES"), svcName) { - fmt.Printf("Service %s is not supported\n", svcName) - os.Exit(1) - } - } - - sort.Strings(files) - - // Remove old API versions from list - m := map[string]bool{} - for i := range files { - idx := len(files) - 1 - i - parts := strings.Split(files[idx], string(filepath.Separator)) - svc := parts[len(parts)-3] // service name is 2nd-to-last component - - if m[svc] { - files[idx] = "" // wipe this one out if we already saw the service - } - m[svc] = true - } - - wg := sync.WaitGroup{} - for i := range files { - filename := files[i] - if filename == "" { // empty file - continue - } - - genInfo := newGenerateInfo(filename, svcPath, svcImportPath) - if genInfo == nil { - continue - } - if _, ok := excludeServices[genInfo.API.PackageName()]; ok { - // Skip services not yet supported. - continue - } - - wg.Add(1) - go func(g *generateInfo, filename string) { - defer wg.Done() - writeServiceFiles(g, filename) - }(genInfo, filename) - } - - wg.Wait() -} - -func writeServiceFiles(g *generateInfo, filename string) { - defer func() { - if r := recover(); r != nil { - fmt.Fprintf(os.Stderr, "Error generating %s\n%s\n%s\n", - filename, r, debug.Stack()) - } - }() - - fmt.Printf("Generating %s (%s)...\n", - g.API.PackageName(), g.API.Metadata.APIVersion) - - // write files for service client and API - Must(writeServiceDocFile(g)) - Must(writeAPIFile(g)) - Must(writeServiceFile(g)) - Must(writeInterfaceFile(g)) - Must(writeWaitersFile(g)) - Must(writeAPIErrorsFile(g)) - Must(writeExamplesFile(g)) -} - -// Must will panic if the error passed in is not nil. -func Must(err error) { - if err != nil { - panic(err) - } -} - -const codeLayout = `// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -%s -package %s - -%s -` - -func writeGoFile(file string, layout string, args ...interface{}) error { - return ioutil.WriteFile(file, []byte(util.GoFmt(fmt.Sprintf(layout, args...))), 0664) -} - -// writeServiceDocFile generates the documentation for service package. -func writeServiceDocFile(g *generateInfo) error { - return writeGoFile(filepath.Join(g.PackageDir, "doc.go"), - codeLayout, - strings.TrimSpace(g.API.ServicePackageDoc()), - g.API.PackageName(), - "", - ) -} - -// writeExamplesFile writes out the service example file. -func writeExamplesFile(g *generateInfo) error { - code := g.API.ExamplesGoCode() - if len(code) > 0 { - return writeGoFile(filepath.Join(g.PackageDir, "examples_test.go"), - codeLayout, - "", - g.API.PackageName()+"_test", - code, - ) - } - return nil -} - -// writeServiceFile writes out the service initialization file. -func writeServiceFile(g *generateInfo) error { - return writeGoFile(filepath.Join(g.PackageDir, "service.go"), - codeLayout, - "", - g.API.PackageName(), - g.API.ServiceGoCode(), - ) -} - -// writeInterfaceFile writes out the service interface file. -func writeInterfaceFile(g *generateInfo) error { - const pkgDoc = ` -// Package %s provides an interface to enable mocking the %s service client -// for testing your code. -// -// It is important to note that this interface will have breaking changes -// when the service model is updated and adds new API operations, paginators, -// and waiters.` - return writeGoFile(filepath.Join(g.PackageDir, g.API.InterfacePackageName(), "interface.go"), - codeLayout, - fmt.Sprintf(pkgDoc, g.API.InterfacePackageName(), g.API.Metadata.ServiceFullName), - g.API.InterfacePackageName(), - g.API.InterfaceGoCode(), - ) -} - -func writeWaitersFile(g *generateInfo) error { - if len(g.API.Waiters) == 0 { - return nil - } - - return writeGoFile(filepath.Join(g.PackageDir, "waiters.go"), - codeLayout, - "", - g.API.PackageName(), - g.API.WaitersGoCode(), - ) -} - -// writeAPIFile writes out the service API file. -func writeAPIFile(g *generateInfo) error { - return writeGoFile(filepath.Join(g.PackageDir, "api.go"), - codeLayout, - "", - g.API.PackageName(), - g.API.APIGoCode(), - ) -} - -// writeAPIErrorsFile writes out the service API errors file. -func writeAPIErrorsFile(g *generateInfo) error { - return writeGoFile(filepath.Join(g.PackageDir, "errors.go"), - codeLayout, - "", - g.API.PackageName(), - g.API.APIErrorsGoCode(), - ) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/model/cli/gen-endpoints/main.go b/vendor/github.com/aws/aws-sdk-go/private/model/cli/gen-endpoints/main.go deleted file mode 100644 index 961eaaf2adc..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/model/cli/gen-endpoints/main.go +++ /dev/null @@ -1,56 +0,0 @@ -// +build codegen - -// Command gen-endpoints parses a JSON description of the AWS endpoint -// discovery logic and generates a Go file which returns an endpoint. -// -// aws-gen-goendpoints apis/_endpoints.json aws/endpoints_map.go -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/aws/aws-sdk-go/aws/endpoints" -) - -// Generates the endpoints from json description -// -// Args: -// -model The definition file to use -// -out The output file to generate -func main() { - var modelName, outName string - flag.StringVar(&modelName, "model", "", "Endpoints definition model") - flag.StringVar(&outName, "out", "", "File to write generated endpoints to.") - flag.Parse() - - if len(modelName) == 0 || len(outName) == 0 { - exitErrorf("model and out both required.") - } - - modelFile, err := os.Open(modelName) - if err != nil { - exitErrorf("failed to open model definition, %v.", err) - } - defer modelFile.Close() - - outFile, err := os.Create(outName) - if err != nil { - exitErrorf("failed to open out file, %v.", err) - } - defer func() { - if err := outFile.Close(); err != nil { - exitErrorf("failed to successfully write %q file, %v", outName, err) - } - }() - - if err := endpoints.CodeGenModel(modelFile, outFile); err != nil { - exitErrorf("failed to codegen model, %v", err) - } -} - -func exitErrorf(msg string, args ...interface{}) { - fmt.Fprintf(os.Stderr, msg+"\n", args...) - os.Exit(1) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go deleted file mode 100644 index 6efe43d5f39..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go +++ /dev/null @@ -1,279 +0,0 @@ -// Package jsonutil provides JSON serialization of AWS requests and responses. -package jsonutil - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "time" - - "github.com/aws/aws-sdk-go/private/protocol" -) - -var timeType = reflect.ValueOf(time.Time{}).Type() -var byteSliceType = reflect.ValueOf([]byte{}).Type() - -// BuildJSON builds a JSON string for a given object v. -func BuildJSON(v interface{}) ([]byte, error) { - var buf bytes.Buffer - - err := buildAny(reflect.ValueOf(v), &buf, "") - return buf.Bytes(), err -} - -func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { - origVal := value - value = reflect.Indirect(value) - if !value.IsValid() { - return nil - } - - vtype := value.Type() - - t := tag.Get("type") - if t == "" { - switch vtype.Kind() { - case reflect.Struct: - // also it can't be a time object - if value.Type() != timeType { - t = "structure" - } - case reflect.Slice: - // also it can't be a byte slice - if _, ok := value.Interface().([]byte); !ok { - t = "list" - } - case reflect.Map: - t = "map" - } - } - - switch t { - case "structure": - if field, ok := vtype.FieldByName("_"); ok { - tag = field.Tag - } - return buildStruct(value, buf, tag) - case "list": - return buildList(value, buf, tag) - case "map": - return buildMap(value, buf, tag) - default: - return buildScalar(origVal, buf, tag) - } -} - -func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { - if !value.IsValid() { - return nil - } - - // unwrap payloads - if payload := tag.Get("payload"); payload != "" { - field, _ := value.Type().FieldByName(payload) - tag = field.Tag - value = elemOf(value.FieldByName(payload)) - - if !value.IsValid() { - return nil - } - } - - buf.WriteByte('{') - - t := value.Type() - first := true - for i := 0; i < t.NumField(); i++ { - member := value.Field(i) - - // This allocates the most memory. - // Additionally, we cannot skip nil fields due to - // idempotency auto filling. - field := t.Field(i) - - if field.PkgPath != "" { - continue // ignore unexported fields - } - if field.Tag.Get("json") == "-" { - continue - } - if field.Tag.Get("location") != "" { - continue // ignore non-body elements - } - if field.Tag.Get("ignore") != "" { - continue - } - - if protocol.CanSetIdempotencyToken(member, field) { - token := protocol.GetIdempotencyToken() - member = reflect.ValueOf(&token) - } - - if (member.Kind() == reflect.Ptr || member.Kind() == reflect.Slice || member.Kind() == reflect.Map) && member.IsNil() { - continue // ignore unset fields - } - - if first { - first = false - } else { - buf.WriteByte(',') - } - - // figure out what this field is called - name := field.Name - if locName := field.Tag.Get("locationName"); locName != "" { - name = locName - } - - writeString(name, buf) - buf.WriteString(`:`) - - err := buildAny(member, buf, field.Tag) - if err != nil { - return err - } - - } - - buf.WriteString("}") - - return nil -} - -func buildList(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { - buf.WriteString("[") - - for i := 0; i < value.Len(); i++ { - buildAny(value.Index(i), buf, "") - - if i < value.Len()-1 { - buf.WriteString(",") - } - } - - buf.WriteString("]") - - return nil -} - -type sortedValues []reflect.Value - -func (sv sortedValues) Len() int { return len(sv) } -func (sv sortedValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } -func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].String() } - -func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { - buf.WriteString("{") - - sv := sortedValues(value.MapKeys()) - sort.Sort(sv) - - for i, k := range sv { - if i > 0 { - buf.WriteByte(',') - } - - writeString(k.String(), buf) - buf.WriteString(`:`) - - buildAny(value.MapIndex(k), buf, "") - } - - buf.WriteString("}") - - return nil -} - -func buildScalar(v reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { - // prevents allocation on the heap. - scratch := [64]byte{} - switch value := reflect.Indirect(v); value.Kind() { - case reflect.String: - writeString(value.String(), buf) - case reflect.Bool: - if value.Bool() { - buf.WriteString("true") - } else { - buf.WriteString("false") - } - case reflect.Int64: - buf.Write(strconv.AppendInt(scratch[:0], value.Int(), 10)) - case reflect.Float64: - f := value.Float() - if math.IsInf(f, 0) || math.IsNaN(f) { - return &json.UnsupportedValueError{Value: v, Str: strconv.FormatFloat(f, 'f', -1, 64)} - } - buf.Write(strconv.AppendFloat(scratch[:0], f, 'f', -1, 64)) - default: - switch value.Type() { - case timeType: - converted := v.Interface().(*time.Time) - - buf.Write(strconv.AppendInt(scratch[:0], converted.UTC().Unix(), 10)) - case byteSliceType: - if !value.IsNil() { - converted := value.Interface().([]byte) - buf.WriteByte('"') - if len(converted) < 1024 { - // for small buffers, using Encode directly is much faster. - dst := make([]byte, base64.StdEncoding.EncodedLen(len(converted))) - base64.StdEncoding.Encode(dst, converted) - buf.Write(dst) - } else { - // for large buffers, avoid unnecessary extra temporary - // buffer space. - enc := base64.NewEncoder(base64.StdEncoding, buf) - enc.Write(converted) - enc.Close() - } - buf.WriteByte('"') - } - default: - return fmt.Errorf("unsupported JSON value %v (%s)", value.Interface(), value.Type()) - } - } - return nil -} - -var hex = "0123456789abcdef" - -func writeString(s string, buf *bytes.Buffer) { - buf.WriteByte('"') - for i := 0; i < len(s); i++ { - if s[i] == '"' { - buf.WriteString(`\"`) - } else if s[i] == '\\' { - buf.WriteString(`\\`) - } else if s[i] == '\b' { - buf.WriteString(`\b`) - } else if s[i] == '\f' { - buf.WriteString(`\f`) - } else if s[i] == '\r' { - buf.WriteString(`\r`) - } else if s[i] == '\t' { - buf.WriteString(`\t`) - } else if s[i] == '\n' { - buf.WriteString(`\n`) - } else if s[i] < 32 { - buf.WriteString("\\u00") - buf.WriteByte(hex[s[i]>>4]) - buf.WriteByte(hex[s[i]&0xF]) - } else { - buf.WriteByte(s[i]) - } - } - buf.WriteByte('"') -} - -// Returns the reflection element of a value, if it is a pointer. -func elemOf(value reflect.Value) reflect.Value { - for value.Kind() == reflect.Ptr { - value = value.Elem() - } - return value -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go deleted file mode 100644 index fea53561366..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go +++ /dev/null @@ -1,213 +0,0 @@ -package jsonutil - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "reflect" - "time" -) - -// UnmarshalJSON reads a stream and unmarshals the results in object v. -func UnmarshalJSON(v interface{}, stream io.Reader) error { - var out interface{} - - b, err := ioutil.ReadAll(stream) - if err != nil { - return err - } - - if len(b) == 0 { - return nil - } - - if err := json.Unmarshal(b, &out); err != nil { - return err - } - - return unmarshalAny(reflect.ValueOf(v), out, "") -} - -func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error { - vtype := value.Type() - if vtype.Kind() == reflect.Ptr { - vtype = vtype.Elem() // check kind of actual element type - } - - t := tag.Get("type") - if t == "" { - switch vtype.Kind() { - case reflect.Struct: - // also it can't be a time object - if _, ok := value.Interface().(*time.Time); !ok { - t = "structure" - } - case reflect.Slice: - // also it can't be a byte slice - if _, ok := value.Interface().([]byte); !ok { - t = "list" - } - case reflect.Map: - t = "map" - } - } - - switch t { - case "structure": - if field, ok := vtype.FieldByName("_"); ok { - tag = field.Tag - } - return unmarshalStruct(value, data, tag) - case "list": - return unmarshalList(value, data, tag) - case "map": - return unmarshalMap(value, data, tag) - default: - return unmarshalScalar(value, data, tag) - } -} - -func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error { - if data == nil { - return nil - } - mapData, ok := data.(map[string]interface{}) - if !ok { - return fmt.Errorf("JSON value is not a structure (%#v)", data) - } - - t := value.Type() - if value.Kind() == reflect.Ptr { - if value.IsNil() { // create the structure if it's nil - s := reflect.New(value.Type().Elem()) - value.Set(s) - value = s - } - - value = value.Elem() - t = t.Elem() - } - - // unwrap any payloads - if payload := tag.Get("payload"); payload != "" { - field, _ := t.FieldByName(payload) - return unmarshalAny(value.FieldByName(payload), data, field.Tag) - } - - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - if field.PkgPath != "" { - continue // ignore unexported fields - } - - // figure out what this field is called - name := field.Name - if locName := field.Tag.Get("locationName"); locName != "" { - name = locName - } - - member := value.FieldByIndex(field.Index) - err := unmarshalAny(member, mapData[name], field.Tag) - if err != nil { - return err - } - } - return nil -} - -func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error { - if data == nil { - return nil - } - listData, ok := data.([]interface{}) - if !ok { - return fmt.Errorf("JSON value is not a list (%#v)", data) - } - - if value.IsNil() { - l := len(listData) - value.Set(reflect.MakeSlice(value.Type(), l, l)) - } - - for i, c := range listData { - err := unmarshalAny(value.Index(i), c, "") - if err != nil { - return err - } - } - - return nil -} - -func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error { - if data == nil { - return nil - } - mapData, ok := data.(map[string]interface{}) - if !ok { - return fmt.Errorf("JSON value is not a map (%#v)", data) - } - - if value.IsNil() { - value.Set(reflect.MakeMap(value.Type())) - } - - for k, v := range mapData { - kvalue := reflect.ValueOf(k) - vvalue := reflect.New(value.Type().Elem()).Elem() - - unmarshalAny(vvalue, v, "") - value.SetMapIndex(kvalue, vvalue) - } - - return nil -} - -func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error { - errf := func() error { - return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type()) - } - - switch d := data.(type) { - case nil: - return nil // nothing to do here - case string: - switch value.Interface().(type) { - case *string: - value.Set(reflect.ValueOf(&d)) - case []byte: - b, err := base64.StdEncoding.DecodeString(d) - if err != nil { - return err - } - value.Set(reflect.ValueOf(b)) - default: - return errf() - } - case float64: - switch value.Interface().(type) { - case *int64: - di := int64(d) - value.Set(reflect.ValueOf(&di)) - case *float64: - value.Set(reflect.ValueOf(&d)) - case *time.Time: - t := time.Unix(int64(d), 0).UTC() - value.Set(reflect.ValueOf(&t)) - default: - return errf() - } - case bool: - switch value.Interface().(type) { - case *bool: - value.Set(reflect.ValueOf(&d)) - default: - return errf() - } - default: - return fmt.Errorf("unsupported JSON value (%v)", data) - } - return nil -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go deleted file mode 100644 index 56af4dc4426..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go +++ /dev/null @@ -1,111 +0,0 @@ -// Package jsonrpc provides JSON RPC utilities for serialization of AWS -// requests and responses. -package jsonrpc - -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go - -import ( - "encoding/json" - "io/ioutil" - "strings" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" - "github.com/aws/aws-sdk-go/private/protocol/rest" -) - -var emptyJSON = []byte("{}") - -// BuildHandler is a named request handler for building jsonrpc protocol requests -var BuildHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Build", Fn: Build} - -// UnmarshalHandler is a named request handler for unmarshaling jsonrpc protocol requests -var UnmarshalHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Unmarshal", Fn: Unmarshal} - -// UnmarshalMetaHandler is a named request handler for unmarshaling jsonrpc protocol request metadata -var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalMeta", Fn: UnmarshalMeta} - -// UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc protocol request errors -var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalError", Fn: UnmarshalError} - -// Build builds a JSON payload for a JSON RPC request. -func Build(req *request.Request) { - var buf []byte - var err error - if req.ParamsFilled() { - buf, err = jsonutil.BuildJSON(req.Params) - if err != nil { - req.Error = awserr.New("SerializationError", "failed encoding JSON RPC request", err) - return - } - } else { - buf = emptyJSON - } - - if req.ClientInfo.TargetPrefix != "" || string(buf) != "{}" { - req.SetBufferBody(buf) - } - - if req.ClientInfo.TargetPrefix != "" { - target := req.ClientInfo.TargetPrefix + "." + req.Operation.Name - req.HTTPRequest.Header.Add("X-Amz-Target", target) - } - if req.ClientInfo.JSONVersion != "" { - jsonVersion := req.ClientInfo.JSONVersion - req.HTTPRequest.Header.Add("Content-Type", "application/x-amz-json-"+jsonVersion) - } -} - -// Unmarshal unmarshals a response for a JSON RPC service. -func Unmarshal(req *request.Request) { - defer req.HTTPResponse.Body.Close() - if req.DataFilled() { - err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body) - if err != nil { - req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err) - } - } - return -} - -// UnmarshalMeta unmarshals headers from a response for a JSON RPC service. -func UnmarshalMeta(req *request.Request) { - rest.UnmarshalMeta(req) -} - -// UnmarshalError unmarshals an error response for a JSON RPC service. -func UnmarshalError(req *request.Request) { - defer req.HTTPResponse.Body.Close() - bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) - if err != nil { - req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err) - return - } - if len(bodyBytes) == 0 { - req.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", req.HTTPResponse.Status, nil), - req.HTTPResponse.StatusCode, - "", - ) - return - } - var jsonErr jsonErrorResponse - if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { - req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err) - return - } - - codes := strings.SplitN(jsonErr.Code, "#", 2) - req.Error = awserr.NewRequestFailure( - awserr.New(codes[len(codes)-1], jsonErr.Message, nil), - req.HTTPResponse.StatusCode, - req.RequestID, - ) -} - -type jsonErrorResponse struct { - Code string `json:"__type"` - Message string `json:"message"` -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue.go new file mode 100644 index 00000000000..776d1101843 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue.go @@ -0,0 +1,76 @@ +package protocol + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "strconv" + + "github.com/aws/aws-sdk-go/aws" +) + +// EscapeMode is the mode that should be use for escaping a value +type EscapeMode uint + +// The modes for escaping a value before it is marshaled, and unmarshaled. +const ( + NoEscape EscapeMode = iota + Base64Escape + QuotedEscape +) + +// EncodeJSONValue marshals the value into a JSON string, and optionally base64 +// encodes the string before returning it. +// +// Will panic if the escape mode is unknown. +func EncodeJSONValue(v aws.JSONValue, escape EscapeMode) (string, error) { + b, err := json.Marshal(v) + if err != nil { + return "", err + } + + switch escape { + case NoEscape: + return string(b), nil + case Base64Escape: + return base64.StdEncoding.EncodeToString(b), nil + case QuotedEscape: + return strconv.Quote(string(b)), nil + } + + panic(fmt.Sprintf("EncodeJSONValue called with unknown EscapeMode, %v", escape)) +} + +// DecodeJSONValue will attempt to decode the string input as a JSONValue. +// Optionally decoding base64 the value first before JSON unmarshaling. +// +// Will panic if the escape mode is unknown. +func DecodeJSONValue(v string, escape EscapeMode) (aws.JSONValue, error) { + var b []byte + var err error + + switch escape { + case NoEscape: + b = []byte(v) + case Base64Escape: + b, err = base64.StdEncoding.DecodeString(v) + case QuotedEscape: + var u string + u, err = strconv.Unquote(v) + b = []byte(u) + default: + panic(fmt.Sprintf("DecodeJSONValue called with unknown EscapeMode, %v", escape)) + } + + if err != nil { + return nil, err + } + + m := aws.JSONValue{} + err = json.Unmarshal(b, &m) + if err != nil { + return nil, err + } + + return m, nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go index 524ca952adf..5ce9cba3291 100644 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go @@ -121,6 +121,10 @@ func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string return nil } + if _, ok := value.Interface().([]byte); ok { + return q.parseScalar(v, value, prefix, tag) + } + // check for unflattened list member if !q.isEC2 && tag.Get("flattened") == "" { if listName := tag.Get("locationNameList"); listName == "" { diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go index 71618356493..c405288d742 100644 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go @@ -4,7 +4,6 @@ package rest import ( "bytes" "encoding/base64" - "encoding/json" "fmt" "io" "net/http" @@ -18,6 +17,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/private/protocol" ) // RFC822 returns an RFC822 formatted timestamp for AWS protocols @@ -252,13 +252,12 @@ func EscapePath(path string, encodeSep bool) string { return buf.String() } -func convertType(v reflect.Value, tag reflect.StructTag) (string, error) { +func convertType(v reflect.Value, tag reflect.StructTag) (str string, err error) { v = reflect.Indirect(v) if !v.IsValid() { return "", errValueNotSet } - var str string switch value := v.Interface().(type) { case string: str = value @@ -273,17 +272,19 @@ func convertType(v reflect.Value, tag reflect.StructTag) (string, error) { case time.Time: str = value.UTC().Format(RFC822) case aws.JSONValue: - b, err := json.Marshal(value) - if err != nil { - return "", err + if len(value) == 0 { + return "", errValueNotSet } + escaping := protocol.NoEscape if tag.Get("location") == "header" { - str = base64.StdEncoding.EncodeToString(b) - } else { - str = string(b) + escaping = protocol.Base64Escape + } + str, err = protocol.EncodeJSONValue(value, escaping) + if err != nil { + return "", fmt.Errorf("unable to encode JSONValue, %v", err) } default: - err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type()) + err := fmt.Errorf("unsupported value for param %v (%s)", v.Interface(), v.Type()) return "", err } return str, nil diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go index 7a779ee2260..823f045eed7 100644 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go @@ -3,7 +3,6 @@ package rest import ( "bytes" "encoding/base64" - "encoding/json" "fmt" "io" "io/ioutil" @@ -16,6 +15,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/private/protocol" ) // UnmarshalHandler is a named request handler for unmarshaling rest protocol requests @@ -204,17 +204,11 @@ func unmarshalHeader(v reflect.Value, header string, tag reflect.StructTag) erro } v.Set(reflect.ValueOf(&t)) case aws.JSONValue: - b := []byte(header) - var err error + escaping := protocol.NoEscape if tag.Get("location") == "header" { - b, err = base64.StdEncoding.DecodeString(header) - if err != nil { - return err - } + escaping = protocol.Base64Escape } - - m := aws.JSONValue{} - err = json.Unmarshal(b, &m) + m, err := protocol.DecodeJSONValue(header, escaping) if err != nil { return err } diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/restjson/restjson.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/restjson/restjson.go deleted file mode 100644 index b1d5294ad93..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/protocol/restjson/restjson.go +++ /dev/null @@ -1,92 +0,0 @@ -// Package restjson provides RESTful JSON serialization of AWS -// requests and responses. -package restjson - -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-json.json build_test.go -//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-json.json unmarshal_test.go - -import ( - "encoding/json" - "io/ioutil" - "strings" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" - "github.com/aws/aws-sdk-go/private/protocol/rest" -) - -// BuildHandler is a named request handler for building restjson protocol requests -var BuildHandler = request.NamedHandler{Name: "awssdk.restjson.Build", Fn: Build} - -// UnmarshalHandler is a named request handler for unmarshaling restjson protocol requests -var UnmarshalHandler = request.NamedHandler{Name: "awssdk.restjson.Unmarshal", Fn: Unmarshal} - -// UnmarshalMetaHandler is a named request handler for unmarshaling restjson protocol request metadata -var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.restjson.UnmarshalMeta", Fn: UnmarshalMeta} - -// UnmarshalErrorHandler is a named request handler for unmarshaling restjson protocol request errors -var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.restjson.UnmarshalError", Fn: UnmarshalError} - -// Build builds a request for the REST JSON protocol. -func Build(r *request.Request) { - rest.Build(r) - - if t := rest.PayloadType(r.Params); t == "structure" || t == "" { - jsonrpc.Build(r) - } -} - -// Unmarshal unmarshals a response body for the REST JSON protocol. -func Unmarshal(r *request.Request) { - if t := rest.PayloadType(r.Data); t == "structure" || t == "" { - jsonrpc.Unmarshal(r) - } else { - rest.Unmarshal(r) - } -} - -// UnmarshalMeta unmarshals response headers for the REST JSON protocol. -func UnmarshalMeta(r *request.Request) { - rest.UnmarshalMeta(r) -} - -// UnmarshalError unmarshals a response error for the REST JSON protocol. -func UnmarshalError(r *request.Request) { - defer r.HTTPResponse.Body.Close() - code := r.HTTPResponse.Header.Get("X-Amzn-Errortype") - bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body) - if err != nil { - r.Error = awserr.New("SerializationError", "failed reading REST JSON error response", err) - return - } - if len(bodyBytes) == 0 { - r.Error = awserr.NewRequestFailure( - awserr.New("SerializationError", r.HTTPResponse.Status, nil), - r.HTTPResponse.StatusCode, - "", - ) - return - } - var jsonErr jsonErrorResponse - if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { - r.Error = awserr.New("SerializationError", "failed decoding REST JSON error response", err) - return - } - - if code == "" { - code = jsonErr.Code - } - - code = strings.SplitN(code, ":", 2)[0] - r.Error = awserr.NewRequestFailure( - awserr.New(code, jsonErr.Message, nil), - r.HTTPResponse.StatusCode, - r.RequestID, - ) -} - -type jsonErrorResponse struct { - Code string `json:"code"` - Message string `json:"message"` -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/signer/v2/v2.go b/vendor/github.com/aws/aws-sdk-go/private/signer/v2/v2.go deleted file mode 100644 index 88c3a2f617f..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/signer/v2/v2.go +++ /dev/null @@ -1,180 +0,0 @@ -package v2 - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "errors" - "fmt" - "net/http" - "net/url" - "sort" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" -) - -var ( - errInvalidMethod = errors.New("v2 signer only handles HTTP POST") -) - -const ( - signatureVersion = "2" - signatureMethod = "HmacSHA256" - timeFormat = "2006-01-02T15:04:05Z" -) - -type signer struct { - // Values that must be populated from the request - Request *http.Request - Time time.Time - Credentials *credentials.Credentials - Debug aws.LogLevelType - Logger aws.Logger - - Query url.Values - stringToSign string - signature string -} - -// SignRequestHandler is a named request handler the SDK will use to sign -// service client request with using the V4 signature. -var SignRequestHandler = request.NamedHandler{ - Name: "v2.SignRequestHandler", Fn: SignSDKRequest, -} - -// SignSDKRequest requests with signature version 2. -// -// Will sign the requests with the service config's Credentials object -// Signing is skipped if the credentials is the credentials.AnonymousCredentials -// object. -func SignSDKRequest(req *request.Request) { - // If the request does not need to be signed ignore the signing of the - // request if the AnonymousCredentials object is used. - if req.Config.Credentials == credentials.AnonymousCredentials { - return - } - - if req.HTTPRequest.Method != "POST" && req.HTTPRequest.Method != "GET" { - // The V2 signer only supports GET and POST - req.Error = errInvalidMethod - return - } - - v2 := signer{ - Request: req.HTTPRequest, - Time: req.Time, - Credentials: req.Config.Credentials, - Debug: req.Config.LogLevel.Value(), - Logger: req.Config.Logger, - } - - req.Error = v2.Sign() - - if req.Error != nil { - return - } - - if req.HTTPRequest.Method == "POST" { - // Set the body of the request based on the modified query parameters - req.SetStringBody(v2.Query.Encode()) - - // Now that the body has changed, remove any Content-Length header, - // because it will be incorrect - req.HTTPRequest.ContentLength = 0 - req.HTTPRequest.Header.Del("Content-Length") - } else { - req.HTTPRequest.URL.RawQuery = v2.Query.Encode() - } -} - -func (v2 *signer) Sign() error { - credValue, err := v2.Credentials.Get() - if err != nil { - return err - } - - if v2.Request.Method == "POST" { - // Parse the HTTP request to obtain the query parameters that will - // be used to build the string to sign. Note that because the HTTP - // request will need to be modified, the PostForm and Form properties - // are reset to nil after parsing. - v2.Request.ParseForm() - v2.Query = v2.Request.PostForm - v2.Request.PostForm = nil - v2.Request.Form = nil - } else { - v2.Query = v2.Request.URL.Query() - } - - // Set new query parameters - v2.Query.Set("AWSAccessKeyId", credValue.AccessKeyID) - v2.Query.Set("SignatureVersion", signatureVersion) - v2.Query.Set("SignatureMethod", signatureMethod) - v2.Query.Set("Timestamp", v2.Time.UTC().Format(timeFormat)) - if credValue.SessionToken != "" { - v2.Query.Set("SecurityToken", credValue.SessionToken) - } - - // in case this is a retry, ensure no signature present - v2.Query.Del("Signature") - - method := v2.Request.Method - host := v2.Request.URL.Host - path := v2.Request.URL.Path - if path == "" { - path = "/" - } - - // obtain all of the query keys and sort them - queryKeys := make([]string, 0, len(v2.Query)) - for key := range v2.Query { - queryKeys = append(queryKeys, key) - } - sort.Strings(queryKeys) - - // build URL-encoded query keys and values - queryKeysAndValues := make([]string, len(queryKeys)) - for i, key := range queryKeys { - k := strings.Replace(url.QueryEscape(key), "+", "%20", -1) - v := strings.Replace(url.QueryEscape(v2.Query.Get(key)), "+", "%20", -1) - queryKeysAndValues[i] = k + "=" + v - } - - // join into one query string - query := strings.Join(queryKeysAndValues, "&") - - // build the canonical string for the V2 signature - v2.stringToSign = strings.Join([]string{ - method, - host, - path, - query, - }, "\n") - - hash := hmac.New(sha256.New, []byte(credValue.SecretAccessKey)) - hash.Write([]byte(v2.stringToSign)) - v2.signature = base64.StdEncoding.EncodeToString(hash.Sum(nil)) - v2.Query.Set("Signature", v2.signature) - - if v2.Debug.Matches(aws.LogDebugWithSigning) { - v2.logSigningInfo() - } - - return nil -} - -const logSignInfoMsg = `DEBUG: Request Signature: ----[ STRING TO SIGN ]-------------------------------- -%s ----[ SIGNATURE ]------------------------------------- -%s ------------------------------------------------------` - -func (v2 *signer) logSigningInfo() { - msg := fmt.Sprintf(logSignInfoMsg, v2.stringToSign, v2.Query.Get("Signature")) - v2.Logger.Log(msg) -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/util/sort_keys.go b/vendor/github.com/aws/aws-sdk-go/private/util/sort_keys.go deleted file mode 100644 index 48000565c86..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/util/sort_keys.go +++ /dev/null @@ -1,14 +0,0 @@ -package util - -import "sort" - -// SortedKeys returns a sorted slice of keys of a map. -func SortedKeys(m map[string]interface{}) []string { - i, sorted := 0, make([]string, len(m)) - for k := range m { - sorted[i] = k - i++ - } - sort.Strings(sorted) - return sorted -} diff --git a/vendor/github.com/aws/aws-sdk-go/private/util/util.go b/vendor/github.com/aws/aws-sdk-go/private/util/util.go deleted file mode 100644 index 5f2dab25e20..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/private/util/util.go +++ /dev/null @@ -1,109 +0,0 @@ -package util - -import ( - "bytes" - "encoding/xml" - "fmt" - "go/format" - "io" - "reflect" - "regexp" - "strings" - - "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" -) - -// GoFmt returns the Go formated string of the input. -// -// Panics if the format fails. -func GoFmt(buf string) string { - formatted, err := format.Source([]byte(buf)) - if err != nil { - panic(fmt.Errorf("%s\nOriginal code:\n%s", err.Error(), buf)) - } - return string(formatted) -} - -var reTrim = regexp.MustCompile(`\s{2,}`) - -// Trim removes all leading and trailing white space. -// -// All consecutive spaces will be reduced to a single space. -func Trim(s string) string { - return strings.TrimSpace(reTrim.ReplaceAllString(s, " ")) -} - -// Capitalize capitalizes the first character of the string. -func Capitalize(s string) string { - if len(s) == 1 { - return strings.ToUpper(s) - } - return strings.ToUpper(s[0:1]) + s[1:] -} - -// SortXML sorts the reader's XML elements -func SortXML(r io.Reader) string { - var buf bytes.Buffer - d := xml.NewDecoder(r) - root, _ := xmlutil.XMLToStruct(d, nil) - e := xml.NewEncoder(&buf) - xmlutil.StructToXML(e, root, true) - return buf.String() -} - -// PrettyPrint generates a human readable representation of the value v. -// All values of v are recursively found and pretty printed also. -func PrettyPrint(v interface{}) string { - value := reflect.ValueOf(v) - switch value.Kind() { - case reflect.Struct: - str := fullName(value.Type()) + "{\n" - for i := 0; i < value.NumField(); i++ { - l := string(value.Type().Field(i).Name[0]) - if strings.ToUpper(l) == l { - str += value.Type().Field(i).Name + ": " - str += PrettyPrint(value.Field(i).Interface()) - str += ",\n" - } - } - str += "}" - return str - case reflect.Map: - str := "map[" + fullName(value.Type().Key()) + "]" + fullName(value.Type().Elem()) + "{\n" - for _, k := range value.MapKeys() { - str += "\"" + k.String() + "\": " - str += PrettyPrint(value.MapIndex(k).Interface()) - str += ",\n" - } - str += "}" - return str - case reflect.Ptr: - if e := value.Elem(); e.IsValid() { - return "&" + PrettyPrint(e.Interface()) - } - return "nil" - case reflect.Slice: - str := "[]" + fullName(value.Type().Elem()) + "{\n" - for i := 0; i < value.Len(); i++ { - str += PrettyPrint(value.Index(i).Interface()) - str += ",\n" - } - str += "}" - return str - default: - return fmt.Sprintf("%#v", v) - } -} - -func pkgName(t reflect.Type) string { - pkg := t.PkgPath() - c := strings.Split(pkg, "/") - return c[len(c)-1] -} - -func fullName(t reflect.Type) string { - if pkg := pkgName(t); pkg != "" { - return pkg + "." + t.Name() - } - return t.Name() -} diff --git a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/api.go b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/api.go index 4a9d1406ed4..47c5f7f9417 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/api.go +++ b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/api.go @@ -17,19 +17,18 @@ const opDeleteAlarms = "DeleteAlarms" // DeleteAlarmsRequest generates a "aws/request.Request" representing the // client's request for the DeleteAlarms operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteAlarms for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteAlarms method directly -// instead. +// See DeleteAlarms for more information on using the DeleteAlarms +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteAlarmsRequest method. // req, resp := client.DeleteAlarmsRequest(params) @@ -39,7 +38,7 @@ const opDeleteAlarms = "DeleteAlarms" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarms +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarms func (c *CloudWatch) DeleteAlarmsRequest(input *DeleteAlarmsInput) (req *request.Request, output *DeleteAlarmsOutput) { op := &request.Operation{ Name: opDeleteAlarms, @@ -73,7 +72,7 @@ func (c *CloudWatch) DeleteAlarmsRequest(input *DeleteAlarmsInput) (req *request // * ErrCodeResourceNotFound "ResourceNotFound" // The named resource does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarms +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarms func (c *CloudWatch) DeleteAlarms(input *DeleteAlarmsInput) (*DeleteAlarmsOutput, error) { req, out := c.DeleteAlarmsRequest(input) return out, req.Send() @@ -99,19 +98,18 @@ const opDeleteDashboards = "DeleteDashboards" // DeleteDashboardsRequest generates a "aws/request.Request" representing the // client's request for the DeleteDashboards operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteDashboards for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteDashboards method directly -// instead. +// See DeleteDashboards for more information on using the DeleteDashboards +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteDashboardsRequest method. // req, resp := client.DeleteDashboardsRequest(params) @@ -121,7 +119,7 @@ const opDeleteDashboards = "DeleteDashboards" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboards +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboards func (c *CloudWatch) DeleteDashboardsRequest(input *DeleteDashboardsInput) (req *request.Request, output *DeleteDashboardsOutput) { op := &request.Operation{ Name: opDeleteDashboards, @@ -160,7 +158,7 @@ func (c *CloudWatch) DeleteDashboardsRequest(input *DeleteDashboardsInput) (req // * ErrCodeInternalServiceFault "InternalServiceError" // Request processing has failed due to some unknown error, exception, or failure. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboards +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboards func (c *CloudWatch) DeleteDashboards(input *DeleteDashboardsInput) (*DeleteDashboardsOutput, error) { req, out := c.DeleteDashboardsRequest(input) return out, req.Send() @@ -186,19 +184,18 @@ const opDescribeAlarmHistory = "DescribeAlarmHistory" // DescribeAlarmHistoryRequest generates a "aws/request.Request" representing the // client's request for the DescribeAlarmHistory operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeAlarmHistory for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeAlarmHistory method directly -// instead. +// See DescribeAlarmHistory for more information on using the DescribeAlarmHistory +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeAlarmHistoryRequest method. // req, resp := client.DescribeAlarmHistoryRequest(params) @@ -208,7 +205,7 @@ const opDescribeAlarmHistory = "DescribeAlarmHistory" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistory +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistory func (c *CloudWatch) DescribeAlarmHistoryRequest(input *DescribeAlarmHistoryInput) (req *request.Request, output *DescribeAlarmHistoryOutput) { op := &request.Operation{ Name: opDescribeAlarmHistory, @@ -250,7 +247,7 @@ func (c *CloudWatch) DescribeAlarmHistoryRequest(input *DescribeAlarmHistoryInpu // * ErrCodeInvalidNextToken "InvalidNextToken" // The next token specified is invalid. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistory +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistory func (c *CloudWatch) DescribeAlarmHistory(input *DescribeAlarmHistoryInput) (*DescribeAlarmHistoryOutput, error) { req, out := c.DescribeAlarmHistoryRequest(input) return out, req.Send() @@ -326,19 +323,18 @@ const opDescribeAlarms = "DescribeAlarms" // DescribeAlarmsRequest generates a "aws/request.Request" representing the // client's request for the DescribeAlarms operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeAlarms for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeAlarms method directly -// instead. +// See DescribeAlarms for more information on using the DescribeAlarms +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeAlarmsRequest method. // req, resp := client.DescribeAlarmsRequest(params) @@ -348,7 +344,7 @@ const opDescribeAlarms = "DescribeAlarms" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarms +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarms func (c *CloudWatch) DescribeAlarmsRequest(input *DescribeAlarmsInput) (req *request.Request, output *DescribeAlarmsOutput) { op := &request.Operation{ Name: opDescribeAlarms, @@ -388,7 +384,7 @@ func (c *CloudWatch) DescribeAlarmsRequest(input *DescribeAlarmsInput) (req *req // * ErrCodeInvalidNextToken "InvalidNextToken" // The next token specified is invalid. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarms +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarms func (c *CloudWatch) DescribeAlarms(input *DescribeAlarmsInput) (*DescribeAlarmsOutput, error) { req, out := c.DescribeAlarmsRequest(input) return out, req.Send() @@ -464,19 +460,18 @@ const opDescribeAlarmsForMetric = "DescribeAlarmsForMetric" // DescribeAlarmsForMetricRequest generates a "aws/request.Request" representing the // client's request for the DescribeAlarmsForMetric operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeAlarmsForMetric for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeAlarmsForMetric method directly -// instead. +// See DescribeAlarmsForMetric for more information on using the DescribeAlarmsForMetric +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeAlarmsForMetricRequest method. // req, resp := client.DescribeAlarmsForMetricRequest(params) @@ -486,7 +481,7 @@ const opDescribeAlarmsForMetric = "DescribeAlarmsForMetric" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetric +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetric func (c *CloudWatch) DescribeAlarmsForMetricRequest(input *DescribeAlarmsForMetricInput) (req *request.Request, output *DescribeAlarmsForMetricOutput) { op := &request.Operation{ Name: opDescribeAlarmsForMetric, @@ -514,7 +509,7 @@ func (c *CloudWatch) DescribeAlarmsForMetricRequest(input *DescribeAlarmsForMetr // // See the AWS API reference guide for Amazon CloudWatch's // API operation DescribeAlarmsForMetric for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetric +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetric func (c *CloudWatch) DescribeAlarmsForMetric(input *DescribeAlarmsForMetricInput) (*DescribeAlarmsForMetricOutput, error) { req, out := c.DescribeAlarmsForMetricRequest(input) return out, req.Send() @@ -540,19 +535,18 @@ const opDisableAlarmActions = "DisableAlarmActions" // DisableAlarmActionsRequest generates a "aws/request.Request" representing the // client's request for the DisableAlarmActions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisableAlarmActions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisableAlarmActions method directly -// instead. +// See DisableAlarmActions for more information on using the DisableAlarmActions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisableAlarmActionsRequest method. // req, resp := client.DisableAlarmActionsRequest(params) @@ -562,7 +556,7 @@ const opDisableAlarmActions = "DisableAlarmActions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActions +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActions func (c *CloudWatch) DisableAlarmActionsRequest(input *DisableAlarmActionsInput) (req *request.Request, output *DisableAlarmActionsOutput) { op := &request.Operation{ Name: opDisableAlarmActions, @@ -592,7 +586,7 @@ func (c *CloudWatch) DisableAlarmActionsRequest(input *DisableAlarmActionsInput) // // See the AWS API reference guide for Amazon CloudWatch's // API operation DisableAlarmActions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActions +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActions func (c *CloudWatch) DisableAlarmActions(input *DisableAlarmActionsInput) (*DisableAlarmActionsOutput, error) { req, out := c.DisableAlarmActionsRequest(input) return out, req.Send() @@ -618,19 +612,18 @@ const opEnableAlarmActions = "EnableAlarmActions" // EnableAlarmActionsRequest generates a "aws/request.Request" representing the // client's request for the EnableAlarmActions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See EnableAlarmActions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the EnableAlarmActions method directly -// instead. +// See EnableAlarmActions for more information on using the EnableAlarmActions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the EnableAlarmActionsRequest method. // req, resp := client.EnableAlarmActionsRequest(params) @@ -640,7 +633,7 @@ const opEnableAlarmActions = "EnableAlarmActions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActions +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActions func (c *CloudWatch) EnableAlarmActionsRequest(input *EnableAlarmActionsInput) (req *request.Request, output *EnableAlarmActionsOutput) { op := &request.Operation{ Name: opEnableAlarmActions, @@ -669,7 +662,7 @@ func (c *CloudWatch) EnableAlarmActionsRequest(input *EnableAlarmActionsInput) ( // // See the AWS API reference guide for Amazon CloudWatch's // API operation EnableAlarmActions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActions +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActions func (c *CloudWatch) EnableAlarmActions(input *EnableAlarmActionsInput) (*EnableAlarmActionsOutput, error) { req, out := c.EnableAlarmActionsRequest(input) return out, req.Send() @@ -695,19 +688,18 @@ const opGetDashboard = "GetDashboard" // GetDashboardRequest generates a "aws/request.Request" representing the // client's request for the GetDashboard operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetDashboard for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetDashboard method directly -// instead. +// See GetDashboard for more information on using the GetDashboard +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetDashboardRequest method. // req, resp := client.GetDashboardRequest(params) @@ -717,7 +709,7 @@ const opGetDashboard = "GetDashboard" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboard +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboard func (c *CloudWatch) GetDashboardRequest(input *GetDashboardInput) (req *request.Request, output *GetDashboardOutput) { op := &request.Operation{ Name: opGetDashboard, @@ -759,7 +751,7 @@ func (c *CloudWatch) GetDashboardRequest(input *GetDashboardInput) (req *request // * ErrCodeInternalServiceFault "InternalServiceError" // Request processing has failed due to some unknown error, exception, or failure. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboard +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboard func (c *CloudWatch) GetDashboard(input *GetDashboardInput) (*GetDashboardOutput, error) { req, out := c.GetDashboardRequest(input) return out, req.Send() @@ -785,19 +777,18 @@ const opGetMetricStatistics = "GetMetricStatistics" // GetMetricStatisticsRequest generates a "aws/request.Request" representing the // client's request for the GetMetricStatistics operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetMetricStatistics for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetMetricStatistics method directly -// instead. +// See GetMetricStatistics for more information on using the GetMetricStatistics +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetMetricStatisticsRequest method. // req, resp := client.GetMetricStatisticsRequest(params) @@ -807,7 +798,7 @@ const opGetMetricStatistics = "GetMetricStatistics" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatistics +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatistics func (c *CloudWatch) GetMetricStatisticsRequest(input *GetMetricStatisticsInput) (req *request.Request, output *GetMetricStatisticsOutput) { op := &request.Operation{ Name: opGetMetricStatistics, @@ -898,7 +889,7 @@ func (c *CloudWatch) GetMetricStatisticsRequest(input *GetMetricStatisticsInput) // * ErrCodeInternalServiceFault "InternalServiceError" // Request processing has failed due to some unknown error, exception, or failure. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatistics +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatistics func (c *CloudWatch) GetMetricStatistics(input *GetMetricStatisticsInput) (*GetMetricStatisticsOutput, error) { req, out := c.GetMetricStatisticsRequest(input) return out, req.Send() @@ -924,19 +915,18 @@ const opListDashboards = "ListDashboards" // ListDashboardsRequest generates a "aws/request.Request" representing the // client's request for the ListDashboards operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListDashboards for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListDashboards method directly -// instead. +// See ListDashboards for more information on using the ListDashboards +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListDashboardsRequest method. // req, resp := client.ListDashboardsRequest(params) @@ -946,7 +936,7 @@ const opListDashboards = "ListDashboards" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboards +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboards func (c *CloudWatch) ListDashboardsRequest(input *ListDashboardsInput) (req *request.Request, output *ListDashboardsOutput) { op := &request.Operation{ Name: opListDashboards, @@ -983,7 +973,7 @@ func (c *CloudWatch) ListDashboardsRequest(input *ListDashboardsInput) (req *req // * ErrCodeInternalServiceFault "InternalServiceError" // Request processing has failed due to some unknown error, exception, or failure. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboards +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboards func (c *CloudWatch) ListDashboards(input *ListDashboardsInput) (*ListDashboardsOutput, error) { req, out := c.ListDashboardsRequest(input) return out, req.Send() @@ -1009,19 +999,18 @@ const opListMetrics = "ListMetrics" // ListMetricsRequest generates a "aws/request.Request" representing the // client's request for the ListMetrics operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListMetrics for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListMetrics method directly -// instead. +// See ListMetrics for more information on using the ListMetrics +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListMetricsRequest method. // req, resp := client.ListMetricsRequest(params) @@ -1031,7 +1020,7 @@ const opListMetrics = "ListMetrics" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetrics +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetrics func (c *CloudWatch) ListMetricsRequest(input *ListMetricsInput) (req *request.Request, output *ListMetricsOutput) { op := &request.Operation{ Name: opListMetrics, @@ -1080,7 +1069,7 @@ func (c *CloudWatch) ListMetricsRequest(input *ListMetricsInput) (req *request.R // * ErrCodeInvalidParameterValueException "InvalidParameterValue" // The value of an input parameter is bad or out-of-range. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetrics +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetrics func (c *CloudWatch) ListMetrics(input *ListMetricsInput) (*ListMetricsOutput, error) { req, out := c.ListMetricsRequest(input) return out, req.Send() @@ -1156,19 +1145,18 @@ const opPutDashboard = "PutDashboard" // PutDashboardRequest generates a "aws/request.Request" representing the // client's request for the PutDashboard operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutDashboard for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutDashboard method directly -// instead. +// See PutDashboard for more information on using the PutDashboard +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutDashboardRequest method. // req, resp := client.PutDashboardRequest(params) @@ -1178,7 +1166,7 @@ const opPutDashboard = "PutDashboard" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboard +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboard func (c *CloudWatch) PutDashboardRequest(input *PutDashboardInput) (req *request.Request, output *PutDashboardOutput) { op := &request.Operation{ Name: opPutDashboard, @@ -1231,7 +1219,7 @@ func (c *CloudWatch) PutDashboardRequest(input *PutDashboardInput) (req *request // * ErrCodeInternalServiceFault "InternalServiceError" // Request processing has failed due to some unknown error, exception, or failure. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboard +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboard func (c *CloudWatch) PutDashboard(input *PutDashboardInput) (*PutDashboardOutput, error) { req, out := c.PutDashboardRequest(input) return out, req.Send() @@ -1257,19 +1245,18 @@ const opPutMetricAlarm = "PutMetricAlarm" // PutMetricAlarmRequest generates a "aws/request.Request" representing the // client's request for the PutMetricAlarm operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutMetricAlarm for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutMetricAlarm method directly -// instead. +// See PutMetricAlarm for more information on using the PutMetricAlarm +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutMetricAlarmRequest method. // req, resp := client.PutMetricAlarmRequest(params) @@ -1279,7 +1266,7 @@ const opPutMetricAlarm = "PutMetricAlarm" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarm +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarm func (c *CloudWatch) PutMetricAlarmRequest(input *PutMetricAlarmInput) (req *request.Request, output *PutMetricAlarmOutput) { op := &request.Operation{ Name: opPutMetricAlarm, @@ -1313,6 +1300,8 @@ func (c *CloudWatch) PutMetricAlarmRequest(input *PutMetricAlarmInput) (req *req // // If you are an IAM user, you must have Amazon EC2 permissions for some operations: // +// * iam:CreateServiceLinkedRole for all alarms with EC2 actions +// // * ec2:DescribeInstanceStatus and ec2:DescribeInstances for all alarms // on EC2 instance status metrics // @@ -1352,7 +1341,7 @@ func (c *CloudWatch) PutMetricAlarmRequest(input *PutMetricAlarmInput) (req *req // * ErrCodeLimitExceededFault "LimitExceeded" // The quota for alarms for this customer has already been reached. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarm +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarm func (c *CloudWatch) PutMetricAlarm(input *PutMetricAlarmInput) (*PutMetricAlarmOutput, error) { req, out := c.PutMetricAlarmRequest(input) return out, req.Send() @@ -1378,19 +1367,18 @@ const opPutMetricData = "PutMetricData" // PutMetricDataRequest generates a "aws/request.Request" representing the // client's request for the PutMetricData operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutMetricData for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutMetricData method directly -// instead. +// See PutMetricData for more information on using the PutMetricData +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutMetricDataRequest method. // req, resp := client.PutMetricDataRequest(params) @@ -1400,7 +1388,7 @@ const opPutMetricData = "PutMetricData" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricData +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricData func (c *CloudWatch) PutMetricDataRequest(input *PutMetricDataInput) (req *request.Request, output *PutMetricDataOutput) { op := &request.Operation{ Name: opPutMetricData, @@ -1471,7 +1459,7 @@ func (c *CloudWatch) PutMetricDataRequest(input *PutMetricDataInput) (req *reque // * ErrCodeInternalServiceFault "InternalServiceError" // Request processing has failed due to some unknown error, exception, or failure. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricData +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricData func (c *CloudWatch) PutMetricData(input *PutMetricDataInput) (*PutMetricDataOutput, error) { req, out := c.PutMetricDataRequest(input) return out, req.Send() @@ -1497,19 +1485,18 @@ const opSetAlarmState = "SetAlarmState" // SetAlarmStateRequest generates a "aws/request.Request" representing the // client's request for the SetAlarmState operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See SetAlarmState for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the SetAlarmState method directly -// instead. +// See SetAlarmState for more information on using the SetAlarmState +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the SetAlarmStateRequest method. // req, resp := client.SetAlarmStateRequest(params) @@ -1519,7 +1506,7 @@ const opSetAlarmState = "SetAlarmState" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmState +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmState func (c *CloudWatch) SetAlarmStateRequest(input *SetAlarmStateInput) (req *request.Request, output *SetAlarmStateOutput) { op := &request.Operation{ Name: opSetAlarmState, @@ -1563,7 +1550,7 @@ func (c *CloudWatch) SetAlarmStateRequest(input *SetAlarmStateInput) (req *reque // * ErrCodeInvalidFormatFault "InvalidFormat" // Data was not syntactically valid JSON. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmState +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmState func (c *CloudWatch) SetAlarmState(input *SetAlarmStateInput) (*SetAlarmStateOutput, error) { req, out := c.SetAlarmStateRequest(input) return out, req.Send() @@ -1586,7 +1573,7 @@ func (c *CloudWatch) SetAlarmStateWithContext(ctx aws.Context, input *SetAlarmSt } // Represents the history of a specific alarm. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/AlarmHistoryItem +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/AlarmHistoryItem type AlarmHistoryItem struct { _ struct{} `type:"structure"` @@ -1647,7 +1634,7 @@ func (s *AlarmHistoryItem) SetTimestamp(v time.Time) *AlarmHistoryItem { } // Represents a specific dashboard. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DashboardEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DashboardEntry type DashboardEntry struct { _ struct{} `type:"structure"` @@ -1701,7 +1688,7 @@ func (s *DashboardEntry) SetSize(v int64) *DashboardEntry { } // An error or warning for the operation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DashboardValidationMessage +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DashboardValidationMessage type DashboardValidationMessage struct { _ struct{} `type:"structure"` @@ -1735,7 +1722,7 @@ func (s *DashboardValidationMessage) SetMessage(v string) *DashboardValidationMe } // Encapsulates the statistical data that CloudWatch computes from metric data. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/Datapoint +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/Datapoint type Datapoint struct { _ struct{} `type:"structure"` @@ -1823,7 +1810,7 @@ func (s *Datapoint) SetUnit(v string) *Datapoint { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarmsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarmsInput type DeleteAlarmsInput struct { _ struct{} `type:"structure"` @@ -1862,7 +1849,7 @@ func (s *DeleteAlarmsInput) SetAlarmNames(v []*string) *DeleteAlarmsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarmsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteAlarmsOutput type DeleteAlarmsOutput struct { _ struct{} `type:"structure"` } @@ -1877,12 +1864,14 @@ func (s DeleteAlarmsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboardsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboardsInput type DeleteDashboardsInput struct { _ struct{} `type:"structure"` - // The dashboards to be deleted. - DashboardNames []*string `type:"list"` + // The dashboards to be deleted. This parameter is required. + // + // DashboardNames is a required field + DashboardNames []*string `type:"list" required:"true"` } // String returns the string representation @@ -1895,13 +1884,26 @@ func (s DeleteDashboardsInput) GoString() string { return s.String() } +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteDashboardsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteDashboardsInput"} + if s.DashboardNames == nil { + invalidParams.Add(request.NewErrParamRequired("DashboardNames")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + // SetDashboardNames sets the DashboardNames field's value. func (s *DeleteDashboardsInput) SetDashboardNames(v []*string) *DeleteDashboardsInput { s.DashboardNames = v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboardsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DeleteDashboardsOutput type DeleteDashboardsOutput struct { _ struct{} `type:"structure"` } @@ -1916,7 +1918,7 @@ func (s DeleteDashboardsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistoryInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistoryInput type DescribeAlarmHistoryInput struct { _ struct{} `type:"structure"` @@ -2002,7 +2004,7 @@ func (s *DescribeAlarmHistoryInput) SetStartDate(v time.Time) *DescribeAlarmHist return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistoryOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmHistoryOutput type DescribeAlarmHistoryOutput struct { _ struct{} `type:"structure"` @@ -2035,7 +2037,7 @@ func (s *DescribeAlarmHistoryOutput) SetNextToken(v string) *DescribeAlarmHistor return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetricInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetricInput type DescribeAlarmsForMetricInput struct { _ struct{} `type:"structure"` @@ -2155,7 +2157,7 @@ func (s *DescribeAlarmsForMetricInput) SetUnit(v string) *DescribeAlarmsForMetri return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetricOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsForMetricOutput type DescribeAlarmsForMetricOutput struct { _ struct{} `type:"structure"` @@ -2179,7 +2181,7 @@ func (s *DescribeAlarmsForMetricOutput) SetMetricAlarms(v []*MetricAlarm) *Descr return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsInput type DescribeAlarmsInput struct { _ struct{} `type:"structure"` @@ -2269,7 +2271,7 @@ func (s *DescribeAlarmsInput) SetStateValue(v string) *DescribeAlarmsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DescribeAlarmsOutput type DescribeAlarmsOutput struct { _ struct{} `type:"structure"` @@ -2303,7 +2305,7 @@ func (s *DescribeAlarmsOutput) SetNextToken(v string) *DescribeAlarmsOutput { } // Expands the identity of a metric. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/Dimension +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/Dimension type Dimension struct { _ struct{} `type:"structure"` @@ -2363,7 +2365,7 @@ func (s *Dimension) SetValue(v string) *Dimension { } // Represents filters for a dimension. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DimensionFilter +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DimensionFilter type DimensionFilter struct { _ struct{} `type:"structure"` @@ -2417,7 +2419,7 @@ func (s *DimensionFilter) SetValue(v string) *DimensionFilter { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActionsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActionsInput type DisableAlarmActionsInput struct { _ struct{} `type:"structure"` @@ -2456,7 +2458,7 @@ func (s *DisableAlarmActionsInput) SetAlarmNames(v []*string) *DisableAlarmActio return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActionsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/DisableAlarmActionsOutput type DisableAlarmActionsOutput struct { _ struct{} `type:"structure"` } @@ -2471,7 +2473,7 @@ func (s DisableAlarmActionsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActionsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActionsInput type EnableAlarmActionsInput struct { _ struct{} `type:"structure"` @@ -2510,7 +2512,7 @@ func (s *EnableAlarmActionsInput) SetAlarmNames(v []*string) *EnableAlarmActions return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActionsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/EnableAlarmActionsOutput type EnableAlarmActionsOutput struct { _ struct{} `type:"structure"` } @@ -2525,12 +2527,14 @@ func (s EnableAlarmActionsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboardInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboardInput type GetDashboardInput struct { _ struct{} `type:"structure"` // The name of the dashboard to be described. - DashboardName *string `type:"string"` + // + // DashboardName is a required field + DashboardName *string `type:"string" required:"true"` } // String returns the string representation @@ -2543,13 +2547,26 @@ func (s GetDashboardInput) GoString() string { return s.String() } +// Validate inspects the fields of the type to determine if they are valid. +func (s *GetDashboardInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "GetDashboardInput"} + if s.DashboardName == nil { + invalidParams.Add(request.NewErrParamRequired("DashboardName")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + // SetDashboardName sets the DashboardName field's value. func (s *GetDashboardInput) SetDashboardName(v string) *GetDashboardInput { s.DashboardName = &v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboardOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetDashboardOutput type GetDashboardOutput struct { _ struct{} `type:"structure"` @@ -2593,7 +2610,7 @@ func (s *GetDashboardOutput) SetDashboardName(v string) *GetDashboardOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatisticsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatisticsInput type GetMetricStatisticsInput struct { _ struct{} `type:"structure"` @@ -2807,7 +2824,7 @@ func (s *GetMetricStatisticsInput) SetUnit(v string) *GetMetricStatisticsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatisticsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/GetMetricStatisticsOutput type GetMetricStatisticsOutput struct { _ struct{} `type:"structure"` @@ -2840,7 +2857,7 @@ func (s *GetMetricStatisticsOutput) SetLabel(v string) *GetMetricStatisticsOutpu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboardsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboardsInput type ListDashboardsInput struct { _ struct{} `type:"structure"` @@ -2876,7 +2893,7 @@ func (s *ListDashboardsInput) SetNextToken(v string) *ListDashboardsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboardsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListDashboardsOutput type ListDashboardsOutput struct { _ struct{} `type:"structure"` @@ -2909,7 +2926,7 @@ func (s *ListDashboardsOutput) SetNextToken(v string) *ListDashboardsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetricsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetricsInput type ListMetricsInput struct { _ struct{} `type:"structure"` @@ -2987,7 +3004,7 @@ func (s *ListMetricsInput) SetNextToken(v string) *ListMetricsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetricsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/ListMetricsOutput type ListMetricsOutput struct { _ struct{} `type:"structure"` @@ -3021,7 +3038,7 @@ func (s *ListMetricsOutput) SetNextToken(v string) *ListMetricsOutput { } // Represents a specific metric. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/Metric +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/Metric type Metric struct { _ struct{} `type:"structure"` @@ -3064,7 +3081,7 @@ func (s *Metric) SetNamespace(v string) *Metric { } // Represents an alarm. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/MetricAlarm +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/MetricAlarm type MetricAlarm struct { _ struct{} `type:"structure"` @@ -3092,6 +3109,9 @@ type MetricAlarm struct { // threshold. The specified statistic value is used as the first operand. ComparisonOperator *string `type:"string" enum:"ComparisonOperator"` + // The number of datapoints that must be breaching to trigger the alarm. + DatapointsToAlarm *int64 `min:"1" type:"integer"` + // The dimensions for the metric associated with the alarm. Dimensions []*Dimension `type:"list"` @@ -3205,6 +3225,12 @@ func (s *MetricAlarm) SetComparisonOperator(v string) *MetricAlarm { return s } +// SetDatapointsToAlarm sets the DatapointsToAlarm field's value. +func (s *MetricAlarm) SetDatapointsToAlarm(v int64) *MetricAlarm { + s.DatapointsToAlarm = &v + return s +} + // SetDimensions sets the Dimensions field's value. func (s *MetricAlarm) SetDimensions(v []*Dimension) *MetricAlarm { s.Dimensions = v @@ -3309,7 +3335,7 @@ func (s *MetricAlarm) SetUnit(v string) *MetricAlarm { // Encapsulates the information sent to either create a metric or add new values // to be aggregated into an existing metric. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/MetricDatum +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/MetricDatum type MetricDatum struct { _ struct{} `type:"structure"` @@ -3438,21 +3464,26 @@ func (s *MetricDatum) SetValue(v float64) *MetricDatum { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboardInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboardInput type PutDashboardInput struct { _ struct{} `type:"structure"` // The detailed information about the dashboard in JSON format, including the - // widgets to include and their location on the dashboard. + // widgets to include and their location on the dashboard. This parameter is + // required. // // For more information about the syntax, see CloudWatch-Dashboard-Body-Structure. - DashboardBody *string `type:"string"` + // + // DashboardBody is a required field + DashboardBody *string `type:"string" required:"true"` // The name of the dashboard. If a dashboard with this name already exists, // this call modifies that dashboard, replacing its current contents. Otherwise, // a new dashboard is created. The maximum length is 255, and valid characters - // are A-Z, a-z, 0-9, "-", and "_". - DashboardName *string `type:"string"` + // are A-Z, a-z, 0-9, "-", and "_". This parameter is required. + // + // DashboardName is a required field + DashboardName *string `type:"string" required:"true"` } // String returns the string representation @@ -3465,6 +3496,22 @@ func (s PutDashboardInput) GoString() string { return s.String() } +// Validate inspects the fields of the type to determine if they are valid. +func (s *PutDashboardInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "PutDashboardInput"} + if s.DashboardBody == nil { + invalidParams.Add(request.NewErrParamRequired("DashboardBody")) + } + if s.DashboardName == nil { + invalidParams.Add(request.NewErrParamRequired("DashboardName")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + // SetDashboardBody sets the DashboardBody field's value. func (s *PutDashboardInput) SetDashboardBody(v string) *PutDashboardInput { s.DashboardBody = &v @@ -3477,7 +3524,7 @@ func (s *PutDashboardInput) SetDashboardName(v string) *PutDashboardInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboardOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutDashboardOutput type PutDashboardOutput struct { _ struct{} `type:"structure"` @@ -3509,7 +3556,7 @@ func (s *PutDashboardOutput) SetDashboardValidationMessages(v []*DashboardValida return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarmInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarmInput type PutMetricAlarmInput struct { _ struct{} `type:"structure"` @@ -3521,11 +3568,12 @@ type PutMetricAlarmInput struct { // any other state. Each action is specified as an Amazon Resource Name (ARN). // // Valid Values: arn:aws:automate:region:ec2:stop | arn:aws:automate:region:ec2:terminate - // | arn:aws:automate:region:ec2:recover + // | arn:aws:automate:region:ec2:recover | arn:aws:sns:region:account-id:sns-topic-name + // | arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name // - // Valid Values (for use with IAM roles): arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Stop/1.0 - // | arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Terminate/1.0 - // | arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + // Valid Values (for use with IAM roles): arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Stop/1.0 + // | arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + // | arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Reboot/1.0 AlarmActions []*string `type:"list"` // The description for the alarm. @@ -3542,6 +3590,9 @@ type PutMetricAlarmInput struct { // ComparisonOperator is a required field ComparisonOperator *string `type:"string" required:"true" enum:"ComparisonOperator"` + // The number of datapoints that must be breaching to trigger the alarm. + DatapointsToAlarm *int64 `min:"1" type:"integer"` + // The dimensions for the metric associated with the alarm. Dimensions []*Dimension `type:"list"` @@ -3563,7 +3614,8 @@ type PutMetricAlarmInput struct { EvaluationPeriods *int64 `min:"1" type:"integer" required:"true"` // The percentile statistic for the metric associated with the alarm. Specify - // a value between p0.0 and p100. + // a value between p0.0 and p100. When you call PutMetricAlarm, you must specify + // either Statistic or ExtendedStatistic, but not both. ExtendedStatistic *string `type:"string"` // The actions to execute when this alarm transitions to the INSUFFICIENT_DATA @@ -3571,11 +3623,12 @@ type PutMetricAlarmInput struct { // Name (ARN). // // Valid Values: arn:aws:automate:region:ec2:stop | arn:aws:automate:region:ec2:terminate - // | arn:aws:automate:region:ec2:recover + // | arn:aws:automate:region:ec2:recover | arn:aws:sns:region:account-id:sns-topic-name + // | arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name // - // Valid Values (for use with IAM roles): arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Stop/1.0 - // | arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Terminate/1.0 - // | arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + // Valid Values (for use with IAM roles): arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Stop/1.0 + // | arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + // | arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Reboot/1.0 InsufficientDataActions []*string `type:"list"` // The name for the metric associated with the alarm. @@ -3592,11 +3645,12 @@ type PutMetricAlarmInput struct { // other state. Each action is specified as an Amazon Resource Name (ARN). // // Valid Values: arn:aws:automate:region:ec2:stop | arn:aws:automate:region:ec2:terminate - // | arn:aws:automate:region:ec2:recover + // | arn:aws:automate:region:ec2:recover | arn:aws:sns:region:account-id:sns-topic-name + // | arn:aws:autoscaling:region:account-id:scalingPolicy:policy-id autoScalingGroupName/group-friendly-name:policyName/policy-friendly-name // - // Valid Values (for use with IAM roles): arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Stop/1.0 - // | arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Terminate/1.0 - // | arn:aws:swf:us-east-1:{customer-account}:action/actions/AWS_EC2.InstanceId.Reboot/1.0 + // Valid Values (for use with IAM roles): arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Stop/1.0 + // | arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Terminate/1.0 + // | arn:aws:swf:region:{account-id}:action/actions/AWS_EC2.InstanceId.Reboot/1.0 OKActions []*string `type:"list"` // The period, in seconds, over which the specified statistic is applied. Valid @@ -3619,7 +3673,8 @@ type PutMetricAlarmInput struct { Period *int64 `min:"1" type:"integer" required:"true"` // The statistic for the metric associated with the alarm, other than percentile. - // For percentile statistics, use ExtendedStatistic. + // For percentile statistics, use ExtendedStatistic. When you call PutMetricAlarm, + // you must specify either Statistic or ExtendedStatistic, but not both. Statistic *string `type:"string" enum:"Statistic"` // The value against which the specified statistic is compared. @@ -3668,6 +3723,9 @@ func (s *PutMetricAlarmInput) Validate() error { if s.ComparisonOperator == nil { invalidParams.Add(request.NewErrParamRequired("ComparisonOperator")) } + if s.DatapointsToAlarm != nil && *s.DatapointsToAlarm < 1 { + invalidParams.Add(request.NewErrParamMinValue("DatapointsToAlarm", 1)) + } if s.EvaluateLowSampleCountPercentile != nil && len(*s.EvaluateLowSampleCountPercentile) < 1 { invalidParams.Add(request.NewErrParamMinLen("EvaluateLowSampleCountPercentile", 1)) } @@ -3748,6 +3806,12 @@ func (s *PutMetricAlarmInput) SetComparisonOperator(v string) *PutMetricAlarmInp return s } +// SetDatapointsToAlarm sets the DatapointsToAlarm field's value. +func (s *PutMetricAlarmInput) SetDatapointsToAlarm(v int64) *PutMetricAlarmInput { + s.DatapointsToAlarm = &v + return s +} + // SetDimensions sets the Dimensions field's value. func (s *PutMetricAlarmInput) SetDimensions(v []*Dimension) *PutMetricAlarmInput { s.Dimensions = v @@ -3826,7 +3890,7 @@ func (s *PutMetricAlarmInput) SetUnit(v string) *PutMetricAlarmInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarmOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricAlarmOutput type PutMetricAlarmOutput struct { _ struct{} `type:"structure"` } @@ -3841,7 +3905,7 @@ func (s PutMetricAlarmOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricDataInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricDataInput type PutMetricDataInput struct { _ struct{} `type:"structure"` @@ -3910,7 +3974,7 @@ func (s *PutMetricDataInput) SetNamespace(v string) *PutMetricDataInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricDataOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/PutMetricDataOutput type PutMetricDataOutput struct { _ struct{} `type:"structure"` } @@ -3925,7 +3989,7 @@ func (s PutMetricDataOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmStateInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmStateInput type SetAlarmStateInput struct { _ struct{} `type:"structure"` @@ -4005,7 +4069,7 @@ func (s *SetAlarmStateInput) SetStateValue(v string) *SetAlarmStateInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmStateOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/SetAlarmStateOutput type SetAlarmStateOutput struct { _ struct{} `type:"structure"` } @@ -4021,7 +4085,7 @@ func (s SetAlarmStateOutput) GoString() string { } // Represents a set of statistics that describes a specific metric. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/StatisticSet +// See also, https://docs.aws.amazon.com/goto/WebAPI/monitoring-2010-08-01/StatisticSet type StatisticSet struct { _ struct{} `type:"structure"` diff --git a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface/interface.go deleted file mode 100644 index 38d3dc60de3..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface/interface.go +++ /dev/null @@ -1,136 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -// Package cloudwatchiface provides an interface to enable mocking the Amazon CloudWatch service client -// for testing your code. -// -// It is important to note that this interface will have breaking changes -// when the service model is updated and adds new API operations, paginators, -// and waiters. -package cloudwatchiface - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/cloudwatch" -) - -// CloudWatchAPI provides an interface to enable mocking the -// cloudwatch.CloudWatch service client's API operation, -// paginators, and waiters. This make unit testing your code that calls out -// to the SDK's service client's calls easier. -// -// The best way to use this interface is so the SDK's service client's calls -// can be stubbed out for unit testing your code with the SDK without needing -// to inject custom request handlers into the the SDK's request pipeline. -// -// // myFunc uses an SDK service client to make a request to -// // Amazon CloudWatch. -// func myFunc(svc cloudwatchiface.CloudWatchAPI) bool { -// // Make svc.DeleteAlarms request -// } -// -// func main() { -// sess := session.New() -// svc := cloudwatch.New(sess) -// -// myFunc(svc) -// } -// -// In your _test.go file: -// -// // Define a mock struct to be used in your unit tests of myFunc. -// type mockCloudWatchClient struct { -// cloudwatchiface.CloudWatchAPI -// } -// func (m *mockCloudWatchClient) DeleteAlarms(input *cloudwatch.DeleteAlarmsInput) (*cloudwatch.DeleteAlarmsOutput, error) { -// // mock response/functionality -// } -// -// func TestMyFunc(t *testing.T) { -// // Setup Test -// mockSvc := &mockCloudWatchClient{} -// -// myfunc(mockSvc) -// -// // Verify myFunc's functionality -// } -// -// It is important to note that this interface will have breaking changes -// when the service model is updated and adds new API operations, paginators, -// and waiters. Its suggested to use the pattern above for testing, or using -// tooling to generate mocks to satisfy the interfaces. -type CloudWatchAPI interface { - DeleteAlarms(*cloudwatch.DeleteAlarmsInput) (*cloudwatch.DeleteAlarmsOutput, error) - DeleteAlarmsWithContext(aws.Context, *cloudwatch.DeleteAlarmsInput, ...request.Option) (*cloudwatch.DeleteAlarmsOutput, error) - DeleteAlarmsRequest(*cloudwatch.DeleteAlarmsInput) (*request.Request, *cloudwatch.DeleteAlarmsOutput) - - DeleteDashboards(*cloudwatch.DeleteDashboardsInput) (*cloudwatch.DeleteDashboardsOutput, error) - DeleteDashboardsWithContext(aws.Context, *cloudwatch.DeleteDashboardsInput, ...request.Option) (*cloudwatch.DeleteDashboardsOutput, error) - DeleteDashboardsRequest(*cloudwatch.DeleteDashboardsInput) (*request.Request, *cloudwatch.DeleteDashboardsOutput) - - DescribeAlarmHistory(*cloudwatch.DescribeAlarmHistoryInput) (*cloudwatch.DescribeAlarmHistoryOutput, error) - DescribeAlarmHistoryWithContext(aws.Context, *cloudwatch.DescribeAlarmHistoryInput, ...request.Option) (*cloudwatch.DescribeAlarmHistoryOutput, error) - DescribeAlarmHistoryRequest(*cloudwatch.DescribeAlarmHistoryInput) (*request.Request, *cloudwatch.DescribeAlarmHistoryOutput) - - DescribeAlarmHistoryPages(*cloudwatch.DescribeAlarmHistoryInput, func(*cloudwatch.DescribeAlarmHistoryOutput, bool) bool) error - DescribeAlarmHistoryPagesWithContext(aws.Context, *cloudwatch.DescribeAlarmHistoryInput, func(*cloudwatch.DescribeAlarmHistoryOutput, bool) bool, ...request.Option) error - - DescribeAlarms(*cloudwatch.DescribeAlarmsInput) (*cloudwatch.DescribeAlarmsOutput, error) - DescribeAlarmsWithContext(aws.Context, *cloudwatch.DescribeAlarmsInput, ...request.Option) (*cloudwatch.DescribeAlarmsOutput, error) - DescribeAlarmsRequest(*cloudwatch.DescribeAlarmsInput) (*request.Request, *cloudwatch.DescribeAlarmsOutput) - - DescribeAlarmsPages(*cloudwatch.DescribeAlarmsInput, func(*cloudwatch.DescribeAlarmsOutput, bool) bool) error - DescribeAlarmsPagesWithContext(aws.Context, *cloudwatch.DescribeAlarmsInput, func(*cloudwatch.DescribeAlarmsOutput, bool) bool, ...request.Option) error - - DescribeAlarmsForMetric(*cloudwatch.DescribeAlarmsForMetricInput) (*cloudwatch.DescribeAlarmsForMetricOutput, error) - DescribeAlarmsForMetricWithContext(aws.Context, *cloudwatch.DescribeAlarmsForMetricInput, ...request.Option) (*cloudwatch.DescribeAlarmsForMetricOutput, error) - DescribeAlarmsForMetricRequest(*cloudwatch.DescribeAlarmsForMetricInput) (*request.Request, *cloudwatch.DescribeAlarmsForMetricOutput) - - DisableAlarmActions(*cloudwatch.DisableAlarmActionsInput) (*cloudwatch.DisableAlarmActionsOutput, error) - DisableAlarmActionsWithContext(aws.Context, *cloudwatch.DisableAlarmActionsInput, ...request.Option) (*cloudwatch.DisableAlarmActionsOutput, error) - DisableAlarmActionsRequest(*cloudwatch.DisableAlarmActionsInput) (*request.Request, *cloudwatch.DisableAlarmActionsOutput) - - EnableAlarmActions(*cloudwatch.EnableAlarmActionsInput) (*cloudwatch.EnableAlarmActionsOutput, error) - EnableAlarmActionsWithContext(aws.Context, *cloudwatch.EnableAlarmActionsInput, ...request.Option) (*cloudwatch.EnableAlarmActionsOutput, error) - EnableAlarmActionsRequest(*cloudwatch.EnableAlarmActionsInput) (*request.Request, *cloudwatch.EnableAlarmActionsOutput) - - GetDashboard(*cloudwatch.GetDashboardInput) (*cloudwatch.GetDashboardOutput, error) - GetDashboardWithContext(aws.Context, *cloudwatch.GetDashboardInput, ...request.Option) (*cloudwatch.GetDashboardOutput, error) - GetDashboardRequest(*cloudwatch.GetDashboardInput) (*request.Request, *cloudwatch.GetDashboardOutput) - - GetMetricStatistics(*cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error) - GetMetricStatisticsWithContext(aws.Context, *cloudwatch.GetMetricStatisticsInput, ...request.Option) (*cloudwatch.GetMetricStatisticsOutput, error) - GetMetricStatisticsRequest(*cloudwatch.GetMetricStatisticsInput) (*request.Request, *cloudwatch.GetMetricStatisticsOutput) - - ListDashboards(*cloudwatch.ListDashboardsInput) (*cloudwatch.ListDashboardsOutput, error) - ListDashboardsWithContext(aws.Context, *cloudwatch.ListDashboardsInput, ...request.Option) (*cloudwatch.ListDashboardsOutput, error) - ListDashboardsRequest(*cloudwatch.ListDashboardsInput) (*request.Request, *cloudwatch.ListDashboardsOutput) - - ListMetrics(*cloudwatch.ListMetricsInput) (*cloudwatch.ListMetricsOutput, error) - ListMetricsWithContext(aws.Context, *cloudwatch.ListMetricsInput, ...request.Option) (*cloudwatch.ListMetricsOutput, error) - ListMetricsRequest(*cloudwatch.ListMetricsInput) (*request.Request, *cloudwatch.ListMetricsOutput) - - ListMetricsPages(*cloudwatch.ListMetricsInput, func(*cloudwatch.ListMetricsOutput, bool) bool) error - ListMetricsPagesWithContext(aws.Context, *cloudwatch.ListMetricsInput, func(*cloudwatch.ListMetricsOutput, bool) bool, ...request.Option) error - - PutDashboard(*cloudwatch.PutDashboardInput) (*cloudwatch.PutDashboardOutput, error) - PutDashboardWithContext(aws.Context, *cloudwatch.PutDashboardInput, ...request.Option) (*cloudwatch.PutDashboardOutput, error) - PutDashboardRequest(*cloudwatch.PutDashboardInput) (*request.Request, *cloudwatch.PutDashboardOutput) - - PutMetricAlarm(*cloudwatch.PutMetricAlarmInput) (*cloudwatch.PutMetricAlarmOutput, error) - PutMetricAlarmWithContext(aws.Context, *cloudwatch.PutMetricAlarmInput, ...request.Option) (*cloudwatch.PutMetricAlarmOutput, error) - PutMetricAlarmRequest(*cloudwatch.PutMetricAlarmInput) (*request.Request, *cloudwatch.PutMetricAlarmOutput) - - PutMetricData(*cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) - PutMetricDataWithContext(aws.Context, *cloudwatch.PutMetricDataInput, ...request.Option) (*cloudwatch.PutMetricDataOutput, error) - PutMetricDataRequest(*cloudwatch.PutMetricDataInput) (*request.Request, *cloudwatch.PutMetricDataOutput) - - SetAlarmState(*cloudwatch.SetAlarmStateInput) (*cloudwatch.SetAlarmStateOutput, error) - SetAlarmStateWithContext(aws.Context, *cloudwatch.SetAlarmStateInput, ...request.Option) (*cloudwatch.SetAlarmStateOutput, error) - SetAlarmStateRequest(*cloudwatch.SetAlarmStateInput) (*request.Request, *cloudwatch.SetAlarmStateOutput) - - WaitUntilAlarmExists(*cloudwatch.DescribeAlarmsInput) error - WaitUntilAlarmExistsWithContext(aws.Context, *cloudwatch.DescribeAlarmsInput, ...request.WaiterOption) error -} - -var _ CloudWatchAPI = (*cloudwatch.CloudWatch)(nil) diff --git a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/doc.go b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/doc.go index ef2f5025036..662023540c8 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/doc.go +++ b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/doc.go @@ -26,69 +26,17 @@ // // Using the Client // -// To use the client for Amazon CloudWatch you will first need -// to create a new instance of it. +// To contact Amazon CloudWatch with the SDK use the New function to create +// a new service client. With that client you can make API requests to the service. +// These clients are safe to use concurrently. // -// When creating a client for an AWS service you'll first need to have a Session -// already created. The Session provides configuration that can be shared -// between multiple service clients. Additional configuration can be applied to -// the Session and service's client when they are constructed. The aws package's -// Config type contains several fields such as Region for the AWS Region the -// client should make API requests too. The optional Config value can be provided -// as the variadic argument for Sessions and client creation. -// -// Once the service's client is created you can use it to make API requests the -// AWS service. These clients are safe to use concurrently. -// -// // Create a session to share configuration, and load external configuration. -// sess := session.Must(session.NewSession()) -// -// // Create the service's client with the session. -// svc := cloudwatch.New(sess) -// -// See the SDK's documentation for more information on how to use service clients. +// See the SDK's documentation for more information on how to use the SDK. // https://docs.aws.amazon.com/sdk-for-go/api/ // -// See aws package's Config type for more information on configuration options. +// See aws.Config documentation for more information on configuring SDK clients. // https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config // // See the Amazon CloudWatch client CloudWatch for more -// information on creating the service's client. +// information on creating client for this service. // https://docs.aws.amazon.com/sdk-for-go/api/service/cloudwatch/#New -// -// Once the client is created you can make an API request to the service. -// Each API method takes a input parameter, and returns the service response -// and an error. -// -// The API method will document which error codes the service can be returned -// by the operation if the service models the API operation's errors. These -// errors will also be available as const strings prefixed with "ErrCode". -// -// result, err := svc.DeleteAlarms(params) -// if err != nil { -// // Cast err to awserr.Error to handle specific error codes. -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == { -// // Specific error code handling -// } -// return err -// } -// -// fmt.Println("DeleteAlarms result:") -// fmt.Println(result) -// -// Using the Client with Context -// -// The service's client also provides methods to make API requests with a Context -// value. This allows you to control the timeout, and cancellation of pending -// requests. These methods also take request Option as variadic parameter to apply -// additional configuration to the API request. -// -// ctx := context.Background() -// -// result, err := svc.DeleteAlarmsWithContext(ctx, params) -// -// See the request package documentation for more information on using Context pattern -// with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/ package cloudwatch diff --git a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/waiters.go b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/waiters.go index 064abf01566..21e42ac581b 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/waiters.go +++ b/vendor/github.com/aws/aws-sdk-go/service/cloudwatch/waiters.go @@ -11,7 +11,7 @@ import ( // WaitUntilAlarmExists uses the CloudWatch API operation // DescribeAlarms to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *CloudWatch) WaitUntilAlarmExists(input *DescribeAlarmsInput) error { return c.WaitUntilAlarmExistsWithContext(aws.BackgroundContext(), input) diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go index 87b13f313b0..1743b344993 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go @@ -17,19 +17,18 @@ const opAcceptReservedInstancesExchangeQuote = "AcceptReservedInstancesExchangeQ // AcceptReservedInstancesExchangeQuoteRequest generates a "aws/request.Request" representing the // client's request for the AcceptReservedInstancesExchangeQuote operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AcceptReservedInstancesExchangeQuote for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AcceptReservedInstancesExchangeQuote method directly -// instead. +// See AcceptReservedInstancesExchangeQuote for more information on using the AcceptReservedInstancesExchangeQuote +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AcceptReservedInstancesExchangeQuoteRequest method. // req, resp := client.AcceptReservedInstancesExchangeQuoteRequest(params) @@ -39,7 +38,7 @@ const opAcceptReservedInstancesExchangeQuote = "AcceptReservedInstancesExchangeQ // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuote +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuote func (c *EC2) AcceptReservedInstancesExchangeQuoteRequest(input *AcceptReservedInstancesExchangeQuoteInput) (req *request.Request, output *AcceptReservedInstancesExchangeQuoteOutput) { op := &request.Operation{ Name: opAcceptReservedInstancesExchangeQuote, @@ -67,7 +66,7 @@ func (c *EC2) AcceptReservedInstancesExchangeQuoteRequest(input *AcceptReservedI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AcceptReservedInstancesExchangeQuote for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuote +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuote func (c *EC2) AcceptReservedInstancesExchangeQuote(input *AcceptReservedInstancesExchangeQuoteInput) (*AcceptReservedInstancesExchangeQuoteOutput, error) { req, out := c.AcceptReservedInstancesExchangeQuoteRequest(input) return out, req.Send() @@ -89,23 +88,97 @@ func (c *EC2) AcceptReservedInstancesExchangeQuoteWithContext(ctx aws.Context, i return out, req.Send() } +const opAcceptVpcEndpointConnections = "AcceptVpcEndpointConnections" + +// AcceptVpcEndpointConnectionsRequest generates a "aws/request.Request" representing the +// client's request for the AcceptVpcEndpointConnections operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See AcceptVpcEndpointConnections for more information on using the AcceptVpcEndpointConnections +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the AcceptVpcEndpointConnectionsRequest method. +// req, resp := client.AcceptVpcEndpointConnectionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcEndpointConnections +func (c *EC2) AcceptVpcEndpointConnectionsRequest(input *AcceptVpcEndpointConnectionsInput) (req *request.Request, output *AcceptVpcEndpointConnectionsOutput) { + op := &request.Operation{ + Name: opAcceptVpcEndpointConnections, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &AcceptVpcEndpointConnectionsInput{} + } + + output = &AcceptVpcEndpointConnectionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// AcceptVpcEndpointConnections API operation for Amazon Elastic Compute Cloud. +// +// Accepts one or more interface VPC endpoint connection requests to your VPC +// endpoint service. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation AcceptVpcEndpointConnections for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcEndpointConnections +func (c *EC2) AcceptVpcEndpointConnections(input *AcceptVpcEndpointConnectionsInput) (*AcceptVpcEndpointConnectionsOutput, error) { + req, out := c.AcceptVpcEndpointConnectionsRequest(input) + return out, req.Send() +} + +// AcceptVpcEndpointConnectionsWithContext is the same as AcceptVpcEndpointConnections with the addition of +// the ability to pass a context and additional request options. +// +// See AcceptVpcEndpointConnections for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) AcceptVpcEndpointConnectionsWithContext(ctx aws.Context, input *AcceptVpcEndpointConnectionsInput, opts ...request.Option) (*AcceptVpcEndpointConnectionsOutput, error) { + req, out := c.AcceptVpcEndpointConnectionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opAcceptVpcPeeringConnection = "AcceptVpcPeeringConnection" // AcceptVpcPeeringConnectionRequest generates a "aws/request.Request" representing the // client's request for the AcceptVpcPeeringConnection operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AcceptVpcPeeringConnection for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AcceptVpcPeeringConnection method directly -// instead. +// See AcceptVpcPeeringConnection for more information on using the AcceptVpcPeeringConnection +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AcceptVpcPeeringConnectionRequest method. // req, resp := client.AcceptVpcPeeringConnectionRequest(params) @@ -115,7 +188,7 @@ const opAcceptVpcPeeringConnection = "AcceptVpcPeeringConnection" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnection func (c *EC2) AcceptVpcPeeringConnectionRequest(input *AcceptVpcPeeringConnectionInput) (req *request.Request, output *AcceptVpcPeeringConnectionOutput) { op := &request.Operation{ Name: opAcceptVpcPeeringConnection, @@ -139,13 +212,16 @@ func (c *EC2) AcceptVpcPeeringConnectionRequest(input *AcceptVpcPeeringConnectio // of the peer VPC. Use DescribeVpcPeeringConnections to view your outstanding // VPC peering connection requests. // +// For an inter-region VPC peering connection request, you must accept the VPC +// peering connection in the region of the accepter VPC. +// // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about // the error. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AcceptVpcPeeringConnection for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnection func (c *EC2) AcceptVpcPeeringConnection(input *AcceptVpcPeeringConnectionInput) (*AcceptVpcPeeringConnectionOutput, error) { req, out := c.AcceptVpcPeeringConnectionRequest(input) return out, req.Send() @@ -171,19 +247,18 @@ const opAllocateAddress = "AllocateAddress" // AllocateAddressRequest generates a "aws/request.Request" representing the // client's request for the AllocateAddress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AllocateAddress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AllocateAddress method directly -// instead. +// See AllocateAddress for more information on using the AllocateAddress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AllocateAddressRequest method. // req, resp := client.AllocateAddressRequest(params) @@ -193,7 +268,7 @@ const opAllocateAddress = "AllocateAddress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddress func (c *EC2) AllocateAddressRequest(input *AllocateAddressInput) (req *request.Request, output *AllocateAddressOutput) { op := &request.Operation{ Name: opAllocateAddress, @@ -212,10 +287,18 @@ func (c *EC2) AllocateAddressRequest(input *AllocateAddressInput) (req *request. // AllocateAddress API operation for Amazon Elastic Compute Cloud. // -// Acquires an Elastic IP address. +// Allocates an Elastic IP address. // // An Elastic IP address is for use either in the EC2-Classic platform or in -// a VPC. For more information, see Elastic IP Addresses (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) +// a VPC. By default, you can allocate 5 Elastic IP addresses for EC2-Classic +// per region and 5 Elastic IP addresses for EC2-VPC per region. +// +// If you release an Elastic IP address for use in a VPC, you might be able +// to recover it. To recover an Elastic IP address that you released, specify +// it in the Address parameter. Note that you cannot recover an Elastic IP address +// that you released after it is allocated to another AWS account. +// +// For more information, see Elastic IP Addresses (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -224,7 +307,7 @@ func (c *EC2) AllocateAddressRequest(input *AllocateAddressInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AllocateAddress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddress func (c *EC2) AllocateAddress(input *AllocateAddressInput) (*AllocateAddressOutput, error) { req, out := c.AllocateAddressRequest(input) return out, req.Send() @@ -250,19 +333,18 @@ const opAllocateHosts = "AllocateHosts" // AllocateHostsRequest generates a "aws/request.Request" representing the // client's request for the AllocateHosts operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AllocateHosts for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AllocateHosts method directly -// instead. +// See AllocateHosts for more information on using the AllocateHosts +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AllocateHostsRequest method. // req, resp := client.AllocateHostsRequest(params) @@ -272,7 +354,7 @@ const opAllocateHosts = "AllocateHosts" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHosts func (c *EC2) AllocateHostsRequest(input *AllocateHostsInput) (req *request.Request, output *AllocateHostsOutput) { op := &request.Operation{ Name: opAllocateHosts, @@ -301,7 +383,7 @@ func (c *EC2) AllocateHostsRequest(input *AllocateHostsInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AllocateHosts for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHosts func (c *EC2) AllocateHosts(input *AllocateHostsInput) (*AllocateHostsOutput, error) { req, out := c.AllocateHostsRequest(input) return out, req.Send() @@ -327,19 +409,18 @@ const opAssignIpv6Addresses = "AssignIpv6Addresses" // AssignIpv6AddressesRequest generates a "aws/request.Request" representing the // client's request for the AssignIpv6Addresses operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssignIpv6Addresses for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssignIpv6Addresses method directly -// instead. +// See AssignIpv6Addresses for more information on using the AssignIpv6Addresses +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssignIpv6AddressesRequest method. // req, resp := client.AssignIpv6AddressesRequest(params) @@ -349,7 +430,7 @@ const opAssignIpv6Addresses = "AssignIpv6Addresses" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6Addresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6Addresses func (c *EC2) AssignIpv6AddressesRequest(input *AssignIpv6AddressesInput) (req *request.Request, output *AssignIpv6AddressesOutput) { op := &request.Operation{ Name: opAssignIpv6Addresses, @@ -383,7 +464,7 @@ func (c *EC2) AssignIpv6AddressesRequest(input *AssignIpv6AddressesInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssignIpv6Addresses for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6Addresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6Addresses func (c *EC2) AssignIpv6Addresses(input *AssignIpv6AddressesInput) (*AssignIpv6AddressesOutput, error) { req, out := c.AssignIpv6AddressesRequest(input) return out, req.Send() @@ -409,19 +490,18 @@ const opAssignPrivateIpAddresses = "AssignPrivateIpAddresses" // AssignPrivateIpAddressesRequest generates a "aws/request.Request" representing the // client's request for the AssignPrivateIpAddresses operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssignPrivateIpAddresses for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssignPrivateIpAddresses method directly -// instead. +// See AssignPrivateIpAddresses for more information on using the AssignPrivateIpAddresses +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssignPrivateIpAddressesRequest method. // req, resp := client.AssignPrivateIpAddressesRequest(params) @@ -431,7 +511,7 @@ const opAssignPrivateIpAddresses = "AssignPrivateIpAddresses" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddresses func (c *EC2) AssignPrivateIpAddressesRequest(input *AssignPrivateIpAddressesInput) (req *request.Request, output *AssignPrivateIpAddressesOutput) { op := &request.Operation{ Name: opAssignPrivateIpAddresses, @@ -470,7 +550,7 @@ func (c *EC2) AssignPrivateIpAddressesRequest(input *AssignPrivateIpAddressesInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssignPrivateIpAddresses for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddresses func (c *EC2) AssignPrivateIpAddresses(input *AssignPrivateIpAddressesInput) (*AssignPrivateIpAddressesOutput, error) { req, out := c.AssignPrivateIpAddressesRequest(input) return out, req.Send() @@ -496,19 +576,18 @@ const opAssociateAddress = "AssociateAddress" // AssociateAddressRequest generates a "aws/request.Request" representing the // client's request for the AssociateAddress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssociateAddress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssociateAddress method directly -// instead. +// See AssociateAddress for more information on using the AssociateAddress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssociateAddressRequest method. // req, resp := client.AssociateAddressRequest(params) @@ -518,7 +597,7 @@ const opAssociateAddress = "AssociateAddress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddress func (c *EC2) AssociateAddressRequest(input *AssociateAddressInput) (req *request.Request, output *AssociateAddressOutput) { op := &request.Operation{ Name: opAssociateAddress, @@ -568,7 +647,7 @@ func (c *EC2) AssociateAddressRequest(input *AssociateAddressInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssociateAddress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddress func (c *EC2) AssociateAddress(input *AssociateAddressInput) (*AssociateAddressOutput, error) { req, out := c.AssociateAddressRequest(input) return out, req.Send() @@ -594,19 +673,18 @@ const opAssociateDhcpOptions = "AssociateDhcpOptions" // AssociateDhcpOptionsRequest generates a "aws/request.Request" representing the // client's request for the AssociateDhcpOptions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssociateDhcpOptions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssociateDhcpOptions method directly -// instead. +// See AssociateDhcpOptions for more information on using the AssociateDhcpOptions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssociateDhcpOptionsRequest method. // req, resp := client.AssociateDhcpOptionsRequest(params) @@ -616,7 +694,7 @@ const opAssociateDhcpOptions = "AssociateDhcpOptions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptions func (c *EC2) AssociateDhcpOptionsRequest(input *AssociateDhcpOptionsInput) (req *request.Request, output *AssociateDhcpOptionsOutput) { op := &request.Operation{ Name: opAssociateDhcpOptions, @@ -656,7 +734,7 @@ func (c *EC2) AssociateDhcpOptionsRequest(input *AssociateDhcpOptionsInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssociateDhcpOptions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptions func (c *EC2) AssociateDhcpOptions(input *AssociateDhcpOptionsInput) (*AssociateDhcpOptionsOutput, error) { req, out := c.AssociateDhcpOptionsRequest(input) return out, req.Send() @@ -682,19 +760,18 @@ const opAssociateIamInstanceProfile = "AssociateIamInstanceProfile" // AssociateIamInstanceProfileRequest generates a "aws/request.Request" representing the // client's request for the AssociateIamInstanceProfile operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssociateIamInstanceProfile for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssociateIamInstanceProfile method directly -// instead. +// See AssociateIamInstanceProfile for more information on using the AssociateIamInstanceProfile +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssociateIamInstanceProfileRequest method. // req, resp := client.AssociateIamInstanceProfileRequest(params) @@ -704,7 +781,7 @@ const opAssociateIamInstanceProfile = "AssociateIamInstanceProfile" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfile +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfile func (c *EC2) AssociateIamInstanceProfileRequest(input *AssociateIamInstanceProfileInput) (req *request.Request, output *AssociateIamInstanceProfileOutput) { op := &request.Operation{ Name: opAssociateIamInstanceProfile, @@ -732,7 +809,7 @@ func (c *EC2) AssociateIamInstanceProfileRequest(input *AssociateIamInstanceProf // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssociateIamInstanceProfile for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfile +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfile func (c *EC2) AssociateIamInstanceProfile(input *AssociateIamInstanceProfileInput) (*AssociateIamInstanceProfileOutput, error) { req, out := c.AssociateIamInstanceProfileRequest(input) return out, req.Send() @@ -758,19 +835,18 @@ const opAssociateRouteTable = "AssociateRouteTable" // AssociateRouteTableRequest generates a "aws/request.Request" representing the // client's request for the AssociateRouteTable operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssociateRouteTable for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssociateRouteTable method directly -// instead. +// See AssociateRouteTable for more information on using the AssociateRouteTable +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssociateRouteTableRequest method. // req, resp := client.AssociateRouteTableRequest(params) @@ -780,7 +856,7 @@ const opAssociateRouteTable = "AssociateRouteTable" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTable func (c *EC2) AssociateRouteTableRequest(input *AssociateRouteTableInput) (req *request.Request, output *AssociateRouteTableOutput) { op := &request.Operation{ Name: opAssociateRouteTable, @@ -814,7 +890,7 @@ func (c *EC2) AssociateRouteTableRequest(input *AssociateRouteTableInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssociateRouteTable for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTable func (c *EC2) AssociateRouteTable(input *AssociateRouteTableInput) (*AssociateRouteTableOutput, error) { req, out := c.AssociateRouteTableRequest(input) return out, req.Send() @@ -840,19 +916,18 @@ const opAssociateSubnetCidrBlock = "AssociateSubnetCidrBlock" // AssociateSubnetCidrBlockRequest generates a "aws/request.Request" representing the // client's request for the AssociateSubnetCidrBlock operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssociateSubnetCidrBlock for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssociateSubnetCidrBlock method directly -// instead. +// See AssociateSubnetCidrBlock for more information on using the AssociateSubnetCidrBlock +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssociateSubnetCidrBlockRequest method. // req, resp := client.AssociateSubnetCidrBlockRequest(params) @@ -862,7 +937,7 @@ const opAssociateSubnetCidrBlock = "AssociateSubnetCidrBlock" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlock func (c *EC2) AssociateSubnetCidrBlockRequest(input *AssociateSubnetCidrBlockInput) (req *request.Request, output *AssociateSubnetCidrBlockOutput) { op := &request.Operation{ Name: opAssociateSubnetCidrBlock, @@ -891,7 +966,7 @@ func (c *EC2) AssociateSubnetCidrBlockRequest(input *AssociateSubnetCidrBlockInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssociateSubnetCidrBlock for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlock func (c *EC2) AssociateSubnetCidrBlock(input *AssociateSubnetCidrBlockInput) (*AssociateSubnetCidrBlockOutput, error) { req, out := c.AssociateSubnetCidrBlockRequest(input) return out, req.Send() @@ -917,19 +992,18 @@ const opAssociateVpcCidrBlock = "AssociateVpcCidrBlock" // AssociateVpcCidrBlockRequest generates a "aws/request.Request" representing the // client's request for the AssociateVpcCidrBlock operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssociateVpcCidrBlock for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssociateVpcCidrBlock method directly -// instead. +// See AssociateVpcCidrBlock for more information on using the AssociateVpcCidrBlock +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssociateVpcCidrBlockRequest method. // req, resp := client.AssociateVpcCidrBlockRequest(params) @@ -939,7 +1013,7 @@ const opAssociateVpcCidrBlock = "AssociateVpcCidrBlock" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlock func (c *EC2) AssociateVpcCidrBlockRequest(input *AssociateVpcCidrBlockInput) (req *request.Request, output *AssociateVpcCidrBlockOutput) { op := &request.Operation{ Name: opAssociateVpcCidrBlock, @@ -958,8 +1032,13 @@ func (c *EC2) AssociateVpcCidrBlockRequest(input *AssociateVpcCidrBlockInput) (r // AssociateVpcCidrBlock API operation for Amazon Elastic Compute Cloud. // -// Associates a CIDR block with your VPC. You can only associate a single Amazon-provided -// IPv6 CIDR block with your VPC. The IPv6 CIDR block size is fixed at /56. +// Associates a CIDR block with your VPC. You can associate a secondary IPv4 +// CIDR block, or you can associate an Amazon-provided IPv6 CIDR block. The +// IPv6 CIDR block size is fixed at /56. +// +// For more information about associating CIDR blocks with your VPC and applicable +// restrictions, see VPC and Subnet Sizing (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Subnets.html#VPC_Sizing) +// in the Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -967,7 +1046,7 @@ func (c *EC2) AssociateVpcCidrBlockRequest(input *AssociateVpcCidrBlockInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AssociateVpcCidrBlock for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlock func (c *EC2) AssociateVpcCidrBlock(input *AssociateVpcCidrBlockInput) (*AssociateVpcCidrBlockOutput, error) { req, out := c.AssociateVpcCidrBlockRequest(input) return out, req.Send() @@ -993,19 +1072,18 @@ const opAttachClassicLinkVpc = "AttachClassicLinkVpc" // AttachClassicLinkVpcRequest generates a "aws/request.Request" representing the // client's request for the AttachClassicLinkVpc operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AttachClassicLinkVpc for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AttachClassicLinkVpc method directly -// instead. +// See AttachClassicLinkVpc for more information on using the AttachClassicLinkVpc +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AttachClassicLinkVpcRequest method. // req, resp := client.AttachClassicLinkVpcRequest(params) @@ -1015,7 +1093,7 @@ const opAttachClassicLinkVpc = "AttachClassicLinkVpc" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpc func (c *EC2) AttachClassicLinkVpcRequest(input *AttachClassicLinkVpcInput) (req *request.Request, output *AttachClassicLinkVpcOutput) { op := &request.Operation{ Name: opAttachClassicLinkVpc, @@ -1053,7 +1131,7 @@ func (c *EC2) AttachClassicLinkVpcRequest(input *AttachClassicLinkVpcInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AttachClassicLinkVpc for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpc func (c *EC2) AttachClassicLinkVpc(input *AttachClassicLinkVpcInput) (*AttachClassicLinkVpcOutput, error) { req, out := c.AttachClassicLinkVpcRequest(input) return out, req.Send() @@ -1079,19 +1157,18 @@ const opAttachInternetGateway = "AttachInternetGateway" // AttachInternetGatewayRequest generates a "aws/request.Request" representing the // client's request for the AttachInternetGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AttachInternetGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AttachInternetGateway method directly -// instead. +// See AttachInternetGateway for more information on using the AttachInternetGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AttachInternetGatewayRequest method. // req, resp := client.AttachInternetGatewayRequest(params) @@ -1101,7 +1178,7 @@ const opAttachInternetGateway = "AttachInternetGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGateway func (c *EC2) AttachInternetGatewayRequest(input *AttachInternetGatewayInput) (req *request.Request, output *AttachInternetGatewayOutput) { op := &request.Operation{ Name: opAttachInternetGateway, @@ -1132,7 +1209,7 @@ func (c *EC2) AttachInternetGatewayRequest(input *AttachInternetGatewayInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AttachInternetGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGateway func (c *EC2) AttachInternetGateway(input *AttachInternetGatewayInput) (*AttachInternetGatewayOutput, error) { req, out := c.AttachInternetGatewayRequest(input) return out, req.Send() @@ -1158,19 +1235,18 @@ const opAttachNetworkInterface = "AttachNetworkInterface" // AttachNetworkInterfaceRequest generates a "aws/request.Request" representing the // client's request for the AttachNetworkInterface operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AttachNetworkInterface for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AttachNetworkInterface method directly -// instead. +// See AttachNetworkInterface for more information on using the AttachNetworkInterface +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AttachNetworkInterfaceRequest method. // req, resp := client.AttachNetworkInterfaceRequest(params) @@ -1180,7 +1256,7 @@ const opAttachNetworkInterface = "AttachNetworkInterface" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterface func (c *EC2) AttachNetworkInterfaceRequest(input *AttachNetworkInterfaceInput) (req *request.Request, output *AttachNetworkInterfaceOutput) { op := &request.Operation{ Name: opAttachNetworkInterface, @@ -1207,7 +1283,7 @@ func (c *EC2) AttachNetworkInterfaceRequest(input *AttachNetworkInterfaceInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AttachNetworkInterface for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterface func (c *EC2) AttachNetworkInterface(input *AttachNetworkInterfaceInput) (*AttachNetworkInterfaceOutput, error) { req, out := c.AttachNetworkInterfaceRequest(input) return out, req.Send() @@ -1233,19 +1309,18 @@ const opAttachVolume = "AttachVolume" // AttachVolumeRequest generates a "aws/request.Request" representing the // client's request for the AttachVolume operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AttachVolume for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AttachVolume method directly -// instead. +// See AttachVolume for more information on using the AttachVolume +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AttachVolumeRequest method. // req, resp := client.AttachVolumeRequest(params) @@ -1255,7 +1330,7 @@ const opAttachVolume = "AttachVolume" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVolume func (c *EC2) AttachVolumeRequest(input *AttachVolumeInput) (req *request.Request, output *VolumeAttachment) { op := &request.Operation{ Name: opAttachVolume, @@ -1311,7 +1386,7 @@ func (c *EC2) AttachVolumeRequest(input *AttachVolumeInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AttachVolume for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVolume func (c *EC2) AttachVolume(input *AttachVolumeInput) (*VolumeAttachment, error) { req, out := c.AttachVolumeRequest(input) return out, req.Send() @@ -1337,19 +1412,18 @@ const opAttachVpnGateway = "AttachVpnGateway" // AttachVpnGatewayRequest generates a "aws/request.Request" representing the // client's request for the AttachVpnGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AttachVpnGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AttachVpnGateway method directly -// instead. +// See AttachVpnGateway for more information on using the AttachVpnGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AttachVpnGatewayRequest method. // req, resp := client.AttachVpnGatewayRequest(params) @@ -1359,7 +1433,7 @@ const opAttachVpnGateway = "AttachVpnGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGateway func (c *EC2) AttachVpnGatewayRequest(input *AttachVpnGatewayInput) (req *request.Request, output *AttachVpnGatewayOutput) { op := &request.Operation{ Name: opAttachVpnGateway, @@ -1381,8 +1455,7 @@ func (c *EC2) AttachVpnGatewayRequest(input *AttachVpnGatewayInput) (req *reques // Attaches a virtual private gateway to a VPC. You can attach one virtual private // gateway to one VPC at a time. // -// For more information, see Adding a Hardware Virtual Private Gateway to Your -// VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) +// For more information, see AWS Managed VPN Connections (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) // in the Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -1391,7 +1464,7 @@ func (c *EC2) AttachVpnGatewayRequest(input *AttachVpnGatewayInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AttachVpnGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGateway func (c *EC2) AttachVpnGateway(input *AttachVpnGatewayInput) (*AttachVpnGatewayOutput, error) { req, out := c.AttachVpnGatewayRequest(input) return out, req.Send() @@ -1417,19 +1490,18 @@ const opAuthorizeSecurityGroupEgress = "AuthorizeSecurityGroupEgress" // AuthorizeSecurityGroupEgressRequest generates a "aws/request.Request" representing the // client's request for the AuthorizeSecurityGroupEgress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AuthorizeSecurityGroupEgress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AuthorizeSecurityGroupEgress method directly -// instead. +// See AuthorizeSecurityGroupEgress for more information on using the AuthorizeSecurityGroupEgress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AuthorizeSecurityGroupEgressRequest method. // req, resp := client.AuthorizeSecurityGroupEgressRequest(params) @@ -1439,7 +1511,7 @@ const opAuthorizeSecurityGroupEgress = "AuthorizeSecurityGroupEgress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgress func (c *EC2) AuthorizeSecurityGroupEgressRequest(input *AuthorizeSecurityGroupEgressInput) (req *request.Request, output *AuthorizeSecurityGroupEgressOutput) { op := &request.Operation{ Name: opAuthorizeSecurityGroupEgress, @@ -1473,7 +1545,8 @@ func (c *EC2) AuthorizeSecurityGroupEgressRequest(input *AuthorizeSecurityGroupE // range or a source group. For the TCP and UDP protocols, you must also specify // the destination port or port range. For the ICMP protocol, you must also // specify the ICMP type and code. You can use -1 for the type or code to mean -// all types or all codes. +// all types or all codes. You can optionally specify a description for the +// rule. // // Rule changes are propagated to affected instances as quickly as possible. // However, a small delay might occur. @@ -1484,7 +1557,7 @@ func (c *EC2) AuthorizeSecurityGroupEgressRequest(input *AuthorizeSecurityGroupE // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AuthorizeSecurityGroupEgress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgress func (c *EC2) AuthorizeSecurityGroupEgress(input *AuthorizeSecurityGroupEgressInput) (*AuthorizeSecurityGroupEgressOutput, error) { req, out := c.AuthorizeSecurityGroupEgressRequest(input) return out, req.Send() @@ -1510,19 +1583,18 @@ const opAuthorizeSecurityGroupIngress = "AuthorizeSecurityGroupIngress" // AuthorizeSecurityGroupIngressRequest generates a "aws/request.Request" representing the // client's request for the AuthorizeSecurityGroupIngress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AuthorizeSecurityGroupIngress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AuthorizeSecurityGroupIngress method directly -// instead. +// See AuthorizeSecurityGroupIngress for more information on using the AuthorizeSecurityGroupIngress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AuthorizeSecurityGroupIngressRequest method. // req, resp := client.AuthorizeSecurityGroupIngressRequest(params) @@ -1532,7 +1604,7 @@ const opAuthorizeSecurityGroupIngress = "AuthorizeSecurityGroupIngress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngress func (c *EC2) AuthorizeSecurityGroupIngressRequest(input *AuthorizeSecurityGroupIngressInput) (req *request.Request, output *AuthorizeSecurityGroupIngressOutput) { op := &request.Operation{ Name: opAuthorizeSecurityGroupIngress, @@ -1571,13 +1643,15 @@ func (c *EC2) AuthorizeSecurityGroupIngressRequest(input *AuthorizeSecurityGroup // peer VPC in a VPC peering connection. For more information about VPC security // group limits, see Amazon VPC Limits (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Appendix_Limits.html). // +// You can optionally specify a description for the security group rule. +// // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about // the error. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation AuthorizeSecurityGroupIngress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngress func (c *EC2) AuthorizeSecurityGroupIngress(input *AuthorizeSecurityGroupIngressInput) (*AuthorizeSecurityGroupIngressOutput, error) { req, out := c.AuthorizeSecurityGroupIngressRequest(input) return out, req.Send() @@ -1603,19 +1677,18 @@ const opBundleInstance = "BundleInstance" // BundleInstanceRequest generates a "aws/request.Request" representing the // client's request for the BundleInstance operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See BundleInstance for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the BundleInstance method directly -// instead. +// See BundleInstance for more information on using the BundleInstance +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the BundleInstanceRequest method. // req, resp := client.BundleInstanceRequest(params) @@ -1625,7 +1698,7 @@ const opBundleInstance = "BundleInstance" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstance func (c *EC2) BundleInstanceRequest(input *BundleInstanceInput) (req *request.Request, output *BundleInstanceOutput) { op := &request.Operation{ Name: opBundleInstance, @@ -1660,7 +1733,7 @@ func (c *EC2) BundleInstanceRequest(input *BundleInstanceInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation BundleInstance for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstance func (c *EC2) BundleInstance(input *BundleInstanceInput) (*BundleInstanceOutput, error) { req, out := c.BundleInstanceRequest(input) return out, req.Send() @@ -1686,19 +1759,18 @@ const opCancelBundleTask = "CancelBundleTask" // CancelBundleTaskRequest generates a "aws/request.Request" representing the // client's request for the CancelBundleTask operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelBundleTask for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelBundleTask method directly -// instead. +// See CancelBundleTask for more information on using the CancelBundleTask +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelBundleTaskRequest method. // req, resp := client.CancelBundleTaskRequest(params) @@ -1708,7 +1780,7 @@ const opCancelBundleTask = "CancelBundleTask" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTask func (c *EC2) CancelBundleTaskRequest(input *CancelBundleTaskInput) (req *request.Request, output *CancelBundleTaskOutput) { op := &request.Operation{ Name: opCancelBundleTask, @@ -1735,7 +1807,7 @@ func (c *EC2) CancelBundleTaskRequest(input *CancelBundleTaskInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelBundleTask for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTask func (c *EC2) CancelBundleTask(input *CancelBundleTaskInput) (*CancelBundleTaskOutput, error) { req, out := c.CancelBundleTaskRequest(input) return out, req.Send() @@ -1761,19 +1833,18 @@ const opCancelConversionTask = "CancelConversionTask" // CancelConversionTaskRequest generates a "aws/request.Request" representing the // client's request for the CancelConversionTask operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelConversionTask for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelConversionTask method directly -// instead. +// See CancelConversionTask for more information on using the CancelConversionTask +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelConversionTaskRequest method. // req, resp := client.CancelConversionTaskRequest(params) @@ -1783,7 +1854,7 @@ const opCancelConversionTask = "CancelConversionTask" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionTask func (c *EC2) CancelConversionTaskRequest(input *CancelConversionTaskInput) (req *request.Request, output *CancelConversionTaskOutput) { op := &request.Operation{ Name: opCancelConversionTask, @@ -1819,7 +1890,7 @@ func (c *EC2) CancelConversionTaskRequest(input *CancelConversionTaskInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelConversionTask for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionTask func (c *EC2) CancelConversionTask(input *CancelConversionTaskInput) (*CancelConversionTaskOutput, error) { req, out := c.CancelConversionTaskRequest(input) return out, req.Send() @@ -1845,19 +1916,18 @@ const opCancelExportTask = "CancelExportTask" // CancelExportTaskRequest generates a "aws/request.Request" representing the // client's request for the CancelExportTask operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelExportTask for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelExportTask method directly -// instead. +// See CancelExportTask for more information on using the CancelExportTask +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelExportTaskRequest method. // req, resp := client.CancelExportTaskRequest(params) @@ -1867,7 +1937,7 @@ const opCancelExportTask = "CancelExportTask" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTask func (c *EC2) CancelExportTaskRequest(input *CancelExportTaskInput) (req *request.Request, output *CancelExportTaskOutput) { op := &request.Operation{ Name: opCancelExportTask, @@ -1899,7 +1969,7 @@ func (c *EC2) CancelExportTaskRequest(input *CancelExportTaskInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelExportTask for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTask func (c *EC2) CancelExportTask(input *CancelExportTaskInput) (*CancelExportTaskOutput, error) { req, out := c.CancelExportTaskRequest(input) return out, req.Send() @@ -1925,19 +1995,18 @@ const opCancelImportTask = "CancelImportTask" // CancelImportTaskRequest generates a "aws/request.Request" representing the // client's request for the CancelImportTask operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelImportTask for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelImportTask method directly -// instead. +// See CancelImportTask for more information on using the CancelImportTask +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelImportTaskRequest method. // req, resp := client.CancelImportTaskRequest(params) @@ -1947,7 +2016,7 @@ const opCancelImportTask = "CancelImportTask" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTask func (c *EC2) CancelImportTaskRequest(input *CancelImportTaskInput) (req *request.Request, output *CancelImportTaskOutput) { op := &request.Operation{ Name: opCancelImportTask, @@ -1974,7 +2043,7 @@ func (c *EC2) CancelImportTaskRequest(input *CancelImportTaskInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelImportTask for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTask func (c *EC2) CancelImportTask(input *CancelImportTaskInput) (*CancelImportTaskOutput, error) { req, out := c.CancelImportTaskRequest(input) return out, req.Send() @@ -2000,19 +2069,18 @@ const opCancelReservedInstancesListing = "CancelReservedInstancesListing" // CancelReservedInstancesListingRequest generates a "aws/request.Request" representing the // client's request for the CancelReservedInstancesListing operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelReservedInstancesListing for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelReservedInstancesListing method directly -// instead. +// See CancelReservedInstancesListing for more information on using the CancelReservedInstancesListing +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelReservedInstancesListingRequest method. // req, resp := client.CancelReservedInstancesListingRequest(params) @@ -2022,7 +2090,7 @@ const opCancelReservedInstancesListing = "CancelReservedInstancesListing" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListing +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListing func (c *EC2) CancelReservedInstancesListingRequest(input *CancelReservedInstancesListingInput) (req *request.Request, output *CancelReservedInstancesListingOutput) { op := &request.Operation{ Name: opCancelReservedInstancesListing, @@ -2053,7 +2121,7 @@ func (c *EC2) CancelReservedInstancesListingRequest(input *CancelReservedInstanc // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelReservedInstancesListing for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListing +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListing func (c *EC2) CancelReservedInstancesListing(input *CancelReservedInstancesListingInput) (*CancelReservedInstancesListingOutput, error) { req, out := c.CancelReservedInstancesListingRequest(input) return out, req.Send() @@ -2079,19 +2147,18 @@ const opCancelSpotFleetRequests = "CancelSpotFleetRequests" // CancelSpotFleetRequestsRequest generates a "aws/request.Request" representing the // client's request for the CancelSpotFleetRequests operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelSpotFleetRequests for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelSpotFleetRequests method directly -// instead. +// See CancelSpotFleetRequests for more information on using the CancelSpotFleetRequests +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelSpotFleetRequestsRequest method. // req, resp := client.CancelSpotFleetRequestsRequest(params) @@ -2101,7 +2168,7 @@ const opCancelSpotFleetRequests = "CancelSpotFleetRequests" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequests func (c *EC2) CancelSpotFleetRequestsRequest(input *CancelSpotFleetRequestsInput) (req *request.Request, output *CancelSpotFleetRequestsOutput) { op := &request.Operation{ Name: opCancelSpotFleetRequests, @@ -2120,12 +2187,12 @@ func (c *EC2) CancelSpotFleetRequestsRequest(input *CancelSpotFleetRequestsInput // CancelSpotFleetRequests API operation for Amazon Elastic Compute Cloud. // -// Cancels the specified Spot fleet requests. +// Cancels the specified Spot Fleet requests. // -// After you cancel a Spot fleet request, the Spot fleet launches no new Spot -// instances. You must specify whether the Spot fleet should also terminate -// its Spot instances. If you terminate the instances, the Spot fleet request -// enters the cancelled_terminating state. Otherwise, the Spot fleet request +// After you cancel a Spot Fleet request, the Spot Fleet launches no new Spot +// Instances. You must specify whether the Spot Fleet should also terminate +// its Spot Instances. If you terminate the instances, the Spot Fleet request +// enters the cancelled_terminating state. Otherwise, the Spot Fleet request // enters the cancelled_running state and the instances continue to run until // they are interrupted or you terminate them manually. // @@ -2135,7 +2202,7 @@ func (c *EC2) CancelSpotFleetRequestsRequest(input *CancelSpotFleetRequestsInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelSpotFleetRequests for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequests func (c *EC2) CancelSpotFleetRequests(input *CancelSpotFleetRequestsInput) (*CancelSpotFleetRequestsOutput, error) { req, out := c.CancelSpotFleetRequestsRequest(input) return out, req.Send() @@ -2161,19 +2228,18 @@ const opCancelSpotInstanceRequests = "CancelSpotInstanceRequests" // CancelSpotInstanceRequestsRequest generates a "aws/request.Request" representing the // client's request for the CancelSpotInstanceRequests operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CancelSpotInstanceRequests for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CancelSpotInstanceRequests method directly -// instead. +// See CancelSpotInstanceRequests for more information on using the CancelSpotInstanceRequests +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CancelSpotInstanceRequestsRequest method. // req, resp := client.CancelSpotInstanceRequestsRequest(params) @@ -2183,7 +2249,7 @@ const opCancelSpotInstanceRequests = "CancelSpotInstanceRequests" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequests func (c *EC2) CancelSpotInstanceRequestsRequest(input *CancelSpotInstanceRequestsInput) (req *request.Request, output *CancelSpotInstanceRequestsOutput) { op := &request.Operation{ Name: opCancelSpotInstanceRequests, @@ -2202,14 +2268,13 @@ func (c *EC2) CancelSpotInstanceRequestsRequest(input *CancelSpotInstanceRequest // CancelSpotInstanceRequests API operation for Amazon Elastic Compute Cloud. // -// Cancels one or more Spot instance requests. Spot instances are instances -// that Amazon EC2 starts on your behalf when the bid price that you specify -// exceeds the current Spot price. Amazon EC2 periodically sets the Spot price -// based on available Spot instance capacity and current Spot instance requests. -// For more information, see Spot Instance Requests (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html) -// in the Amazon Elastic Compute Cloud User Guide. +// Cancels one or more Spot Instance requests. Spot Instances are instances +// that Amazon EC2 starts on your behalf when the maximum price that you specify +// exceeds the current Spot price. For more information, see Spot Instance Requests +// (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html) in +// the Amazon Elastic Compute Cloud User Guide. // -// Canceling a Spot instance request does not terminate running Spot instances +// Canceling a Spot Instance request does not terminate running Spot Instances // associated with the request. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -2218,7 +2283,7 @@ func (c *EC2) CancelSpotInstanceRequestsRequest(input *CancelSpotInstanceRequest // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CancelSpotInstanceRequests for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequests func (c *EC2) CancelSpotInstanceRequests(input *CancelSpotInstanceRequestsInput) (*CancelSpotInstanceRequestsOutput, error) { req, out := c.CancelSpotInstanceRequestsRequest(input) return out, req.Send() @@ -2244,19 +2309,18 @@ const opConfirmProductInstance = "ConfirmProductInstance" // ConfirmProductInstanceRequest generates a "aws/request.Request" representing the // client's request for the ConfirmProductInstance operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ConfirmProductInstance for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ConfirmProductInstance method directly -// instead. +// See ConfirmProductInstance for more information on using the ConfirmProductInstance +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ConfirmProductInstanceRequest method. // req, resp := client.ConfirmProductInstanceRequest(params) @@ -2266,7 +2330,7 @@ const opConfirmProductInstance = "ConfirmProductInstance" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstance func (c *EC2) ConfirmProductInstanceRequest(input *ConfirmProductInstanceInput) (req *request.Request, output *ConfirmProductInstanceOutput) { op := &request.Operation{ Name: opConfirmProductInstance, @@ -2287,8 +2351,7 @@ func (c *EC2) ConfirmProductInstanceRequest(input *ConfirmProductInstanceInput) // // Determines whether a product code is associated with an instance. This action // can only be used by the owner of the product code. It is useful when a product -// code owner needs to verify whether another user's instance is eligible for -// support. +// code owner must verify whether another user's instance is eligible for support. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -2296,7 +2359,7 @@ func (c *EC2) ConfirmProductInstanceRequest(input *ConfirmProductInstanceInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ConfirmProductInstance for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstance func (c *EC2) ConfirmProductInstance(input *ConfirmProductInstanceInput) (*ConfirmProductInstanceOutput, error) { req, out := c.ConfirmProductInstanceRequest(input) return out, req.Send() @@ -2318,23 +2381,96 @@ func (c *EC2) ConfirmProductInstanceWithContext(ctx aws.Context, input *ConfirmP return out, req.Send() } +const opCopyFpgaImage = "CopyFpgaImage" + +// CopyFpgaImageRequest generates a "aws/request.Request" representing the +// client's request for the CopyFpgaImage operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See CopyFpgaImage for more information on using the CopyFpgaImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the CopyFpgaImageRequest method. +// req, resp := client.CopyFpgaImageRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyFpgaImage +func (c *EC2) CopyFpgaImageRequest(input *CopyFpgaImageInput) (req *request.Request, output *CopyFpgaImageOutput) { + op := &request.Operation{ + Name: opCopyFpgaImage, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CopyFpgaImageInput{} + } + + output = &CopyFpgaImageOutput{} + req = c.newRequest(op, input, output) + return +} + +// CopyFpgaImage API operation for Amazon Elastic Compute Cloud. +// +// Copies the specified Amazon FPGA Image (AFI) to the current region. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation CopyFpgaImage for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyFpgaImage +func (c *EC2) CopyFpgaImage(input *CopyFpgaImageInput) (*CopyFpgaImageOutput, error) { + req, out := c.CopyFpgaImageRequest(input) + return out, req.Send() +} + +// CopyFpgaImageWithContext is the same as CopyFpgaImage with the addition of +// the ability to pass a context and additional request options. +// +// See CopyFpgaImage for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) CopyFpgaImageWithContext(ctx aws.Context, input *CopyFpgaImageInput, opts ...request.Option) (*CopyFpgaImageOutput, error) { + req, out := c.CopyFpgaImageRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opCopyImage = "CopyImage" // CopyImageRequest generates a "aws/request.Request" representing the // client's request for the CopyImage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CopyImage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CopyImage method directly -// instead. +// See CopyImage for more information on using the CopyImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CopyImageRequest method. // req, resp := client.CopyImageRequest(params) @@ -2344,7 +2480,7 @@ const opCopyImage = "CopyImage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImage func (c *EC2) CopyImageRequest(input *CopyImageInput) (req *request.Request, output *CopyImageOutput) { op := &request.Operation{ Name: opCopyImage, @@ -2377,7 +2513,7 @@ func (c *EC2) CopyImageRequest(input *CopyImageInput) (req *request.Request, out // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CopyImage for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImage func (c *EC2) CopyImage(input *CopyImageInput) (*CopyImageOutput, error) { req, out := c.CopyImageRequest(input) return out, req.Send() @@ -2403,19 +2539,18 @@ const opCopySnapshot = "CopySnapshot" // CopySnapshotRequest generates a "aws/request.Request" representing the // client's request for the CopySnapshot operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CopySnapshot for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CopySnapshot method directly -// instead. +// See CopySnapshot for more information on using the CopySnapshot +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CopySnapshotRequest method. // req, resp := client.CopySnapshotRequest(params) @@ -2425,7 +2560,7 @@ const opCopySnapshot = "CopySnapshot" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshot func (c *EC2) CopySnapshotRequest(input *CopySnapshotInput) (req *request.Request, output *CopySnapshotOutput) { op := &request.Operation{ Name: opCopySnapshot, @@ -2471,7 +2606,7 @@ func (c *EC2) CopySnapshotRequest(input *CopySnapshotInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CopySnapshot for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshot func (c *EC2) CopySnapshot(input *CopySnapshotInput) (*CopySnapshotOutput, error) { req, out := c.CopySnapshotRequest(input) return out, req.Send() @@ -2497,19 +2632,18 @@ const opCreateCustomerGateway = "CreateCustomerGateway" // CreateCustomerGatewayRequest generates a "aws/request.Request" representing the // client's request for the CreateCustomerGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateCustomerGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateCustomerGateway method directly -// instead. +// See CreateCustomerGateway for more information on using the CreateCustomerGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateCustomerGatewayRequest method. // req, resp := client.CreateCustomerGatewayRequest(params) @@ -2519,7 +2653,7 @@ const opCreateCustomerGateway = "CreateCustomerGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGateway func (c *EC2) CreateCustomerGatewayRequest(input *CreateCustomerGatewayInput) (req *request.Request, output *CreateCustomerGatewayOutput) { op := &request.Operation{ Name: opCreateCustomerGateway, @@ -2554,9 +2688,9 @@ func (c *EC2) CreateCustomerGatewayRequest(input *CreateCustomerGatewayInput) (r // the exception of 7224, which is reserved in the us-east-1 region, and 9059, // which is reserved in the eu-west-1 region. // -// For more information about VPN customer gateways, see Adding a Hardware Virtual -// Private Gateway to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) -// in the Amazon Virtual Private Cloud User Guide. +// For more information about VPN customer gateways, see AWS Managed VPN Connections +// (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) in the +// Amazon Virtual Private Cloud User Guide. // // You cannot create more than one customer gateway with the same VPN type, // IP address, and BGP ASN parameter values. If you run an identical request @@ -2570,7 +2704,7 @@ func (c *EC2) CreateCustomerGatewayRequest(input *CreateCustomerGatewayInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateCustomerGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGateway func (c *EC2) CreateCustomerGateway(input *CreateCustomerGatewayInput) (*CreateCustomerGatewayOutput, error) { req, out := c.CreateCustomerGatewayRequest(input) return out, req.Send() @@ -2592,23 +2726,100 @@ func (c *EC2) CreateCustomerGatewayWithContext(ctx aws.Context, input *CreateCus return out, req.Send() } +const opCreateDefaultSubnet = "CreateDefaultSubnet" + +// CreateDefaultSubnetRequest generates a "aws/request.Request" representing the +// client's request for the CreateDefaultSubnet operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See CreateDefaultSubnet for more information on using the CreateDefaultSubnet +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the CreateDefaultSubnetRequest method. +// req, resp := client.CreateDefaultSubnetRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultSubnet +func (c *EC2) CreateDefaultSubnetRequest(input *CreateDefaultSubnetInput) (req *request.Request, output *CreateDefaultSubnetOutput) { + op := &request.Operation{ + Name: opCreateDefaultSubnet, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CreateDefaultSubnetInput{} + } + + output = &CreateDefaultSubnetOutput{} + req = c.newRequest(op, input, output) + return +} + +// CreateDefaultSubnet API operation for Amazon Elastic Compute Cloud. +// +// Creates a default subnet with a size /20 IPv4 CIDR block in the specified +// Availability Zone in your default VPC. You can have only one default subnet +// per Availability Zone. For more information, see Creating a Default Subnet +// (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/default-vpc.html#create-default-subnet) +// in the Amazon Virtual Private Cloud User Guide. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation CreateDefaultSubnet for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultSubnet +func (c *EC2) CreateDefaultSubnet(input *CreateDefaultSubnetInput) (*CreateDefaultSubnetOutput, error) { + req, out := c.CreateDefaultSubnetRequest(input) + return out, req.Send() +} + +// CreateDefaultSubnetWithContext is the same as CreateDefaultSubnet with the addition of +// the ability to pass a context and additional request options. +// +// See CreateDefaultSubnet for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) CreateDefaultSubnetWithContext(ctx aws.Context, input *CreateDefaultSubnetInput, opts ...request.Option) (*CreateDefaultSubnetOutput, error) { + req, out := c.CreateDefaultSubnetRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opCreateDefaultVpc = "CreateDefaultVpc" // CreateDefaultVpcRequest generates a "aws/request.Request" representing the // client's request for the CreateDefaultVpc operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateDefaultVpc for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateDefaultVpc method directly -// instead. +// See CreateDefaultVpc for more information on using the CreateDefaultVpc +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateDefaultVpcRequest method. // req, resp := client.CreateDefaultVpcRequest(params) @@ -2618,7 +2829,7 @@ const opCreateDefaultVpc = "CreateDefaultVpc" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpc func (c *EC2) CreateDefaultVpcRequest(input *CreateDefaultVpcInput) (req *request.Request, output *CreateDefaultVpcOutput) { op := &request.Operation{ Name: opCreateDefaultVpc, @@ -2657,7 +2868,7 @@ func (c *EC2) CreateDefaultVpcRequest(input *CreateDefaultVpcInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateDefaultVpc for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpc func (c *EC2) CreateDefaultVpc(input *CreateDefaultVpcInput) (*CreateDefaultVpcOutput, error) { req, out := c.CreateDefaultVpcRequest(input) return out, req.Send() @@ -2683,19 +2894,18 @@ const opCreateDhcpOptions = "CreateDhcpOptions" // CreateDhcpOptionsRequest generates a "aws/request.Request" representing the // client's request for the CreateDhcpOptions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateDhcpOptions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateDhcpOptions method directly -// instead. +// See CreateDhcpOptions for more information on using the CreateDhcpOptions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateDhcpOptionsRequest method. // req, resp := client.CreateDhcpOptionsRequest(params) @@ -2705,7 +2915,7 @@ const opCreateDhcpOptions = "CreateDhcpOptions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptions func (c *EC2) CreateDhcpOptionsRequest(input *CreateDhcpOptionsInput) (req *request.Request, output *CreateDhcpOptionsOutput) { op := &request.Operation{ Name: opCreateDhcpOptions, @@ -2771,7 +2981,7 @@ func (c *EC2) CreateDhcpOptionsRequest(input *CreateDhcpOptionsInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateDhcpOptions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptions func (c *EC2) CreateDhcpOptions(input *CreateDhcpOptionsInput) (*CreateDhcpOptionsOutput, error) { req, out := c.CreateDhcpOptionsRequest(input) return out, req.Send() @@ -2797,19 +3007,18 @@ const opCreateEgressOnlyInternetGateway = "CreateEgressOnlyInternetGateway" // CreateEgressOnlyInternetGatewayRequest generates a "aws/request.Request" representing the // client's request for the CreateEgressOnlyInternetGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateEgressOnlyInternetGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateEgressOnlyInternetGateway method directly -// instead. +// See CreateEgressOnlyInternetGateway for more information on using the CreateEgressOnlyInternetGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateEgressOnlyInternetGatewayRequest method. // req, resp := client.CreateEgressOnlyInternetGatewayRequest(params) @@ -2819,7 +3028,7 @@ const opCreateEgressOnlyInternetGateway = "CreateEgressOnlyInternetGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGateway func (c *EC2) CreateEgressOnlyInternetGatewayRequest(input *CreateEgressOnlyInternetGatewayInput) (req *request.Request, output *CreateEgressOnlyInternetGatewayOutput) { op := &request.Operation{ Name: opCreateEgressOnlyInternetGateway, @@ -2849,7 +3058,7 @@ func (c *EC2) CreateEgressOnlyInternetGatewayRequest(input *CreateEgressOnlyInte // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateEgressOnlyInternetGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGateway func (c *EC2) CreateEgressOnlyInternetGateway(input *CreateEgressOnlyInternetGatewayInput) (*CreateEgressOnlyInternetGatewayOutput, error) { req, out := c.CreateEgressOnlyInternetGatewayRequest(input) return out, req.Send() @@ -2875,19 +3084,18 @@ const opCreateFlowLogs = "CreateFlowLogs" // CreateFlowLogsRequest generates a "aws/request.Request" representing the // client's request for the CreateFlowLogs operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateFlowLogs for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateFlowLogs method directly -// instead. +// See CreateFlowLogs for more information on using the CreateFlowLogs +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateFlowLogsRequest method. // req, resp := client.CreateFlowLogsRequest(params) @@ -2897,7 +3105,7 @@ const opCreateFlowLogs = "CreateFlowLogs" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogs func (c *EC2) CreateFlowLogsRequest(input *CreateFlowLogsInput) (req *request.Request, output *CreateFlowLogsOutput) { op := &request.Operation{ Name: opCreateFlowLogs, @@ -2933,7 +3141,7 @@ func (c *EC2) CreateFlowLogsRequest(input *CreateFlowLogsInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateFlowLogs for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogs func (c *EC2) CreateFlowLogs(input *CreateFlowLogsInput) (*CreateFlowLogsOutput, error) { req, out := c.CreateFlowLogsRequest(input) return out, req.Send() @@ -2959,19 +3167,18 @@ const opCreateFpgaImage = "CreateFpgaImage" // CreateFpgaImageRequest generates a "aws/request.Request" representing the // client's request for the CreateFpgaImage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateFpgaImage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateFpgaImage method directly -// instead. +// See CreateFpgaImage for more information on using the CreateFpgaImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateFpgaImageRequest method. // req, resp := client.CreateFpgaImageRequest(params) @@ -2981,7 +3188,7 @@ const opCreateFpgaImage = "CreateFpgaImage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImage func (c *EC2) CreateFpgaImageRequest(input *CreateFpgaImageInput) (req *request.Request, output *CreateFpgaImageOutput) { op := &request.Operation{ Name: opCreateFpgaImage, @@ -3015,7 +3222,7 @@ func (c *EC2) CreateFpgaImageRequest(input *CreateFpgaImageInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateFpgaImage for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImage func (c *EC2) CreateFpgaImage(input *CreateFpgaImageInput) (*CreateFpgaImageOutput, error) { req, out := c.CreateFpgaImageRequest(input) return out, req.Send() @@ -3041,19 +3248,18 @@ const opCreateImage = "CreateImage" // CreateImageRequest generates a "aws/request.Request" representing the // client's request for the CreateImage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateImage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateImage method directly -// instead. +// See CreateImage for more information on using the CreateImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateImageRequest method. // req, resp := client.CreateImageRequest(params) @@ -3063,7 +3269,7 @@ const opCreateImage = "CreateImage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImage func (c *EC2) CreateImageRequest(input *CreateImageInput) (req *request.Request, output *CreateImageOutput) { op := &request.Operation{ Name: opCreateImage, @@ -3099,7 +3305,7 @@ func (c *EC2) CreateImageRequest(input *CreateImageInput) (req *request.Request, // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateImage for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImage func (c *EC2) CreateImage(input *CreateImageInput) (*CreateImageOutput, error) { req, out := c.CreateImageRequest(input) return out, req.Send() @@ -3125,19 +3331,18 @@ const opCreateInstanceExportTask = "CreateInstanceExportTask" // CreateInstanceExportTaskRequest generates a "aws/request.Request" representing the // client's request for the CreateInstanceExportTask operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateInstanceExportTask for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateInstanceExportTask method directly -// instead. +// See CreateInstanceExportTask for more information on using the CreateInstanceExportTask +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateInstanceExportTaskRequest method. // req, resp := client.CreateInstanceExportTaskRequest(params) @@ -3147,7 +3352,7 @@ const opCreateInstanceExportTask = "CreateInstanceExportTask" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTask func (c *EC2) CreateInstanceExportTaskRequest(input *CreateInstanceExportTaskInput) (req *request.Request, output *CreateInstanceExportTaskOutput) { op := &request.Operation{ Name: opCreateInstanceExportTask, @@ -3179,7 +3384,7 @@ func (c *EC2) CreateInstanceExportTaskRequest(input *CreateInstanceExportTaskInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateInstanceExportTask for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTask func (c *EC2) CreateInstanceExportTask(input *CreateInstanceExportTaskInput) (*CreateInstanceExportTaskOutput, error) { req, out := c.CreateInstanceExportTaskRequest(input) return out, req.Send() @@ -3205,19 +3410,18 @@ const opCreateInternetGateway = "CreateInternetGateway" // CreateInternetGatewayRequest generates a "aws/request.Request" representing the // client's request for the CreateInternetGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateInternetGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateInternetGateway method directly -// instead. +// See CreateInternetGateway for more information on using the CreateInternetGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateInternetGatewayRequest method. // req, resp := client.CreateInternetGatewayRequest(params) @@ -3227,7 +3431,7 @@ const opCreateInternetGateway = "CreateInternetGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGateway func (c *EC2) CreateInternetGatewayRequest(input *CreateInternetGatewayInput) (req *request.Request, output *CreateInternetGatewayOutput) { op := &request.Operation{ Name: opCreateInternetGateway, @@ -3258,7 +3462,7 @@ func (c *EC2) CreateInternetGatewayRequest(input *CreateInternetGatewayInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateInternetGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGateway func (c *EC2) CreateInternetGateway(input *CreateInternetGatewayInput) (*CreateInternetGatewayOutput, error) { req, out := c.CreateInternetGatewayRequest(input) return out, req.Send() @@ -3284,19 +3488,18 @@ const opCreateKeyPair = "CreateKeyPair" // CreateKeyPairRequest generates a "aws/request.Request" representing the // client's request for the CreateKeyPair operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateKeyPair for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateKeyPair method directly -// instead. +// See CreateKeyPair for more information on using the CreateKeyPair +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateKeyPairRequest method. // req, resp := client.CreateKeyPairRequest(params) @@ -3306,7 +3509,7 @@ const opCreateKeyPair = "CreateKeyPair" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateKeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateKeyPair func (c *EC2) CreateKeyPairRequest(input *CreateKeyPairInput) (req *request.Request, output *CreateKeyPairOutput) { op := &request.Operation{ Name: opCreateKeyPair, @@ -3327,15 +3530,16 @@ func (c *EC2) CreateKeyPairRequest(input *CreateKeyPairInput) (req *request.Requ // // Creates a 2048-bit RSA key pair with the specified name. Amazon EC2 stores // the public key and displays the private key for you to save to a file. The -// private key is returned as an unencrypted PEM encoded PKCS#8 private key. +// private key is returned as an unencrypted PEM encoded PKCS#1 private key. // If a key with the specified name already exists, Amazon EC2 returns an error. // // You can have up to five thousand key pairs per region. // // The key pair returned to you is available only in the region in which you -// create it. To create a key pair that is available in all regions, use ImportKeyPair. +// create it. If you prefer, you can create your own key pair using a third-party +// tool and upload it to any region using ImportKeyPair. // -// For more information about key pairs, see Key Pairs (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) +// For more information, see Key Pairs (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -3344,7 +3548,7 @@ func (c *EC2) CreateKeyPairRequest(input *CreateKeyPairInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateKeyPair for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateKeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateKeyPair func (c *EC2) CreateKeyPair(input *CreateKeyPairInput) (*CreateKeyPairOutput, error) { req, out := c.CreateKeyPairRequest(input) return out, req.Send() @@ -3366,23 +3570,176 @@ func (c *EC2) CreateKeyPairWithContext(ctx aws.Context, input *CreateKeyPairInpu return out, req.Send() } +const opCreateLaunchTemplate = "CreateLaunchTemplate" + +// CreateLaunchTemplateRequest generates a "aws/request.Request" representing the +// client's request for the CreateLaunchTemplate operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See CreateLaunchTemplate for more information on using the CreateLaunchTemplate +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the CreateLaunchTemplateRequest method. +// req, resp := client.CreateLaunchTemplateRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplate +func (c *EC2) CreateLaunchTemplateRequest(input *CreateLaunchTemplateInput) (req *request.Request, output *CreateLaunchTemplateOutput) { + op := &request.Operation{ + Name: opCreateLaunchTemplate, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CreateLaunchTemplateInput{} + } + + output = &CreateLaunchTemplateOutput{} + req = c.newRequest(op, input, output) + return +} + +// CreateLaunchTemplate API operation for Amazon Elastic Compute Cloud. +// +// Creates a launch template. A launch template contains the parameters to launch +// an instance. When you launch an instance using RunInstances, you can specify +// a launch template instead of providing the launch parameters in the request. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation CreateLaunchTemplate for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplate +func (c *EC2) CreateLaunchTemplate(input *CreateLaunchTemplateInput) (*CreateLaunchTemplateOutput, error) { + req, out := c.CreateLaunchTemplateRequest(input) + return out, req.Send() +} + +// CreateLaunchTemplateWithContext is the same as CreateLaunchTemplate with the addition of +// the ability to pass a context and additional request options. +// +// See CreateLaunchTemplate for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) CreateLaunchTemplateWithContext(ctx aws.Context, input *CreateLaunchTemplateInput, opts ...request.Option) (*CreateLaunchTemplateOutput, error) { + req, out := c.CreateLaunchTemplateRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opCreateLaunchTemplateVersion = "CreateLaunchTemplateVersion" + +// CreateLaunchTemplateVersionRequest generates a "aws/request.Request" representing the +// client's request for the CreateLaunchTemplateVersion operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See CreateLaunchTemplateVersion for more information on using the CreateLaunchTemplateVersion +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the CreateLaunchTemplateVersionRequest method. +// req, resp := client.CreateLaunchTemplateVersionRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplateVersion +func (c *EC2) CreateLaunchTemplateVersionRequest(input *CreateLaunchTemplateVersionInput) (req *request.Request, output *CreateLaunchTemplateVersionOutput) { + op := &request.Operation{ + Name: opCreateLaunchTemplateVersion, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CreateLaunchTemplateVersionInput{} + } + + output = &CreateLaunchTemplateVersionOutput{} + req = c.newRequest(op, input, output) + return +} + +// CreateLaunchTemplateVersion API operation for Amazon Elastic Compute Cloud. +// +// Creates a new version for a launch template. You can specify an existing +// version of launch template from which to base the new version. +// +// Launch template versions are numbered in the order in which they are created. +// You cannot specify, change, or replace the numbering of launch template versions. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation CreateLaunchTemplateVersion for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplateVersion +func (c *EC2) CreateLaunchTemplateVersion(input *CreateLaunchTemplateVersionInput) (*CreateLaunchTemplateVersionOutput, error) { + req, out := c.CreateLaunchTemplateVersionRequest(input) + return out, req.Send() +} + +// CreateLaunchTemplateVersionWithContext is the same as CreateLaunchTemplateVersion with the addition of +// the ability to pass a context and additional request options. +// +// See CreateLaunchTemplateVersion for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) CreateLaunchTemplateVersionWithContext(ctx aws.Context, input *CreateLaunchTemplateVersionInput, opts ...request.Option) (*CreateLaunchTemplateVersionOutput, error) { + req, out := c.CreateLaunchTemplateVersionRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opCreateNatGateway = "CreateNatGateway" // CreateNatGatewayRequest generates a "aws/request.Request" representing the // client's request for the CreateNatGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateNatGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateNatGateway method directly -// instead. +// See CreateNatGateway for more information on using the CreateNatGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateNatGatewayRequest method. // req, resp := client.CreateNatGatewayRequest(params) @@ -3392,7 +3749,7 @@ const opCreateNatGateway = "CreateNatGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGateway func (c *EC2) CreateNatGatewayRequest(input *CreateNatGatewayInput) (req *request.Request, output *CreateNatGatewayOutput) { op := &request.Operation{ Name: opCreateNatGateway, @@ -3424,7 +3781,7 @@ func (c *EC2) CreateNatGatewayRequest(input *CreateNatGatewayInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateNatGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGateway func (c *EC2) CreateNatGateway(input *CreateNatGatewayInput) (*CreateNatGatewayOutput, error) { req, out := c.CreateNatGatewayRequest(input) return out, req.Send() @@ -3450,19 +3807,18 @@ const opCreateNetworkAcl = "CreateNetworkAcl" // CreateNetworkAclRequest generates a "aws/request.Request" representing the // client's request for the CreateNetworkAcl operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateNetworkAcl for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateNetworkAcl method directly -// instead. +// See CreateNetworkAcl for more information on using the CreateNetworkAcl +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateNetworkAclRequest method. // req, resp := client.CreateNetworkAclRequest(params) @@ -3472,7 +3828,7 @@ const opCreateNetworkAcl = "CreateNetworkAcl" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAcl func (c *EC2) CreateNetworkAclRequest(input *CreateNetworkAclInput) (req *request.Request, output *CreateNetworkAclOutput) { op := &request.Operation{ Name: opCreateNetworkAcl, @@ -3503,7 +3859,7 @@ func (c *EC2) CreateNetworkAclRequest(input *CreateNetworkAclInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateNetworkAcl for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAcl func (c *EC2) CreateNetworkAcl(input *CreateNetworkAclInput) (*CreateNetworkAclOutput, error) { req, out := c.CreateNetworkAclRequest(input) return out, req.Send() @@ -3529,19 +3885,18 @@ const opCreateNetworkAclEntry = "CreateNetworkAclEntry" // CreateNetworkAclEntryRequest generates a "aws/request.Request" representing the // client's request for the CreateNetworkAclEntry operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateNetworkAclEntry for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateNetworkAclEntry method directly -// instead. +// See CreateNetworkAclEntry for more information on using the CreateNetworkAclEntry +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateNetworkAclEntryRequest method. // req, resp := client.CreateNetworkAclEntryRequest(params) @@ -3551,7 +3906,7 @@ const opCreateNetworkAclEntry = "CreateNetworkAclEntry" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntry func (c *EC2) CreateNetworkAclEntryRequest(input *CreateNetworkAclEntryInput) (req *request.Request, output *CreateNetworkAclEntryOutput) { op := &request.Operation{ Name: opCreateNetworkAclEntry, @@ -3596,7 +3951,7 @@ func (c *EC2) CreateNetworkAclEntryRequest(input *CreateNetworkAclEntryInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateNetworkAclEntry for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntry func (c *EC2) CreateNetworkAclEntry(input *CreateNetworkAclEntryInput) (*CreateNetworkAclEntryOutput, error) { req, out := c.CreateNetworkAclEntryRequest(input) return out, req.Send() @@ -3622,19 +3977,18 @@ const opCreateNetworkInterface = "CreateNetworkInterface" // CreateNetworkInterfaceRequest generates a "aws/request.Request" representing the // client's request for the CreateNetworkInterface operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateNetworkInterface for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateNetworkInterface method directly -// instead. +// See CreateNetworkInterface for more information on using the CreateNetworkInterface +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateNetworkInterfaceRequest method. // req, resp := client.CreateNetworkInterfaceRequest(params) @@ -3644,7 +3998,7 @@ const opCreateNetworkInterface = "CreateNetworkInterface" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterface func (c *EC2) CreateNetworkInterfaceRequest(input *CreateNetworkInterfaceInput) (req *request.Request, output *CreateNetworkInterfaceOutput) { op := &request.Operation{ Name: opCreateNetworkInterface, @@ -3675,7 +4029,7 @@ func (c *EC2) CreateNetworkInterfaceRequest(input *CreateNetworkInterfaceInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateNetworkInterface for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterface func (c *EC2) CreateNetworkInterface(input *CreateNetworkInterfaceInput) (*CreateNetworkInterfaceOutput, error) { req, out := c.CreateNetworkInterfaceRequest(input) return out, req.Send() @@ -3701,19 +4055,18 @@ const opCreateNetworkInterfacePermission = "CreateNetworkInterfacePermission" // CreateNetworkInterfacePermissionRequest generates a "aws/request.Request" representing the // client's request for the CreateNetworkInterfacePermission operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateNetworkInterfacePermission for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateNetworkInterfacePermission method directly -// instead. +// See CreateNetworkInterfacePermission for more information on using the CreateNetworkInterfacePermission +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateNetworkInterfacePermissionRequest method. // req, resp := client.CreateNetworkInterfacePermissionRequest(params) @@ -3723,7 +4076,7 @@ const opCreateNetworkInterfacePermission = "CreateNetworkInterfacePermission" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermission func (c *EC2) CreateNetworkInterfacePermissionRequest(input *CreateNetworkInterfacePermissionInput) (req *request.Request, output *CreateNetworkInterfacePermissionOutput) { op := &request.Operation{ Name: opCreateNetworkInterfacePermission, @@ -3754,7 +4107,7 @@ func (c *EC2) CreateNetworkInterfacePermissionRequest(input *CreateNetworkInterf // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateNetworkInterfacePermission for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermission func (c *EC2) CreateNetworkInterfacePermission(input *CreateNetworkInterfacePermissionInput) (*CreateNetworkInterfacePermissionOutput, error) { req, out := c.CreateNetworkInterfacePermissionRequest(input) return out, req.Send() @@ -3780,19 +4133,18 @@ const opCreatePlacementGroup = "CreatePlacementGroup" // CreatePlacementGroupRequest generates a "aws/request.Request" representing the // client's request for the CreatePlacementGroup operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreatePlacementGroup for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreatePlacementGroup method directly -// instead. +// See CreatePlacementGroup for more information on using the CreatePlacementGroup +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreatePlacementGroupRequest method. // req, resp := client.CreatePlacementGroupRequest(params) @@ -3802,7 +4154,7 @@ const opCreatePlacementGroup = "CreatePlacementGroup" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroup func (c *EC2) CreatePlacementGroupRequest(input *CreatePlacementGroupInput) (req *request.Request, output *CreatePlacementGroupOutput) { op := &request.Operation{ Name: opCreatePlacementGroup, @@ -3823,11 +4175,14 @@ func (c *EC2) CreatePlacementGroupRequest(input *CreatePlacementGroupInput) (req // CreatePlacementGroup API operation for Amazon Elastic Compute Cloud. // -// Creates a placement group that you launch cluster instances into. You must -// give the group a name that's unique within the scope of your account. +// Creates a placement group in which to launch instances. The strategy of the +// placement group determines how the instances are organized within the group. // -// For more information about placement groups and cluster instances, see Cluster -// Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using_cluster_computing.html) +// A cluster placement group is a logical grouping of instances within a single +// Availability Zone that benefit from low network latency, high network throughput. +// A spread placement group places instances on distinct hardware. +// +// For more information, see Placement Groups (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -3836,7 +4191,7 @@ func (c *EC2) CreatePlacementGroupRequest(input *CreatePlacementGroupInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreatePlacementGroup for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroup func (c *EC2) CreatePlacementGroup(input *CreatePlacementGroupInput) (*CreatePlacementGroupOutput, error) { req, out := c.CreatePlacementGroupRequest(input) return out, req.Send() @@ -3862,19 +4217,18 @@ const opCreateReservedInstancesListing = "CreateReservedInstancesListing" // CreateReservedInstancesListingRequest generates a "aws/request.Request" representing the // client's request for the CreateReservedInstancesListing operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateReservedInstancesListing for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateReservedInstancesListing method directly -// instead. +// See CreateReservedInstancesListing for more information on using the CreateReservedInstancesListing +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateReservedInstancesListingRequest method. // req, resp := client.CreateReservedInstancesListingRequest(params) @@ -3884,7 +4238,7 @@ const opCreateReservedInstancesListing = "CreateReservedInstancesListing" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListing +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListing func (c *EC2) CreateReservedInstancesListingRequest(input *CreateReservedInstancesListingInput) (req *request.Request, output *CreateReservedInstancesListingOutput) { op := &request.Operation{ Name: opCreateReservedInstancesListing, @@ -3934,7 +4288,7 @@ func (c *EC2) CreateReservedInstancesListingRequest(input *CreateReservedInstanc // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateReservedInstancesListing for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListing +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListing func (c *EC2) CreateReservedInstancesListing(input *CreateReservedInstancesListingInput) (*CreateReservedInstancesListingOutput, error) { req, out := c.CreateReservedInstancesListingRequest(input) return out, req.Send() @@ -3960,19 +4314,18 @@ const opCreateRoute = "CreateRoute" // CreateRouteRequest generates a "aws/request.Request" representing the // client's request for the CreateRoute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateRoute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateRoute method directly -// instead. +// See CreateRoute for more information on using the CreateRoute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateRouteRequest method. // req, resp := client.CreateRouteRequest(params) @@ -3982,7 +4335,7 @@ const opCreateRoute = "CreateRoute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRoute func (c *EC2) CreateRouteRequest(input *CreateRouteInput) (req *request.Request, output *CreateRouteOutput) { op := &request.Operation{ Name: opCreateRoute, @@ -4028,7 +4381,7 @@ func (c *EC2) CreateRouteRequest(input *CreateRouteInput) (req *request.Request, // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateRoute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRoute func (c *EC2) CreateRoute(input *CreateRouteInput) (*CreateRouteOutput, error) { req, out := c.CreateRouteRequest(input) return out, req.Send() @@ -4054,19 +4407,18 @@ const opCreateRouteTable = "CreateRouteTable" // CreateRouteTableRequest generates a "aws/request.Request" representing the // client's request for the CreateRouteTable operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateRouteTable for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateRouteTable method directly -// instead. +// See CreateRouteTable for more information on using the CreateRouteTable +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateRouteTableRequest method. // req, resp := client.CreateRouteTableRequest(params) @@ -4076,7 +4428,7 @@ const opCreateRouteTable = "CreateRouteTable" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTable func (c *EC2) CreateRouteTableRequest(input *CreateRouteTableInput) (req *request.Request, output *CreateRouteTableOutput) { op := &request.Operation{ Name: opCreateRouteTable, @@ -4107,7 +4459,7 @@ func (c *EC2) CreateRouteTableRequest(input *CreateRouteTableInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateRouteTable for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTable func (c *EC2) CreateRouteTable(input *CreateRouteTableInput) (*CreateRouteTableOutput, error) { req, out := c.CreateRouteTableRequest(input) return out, req.Send() @@ -4133,19 +4485,18 @@ const opCreateSecurityGroup = "CreateSecurityGroup" // CreateSecurityGroupRequest generates a "aws/request.Request" representing the // client's request for the CreateSecurityGroup operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateSecurityGroup for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateSecurityGroup method directly -// instead. +// See CreateSecurityGroup for more information on using the CreateSecurityGroup +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateSecurityGroupRequest method. // req, resp := client.CreateSecurityGroupRequest(params) @@ -4155,7 +4506,7 @@ const opCreateSecurityGroup = "CreateSecurityGroup" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroup func (c *EC2) CreateSecurityGroupRequest(input *CreateSecurityGroupInput) (req *request.Request, output *CreateSecurityGroupOutput) { op := &request.Operation{ Name: opCreateSecurityGroup, @@ -4208,7 +4559,7 @@ func (c *EC2) CreateSecurityGroupRequest(input *CreateSecurityGroupInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateSecurityGroup for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroup func (c *EC2) CreateSecurityGroup(input *CreateSecurityGroupInput) (*CreateSecurityGroupOutput, error) { req, out := c.CreateSecurityGroupRequest(input) return out, req.Send() @@ -4234,19 +4585,18 @@ const opCreateSnapshot = "CreateSnapshot" // CreateSnapshotRequest generates a "aws/request.Request" representing the // client's request for the CreateSnapshot operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateSnapshot for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateSnapshot method directly -// instead. +// See CreateSnapshot for more information on using the CreateSnapshot +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateSnapshotRequest method. // req, resp := client.CreateSnapshotRequest(params) @@ -4256,7 +4606,7 @@ const opCreateSnapshot = "CreateSnapshot" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSnapshot func (c *EC2) CreateSnapshotRequest(input *CreateSnapshotInput) (req *request.Request, output *Snapshot) { op := &request.Operation{ Name: opCreateSnapshot, @@ -4310,7 +4660,7 @@ func (c *EC2) CreateSnapshotRequest(input *CreateSnapshotInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateSnapshot for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSnapshot func (c *EC2) CreateSnapshot(input *CreateSnapshotInput) (*Snapshot, error) { req, out := c.CreateSnapshotRequest(input) return out, req.Send() @@ -4336,19 +4686,18 @@ const opCreateSpotDatafeedSubscription = "CreateSpotDatafeedSubscription" // CreateSpotDatafeedSubscriptionRequest generates a "aws/request.Request" representing the // client's request for the CreateSpotDatafeedSubscription operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateSpotDatafeedSubscription for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateSpotDatafeedSubscription method directly -// instead. +// See CreateSpotDatafeedSubscription for more information on using the CreateSpotDatafeedSubscription +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateSpotDatafeedSubscriptionRequest method. // req, resp := client.CreateSpotDatafeedSubscriptionRequest(params) @@ -4358,7 +4707,7 @@ const opCreateSpotDatafeedSubscription = "CreateSpotDatafeedSubscription" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscription func (c *EC2) CreateSpotDatafeedSubscriptionRequest(input *CreateSpotDatafeedSubscriptionInput) (req *request.Request, output *CreateSpotDatafeedSubscriptionOutput) { op := &request.Operation{ Name: opCreateSpotDatafeedSubscription, @@ -4377,7 +4726,7 @@ func (c *EC2) CreateSpotDatafeedSubscriptionRequest(input *CreateSpotDatafeedSub // CreateSpotDatafeedSubscription API operation for Amazon Elastic Compute Cloud. // -// Creates a data feed for Spot instances, enabling you to view Spot instance +// Creates a data feed for Spot Instances, enabling you to view Spot Instance // usage logs. You can create one data feed per AWS account. For more information, // see Spot Instance Data Feed (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-data-feeds.html) // in the Amazon Elastic Compute Cloud User Guide. @@ -4388,7 +4737,7 @@ func (c *EC2) CreateSpotDatafeedSubscriptionRequest(input *CreateSpotDatafeedSub // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateSpotDatafeedSubscription for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscription func (c *EC2) CreateSpotDatafeedSubscription(input *CreateSpotDatafeedSubscriptionInput) (*CreateSpotDatafeedSubscriptionOutput, error) { req, out := c.CreateSpotDatafeedSubscriptionRequest(input) return out, req.Send() @@ -4414,19 +4763,18 @@ const opCreateSubnet = "CreateSubnet" // CreateSubnetRequest generates a "aws/request.Request" representing the // client's request for the CreateSubnet operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateSubnet for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateSubnet method directly -// instead. +// See CreateSubnet for more information on using the CreateSubnet +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateSubnetRequest method. // req, resp := client.CreateSubnetRequest(params) @@ -4436,7 +4784,7 @@ const opCreateSubnet = "CreateSubnet" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnet func (c *EC2) CreateSubnetRequest(input *CreateSubnetInput) (req *request.Request, output *CreateSubnetOutput) { op := &request.Operation{ Name: opCreateSubnet, @@ -4457,14 +4805,13 @@ func (c *EC2) CreateSubnetRequest(input *CreateSubnetInput) (req *request.Reques // // Creates a subnet in an existing VPC. // -// When you create each subnet, you provide the VPC ID and the CIDR block you -// want for the subnet. After you create a subnet, you can't change its CIDR -// block. The subnet's IPv4 CIDR block can be the same as the VPC's IPv4 CIDR -// block (assuming you want only a single subnet in the VPC), or a subset of -// the VPC's IPv4 CIDR block. If you create more than one subnet in a VPC, the -// subnets' CIDR blocks must not overlap. The smallest IPv4 subnet (and VPC) -// you can create uses a /28 netmask (16 IPv4 addresses), and the largest uses -// a /16 netmask (65,536 IPv4 addresses). +// When you create each subnet, you provide the VPC ID and the IPv4 CIDR block +// you want for the subnet. After you create a subnet, you can't change its +// CIDR block. The size of the subnet's IPv4 CIDR block can be the same as a +// VPC's IPv4 CIDR block, or a subset of a VPC's IPv4 CIDR block. If you create +// more than one subnet in a VPC, the subnets' CIDR blocks must not overlap. +// The smallest IPv4 subnet (and VPC) you can create uses a /28 netmask (16 +// IPv4 addresses), and the largest uses a /16 netmask (65,536 IPv4 addresses). // // If you've associated an IPv6 CIDR block with your VPC, you can create a subnet // with an IPv6 CIDR block that uses a /64 prefix length. @@ -4490,7 +4837,7 @@ func (c *EC2) CreateSubnetRequest(input *CreateSubnetInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateSubnet for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnet func (c *EC2) CreateSubnet(input *CreateSubnetInput) (*CreateSubnetOutput, error) { req, out := c.CreateSubnetRequest(input) return out, req.Send() @@ -4516,19 +4863,18 @@ const opCreateTags = "CreateTags" // CreateTagsRequest generates a "aws/request.Request" representing the // client's request for the CreateTags operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateTags for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateTags method directly -// instead. +// See CreateTags for more information on using the CreateTags +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateTagsRequest method. // req, resp := client.CreateTagsRequest(params) @@ -4538,7 +4884,7 @@ const opCreateTags = "CreateTags" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTags +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTags func (c *EC2) CreateTagsRequest(input *CreateTagsInput) (req *request.Request, output *CreateTagsOutput) { op := &request.Operation{ Name: opCreateTags, @@ -4575,7 +4921,7 @@ func (c *EC2) CreateTagsRequest(input *CreateTagsInput) (req *request.Request, o // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateTags for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTags +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTags func (c *EC2) CreateTags(input *CreateTagsInput) (*CreateTagsOutput, error) { req, out := c.CreateTagsRequest(input) return out, req.Send() @@ -4601,19 +4947,18 @@ const opCreateVolume = "CreateVolume" // CreateVolumeRequest generates a "aws/request.Request" representing the // client's request for the CreateVolume operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVolume for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVolume method directly -// instead. +// See CreateVolume for more information on using the CreateVolume +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVolumeRequest method. // req, resp := client.CreateVolumeRequest(params) @@ -4623,7 +4968,7 @@ const opCreateVolume = "CreateVolume" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolume func (c *EC2) CreateVolumeRequest(input *CreateVolumeInput) (req *request.Request, output *Volume) { op := &request.Operation{ Name: opCreateVolume, @@ -4668,7 +5013,7 @@ func (c *EC2) CreateVolumeRequest(input *CreateVolumeInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVolume for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolume func (c *EC2) CreateVolume(input *CreateVolumeInput) (*Volume, error) { req, out := c.CreateVolumeRequest(input) return out, req.Send() @@ -4694,19 +5039,18 @@ const opCreateVpc = "CreateVpc" // CreateVpcRequest generates a "aws/request.Request" representing the // client's request for the CreateVpc operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVpc for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVpc method directly -// instead. +// See CreateVpc for more information on using the CreateVpc +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVpcRequest method. // req, resp := client.CreateVpcRequest(params) @@ -4716,7 +5060,7 @@ const opCreateVpc = "CreateVpc" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpc func (c *EC2) CreateVpcRequest(input *CreateVpcInput) (req *request.Request, output *CreateVpcOutput) { op := &request.Operation{ Name: opCreateVpc, @@ -4761,7 +5105,7 @@ func (c *EC2) CreateVpcRequest(input *CreateVpcInput) (req *request.Request, out // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVpc for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpc func (c *EC2) CreateVpc(input *CreateVpcInput) (*CreateVpcOutput, error) { req, out := c.CreateVpcRequest(input) return out, req.Send() @@ -4787,19 +5131,18 @@ const opCreateVpcEndpoint = "CreateVpcEndpoint" // CreateVpcEndpointRequest generates a "aws/request.Request" representing the // client's request for the CreateVpcEndpoint operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVpcEndpoint for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVpcEndpoint method directly -// instead. +// See CreateVpcEndpoint for more information on using the CreateVpcEndpoint +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVpcEndpointRequest method. // req, resp := client.CreateVpcEndpointRequest(params) @@ -4809,7 +5152,7 @@ const opCreateVpcEndpoint = "CreateVpcEndpoint" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpoint +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpoint func (c *EC2) CreateVpcEndpointRequest(input *CreateVpcEndpointInput) (req *request.Request, output *CreateVpcEndpointOutput) { op := &request.Operation{ Name: opCreateVpcEndpoint, @@ -4828,13 +5171,23 @@ func (c *EC2) CreateVpcEndpointRequest(input *CreateVpcEndpointInput) (req *requ // CreateVpcEndpoint API operation for Amazon Elastic Compute Cloud. // -// Creates a VPC endpoint for a specified AWS service. An endpoint enables you -// to create a private connection between your VPC and another AWS service in -// your account. You can specify an endpoint policy to attach to the endpoint -// that will control access to the service from your VPC. You can also specify -// the VPC route tables that use the endpoint. +// Creates a VPC endpoint for a specified service. An endpoint enables you to +// create a private connection between your VPC and the service. The service +// may be provided by AWS, an AWS Marketplace partner, or another AWS account. +// For more information, see VPC Endpoints (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-endpoints.html) +// in the Amazon Virtual Private Cloud User Guide. // -// Use DescribeVpcEndpointServices to get a list of supported AWS services. +// A gateway endpoint serves as a target for a route in your route table for +// traffic destined for the AWS service. You can specify an endpoint policy +// to attach to the endpoint that will control access to the service from your +// VPC. You can also specify the VPC route tables that use the endpoint. +// +// An interface endpoint is a network interface in your subnet that serves as +// an endpoint for communicating with the specified service. You can specify +// the subnets in which to create an endpoint, and the security groups to associate +// with the endpoint network interface. +// +// Use DescribeVpcEndpointServices to get a list of supported services. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -4842,7 +5195,7 @@ func (c *EC2) CreateVpcEndpointRequest(input *CreateVpcEndpointInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVpcEndpoint for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpoint +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpoint func (c *EC2) CreateVpcEndpoint(input *CreateVpcEndpointInput) (*CreateVpcEndpointOutput, error) { req, out := c.CreateVpcEndpointRequest(input) return out, req.Send() @@ -4864,23 +5217,183 @@ func (c *EC2) CreateVpcEndpointWithContext(ctx aws.Context, input *CreateVpcEndp return out, req.Send() } +const opCreateVpcEndpointConnectionNotification = "CreateVpcEndpointConnectionNotification" + +// CreateVpcEndpointConnectionNotificationRequest generates a "aws/request.Request" representing the +// client's request for the CreateVpcEndpointConnectionNotification operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See CreateVpcEndpointConnectionNotification for more information on using the CreateVpcEndpointConnectionNotification +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the CreateVpcEndpointConnectionNotificationRequest method. +// req, resp := client.CreateVpcEndpointConnectionNotificationRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointConnectionNotification +func (c *EC2) CreateVpcEndpointConnectionNotificationRequest(input *CreateVpcEndpointConnectionNotificationInput) (req *request.Request, output *CreateVpcEndpointConnectionNotificationOutput) { + op := &request.Operation{ + Name: opCreateVpcEndpointConnectionNotification, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CreateVpcEndpointConnectionNotificationInput{} + } + + output = &CreateVpcEndpointConnectionNotificationOutput{} + req = c.newRequest(op, input, output) + return +} + +// CreateVpcEndpointConnectionNotification API operation for Amazon Elastic Compute Cloud. +// +// Creates a connection notification for a specified VPC endpoint or VPC endpoint +// service. A connection notification notifies you of specific endpoint events. +// You must create an SNS topic to receive notifications. For more information, +// see Create a Topic (http://docs.aws.amazon.com/sns/latest/dg/CreateTopic.html) +// in the Amazon Simple Notification Service Developer Guide. +// +// You can create a connection notification for interface endpoints only. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation CreateVpcEndpointConnectionNotification for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointConnectionNotification +func (c *EC2) CreateVpcEndpointConnectionNotification(input *CreateVpcEndpointConnectionNotificationInput) (*CreateVpcEndpointConnectionNotificationOutput, error) { + req, out := c.CreateVpcEndpointConnectionNotificationRequest(input) + return out, req.Send() +} + +// CreateVpcEndpointConnectionNotificationWithContext is the same as CreateVpcEndpointConnectionNotification with the addition of +// the ability to pass a context and additional request options. +// +// See CreateVpcEndpointConnectionNotification for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) CreateVpcEndpointConnectionNotificationWithContext(ctx aws.Context, input *CreateVpcEndpointConnectionNotificationInput, opts ...request.Option) (*CreateVpcEndpointConnectionNotificationOutput, error) { + req, out := c.CreateVpcEndpointConnectionNotificationRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opCreateVpcEndpointServiceConfiguration = "CreateVpcEndpointServiceConfiguration" + +// CreateVpcEndpointServiceConfigurationRequest generates a "aws/request.Request" representing the +// client's request for the CreateVpcEndpointServiceConfiguration operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See CreateVpcEndpointServiceConfiguration for more information on using the CreateVpcEndpointServiceConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the CreateVpcEndpointServiceConfigurationRequest method. +// req, resp := client.CreateVpcEndpointServiceConfigurationRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointServiceConfiguration +func (c *EC2) CreateVpcEndpointServiceConfigurationRequest(input *CreateVpcEndpointServiceConfigurationInput) (req *request.Request, output *CreateVpcEndpointServiceConfigurationOutput) { + op := &request.Operation{ + Name: opCreateVpcEndpointServiceConfiguration, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &CreateVpcEndpointServiceConfigurationInput{} + } + + output = &CreateVpcEndpointServiceConfigurationOutput{} + req = c.newRequest(op, input, output) + return +} + +// CreateVpcEndpointServiceConfiguration API operation for Amazon Elastic Compute Cloud. +// +// Creates a VPC endpoint service configuration to which service consumers (AWS +// accounts, IAM users, and IAM roles) can connect. Service consumers can create +// an interface VPC endpoint to connect to your service. +// +// To create an endpoint service configuration, you must first create a Network +// Load Balancer for your service. For more information, see VPC Endpoint Services +// (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/endpoint-service.html) +// in the Amazon Virtual Private Cloud User Guide. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation CreateVpcEndpointServiceConfiguration for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointServiceConfiguration +func (c *EC2) CreateVpcEndpointServiceConfiguration(input *CreateVpcEndpointServiceConfigurationInput) (*CreateVpcEndpointServiceConfigurationOutput, error) { + req, out := c.CreateVpcEndpointServiceConfigurationRequest(input) + return out, req.Send() +} + +// CreateVpcEndpointServiceConfigurationWithContext is the same as CreateVpcEndpointServiceConfiguration with the addition of +// the ability to pass a context and additional request options. +// +// See CreateVpcEndpointServiceConfiguration for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) CreateVpcEndpointServiceConfigurationWithContext(ctx aws.Context, input *CreateVpcEndpointServiceConfigurationInput, opts ...request.Option) (*CreateVpcEndpointServiceConfigurationOutput, error) { + req, out := c.CreateVpcEndpointServiceConfigurationRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opCreateVpcPeeringConnection = "CreateVpcPeeringConnection" // CreateVpcPeeringConnectionRequest generates a "aws/request.Request" representing the // client's request for the CreateVpcPeeringConnection operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVpcPeeringConnection for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVpcPeeringConnection method directly -// instead. +// See CreateVpcPeeringConnection for more information on using the CreateVpcPeeringConnection +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVpcPeeringConnectionRequest method. // req, resp := client.CreateVpcPeeringConnectionRequest(params) @@ -4890,7 +5403,7 @@ const opCreateVpcPeeringConnection = "CreateVpcPeeringConnection" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnection func (c *EC2) CreateVpcPeeringConnectionRequest(input *CreateVpcPeeringConnectionInput) (req *request.Request, output *CreateVpcPeeringConnectionOutput) { op := &request.Operation{ Name: opCreateVpcPeeringConnection, @@ -4910,16 +5423,21 @@ func (c *EC2) CreateVpcPeeringConnectionRequest(input *CreateVpcPeeringConnectio // CreateVpcPeeringConnection API operation for Amazon Elastic Compute Cloud. // // Requests a VPC peering connection between two VPCs: a requester VPC that -// you own and a peer VPC with which to create the connection. The peer VPC -// can belong to another AWS account. The requester VPC and peer VPC cannot -// have overlapping CIDR blocks. +// you own and an accepter VPC with which to create the connection. The accepter +// VPC can belong to another AWS account and can be in a different region to +// the requester VPC. The requester VPC and accepter VPC cannot have overlapping +// CIDR blocks. // -// The owner of the peer VPC must accept the peering request to activate the -// peering connection. The VPC peering connection request expires after 7 days, -// after which it cannot be accepted or rejected. +// Limitations and rules apply to a VPC peering connection. For more information, +// see the limitations (http://docs.aws.amazon.com/AmazonVPC/latest/PeeringGuide/vpc-peering-basics.html#vpc-peering-limitations) +// section in the VPC Peering Guide. // -// If you try to create a VPC peering connection between VPCs that have overlapping -// CIDR blocks, the VPC peering connection status goes to failed. +// The owner of the accepter VPC must accept the peering request to activate +// the peering connection. The VPC peering connection request expires after +// 7 days, after which it cannot be accepted or rejected. +// +// If you create a VPC peering connection request between VPCs with overlapping +// CIDR blocks, the VPC peering connection has a status of failed. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -4927,7 +5445,7 @@ func (c *EC2) CreateVpcPeeringConnectionRequest(input *CreateVpcPeeringConnectio // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVpcPeeringConnection for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnection func (c *EC2) CreateVpcPeeringConnection(input *CreateVpcPeeringConnectionInput) (*CreateVpcPeeringConnectionOutput, error) { req, out := c.CreateVpcPeeringConnectionRequest(input) return out, req.Send() @@ -4953,19 +5471,18 @@ const opCreateVpnConnection = "CreateVpnConnection" // CreateVpnConnectionRequest generates a "aws/request.Request" representing the // client's request for the CreateVpnConnection operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVpnConnection for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVpnConnection method directly -// instead. +// See CreateVpnConnection for more information on using the CreateVpnConnection +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVpnConnectionRequest method. // req, resp := client.CreateVpnConnectionRequest(params) @@ -4975,7 +5492,7 @@ const opCreateVpnConnection = "CreateVpnConnection" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnection func (c *EC2) CreateVpnConnectionRequest(input *CreateVpnConnectionInput) (req *request.Request, output *CreateVpnConnectionOutput) { op := &request.Operation{ Name: opCreateVpnConnection, @@ -5011,8 +5528,7 @@ func (c *EC2) CreateVpnConnectionRequest(input *CreateVpnConnectionInput) (req * // This is an idempotent operation. If you perform the operation more than once, // Amazon EC2 doesn't return an error. // -// For more information about VPN connections, see Adding a Hardware Virtual -// Private Gateway to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) +// For more information, see AWS Managed VPN Connections (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) // in the Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -5021,7 +5537,7 @@ func (c *EC2) CreateVpnConnectionRequest(input *CreateVpnConnectionInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVpnConnection for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnection func (c *EC2) CreateVpnConnection(input *CreateVpnConnectionInput) (*CreateVpnConnectionOutput, error) { req, out := c.CreateVpnConnectionRequest(input) return out, req.Send() @@ -5047,19 +5563,18 @@ const opCreateVpnConnectionRoute = "CreateVpnConnectionRoute" // CreateVpnConnectionRouteRequest generates a "aws/request.Request" representing the // client's request for the CreateVpnConnectionRoute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVpnConnectionRoute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVpnConnectionRoute method directly -// instead. +// See CreateVpnConnectionRoute for more information on using the CreateVpnConnectionRoute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVpnConnectionRouteRequest method. // req, resp := client.CreateVpnConnectionRouteRequest(params) @@ -5069,7 +5584,7 @@ const opCreateVpnConnectionRoute = "CreateVpnConnectionRoute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRoute func (c *EC2) CreateVpnConnectionRouteRequest(input *CreateVpnConnectionRouteInput) (req *request.Request, output *CreateVpnConnectionRouteOutput) { op := &request.Operation{ Name: opCreateVpnConnectionRoute, @@ -5095,9 +5610,9 @@ func (c *EC2) CreateVpnConnectionRouteRequest(input *CreateVpnConnectionRouteInp // traffic to be routed from the virtual private gateway to the VPN customer // gateway. // -// For more information about VPN connections, see Adding a Hardware Virtual -// Private Gateway to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) -// in the Amazon Virtual Private Cloud User Guide. +// For more information about VPN connections, see AWS Managed VPN Connections +// (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) in the +// Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -5105,7 +5620,7 @@ func (c *EC2) CreateVpnConnectionRouteRequest(input *CreateVpnConnectionRouteInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVpnConnectionRoute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRoute func (c *EC2) CreateVpnConnectionRoute(input *CreateVpnConnectionRouteInput) (*CreateVpnConnectionRouteOutput, error) { req, out := c.CreateVpnConnectionRouteRequest(input) return out, req.Send() @@ -5131,19 +5646,18 @@ const opCreateVpnGateway = "CreateVpnGateway" // CreateVpnGatewayRequest generates a "aws/request.Request" representing the // client's request for the CreateVpnGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateVpnGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateVpnGateway method directly -// instead. +// See CreateVpnGateway for more information on using the CreateVpnGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateVpnGatewayRequest method. // req, resp := client.CreateVpnGatewayRequest(params) @@ -5153,7 +5667,7 @@ const opCreateVpnGateway = "CreateVpnGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGateway func (c *EC2) CreateVpnGatewayRequest(input *CreateVpnGatewayInput) (req *request.Request, output *CreateVpnGatewayOutput) { op := &request.Operation{ Name: opCreateVpnGateway, @@ -5176,8 +5690,8 @@ func (c *EC2) CreateVpnGatewayRequest(input *CreateVpnGatewayInput) (req *reques // on the VPC side of your VPN connection. You can create a virtual private // gateway before creating the VPC itself. // -// For more information about virtual private gateways, see Adding a Hardware -// Virtual Private Gateway to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) +// For more information about virtual private gateways, see AWS Managed VPN +// Connections (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) // in the Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -5186,7 +5700,7 @@ func (c *EC2) CreateVpnGatewayRequest(input *CreateVpnGatewayInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation CreateVpnGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGateway func (c *EC2) CreateVpnGateway(input *CreateVpnGatewayInput) (*CreateVpnGatewayOutput, error) { req, out := c.CreateVpnGatewayRequest(input) return out, req.Send() @@ -5212,19 +5726,18 @@ const opDeleteCustomerGateway = "DeleteCustomerGateway" // DeleteCustomerGatewayRequest generates a "aws/request.Request" representing the // client's request for the DeleteCustomerGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteCustomerGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteCustomerGateway method directly -// instead. +// See DeleteCustomerGateway for more information on using the DeleteCustomerGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteCustomerGatewayRequest method. // req, resp := client.DeleteCustomerGatewayRequest(params) @@ -5234,7 +5747,7 @@ const opDeleteCustomerGateway = "DeleteCustomerGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGateway func (c *EC2) DeleteCustomerGatewayRequest(input *DeleteCustomerGatewayInput) (req *request.Request, output *DeleteCustomerGatewayOutput) { op := &request.Operation{ Name: opDeleteCustomerGateway, @@ -5264,7 +5777,7 @@ func (c *EC2) DeleteCustomerGatewayRequest(input *DeleteCustomerGatewayInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteCustomerGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGateway func (c *EC2) DeleteCustomerGateway(input *DeleteCustomerGatewayInput) (*DeleteCustomerGatewayOutput, error) { req, out := c.DeleteCustomerGatewayRequest(input) return out, req.Send() @@ -5290,19 +5803,18 @@ const opDeleteDhcpOptions = "DeleteDhcpOptions" // DeleteDhcpOptionsRequest generates a "aws/request.Request" representing the // client's request for the DeleteDhcpOptions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteDhcpOptions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteDhcpOptions method directly -// instead. +// See DeleteDhcpOptions for more information on using the DeleteDhcpOptions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteDhcpOptionsRequest method. // req, resp := client.DeleteDhcpOptionsRequest(params) @@ -5312,7 +5824,7 @@ const opDeleteDhcpOptions = "DeleteDhcpOptions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptions func (c *EC2) DeleteDhcpOptionsRequest(input *DeleteDhcpOptionsInput) (req *request.Request, output *DeleteDhcpOptionsOutput) { op := &request.Operation{ Name: opDeleteDhcpOptions, @@ -5344,7 +5856,7 @@ func (c *EC2) DeleteDhcpOptionsRequest(input *DeleteDhcpOptionsInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteDhcpOptions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptions func (c *EC2) DeleteDhcpOptions(input *DeleteDhcpOptionsInput) (*DeleteDhcpOptionsOutput, error) { req, out := c.DeleteDhcpOptionsRequest(input) return out, req.Send() @@ -5370,19 +5882,18 @@ const opDeleteEgressOnlyInternetGateway = "DeleteEgressOnlyInternetGateway" // DeleteEgressOnlyInternetGatewayRequest generates a "aws/request.Request" representing the // client's request for the DeleteEgressOnlyInternetGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteEgressOnlyInternetGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteEgressOnlyInternetGateway method directly -// instead. +// See DeleteEgressOnlyInternetGateway for more information on using the DeleteEgressOnlyInternetGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteEgressOnlyInternetGatewayRequest method. // req, resp := client.DeleteEgressOnlyInternetGatewayRequest(params) @@ -5392,7 +5903,7 @@ const opDeleteEgressOnlyInternetGateway = "DeleteEgressOnlyInternetGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGateway func (c *EC2) DeleteEgressOnlyInternetGatewayRequest(input *DeleteEgressOnlyInternetGatewayInput) (req *request.Request, output *DeleteEgressOnlyInternetGatewayOutput) { op := &request.Operation{ Name: opDeleteEgressOnlyInternetGateway, @@ -5419,7 +5930,7 @@ func (c *EC2) DeleteEgressOnlyInternetGatewayRequest(input *DeleteEgressOnlyInte // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteEgressOnlyInternetGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGateway func (c *EC2) DeleteEgressOnlyInternetGateway(input *DeleteEgressOnlyInternetGatewayInput) (*DeleteEgressOnlyInternetGatewayOutput, error) { req, out := c.DeleteEgressOnlyInternetGatewayRequest(input) return out, req.Send() @@ -5445,19 +5956,18 @@ const opDeleteFlowLogs = "DeleteFlowLogs" // DeleteFlowLogsRequest generates a "aws/request.Request" representing the // client's request for the DeleteFlowLogs operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteFlowLogs for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteFlowLogs method directly -// instead. +// See DeleteFlowLogs for more information on using the DeleteFlowLogs +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteFlowLogsRequest method. // req, resp := client.DeleteFlowLogsRequest(params) @@ -5467,7 +5977,7 @@ const opDeleteFlowLogs = "DeleteFlowLogs" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogs func (c *EC2) DeleteFlowLogsRequest(input *DeleteFlowLogsInput) (req *request.Request, output *DeleteFlowLogsOutput) { op := &request.Operation{ Name: opDeleteFlowLogs, @@ -5494,7 +6004,7 @@ func (c *EC2) DeleteFlowLogsRequest(input *DeleteFlowLogsInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteFlowLogs for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogs func (c *EC2) DeleteFlowLogs(input *DeleteFlowLogsInput) (*DeleteFlowLogsOutput, error) { req, out := c.DeleteFlowLogsRequest(input) return out, req.Send() @@ -5516,23 +6026,96 @@ func (c *EC2) DeleteFlowLogsWithContext(ctx aws.Context, input *DeleteFlowLogsIn return out, req.Send() } +const opDeleteFpgaImage = "DeleteFpgaImage" + +// DeleteFpgaImageRequest generates a "aws/request.Request" representing the +// client's request for the DeleteFpgaImage operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DeleteFpgaImage for more information on using the DeleteFpgaImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DeleteFpgaImageRequest method. +// req, resp := client.DeleteFpgaImageRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFpgaImage +func (c *EC2) DeleteFpgaImageRequest(input *DeleteFpgaImageInput) (req *request.Request, output *DeleteFpgaImageOutput) { + op := &request.Operation{ + Name: opDeleteFpgaImage, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteFpgaImageInput{} + } + + output = &DeleteFpgaImageOutput{} + req = c.newRequest(op, input, output) + return +} + +// DeleteFpgaImage API operation for Amazon Elastic Compute Cloud. +// +// Deletes the specified Amazon FPGA Image (AFI). +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DeleteFpgaImage for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFpgaImage +func (c *EC2) DeleteFpgaImage(input *DeleteFpgaImageInput) (*DeleteFpgaImageOutput, error) { + req, out := c.DeleteFpgaImageRequest(input) + return out, req.Send() +} + +// DeleteFpgaImageWithContext is the same as DeleteFpgaImage with the addition of +// the ability to pass a context and additional request options. +// +// See DeleteFpgaImage for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DeleteFpgaImageWithContext(ctx aws.Context, input *DeleteFpgaImageInput, opts ...request.Option) (*DeleteFpgaImageOutput, error) { + req, out := c.DeleteFpgaImageRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDeleteInternetGateway = "DeleteInternetGateway" // DeleteInternetGatewayRequest generates a "aws/request.Request" representing the // client's request for the DeleteInternetGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteInternetGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteInternetGateway method directly -// instead. +// See DeleteInternetGateway for more information on using the DeleteInternetGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteInternetGatewayRequest method. // req, resp := client.DeleteInternetGatewayRequest(params) @@ -5542,7 +6125,7 @@ const opDeleteInternetGateway = "DeleteInternetGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGateway func (c *EC2) DeleteInternetGatewayRequest(input *DeleteInternetGatewayInput) (req *request.Request, output *DeleteInternetGatewayOutput) { op := &request.Operation{ Name: opDeleteInternetGateway, @@ -5572,7 +6155,7 @@ func (c *EC2) DeleteInternetGatewayRequest(input *DeleteInternetGatewayInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteInternetGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGateway func (c *EC2) DeleteInternetGateway(input *DeleteInternetGatewayInput) (*DeleteInternetGatewayOutput, error) { req, out := c.DeleteInternetGatewayRequest(input) return out, req.Send() @@ -5598,19 +6181,18 @@ const opDeleteKeyPair = "DeleteKeyPair" // DeleteKeyPairRequest generates a "aws/request.Request" representing the // client's request for the DeleteKeyPair operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteKeyPair for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteKeyPair method directly -// instead. +// See DeleteKeyPair for more information on using the DeleteKeyPair +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteKeyPairRequest method. // req, resp := client.DeleteKeyPairRequest(params) @@ -5620,7 +6202,7 @@ const opDeleteKeyPair = "DeleteKeyPair" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPair func (c *EC2) DeleteKeyPairRequest(input *DeleteKeyPairInput) (req *request.Request, output *DeleteKeyPairOutput) { op := &request.Operation{ Name: opDeleteKeyPair, @@ -5649,7 +6231,7 @@ func (c *EC2) DeleteKeyPairRequest(input *DeleteKeyPairInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteKeyPair for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPair func (c *EC2) DeleteKeyPair(input *DeleteKeyPairInput) (*DeleteKeyPairOutput, error) { req, out := c.DeleteKeyPairRequest(input) return out, req.Send() @@ -5671,23 +6253,174 @@ func (c *EC2) DeleteKeyPairWithContext(ctx aws.Context, input *DeleteKeyPairInpu return out, req.Send() } +const opDeleteLaunchTemplate = "DeleteLaunchTemplate" + +// DeleteLaunchTemplateRequest generates a "aws/request.Request" representing the +// client's request for the DeleteLaunchTemplate operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DeleteLaunchTemplate for more information on using the DeleteLaunchTemplate +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DeleteLaunchTemplateRequest method. +// req, resp := client.DeleteLaunchTemplateRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplate +func (c *EC2) DeleteLaunchTemplateRequest(input *DeleteLaunchTemplateInput) (req *request.Request, output *DeleteLaunchTemplateOutput) { + op := &request.Operation{ + Name: opDeleteLaunchTemplate, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteLaunchTemplateInput{} + } + + output = &DeleteLaunchTemplateOutput{} + req = c.newRequest(op, input, output) + return +} + +// DeleteLaunchTemplate API operation for Amazon Elastic Compute Cloud. +// +// Deletes a launch template. Deleting a launch template deletes all of its +// versions. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DeleteLaunchTemplate for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplate +func (c *EC2) DeleteLaunchTemplate(input *DeleteLaunchTemplateInput) (*DeleteLaunchTemplateOutput, error) { + req, out := c.DeleteLaunchTemplateRequest(input) + return out, req.Send() +} + +// DeleteLaunchTemplateWithContext is the same as DeleteLaunchTemplate with the addition of +// the ability to pass a context and additional request options. +// +// See DeleteLaunchTemplate for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DeleteLaunchTemplateWithContext(ctx aws.Context, input *DeleteLaunchTemplateInput, opts ...request.Option) (*DeleteLaunchTemplateOutput, error) { + req, out := c.DeleteLaunchTemplateRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opDeleteLaunchTemplateVersions = "DeleteLaunchTemplateVersions" + +// DeleteLaunchTemplateVersionsRequest generates a "aws/request.Request" representing the +// client's request for the DeleteLaunchTemplateVersions operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DeleteLaunchTemplateVersions for more information on using the DeleteLaunchTemplateVersions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DeleteLaunchTemplateVersionsRequest method. +// req, resp := client.DeleteLaunchTemplateVersionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateVersions +func (c *EC2) DeleteLaunchTemplateVersionsRequest(input *DeleteLaunchTemplateVersionsInput) (req *request.Request, output *DeleteLaunchTemplateVersionsOutput) { + op := &request.Operation{ + Name: opDeleteLaunchTemplateVersions, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteLaunchTemplateVersionsInput{} + } + + output = &DeleteLaunchTemplateVersionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DeleteLaunchTemplateVersions API operation for Amazon Elastic Compute Cloud. +// +// Deletes one or more versions of a launch template. You cannot delete the +// default version of a launch template; you must first assign a different version +// as the default. If the default version is the only version for the launch +// template, you must delete the entire launch template using DeleteLaunchTemplate. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DeleteLaunchTemplateVersions for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateVersions +func (c *EC2) DeleteLaunchTemplateVersions(input *DeleteLaunchTemplateVersionsInput) (*DeleteLaunchTemplateVersionsOutput, error) { + req, out := c.DeleteLaunchTemplateVersionsRequest(input) + return out, req.Send() +} + +// DeleteLaunchTemplateVersionsWithContext is the same as DeleteLaunchTemplateVersions with the addition of +// the ability to pass a context and additional request options. +// +// See DeleteLaunchTemplateVersions for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DeleteLaunchTemplateVersionsWithContext(ctx aws.Context, input *DeleteLaunchTemplateVersionsInput, opts ...request.Option) (*DeleteLaunchTemplateVersionsOutput, error) { + req, out := c.DeleteLaunchTemplateVersionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDeleteNatGateway = "DeleteNatGateway" // DeleteNatGatewayRequest generates a "aws/request.Request" representing the // client's request for the DeleteNatGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteNatGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteNatGateway method directly -// instead. +// See DeleteNatGateway for more information on using the DeleteNatGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteNatGatewayRequest method. // req, resp := client.DeleteNatGatewayRequest(params) @@ -5697,7 +6430,7 @@ const opDeleteNatGateway = "DeleteNatGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGateway func (c *EC2) DeleteNatGatewayRequest(input *DeleteNatGatewayInput) (req *request.Request, output *DeleteNatGatewayOutput) { op := &request.Operation{ Name: opDeleteNatGateway, @@ -5726,7 +6459,7 @@ func (c *EC2) DeleteNatGatewayRequest(input *DeleteNatGatewayInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteNatGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGateway func (c *EC2) DeleteNatGateway(input *DeleteNatGatewayInput) (*DeleteNatGatewayOutput, error) { req, out := c.DeleteNatGatewayRequest(input) return out, req.Send() @@ -5752,19 +6485,18 @@ const opDeleteNetworkAcl = "DeleteNetworkAcl" // DeleteNetworkAclRequest generates a "aws/request.Request" representing the // client's request for the DeleteNetworkAcl operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteNetworkAcl for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteNetworkAcl method directly -// instead. +// See DeleteNetworkAcl for more information on using the DeleteNetworkAcl +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteNetworkAclRequest method. // req, resp := client.DeleteNetworkAclRequest(params) @@ -5774,7 +6506,7 @@ const opDeleteNetworkAcl = "DeleteNetworkAcl" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAcl func (c *EC2) DeleteNetworkAclRequest(input *DeleteNetworkAclInput) (req *request.Request, output *DeleteNetworkAclOutput) { op := &request.Operation{ Name: opDeleteNetworkAcl, @@ -5804,7 +6536,7 @@ func (c *EC2) DeleteNetworkAclRequest(input *DeleteNetworkAclInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteNetworkAcl for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAcl func (c *EC2) DeleteNetworkAcl(input *DeleteNetworkAclInput) (*DeleteNetworkAclOutput, error) { req, out := c.DeleteNetworkAclRequest(input) return out, req.Send() @@ -5830,19 +6562,18 @@ const opDeleteNetworkAclEntry = "DeleteNetworkAclEntry" // DeleteNetworkAclEntryRequest generates a "aws/request.Request" representing the // client's request for the DeleteNetworkAclEntry operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteNetworkAclEntry for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteNetworkAclEntry method directly -// instead. +// See DeleteNetworkAclEntry for more information on using the DeleteNetworkAclEntry +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteNetworkAclEntryRequest method. // req, resp := client.DeleteNetworkAclEntryRequest(params) @@ -5852,7 +6583,7 @@ const opDeleteNetworkAclEntry = "DeleteNetworkAclEntry" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntry func (c *EC2) DeleteNetworkAclEntryRequest(input *DeleteNetworkAclEntryInput) (req *request.Request, output *DeleteNetworkAclEntryOutput) { op := &request.Operation{ Name: opDeleteNetworkAclEntry, @@ -5882,7 +6613,7 @@ func (c *EC2) DeleteNetworkAclEntryRequest(input *DeleteNetworkAclEntryInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteNetworkAclEntry for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntry func (c *EC2) DeleteNetworkAclEntry(input *DeleteNetworkAclEntryInput) (*DeleteNetworkAclEntryOutput, error) { req, out := c.DeleteNetworkAclEntryRequest(input) return out, req.Send() @@ -5908,19 +6639,18 @@ const opDeleteNetworkInterface = "DeleteNetworkInterface" // DeleteNetworkInterfaceRequest generates a "aws/request.Request" representing the // client's request for the DeleteNetworkInterface operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteNetworkInterface for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteNetworkInterface method directly -// instead. +// See DeleteNetworkInterface for more information on using the DeleteNetworkInterface +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteNetworkInterfaceRequest method. // req, resp := client.DeleteNetworkInterfaceRequest(params) @@ -5930,7 +6660,7 @@ const opDeleteNetworkInterface = "DeleteNetworkInterface" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterface func (c *EC2) DeleteNetworkInterfaceRequest(input *DeleteNetworkInterfaceInput) (req *request.Request, output *DeleteNetworkInterfaceOutput) { op := &request.Operation{ Name: opDeleteNetworkInterface, @@ -5960,7 +6690,7 @@ func (c *EC2) DeleteNetworkInterfaceRequest(input *DeleteNetworkInterfaceInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteNetworkInterface for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterface func (c *EC2) DeleteNetworkInterface(input *DeleteNetworkInterfaceInput) (*DeleteNetworkInterfaceOutput, error) { req, out := c.DeleteNetworkInterfaceRequest(input) return out, req.Send() @@ -5986,19 +6716,18 @@ const opDeleteNetworkInterfacePermission = "DeleteNetworkInterfacePermission" // DeleteNetworkInterfacePermissionRequest generates a "aws/request.Request" representing the // client's request for the DeleteNetworkInterfacePermission operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteNetworkInterfacePermission for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteNetworkInterfacePermission method directly -// instead. +// See DeleteNetworkInterfacePermission for more information on using the DeleteNetworkInterfacePermission +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteNetworkInterfacePermissionRequest method. // req, resp := client.DeleteNetworkInterfacePermissionRequest(params) @@ -6008,7 +6737,7 @@ const opDeleteNetworkInterfacePermission = "DeleteNetworkInterfacePermission" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermission func (c *EC2) DeleteNetworkInterfacePermissionRequest(input *DeleteNetworkInterfacePermissionInput) (req *request.Request, output *DeleteNetworkInterfacePermissionOutput) { op := &request.Operation{ Name: opDeleteNetworkInterfacePermission, @@ -6038,7 +6767,7 @@ func (c *EC2) DeleteNetworkInterfacePermissionRequest(input *DeleteNetworkInterf // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteNetworkInterfacePermission for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermission func (c *EC2) DeleteNetworkInterfacePermission(input *DeleteNetworkInterfacePermissionInput) (*DeleteNetworkInterfacePermissionOutput, error) { req, out := c.DeleteNetworkInterfacePermissionRequest(input) return out, req.Send() @@ -6064,19 +6793,18 @@ const opDeletePlacementGroup = "DeletePlacementGroup" // DeletePlacementGroupRequest generates a "aws/request.Request" representing the // client's request for the DeletePlacementGroup operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeletePlacementGroup for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeletePlacementGroup method directly -// instead. +// See DeletePlacementGroup for more information on using the DeletePlacementGroup +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeletePlacementGroupRequest method. // req, resp := client.DeletePlacementGroupRequest(params) @@ -6086,7 +6814,7 @@ const opDeletePlacementGroup = "DeletePlacementGroup" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroup func (c *EC2) DeletePlacementGroupRequest(input *DeletePlacementGroupInput) (req *request.Request, output *DeletePlacementGroupOutput) { op := &request.Operation{ Name: opDeletePlacementGroup, @@ -6108,8 +6836,8 @@ func (c *EC2) DeletePlacementGroupRequest(input *DeletePlacementGroupInput) (req // DeletePlacementGroup API operation for Amazon Elastic Compute Cloud. // // Deletes the specified placement group. You must terminate all instances in -// the placement group before you can delete the placement group. For more information -// about placement groups and cluster instances, see Cluster Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using_cluster_computing.html) +// the placement group before you can delete the placement group. For more information, +// see Placement Groups (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -6118,7 +6846,7 @@ func (c *EC2) DeletePlacementGroupRequest(input *DeletePlacementGroupInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeletePlacementGroup for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroup func (c *EC2) DeletePlacementGroup(input *DeletePlacementGroupInput) (*DeletePlacementGroupOutput, error) { req, out := c.DeletePlacementGroupRequest(input) return out, req.Send() @@ -6144,19 +6872,18 @@ const opDeleteRoute = "DeleteRoute" // DeleteRouteRequest generates a "aws/request.Request" representing the // client's request for the DeleteRoute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteRoute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteRoute method directly -// instead. +// See DeleteRoute for more information on using the DeleteRoute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteRouteRequest method. // req, resp := client.DeleteRouteRequest(params) @@ -6166,7 +6893,7 @@ const opDeleteRoute = "DeleteRoute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRoute func (c *EC2) DeleteRouteRequest(input *DeleteRouteInput) (req *request.Request, output *DeleteRouteOutput) { op := &request.Operation{ Name: opDeleteRoute, @@ -6195,7 +6922,7 @@ func (c *EC2) DeleteRouteRequest(input *DeleteRouteInput) (req *request.Request, // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteRoute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRoute func (c *EC2) DeleteRoute(input *DeleteRouteInput) (*DeleteRouteOutput, error) { req, out := c.DeleteRouteRequest(input) return out, req.Send() @@ -6221,19 +6948,18 @@ const opDeleteRouteTable = "DeleteRouteTable" // DeleteRouteTableRequest generates a "aws/request.Request" representing the // client's request for the DeleteRouteTable operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteRouteTable for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteRouteTable method directly -// instead. +// See DeleteRouteTable for more information on using the DeleteRouteTable +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteRouteTableRequest method. // req, resp := client.DeleteRouteTableRequest(params) @@ -6243,7 +6969,7 @@ const opDeleteRouteTable = "DeleteRouteTable" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTable func (c *EC2) DeleteRouteTableRequest(input *DeleteRouteTableInput) (req *request.Request, output *DeleteRouteTableOutput) { op := &request.Operation{ Name: opDeleteRouteTable, @@ -6274,7 +7000,7 @@ func (c *EC2) DeleteRouteTableRequest(input *DeleteRouteTableInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteRouteTable for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTable func (c *EC2) DeleteRouteTable(input *DeleteRouteTableInput) (*DeleteRouteTableOutput, error) { req, out := c.DeleteRouteTableRequest(input) return out, req.Send() @@ -6300,19 +7026,18 @@ const opDeleteSecurityGroup = "DeleteSecurityGroup" // DeleteSecurityGroupRequest generates a "aws/request.Request" representing the // client's request for the DeleteSecurityGroup operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteSecurityGroup for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteSecurityGroup method directly -// instead. +// See DeleteSecurityGroup for more information on using the DeleteSecurityGroup +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteSecurityGroupRequest method. // req, resp := client.DeleteSecurityGroupRequest(params) @@ -6322,7 +7047,7 @@ const opDeleteSecurityGroup = "DeleteSecurityGroup" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroup func (c *EC2) DeleteSecurityGroupRequest(input *DeleteSecurityGroupInput) (req *request.Request, output *DeleteSecurityGroupOutput) { op := &request.Operation{ Name: opDeleteSecurityGroup, @@ -6355,7 +7080,7 @@ func (c *EC2) DeleteSecurityGroupRequest(input *DeleteSecurityGroupInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteSecurityGroup for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroup func (c *EC2) DeleteSecurityGroup(input *DeleteSecurityGroupInput) (*DeleteSecurityGroupOutput, error) { req, out := c.DeleteSecurityGroupRequest(input) return out, req.Send() @@ -6381,19 +7106,18 @@ const opDeleteSnapshot = "DeleteSnapshot" // DeleteSnapshotRequest generates a "aws/request.Request" representing the // client's request for the DeleteSnapshot operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteSnapshot for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteSnapshot method directly -// instead. +// See DeleteSnapshot for more information on using the DeleteSnapshot +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteSnapshotRequest method. // req, resp := client.DeleteSnapshotRequest(params) @@ -6403,7 +7127,7 @@ const opDeleteSnapshot = "DeleteSnapshot" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshot func (c *EC2) DeleteSnapshotRequest(input *DeleteSnapshotInput) (req *request.Request, output *DeleteSnapshotOutput) { op := &request.Operation{ Name: opDeleteSnapshot, @@ -6446,7 +7170,7 @@ func (c *EC2) DeleteSnapshotRequest(input *DeleteSnapshotInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteSnapshot for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshot func (c *EC2) DeleteSnapshot(input *DeleteSnapshotInput) (*DeleteSnapshotOutput, error) { req, out := c.DeleteSnapshotRequest(input) return out, req.Send() @@ -6472,19 +7196,18 @@ const opDeleteSpotDatafeedSubscription = "DeleteSpotDatafeedSubscription" // DeleteSpotDatafeedSubscriptionRequest generates a "aws/request.Request" representing the // client's request for the DeleteSpotDatafeedSubscription operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteSpotDatafeedSubscription for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteSpotDatafeedSubscription method directly -// instead. +// See DeleteSpotDatafeedSubscription for more information on using the DeleteSpotDatafeedSubscription +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteSpotDatafeedSubscriptionRequest method. // req, resp := client.DeleteSpotDatafeedSubscriptionRequest(params) @@ -6494,7 +7217,7 @@ const opDeleteSpotDatafeedSubscription = "DeleteSpotDatafeedSubscription" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscription func (c *EC2) DeleteSpotDatafeedSubscriptionRequest(input *DeleteSpotDatafeedSubscriptionInput) (req *request.Request, output *DeleteSpotDatafeedSubscriptionOutput) { op := &request.Operation{ Name: opDeleteSpotDatafeedSubscription, @@ -6515,7 +7238,7 @@ func (c *EC2) DeleteSpotDatafeedSubscriptionRequest(input *DeleteSpotDatafeedSub // DeleteSpotDatafeedSubscription API operation for Amazon Elastic Compute Cloud. // -// Deletes the data feed for Spot instances. +// Deletes the data feed for Spot Instances. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -6523,7 +7246,7 @@ func (c *EC2) DeleteSpotDatafeedSubscriptionRequest(input *DeleteSpotDatafeedSub // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteSpotDatafeedSubscription for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscription func (c *EC2) DeleteSpotDatafeedSubscription(input *DeleteSpotDatafeedSubscriptionInput) (*DeleteSpotDatafeedSubscriptionOutput, error) { req, out := c.DeleteSpotDatafeedSubscriptionRequest(input) return out, req.Send() @@ -6549,19 +7272,18 @@ const opDeleteSubnet = "DeleteSubnet" // DeleteSubnetRequest generates a "aws/request.Request" representing the // client's request for the DeleteSubnet operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteSubnet for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteSubnet method directly -// instead. +// See DeleteSubnet for more information on using the DeleteSubnet +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteSubnetRequest method. // req, resp := client.DeleteSubnetRequest(params) @@ -6571,7 +7293,7 @@ const opDeleteSubnet = "DeleteSubnet" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnet func (c *EC2) DeleteSubnetRequest(input *DeleteSubnetInput) (req *request.Request, output *DeleteSubnetOutput) { op := &request.Operation{ Name: opDeleteSubnet, @@ -6601,7 +7323,7 @@ func (c *EC2) DeleteSubnetRequest(input *DeleteSubnetInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteSubnet for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnet func (c *EC2) DeleteSubnet(input *DeleteSubnetInput) (*DeleteSubnetOutput, error) { req, out := c.DeleteSubnetRequest(input) return out, req.Send() @@ -6627,19 +7349,18 @@ const opDeleteTags = "DeleteTags" // DeleteTagsRequest generates a "aws/request.Request" representing the // client's request for the DeleteTags operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteTags for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteTags method directly -// instead. +// See DeleteTags for more information on using the DeleteTags +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteTagsRequest method. // req, resp := client.DeleteTagsRequest(params) @@ -6649,7 +7370,7 @@ const opDeleteTags = "DeleteTags" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTags +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTags func (c *EC2) DeleteTagsRequest(input *DeleteTagsInput) (req *request.Request, output *DeleteTagsOutput) { op := &request.Operation{ Name: opDeleteTags, @@ -6670,10 +7391,10 @@ func (c *EC2) DeleteTagsRequest(input *DeleteTagsInput) (req *request.Request, o // DeleteTags API operation for Amazon Elastic Compute Cloud. // -// Deletes the specified set of tags from the specified set of resources. This -// call is designed to follow a DescribeTags request. +// Deletes the specified set of tags from the specified set of resources. // -// For more information about tags, see Tagging Your Resources (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html) +// To list the current tags, use DescribeTags. For more information about tags, +// see Tagging Your Resources (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -6682,7 +7403,7 @@ func (c *EC2) DeleteTagsRequest(input *DeleteTagsInput) (req *request.Request, o // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteTags for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTags +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTags func (c *EC2) DeleteTags(input *DeleteTagsInput) (*DeleteTagsOutput, error) { req, out := c.DeleteTagsRequest(input) return out, req.Send() @@ -6708,19 +7429,18 @@ const opDeleteVolume = "DeleteVolume" // DeleteVolumeRequest generates a "aws/request.Request" representing the // client's request for the DeleteVolume operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVolume for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVolume method directly -// instead. +// See DeleteVolume for more information on using the DeleteVolume +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVolumeRequest method. // req, resp := client.DeleteVolumeRequest(params) @@ -6730,7 +7450,7 @@ const opDeleteVolume = "DeleteVolume" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolume func (c *EC2) DeleteVolumeRequest(input *DeleteVolumeInput) (req *request.Request, output *DeleteVolumeOutput) { op := &request.Operation{ Name: opDeleteVolume, @@ -6765,7 +7485,7 @@ func (c *EC2) DeleteVolumeRequest(input *DeleteVolumeInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVolume for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolume func (c *EC2) DeleteVolume(input *DeleteVolumeInput) (*DeleteVolumeOutput, error) { req, out := c.DeleteVolumeRequest(input) return out, req.Send() @@ -6791,19 +7511,18 @@ const opDeleteVpc = "DeleteVpc" // DeleteVpcRequest generates a "aws/request.Request" representing the // client's request for the DeleteVpc operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVpc for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVpc method directly -// instead. +// See DeleteVpc for more information on using the DeleteVpc +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVpcRequest method. // req, resp := client.DeleteVpcRequest(params) @@ -6813,7 +7532,7 @@ const opDeleteVpc = "DeleteVpc" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpc func (c *EC2) DeleteVpcRequest(input *DeleteVpcInput) (req *request.Request, output *DeleteVpcOutput) { op := &request.Operation{ Name: opDeleteVpc, @@ -6846,7 +7565,7 @@ func (c *EC2) DeleteVpcRequest(input *DeleteVpcInput) (req *request.Request, out // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVpc for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpc func (c *EC2) DeleteVpc(input *DeleteVpcInput) (*DeleteVpcOutput, error) { req, out := c.DeleteVpcRequest(input) return out, req.Send() @@ -6868,23 +7587,173 @@ func (c *EC2) DeleteVpcWithContext(ctx aws.Context, input *DeleteVpcInput, opts return out, req.Send() } +const opDeleteVpcEndpointConnectionNotifications = "DeleteVpcEndpointConnectionNotifications" + +// DeleteVpcEndpointConnectionNotificationsRequest generates a "aws/request.Request" representing the +// client's request for the DeleteVpcEndpointConnectionNotifications operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DeleteVpcEndpointConnectionNotifications for more information on using the DeleteVpcEndpointConnectionNotifications +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DeleteVpcEndpointConnectionNotificationsRequest method. +// req, resp := client.DeleteVpcEndpointConnectionNotificationsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointConnectionNotifications +func (c *EC2) DeleteVpcEndpointConnectionNotificationsRequest(input *DeleteVpcEndpointConnectionNotificationsInput) (req *request.Request, output *DeleteVpcEndpointConnectionNotificationsOutput) { + op := &request.Operation{ + Name: opDeleteVpcEndpointConnectionNotifications, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteVpcEndpointConnectionNotificationsInput{} + } + + output = &DeleteVpcEndpointConnectionNotificationsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DeleteVpcEndpointConnectionNotifications API operation for Amazon Elastic Compute Cloud. +// +// Deletes one or more VPC endpoint connection notifications. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DeleteVpcEndpointConnectionNotifications for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointConnectionNotifications +func (c *EC2) DeleteVpcEndpointConnectionNotifications(input *DeleteVpcEndpointConnectionNotificationsInput) (*DeleteVpcEndpointConnectionNotificationsOutput, error) { + req, out := c.DeleteVpcEndpointConnectionNotificationsRequest(input) + return out, req.Send() +} + +// DeleteVpcEndpointConnectionNotificationsWithContext is the same as DeleteVpcEndpointConnectionNotifications with the addition of +// the ability to pass a context and additional request options. +// +// See DeleteVpcEndpointConnectionNotifications for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DeleteVpcEndpointConnectionNotificationsWithContext(ctx aws.Context, input *DeleteVpcEndpointConnectionNotificationsInput, opts ...request.Option) (*DeleteVpcEndpointConnectionNotificationsOutput, error) { + req, out := c.DeleteVpcEndpointConnectionNotificationsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opDeleteVpcEndpointServiceConfigurations = "DeleteVpcEndpointServiceConfigurations" + +// DeleteVpcEndpointServiceConfigurationsRequest generates a "aws/request.Request" representing the +// client's request for the DeleteVpcEndpointServiceConfigurations operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DeleteVpcEndpointServiceConfigurations for more information on using the DeleteVpcEndpointServiceConfigurations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DeleteVpcEndpointServiceConfigurationsRequest method. +// req, resp := client.DeleteVpcEndpointServiceConfigurationsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointServiceConfigurations +func (c *EC2) DeleteVpcEndpointServiceConfigurationsRequest(input *DeleteVpcEndpointServiceConfigurationsInput) (req *request.Request, output *DeleteVpcEndpointServiceConfigurationsOutput) { + op := &request.Operation{ + Name: opDeleteVpcEndpointServiceConfigurations, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DeleteVpcEndpointServiceConfigurationsInput{} + } + + output = &DeleteVpcEndpointServiceConfigurationsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DeleteVpcEndpointServiceConfigurations API operation for Amazon Elastic Compute Cloud. +// +// Deletes one or more VPC endpoint service configurations in your account. +// Before you delete the endpoint service configuration, you must reject any +// Available or PendingAcceptance interface endpoint connections that are attached +// to the service. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DeleteVpcEndpointServiceConfigurations for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointServiceConfigurations +func (c *EC2) DeleteVpcEndpointServiceConfigurations(input *DeleteVpcEndpointServiceConfigurationsInput) (*DeleteVpcEndpointServiceConfigurationsOutput, error) { + req, out := c.DeleteVpcEndpointServiceConfigurationsRequest(input) + return out, req.Send() +} + +// DeleteVpcEndpointServiceConfigurationsWithContext is the same as DeleteVpcEndpointServiceConfigurations with the addition of +// the ability to pass a context and additional request options. +// +// See DeleteVpcEndpointServiceConfigurations for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DeleteVpcEndpointServiceConfigurationsWithContext(ctx aws.Context, input *DeleteVpcEndpointServiceConfigurationsInput, opts ...request.Option) (*DeleteVpcEndpointServiceConfigurationsOutput, error) { + req, out := c.DeleteVpcEndpointServiceConfigurationsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDeleteVpcEndpoints = "DeleteVpcEndpoints" // DeleteVpcEndpointsRequest generates a "aws/request.Request" representing the // client's request for the DeleteVpcEndpoints operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVpcEndpoints for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVpcEndpoints method directly -// instead. +// See DeleteVpcEndpoints for more information on using the DeleteVpcEndpoints +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVpcEndpointsRequest method. // req, resp := client.DeleteVpcEndpointsRequest(params) @@ -6894,7 +7763,7 @@ const opDeleteVpcEndpoints = "DeleteVpcEndpoints" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpoints +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpoints func (c *EC2) DeleteVpcEndpointsRequest(input *DeleteVpcEndpointsInput) (req *request.Request, output *DeleteVpcEndpointsOutput) { op := &request.Operation{ Name: opDeleteVpcEndpoints, @@ -6913,8 +7782,10 @@ func (c *EC2) DeleteVpcEndpointsRequest(input *DeleteVpcEndpointsInput) (req *re // DeleteVpcEndpoints API operation for Amazon Elastic Compute Cloud. // -// Deletes one or more specified VPC endpoints. Deleting the endpoint also deletes -// the endpoint routes in the route tables that were associated with the endpoint. +// Deletes one or more specified VPC endpoints. Deleting a gateway endpoint +// also deletes the endpoint routes in the route tables that were associated +// with the endpoint. Deleting an interface endpoint deletes the endpoint network +// interfaces. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -6922,7 +7793,7 @@ func (c *EC2) DeleteVpcEndpointsRequest(input *DeleteVpcEndpointsInput) (req *re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVpcEndpoints for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpoints +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpoints func (c *EC2) DeleteVpcEndpoints(input *DeleteVpcEndpointsInput) (*DeleteVpcEndpointsOutput, error) { req, out := c.DeleteVpcEndpointsRequest(input) return out, req.Send() @@ -6948,19 +7819,18 @@ const opDeleteVpcPeeringConnection = "DeleteVpcPeeringConnection" // DeleteVpcPeeringConnectionRequest generates a "aws/request.Request" representing the // client's request for the DeleteVpcPeeringConnection operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVpcPeeringConnection for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVpcPeeringConnection method directly -// instead. +// See DeleteVpcPeeringConnection for more information on using the DeleteVpcPeeringConnection +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVpcPeeringConnectionRequest method. // req, resp := client.DeleteVpcPeeringConnectionRequest(params) @@ -6970,7 +7840,7 @@ const opDeleteVpcPeeringConnection = "DeleteVpcPeeringConnection" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnection func (c *EC2) DeleteVpcPeeringConnectionRequest(input *DeleteVpcPeeringConnectionInput) (req *request.Request, output *DeleteVpcPeeringConnectionOutput) { op := &request.Operation{ Name: opDeleteVpcPeeringConnection, @@ -6990,8 +7860,8 @@ func (c *EC2) DeleteVpcPeeringConnectionRequest(input *DeleteVpcPeeringConnectio // DeleteVpcPeeringConnection API operation for Amazon Elastic Compute Cloud. // // Deletes a VPC peering connection. Either the owner of the requester VPC or -// the owner of the peer VPC can delete the VPC peering connection if it's in -// the active state. The owner of the requester VPC can delete a VPC peering +// the owner of the accepter VPC can delete the VPC peering connection if it's +// in the active state. The owner of the requester VPC can delete a VPC peering // connection in the pending-acceptance state. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -7000,7 +7870,7 @@ func (c *EC2) DeleteVpcPeeringConnectionRequest(input *DeleteVpcPeeringConnectio // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVpcPeeringConnection for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnection func (c *EC2) DeleteVpcPeeringConnection(input *DeleteVpcPeeringConnectionInput) (*DeleteVpcPeeringConnectionOutput, error) { req, out := c.DeleteVpcPeeringConnectionRequest(input) return out, req.Send() @@ -7026,19 +7896,18 @@ const opDeleteVpnConnection = "DeleteVpnConnection" // DeleteVpnConnectionRequest generates a "aws/request.Request" representing the // client's request for the DeleteVpnConnection operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVpnConnection for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVpnConnection method directly -// instead. +// See DeleteVpnConnection for more information on using the DeleteVpnConnection +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVpnConnectionRequest method. // req, resp := client.DeleteVpnConnectionRequest(params) @@ -7048,7 +7917,7 @@ const opDeleteVpnConnection = "DeleteVpnConnection" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnection func (c *EC2) DeleteVpnConnectionRequest(input *DeleteVpnConnectionInput) (req *request.Request, output *DeleteVpnConnectionOutput) { op := &request.Operation{ Name: opDeleteVpnConnection, @@ -7086,7 +7955,7 @@ func (c *EC2) DeleteVpnConnectionRequest(input *DeleteVpnConnectionInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVpnConnection for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnection func (c *EC2) DeleteVpnConnection(input *DeleteVpnConnectionInput) (*DeleteVpnConnectionOutput, error) { req, out := c.DeleteVpnConnectionRequest(input) return out, req.Send() @@ -7112,19 +7981,18 @@ const opDeleteVpnConnectionRoute = "DeleteVpnConnectionRoute" // DeleteVpnConnectionRouteRequest generates a "aws/request.Request" representing the // client's request for the DeleteVpnConnectionRoute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVpnConnectionRoute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVpnConnectionRoute method directly -// instead. +// See DeleteVpnConnectionRoute for more information on using the DeleteVpnConnectionRoute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVpnConnectionRouteRequest method. // req, resp := client.DeleteVpnConnectionRouteRequest(params) @@ -7134,7 +8002,7 @@ const opDeleteVpnConnectionRoute = "DeleteVpnConnectionRoute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRoute func (c *EC2) DeleteVpnConnectionRouteRequest(input *DeleteVpnConnectionRouteInput) (req *request.Request, output *DeleteVpnConnectionRouteOutput) { op := &request.Operation{ Name: opDeleteVpnConnectionRoute, @@ -7166,7 +8034,7 @@ func (c *EC2) DeleteVpnConnectionRouteRequest(input *DeleteVpnConnectionRouteInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVpnConnectionRoute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRoute func (c *EC2) DeleteVpnConnectionRoute(input *DeleteVpnConnectionRouteInput) (*DeleteVpnConnectionRouteOutput, error) { req, out := c.DeleteVpnConnectionRouteRequest(input) return out, req.Send() @@ -7192,19 +8060,18 @@ const opDeleteVpnGateway = "DeleteVpnGateway" // DeleteVpnGatewayRequest generates a "aws/request.Request" representing the // client's request for the DeleteVpnGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteVpnGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteVpnGateway method directly -// instead. +// See DeleteVpnGateway for more information on using the DeleteVpnGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteVpnGatewayRequest method. // req, resp := client.DeleteVpnGatewayRequest(params) @@ -7214,7 +8081,7 @@ const opDeleteVpnGateway = "DeleteVpnGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGateway func (c *EC2) DeleteVpnGatewayRequest(input *DeleteVpnGatewayInput) (req *request.Request, output *DeleteVpnGatewayOutput) { op := &request.Operation{ Name: opDeleteVpnGateway, @@ -7247,7 +8114,7 @@ func (c *EC2) DeleteVpnGatewayRequest(input *DeleteVpnGatewayInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeleteVpnGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGateway func (c *EC2) DeleteVpnGateway(input *DeleteVpnGatewayInput) (*DeleteVpnGatewayOutput, error) { req, out := c.DeleteVpnGatewayRequest(input) return out, req.Send() @@ -7273,19 +8140,18 @@ const opDeregisterImage = "DeregisterImage" // DeregisterImageRequest generates a "aws/request.Request" representing the // client's request for the DeregisterImage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeregisterImage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeregisterImage method directly -// instead. +// See DeregisterImage for more information on using the DeregisterImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeregisterImageRequest method. // req, resp := client.DeregisterImageRequest(params) @@ -7295,7 +8161,7 @@ const opDeregisterImage = "DeregisterImage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImage func (c *EC2) DeregisterImageRequest(input *DeregisterImageInput) (req *request.Request, output *DeregisterImageOutput) { op := &request.Operation{ Name: opDeregisterImage, @@ -7317,9 +8183,14 @@ func (c *EC2) DeregisterImageRequest(input *DeregisterImageInput) (req *request. // DeregisterImage API operation for Amazon Elastic Compute Cloud. // // Deregisters the specified AMI. After you deregister an AMI, it can't be used -// to launch new instances. +// to launch new instances; however, it doesn't affect any instances that you've +// already launched from the AMI. You'll continue to incur usage costs for those +// instances until you terminate them. // -// This command does not delete the AMI. +// When you deregister an Amazon EBS-backed AMI, it doesn't affect the snapshot +// that was created for the root volume of the instance during the AMI creation +// process. When you deregister an instance store-backed AMI, it doesn't affect +// the files that you uploaded to Amazon S3 when you created the AMI. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -7327,7 +8198,7 @@ func (c *EC2) DeregisterImageRequest(input *DeregisterImageInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DeregisterImage for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImage func (c *EC2) DeregisterImage(input *DeregisterImageInput) (*DeregisterImageOutput, error) { req, out := c.DeregisterImageRequest(input) return out, req.Send() @@ -7353,19 +8224,18 @@ const opDescribeAccountAttributes = "DescribeAccountAttributes" // DescribeAccountAttributesRequest generates a "aws/request.Request" representing the // client's request for the DescribeAccountAttributes operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeAccountAttributes for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeAccountAttributes method directly -// instead. +// See DescribeAccountAttributes for more information on using the DescribeAccountAttributes +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeAccountAttributesRequest method. // req, resp := client.DescribeAccountAttributesRequest(params) @@ -7375,7 +8245,7 @@ const opDescribeAccountAttributes = "DescribeAccountAttributes" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributes +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributes func (c *EC2) DescribeAccountAttributesRequest(input *DescribeAccountAttributesInput) (req *request.Request, output *DescribeAccountAttributesOutput) { op := &request.Operation{ Name: opDescribeAccountAttributes, @@ -7420,7 +8290,7 @@ func (c *EC2) DescribeAccountAttributesRequest(input *DescribeAccountAttributesI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeAccountAttributes for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributes +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributes func (c *EC2) DescribeAccountAttributes(input *DescribeAccountAttributesInput) (*DescribeAccountAttributesOutput, error) { req, out := c.DescribeAccountAttributesRequest(input) return out, req.Send() @@ -7446,19 +8316,18 @@ const opDescribeAddresses = "DescribeAddresses" // DescribeAddressesRequest generates a "aws/request.Request" representing the // client's request for the DescribeAddresses operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeAddresses for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeAddresses method directly -// instead. +// See DescribeAddresses for more information on using the DescribeAddresses +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeAddressesRequest method. // req, resp := client.DescribeAddressesRequest(params) @@ -7468,7 +8337,7 @@ const opDescribeAddresses = "DescribeAddresses" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddresses func (c *EC2) DescribeAddressesRequest(input *DescribeAddressesInput) (req *request.Request, output *DescribeAddressesOutput) { op := &request.Operation{ Name: opDescribeAddresses, @@ -7499,7 +8368,7 @@ func (c *EC2) DescribeAddressesRequest(input *DescribeAddressesInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeAddresses for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddresses func (c *EC2) DescribeAddresses(input *DescribeAddressesInput) (*DescribeAddressesOutput, error) { req, out := c.DescribeAddressesRequest(input) return out, req.Send() @@ -7525,19 +8394,18 @@ const opDescribeAvailabilityZones = "DescribeAvailabilityZones" // DescribeAvailabilityZonesRequest generates a "aws/request.Request" representing the // client's request for the DescribeAvailabilityZones operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeAvailabilityZones for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeAvailabilityZones method directly -// instead. +// See DescribeAvailabilityZones for more information on using the DescribeAvailabilityZones +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeAvailabilityZonesRequest method. // req, resp := client.DescribeAvailabilityZonesRequest(params) @@ -7547,7 +8415,7 @@ const opDescribeAvailabilityZones = "DescribeAvailabilityZones" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZones +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZones func (c *EC2) DescribeAvailabilityZonesRequest(input *DescribeAvailabilityZonesInput) (req *request.Request, output *DescribeAvailabilityZonesOutput) { op := &request.Operation{ Name: opDescribeAvailabilityZones, @@ -7580,7 +8448,7 @@ func (c *EC2) DescribeAvailabilityZonesRequest(input *DescribeAvailabilityZonesI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeAvailabilityZones for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZones +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZones func (c *EC2) DescribeAvailabilityZones(input *DescribeAvailabilityZonesInput) (*DescribeAvailabilityZonesOutput, error) { req, out := c.DescribeAvailabilityZonesRequest(input) return out, req.Send() @@ -7606,19 +8474,18 @@ const opDescribeBundleTasks = "DescribeBundleTasks" // DescribeBundleTasksRequest generates a "aws/request.Request" representing the // client's request for the DescribeBundleTasks operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeBundleTasks for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeBundleTasks method directly -// instead. +// See DescribeBundleTasks for more information on using the DescribeBundleTasks +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeBundleTasksRequest method. // req, resp := client.DescribeBundleTasksRequest(params) @@ -7628,7 +8495,7 @@ const opDescribeBundleTasks = "DescribeBundleTasks" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasks func (c *EC2) DescribeBundleTasksRequest(input *DescribeBundleTasksInput) (req *request.Request, output *DescribeBundleTasksOutput) { op := &request.Operation{ Name: opDescribeBundleTasks, @@ -7660,7 +8527,7 @@ func (c *EC2) DescribeBundleTasksRequest(input *DescribeBundleTasksInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeBundleTasks for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasks func (c *EC2) DescribeBundleTasks(input *DescribeBundleTasksInput) (*DescribeBundleTasksOutput, error) { req, out := c.DescribeBundleTasksRequest(input) return out, req.Send() @@ -7686,19 +8553,18 @@ const opDescribeClassicLinkInstances = "DescribeClassicLinkInstances" // DescribeClassicLinkInstancesRequest generates a "aws/request.Request" representing the // client's request for the DescribeClassicLinkInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeClassicLinkInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeClassicLinkInstances method directly -// instead. +// See DescribeClassicLinkInstances for more information on using the DescribeClassicLinkInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeClassicLinkInstancesRequest method. // req, resp := client.DescribeClassicLinkInstancesRequest(params) @@ -7708,7 +8574,7 @@ const opDescribeClassicLinkInstances = "DescribeClassicLinkInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstances func (c *EC2) DescribeClassicLinkInstancesRequest(input *DescribeClassicLinkInstancesInput) (req *request.Request, output *DescribeClassicLinkInstancesOutput) { op := &request.Operation{ Name: opDescribeClassicLinkInstances, @@ -7738,7 +8604,7 @@ func (c *EC2) DescribeClassicLinkInstancesRequest(input *DescribeClassicLinkInst // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeClassicLinkInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstances func (c *EC2) DescribeClassicLinkInstances(input *DescribeClassicLinkInstancesInput) (*DescribeClassicLinkInstancesOutput, error) { req, out := c.DescribeClassicLinkInstancesRequest(input) return out, req.Send() @@ -7764,19 +8630,18 @@ const opDescribeConversionTasks = "DescribeConversionTasks" // DescribeConversionTasksRequest generates a "aws/request.Request" representing the // client's request for the DescribeConversionTasks operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeConversionTasks for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeConversionTasks method directly -// instead. +// See DescribeConversionTasks for more information on using the DescribeConversionTasks +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeConversionTasksRequest method. // req, resp := client.DescribeConversionTasksRequest(params) @@ -7786,7 +8651,7 @@ const opDescribeConversionTasks = "DescribeConversionTasks" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasks func (c *EC2) DescribeConversionTasksRequest(input *DescribeConversionTasksInput) (req *request.Request, output *DescribeConversionTasksOutput) { op := &request.Operation{ Name: opDescribeConversionTasks, @@ -7817,7 +8682,7 @@ func (c *EC2) DescribeConversionTasksRequest(input *DescribeConversionTasksInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeConversionTasks for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasks func (c *EC2) DescribeConversionTasks(input *DescribeConversionTasksInput) (*DescribeConversionTasksOutput, error) { req, out := c.DescribeConversionTasksRequest(input) return out, req.Send() @@ -7843,19 +8708,18 @@ const opDescribeCustomerGateways = "DescribeCustomerGateways" // DescribeCustomerGatewaysRequest generates a "aws/request.Request" representing the // client's request for the DescribeCustomerGateways operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeCustomerGateways for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeCustomerGateways method directly -// instead. +// See DescribeCustomerGateways for more information on using the DescribeCustomerGateways +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeCustomerGatewaysRequest method. // req, resp := client.DescribeCustomerGatewaysRequest(params) @@ -7865,7 +8729,7 @@ const opDescribeCustomerGateways = "DescribeCustomerGateways" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGateways func (c *EC2) DescribeCustomerGatewaysRequest(input *DescribeCustomerGatewaysInput) (req *request.Request, output *DescribeCustomerGatewaysOutput) { op := &request.Operation{ Name: opDescribeCustomerGateways, @@ -7886,9 +8750,9 @@ func (c *EC2) DescribeCustomerGatewaysRequest(input *DescribeCustomerGatewaysInp // // Describes one or more of your VPN customer gateways. // -// For more information about VPN customer gateways, see Adding a Hardware Virtual -// Private Gateway to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) -// in the Amazon Virtual Private Cloud User Guide. +// For more information about VPN customer gateways, see AWS Managed VPN Connections +// (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) in the +// Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -7896,7 +8760,7 @@ func (c *EC2) DescribeCustomerGatewaysRequest(input *DescribeCustomerGatewaysInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeCustomerGateways for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGateways func (c *EC2) DescribeCustomerGateways(input *DescribeCustomerGatewaysInput) (*DescribeCustomerGatewaysOutput, error) { req, out := c.DescribeCustomerGatewaysRequest(input) return out, req.Send() @@ -7922,19 +8786,18 @@ const opDescribeDhcpOptions = "DescribeDhcpOptions" // DescribeDhcpOptionsRequest generates a "aws/request.Request" representing the // client's request for the DescribeDhcpOptions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeDhcpOptions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeDhcpOptions method directly -// instead. +// See DescribeDhcpOptions for more information on using the DescribeDhcpOptions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeDhcpOptionsRequest method. // req, resp := client.DescribeDhcpOptionsRequest(params) @@ -7944,7 +8807,7 @@ const opDescribeDhcpOptions = "DescribeDhcpOptions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptions func (c *EC2) DescribeDhcpOptionsRequest(input *DescribeDhcpOptionsInput) (req *request.Request, output *DescribeDhcpOptionsOutput) { op := &request.Operation{ Name: opDescribeDhcpOptions, @@ -7974,7 +8837,7 @@ func (c *EC2) DescribeDhcpOptionsRequest(input *DescribeDhcpOptionsInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeDhcpOptions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptions func (c *EC2) DescribeDhcpOptions(input *DescribeDhcpOptionsInput) (*DescribeDhcpOptionsOutput, error) { req, out := c.DescribeDhcpOptionsRequest(input) return out, req.Send() @@ -8000,19 +8863,18 @@ const opDescribeEgressOnlyInternetGateways = "DescribeEgressOnlyInternetGateways // DescribeEgressOnlyInternetGatewaysRequest generates a "aws/request.Request" representing the // client's request for the DescribeEgressOnlyInternetGateways operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeEgressOnlyInternetGateways for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeEgressOnlyInternetGateways method directly -// instead. +// See DescribeEgressOnlyInternetGateways for more information on using the DescribeEgressOnlyInternetGateways +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeEgressOnlyInternetGatewaysRequest method. // req, resp := client.DescribeEgressOnlyInternetGatewaysRequest(params) @@ -8022,7 +8884,7 @@ const opDescribeEgressOnlyInternetGateways = "DescribeEgressOnlyInternetGateways // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGateways func (c *EC2) DescribeEgressOnlyInternetGatewaysRequest(input *DescribeEgressOnlyInternetGatewaysInput) (req *request.Request, output *DescribeEgressOnlyInternetGatewaysOutput) { op := &request.Operation{ Name: opDescribeEgressOnlyInternetGateways, @@ -8049,7 +8911,7 @@ func (c *EC2) DescribeEgressOnlyInternetGatewaysRequest(input *DescribeEgressOnl // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeEgressOnlyInternetGateways for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGateways func (c *EC2) DescribeEgressOnlyInternetGateways(input *DescribeEgressOnlyInternetGatewaysInput) (*DescribeEgressOnlyInternetGatewaysOutput, error) { req, out := c.DescribeEgressOnlyInternetGatewaysRequest(input) return out, req.Send() @@ -8075,19 +8937,18 @@ const opDescribeElasticGpus = "DescribeElasticGpus" // DescribeElasticGpusRequest generates a "aws/request.Request" representing the // client's request for the DescribeElasticGpus operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeElasticGpus for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeElasticGpus method directly -// instead. +// See DescribeElasticGpus for more information on using the DescribeElasticGpus +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeElasticGpusRequest method. // req, resp := client.DescribeElasticGpusRequest(params) @@ -8097,7 +8958,7 @@ const opDescribeElasticGpus = "DescribeElasticGpus" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpus func (c *EC2) DescribeElasticGpusRequest(input *DescribeElasticGpusInput) (req *request.Request, output *DescribeElasticGpusOutput) { op := &request.Operation{ Name: opDescribeElasticGpus, @@ -8117,7 +8978,7 @@ func (c *EC2) DescribeElasticGpusRequest(input *DescribeElasticGpusInput) (req * // DescribeElasticGpus API operation for Amazon Elastic Compute Cloud. // // Describes the Elastic GPUs associated with your instances. For more information -// about Elastic GPUs, see Amazon EC2 Elastic GPUs (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-gpus.html). +// about Elastic GPUs, see Amazon EC2 Elastic GPUs (http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/elastic-gpus.html). // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -8125,7 +8986,7 @@ func (c *EC2) DescribeElasticGpusRequest(input *DescribeElasticGpusInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeElasticGpus for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpus func (c *EC2) DescribeElasticGpus(input *DescribeElasticGpusInput) (*DescribeElasticGpusOutput, error) { req, out := c.DescribeElasticGpusRequest(input) return out, req.Send() @@ -8151,19 +9012,18 @@ const opDescribeExportTasks = "DescribeExportTasks" // DescribeExportTasksRequest generates a "aws/request.Request" representing the // client's request for the DescribeExportTasks operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeExportTasks for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeExportTasks method directly -// instead. +// See DescribeExportTasks for more information on using the DescribeExportTasks +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeExportTasksRequest method. // req, resp := client.DescribeExportTasksRequest(params) @@ -8173,7 +9033,7 @@ const opDescribeExportTasks = "DescribeExportTasks" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasks func (c *EC2) DescribeExportTasksRequest(input *DescribeExportTasksInput) (req *request.Request, output *DescribeExportTasksOutput) { op := &request.Operation{ Name: opDescribeExportTasks, @@ -8200,7 +9060,7 @@ func (c *EC2) DescribeExportTasksRequest(input *DescribeExportTasksInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeExportTasks for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasks func (c *EC2) DescribeExportTasks(input *DescribeExportTasksInput) (*DescribeExportTasksOutput, error) { req, out := c.DescribeExportTasksRequest(input) return out, req.Send() @@ -8226,19 +9086,18 @@ const opDescribeFlowLogs = "DescribeFlowLogs" // DescribeFlowLogsRequest generates a "aws/request.Request" representing the // client's request for the DescribeFlowLogs operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeFlowLogs for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeFlowLogs method directly -// instead. +// See DescribeFlowLogs for more information on using the DescribeFlowLogs +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeFlowLogsRequest method. // req, resp := client.DescribeFlowLogsRequest(params) @@ -8248,7 +9107,7 @@ const opDescribeFlowLogs = "DescribeFlowLogs" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogs func (c *EC2) DescribeFlowLogsRequest(input *DescribeFlowLogsInput) (req *request.Request, output *DescribeFlowLogsOutput) { op := &request.Operation{ Name: opDescribeFlowLogs, @@ -8277,7 +9136,7 @@ func (c *EC2) DescribeFlowLogsRequest(input *DescribeFlowLogsInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeFlowLogs for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogs func (c *EC2) DescribeFlowLogs(input *DescribeFlowLogsInput) (*DescribeFlowLogsOutput, error) { req, out := c.DescribeFlowLogsRequest(input) return out, req.Send() @@ -8299,23 +9158,96 @@ func (c *EC2) DescribeFlowLogsWithContext(ctx aws.Context, input *DescribeFlowLo return out, req.Send() } +const opDescribeFpgaImageAttribute = "DescribeFpgaImageAttribute" + +// DescribeFpgaImageAttributeRequest generates a "aws/request.Request" representing the +// client's request for the DescribeFpgaImageAttribute operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeFpgaImageAttribute for more information on using the DescribeFpgaImageAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeFpgaImageAttributeRequest method. +// req, resp := client.DescribeFpgaImageAttributeRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImageAttribute +func (c *EC2) DescribeFpgaImageAttributeRequest(input *DescribeFpgaImageAttributeInput) (req *request.Request, output *DescribeFpgaImageAttributeOutput) { + op := &request.Operation{ + Name: opDescribeFpgaImageAttribute, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeFpgaImageAttributeInput{} + } + + output = &DescribeFpgaImageAttributeOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeFpgaImageAttribute API operation for Amazon Elastic Compute Cloud. +// +// Describes the specified attribute of the specified Amazon FPGA Image (AFI). +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeFpgaImageAttribute for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImageAttribute +func (c *EC2) DescribeFpgaImageAttribute(input *DescribeFpgaImageAttributeInput) (*DescribeFpgaImageAttributeOutput, error) { + req, out := c.DescribeFpgaImageAttributeRequest(input) + return out, req.Send() +} + +// DescribeFpgaImageAttributeWithContext is the same as DescribeFpgaImageAttribute with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeFpgaImageAttribute for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeFpgaImageAttributeWithContext(ctx aws.Context, input *DescribeFpgaImageAttributeInput, opts ...request.Option) (*DescribeFpgaImageAttributeOutput, error) { + req, out := c.DescribeFpgaImageAttributeRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDescribeFpgaImages = "DescribeFpgaImages" // DescribeFpgaImagesRequest generates a "aws/request.Request" representing the // client's request for the DescribeFpgaImages operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeFpgaImages for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeFpgaImages method directly -// instead. +// See DescribeFpgaImages for more information on using the DescribeFpgaImages +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeFpgaImagesRequest method. // req, resp := client.DescribeFpgaImagesRequest(params) @@ -8325,7 +9257,7 @@ const opDescribeFpgaImages = "DescribeFpgaImages" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImages +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImages func (c *EC2) DescribeFpgaImagesRequest(input *DescribeFpgaImagesInput) (req *request.Request, output *DescribeFpgaImagesOutput) { op := &request.Operation{ Name: opDescribeFpgaImages, @@ -8354,7 +9286,7 @@ func (c *EC2) DescribeFpgaImagesRequest(input *DescribeFpgaImagesInput) (req *re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeFpgaImages for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImages +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImages func (c *EC2) DescribeFpgaImages(input *DescribeFpgaImagesInput) (*DescribeFpgaImagesOutput, error) { req, out := c.DescribeFpgaImagesRequest(input) return out, req.Send() @@ -8380,19 +9312,18 @@ const opDescribeHostReservationOfferings = "DescribeHostReservationOfferings" // DescribeHostReservationOfferingsRequest generates a "aws/request.Request" representing the // client's request for the DescribeHostReservationOfferings operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeHostReservationOfferings for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeHostReservationOfferings method directly -// instead. +// See DescribeHostReservationOfferings for more information on using the DescribeHostReservationOfferings +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeHostReservationOfferingsRequest method. // req, resp := client.DescribeHostReservationOfferingsRequest(params) @@ -8402,7 +9333,7 @@ const opDescribeHostReservationOfferings = "DescribeHostReservationOfferings" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferings +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferings func (c *EC2) DescribeHostReservationOfferingsRequest(input *DescribeHostReservationOfferingsInput) (req *request.Request, output *DescribeHostReservationOfferingsOutput) { op := &request.Operation{ Name: opDescribeHostReservationOfferings, @@ -8437,7 +9368,7 @@ func (c *EC2) DescribeHostReservationOfferingsRequest(input *DescribeHostReserva // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeHostReservationOfferings for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferings +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferings func (c *EC2) DescribeHostReservationOfferings(input *DescribeHostReservationOfferingsInput) (*DescribeHostReservationOfferingsOutput, error) { req, out := c.DescribeHostReservationOfferingsRequest(input) return out, req.Send() @@ -8463,19 +9394,18 @@ const opDescribeHostReservations = "DescribeHostReservations" // DescribeHostReservationsRequest generates a "aws/request.Request" representing the // client's request for the DescribeHostReservations operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeHostReservations for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeHostReservations method directly -// instead. +// See DescribeHostReservations for more information on using the DescribeHostReservations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeHostReservationsRequest method. // req, resp := client.DescribeHostReservationsRequest(params) @@ -8485,7 +9415,7 @@ const opDescribeHostReservations = "DescribeHostReservations" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservations +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservations func (c *EC2) DescribeHostReservationsRequest(input *DescribeHostReservationsInput) (req *request.Request, output *DescribeHostReservationsOutput) { op := &request.Operation{ Name: opDescribeHostReservations, @@ -8513,7 +9443,7 @@ func (c *EC2) DescribeHostReservationsRequest(input *DescribeHostReservationsInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeHostReservations for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservations +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservations func (c *EC2) DescribeHostReservations(input *DescribeHostReservationsInput) (*DescribeHostReservationsOutput, error) { req, out := c.DescribeHostReservationsRequest(input) return out, req.Send() @@ -8539,19 +9469,18 @@ const opDescribeHosts = "DescribeHosts" // DescribeHostsRequest generates a "aws/request.Request" representing the // client's request for the DescribeHosts operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeHosts for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeHosts method directly -// instead. +// See DescribeHosts for more information on using the DescribeHosts +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeHostsRequest method. // req, resp := client.DescribeHostsRequest(params) @@ -8561,7 +9490,7 @@ const opDescribeHosts = "DescribeHosts" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHosts func (c *EC2) DescribeHostsRequest(input *DescribeHostsInput) (req *request.Request, output *DescribeHostsOutput) { op := &request.Operation{ Name: opDescribeHosts, @@ -8592,7 +9521,7 @@ func (c *EC2) DescribeHostsRequest(input *DescribeHostsInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeHosts for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHosts func (c *EC2) DescribeHosts(input *DescribeHostsInput) (*DescribeHostsOutput, error) { req, out := c.DescribeHostsRequest(input) return out, req.Send() @@ -8618,19 +9547,18 @@ const opDescribeIamInstanceProfileAssociations = "DescribeIamInstanceProfileAsso // DescribeIamInstanceProfileAssociationsRequest generates a "aws/request.Request" representing the // client's request for the DescribeIamInstanceProfileAssociations operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeIamInstanceProfileAssociations for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeIamInstanceProfileAssociations method directly -// instead. +// See DescribeIamInstanceProfileAssociations for more information on using the DescribeIamInstanceProfileAssociations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeIamInstanceProfileAssociationsRequest method. // req, resp := client.DescribeIamInstanceProfileAssociationsRequest(params) @@ -8640,7 +9568,7 @@ const opDescribeIamInstanceProfileAssociations = "DescribeIamInstanceProfileAsso // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociations +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociations func (c *EC2) DescribeIamInstanceProfileAssociationsRequest(input *DescribeIamInstanceProfileAssociationsInput) (req *request.Request, output *DescribeIamInstanceProfileAssociationsOutput) { op := &request.Operation{ Name: opDescribeIamInstanceProfileAssociations, @@ -8667,7 +9595,7 @@ func (c *EC2) DescribeIamInstanceProfileAssociationsRequest(input *DescribeIamIn // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeIamInstanceProfileAssociations for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociations +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociations func (c *EC2) DescribeIamInstanceProfileAssociations(input *DescribeIamInstanceProfileAssociationsInput) (*DescribeIamInstanceProfileAssociationsOutput, error) { req, out := c.DescribeIamInstanceProfileAssociationsRequest(input) return out, req.Send() @@ -8693,19 +9621,18 @@ const opDescribeIdFormat = "DescribeIdFormat" // DescribeIdFormatRequest generates a "aws/request.Request" representing the // client's request for the DescribeIdFormat operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeIdFormat for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeIdFormat method directly -// instead. +// See DescribeIdFormat for more information on using the DescribeIdFormat +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeIdFormatRequest method. // req, resp := client.DescribeIdFormatRequest(params) @@ -8715,7 +9642,7 @@ const opDescribeIdFormat = "DescribeIdFormat" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormat func (c *EC2) DescribeIdFormatRequest(input *DescribeIdFormatInput) (req *request.Request, output *DescribeIdFormatOutput) { op := &request.Operation{ Name: opDescribeIdFormat, @@ -8755,7 +9682,7 @@ func (c *EC2) DescribeIdFormatRequest(input *DescribeIdFormatInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeIdFormat for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormat func (c *EC2) DescribeIdFormat(input *DescribeIdFormatInput) (*DescribeIdFormatOutput, error) { req, out := c.DescribeIdFormatRequest(input) return out, req.Send() @@ -8781,19 +9708,18 @@ const opDescribeIdentityIdFormat = "DescribeIdentityIdFormat" // DescribeIdentityIdFormatRequest generates a "aws/request.Request" representing the // client's request for the DescribeIdentityIdFormat operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeIdentityIdFormat for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeIdentityIdFormat method directly -// instead. +// See DescribeIdentityIdFormat for more information on using the DescribeIdentityIdFormat +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeIdentityIdFormatRequest method. // req, resp := client.DescribeIdentityIdFormatRequest(params) @@ -8803,7 +9729,7 @@ const opDescribeIdentityIdFormat = "DescribeIdentityIdFormat" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormat func (c *EC2) DescribeIdentityIdFormatRequest(input *DescribeIdentityIdFormatInput) (req *request.Request, output *DescribeIdentityIdFormatOutput) { op := &request.Operation{ Name: opDescribeIdentityIdFormat, @@ -8841,7 +9767,7 @@ func (c *EC2) DescribeIdentityIdFormatRequest(input *DescribeIdentityIdFormatInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeIdentityIdFormat for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormat func (c *EC2) DescribeIdentityIdFormat(input *DescribeIdentityIdFormatInput) (*DescribeIdentityIdFormatOutput, error) { req, out := c.DescribeIdentityIdFormatRequest(input) return out, req.Send() @@ -8867,19 +9793,18 @@ const opDescribeImageAttribute = "DescribeImageAttribute" // DescribeImageAttributeRequest generates a "aws/request.Request" representing the // client's request for the DescribeImageAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeImageAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeImageAttribute method directly -// instead. +// See DescribeImageAttribute for more information on using the DescribeImageAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeImageAttributeRequest method. // req, resp := client.DescribeImageAttributeRequest(params) @@ -8889,7 +9814,7 @@ const opDescribeImageAttribute = "DescribeImageAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImageAttribute func (c *EC2) DescribeImageAttributeRequest(input *DescribeImageAttributeInput) (req *request.Request, output *DescribeImageAttributeOutput) { op := &request.Operation{ Name: opDescribeImageAttribute, @@ -8917,7 +9842,7 @@ func (c *EC2) DescribeImageAttributeRequest(input *DescribeImageAttributeInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeImageAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImageAttribute func (c *EC2) DescribeImageAttribute(input *DescribeImageAttributeInput) (*DescribeImageAttributeOutput, error) { req, out := c.DescribeImageAttributeRequest(input) return out, req.Send() @@ -8943,19 +9868,18 @@ const opDescribeImages = "DescribeImages" // DescribeImagesRequest generates a "aws/request.Request" representing the // client's request for the DescribeImages operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeImages for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeImages method directly -// instead. +// See DescribeImages for more information on using the DescribeImages +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeImagesRequest method. // req, resp := client.DescribeImagesRequest(params) @@ -8965,7 +9889,7 @@ const opDescribeImages = "DescribeImages" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImages +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImages func (c *EC2) DescribeImagesRequest(input *DescribeImagesInput) (req *request.Request, output *DescribeImagesOutput) { op := &request.Operation{ Name: opDescribeImages, @@ -8998,7 +9922,7 @@ func (c *EC2) DescribeImagesRequest(input *DescribeImagesInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeImages for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImages +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImages func (c *EC2) DescribeImages(input *DescribeImagesInput) (*DescribeImagesOutput, error) { req, out := c.DescribeImagesRequest(input) return out, req.Send() @@ -9024,19 +9948,18 @@ const opDescribeImportImageTasks = "DescribeImportImageTasks" // DescribeImportImageTasksRequest generates a "aws/request.Request" representing the // client's request for the DescribeImportImageTasks operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeImportImageTasks for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeImportImageTasks method directly -// instead. +// See DescribeImportImageTasks for more information on using the DescribeImportImageTasks +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeImportImageTasksRequest method. // req, resp := client.DescribeImportImageTasksRequest(params) @@ -9046,7 +9969,7 @@ const opDescribeImportImageTasks = "DescribeImportImageTasks" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasks func (c *EC2) DescribeImportImageTasksRequest(input *DescribeImportImageTasksInput) (req *request.Request, output *DescribeImportImageTasksOutput) { op := &request.Operation{ Name: opDescribeImportImageTasks, @@ -9074,7 +9997,7 @@ func (c *EC2) DescribeImportImageTasksRequest(input *DescribeImportImageTasksInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeImportImageTasks for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasks func (c *EC2) DescribeImportImageTasks(input *DescribeImportImageTasksInput) (*DescribeImportImageTasksOutput, error) { req, out := c.DescribeImportImageTasksRequest(input) return out, req.Send() @@ -9100,19 +10023,18 @@ const opDescribeImportSnapshotTasks = "DescribeImportSnapshotTasks" // DescribeImportSnapshotTasksRequest generates a "aws/request.Request" representing the // client's request for the DescribeImportSnapshotTasks operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeImportSnapshotTasks for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeImportSnapshotTasks method directly -// instead. +// See DescribeImportSnapshotTasks for more information on using the DescribeImportSnapshotTasks +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeImportSnapshotTasksRequest method. // req, resp := client.DescribeImportSnapshotTasksRequest(params) @@ -9122,7 +10044,7 @@ const opDescribeImportSnapshotTasks = "DescribeImportSnapshotTasks" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasks func (c *EC2) DescribeImportSnapshotTasksRequest(input *DescribeImportSnapshotTasksInput) (req *request.Request, output *DescribeImportSnapshotTasksOutput) { op := &request.Operation{ Name: opDescribeImportSnapshotTasks, @@ -9149,7 +10071,7 @@ func (c *EC2) DescribeImportSnapshotTasksRequest(input *DescribeImportSnapshotTa // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeImportSnapshotTasks for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasks +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasks func (c *EC2) DescribeImportSnapshotTasks(input *DescribeImportSnapshotTasksInput) (*DescribeImportSnapshotTasksOutput, error) { req, out := c.DescribeImportSnapshotTasksRequest(input) return out, req.Send() @@ -9175,19 +10097,18 @@ const opDescribeInstanceAttribute = "DescribeInstanceAttribute" // DescribeInstanceAttributeRequest generates a "aws/request.Request" representing the // client's request for the DescribeInstanceAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeInstanceAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeInstanceAttribute method directly -// instead. +// See DescribeInstanceAttribute for more information on using the DescribeInstanceAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeInstanceAttributeRequest method. // req, resp := client.DescribeInstanceAttributeRequest(params) @@ -9197,7 +10118,7 @@ const opDescribeInstanceAttribute = "DescribeInstanceAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceAttribute func (c *EC2) DescribeInstanceAttributeRequest(input *DescribeInstanceAttributeInput) (req *request.Request, output *DescribeInstanceAttributeOutput) { op := &request.Operation{ Name: opDescribeInstanceAttribute, @@ -9228,7 +10149,7 @@ func (c *EC2) DescribeInstanceAttributeRequest(input *DescribeInstanceAttributeI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeInstanceAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceAttribute func (c *EC2) DescribeInstanceAttribute(input *DescribeInstanceAttributeInput) (*DescribeInstanceAttributeOutput, error) { req, out := c.DescribeInstanceAttributeRequest(input) return out, req.Send() @@ -9250,23 +10171,114 @@ func (c *EC2) DescribeInstanceAttributeWithContext(ctx aws.Context, input *Descr return out, req.Send() } +const opDescribeInstanceCreditSpecifications = "DescribeInstanceCreditSpecifications" + +// DescribeInstanceCreditSpecificationsRequest generates a "aws/request.Request" representing the +// client's request for the DescribeInstanceCreditSpecifications operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeInstanceCreditSpecifications for more information on using the DescribeInstanceCreditSpecifications +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeInstanceCreditSpecificationsRequest method. +// req, resp := client.DescribeInstanceCreditSpecificationsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceCreditSpecifications +func (c *EC2) DescribeInstanceCreditSpecificationsRequest(input *DescribeInstanceCreditSpecificationsInput) (req *request.Request, output *DescribeInstanceCreditSpecificationsOutput) { + op := &request.Operation{ + Name: opDescribeInstanceCreditSpecifications, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeInstanceCreditSpecificationsInput{} + } + + output = &DescribeInstanceCreditSpecificationsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeInstanceCreditSpecifications API operation for Amazon Elastic Compute Cloud. +// +// Describes the credit option for CPU usage of one or more of your T2 instances. +// The credit options are standard and unlimited. +// +// If you do not specify an instance ID, Amazon EC2 returns only the T2 instances +// with the unlimited credit option. If you specify one or more instance IDs, +// Amazon EC2 returns the credit option (standard or unlimited) of those instances. +// If you specify an instance ID that is not valid, such as an instance that +// is not a T2 instance, an error is returned. +// +// Recently terminated instances might appear in the returned results. This +// interval is usually less than one hour. +// +// If an Availability Zone is experiencing a service disruption and you specify +// instance IDs in the affected zone, or do not specify any instance IDs at +// all, the call fails. If you specify only instance IDs in an unaffected zone, +// the call works normally. +// +// For more information, see T2 Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-instances.html) +// in the Amazon Elastic Compute Cloud User Guide. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeInstanceCreditSpecifications for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceCreditSpecifications +func (c *EC2) DescribeInstanceCreditSpecifications(input *DescribeInstanceCreditSpecificationsInput) (*DescribeInstanceCreditSpecificationsOutput, error) { + req, out := c.DescribeInstanceCreditSpecificationsRequest(input) + return out, req.Send() +} + +// DescribeInstanceCreditSpecificationsWithContext is the same as DescribeInstanceCreditSpecifications with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeInstanceCreditSpecifications for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeInstanceCreditSpecificationsWithContext(ctx aws.Context, input *DescribeInstanceCreditSpecificationsInput, opts ...request.Option) (*DescribeInstanceCreditSpecificationsOutput, error) { + req, out := c.DescribeInstanceCreditSpecificationsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDescribeInstanceStatus = "DescribeInstanceStatus" // DescribeInstanceStatusRequest generates a "aws/request.Request" representing the // client's request for the DescribeInstanceStatus operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeInstanceStatus for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeInstanceStatus method directly -// instead. +// See DescribeInstanceStatus for more information on using the DescribeInstanceStatus +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeInstanceStatusRequest method. // req, resp := client.DescribeInstanceStatusRequest(params) @@ -9276,7 +10288,7 @@ const opDescribeInstanceStatus = "DescribeInstanceStatus" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatus func (c *EC2) DescribeInstanceStatusRequest(input *DescribeInstanceStatusInput) (req *request.Request, output *DescribeInstanceStatusOutput) { op := &request.Operation{ Name: opDescribeInstanceStatus, @@ -9330,7 +10342,7 @@ func (c *EC2) DescribeInstanceStatusRequest(input *DescribeInstanceStatusInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeInstanceStatus for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatus func (c *EC2) DescribeInstanceStatus(input *DescribeInstanceStatusInput) (*DescribeInstanceStatusOutput, error) { req, out := c.DescribeInstanceStatusRequest(input) return out, req.Send() @@ -9406,19 +10418,18 @@ const opDescribeInstances = "DescribeInstances" // DescribeInstancesRequest generates a "aws/request.Request" representing the // client's request for the DescribeInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeInstances method directly -// instead. +// See DescribeInstances for more information on using the DescribeInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeInstancesRequest method. // req, resp := client.DescribeInstancesRequest(params) @@ -9428,7 +10439,7 @@ const opDescribeInstances = "DescribeInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstances func (c *EC2) DescribeInstancesRequest(input *DescribeInstancesInput) (req *request.Request, output *DescribeInstancesOutput) { op := &request.Operation{ Name: opDescribeInstances, @@ -9476,7 +10487,7 @@ func (c *EC2) DescribeInstancesRequest(input *DescribeInstancesInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstances func (c *EC2) DescribeInstances(input *DescribeInstancesInput) (*DescribeInstancesOutput, error) { req, out := c.DescribeInstancesRequest(input) return out, req.Send() @@ -9552,19 +10563,18 @@ const opDescribeInternetGateways = "DescribeInternetGateways" // DescribeInternetGatewaysRequest generates a "aws/request.Request" representing the // client's request for the DescribeInternetGateways operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeInternetGateways for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeInternetGateways method directly -// instead. +// See DescribeInternetGateways for more information on using the DescribeInternetGateways +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeInternetGatewaysRequest method. // req, resp := client.DescribeInternetGatewaysRequest(params) @@ -9574,7 +10584,7 @@ const opDescribeInternetGateways = "DescribeInternetGateways" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGateways func (c *EC2) DescribeInternetGatewaysRequest(input *DescribeInternetGatewaysInput) (req *request.Request, output *DescribeInternetGatewaysOutput) { op := &request.Operation{ Name: opDescribeInternetGateways, @@ -9601,7 +10611,7 @@ func (c *EC2) DescribeInternetGatewaysRequest(input *DescribeInternetGatewaysInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeInternetGateways for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGateways func (c *EC2) DescribeInternetGateways(input *DescribeInternetGatewaysInput) (*DescribeInternetGatewaysOutput, error) { req, out := c.DescribeInternetGatewaysRequest(input) return out, req.Send() @@ -9627,19 +10637,18 @@ const opDescribeKeyPairs = "DescribeKeyPairs" // DescribeKeyPairsRequest generates a "aws/request.Request" representing the // client's request for the DescribeKeyPairs operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeKeyPairs for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeKeyPairs method directly -// instead. +// See DescribeKeyPairs for more information on using the DescribeKeyPairs +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeKeyPairsRequest method. // req, resp := client.DescribeKeyPairsRequest(params) @@ -9649,7 +10658,7 @@ const opDescribeKeyPairs = "DescribeKeyPairs" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairs func (c *EC2) DescribeKeyPairsRequest(input *DescribeKeyPairsInput) (req *request.Request, output *DescribeKeyPairsOutput) { op := &request.Operation{ Name: opDescribeKeyPairs, @@ -9679,7 +10688,7 @@ func (c *EC2) DescribeKeyPairsRequest(input *DescribeKeyPairsInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeKeyPairs for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairs func (c *EC2) DescribeKeyPairs(input *DescribeKeyPairsInput) (*DescribeKeyPairsOutput, error) { req, out := c.DescribeKeyPairsRequest(input) return out, req.Send() @@ -9701,23 +10710,171 @@ func (c *EC2) DescribeKeyPairsWithContext(ctx aws.Context, input *DescribeKeyPai return out, req.Send() } +const opDescribeLaunchTemplateVersions = "DescribeLaunchTemplateVersions" + +// DescribeLaunchTemplateVersionsRequest generates a "aws/request.Request" representing the +// client's request for the DescribeLaunchTemplateVersions operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeLaunchTemplateVersions for more information on using the DescribeLaunchTemplateVersions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeLaunchTemplateVersionsRequest method. +// req, resp := client.DescribeLaunchTemplateVersionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplateVersions +func (c *EC2) DescribeLaunchTemplateVersionsRequest(input *DescribeLaunchTemplateVersionsInput) (req *request.Request, output *DescribeLaunchTemplateVersionsOutput) { + op := &request.Operation{ + Name: opDescribeLaunchTemplateVersions, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeLaunchTemplateVersionsInput{} + } + + output = &DescribeLaunchTemplateVersionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeLaunchTemplateVersions API operation for Amazon Elastic Compute Cloud. +// +// Describes one or more versions of a specified launch template. You can describe +// all versions, individual versions, or a range of versions. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeLaunchTemplateVersions for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplateVersions +func (c *EC2) DescribeLaunchTemplateVersions(input *DescribeLaunchTemplateVersionsInput) (*DescribeLaunchTemplateVersionsOutput, error) { + req, out := c.DescribeLaunchTemplateVersionsRequest(input) + return out, req.Send() +} + +// DescribeLaunchTemplateVersionsWithContext is the same as DescribeLaunchTemplateVersions with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeLaunchTemplateVersions for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeLaunchTemplateVersionsWithContext(ctx aws.Context, input *DescribeLaunchTemplateVersionsInput, opts ...request.Option) (*DescribeLaunchTemplateVersionsOutput, error) { + req, out := c.DescribeLaunchTemplateVersionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opDescribeLaunchTemplates = "DescribeLaunchTemplates" + +// DescribeLaunchTemplatesRequest generates a "aws/request.Request" representing the +// client's request for the DescribeLaunchTemplates operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeLaunchTemplates for more information on using the DescribeLaunchTemplates +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeLaunchTemplatesRequest method. +// req, resp := client.DescribeLaunchTemplatesRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplates +func (c *EC2) DescribeLaunchTemplatesRequest(input *DescribeLaunchTemplatesInput) (req *request.Request, output *DescribeLaunchTemplatesOutput) { + op := &request.Operation{ + Name: opDescribeLaunchTemplates, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeLaunchTemplatesInput{} + } + + output = &DescribeLaunchTemplatesOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeLaunchTemplates API operation for Amazon Elastic Compute Cloud. +// +// Describes one or more launch templates. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeLaunchTemplates for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplates +func (c *EC2) DescribeLaunchTemplates(input *DescribeLaunchTemplatesInput) (*DescribeLaunchTemplatesOutput, error) { + req, out := c.DescribeLaunchTemplatesRequest(input) + return out, req.Send() +} + +// DescribeLaunchTemplatesWithContext is the same as DescribeLaunchTemplates with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeLaunchTemplates for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeLaunchTemplatesWithContext(ctx aws.Context, input *DescribeLaunchTemplatesInput, opts ...request.Option) (*DescribeLaunchTemplatesOutput, error) { + req, out := c.DescribeLaunchTemplatesRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDescribeMovingAddresses = "DescribeMovingAddresses" // DescribeMovingAddressesRequest generates a "aws/request.Request" representing the // client's request for the DescribeMovingAddresses operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeMovingAddresses for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeMovingAddresses method directly -// instead. +// See DescribeMovingAddresses for more information on using the DescribeMovingAddresses +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeMovingAddressesRequest method. // req, resp := client.DescribeMovingAddressesRequest(params) @@ -9727,7 +10884,7 @@ const opDescribeMovingAddresses = "DescribeMovingAddresses" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddresses func (c *EC2) DescribeMovingAddressesRequest(input *DescribeMovingAddressesInput) (req *request.Request, output *DescribeMovingAddressesOutput) { op := &request.Operation{ Name: opDescribeMovingAddresses, @@ -9756,7 +10913,7 @@ func (c *EC2) DescribeMovingAddressesRequest(input *DescribeMovingAddressesInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeMovingAddresses for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddresses func (c *EC2) DescribeMovingAddresses(input *DescribeMovingAddressesInput) (*DescribeMovingAddressesOutput, error) { req, out := c.DescribeMovingAddressesRequest(input) return out, req.Send() @@ -9782,19 +10939,18 @@ const opDescribeNatGateways = "DescribeNatGateways" // DescribeNatGatewaysRequest generates a "aws/request.Request" representing the // client's request for the DescribeNatGateways operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeNatGateways for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeNatGateways method directly -// instead. +// See DescribeNatGateways for more information on using the DescribeNatGateways +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeNatGatewaysRequest method. // req, resp := client.DescribeNatGatewaysRequest(params) @@ -9804,7 +10960,7 @@ const opDescribeNatGateways = "DescribeNatGateways" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGateways func (c *EC2) DescribeNatGatewaysRequest(input *DescribeNatGatewaysInput) (req *request.Request, output *DescribeNatGatewaysOutput) { op := &request.Operation{ Name: opDescribeNatGateways, @@ -9837,7 +10993,7 @@ func (c *EC2) DescribeNatGatewaysRequest(input *DescribeNatGatewaysInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeNatGateways for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGateways func (c *EC2) DescribeNatGateways(input *DescribeNatGatewaysInput) (*DescribeNatGatewaysOutput, error) { req, out := c.DescribeNatGatewaysRequest(input) return out, req.Send() @@ -9913,19 +11069,18 @@ const opDescribeNetworkAcls = "DescribeNetworkAcls" // DescribeNetworkAclsRequest generates a "aws/request.Request" representing the // client's request for the DescribeNetworkAcls operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeNetworkAcls for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeNetworkAcls method directly -// instead. +// See DescribeNetworkAcls for more information on using the DescribeNetworkAcls +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeNetworkAclsRequest method. // req, resp := client.DescribeNetworkAclsRequest(params) @@ -9935,7 +11090,7 @@ const opDescribeNetworkAcls = "DescribeNetworkAcls" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAcls +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAcls func (c *EC2) DescribeNetworkAclsRequest(input *DescribeNetworkAclsInput) (req *request.Request, output *DescribeNetworkAclsOutput) { op := &request.Operation{ Name: opDescribeNetworkAcls, @@ -9965,7 +11120,7 @@ func (c *EC2) DescribeNetworkAclsRequest(input *DescribeNetworkAclsInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeNetworkAcls for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAcls +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAcls func (c *EC2) DescribeNetworkAcls(input *DescribeNetworkAclsInput) (*DescribeNetworkAclsOutput, error) { req, out := c.DescribeNetworkAclsRequest(input) return out, req.Send() @@ -9991,19 +11146,18 @@ const opDescribeNetworkInterfaceAttribute = "DescribeNetworkInterfaceAttribute" // DescribeNetworkInterfaceAttributeRequest generates a "aws/request.Request" representing the // client's request for the DescribeNetworkInterfaceAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeNetworkInterfaceAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeNetworkInterfaceAttribute method directly -// instead. +// See DescribeNetworkInterfaceAttribute for more information on using the DescribeNetworkInterfaceAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeNetworkInterfaceAttributeRequest method. // req, resp := client.DescribeNetworkInterfaceAttributeRequest(params) @@ -10013,7 +11167,7 @@ const opDescribeNetworkInterfaceAttribute = "DescribeNetworkInterfaceAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttribute func (c *EC2) DescribeNetworkInterfaceAttributeRequest(input *DescribeNetworkInterfaceAttributeInput) (req *request.Request, output *DescribeNetworkInterfaceAttributeOutput) { op := &request.Operation{ Name: opDescribeNetworkInterfaceAttribute, @@ -10041,7 +11195,7 @@ func (c *EC2) DescribeNetworkInterfaceAttributeRequest(input *DescribeNetworkInt // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeNetworkInterfaceAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttribute func (c *EC2) DescribeNetworkInterfaceAttribute(input *DescribeNetworkInterfaceAttributeInput) (*DescribeNetworkInterfaceAttributeOutput, error) { req, out := c.DescribeNetworkInterfaceAttributeRequest(input) return out, req.Send() @@ -10067,19 +11221,18 @@ const opDescribeNetworkInterfacePermissions = "DescribeNetworkInterfacePermissio // DescribeNetworkInterfacePermissionsRequest generates a "aws/request.Request" representing the // client's request for the DescribeNetworkInterfacePermissions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeNetworkInterfacePermissions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeNetworkInterfacePermissions method directly -// instead. +// See DescribeNetworkInterfacePermissions for more information on using the DescribeNetworkInterfacePermissions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeNetworkInterfacePermissionsRequest method. // req, resp := client.DescribeNetworkInterfacePermissionsRequest(params) @@ -10089,7 +11242,7 @@ const opDescribeNetworkInterfacePermissions = "DescribeNetworkInterfacePermissio // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissions func (c *EC2) DescribeNetworkInterfacePermissionsRequest(input *DescribeNetworkInterfacePermissionsInput) (req *request.Request, output *DescribeNetworkInterfacePermissionsOutput) { op := &request.Operation{ Name: opDescribeNetworkInterfacePermissions, @@ -10116,7 +11269,7 @@ func (c *EC2) DescribeNetworkInterfacePermissionsRequest(input *DescribeNetworkI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeNetworkInterfacePermissions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissions func (c *EC2) DescribeNetworkInterfacePermissions(input *DescribeNetworkInterfacePermissionsInput) (*DescribeNetworkInterfacePermissionsOutput, error) { req, out := c.DescribeNetworkInterfacePermissionsRequest(input) return out, req.Send() @@ -10142,19 +11295,18 @@ const opDescribeNetworkInterfaces = "DescribeNetworkInterfaces" // DescribeNetworkInterfacesRequest generates a "aws/request.Request" representing the // client's request for the DescribeNetworkInterfaces operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeNetworkInterfaces for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeNetworkInterfaces method directly -// instead. +// See DescribeNetworkInterfaces for more information on using the DescribeNetworkInterfaces +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeNetworkInterfacesRequest method. // req, resp := client.DescribeNetworkInterfacesRequest(params) @@ -10164,7 +11316,7 @@ const opDescribeNetworkInterfaces = "DescribeNetworkInterfaces" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaces +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaces func (c *EC2) DescribeNetworkInterfacesRequest(input *DescribeNetworkInterfacesInput) (req *request.Request, output *DescribeNetworkInterfacesOutput) { op := &request.Operation{ Name: opDescribeNetworkInterfaces, @@ -10191,7 +11343,7 @@ func (c *EC2) DescribeNetworkInterfacesRequest(input *DescribeNetworkInterfacesI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeNetworkInterfaces for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaces +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaces func (c *EC2) DescribeNetworkInterfaces(input *DescribeNetworkInterfacesInput) (*DescribeNetworkInterfacesOutput, error) { req, out := c.DescribeNetworkInterfacesRequest(input) return out, req.Send() @@ -10217,19 +11369,18 @@ const opDescribePlacementGroups = "DescribePlacementGroups" // DescribePlacementGroupsRequest generates a "aws/request.Request" representing the // client's request for the DescribePlacementGroups operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribePlacementGroups for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribePlacementGroups method directly -// instead. +// See DescribePlacementGroups for more information on using the DescribePlacementGroups +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribePlacementGroupsRequest method. // req, resp := client.DescribePlacementGroupsRequest(params) @@ -10239,7 +11390,7 @@ const opDescribePlacementGroups = "DescribePlacementGroups" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroups +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroups func (c *EC2) DescribePlacementGroupsRequest(input *DescribePlacementGroupsInput) (req *request.Request, output *DescribePlacementGroupsOutput) { op := &request.Operation{ Name: opDescribePlacementGroups, @@ -10258,8 +11409,8 @@ func (c *EC2) DescribePlacementGroupsRequest(input *DescribePlacementGroupsInput // DescribePlacementGroups API operation for Amazon Elastic Compute Cloud. // -// Describes one or more of your placement groups. For more information about -// placement groups and cluster instances, see Cluster Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using_cluster_computing.html) +// Describes one or more of your placement groups. For more information, see +// Placement Groups (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -10268,7 +11419,7 @@ func (c *EC2) DescribePlacementGroupsRequest(input *DescribePlacementGroupsInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribePlacementGroups for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroups +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroups func (c *EC2) DescribePlacementGroups(input *DescribePlacementGroupsInput) (*DescribePlacementGroupsOutput, error) { req, out := c.DescribePlacementGroupsRequest(input) return out, req.Send() @@ -10294,19 +11445,18 @@ const opDescribePrefixLists = "DescribePrefixLists" // DescribePrefixListsRequest generates a "aws/request.Request" representing the // client's request for the DescribePrefixLists operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribePrefixLists for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribePrefixLists method directly -// instead. +// See DescribePrefixLists for more information on using the DescribePrefixLists +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribePrefixListsRequest method. // req, resp := client.DescribePrefixListsRequest(params) @@ -10316,7 +11466,7 @@ const opDescribePrefixLists = "DescribePrefixLists" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixLists +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixLists func (c *EC2) DescribePrefixListsRequest(input *DescribePrefixListsInput) (req *request.Request, output *DescribePrefixListsOutput) { op := &request.Operation{ Name: opDescribePrefixLists, @@ -10339,7 +11489,7 @@ func (c *EC2) DescribePrefixListsRequest(input *DescribePrefixListsInput) (req * // the prefix list name and prefix list ID of the service and the IP address // range for the service. A prefix list ID is required for creating an outbound // security group rule that allows traffic from a VPC to access an AWS service -// through a VPC endpoint. +// through a gateway VPC endpoint. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -10347,7 +11497,7 @@ func (c *EC2) DescribePrefixListsRequest(input *DescribePrefixListsInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribePrefixLists for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixLists +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixLists func (c *EC2) DescribePrefixLists(input *DescribePrefixListsInput) (*DescribePrefixListsOutput, error) { req, out := c.DescribePrefixListsRequest(input) return out, req.Send() @@ -10373,19 +11523,18 @@ const opDescribeRegions = "DescribeRegions" // DescribeRegionsRequest generates a "aws/request.Request" representing the // client's request for the DescribeRegions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeRegions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeRegions method directly -// instead. +// See DescribeRegions for more information on using the DescribeRegions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeRegionsRequest method. // req, resp := client.DescribeRegionsRequest(params) @@ -10395,7 +11544,7 @@ const opDescribeRegions = "DescribeRegions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegions func (c *EC2) DescribeRegionsRequest(input *DescribeRegionsInput) (req *request.Request, output *DescribeRegionsOutput) { op := &request.Operation{ Name: opDescribeRegions, @@ -10425,7 +11574,7 @@ func (c *EC2) DescribeRegionsRequest(input *DescribeRegionsInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeRegions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegions func (c *EC2) DescribeRegions(input *DescribeRegionsInput) (*DescribeRegionsOutput, error) { req, out := c.DescribeRegionsRequest(input) return out, req.Send() @@ -10451,19 +11600,18 @@ const opDescribeReservedInstances = "DescribeReservedInstances" // DescribeReservedInstancesRequest generates a "aws/request.Request" representing the // client's request for the DescribeReservedInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeReservedInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeReservedInstances method directly -// instead. +// See DescribeReservedInstances for more information on using the DescribeReservedInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeReservedInstancesRequest method. // req, resp := client.DescribeReservedInstancesRequest(params) @@ -10473,7 +11621,7 @@ const opDescribeReservedInstances = "DescribeReservedInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstances func (c *EC2) DescribeReservedInstancesRequest(input *DescribeReservedInstancesInput) (req *request.Request, output *DescribeReservedInstancesOutput) { op := &request.Operation{ Name: opDescribeReservedInstances, @@ -10503,7 +11651,7 @@ func (c *EC2) DescribeReservedInstancesRequest(input *DescribeReservedInstancesI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeReservedInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstances func (c *EC2) DescribeReservedInstances(input *DescribeReservedInstancesInput) (*DescribeReservedInstancesOutput, error) { req, out := c.DescribeReservedInstancesRequest(input) return out, req.Send() @@ -10529,19 +11677,18 @@ const opDescribeReservedInstancesListings = "DescribeReservedInstancesListings" // DescribeReservedInstancesListingsRequest generates a "aws/request.Request" representing the // client's request for the DescribeReservedInstancesListings operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeReservedInstancesListings for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeReservedInstancesListings method directly -// instead. +// See DescribeReservedInstancesListings for more information on using the DescribeReservedInstancesListings +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeReservedInstancesListingsRequest method. // req, resp := client.DescribeReservedInstancesListingsRequest(params) @@ -10551,7 +11698,7 @@ const opDescribeReservedInstancesListings = "DescribeReservedInstancesListings" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListings +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListings func (c *EC2) DescribeReservedInstancesListingsRequest(input *DescribeReservedInstancesListingsInput) (req *request.Request, output *DescribeReservedInstancesListingsOutput) { op := &request.Operation{ Name: opDescribeReservedInstancesListings, @@ -10599,7 +11746,7 @@ func (c *EC2) DescribeReservedInstancesListingsRequest(input *DescribeReservedIn // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeReservedInstancesListings for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListings +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListings func (c *EC2) DescribeReservedInstancesListings(input *DescribeReservedInstancesListingsInput) (*DescribeReservedInstancesListingsOutput, error) { req, out := c.DescribeReservedInstancesListingsRequest(input) return out, req.Send() @@ -10625,19 +11772,18 @@ const opDescribeReservedInstancesModifications = "DescribeReservedInstancesModif // DescribeReservedInstancesModificationsRequest generates a "aws/request.Request" representing the // client's request for the DescribeReservedInstancesModifications operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeReservedInstancesModifications for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeReservedInstancesModifications method directly -// instead. +// See DescribeReservedInstancesModifications for more information on using the DescribeReservedInstancesModifications +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeReservedInstancesModificationsRequest method. // req, resp := client.DescribeReservedInstancesModificationsRequest(params) @@ -10647,7 +11793,7 @@ const opDescribeReservedInstancesModifications = "DescribeReservedInstancesModif // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModifications +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModifications func (c *EC2) DescribeReservedInstancesModificationsRequest(input *DescribeReservedInstancesModificationsInput) (req *request.Request, output *DescribeReservedInstancesModificationsOutput) { op := &request.Operation{ Name: opDescribeReservedInstancesModifications, @@ -10686,7 +11832,7 @@ func (c *EC2) DescribeReservedInstancesModificationsRequest(input *DescribeReser // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeReservedInstancesModifications for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModifications +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModifications func (c *EC2) DescribeReservedInstancesModifications(input *DescribeReservedInstancesModificationsInput) (*DescribeReservedInstancesModificationsOutput, error) { req, out := c.DescribeReservedInstancesModificationsRequest(input) return out, req.Send() @@ -10762,19 +11908,18 @@ const opDescribeReservedInstancesOfferings = "DescribeReservedInstancesOfferings // DescribeReservedInstancesOfferingsRequest generates a "aws/request.Request" representing the // client's request for the DescribeReservedInstancesOfferings operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeReservedInstancesOfferings for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeReservedInstancesOfferings method directly -// instead. +// See DescribeReservedInstancesOfferings for more information on using the DescribeReservedInstancesOfferings +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeReservedInstancesOfferingsRequest method. // req, resp := client.DescribeReservedInstancesOfferingsRequest(params) @@ -10784,7 +11929,7 @@ const opDescribeReservedInstancesOfferings = "DescribeReservedInstancesOfferings // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferings +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferings func (c *EC2) DescribeReservedInstancesOfferingsRequest(input *DescribeReservedInstancesOfferingsInput) (req *request.Request, output *DescribeReservedInstancesOfferingsOutput) { op := &request.Operation{ Name: opDescribeReservedInstancesOfferings, @@ -10828,7 +11973,7 @@ func (c *EC2) DescribeReservedInstancesOfferingsRequest(input *DescribeReservedI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeReservedInstancesOfferings for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferings +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferings func (c *EC2) DescribeReservedInstancesOfferings(input *DescribeReservedInstancesOfferingsInput) (*DescribeReservedInstancesOfferingsOutput, error) { req, out := c.DescribeReservedInstancesOfferingsRequest(input) return out, req.Send() @@ -10904,19 +12049,18 @@ const opDescribeRouteTables = "DescribeRouteTables" // DescribeRouteTablesRequest generates a "aws/request.Request" representing the // client's request for the DescribeRouteTables operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeRouteTables for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeRouteTables method directly -// instead. +// See DescribeRouteTables for more information on using the DescribeRouteTables +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeRouteTablesRequest method. // req, resp := client.DescribeRouteTablesRequest(params) @@ -10926,7 +12070,7 @@ const opDescribeRouteTables = "DescribeRouteTables" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTables +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTables func (c *EC2) DescribeRouteTablesRequest(input *DescribeRouteTablesInput) (req *request.Request, output *DescribeRouteTablesOutput) { op := &request.Operation{ Name: opDescribeRouteTables, @@ -10961,7 +12105,7 @@ func (c *EC2) DescribeRouteTablesRequest(input *DescribeRouteTablesInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeRouteTables for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTables +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTables func (c *EC2) DescribeRouteTables(input *DescribeRouteTablesInput) (*DescribeRouteTablesOutput, error) { req, out := c.DescribeRouteTablesRequest(input) return out, req.Send() @@ -10987,19 +12131,18 @@ const opDescribeScheduledInstanceAvailability = "DescribeScheduledInstanceAvaila // DescribeScheduledInstanceAvailabilityRequest generates a "aws/request.Request" representing the // client's request for the DescribeScheduledInstanceAvailability operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeScheduledInstanceAvailability for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeScheduledInstanceAvailability method directly -// instead. +// See DescribeScheduledInstanceAvailability for more information on using the DescribeScheduledInstanceAvailability +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeScheduledInstanceAvailabilityRequest method. // req, resp := client.DescribeScheduledInstanceAvailabilityRequest(params) @@ -11009,7 +12152,7 @@ const opDescribeScheduledInstanceAvailability = "DescribeScheduledInstanceAvaila // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailability +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailability func (c *EC2) DescribeScheduledInstanceAvailabilityRequest(input *DescribeScheduledInstanceAvailabilityInput) (req *request.Request, output *DescribeScheduledInstanceAvailabilityOutput) { op := &request.Operation{ Name: opDescribeScheduledInstanceAvailability, @@ -11044,7 +12187,7 @@ func (c *EC2) DescribeScheduledInstanceAvailabilityRequest(input *DescribeSchedu // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeScheduledInstanceAvailability for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailability +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailability func (c *EC2) DescribeScheduledInstanceAvailability(input *DescribeScheduledInstanceAvailabilityInput) (*DescribeScheduledInstanceAvailabilityOutput, error) { req, out := c.DescribeScheduledInstanceAvailabilityRequest(input) return out, req.Send() @@ -11070,19 +12213,18 @@ const opDescribeScheduledInstances = "DescribeScheduledInstances" // DescribeScheduledInstancesRequest generates a "aws/request.Request" representing the // client's request for the DescribeScheduledInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeScheduledInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeScheduledInstances method directly -// instead. +// See DescribeScheduledInstances for more information on using the DescribeScheduledInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeScheduledInstancesRequest method. // req, resp := client.DescribeScheduledInstancesRequest(params) @@ -11092,7 +12234,7 @@ const opDescribeScheduledInstances = "DescribeScheduledInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstances func (c *EC2) DescribeScheduledInstancesRequest(input *DescribeScheduledInstancesInput) (req *request.Request, output *DescribeScheduledInstancesOutput) { op := &request.Operation{ Name: opDescribeScheduledInstances, @@ -11119,7 +12261,7 @@ func (c *EC2) DescribeScheduledInstancesRequest(input *DescribeScheduledInstance // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeScheduledInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstances func (c *EC2) DescribeScheduledInstances(input *DescribeScheduledInstancesInput) (*DescribeScheduledInstancesOutput, error) { req, out := c.DescribeScheduledInstancesRequest(input) return out, req.Send() @@ -11145,19 +12287,18 @@ const opDescribeSecurityGroupReferences = "DescribeSecurityGroupReferences" // DescribeSecurityGroupReferencesRequest generates a "aws/request.Request" representing the // client's request for the DescribeSecurityGroupReferences operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSecurityGroupReferences for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSecurityGroupReferences method directly -// instead. +// See DescribeSecurityGroupReferences for more information on using the DescribeSecurityGroupReferences +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSecurityGroupReferencesRequest method. // req, resp := client.DescribeSecurityGroupReferencesRequest(params) @@ -11167,7 +12308,7 @@ const opDescribeSecurityGroupReferences = "DescribeSecurityGroupReferences" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferences +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferences func (c *EC2) DescribeSecurityGroupReferencesRequest(input *DescribeSecurityGroupReferencesInput) (req *request.Request, output *DescribeSecurityGroupReferencesOutput) { op := &request.Operation{ Name: opDescribeSecurityGroupReferences, @@ -11195,7 +12336,7 @@ func (c *EC2) DescribeSecurityGroupReferencesRequest(input *DescribeSecurityGrou // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSecurityGroupReferences for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferences +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferences func (c *EC2) DescribeSecurityGroupReferences(input *DescribeSecurityGroupReferencesInput) (*DescribeSecurityGroupReferencesOutput, error) { req, out := c.DescribeSecurityGroupReferencesRequest(input) return out, req.Send() @@ -11221,19 +12362,18 @@ const opDescribeSecurityGroups = "DescribeSecurityGroups" // DescribeSecurityGroupsRequest generates a "aws/request.Request" representing the // client's request for the DescribeSecurityGroups operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSecurityGroups for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSecurityGroups method directly -// instead. +// See DescribeSecurityGroups for more information on using the DescribeSecurityGroups +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSecurityGroupsRequest method. // req, resp := client.DescribeSecurityGroupsRequest(params) @@ -11243,7 +12383,7 @@ const opDescribeSecurityGroups = "DescribeSecurityGroups" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroups +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroups func (c *EC2) DescribeSecurityGroupsRequest(input *DescribeSecurityGroupsInput) (req *request.Request, output *DescribeSecurityGroupsOutput) { op := &request.Operation{ Name: opDescribeSecurityGroups, @@ -11277,7 +12417,7 @@ func (c *EC2) DescribeSecurityGroupsRequest(input *DescribeSecurityGroupsInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSecurityGroups for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroups +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroups func (c *EC2) DescribeSecurityGroups(input *DescribeSecurityGroupsInput) (*DescribeSecurityGroupsOutput, error) { req, out := c.DescribeSecurityGroupsRequest(input) return out, req.Send() @@ -11303,19 +12443,18 @@ const opDescribeSnapshotAttribute = "DescribeSnapshotAttribute" // DescribeSnapshotAttributeRequest generates a "aws/request.Request" representing the // client's request for the DescribeSnapshotAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSnapshotAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSnapshotAttribute method directly -// instead. +// See DescribeSnapshotAttribute for more information on using the DescribeSnapshotAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSnapshotAttributeRequest method. // req, resp := client.DescribeSnapshotAttributeRequest(params) @@ -11325,7 +12464,7 @@ const opDescribeSnapshotAttribute = "DescribeSnapshotAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttribute func (c *EC2) DescribeSnapshotAttributeRequest(input *DescribeSnapshotAttributeInput) (req *request.Request, output *DescribeSnapshotAttributeOutput) { op := &request.Operation{ Name: opDescribeSnapshotAttribute, @@ -11356,7 +12495,7 @@ func (c *EC2) DescribeSnapshotAttributeRequest(input *DescribeSnapshotAttributeI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSnapshotAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttribute func (c *EC2) DescribeSnapshotAttribute(input *DescribeSnapshotAttributeInput) (*DescribeSnapshotAttributeOutput, error) { req, out := c.DescribeSnapshotAttributeRequest(input) return out, req.Send() @@ -11382,19 +12521,18 @@ const opDescribeSnapshots = "DescribeSnapshots" // DescribeSnapshotsRequest generates a "aws/request.Request" representing the // client's request for the DescribeSnapshots operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSnapshots for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSnapshots method directly -// instead. +// See DescribeSnapshots for more information on using the DescribeSnapshots +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSnapshotsRequest method. // req, resp := client.DescribeSnapshotsRequest(params) @@ -11404,7 +12542,7 @@ const opDescribeSnapshots = "DescribeSnapshots" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshots +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshots func (c *EC2) DescribeSnapshotsRequest(input *DescribeSnapshotsInput) (req *request.Request, output *DescribeSnapshotsOutput) { op := &request.Operation{ Name: opDescribeSnapshots, @@ -11482,7 +12620,7 @@ func (c *EC2) DescribeSnapshotsRequest(input *DescribeSnapshotsInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSnapshots for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshots +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshots func (c *EC2) DescribeSnapshots(input *DescribeSnapshotsInput) (*DescribeSnapshotsOutput, error) { req, out := c.DescribeSnapshotsRequest(input) return out, req.Send() @@ -11558,19 +12696,18 @@ const opDescribeSpotDatafeedSubscription = "DescribeSpotDatafeedSubscription" // DescribeSpotDatafeedSubscriptionRequest generates a "aws/request.Request" representing the // client's request for the DescribeSpotDatafeedSubscription operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSpotDatafeedSubscription for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSpotDatafeedSubscription method directly -// instead. +// See DescribeSpotDatafeedSubscription for more information on using the DescribeSpotDatafeedSubscription +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSpotDatafeedSubscriptionRequest method. // req, resp := client.DescribeSpotDatafeedSubscriptionRequest(params) @@ -11580,7 +12717,7 @@ const opDescribeSpotDatafeedSubscription = "DescribeSpotDatafeedSubscription" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscription func (c *EC2) DescribeSpotDatafeedSubscriptionRequest(input *DescribeSpotDatafeedSubscriptionInput) (req *request.Request, output *DescribeSpotDatafeedSubscriptionOutput) { op := &request.Operation{ Name: opDescribeSpotDatafeedSubscription, @@ -11599,7 +12736,7 @@ func (c *EC2) DescribeSpotDatafeedSubscriptionRequest(input *DescribeSpotDatafee // DescribeSpotDatafeedSubscription API operation for Amazon Elastic Compute Cloud. // -// Describes the data feed for Spot instances. For more information, see Spot +// Describes the data feed for Spot Instances. For more information, see Spot // Instance Data Feed (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-data-feeds.html) // in the Amazon Elastic Compute Cloud User Guide. // @@ -11609,7 +12746,7 @@ func (c *EC2) DescribeSpotDatafeedSubscriptionRequest(input *DescribeSpotDatafee // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSpotDatafeedSubscription for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscription func (c *EC2) DescribeSpotDatafeedSubscription(input *DescribeSpotDatafeedSubscriptionInput) (*DescribeSpotDatafeedSubscriptionOutput, error) { req, out := c.DescribeSpotDatafeedSubscriptionRequest(input) return out, req.Send() @@ -11635,19 +12772,18 @@ const opDescribeSpotFleetInstances = "DescribeSpotFleetInstances" // DescribeSpotFleetInstancesRequest generates a "aws/request.Request" representing the // client's request for the DescribeSpotFleetInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSpotFleetInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSpotFleetInstances method directly -// instead. +// See DescribeSpotFleetInstances for more information on using the DescribeSpotFleetInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSpotFleetInstancesRequest method. // req, resp := client.DescribeSpotFleetInstancesRequest(params) @@ -11657,7 +12793,7 @@ const opDescribeSpotFleetInstances = "DescribeSpotFleetInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstances func (c *EC2) DescribeSpotFleetInstancesRequest(input *DescribeSpotFleetInstancesInput) (req *request.Request, output *DescribeSpotFleetInstancesOutput) { op := &request.Operation{ Name: opDescribeSpotFleetInstances, @@ -11676,7 +12812,7 @@ func (c *EC2) DescribeSpotFleetInstancesRequest(input *DescribeSpotFleetInstance // DescribeSpotFleetInstances API operation for Amazon Elastic Compute Cloud. // -// Describes the running instances for the specified Spot fleet. +// Describes the running instances for the specified Spot Fleet. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -11684,7 +12820,7 @@ func (c *EC2) DescribeSpotFleetInstancesRequest(input *DescribeSpotFleetInstance // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSpotFleetInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstances func (c *EC2) DescribeSpotFleetInstances(input *DescribeSpotFleetInstancesInput) (*DescribeSpotFleetInstancesOutput, error) { req, out := c.DescribeSpotFleetInstancesRequest(input) return out, req.Send() @@ -11710,19 +12846,18 @@ const opDescribeSpotFleetRequestHistory = "DescribeSpotFleetRequestHistory" // DescribeSpotFleetRequestHistoryRequest generates a "aws/request.Request" representing the // client's request for the DescribeSpotFleetRequestHistory operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSpotFleetRequestHistory for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSpotFleetRequestHistory method directly -// instead. +// See DescribeSpotFleetRequestHistory for more information on using the DescribeSpotFleetRequestHistory +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSpotFleetRequestHistoryRequest method. // req, resp := client.DescribeSpotFleetRequestHistoryRequest(params) @@ -11732,7 +12867,7 @@ const opDescribeSpotFleetRequestHistory = "DescribeSpotFleetRequestHistory" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistory +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistory func (c *EC2) DescribeSpotFleetRequestHistoryRequest(input *DescribeSpotFleetRequestHistoryInput) (req *request.Request, output *DescribeSpotFleetRequestHistoryOutput) { op := &request.Operation{ Name: opDescribeSpotFleetRequestHistory, @@ -11751,10 +12886,10 @@ func (c *EC2) DescribeSpotFleetRequestHistoryRequest(input *DescribeSpotFleetReq // DescribeSpotFleetRequestHistory API operation for Amazon Elastic Compute Cloud. // -// Describes the events for the specified Spot fleet request during the specified +// Describes the events for the specified Spot Fleet request during the specified // time. // -// Spot fleet events are delayed by up to 30 seconds before they can be described. +// Spot Fleet events are delayed by up to 30 seconds before they can be described. // This ensures that you can query by the last evaluated time and not miss a // recorded event. // @@ -11764,7 +12899,7 @@ func (c *EC2) DescribeSpotFleetRequestHistoryRequest(input *DescribeSpotFleetReq // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSpotFleetRequestHistory for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistory +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistory func (c *EC2) DescribeSpotFleetRequestHistory(input *DescribeSpotFleetRequestHistoryInput) (*DescribeSpotFleetRequestHistoryOutput, error) { req, out := c.DescribeSpotFleetRequestHistoryRequest(input) return out, req.Send() @@ -11790,19 +12925,18 @@ const opDescribeSpotFleetRequests = "DescribeSpotFleetRequests" // DescribeSpotFleetRequestsRequest generates a "aws/request.Request" representing the // client's request for the DescribeSpotFleetRequests operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSpotFleetRequests for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSpotFleetRequests method directly -// instead. +// See DescribeSpotFleetRequests for more information on using the DescribeSpotFleetRequests +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSpotFleetRequestsRequest method. // req, resp := client.DescribeSpotFleetRequestsRequest(params) @@ -11812,7 +12946,7 @@ const opDescribeSpotFleetRequests = "DescribeSpotFleetRequests" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequests func (c *EC2) DescribeSpotFleetRequestsRequest(input *DescribeSpotFleetRequestsInput) (req *request.Request, output *DescribeSpotFleetRequestsOutput) { op := &request.Operation{ Name: opDescribeSpotFleetRequests, @@ -11837,9 +12971,9 @@ func (c *EC2) DescribeSpotFleetRequestsRequest(input *DescribeSpotFleetRequestsI // DescribeSpotFleetRequests API operation for Amazon Elastic Compute Cloud. // -// Describes your Spot fleet requests. +// Describes your Spot Fleet requests. // -// Spot fleet requests are deleted 48 hours after they are canceled and their +// Spot Fleet requests are deleted 48 hours after they are canceled and their // instances are terminated. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -11848,7 +12982,7 @@ func (c *EC2) DescribeSpotFleetRequestsRequest(input *DescribeSpotFleetRequestsI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSpotFleetRequests for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequests func (c *EC2) DescribeSpotFleetRequests(input *DescribeSpotFleetRequestsInput) (*DescribeSpotFleetRequestsOutput, error) { req, out := c.DescribeSpotFleetRequestsRequest(input) return out, req.Send() @@ -11924,19 +13058,18 @@ const opDescribeSpotInstanceRequests = "DescribeSpotInstanceRequests" // DescribeSpotInstanceRequestsRequest generates a "aws/request.Request" representing the // client's request for the DescribeSpotInstanceRequests operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSpotInstanceRequests for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSpotInstanceRequests method directly -// instead. +// See DescribeSpotInstanceRequests for more information on using the DescribeSpotInstanceRequests +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSpotInstanceRequestsRequest method. // req, resp := client.DescribeSpotInstanceRequestsRequest(params) @@ -11946,7 +13079,7 @@ const opDescribeSpotInstanceRequests = "DescribeSpotInstanceRequests" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequests func (c *EC2) DescribeSpotInstanceRequestsRequest(input *DescribeSpotInstanceRequestsInput) (req *request.Request, output *DescribeSpotInstanceRequestsOutput) { op := &request.Operation{ Name: opDescribeSpotInstanceRequests, @@ -11965,20 +13098,19 @@ func (c *EC2) DescribeSpotInstanceRequestsRequest(input *DescribeSpotInstanceReq // DescribeSpotInstanceRequests API operation for Amazon Elastic Compute Cloud. // -// Describes the Spot instance requests that belong to your account. Spot instances -// are instances that Amazon EC2 launches when the bid price that you specify -// exceeds the current Spot price. Amazon EC2 periodically sets the Spot price -// based on available Spot instance capacity and current Spot instance requests. -// For more information, see Spot Instance Requests (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html) -// in the Amazon Elastic Compute Cloud User Guide. +// Describes the Spot Instance requests that belong to your account. Spot Instances +// are instances that Amazon EC2 launches when the Spot price that you specify +// exceeds the current Spot price. For more information, see Spot Instance Requests +// (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html) in +// the Amazon Elastic Compute Cloud User Guide. // -// You can use DescribeSpotInstanceRequests to find a running Spot instance -// by examining the response. If the status of the Spot instance is fulfilled, +// You can use DescribeSpotInstanceRequests to find a running Spot Instance +// by examining the response. If the status of the Spot Instance is fulfilled, // the instance ID appears in the response and contains the identifier of the // instance. Alternatively, you can use DescribeInstances with a filter to look // for instances where the instance lifecycle is spot. // -// Spot instance requests are deleted 4 hours after they are canceled and their +// Spot Instance requests are deleted 4 hours after they are canceled and their // instances are terminated. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -11987,7 +13119,7 @@ func (c *EC2) DescribeSpotInstanceRequestsRequest(input *DescribeSpotInstanceReq // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSpotInstanceRequests for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequests +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequests func (c *EC2) DescribeSpotInstanceRequests(input *DescribeSpotInstanceRequestsInput) (*DescribeSpotInstanceRequestsOutput, error) { req, out := c.DescribeSpotInstanceRequestsRequest(input) return out, req.Send() @@ -12013,19 +13145,18 @@ const opDescribeSpotPriceHistory = "DescribeSpotPriceHistory" // DescribeSpotPriceHistoryRequest generates a "aws/request.Request" representing the // client's request for the DescribeSpotPriceHistory operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSpotPriceHistory for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSpotPriceHistory method directly -// instead. +// See DescribeSpotPriceHistory for more information on using the DescribeSpotPriceHistory +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSpotPriceHistoryRequest method. // req, resp := client.DescribeSpotPriceHistoryRequest(params) @@ -12035,7 +13166,7 @@ const opDescribeSpotPriceHistory = "DescribeSpotPriceHistory" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistory +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistory func (c *EC2) DescribeSpotPriceHistoryRequest(input *DescribeSpotPriceHistoryInput) (req *request.Request, output *DescribeSpotPriceHistoryOutput) { op := &request.Operation{ Name: opDescribeSpotPriceHistory, @@ -12075,7 +13206,7 @@ func (c *EC2) DescribeSpotPriceHistoryRequest(input *DescribeSpotPriceHistoryInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSpotPriceHistory for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistory +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistory func (c *EC2) DescribeSpotPriceHistory(input *DescribeSpotPriceHistoryInput) (*DescribeSpotPriceHistoryOutput, error) { req, out := c.DescribeSpotPriceHistoryRequest(input) return out, req.Send() @@ -12151,19 +13282,18 @@ const opDescribeStaleSecurityGroups = "DescribeStaleSecurityGroups" // DescribeStaleSecurityGroupsRequest generates a "aws/request.Request" representing the // client's request for the DescribeStaleSecurityGroups operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeStaleSecurityGroups for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeStaleSecurityGroups method directly -// instead. +// See DescribeStaleSecurityGroups for more information on using the DescribeStaleSecurityGroups +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeStaleSecurityGroupsRequest method. // req, resp := client.DescribeStaleSecurityGroupsRequest(params) @@ -12173,7 +13303,7 @@ const opDescribeStaleSecurityGroups = "DescribeStaleSecurityGroups" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroups +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroups func (c *EC2) DescribeStaleSecurityGroupsRequest(input *DescribeStaleSecurityGroupsInput) (req *request.Request, output *DescribeStaleSecurityGroupsOutput) { op := &request.Operation{ Name: opDescribeStaleSecurityGroups, @@ -12203,7 +13333,7 @@ func (c *EC2) DescribeStaleSecurityGroupsRequest(input *DescribeStaleSecurityGro // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeStaleSecurityGroups for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroups +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroups func (c *EC2) DescribeStaleSecurityGroups(input *DescribeStaleSecurityGroupsInput) (*DescribeStaleSecurityGroupsOutput, error) { req, out := c.DescribeStaleSecurityGroupsRequest(input) return out, req.Send() @@ -12229,19 +13359,18 @@ const opDescribeSubnets = "DescribeSubnets" // DescribeSubnetsRequest generates a "aws/request.Request" representing the // client's request for the DescribeSubnets operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeSubnets for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeSubnets method directly -// instead. +// See DescribeSubnets for more information on using the DescribeSubnets +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeSubnetsRequest method. // req, resp := client.DescribeSubnetsRequest(params) @@ -12251,7 +13380,7 @@ const opDescribeSubnets = "DescribeSubnets" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnets +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnets func (c *EC2) DescribeSubnetsRequest(input *DescribeSubnetsInput) (req *request.Request, output *DescribeSubnetsOutput) { op := &request.Operation{ Name: opDescribeSubnets, @@ -12281,7 +13410,7 @@ func (c *EC2) DescribeSubnetsRequest(input *DescribeSubnetsInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeSubnets for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnets +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnets func (c *EC2) DescribeSubnets(input *DescribeSubnetsInput) (*DescribeSubnetsOutput, error) { req, out := c.DescribeSubnetsRequest(input) return out, req.Send() @@ -12307,19 +13436,18 @@ const opDescribeTags = "DescribeTags" // DescribeTagsRequest generates a "aws/request.Request" representing the // client's request for the DescribeTags operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeTags for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeTags method directly -// instead. +// See DescribeTags for more information on using the DescribeTags +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeTagsRequest method. // req, resp := client.DescribeTagsRequest(params) @@ -12329,7 +13457,7 @@ const opDescribeTags = "DescribeTags" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTags +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTags func (c *EC2) DescribeTagsRequest(input *DescribeTagsInput) (req *request.Request, output *DescribeTagsOutput) { op := &request.Operation{ Name: opDescribeTags, @@ -12365,7 +13493,7 @@ func (c *EC2) DescribeTagsRequest(input *DescribeTagsInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeTags for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTags +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTags func (c *EC2) DescribeTags(input *DescribeTagsInput) (*DescribeTagsOutput, error) { req, out := c.DescribeTagsRequest(input) return out, req.Send() @@ -12441,19 +13569,18 @@ const opDescribeVolumeAttribute = "DescribeVolumeAttribute" // DescribeVolumeAttributeRequest generates a "aws/request.Request" representing the // client's request for the DescribeVolumeAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVolumeAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVolumeAttribute method directly -// instead. +// See DescribeVolumeAttribute for more information on using the DescribeVolumeAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVolumeAttributeRequest method. // req, resp := client.DescribeVolumeAttributeRequest(params) @@ -12463,7 +13590,7 @@ const opDescribeVolumeAttribute = "DescribeVolumeAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttribute func (c *EC2) DescribeVolumeAttributeRequest(input *DescribeVolumeAttributeInput) (req *request.Request, output *DescribeVolumeAttributeOutput) { op := &request.Operation{ Name: opDescribeVolumeAttribute, @@ -12494,7 +13621,7 @@ func (c *EC2) DescribeVolumeAttributeRequest(input *DescribeVolumeAttributeInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVolumeAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttribute func (c *EC2) DescribeVolumeAttribute(input *DescribeVolumeAttributeInput) (*DescribeVolumeAttributeOutput, error) { req, out := c.DescribeVolumeAttributeRequest(input) return out, req.Send() @@ -12520,19 +13647,18 @@ const opDescribeVolumeStatus = "DescribeVolumeStatus" // DescribeVolumeStatusRequest generates a "aws/request.Request" representing the // client's request for the DescribeVolumeStatus operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVolumeStatus for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVolumeStatus method directly -// instead. +// See DescribeVolumeStatus for more information on using the DescribeVolumeStatus +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVolumeStatusRequest method. // req, resp := client.DescribeVolumeStatusRequest(params) @@ -12542,7 +13668,7 @@ const opDescribeVolumeStatus = "DescribeVolumeStatus" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatus func (c *EC2) DescribeVolumeStatusRequest(input *DescribeVolumeStatusInput) (req *request.Request, output *DescribeVolumeStatusOutput) { op := &request.Operation{ Name: opDescribeVolumeStatus, @@ -12609,7 +13735,7 @@ func (c *EC2) DescribeVolumeStatusRequest(input *DescribeVolumeStatusInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVolumeStatus for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatus func (c *EC2) DescribeVolumeStatus(input *DescribeVolumeStatusInput) (*DescribeVolumeStatusOutput, error) { req, out := c.DescribeVolumeStatusRequest(input) return out, req.Send() @@ -12685,19 +13811,18 @@ const opDescribeVolumes = "DescribeVolumes" // DescribeVolumesRequest generates a "aws/request.Request" representing the // client's request for the DescribeVolumes operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVolumes for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVolumes method directly -// instead. +// See DescribeVolumes for more information on using the DescribeVolumes +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVolumesRequest method. // req, resp := client.DescribeVolumesRequest(params) @@ -12707,7 +13832,7 @@ const opDescribeVolumes = "DescribeVolumes" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumes +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumes func (c *EC2) DescribeVolumesRequest(input *DescribeVolumesInput) (req *request.Request, output *DescribeVolumesOutput) { op := &request.Operation{ Name: opDescribeVolumes, @@ -12750,7 +13875,7 @@ func (c *EC2) DescribeVolumesRequest(input *DescribeVolumesInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVolumes for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumes +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumes func (c *EC2) DescribeVolumes(input *DescribeVolumesInput) (*DescribeVolumesOutput, error) { req, out := c.DescribeVolumesRequest(input) return out, req.Send() @@ -12826,19 +13951,18 @@ const opDescribeVolumesModifications = "DescribeVolumesModifications" // DescribeVolumesModificationsRequest generates a "aws/request.Request" representing the // client's request for the DescribeVolumesModifications operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVolumesModifications for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVolumesModifications method directly -// instead. +// See DescribeVolumesModifications for more information on using the DescribeVolumesModifications +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVolumesModificationsRequest method. // req, resp := client.DescribeVolumesModificationsRequest(params) @@ -12848,7 +13972,7 @@ const opDescribeVolumesModifications = "DescribeVolumesModifications" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModifications +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModifications func (c *EC2) DescribeVolumesModificationsRequest(input *DescribeVolumesModificationsInput) (req *request.Request, output *DescribeVolumesModificationsOutput) { op := &request.Operation{ Name: opDescribeVolumesModifications, @@ -12887,7 +14011,7 @@ func (c *EC2) DescribeVolumesModificationsRequest(input *DescribeVolumesModifica // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVolumesModifications for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModifications +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModifications func (c *EC2) DescribeVolumesModifications(input *DescribeVolumesModificationsInput) (*DescribeVolumesModificationsOutput, error) { req, out := c.DescribeVolumesModificationsRequest(input) return out, req.Send() @@ -12913,19 +14037,18 @@ const opDescribeVpcAttribute = "DescribeVpcAttribute" // DescribeVpcAttributeRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcAttribute method directly -// instead. +// See DescribeVpcAttribute for more information on using the DescribeVpcAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcAttributeRequest method. // req, resp := client.DescribeVpcAttributeRequest(params) @@ -12935,7 +14058,7 @@ const opDescribeVpcAttribute = "DescribeVpcAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttribute func (c *EC2) DescribeVpcAttributeRequest(input *DescribeVpcAttributeInput) (req *request.Request, output *DescribeVpcAttributeOutput) { op := &request.Operation{ Name: opDescribeVpcAttribute, @@ -12963,7 +14086,7 @@ func (c *EC2) DescribeVpcAttributeRequest(input *DescribeVpcAttributeInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttribute func (c *EC2) DescribeVpcAttribute(input *DescribeVpcAttributeInput) (*DescribeVpcAttributeOutput, error) { req, out := c.DescribeVpcAttributeRequest(input) return out, req.Send() @@ -12989,19 +14112,18 @@ const opDescribeVpcClassicLink = "DescribeVpcClassicLink" // DescribeVpcClassicLinkRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcClassicLink operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcClassicLink for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcClassicLink method directly -// instead. +// See DescribeVpcClassicLink for more information on using the DescribeVpcClassicLink +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcClassicLinkRequest method. // req, resp := client.DescribeVpcClassicLinkRequest(params) @@ -13011,7 +14133,7 @@ const opDescribeVpcClassicLink = "DescribeVpcClassicLink" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLink func (c *EC2) DescribeVpcClassicLinkRequest(input *DescribeVpcClassicLinkInput) (req *request.Request, output *DescribeVpcClassicLinkOutput) { op := &request.Operation{ Name: opDescribeVpcClassicLink, @@ -13038,7 +14160,7 @@ func (c *EC2) DescribeVpcClassicLinkRequest(input *DescribeVpcClassicLinkInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcClassicLink for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLink func (c *EC2) DescribeVpcClassicLink(input *DescribeVpcClassicLinkInput) (*DescribeVpcClassicLinkOutput, error) { req, out := c.DescribeVpcClassicLinkRequest(input) return out, req.Send() @@ -13064,19 +14186,18 @@ const opDescribeVpcClassicLinkDnsSupport = "DescribeVpcClassicLinkDnsSupport" // DescribeVpcClassicLinkDnsSupportRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcClassicLinkDnsSupport operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcClassicLinkDnsSupport for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcClassicLinkDnsSupport method directly -// instead. +// See DescribeVpcClassicLinkDnsSupport for more information on using the DescribeVpcClassicLinkDnsSupport +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcClassicLinkDnsSupportRequest method. // req, resp := client.DescribeVpcClassicLinkDnsSupportRequest(params) @@ -13086,7 +14207,7 @@ const opDescribeVpcClassicLinkDnsSupport = "DescribeVpcClassicLinkDnsSupport" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupport func (c *EC2) DescribeVpcClassicLinkDnsSupportRequest(input *DescribeVpcClassicLinkDnsSupportInput) (req *request.Request, output *DescribeVpcClassicLinkDnsSupportOutput) { op := &request.Operation{ Name: opDescribeVpcClassicLinkDnsSupport, @@ -13119,7 +14240,7 @@ func (c *EC2) DescribeVpcClassicLinkDnsSupportRequest(input *DescribeVpcClassicL // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcClassicLinkDnsSupport for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupport func (c *EC2) DescribeVpcClassicLinkDnsSupport(input *DescribeVpcClassicLinkDnsSupportInput) (*DescribeVpcClassicLinkDnsSupportOutput, error) { req, out := c.DescribeVpcClassicLinkDnsSupportRequest(input) return out, req.Send() @@ -13141,23 +14262,321 @@ func (c *EC2) DescribeVpcClassicLinkDnsSupportWithContext(ctx aws.Context, input return out, req.Send() } +const opDescribeVpcEndpointConnectionNotifications = "DescribeVpcEndpointConnectionNotifications" + +// DescribeVpcEndpointConnectionNotificationsRequest generates a "aws/request.Request" representing the +// client's request for the DescribeVpcEndpointConnectionNotifications operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeVpcEndpointConnectionNotifications for more information on using the DescribeVpcEndpointConnectionNotifications +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeVpcEndpointConnectionNotificationsRequest method. +// req, resp := client.DescribeVpcEndpointConnectionNotificationsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnectionNotifications +func (c *EC2) DescribeVpcEndpointConnectionNotificationsRequest(input *DescribeVpcEndpointConnectionNotificationsInput) (req *request.Request, output *DescribeVpcEndpointConnectionNotificationsOutput) { + op := &request.Operation{ + Name: opDescribeVpcEndpointConnectionNotifications, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeVpcEndpointConnectionNotificationsInput{} + } + + output = &DescribeVpcEndpointConnectionNotificationsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeVpcEndpointConnectionNotifications API operation for Amazon Elastic Compute Cloud. +// +// Describes the connection notifications for VPC endpoints and VPC endpoint +// services. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeVpcEndpointConnectionNotifications for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnectionNotifications +func (c *EC2) DescribeVpcEndpointConnectionNotifications(input *DescribeVpcEndpointConnectionNotificationsInput) (*DescribeVpcEndpointConnectionNotificationsOutput, error) { + req, out := c.DescribeVpcEndpointConnectionNotificationsRequest(input) + return out, req.Send() +} + +// DescribeVpcEndpointConnectionNotificationsWithContext is the same as DescribeVpcEndpointConnectionNotifications with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeVpcEndpointConnectionNotifications for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeVpcEndpointConnectionNotificationsWithContext(ctx aws.Context, input *DescribeVpcEndpointConnectionNotificationsInput, opts ...request.Option) (*DescribeVpcEndpointConnectionNotificationsOutput, error) { + req, out := c.DescribeVpcEndpointConnectionNotificationsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opDescribeVpcEndpointConnections = "DescribeVpcEndpointConnections" + +// DescribeVpcEndpointConnectionsRequest generates a "aws/request.Request" representing the +// client's request for the DescribeVpcEndpointConnections operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeVpcEndpointConnections for more information on using the DescribeVpcEndpointConnections +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeVpcEndpointConnectionsRequest method. +// req, resp := client.DescribeVpcEndpointConnectionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnections +func (c *EC2) DescribeVpcEndpointConnectionsRequest(input *DescribeVpcEndpointConnectionsInput) (req *request.Request, output *DescribeVpcEndpointConnectionsOutput) { + op := &request.Operation{ + Name: opDescribeVpcEndpointConnections, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeVpcEndpointConnectionsInput{} + } + + output = &DescribeVpcEndpointConnectionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeVpcEndpointConnections API operation for Amazon Elastic Compute Cloud. +// +// Describes the VPC endpoint connections to your VPC endpoint services, including +// any endpoints that are pending your acceptance. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeVpcEndpointConnections for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnections +func (c *EC2) DescribeVpcEndpointConnections(input *DescribeVpcEndpointConnectionsInput) (*DescribeVpcEndpointConnectionsOutput, error) { + req, out := c.DescribeVpcEndpointConnectionsRequest(input) + return out, req.Send() +} + +// DescribeVpcEndpointConnectionsWithContext is the same as DescribeVpcEndpointConnections with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeVpcEndpointConnections for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeVpcEndpointConnectionsWithContext(ctx aws.Context, input *DescribeVpcEndpointConnectionsInput, opts ...request.Option) (*DescribeVpcEndpointConnectionsOutput, error) { + req, out := c.DescribeVpcEndpointConnectionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opDescribeVpcEndpointServiceConfigurations = "DescribeVpcEndpointServiceConfigurations" + +// DescribeVpcEndpointServiceConfigurationsRequest generates a "aws/request.Request" representing the +// client's request for the DescribeVpcEndpointServiceConfigurations operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeVpcEndpointServiceConfigurations for more information on using the DescribeVpcEndpointServiceConfigurations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeVpcEndpointServiceConfigurationsRequest method. +// req, resp := client.DescribeVpcEndpointServiceConfigurationsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServiceConfigurations +func (c *EC2) DescribeVpcEndpointServiceConfigurationsRequest(input *DescribeVpcEndpointServiceConfigurationsInput) (req *request.Request, output *DescribeVpcEndpointServiceConfigurationsOutput) { + op := &request.Operation{ + Name: opDescribeVpcEndpointServiceConfigurations, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeVpcEndpointServiceConfigurationsInput{} + } + + output = &DescribeVpcEndpointServiceConfigurationsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeVpcEndpointServiceConfigurations API operation for Amazon Elastic Compute Cloud. +// +// Describes the VPC endpoint service configurations in your account (your services). +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeVpcEndpointServiceConfigurations for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServiceConfigurations +func (c *EC2) DescribeVpcEndpointServiceConfigurations(input *DescribeVpcEndpointServiceConfigurationsInput) (*DescribeVpcEndpointServiceConfigurationsOutput, error) { + req, out := c.DescribeVpcEndpointServiceConfigurationsRequest(input) + return out, req.Send() +} + +// DescribeVpcEndpointServiceConfigurationsWithContext is the same as DescribeVpcEndpointServiceConfigurations with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeVpcEndpointServiceConfigurations for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeVpcEndpointServiceConfigurationsWithContext(ctx aws.Context, input *DescribeVpcEndpointServiceConfigurationsInput, opts ...request.Option) (*DescribeVpcEndpointServiceConfigurationsOutput, error) { + req, out := c.DescribeVpcEndpointServiceConfigurationsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opDescribeVpcEndpointServicePermissions = "DescribeVpcEndpointServicePermissions" + +// DescribeVpcEndpointServicePermissionsRequest generates a "aws/request.Request" representing the +// client's request for the DescribeVpcEndpointServicePermissions operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DescribeVpcEndpointServicePermissions for more information on using the DescribeVpcEndpointServicePermissions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DescribeVpcEndpointServicePermissionsRequest method. +// req, resp := client.DescribeVpcEndpointServicePermissionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicePermissions +func (c *EC2) DescribeVpcEndpointServicePermissionsRequest(input *DescribeVpcEndpointServicePermissionsInput) (req *request.Request, output *DescribeVpcEndpointServicePermissionsOutput) { + op := &request.Operation{ + Name: opDescribeVpcEndpointServicePermissions, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &DescribeVpcEndpointServicePermissionsInput{} + } + + output = &DescribeVpcEndpointServicePermissionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// DescribeVpcEndpointServicePermissions API operation for Amazon Elastic Compute Cloud. +// +// Describes the principals (service consumers) that are permitted to discover +// your VPC endpoint service. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation DescribeVpcEndpointServicePermissions for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicePermissions +func (c *EC2) DescribeVpcEndpointServicePermissions(input *DescribeVpcEndpointServicePermissionsInput) (*DescribeVpcEndpointServicePermissionsOutput, error) { + req, out := c.DescribeVpcEndpointServicePermissionsRequest(input) + return out, req.Send() +} + +// DescribeVpcEndpointServicePermissionsWithContext is the same as DescribeVpcEndpointServicePermissions with the addition of +// the ability to pass a context and additional request options. +// +// See DescribeVpcEndpointServicePermissions for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) DescribeVpcEndpointServicePermissionsWithContext(ctx aws.Context, input *DescribeVpcEndpointServicePermissionsInput, opts ...request.Option) (*DescribeVpcEndpointServicePermissionsOutput, error) { + req, out := c.DescribeVpcEndpointServicePermissionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDescribeVpcEndpointServices = "DescribeVpcEndpointServices" // DescribeVpcEndpointServicesRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcEndpointServices operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcEndpointServices for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcEndpointServices method directly -// instead. +// See DescribeVpcEndpointServices for more information on using the DescribeVpcEndpointServices +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcEndpointServicesRequest method. // req, resp := client.DescribeVpcEndpointServicesRequest(params) @@ -13167,7 +14586,7 @@ const opDescribeVpcEndpointServices = "DescribeVpcEndpointServices" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServices +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServices func (c *EC2) DescribeVpcEndpointServicesRequest(input *DescribeVpcEndpointServicesInput) (req *request.Request, output *DescribeVpcEndpointServicesOutput) { op := &request.Operation{ Name: opDescribeVpcEndpointServices, @@ -13186,8 +14605,7 @@ func (c *EC2) DescribeVpcEndpointServicesRequest(input *DescribeVpcEndpointServi // DescribeVpcEndpointServices API operation for Amazon Elastic Compute Cloud. // -// Describes all supported AWS services that can be specified when creating -// a VPC endpoint. +// Describes available services to which you can create a VPC endpoint. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -13195,7 +14613,7 @@ func (c *EC2) DescribeVpcEndpointServicesRequest(input *DescribeVpcEndpointServi // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcEndpointServices for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServices +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServices func (c *EC2) DescribeVpcEndpointServices(input *DescribeVpcEndpointServicesInput) (*DescribeVpcEndpointServicesOutput, error) { req, out := c.DescribeVpcEndpointServicesRequest(input) return out, req.Send() @@ -13221,19 +14639,18 @@ const opDescribeVpcEndpoints = "DescribeVpcEndpoints" // DescribeVpcEndpointsRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcEndpoints operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcEndpoints for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcEndpoints method directly -// instead. +// See DescribeVpcEndpoints for more information on using the DescribeVpcEndpoints +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcEndpointsRequest method. // req, resp := client.DescribeVpcEndpointsRequest(params) @@ -13243,7 +14660,7 @@ const opDescribeVpcEndpoints = "DescribeVpcEndpoints" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpoints +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpoints func (c *EC2) DescribeVpcEndpointsRequest(input *DescribeVpcEndpointsInput) (req *request.Request, output *DescribeVpcEndpointsOutput) { op := &request.Operation{ Name: opDescribeVpcEndpoints, @@ -13270,7 +14687,7 @@ func (c *EC2) DescribeVpcEndpointsRequest(input *DescribeVpcEndpointsInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcEndpoints for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpoints +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpoints func (c *EC2) DescribeVpcEndpoints(input *DescribeVpcEndpointsInput) (*DescribeVpcEndpointsOutput, error) { req, out := c.DescribeVpcEndpointsRequest(input) return out, req.Send() @@ -13296,19 +14713,18 @@ const opDescribeVpcPeeringConnections = "DescribeVpcPeeringConnections" // DescribeVpcPeeringConnectionsRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcPeeringConnections operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcPeeringConnections for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcPeeringConnections method directly -// instead. +// See DescribeVpcPeeringConnections for more information on using the DescribeVpcPeeringConnections +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcPeeringConnectionsRequest method. // req, resp := client.DescribeVpcPeeringConnectionsRequest(params) @@ -13318,7 +14734,7 @@ const opDescribeVpcPeeringConnections = "DescribeVpcPeeringConnections" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnections +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnections func (c *EC2) DescribeVpcPeeringConnectionsRequest(input *DescribeVpcPeeringConnectionsInput) (req *request.Request, output *DescribeVpcPeeringConnectionsOutput) { op := &request.Operation{ Name: opDescribeVpcPeeringConnections, @@ -13345,7 +14761,7 @@ func (c *EC2) DescribeVpcPeeringConnectionsRequest(input *DescribeVpcPeeringConn // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcPeeringConnections for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnections +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnections func (c *EC2) DescribeVpcPeeringConnections(input *DescribeVpcPeeringConnectionsInput) (*DescribeVpcPeeringConnectionsOutput, error) { req, out := c.DescribeVpcPeeringConnectionsRequest(input) return out, req.Send() @@ -13371,19 +14787,18 @@ const opDescribeVpcs = "DescribeVpcs" // DescribeVpcsRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpcs operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpcs for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpcs method directly -// instead. +// See DescribeVpcs for more information on using the DescribeVpcs +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpcsRequest method. // req, resp := client.DescribeVpcsRequest(params) @@ -13393,7 +14808,7 @@ const opDescribeVpcs = "DescribeVpcs" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcs func (c *EC2) DescribeVpcsRequest(input *DescribeVpcsInput) (req *request.Request, output *DescribeVpcsOutput) { op := &request.Operation{ Name: opDescribeVpcs, @@ -13420,7 +14835,7 @@ func (c *EC2) DescribeVpcsRequest(input *DescribeVpcsInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpcs for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcs func (c *EC2) DescribeVpcs(input *DescribeVpcsInput) (*DescribeVpcsOutput, error) { req, out := c.DescribeVpcsRequest(input) return out, req.Send() @@ -13446,19 +14861,18 @@ const opDescribeVpnConnections = "DescribeVpnConnections" // DescribeVpnConnectionsRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpnConnections operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpnConnections for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpnConnections method directly -// instead. +// See DescribeVpnConnections for more information on using the DescribeVpnConnections +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpnConnectionsRequest method. // req, resp := client.DescribeVpnConnectionsRequest(params) @@ -13468,7 +14882,7 @@ const opDescribeVpnConnections = "DescribeVpnConnections" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnections +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnections func (c *EC2) DescribeVpnConnectionsRequest(input *DescribeVpnConnectionsInput) (req *request.Request, output *DescribeVpnConnectionsOutput) { op := &request.Operation{ Name: opDescribeVpnConnections, @@ -13489,9 +14903,9 @@ func (c *EC2) DescribeVpnConnectionsRequest(input *DescribeVpnConnectionsInput) // // Describes one or more of your VPN connections. // -// For more information about VPN connections, see Adding a Hardware Virtual -// Private Gateway to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) -// in the Amazon Virtual Private Cloud User Guide. +// For more information about VPN connections, see AWS Managed VPN Connections +// (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) in the +// Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -13499,7 +14913,7 @@ func (c *EC2) DescribeVpnConnectionsRequest(input *DescribeVpnConnectionsInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpnConnections for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnections +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnections func (c *EC2) DescribeVpnConnections(input *DescribeVpnConnectionsInput) (*DescribeVpnConnectionsOutput, error) { req, out := c.DescribeVpnConnectionsRequest(input) return out, req.Send() @@ -13525,19 +14939,18 @@ const opDescribeVpnGateways = "DescribeVpnGateways" // DescribeVpnGatewaysRequest generates a "aws/request.Request" representing the // client's request for the DescribeVpnGateways operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DescribeVpnGateways for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DescribeVpnGateways method directly -// instead. +// See DescribeVpnGateways for more information on using the DescribeVpnGateways +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DescribeVpnGatewaysRequest method. // req, resp := client.DescribeVpnGatewaysRequest(params) @@ -13547,7 +14960,7 @@ const opDescribeVpnGateways = "DescribeVpnGateways" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGateways func (c *EC2) DescribeVpnGatewaysRequest(input *DescribeVpnGatewaysInput) (req *request.Request, output *DescribeVpnGatewaysOutput) { op := &request.Operation{ Name: opDescribeVpnGateways, @@ -13568,8 +14981,8 @@ func (c *EC2) DescribeVpnGatewaysRequest(input *DescribeVpnGatewaysInput) (req * // // Describes one or more of your virtual private gateways. // -// For more information about virtual private gateways, see Adding an IPsec -// Hardware VPN to Your VPC (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) +// For more information about virtual private gateways, see AWS Managed VPN +// Connections (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html) // in the Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -13578,7 +14991,7 @@ func (c *EC2) DescribeVpnGatewaysRequest(input *DescribeVpnGatewaysInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DescribeVpnGateways for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGateways +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGateways func (c *EC2) DescribeVpnGateways(input *DescribeVpnGatewaysInput) (*DescribeVpnGatewaysOutput, error) { req, out := c.DescribeVpnGatewaysRequest(input) return out, req.Send() @@ -13604,19 +15017,18 @@ const opDetachClassicLinkVpc = "DetachClassicLinkVpc" // DetachClassicLinkVpcRequest generates a "aws/request.Request" representing the // client's request for the DetachClassicLinkVpc operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DetachClassicLinkVpc for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DetachClassicLinkVpc method directly -// instead. +// See DetachClassicLinkVpc for more information on using the DetachClassicLinkVpc +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DetachClassicLinkVpcRequest method. // req, resp := client.DetachClassicLinkVpcRequest(params) @@ -13626,7 +15038,7 @@ const opDetachClassicLinkVpc = "DetachClassicLinkVpc" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpc func (c *EC2) DetachClassicLinkVpcRequest(input *DetachClassicLinkVpcInput) (req *request.Request, output *DetachClassicLinkVpcOutput) { op := &request.Operation{ Name: opDetachClassicLinkVpc, @@ -13655,7 +15067,7 @@ func (c *EC2) DetachClassicLinkVpcRequest(input *DetachClassicLinkVpcInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DetachClassicLinkVpc for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpc func (c *EC2) DetachClassicLinkVpc(input *DetachClassicLinkVpcInput) (*DetachClassicLinkVpcOutput, error) { req, out := c.DetachClassicLinkVpcRequest(input) return out, req.Send() @@ -13681,19 +15093,18 @@ const opDetachInternetGateway = "DetachInternetGateway" // DetachInternetGatewayRequest generates a "aws/request.Request" representing the // client's request for the DetachInternetGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DetachInternetGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DetachInternetGateway method directly -// instead. +// See DetachInternetGateway for more information on using the DetachInternetGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DetachInternetGatewayRequest method. // req, resp := client.DetachInternetGatewayRequest(params) @@ -13703,7 +15114,7 @@ const opDetachInternetGateway = "DetachInternetGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGateway func (c *EC2) DetachInternetGatewayRequest(input *DetachInternetGatewayInput) (req *request.Request, output *DetachInternetGatewayOutput) { op := &request.Operation{ Name: opDetachInternetGateway, @@ -13734,7 +15145,7 @@ func (c *EC2) DetachInternetGatewayRequest(input *DetachInternetGatewayInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DetachInternetGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGateway func (c *EC2) DetachInternetGateway(input *DetachInternetGatewayInput) (*DetachInternetGatewayOutput, error) { req, out := c.DetachInternetGatewayRequest(input) return out, req.Send() @@ -13760,19 +15171,18 @@ const opDetachNetworkInterface = "DetachNetworkInterface" // DetachNetworkInterfaceRequest generates a "aws/request.Request" representing the // client's request for the DetachNetworkInterface operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DetachNetworkInterface for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DetachNetworkInterface method directly -// instead. +// See DetachNetworkInterface for more information on using the DetachNetworkInterface +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DetachNetworkInterfaceRequest method. // req, resp := client.DetachNetworkInterfaceRequest(params) @@ -13782,7 +15192,7 @@ const opDetachNetworkInterface = "DetachNetworkInterface" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterface func (c *EC2) DetachNetworkInterfaceRequest(input *DetachNetworkInterfaceInput) (req *request.Request, output *DetachNetworkInterfaceOutput) { op := &request.Operation{ Name: opDetachNetworkInterface, @@ -13811,7 +15221,7 @@ func (c *EC2) DetachNetworkInterfaceRequest(input *DetachNetworkInterfaceInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DetachNetworkInterface for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterface func (c *EC2) DetachNetworkInterface(input *DetachNetworkInterfaceInput) (*DetachNetworkInterfaceOutput, error) { req, out := c.DetachNetworkInterfaceRequest(input) return out, req.Send() @@ -13837,19 +15247,18 @@ const opDetachVolume = "DetachVolume" // DetachVolumeRequest generates a "aws/request.Request" representing the // client's request for the DetachVolume operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DetachVolume for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DetachVolume method directly -// instead. +// See DetachVolume for more information on using the DetachVolume +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DetachVolumeRequest method. // req, resp := client.DetachVolumeRequest(params) @@ -13859,7 +15268,7 @@ const opDetachVolume = "DetachVolume" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVolume func (c *EC2) DetachVolumeRequest(input *DetachVolumeInput) (req *request.Request, output *VolumeAttachment) { op := &request.Operation{ Name: opDetachVolume, @@ -13899,7 +15308,7 @@ func (c *EC2) DetachVolumeRequest(input *DetachVolumeInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DetachVolume for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVolume func (c *EC2) DetachVolume(input *DetachVolumeInput) (*VolumeAttachment, error) { req, out := c.DetachVolumeRequest(input) return out, req.Send() @@ -13925,19 +15334,18 @@ const opDetachVpnGateway = "DetachVpnGateway" // DetachVpnGatewayRequest generates a "aws/request.Request" representing the // client's request for the DetachVpnGateway operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DetachVpnGateway for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DetachVpnGateway method directly -// instead. +// See DetachVpnGateway for more information on using the DetachVpnGateway +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DetachVpnGatewayRequest method. // req, resp := client.DetachVpnGatewayRequest(params) @@ -13947,7 +15355,7 @@ const opDetachVpnGateway = "DetachVpnGateway" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGateway func (c *EC2) DetachVpnGatewayRequest(input *DetachVpnGatewayInput) (req *request.Request, output *DetachVpnGatewayOutput) { op := &request.Operation{ Name: opDetachVpnGateway, @@ -13983,7 +15391,7 @@ func (c *EC2) DetachVpnGatewayRequest(input *DetachVpnGatewayInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DetachVpnGateway for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGateway func (c *EC2) DetachVpnGateway(input *DetachVpnGatewayInput) (*DetachVpnGatewayOutput, error) { req, out := c.DetachVpnGatewayRequest(input) return out, req.Send() @@ -14009,19 +15417,18 @@ const opDisableVgwRoutePropagation = "DisableVgwRoutePropagation" // DisableVgwRoutePropagationRequest generates a "aws/request.Request" representing the // client's request for the DisableVgwRoutePropagation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisableVgwRoutePropagation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisableVgwRoutePropagation method directly -// instead. +// See DisableVgwRoutePropagation for more information on using the DisableVgwRoutePropagation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisableVgwRoutePropagationRequest method. // req, resp := client.DisableVgwRoutePropagationRequest(params) @@ -14031,7 +15438,7 @@ const opDisableVgwRoutePropagation = "DisableVgwRoutePropagation" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagation func (c *EC2) DisableVgwRoutePropagationRequest(input *DisableVgwRoutePropagationInput) (req *request.Request, output *DisableVgwRoutePropagationOutput) { op := &request.Operation{ Name: opDisableVgwRoutePropagation, @@ -14061,7 +15468,7 @@ func (c *EC2) DisableVgwRoutePropagationRequest(input *DisableVgwRoutePropagatio // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisableVgwRoutePropagation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagation func (c *EC2) DisableVgwRoutePropagation(input *DisableVgwRoutePropagationInput) (*DisableVgwRoutePropagationOutput, error) { req, out := c.DisableVgwRoutePropagationRequest(input) return out, req.Send() @@ -14087,19 +15494,18 @@ const opDisableVpcClassicLink = "DisableVpcClassicLink" // DisableVpcClassicLinkRequest generates a "aws/request.Request" representing the // client's request for the DisableVpcClassicLink operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisableVpcClassicLink for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisableVpcClassicLink method directly -// instead. +// See DisableVpcClassicLink for more information on using the DisableVpcClassicLink +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisableVpcClassicLinkRequest method. // req, resp := client.DisableVpcClassicLinkRequest(params) @@ -14109,7 +15515,7 @@ const opDisableVpcClassicLink = "DisableVpcClassicLink" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLink func (c *EC2) DisableVpcClassicLinkRequest(input *DisableVpcClassicLinkInput) (req *request.Request, output *DisableVpcClassicLinkOutput) { op := &request.Operation{ Name: opDisableVpcClassicLink, @@ -14137,7 +15543,7 @@ func (c *EC2) DisableVpcClassicLinkRequest(input *DisableVpcClassicLinkInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisableVpcClassicLink for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLink func (c *EC2) DisableVpcClassicLink(input *DisableVpcClassicLinkInput) (*DisableVpcClassicLinkOutput, error) { req, out := c.DisableVpcClassicLinkRequest(input) return out, req.Send() @@ -14163,19 +15569,18 @@ const opDisableVpcClassicLinkDnsSupport = "DisableVpcClassicLinkDnsSupport" // DisableVpcClassicLinkDnsSupportRequest generates a "aws/request.Request" representing the // client's request for the DisableVpcClassicLinkDnsSupport operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisableVpcClassicLinkDnsSupport for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisableVpcClassicLinkDnsSupport method directly -// instead. +// See DisableVpcClassicLinkDnsSupport for more information on using the DisableVpcClassicLinkDnsSupport +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisableVpcClassicLinkDnsSupportRequest method. // req, resp := client.DisableVpcClassicLinkDnsSupportRequest(params) @@ -14185,7 +15590,7 @@ const opDisableVpcClassicLinkDnsSupport = "DisableVpcClassicLinkDnsSupport" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupport func (c *EC2) DisableVpcClassicLinkDnsSupportRequest(input *DisableVpcClassicLinkDnsSupportInput) (req *request.Request, output *DisableVpcClassicLinkDnsSupportOutput) { op := &request.Operation{ Name: opDisableVpcClassicLinkDnsSupport, @@ -14216,7 +15621,7 @@ func (c *EC2) DisableVpcClassicLinkDnsSupportRequest(input *DisableVpcClassicLin // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisableVpcClassicLinkDnsSupport for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupport func (c *EC2) DisableVpcClassicLinkDnsSupport(input *DisableVpcClassicLinkDnsSupportInput) (*DisableVpcClassicLinkDnsSupportOutput, error) { req, out := c.DisableVpcClassicLinkDnsSupportRequest(input) return out, req.Send() @@ -14242,19 +15647,18 @@ const opDisassociateAddress = "DisassociateAddress" // DisassociateAddressRequest generates a "aws/request.Request" representing the // client's request for the DisassociateAddress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisassociateAddress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisassociateAddress method directly -// instead. +// See DisassociateAddress for more information on using the DisassociateAddress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisassociateAddressRequest method. // req, resp := client.DisassociateAddressRequest(params) @@ -14264,7 +15668,7 @@ const opDisassociateAddress = "DisassociateAddress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddress func (c *EC2) DisassociateAddressRequest(input *DisassociateAddressInput) (req *request.Request, output *DisassociateAddressOutput) { op := &request.Operation{ Name: opDisassociateAddress, @@ -14301,7 +15705,7 @@ func (c *EC2) DisassociateAddressRequest(input *DisassociateAddressInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisassociateAddress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddress func (c *EC2) DisassociateAddress(input *DisassociateAddressInput) (*DisassociateAddressOutput, error) { req, out := c.DisassociateAddressRequest(input) return out, req.Send() @@ -14327,19 +15731,18 @@ const opDisassociateIamInstanceProfile = "DisassociateIamInstanceProfile" // DisassociateIamInstanceProfileRequest generates a "aws/request.Request" representing the // client's request for the DisassociateIamInstanceProfile operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisassociateIamInstanceProfile for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisassociateIamInstanceProfile method directly -// instead. +// See DisassociateIamInstanceProfile for more information on using the DisassociateIamInstanceProfile +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisassociateIamInstanceProfileRequest method. // req, resp := client.DisassociateIamInstanceProfileRequest(params) @@ -14349,7 +15752,7 @@ const opDisassociateIamInstanceProfile = "DisassociateIamInstanceProfile" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfile +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfile func (c *EC2) DisassociateIamInstanceProfileRequest(input *DisassociateIamInstanceProfileInput) (req *request.Request, output *DisassociateIamInstanceProfileOutput) { op := &request.Operation{ Name: opDisassociateIamInstanceProfile, @@ -14378,7 +15781,7 @@ func (c *EC2) DisassociateIamInstanceProfileRequest(input *DisassociateIamInstan // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisassociateIamInstanceProfile for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfile +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfile func (c *EC2) DisassociateIamInstanceProfile(input *DisassociateIamInstanceProfileInput) (*DisassociateIamInstanceProfileOutput, error) { req, out := c.DisassociateIamInstanceProfileRequest(input) return out, req.Send() @@ -14404,19 +15807,18 @@ const opDisassociateRouteTable = "DisassociateRouteTable" // DisassociateRouteTableRequest generates a "aws/request.Request" representing the // client's request for the DisassociateRouteTable operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisassociateRouteTable for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisassociateRouteTable method directly -// instead. +// See DisassociateRouteTable for more information on using the DisassociateRouteTable +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisassociateRouteTableRequest method. // req, resp := client.DisassociateRouteTableRequest(params) @@ -14426,7 +15828,7 @@ const opDisassociateRouteTable = "DisassociateRouteTable" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTable func (c *EC2) DisassociateRouteTableRequest(input *DisassociateRouteTableInput) (req *request.Request, output *DisassociateRouteTableOutput) { op := &request.Operation{ Name: opDisassociateRouteTable, @@ -14460,7 +15862,7 @@ func (c *EC2) DisassociateRouteTableRequest(input *DisassociateRouteTableInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisassociateRouteTable for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTable func (c *EC2) DisassociateRouteTable(input *DisassociateRouteTableInput) (*DisassociateRouteTableOutput, error) { req, out := c.DisassociateRouteTableRequest(input) return out, req.Send() @@ -14486,19 +15888,18 @@ const opDisassociateSubnetCidrBlock = "DisassociateSubnetCidrBlock" // DisassociateSubnetCidrBlockRequest generates a "aws/request.Request" representing the // client's request for the DisassociateSubnetCidrBlock operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisassociateSubnetCidrBlock for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisassociateSubnetCidrBlock method directly -// instead. +// See DisassociateSubnetCidrBlock for more information on using the DisassociateSubnetCidrBlock +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisassociateSubnetCidrBlockRequest method. // req, resp := client.DisassociateSubnetCidrBlockRequest(params) @@ -14508,7 +15909,7 @@ const opDisassociateSubnetCidrBlock = "DisassociateSubnetCidrBlock" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlock func (c *EC2) DisassociateSubnetCidrBlockRequest(input *DisassociateSubnetCidrBlockInput) (req *request.Request, output *DisassociateSubnetCidrBlockOutput) { op := &request.Operation{ Name: opDisassociateSubnetCidrBlock, @@ -14537,7 +15938,7 @@ func (c *EC2) DisassociateSubnetCidrBlockRequest(input *DisassociateSubnetCidrBl // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisassociateSubnetCidrBlock for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlock func (c *EC2) DisassociateSubnetCidrBlock(input *DisassociateSubnetCidrBlockInput) (*DisassociateSubnetCidrBlockOutput, error) { req, out := c.DisassociateSubnetCidrBlockRequest(input) return out, req.Send() @@ -14563,19 +15964,18 @@ const opDisassociateVpcCidrBlock = "DisassociateVpcCidrBlock" // DisassociateVpcCidrBlockRequest generates a "aws/request.Request" representing the // client's request for the DisassociateVpcCidrBlock operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DisassociateVpcCidrBlock for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DisassociateVpcCidrBlock method directly -// instead. +// See DisassociateVpcCidrBlock for more information on using the DisassociateVpcCidrBlock +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DisassociateVpcCidrBlockRequest method. // req, resp := client.DisassociateVpcCidrBlockRequest(params) @@ -14585,7 +15985,7 @@ const opDisassociateVpcCidrBlock = "DisassociateVpcCidrBlock" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlock func (c *EC2) DisassociateVpcCidrBlockRequest(input *DisassociateVpcCidrBlockInput) (req *request.Request, output *DisassociateVpcCidrBlockOutput) { op := &request.Operation{ Name: opDisassociateVpcCidrBlock, @@ -14604,9 +16004,13 @@ func (c *EC2) DisassociateVpcCidrBlockRequest(input *DisassociateVpcCidrBlockInp // DisassociateVpcCidrBlock API operation for Amazon Elastic Compute Cloud. // -// Disassociates a CIDR block from a VPC. Currently, you can disassociate an -// IPv6 CIDR block only. You must detach or delete all gateways and resources -// that are associated with the CIDR block before you can disassociate it. +// Disassociates a CIDR block from a VPC. To disassociate the CIDR block, you +// must specify its association ID. You can get the association ID by using +// DescribeVpcs. You must detach or delete all gateways and resources that are +// associated with the CIDR block before you can disassociate it. +// +// You cannot disassociate the CIDR block with which you originally created +// the VPC (the primary CIDR block). // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -14614,7 +16018,7 @@ func (c *EC2) DisassociateVpcCidrBlockRequest(input *DisassociateVpcCidrBlockInp // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation DisassociateVpcCidrBlock for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlock func (c *EC2) DisassociateVpcCidrBlock(input *DisassociateVpcCidrBlockInput) (*DisassociateVpcCidrBlockOutput, error) { req, out := c.DisassociateVpcCidrBlockRequest(input) return out, req.Send() @@ -14640,19 +16044,18 @@ const opEnableVgwRoutePropagation = "EnableVgwRoutePropagation" // EnableVgwRoutePropagationRequest generates a "aws/request.Request" representing the // client's request for the EnableVgwRoutePropagation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See EnableVgwRoutePropagation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the EnableVgwRoutePropagation method directly -// instead. +// See EnableVgwRoutePropagation for more information on using the EnableVgwRoutePropagation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the EnableVgwRoutePropagationRequest method. // req, resp := client.EnableVgwRoutePropagationRequest(params) @@ -14662,7 +16065,7 @@ const opEnableVgwRoutePropagation = "EnableVgwRoutePropagation" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagation func (c *EC2) EnableVgwRoutePropagationRequest(input *EnableVgwRoutePropagationInput) (req *request.Request, output *EnableVgwRoutePropagationOutput) { op := &request.Operation{ Name: opEnableVgwRoutePropagation, @@ -14692,7 +16095,7 @@ func (c *EC2) EnableVgwRoutePropagationRequest(input *EnableVgwRoutePropagationI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation EnableVgwRoutePropagation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagation func (c *EC2) EnableVgwRoutePropagation(input *EnableVgwRoutePropagationInput) (*EnableVgwRoutePropagationOutput, error) { req, out := c.EnableVgwRoutePropagationRequest(input) return out, req.Send() @@ -14718,19 +16121,18 @@ const opEnableVolumeIO = "EnableVolumeIO" // EnableVolumeIORequest generates a "aws/request.Request" representing the // client's request for the EnableVolumeIO operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See EnableVolumeIO for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the EnableVolumeIO method directly -// instead. +// See EnableVolumeIO for more information on using the EnableVolumeIO +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the EnableVolumeIORequest method. // req, resp := client.EnableVolumeIORequest(params) @@ -14740,7 +16142,7 @@ const opEnableVolumeIO = "EnableVolumeIO" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIO +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIO func (c *EC2) EnableVolumeIORequest(input *EnableVolumeIOInput) (req *request.Request, output *EnableVolumeIOOutput) { op := &request.Operation{ Name: opEnableVolumeIO, @@ -14770,7 +16172,7 @@ func (c *EC2) EnableVolumeIORequest(input *EnableVolumeIOInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation EnableVolumeIO for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIO +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIO func (c *EC2) EnableVolumeIO(input *EnableVolumeIOInput) (*EnableVolumeIOOutput, error) { req, out := c.EnableVolumeIORequest(input) return out, req.Send() @@ -14796,19 +16198,18 @@ const opEnableVpcClassicLink = "EnableVpcClassicLink" // EnableVpcClassicLinkRequest generates a "aws/request.Request" representing the // client's request for the EnableVpcClassicLink operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See EnableVpcClassicLink for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the EnableVpcClassicLink method directly -// instead. +// See EnableVpcClassicLink for more information on using the EnableVpcClassicLink +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the EnableVpcClassicLinkRequest method. // req, resp := client.EnableVpcClassicLinkRequest(params) @@ -14818,7 +16219,7 @@ const opEnableVpcClassicLink = "EnableVpcClassicLink" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLink func (c *EC2) EnableVpcClassicLinkRequest(input *EnableVpcClassicLinkInput) (req *request.Request, output *EnableVpcClassicLinkOutput) { op := &request.Operation{ Name: opEnableVpcClassicLink, @@ -14851,7 +16252,7 @@ func (c *EC2) EnableVpcClassicLinkRequest(input *EnableVpcClassicLinkInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation EnableVpcClassicLink for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLink func (c *EC2) EnableVpcClassicLink(input *EnableVpcClassicLinkInput) (*EnableVpcClassicLinkOutput, error) { req, out := c.EnableVpcClassicLinkRequest(input) return out, req.Send() @@ -14877,19 +16278,18 @@ const opEnableVpcClassicLinkDnsSupport = "EnableVpcClassicLinkDnsSupport" // EnableVpcClassicLinkDnsSupportRequest generates a "aws/request.Request" representing the // client's request for the EnableVpcClassicLinkDnsSupport operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See EnableVpcClassicLinkDnsSupport for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the EnableVpcClassicLinkDnsSupport method directly -// instead. +// See EnableVpcClassicLinkDnsSupport for more information on using the EnableVpcClassicLinkDnsSupport +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the EnableVpcClassicLinkDnsSupportRequest method. // req, resp := client.EnableVpcClassicLinkDnsSupportRequest(params) @@ -14899,7 +16299,7 @@ const opEnableVpcClassicLinkDnsSupport = "EnableVpcClassicLinkDnsSupport" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupport func (c *EC2) EnableVpcClassicLinkDnsSupportRequest(input *EnableVpcClassicLinkDnsSupportInput) (req *request.Request, output *EnableVpcClassicLinkDnsSupportOutput) { op := &request.Operation{ Name: opEnableVpcClassicLinkDnsSupport, @@ -14932,7 +16332,7 @@ func (c *EC2) EnableVpcClassicLinkDnsSupportRequest(input *EnableVpcClassicLinkD // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation EnableVpcClassicLinkDnsSupport for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupport func (c *EC2) EnableVpcClassicLinkDnsSupport(input *EnableVpcClassicLinkDnsSupportInput) (*EnableVpcClassicLinkDnsSupportOutput, error) { req, out := c.EnableVpcClassicLinkDnsSupportRequest(input) return out, req.Send() @@ -14958,19 +16358,18 @@ const opGetConsoleOutput = "GetConsoleOutput" // GetConsoleOutputRequest generates a "aws/request.Request" representing the // client's request for the GetConsoleOutput operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetConsoleOutput for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetConsoleOutput method directly -// instead. +// See GetConsoleOutput for more information on using the GetConsoleOutput +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetConsoleOutputRequest method. // req, resp := client.GetConsoleOutputRequest(params) @@ -14980,7 +16379,7 @@ const opGetConsoleOutput = "GetConsoleOutput" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutput func (c *EC2) GetConsoleOutputRequest(input *GetConsoleOutputInput) (req *request.Request, output *GetConsoleOutputOutput) { op := &request.Operation{ Name: opGetConsoleOutput, @@ -15007,7 +16406,7 @@ func (c *EC2) GetConsoleOutputRequest(input *GetConsoleOutputInput) (req *reques // the Amazon EC2 API and command line interface. // // Instance console output is buffered and posted shortly after instance boot, -// reboot, and termination. Amazon EC2 preserves the most recent 64 KB output +// reboot, and termination. Amazon EC2 preserves the most recent 64 KB output, // which is available for at least one hour after the most recent post. // // For Linux instances, the instance console output displays the exact console @@ -15024,7 +16423,7 @@ func (c *EC2) GetConsoleOutputRequest(input *GetConsoleOutputInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation GetConsoleOutput for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutput func (c *EC2) GetConsoleOutput(input *GetConsoleOutputInput) (*GetConsoleOutputOutput, error) { req, out := c.GetConsoleOutputRequest(input) return out, req.Send() @@ -15050,19 +16449,18 @@ const opGetConsoleScreenshot = "GetConsoleScreenshot" // GetConsoleScreenshotRequest generates a "aws/request.Request" representing the // client's request for the GetConsoleScreenshot operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetConsoleScreenshot for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetConsoleScreenshot method directly -// instead. +// See GetConsoleScreenshot for more information on using the GetConsoleScreenshot +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetConsoleScreenshotRequest method. // req, resp := client.GetConsoleScreenshotRequest(params) @@ -15072,7 +16470,7 @@ const opGetConsoleScreenshot = "GetConsoleScreenshot" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshot func (c *EC2) GetConsoleScreenshotRequest(input *GetConsoleScreenshotInput) (req *request.Request, output *GetConsoleScreenshotOutput) { op := &request.Operation{ Name: opGetConsoleScreenshot, @@ -15101,7 +16499,7 @@ func (c *EC2) GetConsoleScreenshotRequest(input *GetConsoleScreenshotInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation GetConsoleScreenshot for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshot func (c *EC2) GetConsoleScreenshot(input *GetConsoleScreenshotInput) (*GetConsoleScreenshotOutput, error) { req, out := c.GetConsoleScreenshotRequest(input) return out, req.Send() @@ -15127,19 +16525,18 @@ const opGetHostReservationPurchasePreview = "GetHostReservationPurchasePreview" // GetHostReservationPurchasePreviewRequest generates a "aws/request.Request" representing the // client's request for the GetHostReservationPurchasePreview operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetHostReservationPurchasePreview for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetHostReservationPurchasePreview method directly -// instead. +// See GetHostReservationPurchasePreview for more information on using the GetHostReservationPurchasePreview +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetHostReservationPurchasePreviewRequest method. // req, resp := client.GetHostReservationPurchasePreviewRequest(params) @@ -15149,7 +16546,7 @@ const opGetHostReservationPurchasePreview = "GetHostReservationPurchasePreview" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreview +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreview func (c *EC2) GetHostReservationPurchasePreviewRequest(input *GetHostReservationPurchasePreviewInput) (req *request.Request, output *GetHostReservationPurchasePreviewOutput) { op := &request.Operation{ Name: opGetHostReservationPurchasePreview, @@ -15181,7 +16578,7 @@ func (c *EC2) GetHostReservationPurchasePreviewRequest(input *GetHostReservation // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation GetHostReservationPurchasePreview for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreview +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreview func (c *EC2) GetHostReservationPurchasePreview(input *GetHostReservationPurchasePreviewInput) (*GetHostReservationPurchasePreviewOutput, error) { req, out := c.GetHostReservationPurchasePreviewRequest(input) return out, req.Send() @@ -15203,23 +16600,97 @@ func (c *EC2) GetHostReservationPurchasePreviewWithContext(ctx aws.Context, inpu return out, req.Send() } +const opGetLaunchTemplateData = "GetLaunchTemplateData" + +// GetLaunchTemplateDataRequest generates a "aws/request.Request" representing the +// client's request for the GetLaunchTemplateData operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See GetLaunchTemplateData for more information on using the GetLaunchTemplateData +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the GetLaunchTemplateDataRequest method. +// req, resp := client.GetLaunchTemplateDataRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetLaunchTemplateData +func (c *EC2) GetLaunchTemplateDataRequest(input *GetLaunchTemplateDataInput) (req *request.Request, output *GetLaunchTemplateDataOutput) { + op := &request.Operation{ + Name: opGetLaunchTemplateData, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &GetLaunchTemplateDataInput{} + } + + output = &GetLaunchTemplateDataOutput{} + req = c.newRequest(op, input, output) + return +} + +// GetLaunchTemplateData API operation for Amazon Elastic Compute Cloud. +// +// Retrieves the configuration data of the specified instance. You can use this +// data to create a launch template. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation GetLaunchTemplateData for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetLaunchTemplateData +func (c *EC2) GetLaunchTemplateData(input *GetLaunchTemplateDataInput) (*GetLaunchTemplateDataOutput, error) { + req, out := c.GetLaunchTemplateDataRequest(input) + return out, req.Send() +} + +// GetLaunchTemplateDataWithContext is the same as GetLaunchTemplateData with the addition of +// the ability to pass a context and additional request options. +// +// See GetLaunchTemplateData for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) GetLaunchTemplateDataWithContext(ctx aws.Context, input *GetLaunchTemplateDataInput, opts ...request.Option) (*GetLaunchTemplateDataOutput, error) { + req, out := c.GetLaunchTemplateDataRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opGetPasswordData = "GetPasswordData" // GetPasswordDataRequest generates a "aws/request.Request" representing the // client's request for the GetPasswordData operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetPasswordData for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetPasswordData method directly -// instead. +// See GetPasswordData for more information on using the GetPasswordData +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetPasswordDataRequest method. // req, resp := client.GetPasswordDataRequest(params) @@ -15229,7 +16700,7 @@ const opGetPasswordData = "GetPasswordData" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordData +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordData func (c *EC2) GetPasswordDataRequest(input *GetPasswordDataInput) (req *request.Request, output *GetPasswordDataOutput) { op := &request.Operation{ Name: opGetPasswordData, @@ -15248,20 +16719,24 @@ func (c *EC2) GetPasswordDataRequest(input *GetPasswordDataInput) (req *request. // GetPasswordData API operation for Amazon Elastic Compute Cloud. // -// Retrieves the encrypted administrator password for an instance running Windows. +// Retrieves the encrypted administrator password for a running Windows instance. // -// The Windows password is generated at boot if the EC2Config service plugin, -// Ec2SetPassword, is enabled. This usually only happens the first time an AMI -// is launched, and then Ec2SetPassword is automatically disabled. The password -// is not generated for rebundled AMIs unless Ec2SetPassword is enabled before -// bundling. +// The Windows password is generated at boot by the EC2Config service or EC2Launch +// scripts (Windows Server 2016 and later). This usually only happens the first +// time an instance is launched. For more information, see EC2Config (http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/UsingConfig_WinAMI.html) +// and EC2Launch (http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2launch.html) +// in the Amazon Elastic Compute Cloud User Guide. +// +// For the EC2Config service, the password is not generated for rebundled AMIs +// unless Ec2SetPassword is enabled before bundling. // // The password is encrypted using the key pair that you specified when you // launched the instance. You must provide the corresponding key pair file. // -// Password generation and encryption takes a few moments. We recommend that -// you wait up to 15 minutes after launching an instance before trying to retrieve -// the generated password. +// When you launch an instance, password generation and encryption may take +// a few minutes. If you try to retrieve the password before it's available, +// the output returns an empty string. We recommend that you wait up to 15 minutes +// after launching an instance before trying to retrieve the generated password. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -15269,7 +16744,7 @@ func (c *EC2) GetPasswordDataRequest(input *GetPasswordDataInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation GetPasswordData for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordData +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordData func (c *EC2) GetPasswordData(input *GetPasswordDataInput) (*GetPasswordDataOutput, error) { req, out := c.GetPasswordDataRequest(input) return out, req.Send() @@ -15295,19 +16770,18 @@ const opGetReservedInstancesExchangeQuote = "GetReservedInstancesExchangeQuote" // GetReservedInstancesExchangeQuoteRequest generates a "aws/request.Request" representing the // client's request for the GetReservedInstancesExchangeQuote operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetReservedInstancesExchangeQuote for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetReservedInstancesExchangeQuote method directly -// instead. +// See GetReservedInstancesExchangeQuote for more information on using the GetReservedInstancesExchangeQuote +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetReservedInstancesExchangeQuoteRequest method. // req, resp := client.GetReservedInstancesExchangeQuoteRequest(params) @@ -15317,7 +16791,7 @@ const opGetReservedInstancesExchangeQuote = "GetReservedInstancesExchangeQuote" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuote +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuote func (c *EC2) GetReservedInstancesExchangeQuoteRequest(input *GetReservedInstancesExchangeQuoteInput) (req *request.Request, output *GetReservedInstancesExchangeQuoteOutput) { op := &request.Operation{ Name: opGetReservedInstancesExchangeQuote, @@ -15336,9 +16810,10 @@ func (c *EC2) GetReservedInstancesExchangeQuoteRequest(input *GetReservedInstanc // GetReservedInstancesExchangeQuote API operation for Amazon Elastic Compute Cloud. // -// Returns details about the values and term of your specified Convertible Reserved -// Instances. When a target configuration is specified, it returns information -// about whether the exchange is valid and can be performed. +// Returns a quote and exchange information for exchanging one or more specified +// Convertible Reserved Instances for a new Convertible Reserved Instance. If +// the exchange cannot be performed, the reason is returned in the response. +// Use AcceptReservedInstancesExchangeQuote to perform the exchange. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -15346,7 +16821,7 @@ func (c *EC2) GetReservedInstancesExchangeQuoteRequest(input *GetReservedInstanc // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation GetReservedInstancesExchangeQuote for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuote +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuote func (c *EC2) GetReservedInstancesExchangeQuote(input *GetReservedInstancesExchangeQuoteInput) (*GetReservedInstancesExchangeQuoteOutput, error) { req, out := c.GetReservedInstancesExchangeQuoteRequest(input) return out, req.Send() @@ -15372,19 +16847,18 @@ const opImportImage = "ImportImage" // ImportImageRequest generates a "aws/request.Request" representing the // client's request for the ImportImage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ImportImage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ImportImage method directly -// instead. +// See ImportImage for more information on using the ImportImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ImportImageRequest method. // req, resp := client.ImportImageRequest(params) @@ -15394,7 +16868,7 @@ const opImportImage = "ImportImage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImage func (c *EC2) ImportImageRequest(input *ImportImageInput) (req *request.Request, output *ImportImageOutput) { op := &request.Operation{ Name: opImportImage, @@ -15424,7 +16898,7 @@ func (c *EC2) ImportImageRequest(input *ImportImageInput) (req *request.Request, // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ImportImage for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImage func (c *EC2) ImportImage(input *ImportImageInput) (*ImportImageOutput, error) { req, out := c.ImportImageRequest(input) return out, req.Send() @@ -15450,19 +16924,18 @@ const opImportInstance = "ImportInstance" // ImportInstanceRequest generates a "aws/request.Request" representing the // client's request for the ImportInstance operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ImportInstance for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ImportInstance method directly -// instead. +// See ImportInstance for more information on using the ImportInstance +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ImportInstanceRequest method. // req, resp := client.ImportInstanceRequest(params) @@ -15472,7 +16945,7 @@ const opImportInstance = "ImportInstance" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstance func (c *EC2) ImportInstanceRequest(input *ImportInstanceInput) (req *request.Request, output *ImportInstanceOutput) { op := &request.Operation{ Name: opImportInstance, @@ -15505,7 +16978,7 @@ func (c *EC2) ImportInstanceRequest(input *ImportInstanceInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ImportInstance for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstance func (c *EC2) ImportInstance(input *ImportInstanceInput) (*ImportInstanceOutput, error) { req, out := c.ImportInstanceRequest(input) return out, req.Send() @@ -15531,19 +17004,18 @@ const opImportKeyPair = "ImportKeyPair" // ImportKeyPairRequest generates a "aws/request.Request" representing the // client's request for the ImportKeyPair operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ImportKeyPair for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ImportKeyPair method directly -// instead. +// See ImportKeyPair for more information on using the ImportKeyPair +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ImportKeyPairRequest method. // req, resp := client.ImportKeyPairRequest(params) @@ -15553,7 +17025,7 @@ const opImportKeyPair = "ImportKeyPair" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPair func (c *EC2) ImportKeyPairRequest(input *ImportKeyPairInput) (req *request.Request, output *ImportKeyPairOutput) { op := &request.Operation{ Name: opImportKeyPair, @@ -15587,7 +17059,7 @@ func (c *EC2) ImportKeyPairRequest(input *ImportKeyPairInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ImportKeyPair for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPair func (c *EC2) ImportKeyPair(input *ImportKeyPairInput) (*ImportKeyPairOutput, error) { req, out := c.ImportKeyPairRequest(input) return out, req.Send() @@ -15613,19 +17085,18 @@ const opImportSnapshot = "ImportSnapshot" // ImportSnapshotRequest generates a "aws/request.Request" representing the // client's request for the ImportSnapshot operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ImportSnapshot for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ImportSnapshot method directly -// instead. +// See ImportSnapshot for more information on using the ImportSnapshot +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ImportSnapshotRequest method. // req, resp := client.ImportSnapshotRequest(params) @@ -15635,7 +17106,7 @@ const opImportSnapshot = "ImportSnapshot" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshot func (c *EC2) ImportSnapshotRequest(input *ImportSnapshotInput) (req *request.Request, output *ImportSnapshotOutput) { op := &request.Operation{ Name: opImportSnapshot, @@ -15662,7 +17133,7 @@ func (c *EC2) ImportSnapshotRequest(input *ImportSnapshotInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ImportSnapshot for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshot func (c *EC2) ImportSnapshot(input *ImportSnapshotInput) (*ImportSnapshotOutput, error) { req, out := c.ImportSnapshotRequest(input) return out, req.Send() @@ -15688,19 +17159,18 @@ const opImportVolume = "ImportVolume" // ImportVolumeRequest generates a "aws/request.Request" representing the // client's request for the ImportVolume operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ImportVolume for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ImportVolume method directly -// instead. +// See ImportVolume for more information on using the ImportVolume +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ImportVolumeRequest method. // req, resp := client.ImportVolumeRequest(params) @@ -15710,7 +17180,7 @@ const opImportVolume = "ImportVolume" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolume func (c *EC2) ImportVolumeRequest(input *ImportVolumeInput) (req *request.Request, output *ImportVolumeOutput) { op := &request.Operation{ Name: opImportVolume, @@ -15741,7 +17211,7 @@ func (c *EC2) ImportVolumeRequest(input *ImportVolumeInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ImportVolume for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolume func (c *EC2) ImportVolume(input *ImportVolumeInput) (*ImportVolumeOutput, error) { req, out := c.ImportVolumeRequest(input) return out, req.Send() @@ -15763,23 +17233,96 @@ func (c *EC2) ImportVolumeWithContext(ctx aws.Context, input *ImportVolumeInput, return out, req.Send() } +const opModifyFpgaImageAttribute = "ModifyFpgaImageAttribute" + +// ModifyFpgaImageAttributeRequest generates a "aws/request.Request" representing the +// client's request for the ModifyFpgaImageAttribute operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyFpgaImageAttribute for more information on using the ModifyFpgaImageAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyFpgaImageAttributeRequest method. +// req, resp := client.ModifyFpgaImageAttributeRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyFpgaImageAttribute +func (c *EC2) ModifyFpgaImageAttributeRequest(input *ModifyFpgaImageAttributeInput) (req *request.Request, output *ModifyFpgaImageAttributeOutput) { + op := &request.Operation{ + Name: opModifyFpgaImageAttribute, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyFpgaImageAttributeInput{} + } + + output = &ModifyFpgaImageAttributeOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyFpgaImageAttribute API operation for Amazon Elastic Compute Cloud. +// +// Modifies the specified attribute of the specified Amazon FPGA Image (AFI). +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyFpgaImageAttribute for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyFpgaImageAttribute +func (c *EC2) ModifyFpgaImageAttribute(input *ModifyFpgaImageAttributeInput) (*ModifyFpgaImageAttributeOutput, error) { + req, out := c.ModifyFpgaImageAttributeRequest(input) + return out, req.Send() +} + +// ModifyFpgaImageAttributeWithContext is the same as ModifyFpgaImageAttribute with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyFpgaImageAttribute for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyFpgaImageAttributeWithContext(ctx aws.Context, input *ModifyFpgaImageAttributeInput, opts ...request.Option) (*ModifyFpgaImageAttributeOutput, error) { + req, out := c.ModifyFpgaImageAttributeRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opModifyHosts = "ModifyHosts" // ModifyHostsRequest generates a "aws/request.Request" representing the // client's request for the ModifyHosts operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyHosts for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyHosts method directly -// instead. +// See ModifyHosts for more information on using the ModifyHosts +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyHostsRequest method. // req, resp := client.ModifyHostsRequest(params) @@ -15789,7 +17332,7 @@ const opModifyHosts = "ModifyHosts" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHosts func (c *EC2) ModifyHostsRequest(input *ModifyHostsInput) (req *request.Request, output *ModifyHostsOutput) { op := &request.Operation{ Name: opModifyHosts, @@ -15822,7 +17365,7 @@ func (c *EC2) ModifyHostsRequest(input *ModifyHostsInput) (req *request.Request, // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyHosts for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHosts func (c *EC2) ModifyHosts(input *ModifyHostsInput) (*ModifyHostsOutput, error) { req, out := c.ModifyHostsRequest(input) return out, req.Send() @@ -15848,19 +17391,18 @@ const opModifyIdFormat = "ModifyIdFormat" // ModifyIdFormatRequest generates a "aws/request.Request" representing the // client's request for the ModifyIdFormat operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyIdFormat for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyIdFormat method directly -// instead. +// See ModifyIdFormat for more information on using the ModifyIdFormat +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyIdFormatRequest method. // req, resp := client.ModifyIdFormatRequest(params) @@ -15870,7 +17412,7 @@ const opModifyIdFormat = "ModifyIdFormat" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormat func (c *EC2) ModifyIdFormatRequest(input *ModifyIdFormatInput) (req *request.Request, output *ModifyIdFormatOutput) { op := &request.Operation{ Name: opModifyIdFormat, @@ -15913,7 +17455,7 @@ func (c *EC2) ModifyIdFormatRequest(input *ModifyIdFormatInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyIdFormat for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormat func (c *EC2) ModifyIdFormat(input *ModifyIdFormatInput) (*ModifyIdFormatOutput, error) { req, out := c.ModifyIdFormatRequest(input) return out, req.Send() @@ -15939,19 +17481,18 @@ const opModifyIdentityIdFormat = "ModifyIdentityIdFormat" // ModifyIdentityIdFormatRequest generates a "aws/request.Request" representing the // client's request for the ModifyIdentityIdFormat operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyIdentityIdFormat for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyIdentityIdFormat method directly -// instead. +// See ModifyIdentityIdFormat for more information on using the ModifyIdentityIdFormat +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyIdentityIdFormatRequest method. // req, resp := client.ModifyIdentityIdFormatRequest(params) @@ -15961,7 +17502,7 @@ const opModifyIdentityIdFormat = "ModifyIdentityIdFormat" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormat func (c *EC2) ModifyIdentityIdFormatRequest(input *ModifyIdentityIdFormatInput) (req *request.Request, output *ModifyIdentityIdFormatOutput) { op := &request.Operation{ Name: opModifyIdentityIdFormat, @@ -16004,7 +17545,7 @@ func (c *EC2) ModifyIdentityIdFormatRequest(input *ModifyIdentityIdFormatInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyIdentityIdFormat for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormat func (c *EC2) ModifyIdentityIdFormat(input *ModifyIdentityIdFormatInput) (*ModifyIdentityIdFormatOutput, error) { req, out := c.ModifyIdentityIdFormatRequest(input) return out, req.Send() @@ -16030,19 +17571,18 @@ const opModifyImageAttribute = "ModifyImageAttribute" // ModifyImageAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifyImageAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyImageAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyImageAttribute method directly -// instead. +// See ModifyImageAttribute for more information on using the ModifyImageAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyImageAttributeRequest method. // req, resp := client.ModifyImageAttributeRequest(params) @@ -16052,7 +17592,7 @@ const opModifyImageAttribute = "ModifyImageAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttribute func (c *EC2) ModifyImageAttributeRequest(input *ModifyImageAttributeInput) (req *request.Request, output *ModifyImageAttributeOutput) { op := &request.Operation{ Name: opModifyImageAttribute, @@ -16074,15 +17614,15 @@ func (c *EC2) ModifyImageAttributeRequest(input *ModifyImageAttributeInput) (req // ModifyImageAttribute API operation for Amazon Elastic Compute Cloud. // // Modifies the specified attribute of the specified AMI. You can specify only -// one attribute at a time. +// one attribute at a time. You can use the Attribute parameter to specify the +// attribute or one of the following parameters: Description, LaunchPermission, +// or ProductCode. // // AWS Marketplace product codes cannot be modified. Images with an AWS Marketplace // product code cannot be made public. // -// The SriovNetSupport enhanced networking attribute cannot be changed using -// this command. Instead, enable SriovNetSupport on an instance and create an -// AMI from the instance. This will result in an image with SriovNetSupport -// enabled. +// To enable the SriovNetSupport enhanced networking attribute of an image, +// enable SriovNetSupport on an instance and create an AMI from the instance. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -16090,7 +17630,7 @@ func (c *EC2) ModifyImageAttributeRequest(input *ModifyImageAttributeInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyImageAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttribute func (c *EC2) ModifyImageAttribute(input *ModifyImageAttributeInput) (*ModifyImageAttributeOutput, error) { req, out := c.ModifyImageAttributeRequest(input) return out, req.Send() @@ -16116,19 +17656,18 @@ const opModifyInstanceAttribute = "ModifyInstanceAttribute" // ModifyInstanceAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifyInstanceAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyInstanceAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyInstanceAttribute method directly -// instead. +// See ModifyInstanceAttribute for more information on using the ModifyInstanceAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyInstanceAttributeRequest method. // req, resp := client.ModifyInstanceAttributeRequest(params) @@ -16138,7 +17677,7 @@ const opModifyInstanceAttribute = "ModifyInstanceAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttribute func (c *EC2) ModifyInstanceAttributeRequest(input *ModifyInstanceAttributeInput) (req *request.Request, output *ModifyInstanceAttributeOutput) { op := &request.Operation{ Name: opModifyInstanceAttribute, @@ -16172,7 +17711,7 @@ func (c *EC2) ModifyInstanceAttributeRequest(input *ModifyInstanceAttributeInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyInstanceAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttribute func (c *EC2) ModifyInstanceAttribute(input *ModifyInstanceAttributeInput) (*ModifyInstanceAttributeOutput, error) { req, out := c.ModifyInstanceAttributeRequest(input) return out, req.Send() @@ -16194,23 +17733,100 @@ func (c *EC2) ModifyInstanceAttributeWithContext(ctx aws.Context, input *ModifyI return out, req.Send() } +const opModifyInstanceCreditSpecification = "ModifyInstanceCreditSpecification" + +// ModifyInstanceCreditSpecificationRequest generates a "aws/request.Request" representing the +// client's request for the ModifyInstanceCreditSpecification operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyInstanceCreditSpecification for more information on using the ModifyInstanceCreditSpecification +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyInstanceCreditSpecificationRequest method. +// req, resp := client.ModifyInstanceCreditSpecificationRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceCreditSpecification +func (c *EC2) ModifyInstanceCreditSpecificationRequest(input *ModifyInstanceCreditSpecificationInput) (req *request.Request, output *ModifyInstanceCreditSpecificationOutput) { + op := &request.Operation{ + Name: opModifyInstanceCreditSpecification, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyInstanceCreditSpecificationInput{} + } + + output = &ModifyInstanceCreditSpecificationOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyInstanceCreditSpecification API operation for Amazon Elastic Compute Cloud. +// +// Modifies the credit option for CPU usage on a running or stopped T2 instance. +// The credit options are standard and unlimited. +// +// For more information, see T2 Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-instances.html) +// in the Amazon Elastic Compute Cloud User Guide. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyInstanceCreditSpecification for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceCreditSpecification +func (c *EC2) ModifyInstanceCreditSpecification(input *ModifyInstanceCreditSpecificationInput) (*ModifyInstanceCreditSpecificationOutput, error) { + req, out := c.ModifyInstanceCreditSpecificationRequest(input) + return out, req.Send() +} + +// ModifyInstanceCreditSpecificationWithContext is the same as ModifyInstanceCreditSpecification with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyInstanceCreditSpecification for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyInstanceCreditSpecificationWithContext(ctx aws.Context, input *ModifyInstanceCreditSpecificationInput, opts ...request.Option) (*ModifyInstanceCreditSpecificationOutput, error) { + req, out := c.ModifyInstanceCreditSpecificationRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opModifyInstancePlacement = "ModifyInstancePlacement" // ModifyInstancePlacementRequest generates a "aws/request.Request" representing the // client's request for the ModifyInstancePlacement operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyInstancePlacement for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyInstancePlacement method directly -// instead. +// See ModifyInstancePlacement for more information on using the ModifyInstancePlacement +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyInstancePlacementRequest method. // req, resp := client.ModifyInstancePlacementRequest(params) @@ -16220,7 +17836,7 @@ const opModifyInstancePlacement = "ModifyInstancePlacement" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacement +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacement func (c *EC2) ModifyInstancePlacementRequest(input *ModifyInstancePlacementInput) (req *request.Request, output *ModifyInstancePlacementOutput) { op := &request.Operation{ Name: opModifyInstancePlacement, @@ -16265,7 +17881,7 @@ func (c *EC2) ModifyInstancePlacementRequest(input *ModifyInstancePlacementInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyInstancePlacement for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacement +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacement func (c *EC2) ModifyInstancePlacement(input *ModifyInstancePlacementInput) (*ModifyInstancePlacementOutput, error) { req, out := c.ModifyInstancePlacementRequest(input) return out, req.Send() @@ -16287,23 +17903,98 @@ func (c *EC2) ModifyInstancePlacementWithContext(ctx aws.Context, input *ModifyI return out, req.Send() } +const opModifyLaunchTemplate = "ModifyLaunchTemplate" + +// ModifyLaunchTemplateRequest generates a "aws/request.Request" representing the +// client's request for the ModifyLaunchTemplate operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyLaunchTemplate for more information on using the ModifyLaunchTemplate +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyLaunchTemplateRequest method. +// req, resp := client.ModifyLaunchTemplateRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyLaunchTemplate +func (c *EC2) ModifyLaunchTemplateRequest(input *ModifyLaunchTemplateInput) (req *request.Request, output *ModifyLaunchTemplateOutput) { + op := &request.Operation{ + Name: opModifyLaunchTemplate, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyLaunchTemplateInput{} + } + + output = &ModifyLaunchTemplateOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyLaunchTemplate API operation for Amazon Elastic Compute Cloud. +// +// Modifies a launch template. You can specify which version of the launch template +// to set as the default version. When launching an instance, the default version +// applies when a launch template version is not specified. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyLaunchTemplate for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyLaunchTemplate +func (c *EC2) ModifyLaunchTemplate(input *ModifyLaunchTemplateInput) (*ModifyLaunchTemplateOutput, error) { + req, out := c.ModifyLaunchTemplateRequest(input) + return out, req.Send() +} + +// ModifyLaunchTemplateWithContext is the same as ModifyLaunchTemplate with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyLaunchTemplate for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyLaunchTemplateWithContext(ctx aws.Context, input *ModifyLaunchTemplateInput, opts ...request.Option) (*ModifyLaunchTemplateOutput, error) { + req, out := c.ModifyLaunchTemplateRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opModifyNetworkInterfaceAttribute = "ModifyNetworkInterfaceAttribute" // ModifyNetworkInterfaceAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifyNetworkInterfaceAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyNetworkInterfaceAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyNetworkInterfaceAttribute method directly -// instead. +// See ModifyNetworkInterfaceAttribute for more information on using the ModifyNetworkInterfaceAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyNetworkInterfaceAttributeRequest method. // req, resp := client.ModifyNetworkInterfaceAttributeRequest(params) @@ -16313,7 +18004,7 @@ const opModifyNetworkInterfaceAttribute = "ModifyNetworkInterfaceAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttribute func (c *EC2) ModifyNetworkInterfaceAttributeRequest(input *ModifyNetworkInterfaceAttributeInput) (req *request.Request, output *ModifyNetworkInterfaceAttributeOutput) { op := &request.Operation{ Name: opModifyNetworkInterfaceAttribute, @@ -16343,7 +18034,7 @@ func (c *EC2) ModifyNetworkInterfaceAttributeRequest(input *ModifyNetworkInterfa // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyNetworkInterfaceAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttribute func (c *EC2) ModifyNetworkInterfaceAttribute(input *ModifyNetworkInterfaceAttributeInput) (*ModifyNetworkInterfaceAttributeOutput, error) { req, out := c.ModifyNetworkInterfaceAttributeRequest(input) return out, req.Send() @@ -16369,19 +18060,18 @@ const opModifyReservedInstances = "ModifyReservedInstances" // ModifyReservedInstancesRequest generates a "aws/request.Request" representing the // client's request for the ModifyReservedInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyReservedInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyReservedInstances method directly -// instead. +// See ModifyReservedInstances for more information on using the ModifyReservedInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyReservedInstancesRequest method. // req, resp := client.ModifyReservedInstancesRequest(params) @@ -16391,7 +18081,7 @@ const opModifyReservedInstances = "ModifyReservedInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstances func (c *EC2) ModifyReservedInstancesRequest(input *ModifyReservedInstancesInput) (req *request.Request, output *ModifyReservedInstancesOutput) { op := &request.Operation{ Name: opModifyReservedInstances, @@ -16411,9 +18101,9 @@ func (c *EC2) ModifyReservedInstancesRequest(input *ModifyReservedInstancesInput // ModifyReservedInstances API operation for Amazon Elastic Compute Cloud. // // Modifies the Availability Zone, instance count, instance type, or network -// platform (EC2-Classic or EC2-VPC) of your Standard Reserved Instances. The -// Reserved Instances to be modified must be identical, except for Availability -// Zone, network platform, and instance type. +// platform (EC2-Classic or EC2-VPC) of your Reserved Instances. The Reserved +// Instances to be modified must be identical, except for Availability Zone, +// network platform, and instance type. // // For more information, see Modifying Reserved Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ri-modifying.html) // in the Amazon Elastic Compute Cloud User Guide. @@ -16424,7 +18114,7 @@ func (c *EC2) ModifyReservedInstancesRequest(input *ModifyReservedInstancesInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyReservedInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstances func (c *EC2) ModifyReservedInstances(input *ModifyReservedInstancesInput) (*ModifyReservedInstancesOutput, error) { req, out := c.ModifyReservedInstancesRequest(input) return out, req.Send() @@ -16450,19 +18140,18 @@ const opModifySnapshotAttribute = "ModifySnapshotAttribute" // ModifySnapshotAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifySnapshotAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifySnapshotAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifySnapshotAttribute method directly -// instead. +// See ModifySnapshotAttribute for more information on using the ModifySnapshotAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifySnapshotAttributeRequest method. // req, resp := client.ModifySnapshotAttributeRequest(params) @@ -16472,7 +18161,7 @@ const opModifySnapshotAttribute = "ModifySnapshotAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttribute func (c *EC2) ModifySnapshotAttributeRequest(input *ModifySnapshotAttributeInput) (req *request.Request, output *ModifySnapshotAttributeOutput) { op := &request.Operation{ Name: opModifySnapshotAttribute, @@ -16513,7 +18202,7 @@ func (c *EC2) ModifySnapshotAttributeRequest(input *ModifySnapshotAttributeInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifySnapshotAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttribute func (c *EC2) ModifySnapshotAttribute(input *ModifySnapshotAttributeInput) (*ModifySnapshotAttributeOutput, error) { req, out := c.ModifySnapshotAttributeRequest(input) return out, req.Send() @@ -16539,19 +18228,18 @@ const opModifySpotFleetRequest = "ModifySpotFleetRequest" // ModifySpotFleetRequestRequest generates a "aws/request.Request" representing the // client's request for the ModifySpotFleetRequest operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifySpotFleetRequest for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifySpotFleetRequest method directly -// instead. +// See ModifySpotFleetRequest for more information on using the ModifySpotFleetRequest +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifySpotFleetRequestRequest method. // req, resp := client.ModifySpotFleetRequestRequest(params) @@ -16561,7 +18249,7 @@ const opModifySpotFleetRequest = "ModifySpotFleetRequest" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequest func (c *EC2) ModifySpotFleetRequestRequest(input *ModifySpotFleetRequestInput) (req *request.Request, output *ModifySpotFleetRequestOutput) { op := &request.Operation{ Name: opModifySpotFleetRequest, @@ -16580,26 +18268,29 @@ func (c *EC2) ModifySpotFleetRequestRequest(input *ModifySpotFleetRequestInput) // ModifySpotFleetRequest API operation for Amazon Elastic Compute Cloud. // -// Modifies the specified Spot fleet request. +// Modifies the specified Spot Fleet request. // -// While the Spot fleet request is being modified, it is in the modifying state. +// While the Spot Fleet request is being modified, it is in the modifying state. // -// To scale up your Spot fleet, increase its target capacity. The Spot fleet -// launches the additional Spot instances according to the allocation strategy -// for the Spot fleet request. If the allocation strategy is lowestPrice, the -// Spot fleet launches instances using the Spot pool with the lowest price. -// If the allocation strategy is diversified, the Spot fleet distributes the +// To scale up your Spot Fleet, increase its target capacity. The Spot Fleet +// launches the additional Spot Instances according to the allocation strategy +// for the Spot Fleet request. If the allocation strategy is lowestPrice, the +// Spot Fleet launches instances using the Spot pool with the lowest price. +// If the allocation strategy is diversified, the Spot Fleet distributes the // instances across the Spot pools. // -// To scale down your Spot fleet, decrease its target capacity. First, the Spot -// fleet cancels any open bids that exceed the new target capacity. You can -// request that the Spot fleet terminate Spot instances until the size of the -// fleet no longer exceeds the new target capacity. If the allocation strategy -// is lowestPrice, the Spot fleet terminates the instances with the highest -// price per unit. If the allocation strategy is diversified, the Spot fleet +// To scale down your Spot Fleet, decrease its target capacity. First, the Spot +// Fleet cancels any open requests that exceed the new target capacity. You +// can request that the Spot Fleet terminate Spot Instances until the size of +// the fleet no longer exceeds the new target capacity. If the allocation strategy +// is lowestPrice, the Spot Fleet terminates the instances with the highest +// price per unit. If the allocation strategy is diversified, the Spot Fleet // terminates instances across the Spot pools. Alternatively, you can request -// that the Spot fleet keep the fleet at its current size, but not replace any -// Spot instances that are interrupted or that you terminate manually. +// that the Spot Fleet keep the fleet at its current size, but not replace any +// Spot Instances that are interrupted or that you terminate manually. +// +// If you are finished with your Spot Fleet for now, but will use it again later, +// you can set the target capacity to 0. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -16607,7 +18298,7 @@ func (c *EC2) ModifySpotFleetRequestRequest(input *ModifySpotFleetRequestInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifySpotFleetRequest for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequest func (c *EC2) ModifySpotFleetRequest(input *ModifySpotFleetRequestInput) (*ModifySpotFleetRequestOutput, error) { req, out := c.ModifySpotFleetRequestRequest(input) return out, req.Send() @@ -16633,19 +18324,18 @@ const opModifySubnetAttribute = "ModifySubnetAttribute" // ModifySubnetAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifySubnetAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifySubnetAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifySubnetAttribute method directly -// instead. +// See ModifySubnetAttribute for more information on using the ModifySubnetAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifySubnetAttributeRequest method. // req, resp := client.ModifySubnetAttributeRequest(params) @@ -16655,7 +18345,7 @@ const opModifySubnetAttribute = "ModifySubnetAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttribute func (c *EC2) ModifySubnetAttributeRequest(input *ModifySubnetAttributeInput) (req *request.Request, output *ModifySubnetAttributeOutput) { op := &request.Operation{ Name: opModifySubnetAttribute, @@ -16684,7 +18374,7 @@ func (c *EC2) ModifySubnetAttributeRequest(input *ModifySubnetAttributeInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifySubnetAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttribute func (c *EC2) ModifySubnetAttribute(input *ModifySubnetAttributeInput) (*ModifySubnetAttributeOutput, error) { req, out := c.ModifySubnetAttributeRequest(input) return out, req.Send() @@ -16710,19 +18400,18 @@ const opModifyVolume = "ModifyVolume" // ModifyVolumeRequest generates a "aws/request.Request" representing the // client's request for the ModifyVolume operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyVolume for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyVolume method directly -// instead. +// See ModifyVolume for more information on using the ModifyVolume +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyVolumeRequest method. // req, resp := client.ModifyVolumeRequest(params) @@ -16732,7 +18421,7 @@ const opModifyVolume = "ModifyVolume" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolume func (c *EC2) ModifyVolumeRequest(input *ModifyVolumeInput) (req *request.Request, output *ModifyVolumeOutput) { op := &request.Operation{ Name: opModifyVolume, @@ -16791,7 +18480,7 @@ func (c *EC2) ModifyVolumeRequest(input *ModifyVolumeInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyVolume for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolume func (c *EC2) ModifyVolume(input *ModifyVolumeInput) (*ModifyVolumeOutput, error) { req, out := c.ModifyVolumeRequest(input) return out, req.Send() @@ -16817,19 +18506,18 @@ const opModifyVolumeAttribute = "ModifyVolumeAttribute" // ModifyVolumeAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifyVolumeAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyVolumeAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyVolumeAttribute method directly -// instead. +// See ModifyVolumeAttribute for more information on using the ModifyVolumeAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyVolumeAttributeRequest method. // req, resp := client.ModifyVolumeAttributeRequest(params) @@ -16839,7 +18527,7 @@ const opModifyVolumeAttribute = "ModifyVolumeAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttribute func (c *EC2) ModifyVolumeAttributeRequest(input *ModifyVolumeAttributeInput) (req *request.Request, output *ModifyVolumeAttributeOutput) { op := &request.Operation{ Name: opModifyVolumeAttribute, @@ -16877,7 +18565,7 @@ func (c *EC2) ModifyVolumeAttributeRequest(input *ModifyVolumeAttributeInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyVolumeAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttribute func (c *EC2) ModifyVolumeAttribute(input *ModifyVolumeAttributeInput) (*ModifyVolumeAttributeOutput, error) { req, out := c.ModifyVolumeAttributeRequest(input) return out, req.Send() @@ -16903,19 +18591,18 @@ const opModifyVpcAttribute = "ModifyVpcAttribute" // ModifyVpcAttributeRequest generates a "aws/request.Request" representing the // client's request for the ModifyVpcAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyVpcAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyVpcAttribute method directly -// instead. +// See ModifyVpcAttribute for more information on using the ModifyVpcAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyVpcAttributeRequest method. // req, resp := client.ModifyVpcAttributeRequest(params) @@ -16925,7 +18612,7 @@ const opModifyVpcAttribute = "ModifyVpcAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttribute func (c *EC2) ModifyVpcAttributeRequest(input *ModifyVpcAttributeInput) (req *request.Request, output *ModifyVpcAttributeOutput) { op := &request.Operation{ Name: opModifyVpcAttribute, @@ -16954,7 +18641,7 @@ func (c *EC2) ModifyVpcAttributeRequest(input *ModifyVpcAttributeInput) (req *re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyVpcAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttribute func (c *EC2) ModifyVpcAttribute(input *ModifyVpcAttributeInput) (*ModifyVpcAttributeOutput, error) { req, out := c.ModifyVpcAttributeRequest(input) return out, req.Send() @@ -16980,19 +18667,18 @@ const opModifyVpcEndpoint = "ModifyVpcEndpoint" // ModifyVpcEndpointRequest generates a "aws/request.Request" representing the // client's request for the ModifyVpcEndpoint operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyVpcEndpoint for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyVpcEndpoint method directly -// instead. +// See ModifyVpcEndpoint for more information on using the ModifyVpcEndpoint +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyVpcEndpointRequest method. // req, resp := client.ModifyVpcEndpointRequest(params) @@ -17002,7 +18688,7 @@ const opModifyVpcEndpoint = "ModifyVpcEndpoint" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpoint +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpoint func (c *EC2) ModifyVpcEndpointRequest(input *ModifyVpcEndpointInput) (req *request.Request, output *ModifyVpcEndpointOutput) { op := &request.Operation{ Name: opModifyVpcEndpoint, @@ -17021,9 +18707,10 @@ func (c *EC2) ModifyVpcEndpointRequest(input *ModifyVpcEndpointInput) (req *requ // ModifyVpcEndpoint API operation for Amazon Elastic Compute Cloud. // -// Modifies attributes of a specified VPC endpoint. You can modify the policy -// associated with the endpoint, and you can add and remove route tables associated -// with the endpoint. +// Modifies attributes of a specified VPC endpoint. The attributes that you +// can modify depend on the type of VPC endpoint (interface or gateway). For +// more information, see VPC Endpoints (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-endpoints.html) +// in the Amazon Virtual Private Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -17031,7 +18718,7 @@ func (c *EC2) ModifyVpcEndpointRequest(input *ModifyVpcEndpointInput) (req *requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyVpcEndpoint for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpoint +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpoint func (c *EC2) ModifyVpcEndpoint(input *ModifyVpcEndpointInput) (*ModifyVpcEndpointOutput, error) { req, out := c.ModifyVpcEndpointRequest(input) return out, req.Send() @@ -17053,23 +18740,251 @@ func (c *EC2) ModifyVpcEndpointWithContext(ctx aws.Context, input *ModifyVpcEndp return out, req.Send() } +const opModifyVpcEndpointConnectionNotification = "ModifyVpcEndpointConnectionNotification" + +// ModifyVpcEndpointConnectionNotificationRequest generates a "aws/request.Request" representing the +// client's request for the ModifyVpcEndpointConnectionNotification operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyVpcEndpointConnectionNotification for more information on using the ModifyVpcEndpointConnectionNotification +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyVpcEndpointConnectionNotificationRequest method. +// req, resp := client.ModifyVpcEndpointConnectionNotificationRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointConnectionNotification +func (c *EC2) ModifyVpcEndpointConnectionNotificationRequest(input *ModifyVpcEndpointConnectionNotificationInput) (req *request.Request, output *ModifyVpcEndpointConnectionNotificationOutput) { + op := &request.Operation{ + Name: opModifyVpcEndpointConnectionNotification, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyVpcEndpointConnectionNotificationInput{} + } + + output = &ModifyVpcEndpointConnectionNotificationOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyVpcEndpointConnectionNotification API operation for Amazon Elastic Compute Cloud. +// +// Modifies a connection notification for VPC endpoint or VPC endpoint service. +// You can change the SNS topic for the notification, or the events for which +// to be notified. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyVpcEndpointConnectionNotification for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointConnectionNotification +func (c *EC2) ModifyVpcEndpointConnectionNotification(input *ModifyVpcEndpointConnectionNotificationInput) (*ModifyVpcEndpointConnectionNotificationOutput, error) { + req, out := c.ModifyVpcEndpointConnectionNotificationRequest(input) + return out, req.Send() +} + +// ModifyVpcEndpointConnectionNotificationWithContext is the same as ModifyVpcEndpointConnectionNotification with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyVpcEndpointConnectionNotification for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyVpcEndpointConnectionNotificationWithContext(ctx aws.Context, input *ModifyVpcEndpointConnectionNotificationInput, opts ...request.Option) (*ModifyVpcEndpointConnectionNotificationOutput, error) { + req, out := c.ModifyVpcEndpointConnectionNotificationRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opModifyVpcEndpointServiceConfiguration = "ModifyVpcEndpointServiceConfiguration" + +// ModifyVpcEndpointServiceConfigurationRequest generates a "aws/request.Request" representing the +// client's request for the ModifyVpcEndpointServiceConfiguration operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyVpcEndpointServiceConfiguration for more information on using the ModifyVpcEndpointServiceConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyVpcEndpointServiceConfigurationRequest method. +// req, resp := client.ModifyVpcEndpointServiceConfigurationRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServiceConfiguration +func (c *EC2) ModifyVpcEndpointServiceConfigurationRequest(input *ModifyVpcEndpointServiceConfigurationInput) (req *request.Request, output *ModifyVpcEndpointServiceConfigurationOutput) { + op := &request.Operation{ + Name: opModifyVpcEndpointServiceConfiguration, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyVpcEndpointServiceConfigurationInput{} + } + + output = &ModifyVpcEndpointServiceConfigurationOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyVpcEndpointServiceConfiguration API operation for Amazon Elastic Compute Cloud. +// +// Modifies the attributes of your VPC endpoint service configuration. You can +// change the Network Load Balancers for your service, and you can specify whether +// acceptance is required for requests to connect to your endpoint service through +// an interface VPC endpoint. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyVpcEndpointServiceConfiguration for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServiceConfiguration +func (c *EC2) ModifyVpcEndpointServiceConfiguration(input *ModifyVpcEndpointServiceConfigurationInput) (*ModifyVpcEndpointServiceConfigurationOutput, error) { + req, out := c.ModifyVpcEndpointServiceConfigurationRequest(input) + return out, req.Send() +} + +// ModifyVpcEndpointServiceConfigurationWithContext is the same as ModifyVpcEndpointServiceConfiguration with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyVpcEndpointServiceConfiguration for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyVpcEndpointServiceConfigurationWithContext(ctx aws.Context, input *ModifyVpcEndpointServiceConfigurationInput, opts ...request.Option) (*ModifyVpcEndpointServiceConfigurationOutput, error) { + req, out := c.ModifyVpcEndpointServiceConfigurationRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opModifyVpcEndpointServicePermissions = "ModifyVpcEndpointServicePermissions" + +// ModifyVpcEndpointServicePermissionsRequest generates a "aws/request.Request" representing the +// client's request for the ModifyVpcEndpointServicePermissions operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyVpcEndpointServicePermissions for more information on using the ModifyVpcEndpointServicePermissions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyVpcEndpointServicePermissionsRequest method. +// req, resp := client.ModifyVpcEndpointServicePermissionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServicePermissions +func (c *EC2) ModifyVpcEndpointServicePermissionsRequest(input *ModifyVpcEndpointServicePermissionsInput) (req *request.Request, output *ModifyVpcEndpointServicePermissionsOutput) { + op := &request.Operation{ + Name: opModifyVpcEndpointServicePermissions, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyVpcEndpointServicePermissionsInput{} + } + + output = &ModifyVpcEndpointServicePermissionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyVpcEndpointServicePermissions API operation for Amazon Elastic Compute Cloud. +// +// Modifies the permissions for your VPC endpoint service (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/endpoint-service.html). +// You can add or remove permissions for service consumers (IAM users, IAM roles, +// and AWS accounts) to connect to your endpoint service. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyVpcEndpointServicePermissions for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServicePermissions +func (c *EC2) ModifyVpcEndpointServicePermissions(input *ModifyVpcEndpointServicePermissionsInput) (*ModifyVpcEndpointServicePermissionsOutput, error) { + req, out := c.ModifyVpcEndpointServicePermissionsRequest(input) + return out, req.Send() +} + +// ModifyVpcEndpointServicePermissionsWithContext is the same as ModifyVpcEndpointServicePermissions with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyVpcEndpointServicePermissions for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyVpcEndpointServicePermissionsWithContext(ctx aws.Context, input *ModifyVpcEndpointServicePermissionsInput, opts ...request.Option) (*ModifyVpcEndpointServicePermissionsOutput, error) { + req, out := c.ModifyVpcEndpointServicePermissionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opModifyVpcPeeringConnectionOptions = "ModifyVpcPeeringConnectionOptions" // ModifyVpcPeeringConnectionOptionsRequest generates a "aws/request.Request" representing the // client's request for the ModifyVpcPeeringConnectionOptions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ModifyVpcPeeringConnectionOptions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ModifyVpcPeeringConnectionOptions method directly -// instead. +// See ModifyVpcPeeringConnectionOptions for more information on using the ModifyVpcPeeringConnectionOptions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ModifyVpcPeeringConnectionOptionsRequest method. // req, resp := client.ModifyVpcPeeringConnectionOptionsRequest(params) @@ -17079,7 +18994,7 @@ const opModifyVpcPeeringConnectionOptions = "ModifyVpcPeeringConnectionOptions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptions func (c *EC2) ModifyVpcPeeringConnectionOptionsRequest(input *ModifyVpcPeeringConnectionOptionsInput) (req *request.Request, output *ModifyVpcPeeringConnectionOptionsOutput) { op := &request.Operation{ Name: opModifyVpcPeeringConnectionOptions, @@ -17125,7 +19040,7 @@ func (c *EC2) ModifyVpcPeeringConnectionOptionsRequest(input *ModifyVpcPeeringCo // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ModifyVpcPeeringConnectionOptions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptions func (c *EC2) ModifyVpcPeeringConnectionOptions(input *ModifyVpcPeeringConnectionOptionsInput) (*ModifyVpcPeeringConnectionOptionsOutput, error) { req, out := c.ModifyVpcPeeringConnectionOptionsRequest(input) return out, req.Send() @@ -17147,23 +19062,105 @@ func (c *EC2) ModifyVpcPeeringConnectionOptionsWithContext(ctx aws.Context, inpu return out, req.Send() } +const opModifyVpcTenancy = "ModifyVpcTenancy" + +// ModifyVpcTenancyRequest generates a "aws/request.Request" representing the +// client's request for the ModifyVpcTenancy operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ModifyVpcTenancy for more information on using the ModifyVpcTenancy +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ModifyVpcTenancyRequest method. +// req, resp := client.ModifyVpcTenancyRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcTenancy +func (c *EC2) ModifyVpcTenancyRequest(input *ModifyVpcTenancyInput) (req *request.Request, output *ModifyVpcTenancyOutput) { + op := &request.Operation{ + Name: opModifyVpcTenancy, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ModifyVpcTenancyInput{} + } + + output = &ModifyVpcTenancyOutput{} + req = c.newRequest(op, input, output) + return +} + +// ModifyVpcTenancy API operation for Amazon Elastic Compute Cloud. +// +// Modifies the instance tenancy attribute of the specified VPC. You can change +// the instance tenancy attribute of a VPC to default only. You cannot change +// the instance tenancy attribute to dedicated. +// +// After you modify the tenancy of the VPC, any new instances that you launch +// into the VPC have a tenancy of default, unless you specify otherwise during +// launch. The tenancy of any existing instances in the VPC is not affected. +// +// For more information about Dedicated Instances, see Dedicated Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html) +// in the Amazon Elastic Compute Cloud User Guide. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ModifyVpcTenancy for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcTenancy +func (c *EC2) ModifyVpcTenancy(input *ModifyVpcTenancyInput) (*ModifyVpcTenancyOutput, error) { + req, out := c.ModifyVpcTenancyRequest(input) + return out, req.Send() +} + +// ModifyVpcTenancyWithContext is the same as ModifyVpcTenancy with the addition of +// the ability to pass a context and additional request options. +// +// See ModifyVpcTenancy for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ModifyVpcTenancyWithContext(ctx aws.Context, input *ModifyVpcTenancyInput, opts ...request.Option) (*ModifyVpcTenancyOutput, error) { + req, out := c.ModifyVpcTenancyRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opMonitorInstances = "MonitorInstances" // MonitorInstancesRequest generates a "aws/request.Request" representing the // client's request for the MonitorInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See MonitorInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the MonitorInstances method directly -// instead. +// See MonitorInstances for more information on using the MonitorInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the MonitorInstancesRequest method. // req, resp := client.MonitorInstancesRequest(params) @@ -17173,7 +19170,7 @@ const opMonitorInstances = "MonitorInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstances func (c *EC2) MonitorInstancesRequest(input *MonitorInstancesInput) (req *request.Request, output *MonitorInstancesOutput) { op := &request.Operation{ Name: opMonitorInstances, @@ -17205,7 +19202,7 @@ func (c *EC2) MonitorInstancesRequest(input *MonitorInstancesInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation MonitorInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstances func (c *EC2) MonitorInstances(input *MonitorInstancesInput) (*MonitorInstancesOutput, error) { req, out := c.MonitorInstancesRequest(input) return out, req.Send() @@ -17231,19 +19228,18 @@ const opMoveAddressToVpc = "MoveAddressToVpc" // MoveAddressToVpcRequest generates a "aws/request.Request" representing the // client's request for the MoveAddressToVpc operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See MoveAddressToVpc for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the MoveAddressToVpc method directly -// instead. +// See MoveAddressToVpc for more information on using the MoveAddressToVpc +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the MoveAddressToVpcRequest method. // req, resp := client.MoveAddressToVpcRequest(params) @@ -17253,7 +19249,7 @@ const opMoveAddressToVpc = "MoveAddressToVpc" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpc func (c *EC2) MoveAddressToVpcRequest(input *MoveAddressToVpcInput) (req *request.Request, output *MoveAddressToVpcOutput) { op := &request.Operation{ Name: opMoveAddressToVpc, @@ -17286,7 +19282,7 @@ func (c *EC2) MoveAddressToVpcRequest(input *MoveAddressToVpcInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation MoveAddressToVpc for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpc func (c *EC2) MoveAddressToVpc(input *MoveAddressToVpcInput) (*MoveAddressToVpcOutput, error) { req, out := c.MoveAddressToVpcRequest(input) return out, req.Send() @@ -17312,19 +19308,18 @@ const opPurchaseHostReservation = "PurchaseHostReservation" // PurchaseHostReservationRequest generates a "aws/request.Request" representing the // client's request for the PurchaseHostReservation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PurchaseHostReservation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PurchaseHostReservation method directly -// instead. +// See PurchaseHostReservation for more information on using the PurchaseHostReservation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PurchaseHostReservationRequest method. // req, resp := client.PurchaseHostReservationRequest(params) @@ -17334,7 +19329,7 @@ const opPurchaseHostReservation = "PurchaseHostReservation" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservation func (c *EC2) PurchaseHostReservationRequest(input *PurchaseHostReservationInput) (req *request.Request, output *PurchaseHostReservationOutput) { op := &request.Operation{ Name: opPurchaseHostReservation, @@ -17364,7 +19359,7 @@ func (c *EC2) PurchaseHostReservationRequest(input *PurchaseHostReservationInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation PurchaseHostReservation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservation func (c *EC2) PurchaseHostReservation(input *PurchaseHostReservationInput) (*PurchaseHostReservationOutput, error) { req, out := c.PurchaseHostReservationRequest(input) return out, req.Send() @@ -17390,19 +19385,18 @@ const opPurchaseReservedInstancesOffering = "PurchaseReservedInstancesOffering" // PurchaseReservedInstancesOfferingRequest generates a "aws/request.Request" representing the // client's request for the PurchaseReservedInstancesOffering operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PurchaseReservedInstancesOffering for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PurchaseReservedInstancesOffering method directly -// instead. +// See PurchaseReservedInstancesOffering for more information on using the PurchaseReservedInstancesOffering +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PurchaseReservedInstancesOfferingRequest method. // req, resp := client.PurchaseReservedInstancesOfferingRequest(params) @@ -17412,7 +19406,7 @@ const opPurchaseReservedInstancesOffering = "PurchaseReservedInstancesOffering" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOffering +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOffering func (c *EC2) PurchaseReservedInstancesOfferingRequest(input *PurchaseReservedInstancesOfferingInput) (req *request.Request, output *PurchaseReservedInstancesOfferingOutput) { op := &request.Operation{ Name: opPurchaseReservedInstancesOffering, @@ -17448,7 +19442,7 @@ func (c *EC2) PurchaseReservedInstancesOfferingRequest(input *PurchaseReservedIn // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation PurchaseReservedInstancesOffering for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOffering +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOffering func (c *EC2) PurchaseReservedInstancesOffering(input *PurchaseReservedInstancesOfferingInput) (*PurchaseReservedInstancesOfferingOutput, error) { req, out := c.PurchaseReservedInstancesOfferingRequest(input) return out, req.Send() @@ -17474,19 +19468,18 @@ const opPurchaseScheduledInstances = "PurchaseScheduledInstances" // PurchaseScheduledInstancesRequest generates a "aws/request.Request" representing the // client's request for the PurchaseScheduledInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PurchaseScheduledInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PurchaseScheduledInstances method directly -// instead. +// See PurchaseScheduledInstances for more information on using the PurchaseScheduledInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PurchaseScheduledInstancesRequest method. // req, resp := client.PurchaseScheduledInstancesRequest(params) @@ -17496,7 +19489,7 @@ const opPurchaseScheduledInstances = "PurchaseScheduledInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstances func (c *EC2) PurchaseScheduledInstancesRequest(input *PurchaseScheduledInstancesInput) (req *request.Request, output *PurchaseScheduledInstancesOutput) { op := &request.Operation{ Name: opPurchaseScheduledInstances, @@ -17532,7 +19525,7 @@ func (c *EC2) PurchaseScheduledInstancesRequest(input *PurchaseScheduledInstance // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation PurchaseScheduledInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstances func (c *EC2) PurchaseScheduledInstances(input *PurchaseScheduledInstancesInput) (*PurchaseScheduledInstancesOutput, error) { req, out := c.PurchaseScheduledInstancesRequest(input) return out, req.Send() @@ -17558,19 +19551,18 @@ const opRebootInstances = "RebootInstances" // RebootInstancesRequest generates a "aws/request.Request" representing the // client's request for the RebootInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RebootInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RebootInstances method directly -// instead. +// See RebootInstances for more information on using the RebootInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RebootInstancesRequest method. // req, resp := client.RebootInstancesRequest(params) @@ -17580,7 +19572,7 @@ const opRebootInstances = "RebootInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstances func (c *EC2) RebootInstancesRequest(input *RebootInstancesInput) (req *request.Request, output *RebootInstancesOutput) { op := &request.Operation{ Name: opRebootInstances, @@ -17619,7 +19611,7 @@ func (c *EC2) RebootInstancesRequest(input *RebootInstancesInput) (req *request. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RebootInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstances func (c *EC2) RebootInstances(input *RebootInstancesInput) (*RebootInstancesOutput, error) { req, out := c.RebootInstancesRequest(input) return out, req.Send() @@ -17645,19 +19637,18 @@ const opRegisterImage = "RegisterImage" // RegisterImageRequest generates a "aws/request.Request" representing the // client's request for the RegisterImage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RegisterImage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RegisterImage method directly -// instead. +// See RegisterImage for more information on using the RegisterImage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RegisterImageRequest method. // req, resp := client.RegisterImageRequest(params) @@ -17667,7 +19658,7 @@ const opRegisterImage = "RegisterImage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImage func (c *EC2) RegisterImageRequest(input *RegisterImageInput) (req *request.Request, output *RegisterImageOutput) { op := &request.Operation{ Name: opRegisterImage, @@ -17722,7 +19713,7 @@ func (c *EC2) RegisterImageRequest(input *RegisterImageInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RegisterImage for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImage func (c *EC2) RegisterImage(input *RegisterImageInput) (*RegisterImageOutput, error) { req, out := c.RegisterImageRequest(input) return out, req.Send() @@ -17744,23 +19735,97 @@ func (c *EC2) RegisterImageWithContext(ctx aws.Context, input *RegisterImageInpu return out, req.Send() } +const opRejectVpcEndpointConnections = "RejectVpcEndpointConnections" + +// RejectVpcEndpointConnectionsRequest generates a "aws/request.Request" representing the +// client's request for the RejectVpcEndpointConnections operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See RejectVpcEndpointConnections for more information on using the RejectVpcEndpointConnections +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the RejectVpcEndpointConnectionsRequest method. +// req, resp := client.RejectVpcEndpointConnectionsRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcEndpointConnections +func (c *EC2) RejectVpcEndpointConnectionsRequest(input *RejectVpcEndpointConnectionsInput) (req *request.Request, output *RejectVpcEndpointConnectionsOutput) { + op := &request.Operation{ + Name: opRejectVpcEndpointConnections, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &RejectVpcEndpointConnectionsInput{} + } + + output = &RejectVpcEndpointConnectionsOutput{} + req = c.newRequest(op, input, output) + return +} + +// RejectVpcEndpointConnections API operation for Amazon Elastic Compute Cloud. +// +// Rejects one or more VPC endpoint connection requests to your VPC endpoint +// service. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation RejectVpcEndpointConnections for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcEndpointConnections +func (c *EC2) RejectVpcEndpointConnections(input *RejectVpcEndpointConnectionsInput) (*RejectVpcEndpointConnectionsOutput, error) { + req, out := c.RejectVpcEndpointConnectionsRequest(input) + return out, req.Send() +} + +// RejectVpcEndpointConnectionsWithContext is the same as RejectVpcEndpointConnections with the addition of +// the ability to pass a context and additional request options. +// +// See RejectVpcEndpointConnections for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) RejectVpcEndpointConnectionsWithContext(ctx aws.Context, input *RejectVpcEndpointConnectionsInput, opts ...request.Option) (*RejectVpcEndpointConnectionsOutput, error) { + req, out := c.RejectVpcEndpointConnectionsRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opRejectVpcPeeringConnection = "RejectVpcPeeringConnection" // RejectVpcPeeringConnectionRequest generates a "aws/request.Request" representing the // client's request for the RejectVpcPeeringConnection operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RejectVpcPeeringConnection for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RejectVpcPeeringConnection method directly -// instead. +// See RejectVpcPeeringConnection for more information on using the RejectVpcPeeringConnection +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RejectVpcPeeringConnectionRequest method. // req, resp := client.RejectVpcPeeringConnectionRequest(params) @@ -17770,7 +19835,7 @@ const opRejectVpcPeeringConnection = "RejectVpcPeeringConnection" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnection func (c *EC2) RejectVpcPeeringConnectionRequest(input *RejectVpcPeeringConnectionInput) (req *request.Request, output *RejectVpcPeeringConnectionOutput) { op := &request.Operation{ Name: opRejectVpcPeeringConnection, @@ -17801,7 +19866,7 @@ func (c *EC2) RejectVpcPeeringConnectionRequest(input *RejectVpcPeeringConnectio // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RejectVpcPeeringConnection for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnection func (c *EC2) RejectVpcPeeringConnection(input *RejectVpcPeeringConnectionInput) (*RejectVpcPeeringConnectionOutput, error) { req, out := c.RejectVpcPeeringConnectionRequest(input) return out, req.Send() @@ -17827,19 +19892,18 @@ const opReleaseAddress = "ReleaseAddress" // ReleaseAddressRequest generates a "aws/request.Request" representing the // client's request for the ReleaseAddress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReleaseAddress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReleaseAddress method directly -// instead. +// See ReleaseAddress for more information on using the ReleaseAddress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReleaseAddressRequest method. // req, resp := client.ReleaseAddressRequest(params) @@ -17849,7 +19913,7 @@ const opReleaseAddress = "ReleaseAddress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddress func (c *EC2) ReleaseAddressRequest(input *ReleaseAddressInput) (req *request.Request, output *ReleaseAddressOutput) { op := &request.Operation{ Name: opReleaseAddress, @@ -17872,19 +19936,22 @@ func (c *EC2) ReleaseAddressRequest(input *ReleaseAddressInput) (req *request.Re // // Releases the specified Elastic IP address. // -// After releasing an Elastic IP address, it is released to the IP address pool -// and might be unavailable to you. Be sure to update your DNS records and any -// servers or devices that communicate with the address. If you attempt to release -// an Elastic IP address that you already released, you'll get an AuthFailure -// error if the address is already allocated to another AWS account. -// // [EC2-Classic, default VPC] Releasing an Elastic IP address automatically // disassociates it from any instance that it's associated with. To disassociate // an Elastic IP address without releasing it, use DisassociateAddress. // // [Nondefault VPC] You must use DisassociateAddress to disassociate the Elastic -// IP address before you try to release it. Otherwise, Amazon EC2 returns an -// error (InvalidIPAddress.InUse). +// IP address before you can release it. Otherwise, Amazon EC2 returns an error +// (InvalidIPAddress.InUse). +// +// After releasing an Elastic IP address, it is released to the IP address pool. +// Be sure to update your DNS records and any servers or devices that communicate +// with the address. If you attempt to release an Elastic IP address that you +// already released, you'll get an AuthFailure error if the address is already +// allocated to another AWS account. +// +// [EC2-VPC] After you release an Elastic IP address for use in a VPC, you might +// be able to recover it. For more information, see AllocateAddress. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about @@ -17892,7 +19959,7 @@ func (c *EC2) ReleaseAddressRequest(input *ReleaseAddressInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReleaseAddress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddress func (c *EC2) ReleaseAddress(input *ReleaseAddressInput) (*ReleaseAddressOutput, error) { req, out := c.ReleaseAddressRequest(input) return out, req.Send() @@ -17918,19 +19985,18 @@ const opReleaseHosts = "ReleaseHosts" // ReleaseHostsRequest generates a "aws/request.Request" representing the // client's request for the ReleaseHosts operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReleaseHosts for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReleaseHosts method directly -// instead. +// See ReleaseHosts for more information on using the ReleaseHosts +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReleaseHostsRequest method. // req, resp := client.ReleaseHostsRequest(params) @@ -17940,7 +20006,7 @@ const opReleaseHosts = "ReleaseHosts" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHosts func (c *EC2) ReleaseHostsRequest(input *ReleaseHostsInput) (req *request.Request, output *ReleaseHostsOutput) { op := &request.Operation{ Name: opReleaseHosts, @@ -17978,7 +20044,7 @@ func (c *EC2) ReleaseHostsRequest(input *ReleaseHostsInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReleaseHosts for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHosts +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHosts func (c *EC2) ReleaseHosts(input *ReleaseHostsInput) (*ReleaseHostsOutput, error) { req, out := c.ReleaseHostsRequest(input) return out, req.Send() @@ -18004,19 +20070,18 @@ const opReplaceIamInstanceProfileAssociation = "ReplaceIamInstanceProfileAssocia // ReplaceIamInstanceProfileAssociationRequest generates a "aws/request.Request" representing the // client's request for the ReplaceIamInstanceProfileAssociation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReplaceIamInstanceProfileAssociation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReplaceIamInstanceProfileAssociation method directly -// instead. +// See ReplaceIamInstanceProfileAssociation for more information on using the ReplaceIamInstanceProfileAssociation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReplaceIamInstanceProfileAssociationRequest method. // req, resp := client.ReplaceIamInstanceProfileAssociationRequest(params) @@ -18026,7 +20091,7 @@ const opReplaceIamInstanceProfileAssociation = "ReplaceIamInstanceProfileAssocia // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociation func (c *EC2) ReplaceIamInstanceProfileAssociationRequest(input *ReplaceIamInstanceProfileAssociationInput) (req *request.Request, output *ReplaceIamInstanceProfileAssociationOutput) { op := &request.Operation{ Name: opReplaceIamInstanceProfileAssociation, @@ -18058,7 +20123,7 @@ func (c *EC2) ReplaceIamInstanceProfileAssociationRequest(input *ReplaceIamInsta // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReplaceIamInstanceProfileAssociation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociation func (c *EC2) ReplaceIamInstanceProfileAssociation(input *ReplaceIamInstanceProfileAssociationInput) (*ReplaceIamInstanceProfileAssociationOutput, error) { req, out := c.ReplaceIamInstanceProfileAssociationRequest(input) return out, req.Send() @@ -18084,19 +20149,18 @@ const opReplaceNetworkAclAssociation = "ReplaceNetworkAclAssociation" // ReplaceNetworkAclAssociationRequest generates a "aws/request.Request" representing the // client's request for the ReplaceNetworkAclAssociation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReplaceNetworkAclAssociation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReplaceNetworkAclAssociation method directly -// instead. +// See ReplaceNetworkAclAssociation for more information on using the ReplaceNetworkAclAssociation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReplaceNetworkAclAssociationRequest method. // req, resp := client.ReplaceNetworkAclAssociationRequest(params) @@ -18106,7 +20170,7 @@ const opReplaceNetworkAclAssociation = "ReplaceNetworkAclAssociation" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociation func (c *EC2) ReplaceNetworkAclAssociationRequest(input *ReplaceNetworkAclAssociationInput) (req *request.Request, output *ReplaceNetworkAclAssociationOutput) { op := &request.Operation{ Name: opReplaceNetworkAclAssociation, @@ -18130,13 +20194,15 @@ func (c *EC2) ReplaceNetworkAclAssociationRequest(input *ReplaceNetworkAclAssoci // For more information about network ACLs, see Network ACLs (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_ACLs.html) // in the Amazon Virtual Private Cloud User Guide. // +// This is an idempotent operation. +// // Returns awserr.Error for service API and SDK errors. Use runtime type assertions // with awserr.Error's Code and Message methods to get detailed information about // the error. // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReplaceNetworkAclAssociation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociation func (c *EC2) ReplaceNetworkAclAssociation(input *ReplaceNetworkAclAssociationInput) (*ReplaceNetworkAclAssociationOutput, error) { req, out := c.ReplaceNetworkAclAssociationRequest(input) return out, req.Send() @@ -18162,19 +20228,18 @@ const opReplaceNetworkAclEntry = "ReplaceNetworkAclEntry" // ReplaceNetworkAclEntryRequest generates a "aws/request.Request" representing the // client's request for the ReplaceNetworkAclEntry operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReplaceNetworkAclEntry for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReplaceNetworkAclEntry method directly -// instead. +// See ReplaceNetworkAclEntry for more information on using the ReplaceNetworkAclEntry +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReplaceNetworkAclEntryRequest method. // req, resp := client.ReplaceNetworkAclEntryRequest(params) @@ -18184,7 +20249,7 @@ const opReplaceNetworkAclEntry = "ReplaceNetworkAclEntry" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntry func (c *EC2) ReplaceNetworkAclEntryRequest(input *ReplaceNetworkAclEntryInput) (req *request.Request, output *ReplaceNetworkAclEntryOutput) { op := &request.Operation{ Name: opReplaceNetworkAclEntry, @@ -18215,7 +20280,7 @@ func (c *EC2) ReplaceNetworkAclEntryRequest(input *ReplaceNetworkAclEntryInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReplaceNetworkAclEntry for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntry func (c *EC2) ReplaceNetworkAclEntry(input *ReplaceNetworkAclEntryInput) (*ReplaceNetworkAclEntryOutput, error) { req, out := c.ReplaceNetworkAclEntryRequest(input) return out, req.Send() @@ -18241,19 +20306,18 @@ const opReplaceRoute = "ReplaceRoute" // ReplaceRouteRequest generates a "aws/request.Request" representing the // client's request for the ReplaceRoute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReplaceRoute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReplaceRoute method directly -// instead. +// See ReplaceRoute for more information on using the ReplaceRoute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReplaceRouteRequest method. // req, resp := client.ReplaceRouteRequest(params) @@ -18263,7 +20327,7 @@ const opReplaceRoute = "ReplaceRoute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRoute func (c *EC2) ReplaceRouteRequest(input *ReplaceRouteInput) (req *request.Request, output *ReplaceRouteOutput) { op := &request.Operation{ Name: opReplaceRoute, @@ -18298,7 +20362,7 @@ func (c *EC2) ReplaceRouteRequest(input *ReplaceRouteInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReplaceRoute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRoute func (c *EC2) ReplaceRoute(input *ReplaceRouteInput) (*ReplaceRouteOutput, error) { req, out := c.ReplaceRouteRequest(input) return out, req.Send() @@ -18324,19 +20388,18 @@ const opReplaceRouteTableAssociation = "ReplaceRouteTableAssociation" // ReplaceRouteTableAssociationRequest generates a "aws/request.Request" representing the // client's request for the ReplaceRouteTableAssociation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReplaceRouteTableAssociation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReplaceRouteTableAssociation method directly -// instead. +// See ReplaceRouteTableAssociation for more information on using the ReplaceRouteTableAssociation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReplaceRouteTableAssociationRequest method. // req, resp := client.ReplaceRouteTableAssociationRequest(params) @@ -18346,7 +20409,7 @@ const opReplaceRouteTableAssociation = "ReplaceRouteTableAssociation" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociation func (c *EC2) ReplaceRouteTableAssociationRequest(input *ReplaceRouteTableAssociationInput) (req *request.Request, output *ReplaceRouteTableAssociationOutput) { op := &request.Operation{ Name: opReplaceRouteTableAssociation, @@ -18381,7 +20444,7 @@ func (c *EC2) ReplaceRouteTableAssociationRequest(input *ReplaceRouteTableAssoci // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReplaceRouteTableAssociation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociation func (c *EC2) ReplaceRouteTableAssociation(input *ReplaceRouteTableAssociationInput) (*ReplaceRouteTableAssociationOutput, error) { req, out := c.ReplaceRouteTableAssociationRequest(input) return out, req.Send() @@ -18407,19 +20470,18 @@ const opReportInstanceStatus = "ReportInstanceStatus" // ReportInstanceStatusRequest generates a "aws/request.Request" representing the // client's request for the ReportInstanceStatus operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ReportInstanceStatus for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ReportInstanceStatus method directly -// instead. +// See ReportInstanceStatus for more information on using the ReportInstanceStatus +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ReportInstanceStatusRequest method. // req, resp := client.ReportInstanceStatusRequest(params) @@ -18429,7 +20491,7 @@ const opReportInstanceStatus = "ReportInstanceStatus" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatus func (c *EC2) ReportInstanceStatusRequest(input *ReportInstanceStatusInput) (req *request.Request, output *ReportInstanceStatusOutput) { op := &request.Operation{ Name: opReportInstanceStatus, @@ -18464,7 +20526,7 @@ func (c *EC2) ReportInstanceStatusRequest(input *ReportInstanceStatusInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ReportInstanceStatus for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatus func (c *EC2) ReportInstanceStatus(input *ReportInstanceStatusInput) (*ReportInstanceStatusOutput, error) { req, out := c.ReportInstanceStatusRequest(input) return out, req.Send() @@ -18490,19 +20552,18 @@ const opRequestSpotFleet = "RequestSpotFleet" // RequestSpotFleetRequest generates a "aws/request.Request" representing the // client's request for the RequestSpotFleet operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RequestSpotFleet for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RequestSpotFleet method directly -// instead. +// See RequestSpotFleet for more information on using the RequestSpotFleet +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RequestSpotFleetRequest method. // req, resp := client.RequestSpotFleetRequest(params) @@ -18512,7 +20573,7 @@ const opRequestSpotFleet = "RequestSpotFleet" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleet func (c *EC2) RequestSpotFleetRequest(input *RequestSpotFleetInput) (req *request.Request, output *RequestSpotFleetOutput) { op := &request.Operation{ Name: opRequestSpotFleet, @@ -18531,21 +20592,24 @@ func (c *EC2) RequestSpotFleetRequest(input *RequestSpotFleetInput) (req *reques // RequestSpotFleet API operation for Amazon Elastic Compute Cloud. // -// Creates a Spot fleet request. +// Creates a Spot Fleet request. // // You can submit a single request that includes multiple launch specifications // that vary by instance type, AMI, Availability Zone, or subnet. // -// By default, the Spot fleet requests Spot instances in the Spot pool where +// By default, the Spot Fleet requests Spot Instances in the Spot pool where // the price per unit is the lowest. Each launch specification can include its // own instance weighting that reflects the value of the instance type to your // application workload. // -// Alternatively, you can specify that the Spot fleet distribute the target +// Alternatively, you can specify that the Spot Fleet distribute the target // capacity across the Spot pools included in its launch specifications. By -// ensuring that the Spot instances in your Spot fleet are in different Spot +// ensuring that the Spot Instances in your Spot Fleet are in different Spot // pools, you can improve the availability of your fleet. // +// You can specify tags for the Spot Instances. You cannot tag other resource +// types in a Spot Fleet request; only the instance resource type is supported. +// // For more information, see Spot Fleet Requests (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-fleet-requests.html) // in the Amazon Elastic Compute Cloud User Guide. // @@ -18555,7 +20619,7 @@ func (c *EC2) RequestSpotFleetRequest(input *RequestSpotFleetInput) (req *reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RequestSpotFleet for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleet func (c *EC2) RequestSpotFleet(input *RequestSpotFleetInput) (*RequestSpotFleetOutput, error) { req, out := c.RequestSpotFleetRequest(input) return out, req.Send() @@ -18581,19 +20645,18 @@ const opRequestSpotInstances = "RequestSpotInstances" // RequestSpotInstancesRequest generates a "aws/request.Request" representing the // client's request for the RequestSpotInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RequestSpotInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RequestSpotInstances method directly -// instead. +// See RequestSpotInstances for more information on using the RequestSpotInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RequestSpotInstancesRequest method. // req, resp := client.RequestSpotInstancesRequest(params) @@ -18603,7 +20666,7 @@ const opRequestSpotInstances = "RequestSpotInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstances func (c *EC2) RequestSpotInstancesRequest(input *RequestSpotInstancesInput) (req *request.Request, output *RequestSpotInstancesOutput) { op := &request.Operation{ Name: opRequestSpotInstances, @@ -18622,11 +20685,9 @@ func (c *EC2) RequestSpotInstancesRequest(input *RequestSpotInstancesInput) (req // RequestSpotInstances API operation for Amazon Elastic Compute Cloud. // -// Creates a Spot instance request. Spot instances are instances that Amazon -// EC2 launches when the bid price that you specify exceeds the current Spot -// price. Amazon EC2 periodically sets the Spot price based on available Spot -// Instance capacity and current Spot instance requests. For more information, -// see Spot Instance Requests (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html) +// Creates a Spot Instance request. Spot Instances are instances that Amazon +// EC2 launches when the maximum price that you specify exceeds the current +// Spot price. For more information, see Spot Instance Requests (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html) // in the Amazon Elastic Compute Cloud User Guide. // // Returns awserr.Error for service API and SDK errors. Use runtime type assertions @@ -18635,7 +20696,7 @@ func (c *EC2) RequestSpotInstancesRequest(input *RequestSpotInstancesInput) (req // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RequestSpotInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstances func (c *EC2) RequestSpotInstances(input *RequestSpotInstancesInput) (*RequestSpotInstancesOutput, error) { req, out := c.RequestSpotInstancesRequest(input) return out, req.Send() @@ -18657,23 +20718,97 @@ func (c *EC2) RequestSpotInstancesWithContext(ctx aws.Context, input *RequestSpo return out, req.Send() } +const opResetFpgaImageAttribute = "ResetFpgaImageAttribute" + +// ResetFpgaImageAttributeRequest generates a "aws/request.Request" representing the +// client's request for the ResetFpgaImageAttribute operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See ResetFpgaImageAttribute for more information on using the ResetFpgaImageAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the ResetFpgaImageAttributeRequest method. +// req, resp := client.ResetFpgaImageAttributeRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetFpgaImageAttribute +func (c *EC2) ResetFpgaImageAttributeRequest(input *ResetFpgaImageAttributeInput) (req *request.Request, output *ResetFpgaImageAttributeOutput) { + op := &request.Operation{ + Name: opResetFpgaImageAttribute, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &ResetFpgaImageAttributeInput{} + } + + output = &ResetFpgaImageAttributeOutput{} + req = c.newRequest(op, input, output) + return +} + +// ResetFpgaImageAttribute API operation for Amazon Elastic Compute Cloud. +// +// Resets the specified attribute of the specified Amazon FPGA Image (AFI) to +// its default value. You can only reset the load permission attribute. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation ResetFpgaImageAttribute for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetFpgaImageAttribute +func (c *EC2) ResetFpgaImageAttribute(input *ResetFpgaImageAttributeInput) (*ResetFpgaImageAttributeOutput, error) { + req, out := c.ResetFpgaImageAttributeRequest(input) + return out, req.Send() +} + +// ResetFpgaImageAttributeWithContext is the same as ResetFpgaImageAttribute with the addition of +// the ability to pass a context and additional request options. +// +// See ResetFpgaImageAttribute for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) ResetFpgaImageAttributeWithContext(ctx aws.Context, input *ResetFpgaImageAttributeInput, opts ...request.Option) (*ResetFpgaImageAttributeOutput, error) { + req, out := c.ResetFpgaImageAttributeRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opResetImageAttribute = "ResetImageAttribute" // ResetImageAttributeRequest generates a "aws/request.Request" representing the // client's request for the ResetImageAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ResetImageAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ResetImageAttribute method directly -// instead. +// See ResetImageAttribute for more information on using the ResetImageAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ResetImageAttributeRequest method. // req, resp := client.ResetImageAttributeRequest(params) @@ -18683,7 +20818,7 @@ const opResetImageAttribute = "ResetImageAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttribute func (c *EC2) ResetImageAttributeRequest(input *ResetImageAttributeInput) (req *request.Request, output *ResetImageAttributeOutput) { op := &request.Operation{ Name: opResetImageAttribute, @@ -18714,7 +20849,7 @@ func (c *EC2) ResetImageAttributeRequest(input *ResetImageAttributeInput) (req * // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ResetImageAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttribute func (c *EC2) ResetImageAttribute(input *ResetImageAttributeInput) (*ResetImageAttributeOutput, error) { req, out := c.ResetImageAttributeRequest(input) return out, req.Send() @@ -18740,19 +20875,18 @@ const opResetInstanceAttribute = "ResetInstanceAttribute" // ResetInstanceAttributeRequest generates a "aws/request.Request" representing the // client's request for the ResetInstanceAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ResetInstanceAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ResetInstanceAttribute method directly -// instead. +// See ResetInstanceAttribute for more information on using the ResetInstanceAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ResetInstanceAttributeRequest method. // req, resp := client.ResetInstanceAttributeRequest(params) @@ -18762,7 +20896,7 @@ const opResetInstanceAttribute = "ResetInstanceAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttribute func (c *EC2) ResetInstanceAttributeRequest(input *ResetInstanceAttributeInput) (req *request.Request, output *ResetInstanceAttributeOutput) { op := &request.Operation{ Name: opResetInstanceAttribute, @@ -18799,7 +20933,7 @@ func (c *EC2) ResetInstanceAttributeRequest(input *ResetInstanceAttributeInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ResetInstanceAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttribute func (c *EC2) ResetInstanceAttribute(input *ResetInstanceAttributeInput) (*ResetInstanceAttributeOutput, error) { req, out := c.ResetInstanceAttributeRequest(input) return out, req.Send() @@ -18825,19 +20959,18 @@ const opResetNetworkInterfaceAttribute = "ResetNetworkInterfaceAttribute" // ResetNetworkInterfaceAttributeRequest generates a "aws/request.Request" representing the // client's request for the ResetNetworkInterfaceAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ResetNetworkInterfaceAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ResetNetworkInterfaceAttribute method directly -// instead. +// See ResetNetworkInterfaceAttribute for more information on using the ResetNetworkInterfaceAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ResetNetworkInterfaceAttributeRequest method. // req, resp := client.ResetNetworkInterfaceAttributeRequest(params) @@ -18847,7 +20980,7 @@ const opResetNetworkInterfaceAttribute = "ResetNetworkInterfaceAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttribute func (c *EC2) ResetNetworkInterfaceAttributeRequest(input *ResetNetworkInterfaceAttributeInput) (req *request.Request, output *ResetNetworkInterfaceAttributeOutput) { op := &request.Operation{ Name: opResetNetworkInterfaceAttribute, @@ -18877,7 +21010,7 @@ func (c *EC2) ResetNetworkInterfaceAttributeRequest(input *ResetNetworkInterface // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ResetNetworkInterfaceAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttribute func (c *EC2) ResetNetworkInterfaceAttribute(input *ResetNetworkInterfaceAttributeInput) (*ResetNetworkInterfaceAttributeOutput, error) { req, out := c.ResetNetworkInterfaceAttributeRequest(input) return out, req.Send() @@ -18903,19 +21036,18 @@ const opResetSnapshotAttribute = "ResetSnapshotAttribute" // ResetSnapshotAttributeRequest generates a "aws/request.Request" representing the // client's request for the ResetSnapshotAttribute operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ResetSnapshotAttribute for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ResetSnapshotAttribute method directly -// instead. +// See ResetSnapshotAttribute for more information on using the ResetSnapshotAttribute +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ResetSnapshotAttributeRequest method. // req, resp := client.ResetSnapshotAttributeRequest(params) @@ -18925,7 +21057,7 @@ const opResetSnapshotAttribute = "ResetSnapshotAttribute" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttribute func (c *EC2) ResetSnapshotAttributeRequest(input *ResetSnapshotAttributeInput) (req *request.Request, output *ResetSnapshotAttributeOutput) { op := &request.Operation{ Name: opResetSnapshotAttribute, @@ -18958,7 +21090,7 @@ func (c *EC2) ResetSnapshotAttributeRequest(input *ResetSnapshotAttributeInput) // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation ResetSnapshotAttribute for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttribute func (c *EC2) ResetSnapshotAttribute(input *ResetSnapshotAttributeInput) (*ResetSnapshotAttributeOutput, error) { req, out := c.ResetSnapshotAttributeRequest(input) return out, req.Send() @@ -18984,19 +21116,18 @@ const opRestoreAddressToClassic = "RestoreAddressToClassic" // RestoreAddressToClassicRequest generates a "aws/request.Request" representing the // client's request for the RestoreAddressToClassic operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RestoreAddressToClassic for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RestoreAddressToClassic method directly -// instead. +// See RestoreAddressToClassic for more information on using the RestoreAddressToClassic +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RestoreAddressToClassicRequest method. // req, resp := client.RestoreAddressToClassicRequest(params) @@ -19006,7 +21137,7 @@ const opRestoreAddressToClassic = "RestoreAddressToClassic" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassic +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassic func (c *EC2) RestoreAddressToClassicRequest(input *RestoreAddressToClassicInput) (req *request.Request, output *RestoreAddressToClassicOutput) { op := &request.Operation{ Name: opRestoreAddressToClassic, @@ -19036,7 +21167,7 @@ func (c *EC2) RestoreAddressToClassicRequest(input *RestoreAddressToClassicInput // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RestoreAddressToClassic for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassic +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassic func (c *EC2) RestoreAddressToClassic(input *RestoreAddressToClassicInput) (*RestoreAddressToClassicOutput, error) { req, out := c.RestoreAddressToClassicRequest(input) return out, req.Send() @@ -19062,19 +21193,18 @@ const opRevokeSecurityGroupEgress = "RevokeSecurityGroupEgress" // RevokeSecurityGroupEgressRequest generates a "aws/request.Request" representing the // client's request for the RevokeSecurityGroupEgress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RevokeSecurityGroupEgress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RevokeSecurityGroupEgress method directly -// instead. +// See RevokeSecurityGroupEgress for more information on using the RevokeSecurityGroupEgress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RevokeSecurityGroupEgressRequest method. // req, resp := client.RevokeSecurityGroupEgressRequest(params) @@ -19084,7 +21214,7 @@ const opRevokeSecurityGroupEgress = "RevokeSecurityGroupEgress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgress func (c *EC2) RevokeSecurityGroupEgressRequest(input *RevokeSecurityGroupEgressInput) (req *request.Request, output *RevokeSecurityGroupEgressOutput) { op := &request.Operation{ Name: opRevokeSecurityGroupEgress, @@ -19107,13 +21237,14 @@ func (c *EC2) RevokeSecurityGroupEgressRequest(input *RevokeSecurityGroupEgressI // // [EC2-VPC only] Removes one or more egress rules from a security group for // EC2-VPC. This action doesn't apply to security groups for use in EC2-Classic. -// The values that you specify in the revoke request (for example, ports) must -// match the existing rule's values for the rule to be revoked. +// To remove a rule, the values that you specify (for example, ports) must match +// the existing rule's values exactly. // // Each rule consists of the protocol and the IPv4 or IPv6 CIDR range or source // security group. For the TCP and UDP protocols, you must also specify the // destination port or range of ports. For the ICMP protocol, you must also -// specify the ICMP type and code. +// specify the ICMP type and code. If the security group rule has a description, +// you do not have to specify the description to revoke the rule. // // Rule changes are propagated to instances within the security group as quickly // as possible. However, a small delay might occur. @@ -19124,7 +21255,7 @@ func (c *EC2) RevokeSecurityGroupEgressRequest(input *RevokeSecurityGroupEgressI // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RevokeSecurityGroupEgress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgress func (c *EC2) RevokeSecurityGroupEgress(input *RevokeSecurityGroupEgressInput) (*RevokeSecurityGroupEgressOutput, error) { req, out := c.RevokeSecurityGroupEgressRequest(input) return out, req.Send() @@ -19150,19 +21281,18 @@ const opRevokeSecurityGroupIngress = "RevokeSecurityGroupIngress" // RevokeSecurityGroupIngressRequest generates a "aws/request.Request" representing the // client's request for the RevokeSecurityGroupIngress operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RevokeSecurityGroupIngress for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RevokeSecurityGroupIngress method directly -// instead. +// See RevokeSecurityGroupIngress for more information on using the RevokeSecurityGroupIngress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RevokeSecurityGroupIngressRequest method. // req, resp := client.RevokeSecurityGroupIngressRequest(params) @@ -19172,7 +21302,7 @@ const opRevokeSecurityGroupIngress = "RevokeSecurityGroupIngress" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngress func (c *EC2) RevokeSecurityGroupIngressRequest(input *RevokeSecurityGroupIngressInput) (req *request.Request, output *RevokeSecurityGroupIngressOutput) { op := &request.Operation{ Name: opRevokeSecurityGroupIngress, @@ -19193,14 +21323,19 @@ func (c *EC2) RevokeSecurityGroupIngressRequest(input *RevokeSecurityGroupIngres // RevokeSecurityGroupIngress API operation for Amazon Elastic Compute Cloud. // -// Removes one or more ingress rules from a security group. The values that -// you specify in the revoke request (for example, ports) must match the existing -// rule's values for the rule to be removed. +// Removes one or more ingress rules from a security group. To remove a rule, +// the values that you specify (for example, ports) must match the existing +// rule's values exactly. +// +// [EC2-Classic security groups only] If the values you specify do not match +// the existing rule's values, no error is returned. Use DescribeSecurityGroups +// to verify that the rule has been removed. // // Each rule consists of the protocol and the CIDR range or source security // group. For the TCP and UDP protocols, you must also specify the destination // port or range of ports. For the ICMP protocol, you must also specify the -// ICMP type and code. +// ICMP type and code. If the security group rule has a description, you do +// not have to specify the description to revoke the rule. // // Rule changes are propagated to instances within the security group as quickly // as possible. However, a small delay might occur. @@ -19211,7 +21346,7 @@ func (c *EC2) RevokeSecurityGroupIngressRequest(input *RevokeSecurityGroupIngres // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RevokeSecurityGroupIngress for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngress func (c *EC2) RevokeSecurityGroupIngress(input *RevokeSecurityGroupIngressInput) (*RevokeSecurityGroupIngressOutput, error) { req, out := c.RevokeSecurityGroupIngressRequest(input) return out, req.Send() @@ -19237,19 +21372,18 @@ const opRunInstances = "RunInstances" // RunInstancesRequest generates a "aws/request.Request" representing the // client's request for the RunInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RunInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RunInstances method directly -// instead. +// See RunInstances for more information on using the RunInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RunInstancesRequest method. // req, resp := client.RunInstancesRequest(params) @@ -19259,7 +21393,7 @@ const opRunInstances = "RunInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstances func (c *EC2) RunInstancesRequest(input *RunInstancesInput) (req *request.Request, output *Reservation) { op := &request.Operation{ Name: opRunInstances, @@ -19308,9 +21442,14 @@ func (c *EC2) RunInstancesRequest(input *RunInstancesInput) (req *request.Reques // * If any of the AMIs have a product code attached for which the user has // not subscribed, the request fails. // +// You can create a launch template (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html), +// which is a resource that contains the parameters to launch an instance. When +// you launch an instance using RunInstances, you can specify the launch template +// instead of specifying the launch parameters. +// // To ensure faster instance launches, break up large requests into smaller -// batches. For example, create 5 separate launch requests for 100 instances -// each instead of 1 launch request for 500 instances. +// batches. For example, create five separate launch requests for 100 instances +// each instead of one launch request for 500 instances. // // An instance is ready for you to use when it's in the running state. You can // check the state of your instance using DescribeInstances. You can tag instances @@ -19334,7 +21473,7 @@ func (c *EC2) RunInstancesRequest(input *RunInstancesInput) (req *request.Reques // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RunInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstances func (c *EC2) RunInstances(input *RunInstancesInput) (*Reservation, error) { req, out := c.RunInstancesRequest(input) return out, req.Send() @@ -19360,19 +21499,18 @@ const opRunScheduledInstances = "RunScheduledInstances" // RunScheduledInstancesRequest generates a "aws/request.Request" representing the // client's request for the RunScheduledInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RunScheduledInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RunScheduledInstances method directly -// instead. +// See RunScheduledInstances for more information on using the RunScheduledInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RunScheduledInstancesRequest method. // req, resp := client.RunScheduledInstancesRequest(params) @@ -19382,7 +21520,7 @@ const opRunScheduledInstances = "RunScheduledInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstances func (c *EC2) RunScheduledInstancesRequest(input *RunScheduledInstancesInput) (req *request.Request, output *RunScheduledInstancesOutput) { op := &request.Operation{ Name: opRunScheduledInstances, @@ -19419,7 +21557,7 @@ func (c *EC2) RunScheduledInstancesRequest(input *RunScheduledInstancesInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation RunScheduledInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstances func (c *EC2) RunScheduledInstances(input *RunScheduledInstancesInput) (*RunScheduledInstancesOutput, error) { req, out := c.RunScheduledInstancesRequest(input) return out, req.Send() @@ -19445,19 +21583,18 @@ const opStartInstances = "StartInstances" // StartInstancesRequest generates a "aws/request.Request" representing the // client's request for the StartInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See StartInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the StartInstances method directly -// instead. +// See StartInstances for more information on using the StartInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the StartInstancesRequest method. // req, resp := client.StartInstancesRequest(params) @@ -19467,7 +21604,7 @@ const opStartInstances = "StartInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstances func (c *EC2) StartInstancesRequest(input *StartInstancesInput) (req *request.Request, output *StartInstancesOutput) { op := &request.Operation{ Name: opStartInstances, @@ -19486,16 +21623,20 @@ func (c *EC2) StartInstancesRequest(input *StartInstancesInput) (req *request.Re // StartInstances API operation for Amazon Elastic Compute Cloud. // -// Starts an Amazon EBS-backed AMI that you've previously stopped. +// Starts an Amazon EBS-backed instance that you've previously stopped. // // Instances that use Amazon EBS volumes as their root devices can be quickly // stopped and started. When an instance is stopped, the compute resources are -// released and you are not billed for hourly instance usage. However, your -// root partition Amazon EBS volume remains, continues to persist your data, -// and you are charged for Amazon EBS volume usage. You can restart your instance -// at any time. Each time you transition an instance from stopped to started, -// Amazon EC2 charges a full instance hour, even if transitions happen multiple -// times within a single hour. +// released and you are not billed for instance usage. However, your root partition +// Amazon EBS volume remains and continues to persist your data, and you are +// charged for Amazon EBS volume usage. You can restart your instance at any +// time. Every time you start your Windows instance, Amazon EC2 charges you +// for a full instance hour. If you stop and restart your Windows instance, +// a new instance hour begins and Amazon EC2 charges you for another full instance +// hour even if you are still within the same 60-minute period when it was stopped. +// Every time you start your Linux instance, Amazon EC2 charges a one-minute +// minimum for instance usage, and thereafter charges per second for instance +// usage. // // Before stopping an instance, make sure it is in a state from which it can // be restarted. Stopping an instance does not preserve data stored in RAM. @@ -19512,7 +21653,7 @@ func (c *EC2) StartInstancesRequest(input *StartInstancesInput) (req *request.Re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation StartInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstances func (c *EC2) StartInstances(input *StartInstancesInput) (*StartInstancesOutput, error) { req, out := c.StartInstancesRequest(input) return out, req.Send() @@ -19538,19 +21679,18 @@ const opStopInstances = "StopInstances" // StopInstancesRequest generates a "aws/request.Request" representing the // client's request for the StopInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See StopInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the StopInstances method directly -// instead. +// See StopInstances for more information on using the StopInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the StopInstancesRequest method. // req, resp := client.StopInstancesRequest(params) @@ -19560,7 +21700,7 @@ const opStopInstances = "StopInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstances func (c *EC2) StopInstancesRequest(input *StopInstancesInput) (req *request.Request, output *StopInstancesOutput) { op := &request.Operation{ Name: opStopInstances, @@ -19581,14 +21721,17 @@ func (c *EC2) StopInstancesRequest(input *StopInstancesInput) (req *request.Requ // // Stops an Amazon EBS-backed instance. // -// We don't charge hourly usage for a stopped instance, or data transfer fees; -// however, your root partition Amazon EBS volume remains, continues to persist -// your data, and you are charged for Amazon EBS volume usage. Each time you -// transition an instance from stopped to started, Amazon EC2 charges a full -// instance hour, even if transitions happen multiple times within a single -// hour. +// We don't charge usage for a stopped instance, or data transfer fees; however, +// your root partition Amazon EBS volume remains and continues to persist your +// data, and you are charged for Amazon EBS volume usage. Every time you start +// your Windows instance, Amazon EC2 charges you for a full instance hour. If +// you stop and restart your Windows instance, a new instance hour begins and +// Amazon EC2 charges you for another full instance hour even if you are still +// within the same 60-minute period when it was stopped. Every time you start +// your Linux instance, Amazon EC2 charges a one-minute minimum for instance +// usage, and thereafter charges per second for instance usage. // -// You can't start or stop Spot instances, and you can't stop instance store-backed +// You can't start or stop Spot Instances, and you can't stop instance store-backed // instances. // // When you stop an instance, we shut it down. You can restart your instance @@ -19616,7 +21759,7 @@ func (c *EC2) StopInstancesRequest(input *StopInstancesInput) (req *request.Requ // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation StopInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstances func (c *EC2) StopInstances(input *StopInstancesInput) (*StopInstancesOutput, error) { req, out := c.StopInstancesRequest(input) return out, req.Send() @@ -19642,19 +21785,18 @@ const opTerminateInstances = "TerminateInstances" // TerminateInstancesRequest generates a "aws/request.Request" representing the // client's request for the TerminateInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See TerminateInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the TerminateInstances method directly -// instead. +// See TerminateInstances for more information on using the TerminateInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the TerminateInstancesRequest method. // req, resp := client.TerminateInstancesRequest(params) @@ -19664,7 +21806,7 @@ const opTerminateInstances = "TerminateInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstances func (c *EC2) TerminateInstancesRequest(input *TerminateInstancesInput) (req *request.Request, output *TerminateInstancesOutput) { op := &request.Operation{ Name: opTerminateInstances, @@ -19715,7 +21857,7 @@ func (c *EC2) TerminateInstancesRequest(input *TerminateInstancesInput) (req *re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation TerminateInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstances func (c *EC2) TerminateInstances(input *TerminateInstancesInput) (*TerminateInstancesOutput, error) { req, out := c.TerminateInstancesRequest(input) return out, req.Send() @@ -19741,19 +21883,18 @@ const opUnassignIpv6Addresses = "UnassignIpv6Addresses" // UnassignIpv6AddressesRequest generates a "aws/request.Request" representing the // client's request for the UnassignIpv6Addresses operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See UnassignIpv6Addresses for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the UnassignIpv6Addresses method directly -// instead. +// See UnassignIpv6Addresses for more information on using the UnassignIpv6Addresses +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the UnassignIpv6AddressesRequest method. // req, resp := client.UnassignIpv6AddressesRequest(params) @@ -19763,7 +21904,7 @@ const opUnassignIpv6Addresses = "UnassignIpv6Addresses" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6Addresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6Addresses func (c *EC2) UnassignIpv6AddressesRequest(input *UnassignIpv6AddressesInput) (req *request.Request, output *UnassignIpv6AddressesOutput) { op := &request.Operation{ Name: opUnassignIpv6Addresses, @@ -19790,7 +21931,7 @@ func (c *EC2) UnassignIpv6AddressesRequest(input *UnassignIpv6AddressesInput) (r // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation UnassignIpv6Addresses for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6Addresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6Addresses func (c *EC2) UnassignIpv6Addresses(input *UnassignIpv6AddressesInput) (*UnassignIpv6AddressesOutput, error) { req, out := c.UnassignIpv6AddressesRequest(input) return out, req.Send() @@ -19816,19 +21957,18 @@ const opUnassignPrivateIpAddresses = "UnassignPrivateIpAddresses" // UnassignPrivateIpAddressesRequest generates a "aws/request.Request" representing the // client's request for the UnassignPrivateIpAddresses operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See UnassignPrivateIpAddresses for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the UnassignPrivateIpAddresses method directly -// instead. +// See UnassignPrivateIpAddresses for more information on using the UnassignPrivateIpAddresses +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the UnassignPrivateIpAddressesRequest method. // req, resp := client.UnassignPrivateIpAddressesRequest(params) @@ -19838,7 +21978,7 @@ const opUnassignPrivateIpAddresses = "UnassignPrivateIpAddresses" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddresses func (c *EC2) UnassignPrivateIpAddressesRequest(input *UnassignPrivateIpAddressesInput) (req *request.Request, output *UnassignPrivateIpAddressesOutput) { op := &request.Operation{ Name: opUnassignPrivateIpAddresses, @@ -19867,7 +22007,7 @@ func (c *EC2) UnassignPrivateIpAddressesRequest(input *UnassignPrivateIpAddresse // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation UnassignPrivateIpAddresses for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddresses +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddresses func (c *EC2) UnassignPrivateIpAddresses(input *UnassignPrivateIpAddressesInput) (*UnassignPrivateIpAddressesOutput, error) { req, out := c.UnassignPrivateIpAddressesRequest(input) return out, req.Send() @@ -19893,19 +22033,18 @@ const opUnmonitorInstances = "UnmonitorInstances" // UnmonitorInstancesRequest generates a "aws/request.Request" representing the // client's request for the UnmonitorInstances operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See UnmonitorInstances for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the UnmonitorInstances method directly -// instead. +// See UnmonitorInstances for more information on using the UnmonitorInstances +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the UnmonitorInstancesRequest method. // req, resp := client.UnmonitorInstancesRequest(params) @@ -19915,7 +22054,7 @@ const opUnmonitorInstances = "UnmonitorInstances" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstances func (c *EC2) UnmonitorInstancesRequest(input *UnmonitorInstancesInput) (req *request.Request, output *UnmonitorInstancesOutput) { op := &request.Operation{ Name: opUnmonitorInstances, @@ -19944,7 +22083,7 @@ func (c *EC2) UnmonitorInstancesRequest(input *UnmonitorInstancesInput) (req *re // // See the AWS API reference guide for Amazon Elastic Compute Cloud's // API operation UnmonitorInstances for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstances func (c *EC2) UnmonitorInstances(input *UnmonitorInstancesInput) (*UnmonitorInstancesOutput, error) { req, out := c.UnmonitorInstancesRequest(input) return out, req.Send() @@ -19966,8 +22105,168 @@ func (c *EC2) UnmonitorInstancesWithContext(ctx aws.Context, input *UnmonitorIns return out, req.Send() } +const opUpdateSecurityGroupRuleDescriptionsEgress = "UpdateSecurityGroupRuleDescriptionsEgress" + +// UpdateSecurityGroupRuleDescriptionsEgressRequest generates a "aws/request.Request" representing the +// client's request for the UpdateSecurityGroupRuleDescriptionsEgress operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See UpdateSecurityGroupRuleDescriptionsEgress for more information on using the UpdateSecurityGroupRuleDescriptionsEgress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the UpdateSecurityGroupRuleDescriptionsEgressRequest method. +// req, resp := client.UpdateSecurityGroupRuleDescriptionsEgressRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsEgress +func (c *EC2) UpdateSecurityGroupRuleDescriptionsEgressRequest(input *UpdateSecurityGroupRuleDescriptionsEgressInput) (req *request.Request, output *UpdateSecurityGroupRuleDescriptionsEgressOutput) { + op := &request.Operation{ + Name: opUpdateSecurityGroupRuleDescriptionsEgress, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &UpdateSecurityGroupRuleDescriptionsEgressInput{} + } + + output = &UpdateSecurityGroupRuleDescriptionsEgressOutput{} + req = c.newRequest(op, input, output) + return +} + +// UpdateSecurityGroupRuleDescriptionsEgress API operation for Amazon Elastic Compute Cloud. +// +// [EC2-VPC only] Updates the description of an egress (outbound) security group +// rule. You can replace an existing description, or add a description to a +// rule that did not have one previously. +// +// You specify the description as part of the IP permissions structure. You +// can remove a description for a security group rule by omitting the description +// parameter in the request. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation UpdateSecurityGroupRuleDescriptionsEgress for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsEgress +func (c *EC2) UpdateSecurityGroupRuleDescriptionsEgress(input *UpdateSecurityGroupRuleDescriptionsEgressInput) (*UpdateSecurityGroupRuleDescriptionsEgressOutput, error) { + req, out := c.UpdateSecurityGroupRuleDescriptionsEgressRequest(input) + return out, req.Send() +} + +// UpdateSecurityGroupRuleDescriptionsEgressWithContext is the same as UpdateSecurityGroupRuleDescriptionsEgress with the addition of +// the ability to pass a context and additional request options. +// +// See UpdateSecurityGroupRuleDescriptionsEgress for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) UpdateSecurityGroupRuleDescriptionsEgressWithContext(ctx aws.Context, input *UpdateSecurityGroupRuleDescriptionsEgressInput, opts ...request.Option) (*UpdateSecurityGroupRuleDescriptionsEgressOutput, error) { + req, out := c.UpdateSecurityGroupRuleDescriptionsEgressRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opUpdateSecurityGroupRuleDescriptionsIngress = "UpdateSecurityGroupRuleDescriptionsIngress" + +// UpdateSecurityGroupRuleDescriptionsIngressRequest generates a "aws/request.Request" representing the +// client's request for the UpdateSecurityGroupRuleDescriptionsIngress operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See UpdateSecurityGroupRuleDescriptionsIngress for more information on using the UpdateSecurityGroupRuleDescriptionsIngress +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the UpdateSecurityGroupRuleDescriptionsIngressRequest method. +// req, resp := client.UpdateSecurityGroupRuleDescriptionsIngressRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsIngress +func (c *EC2) UpdateSecurityGroupRuleDescriptionsIngressRequest(input *UpdateSecurityGroupRuleDescriptionsIngressInput) (req *request.Request, output *UpdateSecurityGroupRuleDescriptionsIngressOutput) { + op := &request.Operation{ + Name: opUpdateSecurityGroupRuleDescriptionsIngress, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &UpdateSecurityGroupRuleDescriptionsIngressInput{} + } + + output = &UpdateSecurityGroupRuleDescriptionsIngressOutput{} + req = c.newRequest(op, input, output) + return +} + +// UpdateSecurityGroupRuleDescriptionsIngress API operation for Amazon Elastic Compute Cloud. +// +// Updates the description of an ingress (inbound) security group rule. You +// can replace an existing description, or add a description to a rule that +// did not have one previously. +// +// You specify the description as part of the IP permissions structure. You +// can remove a description for a security group rule by omitting the description +// parameter in the request. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Elastic Compute Cloud's +// API operation UpdateSecurityGroupRuleDescriptionsIngress for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsIngress +func (c *EC2) UpdateSecurityGroupRuleDescriptionsIngress(input *UpdateSecurityGroupRuleDescriptionsIngressInput) (*UpdateSecurityGroupRuleDescriptionsIngressOutput, error) { + req, out := c.UpdateSecurityGroupRuleDescriptionsIngressRequest(input) + return out, req.Send() +} + +// UpdateSecurityGroupRuleDescriptionsIngressWithContext is the same as UpdateSecurityGroupRuleDescriptionsIngress with the addition of +// the ability to pass a context and additional request options. +// +// See UpdateSecurityGroupRuleDescriptionsIngress for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *EC2) UpdateSecurityGroupRuleDescriptionsIngressWithContext(ctx aws.Context, input *UpdateSecurityGroupRuleDescriptionsIngressInput, opts ...request.Option) (*UpdateSecurityGroupRuleDescriptionsIngressOutput, error) { + req, out := c.UpdateSecurityGroupRuleDescriptionsIngressRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + // Contains the parameters for accepting the quote. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuoteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuoteRequest type AcceptReservedInstancesExchangeQuoteInput struct { _ struct{} `type:"structure"` @@ -19977,14 +22276,14 @@ type AcceptReservedInstancesExchangeQuoteInput struct { // it is UnauthorizedOperation. DryRun *bool `type:"boolean"` - // The IDs of the Convertible Reserved Instances to exchange for other Convertible - // Reserved Instances of the same or higher value. + // The IDs of the Convertible Reserved Instances to exchange for another Convertible + // Reserved Instance of the same or higher value. // // ReservedInstanceIds is a required field ReservedInstanceIds []*string `locationName:"ReservedInstanceId" locationNameList:"ReservedInstanceId" type:"list" required:"true"` - // The configurations of the Convertible Reserved Instance offerings that you - // are purchasing in this exchange. + // The configuration of the target Convertible Reserved Instance to exchange + // for your current Convertible Reserved Instances. TargetConfigurations []*TargetConfigurationRequest `locationName:"TargetConfiguration" locationNameList:"TargetConfigurationRequest" type:"list"` } @@ -20040,7 +22339,7 @@ func (s *AcceptReservedInstancesExchangeQuoteInput) SetTargetConfigurations(v [] } // The result of the exchange and whether it was successful. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuoteResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptReservedInstancesExchangeQuoteResult type AcceptReservedInstancesExchangeQuoteOutput struct { _ struct{} `type:"structure"` @@ -20064,8 +22363,97 @@ func (s *AcceptReservedInstancesExchangeQuoteOutput) SetExchangeId(v string) *Ac return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcEndpointConnectionsRequest +type AcceptVpcEndpointConnectionsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the endpoint service. + // + // ServiceId is a required field + ServiceId *string `type:"string" required:"true"` + + // The IDs of one or more interface VPC endpoints. + // + // VpcEndpointIds is a required field + VpcEndpointIds []*string `locationName:"VpcEndpointId" locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s AcceptVpcEndpointConnectionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s AcceptVpcEndpointConnectionsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *AcceptVpcEndpointConnectionsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "AcceptVpcEndpointConnectionsInput"} + if s.ServiceId == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceId")) + } + if s.VpcEndpointIds == nil { + invalidParams.Add(request.NewErrParamRequired("VpcEndpointIds")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *AcceptVpcEndpointConnectionsInput) SetDryRun(v bool) *AcceptVpcEndpointConnectionsInput { + s.DryRun = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *AcceptVpcEndpointConnectionsInput) SetServiceId(v string) *AcceptVpcEndpointConnectionsInput { + s.ServiceId = &v + return s +} + +// SetVpcEndpointIds sets the VpcEndpointIds field's value. +func (s *AcceptVpcEndpointConnectionsInput) SetVpcEndpointIds(v []*string) *AcceptVpcEndpointConnectionsInput { + s.VpcEndpointIds = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcEndpointConnectionsResult +type AcceptVpcEndpointConnectionsOutput struct { + _ struct{} `type:"structure"` + + // Information about the interface endpoints that were not accepted, if applicable. + Unsuccessful []*UnsuccessfulItem `locationName:"unsuccessful" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s AcceptVpcEndpointConnectionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s AcceptVpcEndpointConnectionsOutput) GoString() string { + return s.String() +} + +// SetUnsuccessful sets the Unsuccessful field's value. +func (s *AcceptVpcEndpointConnectionsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *AcceptVpcEndpointConnectionsOutput { + s.Unsuccessful = v + return s +} + // Contains the parameters for AcceptVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnectionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnectionRequest type AcceptVpcPeeringConnectionInput struct { _ struct{} `type:"structure"` @@ -20075,7 +22463,8 @@ type AcceptVpcPeeringConnectionInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The ID of the VPC peering connection. + // The ID of the VPC peering connection. You must specify this parameter in + // the request. VpcPeeringConnectionId *string `locationName:"vpcPeeringConnectionId" type:"string"` } @@ -20102,7 +22491,7 @@ func (s *AcceptVpcPeeringConnectionInput) SetVpcPeeringConnectionId(v string) *A } // Contains the output of AcceptVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnectionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AcceptVpcPeeringConnectionResult type AcceptVpcPeeringConnectionOutput struct { _ struct{} `type:"structure"` @@ -20127,7 +22516,7 @@ func (s *AcceptVpcPeeringConnectionOutput) SetVpcPeeringConnection(v *VpcPeering } // Describes an account attribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AccountAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AccountAttribute type AccountAttribute struct { _ struct{} `type:"structure"` @@ -20161,7 +22550,7 @@ func (s *AccountAttribute) SetAttributeValues(v []*AccountAttributeValue) *Accou } // Describes a value of an account attribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AccountAttributeValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AccountAttributeValue type AccountAttributeValue struct { _ struct{} `type:"structure"` @@ -20185,8 +22574,8 @@ func (s *AccountAttributeValue) SetAttributeValue(v string) *AccountAttributeVal return s } -// Describes a running instance in a Spot fleet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ActiveInstance +// Describes a running instance in a Spot Fleet. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ActiveInstance type ActiveInstance struct { _ struct{} `type:"structure"` @@ -20201,7 +22590,7 @@ type ActiveInstance struct { // The instance type. InstanceType *string `locationName:"instanceType" type:"string"` - // The ID of the Spot instance request. + // The ID of the Spot Instance request. SpotInstanceRequestId *string `locationName:"spotInstanceRequestId" type:"string"` } @@ -20240,7 +22629,7 @@ func (s *ActiveInstance) SetSpotInstanceRequestId(v string) *ActiveInstance { } // Describes an Elastic IP address. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Address +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Address type Address struct { _ struct{} `type:"structure"` @@ -20269,6 +22658,9 @@ type Address struct { // The Elastic IP address. PublicIp *string `locationName:"publicIp" type:"string"` + + // Any tags assigned to the Elastic IP address. + Tags []*Tag `locationName:"tagSet" locationNameList:"item" type:"list"` } // String returns the string representation @@ -20329,11 +22721,20 @@ func (s *Address) SetPublicIp(v string) *Address { return s } +// SetTags sets the Tags field's value. +func (s *Address) SetTags(v []*Tag) *Address { + s.Tags = v + return s +} + // Contains the parameters for AllocateAddress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddressRequest type AllocateAddressInput struct { _ struct{} `type:"structure"` + // [EC2-VPC] The Elastic IP address to recover. + Address *string `type:"string"` + // Set to vpc to allocate the address for use with instances in a VPC. // // Default: The address is for use with instances in EC2-Classic. @@ -20356,6 +22757,12 @@ func (s AllocateAddressInput) GoString() string { return s.String() } +// SetAddress sets the Address field's value. +func (s *AllocateAddressInput) SetAddress(v string) *AllocateAddressInput { + s.Address = &v + return s +} + // SetDomain sets the Domain field's value. func (s *AllocateAddressInput) SetDomain(v string) *AllocateAddressInput { s.Domain = &v @@ -20369,7 +22776,7 @@ func (s *AllocateAddressInput) SetDryRun(v bool) *AllocateAddressInput { } // Contains the output of AllocateAddress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddressResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateAddressResult type AllocateAddressOutput struct { _ struct{} `type:"structure"` @@ -20414,7 +22821,7 @@ func (s *AllocateAddressOutput) SetPublicIp(v string) *AllocateAddressOutput { } // Contains the parameters for AllocateHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHostsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHostsRequest type AllocateHostsInput struct { _ struct{} `type:"structure"` @@ -20509,7 +22916,7 @@ func (s *AllocateHostsInput) SetQuantity(v int64) *AllocateHostsInput { } // Contains the output of AllocateHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHostsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllocateHostsResult type AllocateHostsOutput struct { _ struct{} `type:"structure"` @@ -20534,7 +22941,41 @@ func (s *AllocateHostsOutput) SetHostIds(v []*string) *AllocateHostsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6AddressesRequest +// Describes a principal. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AllowedPrincipal +type AllowedPrincipal struct { + _ struct{} `type:"structure"` + + // The Amazon Resource Name (ARN) of the principal. + Principal *string `locationName:"principal" type:"string"` + + // The type of principal. + PrincipalType *string `locationName:"principalType" type:"string" enum:"PrincipalType"` +} + +// String returns the string representation +func (s AllowedPrincipal) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s AllowedPrincipal) GoString() string { + return s.String() +} + +// SetPrincipal sets the Principal field's value. +func (s *AllowedPrincipal) SetPrincipal(v string) *AllowedPrincipal { + s.Principal = &v + return s +} + +// SetPrincipalType sets the PrincipalType field's value. +func (s *AllowedPrincipal) SetPrincipalType(v string) *AllowedPrincipal { + s.PrincipalType = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6AddressesRequest type AssignIpv6AddressesInput struct { _ struct{} `type:"structure"` @@ -20594,7 +23035,7 @@ func (s *AssignIpv6AddressesInput) SetNetworkInterfaceId(v string) *AssignIpv6Ad return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6AddressesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignIpv6AddressesResult type AssignIpv6AddressesOutput struct { _ struct{} `type:"structure"` @@ -20628,7 +23069,7 @@ func (s *AssignIpv6AddressesOutput) SetNetworkInterfaceId(v string) *AssignIpv6A } // Contains the parameters for AssignPrivateIpAddresses. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddressesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddressesRequest type AssignPrivateIpAddressesInput struct { _ struct{} `type:"structure"` @@ -20701,7 +23142,7 @@ func (s *AssignPrivateIpAddressesInput) SetSecondaryPrivateIpAddressCount(v int6 return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddressesOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssignPrivateIpAddressesOutput type AssignPrivateIpAddressesOutput struct { _ struct{} `type:"structure"` } @@ -20717,7 +23158,7 @@ func (s AssignPrivateIpAddressesOutput) GoString() string { } // Contains the parameters for AssociateAddress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddressRequest type AssociateAddressInput struct { _ struct{} `type:"structure"` @@ -20810,7 +23251,7 @@ func (s *AssociateAddressInput) SetPublicIp(v string) *AssociateAddressInput { } // Contains the output of AssociateAddress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddressResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateAddressResult type AssociateAddressOutput struct { _ struct{} `type:"structure"` @@ -20836,7 +23277,7 @@ func (s *AssociateAddressOutput) SetAssociationId(v string) *AssociateAddressOut } // Contains the parameters for AssociateDhcpOptions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptionsRequest type AssociateDhcpOptionsInput struct { _ struct{} `type:"structure"` @@ -20902,7 +23343,7 @@ func (s *AssociateDhcpOptionsInput) SetVpcId(v string) *AssociateDhcpOptionsInpu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptionsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateDhcpOptionsOutput type AssociateDhcpOptionsOutput struct { _ struct{} `type:"structure"` } @@ -20917,7 +23358,7 @@ func (s AssociateDhcpOptionsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfileRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfileRequest type AssociateIamInstanceProfileInput struct { _ struct{} `type:"structure"` @@ -20970,7 +23411,7 @@ func (s *AssociateIamInstanceProfileInput) SetInstanceId(v string) *AssociateIam return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfileResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateIamInstanceProfileResult type AssociateIamInstanceProfileOutput struct { _ struct{} `type:"structure"` @@ -20995,7 +23436,7 @@ func (s *AssociateIamInstanceProfileOutput) SetIamInstanceProfileAssociation(v * } // Contains the parameters for AssociateRouteTable. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTableRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTableRequest type AssociateRouteTableInput struct { _ struct{} `type:"structure"` @@ -21061,7 +23502,7 @@ func (s *AssociateRouteTableInput) SetSubnetId(v string) *AssociateRouteTableInp } // Contains the output of AssociateRouteTable. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTableResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateRouteTableResult type AssociateRouteTableOutput struct { _ struct{} `type:"structure"` @@ -21085,7 +23526,7 @@ func (s *AssociateRouteTableOutput) SetAssociationId(v string) *AssociateRouteTa return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlockRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlockRequest type AssociateSubnetCidrBlockInput struct { _ struct{} `type:"structure"` @@ -21138,7 +23579,7 @@ func (s *AssociateSubnetCidrBlockInput) SetSubnetId(v string) *AssociateSubnetCi return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlockResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateSubnetCidrBlockResult type AssociateSubnetCidrBlockOutput struct { _ struct{} `type:"structure"` @@ -21171,7 +23612,7 @@ func (s *AssociateSubnetCidrBlockOutput) SetSubnetId(v string) *AssociateSubnetC return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlockRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlockRequest type AssociateVpcCidrBlockInput struct { _ struct{} `type:"structure"` @@ -21180,6 +23621,9 @@ type AssociateVpcCidrBlockInput struct { // CIDR block. AmazonProvidedIpv6CidrBlock *bool `locationName:"amazonProvidedIpv6CidrBlock" type:"boolean"` + // An IPv4 CIDR block to associate with the VPC. + CidrBlock *string `type:"string"` + // The ID of the VPC. // // VpcId is a required field @@ -21215,16 +23659,25 @@ func (s *AssociateVpcCidrBlockInput) SetAmazonProvidedIpv6CidrBlock(v bool) *Ass return s } +// SetCidrBlock sets the CidrBlock field's value. +func (s *AssociateVpcCidrBlockInput) SetCidrBlock(v string) *AssociateVpcCidrBlockInput { + s.CidrBlock = &v + return s +} + // SetVpcId sets the VpcId field's value. func (s *AssociateVpcCidrBlockInput) SetVpcId(v string) *AssociateVpcCidrBlockInput { s.VpcId = &v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlockResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AssociateVpcCidrBlockResult type AssociateVpcCidrBlockOutput struct { _ struct{} `type:"structure"` + // Information about the IPv4 CIDR block association. + CidrBlockAssociation *VpcCidrBlockAssociation `locationName:"cidrBlockAssociation" type:"structure"` + // Information about the IPv6 CIDR block association. Ipv6CidrBlockAssociation *VpcIpv6CidrBlockAssociation `locationName:"ipv6CidrBlockAssociation" type:"structure"` @@ -21242,6 +23695,12 @@ func (s AssociateVpcCidrBlockOutput) GoString() string { return s.String() } +// SetCidrBlockAssociation sets the CidrBlockAssociation field's value. +func (s *AssociateVpcCidrBlockOutput) SetCidrBlockAssociation(v *VpcCidrBlockAssociation) *AssociateVpcCidrBlockOutput { + s.CidrBlockAssociation = v + return s +} + // SetIpv6CidrBlockAssociation sets the Ipv6CidrBlockAssociation field's value. func (s *AssociateVpcCidrBlockOutput) SetIpv6CidrBlockAssociation(v *VpcIpv6CidrBlockAssociation) *AssociateVpcCidrBlockOutput { s.Ipv6CidrBlockAssociation = v @@ -21255,7 +23714,7 @@ func (s *AssociateVpcCidrBlockOutput) SetVpcId(v string) *AssociateVpcCidrBlockO } // Contains the parameters for AttachClassicLinkVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpcRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpcRequest type AttachClassicLinkVpcInput struct { _ struct{} `type:"structure"` @@ -21336,7 +23795,7 @@ func (s *AttachClassicLinkVpcInput) SetVpcId(v string) *AttachClassicLinkVpcInpu } // Contains the output of AttachClassicLinkVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpcResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachClassicLinkVpcResult type AttachClassicLinkVpcOutput struct { _ struct{} `type:"structure"` @@ -21361,7 +23820,7 @@ func (s *AttachClassicLinkVpcOutput) SetReturn(v bool) *AttachClassicLinkVpcOutp } // Contains the parameters for AttachInternetGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGatewayRequest type AttachInternetGatewayInput struct { _ struct{} `type:"structure"` @@ -21426,7 +23885,7 @@ func (s *AttachInternetGatewayInput) SetVpcId(v string) *AttachInternetGatewayIn return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGatewayOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachInternetGatewayOutput type AttachInternetGatewayOutput struct { _ struct{} `type:"structure"` } @@ -21442,7 +23901,7 @@ func (s AttachInternetGatewayOutput) GoString() string { } // Contains the parameters for AttachNetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterfaceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterfaceRequest type AttachNetworkInterfaceInput struct { _ struct{} `type:"structure"` @@ -21522,7 +23981,7 @@ func (s *AttachNetworkInterfaceInput) SetNetworkInterfaceId(v string) *AttachNet } // Contains the output of AttachNetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterfaceResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachNetworkInterfaceResult type AttachNetworkInterfaceOutput struct { _ struct{} `type:"structure"` @@ -21547,11 +24006,11 @@ func (s *AttachNetworkInterfaceOutput) SetAttachmentId(v string) *AttachNetworkI } // Contains the parameters for AttachVolume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVolumeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVolumeRequest type AttachVolumeInput struct { _ struct{} `type:"structure"` - // The device name to expose to the instance (for example, /dev/sdh or xvdh). + // The device name (for example, /dev/sdh or xvdh). // // Device is a required field Device *string `type:"string" required:"true"` @@ -21628,7 +24087,7 @@ func (s *AttachVolumeInput) SetVolumeId(v string) *AttachVolumeInput { } // Contains the parameters for AttachVpnGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGatewayRequest type AttachVpnGatewayInput struct { _ struct{} `type:"structure"` @@ -21694,7 +24153,7 @@ func (s *AttachVpnGatewayInput) SetVpnGatewayId(v string) *AttachVpnGatewayInput } // Contains the output of AttachVpnGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttachVpnGatewayResult type AttachVpnGatewayOutput struct { _ struct{} `type:"structure"` @@ -21719,7 +24178,7 @@ func (s *AttachVpnGatewayOutput) SetVpcAttachment(v *VpcAttachment) *AttachVpnGa } // Describes a value for a resource attribute that is a Boolean value. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttributeBooleanValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttributeBooleanValue type AttributeBooleanValue struct { _ struct{} `type:"structure"` @@ -21744,7 +24203,7 @@ func (s *AttributeBooleanValue) SetValue(v bool) *AttributeBooleanValue { } // Describes a value for a resource attribute that is a String. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttributeValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AttributeValue type AttributeValue struct { _ struct{} `type:"structure"` @@ -21769,12 +24228,11 @@ func (s *AttributeValue) SetValue(v string) *AttributeValue { } // Contains the parameters for AuthorizeSecurityGroupEgress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgressRequest type AuthorizeSecurityGroupEgressInput struct { _ struct{} `type:"structure"` - // The CIDR IPv4 address range. We recommend that you specify the CIDR range - // in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the CIDR. CidrIp *string `locationName:"cidrIp" type:"string"` // Checks whether you have the required permissions for the action, without @@ -21783,8 +24241,7 @@ type AuthorizeSecurityGroupEgressInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The start of port range for the TCP and UDP protocols, or an ICMP type number. - // We recommend that you specify the port range in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the port. FromPort *int64 `locationName:"fromPort" type:"integer"` // The ID of the security group. @@ -21792,26 +24249,23 @@ type AuthorizeSecurityGroupEgressInput struct { // GroupId is a required field GroupId *string `locationName:"groupId" type:"string" required:"true"` - // A set of IP permissions. You can't specify a destination security group and - // a CIDR IP address range. + // One or more sets of IP permissions. You can't specify a destination security + // group and a CIDR IP address range in the same set of permissions. IpPermissions []*IpPermission `locationName:"ipPermissions" locationNameList:"item" type:"list"` - // The IP protocol name or number. We recommend that you specify the protocol - // in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the protocol name or + // number. IpProtocol *string `locationName:"ipProtocol" type:"string"` - // The name of a destination security group. To authorize outbound access to - // a destination security group, we recommend that you use a set of IP permissions - // instead. + // Not supported. Use a set of IP permissions to specify a destination security + // group. SourceSecurityGroupName *string `locationName:"sourceSecurityGroupName" type:"string"` - // The AWS account number for a destination security group. To authorize outbound - // access to a destination security group, we recommend that you use a set of - // IP permissions instead. + // Not supported. Use a set of IP permissions to specify a destination security + // group. SourceSecurityGroupOwnerId *string `locationName:"sourceSecurityGroupOwnerId" type:"string"` - // The end of port range for the TCP and UDP protocols, or an ICMP type number. - // We recommend that you specify the port range in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the port. ToPort *int64 `locationName:"toPort" type:"integer"` } @@ -21892,7 +24346,7 @@ func (s *AuthorizeSecurityGroupEgressInput) SetToPort(v int64) *AuthorizeSecurit return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgressOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupEgressOutput type AuthorizeSecurityGroupEgressOutput struct { _ struct{} `type:"structure"` } @@ -21908,7 +24362,7 @@ func (s AuthorizeSecurityGroupEgressOutput) GoString() string { } // Contains the parameters for AuthorizeSecurityGroupIngress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngressRequest type AuthorizeSecurityGroupIngressInput struct { _ struct{} `type:"structure"` @@ -21924,16 +24378,20 @@ type AuthorizeSecurityGroupIngressInput struct { // The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 // type number. For the ICMP/ICMPv6 type number, use -1 to specify all types. + // If you specify all ICMP/ICMPv6 types, you must specify all codes. FromPort *int64 `type:"integer"` - // The ID of the security group. Required for a nondefault VPC. + // The ID of the security group. You must specify either the security group + // ID or the security group name in the request. For security groups in a nondefault + // VPC, you must specify the security group ID. GroupId *string `type:"string"` - // [EC2-Classic, default VPC] The name of the security group. + // [EC2-Classic, default VPC] The name of the security group. You must specify + // either the security group ID or the security group name in the request. GroupName *string `type:"string"` - // A set of IP permissions. Can be used to specify multiple rules in a single - // command. + // One or more sets of IP permissions. Can be used to specify multiple rules + // in a single command. IpPermissions []*IpPermission `locationNameList:"item" type:"list"` // The IP protocol name (tcp, udp, icmp) or number (see Protocol Numbers (http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml)). @@ -21953,8 +24411,8 @@ type AuthorizeSecurityGroupIngressInput struct { // be in the same VPC. SourceSecurityGroupName *string `type:"string"` - // [EC2-Classic] The AWS account number for the source security group, if the - // source security group is in a different account. You can't specify this parameter + // [EC2-Classic] The AWS account ID for the source security group, if the source + // security group is in a different account. You can't specify this parameter // in combination with the following parameters: the CIDR IP address range, // the IP protocol, the start of the port range, and the end of the port range. // Creates rules that grant full ICMP, UDP, and TCP access. To create a rule @@ -21962,7 +24420,8 @@ type AuthorizeSecurityGroupIngressInput struct { SourceSecurityGroupOwnerId *string `type:"string"` // The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code - // number. For the ICMP/ICMPv6 code number, use -1 to specify all codes. + // number. For the ICMP/ICMPv6 code number, use -1 to specify all codes. If + // you specify all ICMP/ICMPv6 types, you must specify all codes. ToPort *int64 `type:"integer"` } @@ -22036,7 +24495,7 @@ func (s *AuthorizeSecurityGroupIngressInput) SetToPort(v int64) *AuthorizeSecuri return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngressOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AuthorizeSecurityGroupIngressOutput type AuthorizeSecurityGroupIngressOutput struct { _ struct{} `type:"structure"` } @@ -22052,7 +24511,7 @@ func (s AuthorizeSecurityGroupIngressOutput) GoString() string { } // Describes an Availability Zone. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AvailabilityZone +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AvailabilityZone type AvailabilityZone struct { _ struct{} `type:"structure"` @@ -22104,7 +24563,7 @@ func (s *AvailabilityZone) SetZoneName(v string) *AvailabilityZone { } // Describes a message about an Availability Zone. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AvailabilityZoneMessage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AvailabilityZoneMessage type AvailabilityZoneMessage struct { _ struct{} `type:"structure"` @@ -22129,7 +24588,7 @@ func (s *AvailabilityZoneMessage) SetMessage(v string) *AvailabilityZoneMessage } // The capacity information for instances launched onto the Dedicated Host. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AvailableCapacity +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/AvailableCapacity type AvailableCapacity struct { _ struct{} `type:"structure"` @@ -22162,7 +24621,7 @@ func (s *AvailableCapacity) SetAvailableVCpus(v int64) *AvailableCapacity { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BlobAttributeValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BlobAttributeValue type BlobAttributeValue struct { _ struct{} `type:"structure"` @@ -22187,11 +24646,11 @@ func (s *BlobAttributeValue) SetValue(v []byte) *BlobAttributeValue { } // Describes a block device mapping. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BlockDeviceMapping +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BlockDeviceMapping type BlockDeviceMapping struct { _ struct{} `type:"structure"` - // The device name exposed to the instance (for example, /dev/sdh or xvdh). + // The device name (for example, /dev/sdh or xvdh). DeviceName *string `locationName:"deviceName" type:"string"` // Parameters used to automatically set up EBS volumes when the instance is @@ -22250,7 +24709,7 @@ func (s *BlockDeviceMapping) SetVirtualName(v string) *BlockDeviceMapping { } // Contains the parameters for BundleInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstanceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstanceRequest type BundleInstanceInput struct { _ struct{} `type:"structure"` @@ -22324,7 +24783,7 @@ func (s *BundleInstanceInput) SetStorage(v *Storage) *BundleInstanceInput { } // Contains the output of BundleInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstanceResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleInstanceResult type BundleInstanceOutput struct { _ struct{} `type:"structure"` @@ -22349,7 +24808,7 @@ func (s *BundleInstanceOutput) SetBundleTask(v *BundleTask) *BundleInstanceOutpu } // Describes a bundle task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleTask type BundleTask struct { _ struct{} `type:"structure"` @@ -22437,7 +24896,7 @@ func (s *BundleTask) SetUpdateTime(v time.Time) *BundleTask { } // Describes an error for BundleInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleTaskError +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/BundleTaskError type BundleTaskError struct { _ struct{} `type:"structure"` @@ -22471,7 +24930,7 @@ func (s *BundleTaskError) SetMessage(v string) *BundleTaskError { } // Contains the parameters for CancelBundleTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTaskRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTaskRequest type CancelBundleTaskInput struct { _ struct{} `type:"structure"` @@ -22523,7 +24982,7 @@ func (s *CancelBundleTaskInput) SetDryRun(v bool) *CancelBundleTaskInput { } // Contains the output of CancelBundleTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTaskResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelBundleTaskResult type CancelBundleTaskOutput struct { _ struct{} `type:"structure"` @@ -22548,7 +25007,7 @@ func (s *CancelBundleTaskOutput) SetBundleTask(v *BundleTask) *CancelBundleTaskO } // Contains the parameters for CancelConversionTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionRequest type CancelConversionTaskInput struct { _ struct{} `type:"structure"` @@ -22608,7 +25067,7 @@ func (s *CancelConversionTaskInput) SetReasonMessage(v string) *CancelConversion return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionTaskOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelConversionTaskOutput type CancelConversionTaskOutput struct { _ struct{} `type:"structure"` } @@ -22624,7 +25083,7 @@ func (s CancelConversionTaskOutput) GoString() string { } // Contains the parameters for CancelExportTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTaskRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTaskRequest type CancelExportTaskInput struct { _ struct{} `type:"structure"` @@ -22663,7 +25122,7 @@ func (s *CancelExportTaskInput) SetExportTaskId(v string) *CancelExportTaskInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTaskOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelExportTaskOutput type CancelExportTaskOutput struct { _ struct{} `type:"structure"` } @@ -22679,7 +25138,7 @@ func (s CancelExportTaskOutput) GoString() string { } // Contains the parameters for CancelImportTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTaskRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTaskRequest type CancelImportTaskInput struct { _ struct{} `type:"structure"` @@ -22725,7 +25184,7 @@ func (s *CancelImportTaskInput) SetImportTaskId(v string) *CancelImportTaskInput } // Contains the output for CancelImportTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTaskResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelImportTaskResult type CancelImportTaskOutput struct { _ struct{} `type:"structure"` @@ -22768,7 +25227,7 @@ func (s *CancelImportTaskOutput) SetState(v string) *CancelImportTaskOutput { } // Contains the parameters for CancelReservedInstancesListing. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListingRequest type CancelReservedInstancesListingInput struct { _ struct{} `type:"structure"` @@ -22808,7 +25267,7 @@ func (s *CancelReservedInstancesListingInput) SetReservedInstancesListingId(v st } // Contains the output of CancelReservedInstancesListing. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListingResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelReservedInstancesListingResult type CancelReservedInstancesListingOutput struct { _ struct{} `type:"structure"` @@ -22832,8 +25291,8 @@ func (s *CancelReservedInstancesListingOutput) SetReservedInstancesListings(v [] return s } -// Describes a Spot fleet error. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsError +// Describes a Spot Fleet error. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsError type CancelSpotFleetRequestsError struct { _ struct{} `type:"structure"` @@ -22870,8 +25329,8 @@ func (s *CancelSpotFleetRequestsError) SetMessage(v string) *CancelSpotFleetRequ return s } -// Describes a Spot fleet request that was not successfully canceled. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsErrorItem +// Describes a Spot Fleet request that was not successfully canceled. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsErrorItem type CancelSpotFleetRequestsErrorItem struct { _ struct{} `type:"structure"` @@ -22880,7 +25339,7 @@ type CancelSpotFleetRequestsErrorItem struct { // Error is a required field Error *CancelSpotFleetRequestsError `locationName:"error" type:"structure" required:"true"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -22909,7 +25368,7 @@ func (s *CancelSpotFleetRequestsErrorItem) SetSpotFleetRequestId(v string) *Canc } // Contains the parameters for CancelSpotFleetRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsRequest type CancelSpotFleetRequestsInput struct { _ struct{} `type:"structure"` @@ -22919,12 +25378,12 @@ type CancelSpotFleetRequestsInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The IDs of the Spot fleet requests. + // The IDs of the Spot Fleet requests. // // SpotFleetRequestIds is a required field SpotFleetRequestIds []*string `locationName:"spotFleetRequestId" locationNameList:"item" type:"list" required:"true"` - // Indicates whether to terminate instances for a Spot fleet request if it is + // Indicates whether to terminate instances for a Spot Fleet request if it is // canceled successfully. // // TerminateInstances is a required field @@ -22976,14 +25435,14 @@ func (s *CancelSpotFleetRequestsInput) SetTerminateInstances(v bool) *CancelSpot } // Contains the output of CancelSpotFleetRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsResponse type CancelSpotFleetRequestsOutput struct { _ struct{} `type:"structure"` - // Information about the Spot fleet requests that are successfully canceled. + // Information about the Spot Fleet requests that are successfully canceled. SuccessfulFleetRequests []*CancelSpotFleetRequestsSuccessItem `locationName:"successfulFleetRequestSet" locationNameList:"item" type:"list"` - // Information about the Spot fleet requests that are not successfully canceled. + // Information about the Spot Fleet requests that are not successfully canceled. UnsuccessfulFleetRequests []*CancelSpotFleetRequestsErrorItem `locationName:"unsuccessfulFleetRequestSet" locationNameList:"item" type:"list"` } @@ -23009,22 +25468,22 @@ func (s *CancelSpotFleetRequestsOutput) SetUnsuccessfulFleetRequests(v []*Cancel return s } -// Describes a Spot fleet request that was successfully canceled. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsSuccessItem +// Describes a Spot Fleet request that was successfully canceled. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotFleetRequestsSuccessItem type CancelSpotFleetRequestsSuccessItem struct { _ struct{} `type:"structure"` - // The current state of the Spot fleet request. + // The current state of the Spot Fleet request. // // CurrentSpotFleetRequestState is a required field CurrentSpotFleetRequestState *string `locationName:"currentSpotFleetRequestState" type:"string" required:"true" enum:"BatchState"` - // The previous state of the Spot fleet request. + // The previous state of the Spot Fleet request. // // PreviousSpotFleetRequestState is a required field PreviousSpotFleetRequestState *string `locationName:"previousSpotFleetRequestState" type:"string" required:"true" enum:"BatchState"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -23059,7 +25518,7 @@ func (s *CancelSpotFleetRequestsSuccessItem) SetSpotFleetRequestId(v string) *Ca } // Contains the parameters for CancelSpotInstanceRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequestsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequestsRequest type CancelSpotInstanceRequestsInput struct { _ struct{} `type:"structure"` @@ -23069,7 +25528,7 @@ type CancelSpotInstanceRequestsInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // One or more Spot instance request IDs. + // One or more Spot Instance request IDs. // // SpotInstanceRequestIds is a required field SpotInstanceRequestIds []*string `locationName:"SpotInstanceRequestId" locationNameList:"SpotInstanceRequestId" type:"list" required:"true"` @@ -23111,11 +25570,11 @@ func (s *CancelSpotInstanceRequestsInput) SetSpotInstanceRequestIds(v []*string) } // Contains the output of CancelSpotInstanceRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequestsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelSpotInstanceRequestsResult type CancelSpotInstanceRequestsOutput struct { _ struct{} `type:"structure"` - // One or more Spot instance requests. + // One or more Spot Instance requests. CancelledSpotInstanceRequests []*CancelledSpotInstanceRequest `locationName:"spotInstanceRequestSet" locationNameList:"item" type:"list"` } @@ -23135,15 +25594,15 @@ func (s *CancelSpotInstanceRequestsOutput) SetCancelledSpotInstanceRequests(v [] return s } -// Describes a request to cancel a Spot instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelledSpotInstanceRequest +// Describes a request to cancel a Spot Instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CancelledSpotInstanceRequest type CancelledSpotInstanceRequest struct { _ struct{} `type:"structure"` - // The ID of the Spot instance request. + // The ID of the Spot Instance request. SpotInstanceRequestId *string `locationName:"spotInstanceRequestId" type:"string"` - // The state of the Spot instance request. + // The state of the Spot Instance request. State *string `locationName:"state" type:"string" enum:"CancelSpotInstanceRequestState"` } @@ -23169,8 +25628,33 @@ func (s *CancelledSpotInstanceRequest) SetState(v string) *CancelledSpotInstance return s } +// Describes an IPv4 CIDR block. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CidrBlock +type CidrBlock struct { + _ struct{} `type:"structure"` + + // The IPv4 CIDR block. + CidrBlock *string `locationName:"cidrBlock" type:"string"` +} + +// String returns the string representation +func (s CidrBlock) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CidrBlock) GoString() string { + return s.String() +} + +// SetCidrBlock sets the CidrBlock field's value. +func (s *CidrBlock) SetCidrBlock(v string) *CidrBlock { + s.CidrBlock = &v + return s +} + // Describes the ClassicLink DNS support status of a VPC. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClassicLinkDnsSupport +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClassicLinkDnsSupport type ClassicLinkDnsSupport struct { _ struct{} `type:"structure"` @@ -23204,7 +25688,7 @@ func (s *ClassicLinkDnsSupport) SetVpcId(v string) *ClassicLinkDnsSupport { } // Describes a linked EC2-Classic instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClassicLinkInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClassicLinkInstance type ClassicLinkInstance struct { _ struct{} `type:"structure"` @@ -23255,8 +25739,102 @@ func (s *ClassicLinkInstance) SetVpcId(v string) *ClassicLinkInstance { return s } +// Describes a Classic Load Balancer. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClassicLoadBalancer +type ClassicLoadBalancer struct { + _ struct{} `type:"structure"` + + // The name of the load balancer. + // + // Name is a required field + Name *string `locationName:"name" type:"string" required:"true"` +} + +// String returns the string representation +func (s ClassicLoadBalancer) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ClassicLoadBalancer) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ClassicLoadBalancer) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ClassicLoadBalancer"} + if s.Name == nil { + invalidParams.Add(request.NewErrParamRequired("Name")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetName sets the Name field's value. +func (s *ClassicLoadBalancer) SetName(v string) *ClassicLoadBalancer { + s.Name = &v + return s +} + +// Describes the Classic Load Balancers to attach to a Spot Fleet. Spot Fleet +// registers the running Spot Instances with these Classic Load Balancers. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClassicLoadBalancersConfig +type ClassicLoadBalancersConfig struct { + _ struct{} `type:"structure"` + + // One or more Classic Load Balancers. + // + // ClassicLoadBalancers is a required field + ClassicLoadBalancers []*ClassicLoadBalancer `locationName:"classicLoadBalancers" locationNameList:"item" min:"1" type:"list" required:"true"` +} + +// String returns the string representation +func (s ClassicLoadBalancersConfig) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ClassicLoadBalancersConfig) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ClassicLoadBalancersConfig) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ClassicLoadBalancersConfig"} + if s.ClassicLoadBalancers == nil { + invalidParams.Add(request.NewErrParamRequired("ClassicLoadBalancers")) + } + if s.ClassicLoadBalancers != nil && len(s.ClassicLoadBalancers) < 1 { + invalidParams.Add(request.NewErrParamMinLen("ClassicLoadBalancers", 1)) + } + if s.ClassicLoadBalancers != nil { + for i, v := range s.ClassicLoadBalancers { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "ClassicLoadBalancers", i), err.(request.ErrInvalidParams)) + } + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClassicLoadBalancers sets the ClassicLoadBalancers field's value. +func (s *ClassicLoadBalancersConfig) SetClassicLoadBalancers(v []*ClassicLoadBalancer) *ClassicLoadBalancersConfig { + s.ClassicLoadBalancers = v + return s +} + // Describes the client-specific data. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClientData +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ClientData type ClientData struct { _ struct{} `type:"structure"` @@ -23308,7 +25886,7 @@ func (s *ClientData) SetUploadStart(v time.Time) *ClientData { } // Contains the parameters for ConfirmProductInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstanceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstanceRequest type ConfirmProductInstanceInput struct { _ struct{} `type:"structure"` @@ -23374,7 +25952,7 @@ func (s *ConfirmProductInstanceInput) SetProductCode(v string) *ConfirmProductIn } // Contains the output of ConfirmProductInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstanceResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConfirmProductInstanceResult type ConfirmProductInstanceOutput struct { _ struct{} `type:"structure"` @@ -23409,8 +25987,88 @@ func (s *ConfirmProductInstanceOutput) SetReturn(v bool) *ConfirmProductInstance return s } +// Describes a connection notification for a VPC endpoint or VPC endpoint service. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConnectionNotification +type ConnectionNotification struct { + _ struct{} `type:"structure"` + + // The events for the notification. Valid values are Accept, Connect, Delete, + // and Reject. + ConnectionEvents []*string `locationName:"connectionEvents" locationNameList:"item" type:"list"` + + // The ARN of the SNS topic for the notification. + ConnectionNotificationArn *string `locationName:"connectionNotificationArn" type:"string"` + + // The ID of the notification. + ConnectionNotificationId *string `locationName:"connectionNotificationId" type:"string"` + + // The state of the notification. + ConnectionNotificationState *string `locationName:"connectionNotificationState" type:"string" enum:"ConnectionNotificationState"` + + // The type of notification. + ConnectionNotificationType *string `locationName:"connectionNotificationType" type:"string" enum:"ConnectionNotificationType"` + + // The ID of the endpoint service. + ServiceId *string `locationName:"serviceId" type:"string"` + + // The ID of the VPC endpoint. + VpcEndpointId *string `locationName:"vpcEndpointId" type:"string"` +} + +// String returns the string representation +func (s ConnectionNotification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ConnectionNotification) GoString() string { + return s.String() +} + +// SetConnectionEvents sets the ConnectionEvents field's value. +func (s *ConnectionNotification) SetConnectionEvents(v []*string) *ConnectionNotification { + s.ConnectionEvents = v + return s +} + +// SetConnectionNotificationArn sets the ConnectionNotificationArn field's value. +func (s *ConnectionNotification) SetConnectionNotificationArn(v string) *ConnectionNotification { + s.ConnectionNotificationArn = &v + return s +} + +// SetConnectionNotificationId sets the ConnectionNotificationId field's value. +func (s *ConnectionNotification) SetConnectionNotificationId(v string) *ConnectionNotification { + s.ConnectionNotificationId = &v + return s +} + +// SetConnectionNotificationState sets the ConnectionNotificationState field's value. +func (s *ConnectionNotification) SetConnectionNotificationState(v string) *ConnectionNotification { + s.ConnectionNotificationState = &v + return s +} + +// SetConnectionNotificationType sets the ConnectionNotificationType field's value. +func (s *ConnectionNotification) SetConnectionNotificationType(v string) *ConnectionNotification { + s.ConnectionNotificationType = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *ConnectionNotification) SetServiceId(v string) *ConnectionNotification { + s.ServiceId = &v + return s +} + +// SetVpcEndpointId sets the VpcEndpointId field's value. +func (s *ConnectionNotification) SetVpcEndpointId(v string) *ConnectionNotification { + s.VpcEndpointId = &v + return s +} + // Describes a conversion task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConversionTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ConversionTask type ConversionTask struct { _ struct{} `type:"structure"` @@ -23495,8 +26153,125 @@ func (s *ConversionTask) SetTags(v []*Tag) *ConversionTask { return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyFpgaImageRequest +type CopyFpgaImageInput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier that you provide to ensure the idempotency + // of the request. For more information, see Ensuring Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // The description for the new AFI. + Description *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The name for the new AFI. The default is the name of the source AFI. + Name *string `type:"string"` + + // The ID of the source AFI. + // + // SourceFpgaImageId is a required field + SourceFpgaImageId *string `type:"string" required:"true"` + + // The region that contains the source AFI. + // + // SourceRegion is a required field + SourceRegion *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s CopyFpgaImageInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CopyFpgaImageInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CopyFpgaImageInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CopyFpgaImageInput"} + if s.SourceFpgaImageId == nil { + invalidParams.Add(request.NewErrParamRequired("SourceFpgaImageId")) + } + if s.SourceRegion == nil { + invalidParams.Add(request.NewErrParamRequired("SourceRegion")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClientToken sets the ClientToken field's value. +func (s *CopyFpgaImageInput) SetClientToken(v string) *CopyFpgaImageInput { + s.ClientToken = &v + return s +} + +// SetDescription sets the Description field's value. +func (s *CopyFpgaImageInput) SetDescription(v string) *CopyFpgaImageInput { + s.Description = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *CopyFpgaImageInput) SetDryRun(v bool) *CopyFpgaImageInput { + s.DryRun = &v + return s +} + +// SetName sets the Name field's value. +func (s *CopyFpgaImageInput) SetName(v string) *CopyFpgaImageInput { + s.Name = &v + return s +} + +// SetSourceFpgaImageId sets the SourceFpgaImageId field's value. +func (s *CopyFpgaImageInput) SetSourceFpgaImageId(v string) *CopyFpgaImageInput { + s.SourceFpgaImageId = &v + return s +} + +// SetSourceRegion sets the SourceRegion field's value. +func (s *CopyFpgaImageInput) SetSourceRegion(v string) *CopyFpgaImageInput { + s.SourceRegion = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyFpgaImageResult +type CopyFpgaImageOutput struct { + _ struct{} `type:"structure"` + + // The ID of the new AFI. + FpgaImageId *string `locationName:"fpgaImageId" type:"string"` +} + +// String returns the string representation +func (s CopyFpgaImageOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CopyFpgaImageOutput) GoString() string { + return s.String() +} + +// SetFpgaImageId sets the FpgaImageId field's value. +func (s *CopyFpgaImageOutput) SetFpgaImageId(v string) *CopyFpgaImageOutput { + s.FpgaImageId = &v + return s +} + // Contains the parameters for CopyImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImageRequest type CopyImageInput struct { _ struct{} `type:"structure"` @@ -23625,7 +26400,7 @@ func (s *CopyImageInput) SetSourceRegion(v string) *CopyImageInput { } // Contains the output of CopyImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImageResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopyImageResult type CopyImageOutput struct { _ struct{} `type:"structure"` @@ -23650,7 +26425,7 @@ func (s *CopyImageOutput) SetImageId(v string) *CopyImageOutput { } // Contains the parameters for CopySnapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshotRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshotRequest type CopySnapshotInput struct { _ struct{} `type:"structure"` @@ -23792,7 +26567,7 @@ func (s *CopySnapshotInput) SetSourceSnapshotId(v string) *CopySnapshotInput { } // Contains the output of CopySnapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshotResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CopySnapshotResult type CopySnapshotOutput struct { _ struct{} `type:"structure"` @@ -23817,7 +26592,7 @@ func (s *CopySnapshotOutput) SetSnapshotId(v string) *CopySnapshotOutput { } // Contains the parameters for CreateCustomerGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGatewayRequest type CreateCustomerGatewayInput struct { _ struct{} `type:"structure"` @@ -23900,7 +26675,7 @@ func (s *CreateCustomerGatewayInput) SetType(v string) *CreateCustomerGatewayInp } // Contains the output of CreateCustomerGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateCustomerGatewayResult type CreateCustomerGatewayOutput struct { _ struct{} `type:"structure"` @@ -23924,8 +26699,83 @@ func (s *CreateCustomerGatewayOutput) SetCustomerGateway(v *CustomerGateway) *Cr return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultSubnetRequest +type CreateDefaultSubnetInput struct { + _ struct{} `type:"structure"` + + // The Availability Zone in which to create the default subnet. + // + // AvailabilityZone is a required field + AvailabilityZone *string `type:"string" required:"true"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` +} + +// String returns the string representation +func (s CreateDefaultSubnetInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateDefaultSubnetInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CreateDefaultSubnetInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CreateDefaultSubnetInput"} + if s.AvailabilityZone == nil { + invalidParams.Add(request.NewErrParamRequired("AvailabilityZone")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAvailabilityZone sets the AvailabilityZone field's value. +func (s *CreateDefaultSubnetInput) SetAvailabilityZone(v string) *CreateDefaultSubnetInput { + s.AvailabilityZone = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *CreateDefaultSubnetInput) SetDryRun(v bool) *CreateDefaultSubnetInput { + s.DryRun = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultSubnetResult +type CreateDefaultSubnetOutput struct { + _ struct{} `type:"structure"` + + // Information about the subnet. + Subnet *Subnet `locationName:"subnet" type:"structure"` +} + +// String returns the string representation +func (s CreateDefaultSubnetOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateDefaultSubnetOutput) GoString() string { + return s.String() +} + +// SetSubnet sets the Subnet field's value. +func (s *CreateDefaultSubnetOutput) SetSubnet(v *Subnet) *CreateDefaultSubnetOutput { + s.Subnet = v + return s +} + // Contains the parameters for CreateDefaultVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpcRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpcRequest type CreateDefaultVpcInput struct { _ struct{} `type:"structure"` @@ -23953,7 +26803,7 @@ func (s *CreateDefaultVpcInput) SetDryRun(v bool) *CreateDefaultVpcInput { } // Contains the output of CreateDefaultVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpcResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDefaultVpcResult type CreateDefaultVpcOutput struct { _ struct{} `type:"structure"` @@ -23978,7 +26828,7 @@ func (s *CreateDefaultVpcOutput) SetVpc(v *Vpc) *CreateDefaultVpcOutput { } // Contains the parameters for CreateDhcpOptions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptionsRequest type CreateDhcpOptionsInput struct { _ struct{} `type:"structure"` @@ -24030,7 +26880,7 @@ func (s *CreateDhcpOptionsInput) SetDryRun(v bool) *CreateDhcpOptionsInput { } // Contains the output of CreateDhcpOptions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateDhcpOptionsResult type CreateDhcpOptionsOutput struct { _ struct{} `type:"structure"` @@ -24054,7 +26904,7 @@ func (s *CreateDhcpOptionsOutput) SetDhcpOptions(v *DhcpOptions) *CreateDhcpOpti return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGatewayRequest type CreateEgressOnlyInternetGatewayInput struct { _ struct{} `type:"structure"` @@ -24115,7 +26965,7 @@ func (s *CreateEgressOnlyInternetGatewayInput) SetVpcId(v string) *CreateEgressO return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateEgressOnlyInternetGatewayResult type CreateEgressOnlyInternetGatewayOutput struct { _ struct{} `type:"structure"` @@ -24150,7 +27000,7 @@ func (s *CreateEgressOnlyInternetGatewayOutput) SetEgressOnlyInternetGateway(v * } // Contains the parameters for CreateFlowLogs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogsRequest type CreateFlowLogsInput struct { _ struct{} `type:"structure"` @@ -24259,7 +27109,7 @@ func (s *CreateFlowLogsInput) SetTrafficType(v string) *CreateFlowLogsInput { } // Contains the output of CreateFlowLogs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFlowLogsResult type CreateFlowLogsOutput struct { _ struct{} `type:"structure"` @@ -24302,7 +27152,7 @@ func (s *CreateFlowLogsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *CreateFlo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImageRequest type CreateFpgaImageInput struct { _ struct{} `type:"structure"` @@ -24391,7 +27241,7 @@ func (s *CreateFpgaImageInput) SetName(v string) *CreateFpgaImageInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImageResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateFpgaImageResult type CreateFpgaImageOutput struct { _ struct{} `type:"structure"` @@ -24425,7 +27275,7 @@ func (s *CreateFpgaImageOutput) SetFpgaImageId(v string) *CreateFpgaImageOutput } // Contains the parameters for CreateImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImageRequest type CreateImageInput struct { _ struct{} `type:"structure"` @@ -24525,7 +27375,7 @@ func (s *CreateImageInput) SetNoReboot(v bool) *CreateImageInput { } // Contains the output of CreateImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImageResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateImageResult type CreateImageOutput struct { _ struct{} `type:"structure"` @@ -24550,7 +27400,7 @@ func (s *CreateImageOutput) SetImageId(v string) *CreateImageOutput { } // Contains the parameters for CreateInstanceExportTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTaskRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTaskRequest type CreateInstanceExportTaskInput struct { _ struct{} `type:"structure"` @@ -24618,7 +27468,7 @@ func (s *CreateInstanceExportTaskInput) SetTargetEnvironment(v string) *CreateIn } // Contains the output for CreateInstanceExportTask. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTaskResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInstanceExportTaskResult type CreateInstanceExportTaskOutput struct { _ struct{} `type:"structure"` @@ -24643,7 +27493,7 @@ func (s *CreateInstanceExportTaskOutput) SetExportTask(v *ExportTask) *CreateIns } // Contains the parameters for CreateInternetGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGatewayRequest type CreateInternetGatewayInput struct { _ struct{} `type:"structure"` @@ -24671,7 +27521,7 @@ func (s *CreateInternetGatewayInput) SetDryRun(v bool) *CreateInternetGatewayInp } // Contains the output of CreateInternetGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateInternetGatewayResult type CreateInternetGatewayOutput struct { _ struct{} `type:"structure"` @@ -24696,7 +27546,7 @@ func (s *CreateInternetGatewayOutput) SetInternetGateway(v *InternetGateway) *Cr } // Contains the parameters for CreateKeyPair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateKeyPairRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateKeyPairRequest type CreateKeyPairInput struct { _ struct{} `type:"structure"` @@ -24750,7 +27600,7 @@ func (s *CreateKeyPairInput) SetKeyName(v string) *CreateKeyPairInput { } // Describes a key pair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/KeyPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/KeyPair type CreateKeyPairOutput struct { _ struct{} `type:"structure"` @@ -24792,8 +27642,257 @@ func (s *CreateKeyPairOutput) SetKeyName(v string) *CreateKeyPairOutput { return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplateRequest +type CreateLaunchTemplateInput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. For more information, see Ensuring Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The information for the launch template. + // + // LaunchTemplateData is a required field + LaunchTemplateData *RequestLaunchTemplateData `type:"structure" required:"true"` + + // A name for the launch template. + // + // LaunchTemplateName is a required field + LaunchTemplateName *string `min:"3" type:"string" required:"true"` + + // A description for the first version of the launch template. + VersionDescription *string `type:"string"` +} + +// String returns the string representation +func (s CreateLaunchTemplateInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateLaunchTemplateInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CreateLaunchTemplateInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CreateLaunchTemplateInput"} + if s.LaunchTemplateData == nil { + invalidParams.Add(request.NewErrParamRequired("LaunchTemplateData")) + } + if s.LaunchTemplateName == nil { + invalidParams.Add(request.NewErrParamRequired("LaunchTemplateName")) + } + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + if s.LaunchTemplateData != nil { + if err := s.LaunchTemplateData.Validate(); err != nil { + invalidParams.AddNested("LaunchTemplateData", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClientToken sets the ClientToken field's value. +func (s *CreateLaunchTemplateInput) SetClientToken(v string) *CreateLaunchTemplateInput { + s.ClientToken = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *CreateLaunchTemplateInput) SetDryRun(v bool) *CreateLaunchTemplateInput { + s.DryRun = &v + return s +} + +// SetLaunchTemplateData sets the LaunchTemplateData field's value. +func (s *CreateLaunchTemplateInput) SetLaunchTemplateData(v *RequestLaunchTemplateData) *CreateLaunchTemplateInput { + s.LaunchTemplateData = v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *CreateLaunchTemplateInput) SetLaunchTemplateName(v string) *CreateLaunchTemplateInput { + s.LaunchTemplateName = &v + return s +} + +// SetVersionDescription sets the VersionDescription field's value. +func (s *CreateLaunchTemplateInput) SetVersionDescription(v string) *CreateLaunchTemplateInput { + s.VersionDescription = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplateResult +type CreateLaunchTemplateOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch template. + LaunchTemplate *LaunchTemplate `locationName:"launchTemplate" type:"structure"` +} + +// String returns the string representation +func (s CreateLaunchTemplateOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateLaunchTemplateOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplate sets the LaunchTemplate field's value. +func (s *CreateLaunchTemplateOutput) SetLaunchTemplate(v *LaunchTemplate) *CreateLaunchTemplateOutput { + s.LaunchTemplate = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplateVersionRequest +type CreateLaunchTemplateVersionInput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. For more information, see Ensuring Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The information for the launch template. + // + // LaunchTemplateData is a required field + LaunchTemplateData *RequestLaunchTemplateData `type:"structure" required:"true"` + + // The ID of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateId *string `type:"string"` + + // The name of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateName *string `min:"3" type:"string"` + + // The version number of the launch template version on which to base the new + // version. The new version inherits the same launch parameters as the source + // version, except for parameters that you specify in LaunchTemplateData. + SourceVersion *string `type:"string"` + + // A description for the version of the launch template. + VersionDescription *string `type:"string"` +} + +// String returns the string representation +func (s CreateLaunchTemplateVersionInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateLaunchTemplateVersionInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CreateLaunchTemplateVersionInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CreateLaunchTemplateVersionInput"} + if s.LaunchTemplateData == nil { + invalidParams.Add(request.NewErrParamRequired("LaunchTemplateData")) + } + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + if s.LaunchTemplateData != nil { + if err := s.LaunchTemplateData.Validate(); err != nil { + invalidParams.AddNested("LaunchTemplateData", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClientToken sets the ClientToken field's value. +func (s *CreateLaunchTemplateVersionInput) SetClientToken(v string) *CreateLaunchTemplateVersionInput { + s.ClientToken = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *CreateLaunchTemplateVersionInput) SetDryRun(v bool) *CreateLaunchTemplateVersionInput { + s.DryRun = &v + return s +} + +// SetLaunchTemplateData sets the LaunchTemplateData field's value. +func (s *CreateLaunchTemplateVersionInput) SetLaunchTemplateData(v *RequestLaunchTemplateData) *CreateLaunchTemplateVersionInput { + s.LaunchTemplateData = v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *CreateLaunchTemplateVersionInput) SetLaunchTemplateId(v string) *CreateLaunchTemplateVersionInput { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *CreateLaunchTemplateVersionInput) SetLaunchTemplateName(v string) *CreateLaunchTemplateVersionInput { + s.LaunchTemplateName = &v + return s +} + +// SetSourceVersion sets the SourceVersion field's value. +func (s *CreateLaunchTemplateVersionInput) SetSourceVersion(v string) *CreateLaunchTemplateVersionInput { + s.SourceVersion = &v + return s +} + +// SetVersionDescription sets the VersionDescription field's value. +func (s *CreateLaunchTemplateVersionInput) SetVersionDescription(v string) *CreateLaunchTemplateVersionInput { + s.VersionDescription = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateLaunchTemplateVersionResult +type CreateLaunchTemplateVersionOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch template version. + LaunchTemplateVersion *LaunchTemplateVersion `locationName:"launchTemplateVersion" type:"structure"` +} + +// String returns the string representation +func (s CreateLaunchTemplateVersionOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateLaunchTemplateVersionOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplateVersion sets the LaunchTemplateVersion field's value. +func (s *CreateLaunchTemplateVersionOutput) SetLaunchTemplateVersion(v *LaunchTemplateVersion) *CreateLaunchTemplateVersionOutput { + s.LaunchTemplateVersion = v + return s +} + // Contains the parameters for CreateNatGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGatewayRequest type CreateNatGatewayInput struct { _ struct{} `type:"structure"` @@ -24861,7 +27960,7 @@ func (s *CreateNatGatewayInput) SetSubnetId(v string) *CreateNatGatewayInput { } // Contains the output of CreateNatGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNatGatewayResult type CreateNatGatewayOutput struct { _ struct{} `type:"structure"` @@ -24896,7 +27995,7 @@ func (s *CreateNatGatewayOutput) SetNatGateway(v *NatGateway) *CreateNatGatewayO } // Contains the parameters for CreateNetworkAclEntry. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntryRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntryRequest type CreateNetworkAclEntryInput struct { _ struct{} `type:"structure"` @@ -25051,7 +28150,7 @@ func (s *CreateNetworkAclEntryInput) SetRuleNumber(v int64) *CreateNetworkAclEnt return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntryOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclEntryOutput type CreateNetworkAclEntryOutput struct { _ struct{} `type:"structure"` } @@ -25067,7 +28166,7 @@ func (s CreateNetworkAclEntryOutput) GoString() string { } // Contains the parameters for CreateNetworkAcl. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclRequest type CreateNetworkAclInput struct { _ struct{} `type:"structure"` @@ -25119,7 +28218,7 @@ func (s *CreateNetworkAclInput) SetVpcId(v string) *CreateNetworkAclInput { } // Contains the output of CreateNetworkAcl. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkAclResult type CreateNetworkAclOutput struct { _ struct{} `type:"structure"` @@ -25144,7 +28243,7 @@ func (s *CreateNetworkAclOutput) SetNetworkAcl(v *NetworkAcl) *CreateNetworkAclO } // Contains the parameters for CreateNetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfaceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfaceRequest type CreateNetworkInterfaceInput struct { _ struct{} `type:"structure"` @@ -25286,7 +28385,7 @@ func (s *CreateNetworkInterfaceInput) SetSubnetId(v string) *CreateNetworkInterf } // Contains the output of CreateNetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfaceResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfaceResult type CreateNetworkInterfaceOutput struct { _ struct{} `type:"structure"` @@ -25311,7 +28410,7 @@ func (s *CreateNetworkInterfaceOutput) SetNetworkInterface(v *NetworkInterface) } // Contains the parameters for CreateNetworkInterfacePermission. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermissionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermissionRequest type CreateNetworkInterfacePermissionInput struct { _ struct{} `type:"structure"` @@ -25395,7 +28494,7 @@ func (s *CreateNetworkInterfacePermissionInput) SetPermission(v string) *CreateN } // Contains the output of CreateNetworkInterfacePermission. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermissionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateNetworkInterfacePermissionResult type CreateNetworkInterfacePermissionOutput struct { _ struct{} `type:"structure"` @@ -25420,7 +28519,7 @@ func (s *CreateNetworkInterfacePermissionOutput) SetInterfacePermission(v *Netwo } // Contains the parameters for CreatePlacementGroup. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroupRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroupRequest type CreatePlacementGroupInput struct { _ struct{} `type:"structure"` @@ -25430,7 +28529,8 @@ type CreatePlacementGroupInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // A name for the placement group. + // A name for the placement group. Must be unique within the scope of your account + // for the region. // // Constraints: Up to 255 ASCII characters // @@ -25487,7 +28587,7 @@ func (s *CreatePlacementGroupInput) SetStrategy(v string) *CreatePlacementGroupI return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroupOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreatePlacementGroupOutput type CreatePlacementGroupOutput struct { _ struct{} `type:"structure"` } @@ -25503,7 +28603,7 @@ func (s CreatePlacementGroupOutput) GoString() string { } // Contains the parameters for CreateReservedInstancesListing. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListingRequest type CreateReservedInstancesListingInput struct { _ struct{} `type:"structure"` @@ -25591,7 +28691,7 @@ func (s *CreateReservedInstancesListingInput) SetReservedInstancesId(v string) * } // Contains the output of CreateReservedInstancesListing. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListingResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateReservedInstancesListingResult type CreateReservedInstancesListingOutput struct { _ struct{} `type:"structure"` @@ -25616,7 +28716,7 @@ func (s *CreateReservedInstancesListingOutput) SetReservedInstancesListings(v [] } // Contains the parameters for CreateRoute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteRequest type CreateRouteInput struct { _ struct{} `type:"structure"` @@ -25744,7 +28844,7 @@ func (s *CreateRouteInput) SetVpcPeeringConnectionId(v string) *CreateRouteInput } // Contains the output of CreateRoute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteResult type CreateRouteOutput struct { _ struct{} `type:"structure"` @@ -25769,7 +28869,7 @@ func (s *CreateRouteOutput) SetReturn(v bool) *CreateRouteOutput { } // Contains the parameters for CreateRouteTable. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTableRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTableRequest type CreateRouteTableInput struct { _ struct{} `type:"structure"` @@ -25821,7 +28921,7 @@ func (s *CreateRouteTableInput) SetVpcId(v string) *CreateRouteTableInput { } // Contains the output of CreateRouteTable. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTableResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateRouteTableResult type CreateRouteTableOutput struct { _ struct{} `type:"structure"` @@ -25846,7 +28946,7 @@ func (s *CreateRouteTableOutput) SetRouteTable(v *RouteTable) *CreateRouteTableO } // Contains the parameters for CreateSecurityGroup. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroupRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroupRequest type CreateSecurityGroupInput struct { _ struct{} `type:"structure"` @@ -25933,7 +29033,7 @@ func (s *CreateSecurityGroupInput) SetVpcId(v string) *CreateSecurityGroupInput } // Contains the output of CreateSecurityGroup. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroupResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSecurityGroupResult type CreateSecurityGroupOutput struct { _ struct{} `type:"structure"` @@ -25958,7 +29058,7 @@ func (s *CreateSecurityGroupOutput) SetGroupId(v string) *CreateSecurityGroupOut } // Contains the parameters for CreateSnapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSnapshotRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSnapshotRequest type CreateSnapshotInput struct { _ struct{} `type:"structure"` @@ -26019,11 +29119,11 @@ func (s *CreateSnapshotInput) SetVolumeId(v string) *CreateSnapshotInput { } // Contains the parameters for CreateSpotDatafeedSubscription. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscriptionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscriptionRequest type CreateSpotDatafeedSubscriptionInput struct { _ struct{} `type:"structure"` - // The Amazon S3 bucket in which to store the Spot instance data feed. + // The Amazon S3 bucket in which to store the Spot Instance data feed. // // Bucket is a required field Bucket *string `locationName:"bucket" type:"string" required:"true"` @@ -26080,11 +29180,11 @@ func (s *CreateSpotDatafeedSubscriptionInput) SetPrefix(v string) *CreateSpotDat } // Contains the output of CreateSpotDatafeedSubscription. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscriptionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSpotDatafeedSubscriptionResult type CreateSpotDatafeedSubscriptionOutput struct { _ struct{} `type:"structure"` - // The Spot instance data feed subscription. + // The Spot Instance data feed subscription. SpotDatafeedSubscription *SpotDatafeedSubscription `locationName:"spotDatafeedSubscription" type:"structure"` } @@ -26105,7 +29205,7 @@ func (s *CreateSpotDatafeedSubscriptionOutput) SetSpotDatafeedSubscription(v *Sp } // Contains the parameters for CreateSubnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnetRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnetRequest type CreateSubnetInput struct { _ struct{} `type:"structure"` @@ -26193,7 +29293,7 @@ func (s *CreateSubnetInput) SetVpcId(v string) *CreateSubnetInput { } // Contains the output of CreateSubnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnetResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateSubnetResult type CreateSubnetOutput struct { _ struct{} `type:"structure"` @@ -26218,7 +29318,7 @@ func (s *CreateSubnetOutput) SetSubnet(v *Subnet) *CreateSubnetOutput { } // Contains the parameters for CreateTags. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTagsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTagsRequest type CreateTagsInput struct { _ struct{} `type:"structure"` @@ -26285,7 +29385,7 @@ func (s *CreateTagsInput) SetTags(v []*Tag) *CreateTagsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTagsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateTagsOutput type CreateTagsOutput struct { _ struct{} `type:"structure"` } @@ -26301,7 +29401,7 @@ func (s CreateTagsOutput) GoString() string { } // Contains the parameters for CreateVolume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolumeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolumeRequest type CreateVolumeInput struct { _ struct{} `type:"structure"` @@ -26445,7 +29545,7 @@ func (s *CreateVolumeInput) SetVolumeType(v string) *CreateVolumeInput { // Describes the user or group to be added or removed from the permissions for // a volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolumePermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolumePermission type CreateVolumePermission struct { _ struct{} `type:"structure"` @@ -26481,7 +29581,7 @@ func (s *CreateVolumePermission) SetUserId(v string) *CreateVolumePermission { } // Describes modifications to the permissions for a volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolumePermissionModifications +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVolumePermissionModifications type CreateVolumePermissionModifications struct { _ struct{} `type:"structure"` @@ -26516,8 +29616,136 @@ func (s *CreateVolumePermissionModifications) SetRemove(v []*CreateVolumePermiss return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointConnectionNotificationRequest +type CreateVpcEndpointConnectionNotificationInput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. For more information, see How to Ensure Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // One or more endpoint events for which to receive notifications. Valid values + // are Accept, Connect, Delete, and Reject. + // + // ConnectionEvents is a required field + ConnectionEvents []*string `locationNameList:"item" type:"list" required:"true"` + + // The ARN of the SNS topic for the notifications. + // + // ConnectionNotificationArn is a required field + ConnectionNotificationArn *string `type:"string" required:"true"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the endpoint service. + ServiceId *string `type:"string"` + + // The ID of the endpoint. + VpcEndpointId *string `type:"string"` +} + +// String returns the string representation +func (s CreateVpcEndpointConnectionNotificationInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateVpcEndpointConnectionNotificationInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CreateVpcEndpointConnectionNotificationInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CreateVpcEndpointConnectionNotificationInput"} + if s.ConnectionEvents == nil { + invalidParams.Add(request.NewErrParamRequired("ConnectionEvents")) + } + if s.ConnectionNotificationArn == nil { + invalidParams.Add(request.NewErrParamRequired("ConnectionNotificationArn")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClientToken sets the ClientToken field's value. +func (s *CreateVpcEndpointConnectionNotificationInput) SetClientToken(v string) *CreateVpcEndpointConnectionNotificationInput { + s.ClientToken = &v + return s +} + +// SetConnectionEvents sets the ConnectionEvents field's value. +func (s *CreateVpcEndpointConnectionNotificationInput) SetConnectionEvents(v []*string) *CreateVpcEndpointConnectionNotificationInput { + s.ConnectionEvents = v + return s +} + +// SetConnectionNotificationArn sets the ConnectionNotificationArn field's value. +func (s *CreateVpcEndpointConnectionNotificationInput) SetConnectionNotificationArn(v string) *CreateVpcEndpointConnectionNotificationInput { + s.ConnectionNotificationArn = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *CreateVpcEndpointConnectionNotificationInput) SetDryRun(v bool) *CreateVpcEndpointConnectionNotificationInput { + s.DryRun = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *CreateVpcEndpointConnectionNotificationInput) SetServiceId(v string) *CreateVpcEndpointConnectionNotificationInput { + s.ServiceId = &v + return s +} + +// SetVpcEndpointId sets the VpcEndpointId field's value. +func (s *CreateVpcEndpointConnectionNotificationInput) SetVpcEndpointId(v string) *CreateVpcEndpointConnectionNotificationInput { + s.VpcEndpointId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointConnectionNotificationResult +type CreateVpcEndpointConnectionNotificationOutput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. + ClientToken *string `locationName:"clientToken" type:"string"` + + // Information about the notification. + ConnectionNotification *ConnectionNotification `locationName:"connectionNotification" type:"structure"` +} + +// String returns the string representation +func (s CreateVpcEndpointConnectionNotificationOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateVpcEndpointConnectionNotificationOutput) GoString() string { + return s.String() +} + +// SetClientToken sets the ClientToken field's value. +func (s *CreateVpcEndpointConnectionNotificationOutput) SetClientToken(v string) *CreateVpcEndpointConnectionNotificationOutput { + s.ClientToken = &v + return s +} + +// SetConnectionNotification sets the ConnectionNotification field's value. +func (s *CreateVpcEndpointConnectionNotificationOutput) SetConnectionNotification(v *ConnectionNotification) *CreateVpcEndpointConnectionNotificationOutput { + s.ConnectionNotification = v + return s +} + // Contains the parameters for CreateVpcEndpoint. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointRequest type CreateVpcEndpointInput struct { _ struct{} `type:"structure"` @@ -26531,20 +29759,49 @@ type CreateVpcEndpointInput struct { // it is UnauthorizedOperation. DryRun *bool `type:"boolean"` - // A policy to attach to the endpoint that controls access to the service. The - // policy must be in valid JSON format. If this parameter is not specified, - // we attach a default policy that allows full access to the service. + // (Gateway endpoint) A policy to attach to the endpoint that controls access + // to the service. The policy must be in valid JSON format. If this parameter + // is not specified, we attach a default policy that allows full access to the + // service. PolicyDocument *string `type:"string"` - // One or more route table IDs. + // (Interface endpoint) Indicate whether to associate a private hosted zone + // with the specified VPC. The private hosted zone contains a record set for + // the default public DNS name for the service for the region (for example, + // kinesis.us-east-1.amazonaws.com) which resolves to the private IP addresses + // of the endpoint network interfaces in the VPC. This enables you to make requests + // to the default public DNS name for the service instead of the public DNS + // names that are automatically generated by the VPC endpoint service. + // + // To use a private hosted zone, you must set the following VPC attributes to + // true: enableDnsHostnames and enableDnsSupport. Use ModifyVpcAttribute to + // set the VPC attributes. + // + // Default: true + PrivateDnsEnabled *bool `type:"boolean"` + + // (Gateway endpoint) One or more route table IDs. RouteTableIds []*string `locationName:"RouteTableId" locationNameList:"item" type:"list"` - // The AWS service name, in the form com.amazonaws.region.service. To get a - // list of available services, use the DescribeVpcEndpointServices request. + // (Interface endpoint) The ID of one or more security groups to associate with + // the endpoint network interface. + SecurityGroupIds []*string `locationName:"SecurityGroupId" locationNameList:"item" type:"list"` + + // The service name. To get a list of available services, use the DescribeVpcEndpointServices + // request, or get the name from the service provider. // // ServiceName is a required field ServiceName *string `type:"string" required:"true"` + // (Interface endpoint) The ID of one or more subnets in which to create an + // endpoint network interface. + SubnetIds []*string `locationName:"SubnetId" locationNameList:"item" type:"list"` + + // The type of endpoint. + // + // Default: Gateway + VpcEndpointType *string `type:"string" enum:"VpcEndpointType"` + // The ID of the VPC in which the endpoint will be used. // // VpcId is a required field @@ -26595,18 +29852,42 @@ func (s *CreateVpcEndpointInput) SetPolicyDocument(v string) *CreateVpcEndpointI return s } +// SetPrivateDnsEnabled sets the PrivateDnsEnabled field's value. +func (s *CreateVpcEndpointInput) SetPrivateDnsEnabled(v bool) *CreateVpcEndpointInput { + s.PrivateDnsEnabled = &v + return s +} + // SetRouteTableIds sets the RouteTableIds field's value. func (s *CreateVpcEndpointInput) SetRouteTableIds(v []*string) *CreateVpcEndpointInput { s.RouteTableIds = v return s } +// SetSecurityGroupIds sets the SecurityGroupIds field's value. +func (s *CreateVpcEndpointInput) SetSecurityGroupIds(v []*string) *CreateVpcEndpointInput { + s.SecurityGroupIds = v + return s +} + // SetServiceName sets the ServiceName field's value. func (s *CreateVpcEndpointInput) SetServiceName(v string) *CreateVpcEndpointInput { s.ServiceName = &v return s } +// SetSubnetIds sets the SubnetIds field's value. +func (s *CreateVpcEndpointInput) SetSubnetIds(v []*string) *CreateVpcEndpointInput { + s.SubnetIds = v + return s +} + +// SetVpcEndpointType sets the VpcEndpointType field's value. +func (s *CreateVpcEndpointInput) SetVpcEndpointType(v string) *CreateVpcEndpointInput { + s.VpcEndpointType = &v + return s +} + // SetVpcId sets the VpcId field's value. func (s *CreateVpcEndpointInput) SetVpcId(v string) *CreateVpcEndpointInput { s.VpcId = &v @@ -26614,7 +29895,7 @@ func (s *CreateVpcEndpointInput) SetVpcId(v string) *CreateVpcEndpointInput { } // Contains the output of CreateVpcEndpoint. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointResult type CreateVpcEndpointOutput struct { _ struct{} `type:"structure"` @@ -26648,8 +29929,114 @@ func (s *CreateVpcEndpointOutput) SetVpcEndpoint(v *VpcEndpoint) *CreateVpcEndpo return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointServiceConfigurationRequest +type CreateVpcEndpointServiceConfigurationInput struct { + _ struct{} `type:"structure"` + + // Indicate whether requests from service consumers to create an endpoint to + // your service must be accepted. To accept a request, use AcceptVpcEndpointConnections. + AcceptanceRequired *bool `type:"boolean"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. For more information, see How to Ensure Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The Amazon Resource Names (ARNs) of one or more Network Load Balancers for + // your service. + // + // NetworkLoadBalancerArns is a required field + NetworkLoadBalancerArns []*string `locationName:"NetworkLoadBalancerArn" locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s CreateVpcEndpointServiceConfigurationInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateVpcEndpointServiceConfigurationInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CreateVpcEndpointServiceConfigurationInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CreateVpcEndpointServiceConfigurationInput"} + if s.NetworkLoadBalancerArns == nil { + invalidParams.Add(request.NewErrParamRequired("NetworkLoadBalancerArns")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAcceptanceRequired sets the AcceptanceRequired field's value. +func (s *CreateVpcEndpointServiceConfigurationInput) SetAcceptanceRequired(v bool) *CreateVpcEndpointServiceConfigurationInput { + s.AcceptanceRequired = &v + return s +} + +// SetClientToken sets the ClientToken field's value. +func (s *CreateVpcEndpointServiceConfigurationInput) SetClientToken(v string) *CreateVpcEndpointServiceConfigurationInput { + s.ClientToken = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *CreateVpcEndpointServiceConfigurationInput) SetDryRun(v bool) *CreateVpcEndpointServiceConfigurationInput { + s.DryRun = &v + return s +} + +// SetNetworkLoadBalancerArns sets the NetworkLoadBalancerArns field's value. +func (s *CreateVpcEndpointServiceConfigurationInput) SetNetworkLoadBalancerArns(v []*string) *CreateVpcEndpointServiceConfigurationInput { + s.NetworkLoadBalancerArns = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcEndpointServiceConfigurationResult +type CreateVpcEndpointServiceConfigurationOutput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. + ClientToken *string `locationName:"clientToken" type:"string"` + + // Information about the service configuration. + ServiceConfiguration *ServiceConfiguration `locationName:"serviceConfiguration" type:"structure"` +} + +// String returns the string representation +func (s CreateVpcEndpointServiceConfigurationOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreateVpcEndpointServiceConfigurationOutput) GoString() string { + return s.String() +} + +// SetClientToken sets the ClientToken field's value. +func (s *CreateVpcEndpointServiceConfigurationOutput) SetClientToken(v string) *CreateVpcEndpointServiceConfigurationOutput { + s.ClientToken = &v + return s +} + +// SetServiceConfiguration sets the ServiceConfiguration field's value. +func (s *CreateVpcEndpointServiceConfigurationOutput) SetServiceConfiguration(v *ServiceConfiguration) *CreateVpcEndpointServiceConfigurationOutput { + s.ServiceConfiguration = v + return s +} + // Contains the parameters for CreateVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcRequest type CreateVpcInput struct { _ struct{} `type:"structure"` @@ -26730,7 +30117,7 @@ func (s *CreateVpcInput) SetInstanceTenancy(v string) *CreateVpcInput { } // Contains the output of CreateVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcResult type CreateVpcOutput struct { _ struct{} `type:"structure"` @@ -26755,7 +30142,7 @@ func (s *CreateVpcOutput) SetVpc(v *Vpc) *CreateVpcOutput { } // Contains the parameters for CreateVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnectionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnectionRequest type CreateVpcPeeringConnectionInput struct { _ struct{} `type:"structure"` @@ -26765,15 +30152,22 @@ type CreateVpcPeeringConnectionInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The AWS account ID of the owner of the peer VPC. + // The AWS account ID of the owner of the accepter VPC. // // Default: Your AWS account ID PeerOwnerId *string `locationName:"peerOwnerId" type:"string"` + // The region code for the accepter VPC, if the accepter VPC is located in a + // region other than the region in which you make the request. + // + // Default: The region in which you make the request. + PeerRegion *string `type:"string"` + // The ID of the VPC with which you are creating the VPC peering connection. + // You must specify this parameter in the request. PeerVpcId *string `locationName:"peerVpcId" type:"string"` - // The ID of the requester VPC. + // The ID of the requester VPC. You must specify this parameter in the request. VpcId *string `locationName:"vpcId" type:"string"` } @@ -26799,6 +30193,12 @@ func (s *CreateVpcPeeringConnectionInput) SetPeerOwnerId(v string) *CreateVpcPee return s } +// SetPeerRegion sets the PeerRegion field's value. +func (s *CreateVpcPeeringConnectionInput) SetPeerRegion(v string) *CreateVpcPeeringConnectionInput { + s.PeerRegion = &v + return s +} + // SetPeerVpcId sets the PeerVpcId field's value. func (s *CreateVpcPeeringConnectionInput) SetPeerVpcId(v string) *CreateVpcPeeringConnectionInput { s.PeerVpcId = &v @@ -26812,7 +30212,7 @@ func (s *CreateVpcPeeringConnectionInput) SetVpcId(v string) *CreateVpcPeeringCo } // Contains the output of CreateVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnectionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpcPeeringConnectionResult type CreateVpcPeeringConnectionOutput struct { _ struct{} `type:"structure"` @@ -26837,7 +30237,7 @@ func (s *CreateVpcPeeringConnectionOutput) SetVpcPeeringConnection(v *VpcPeering } // Contains the parameters for CreateVpnConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRequest type CreateVpnConnectionInput struct { _ struct{} `type:"structure"` @@ -26852,11 +30252,7 @@ type CreateVpnConnectionInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // Indicates whether the VPN connection requires static routes. If you are creating - // a VPN connection for a device that does not support BGP, you must specify - // true. - // - // Default: false + // The options for the VPN connection. Options *VpnConnectionOptionsSpecification `locationName:"options" type:"structure"` // The type of VPN connection (ipsec.1). @@ -26930,7 +30326,7 @@ func (s *CreateVpnConnectionInput) SetVpnGatewayId(v string) *CreateVpnConnectio } // Contains the output of CreateVpnConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionResult type CreateVpnConnectionOutput struct { _ struct{} `type:"structure"` @@ -26955,7 +30351,7 @@ func (s *CreateVpnConnectionOutput) SetVpnConnection(v *VpnConnection) *CreateVp } // Contains the parameters for CreateVpnConnectionRoute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRouteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRouteRequest type CreateVpnConnectionRouteInput struct { _ struct{} `type:"structure"` @@ -27008,7 +30404,7 @@ func (s *CreateVpnConnectionRouteInput) SetVpnConnectionId(v string) *CreateVpnC return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRouteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnConnectionRouteOutput type CreateVpnConnectionRouteOutput struct { _ struct{} `type:"structure"` } @@ -27024,10 +30420,17 @@ func (s CreateVpnConnectionRouteOutput) GoString() string { } // Contains the parameters for CreateVpnGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGatewayRequest type CreateVpnGatewayInput struct { _ struct{} `type:"structure"` + // A private Autonomous System Number (ASN) for the Amazon side of a BGP session. + // If you're using a 16-bit ASN, it must be in the 64512 to 65534 range. If + // you're using a 32-bit ASN, it must be in the 4200000000 to 4294967294 range. + // + // Default: 64512 + AmazonSideAsn *int64 `type:"long"` + // The Availability Zone for the virtual private gateway. AvailabilityZone *string `type:"string"` @@ -27066,6 +30469,12 @@ func (s *CreateVpnGatewayInput) Validate() error { return nil } +// SetAmazonSideAsn sets the AmazonSideAsn field's value. +func (s *CreateVpnGatewayInput) SetAmazonSideAsn(v int64) *CreateVpnGatewayInput { + s.AmazonSideAsn = &v + return s +} + // SetAvailabilityZone sets the AvailabilityZone field's value. func (s *CreateVpnGatewayInput) SetAvailabilityZone(v string) *CreateVpnGatewayInput { s.AvailabilityZone = &v @@ -27085,7 +30494,7 @@ func (s *CreateVpnGatewayInput) SetType(v string) *CreateVpnGatewayInput { } // Contains the output of CreateVpnGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreateVpnGatewayResult type CreateVpnGatewayOutput struct { _ struct{} `type:"structure"` @@ -27109,8 +30518,74 @@ func (s *CreateVpnGatewayOutput) SetVpnGateway(v *VpnGateway) *CreateVpnGatewayO return s } +// Describes the credit option for CPU usage of a T2 instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreditSpecification +type CreditSpecification struct { + _ struct{} `type:"structure"` + + // The credit option for CPU usage of a T2 instance. + CpuCredits *string `locationName:"cpuCredits" type:"string"` +} + +// String returns the string representation +func (s CreditSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreditSpecification) GoString() string { + return s.String() +} + +// SetCpuCredits sets the CpuCredits field's value. +func (s *CreditSpecification) SetCpuCredits(v string) *CreditSpecification { + s.CpuCredits = &v + return s +} + +// The credit option for CPU usage of a T2 instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CreditSpecificationRequest +type CreditSpecificationRequest struct { + _ struct{} `type:"structure"` + + // The credit option for CPU usage of a T2 instance. Valid values are standard + // and unlimited. + // + // CpuCredits is a required field + CpuCredits *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s CreditSpecificationRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CreditSpecificationRequest) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *CreditSpecificationRequest) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "CreditSpecificationRequest"} + if s.CpuCredits == nil { + invalidParams.Add(request.NewErrParamRequired("CpuCredits")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetCpuCredits sets the CpuCredits field's value. +func (s *CreditSpecificationRequest) SetCpuCredits(v string) *CreditSpecificationRequest { + s.CpuCredits = &v + return s +} + // Describes a customer gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CustomerGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/CustomerGateway type CustomerGateway struct { _ struct{} `type:"structure"` @@ -27182,7 +30657,7 @@ func (s *CustomerGateway) SetType(v string) *CustomerGateway { } // Contains the parameters for DeleteCustomerGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGatewayRequest type DeleteCustomerGatewayInput struct { _ struct{} `type:"structure"` @@ -27233,7 +30708,7 @@ func (s *DeleteCustomerGatewayInput) SetDryRun(v bool) *DeleteCustomerGatewayInp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGatewayOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteCustomerGatewayOutput type DeleteCustomerGatewayOutput struct { _ struct{} `type:"structure"` } @@ -27249,7 +30724,7 @@ func (s DeleteCustomerGatewayOutput) GoString() string { } // Contains the parameters for DeleteDhcpOptions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptionsRequest type DeleteDhcpOptionsInput struct { _ struct{} `type:"structure"` @@ -27300,7 +30775,7 @@ func (s *DeleteDhcpOptionsInput) SetDryRun(v bool) *DeleteDhcpOptionsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptionsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteDhcpOptionsOutput type DeleteDhcpOptionsOutput struct { _ struct{} `type:"structure"` } @@ -27315,7 +30790,7 @@ func (s DeleteDhcpOptionsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGatewayRequest type DeleteEgressOnlyInternetGatewayInput struct { _ struct{} `type:"structure"` @@ -27366,7 +30841,7 @@ func (s *DeleteEgressOnlyInternetGatewayInput) SetEgressOnlyInternetGatewayId(v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteEgressOnlyInternetGatewayResult type DeleteEgressOnlyInternetGatewayOutput struct { _ struct{} `type:"structure"` @@ -27391,7 +30866,7 @@ func (s *DeleteEgressOnlyInternetGatewayOutput) SetReturnCode(v bool) *DeleteEgr } // Contains the parameters for DeleteFlowLogs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogsRequest type DeleteFlowLogsInput struct { _ struct{} `type:"structure"` @@ -27431,7 +30906,7 @@ func (s *DeleteFlowLogsInput) SetFlowLogIds(v []*string) *DeleteFlowLogsInput { } // Contains the output of DeleteFlowLogs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFlowLogsResult type DeleteFlowLogsOutput struct { _ struct{} `type:"structure"` @@ -27455,8 +30930,83 @@ func (s *DeleteFlowLogsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *DeleteFlo return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFpgaImageRequest +type DeleteFpgaImageInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the AFI. + // + // FpgaImageId is a required field + FpgaImageId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s DeleteFpgaImageInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteFpgaImageInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteFpgaImageInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteFpgaImageInput"} + if s.FpgaImageId == nil { + invalidParams.Add(request.NewErrParamRequired("FpgaImageId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *DeleteFpgaImageInput) SetDryRun(v bool) *DeleteFpgaImageInput { + s.DryRun = &v + return s +} + +// SetFpgaImageId sets the FpgaImageId field's value. +func (s *DeleteFpgaImageInput) SetFpgaImageId(v string) *DeleteFpgaImageInput { + s.FpgaImageId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteFpgaImageResult +type DeleteFpgaImageOutput struct { + _ struct{} `type:"structure"` + + // Is true if the request succeeds, and an error otherwise. + Return *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s DeleteFpgaImageOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteFpgaImageOutput) GoString() string { + return s.String() +} + +// SetReturn sets the Return field's value. +func (s *DeleteFpgaImageOutput) SetReturn(v bool) *DeleteFpgaImageOutput { + s.Return = &v + return s +} + // Contains the parameters for DeleteInternetGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGatewayRequest type DeleteInternetGatewayInput struct { _ struct{} `type:"structure"` @@ -27507,7 +31057,7 @@ func (s *DeleteInternetGatewayInput) SetInternetGatewayId(v string) *DeleteInter return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGatewayOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteInternetGatewayOutput type DeleteInternetGatewayOutput struct { _ struct{} `type:"structure"` } @@ -27523,7 +31073,7 @@ func (s DeleteInternetGatewayOutput) GoString() string { } // Contains the parameters for DeleteKeyPair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPairRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPairRequest type DeleteKeyPairInput struct { _ struct{} `type:"structure"` @@ -27574,7 +31124,7 @@ func (s *DeleteKeyPairInput) SetKeyName(v string) *DeleteKeyPairInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPairOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteKeyPairOutput type DeleteKeyPairOutput struct { _ struct{} `type:"structure"` } @@ -27589,8 +31139,294 @@ func (s DeleteKeyPairOutput) GoString() string { return s.String() } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateRequest +type DeleteLaunchTemplateInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateId *string `type:"string"` + + // The name of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateName *string `min:"3" type:"string"` +} + +// String returns the string representation +func (s DeleteLaunchTemplateInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteLaunchTemplateInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteLaunchTemplateInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteLaunchTemplateInput"} + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *DeleteLaunchTemplateInput) SetDryRun(v bool) *DeleteLaunchTemplateInput { + s.DryRun = &v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *DeleteLaunchTemplateInput) SetLaunchTemplateId(v string) *DeleteLaunchTemplateInput { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *DeleteLaunchTemplateInput) SetLaunchTemplateName(v string) *DeleteLaunchTemplateInput { + s.LaunchTemplateName = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateResult +type DeleteLaunchTemplateOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch template. + LaunchTemplate *LaunchTemplate `locationName:"launchTemplate" type:"structure"` +} + +// String returns the string representation +func (s DeleteLaunchTemplateOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteLaunchTemplateOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplate sets the LaunchTemplate field's value. +func (s *DeleteLaunchTemplateOutput) SetLaunchTemplate(v *LaunchTemplate) *DeleteLaunchTemplateOutput { + s.LaunchTemplate = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateVersionsRequest +type DeleteLaunchTemplateVersionsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateId *string `type:"string"` + + // The name of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateName *string `min:"3" type:"string"` + + // The version numbers of one or more launch template versions to delete. + // + // Versions is a required field + Versions []*string `locationName:"LaunchTemplateVersion" locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s DeleteLaunchTemplateVersionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteLaunchTemplateVersionsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteLaunchTemplateVersionsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteLaunchTemplateVersionsInput"} + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + if s.Versions == nil { + invalidParams.Add(request.NewErrParamRequired("Versions")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *DeleteLaunchTemplateVersionsInput) SetDryRun(v bool) *DeleteLaunchTemplateVersionsInput { + s.DryRun = &v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *DeleteLaunchTemplateVersionsInput) SetLaunchTemplateId(v string) *DeleteLaunchTemplateVersionsInput { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *DeleteLaunchTemplateVersionsInput) SetLaunchTemplateName(v string) *DeleteLaunchTemplateVersionsInput { + s.LaunchTemplateName = &v + return s +} + +// SetVersions sets the Versions field's value. +func (s *DeleteLaunchTemplateVersionsInput) SetVersions(v []*string) *DeleteLaunchTemplateVersionsInput { + s.Versions = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateVersionsResult +type DeleteLaunchTemplateVersionsOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch template versions that were successfully deleted. + SuccessfullyDeletedLaunchTemplateVersions []*DeleteLaunchTemplateVersionsResponseSuccessItem `locationName:"successfullyDeletedLaunchTemplateVersionSet" locationNameList:"item" type:"list"` + + // Information about the launch template versions that could not be deleted. + UnsuccessfullyDeletedLaunchTemplateVersions []*DeleteLaunchTemplateVersionsResponseErrorItem `locationName:"unsuccessfullyDeletedLaunchTemplateVersionSet" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DeleteLaunchTemplateVersionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteLaunchTemplateVersionsOutput) GoString() string { + return s.String() +} + +// SetSuccessfullyDeletedLaunchTemplateVersions sets the SuccessfullyDeletedLaunchTemplateVersions field's value. +func (s *DeleteLaunchTemplateVersionsOutput) SetSuccessfullyDeletedLaunchTemplateVersions(v []*DeleteLaunchTemplateVersionsResponseSuccessItem) *DeleteLaunchTemplateVersionsOutput { + s.SuccessfullyDeletedLaunchTemplateVersions = v + return s +} + +// SetUnsuccessfullyDeletedLaunchTemplateVersions sets the UnsuccessfullyDeletedLaunchTemplateVersions field's value. +func (s *DeleteLaunchTemplateVersionsOutput) SetUnsuccessfullyDeletedLaunchTemplateVersions(v []*DeleteLaunchTemplateVersionsResponseErrorItem) *DeleteLaunchTemplateVersionsOutput { + s.UnsuccessfullyDeletedLaunchTemplateVersions = v + return s +} + +// Describes a launch template version that could not be deleted. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateVersionsResponseErrorItem +type DeleteLaunchTemplateVersionsResponseErrorItem struct { + _ struct{} `type:"structure"` + + // The ID of the launch template. + LaunchTemplateId *string `locationName:"launchTemplateId" type:"string"` + + // The name of the launch template. + LaunchTemplateName *string `locationName:"launchTemplateName" type:"string"` + + // Information about the error. + ResponseError *ResponseError `locationName:"responseError" type:"structure"` + + // The version number of the launch template. + VersionNumber *int64 `locationName:"versionNumber" type:"long"` +} + +// String returns the string representation +func (s DeleteLaunchTemplateVersionsResponseErrorItem) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteLaunchTemplateVersionsResponseErrorItem) GoString() string { + return s.String() +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *DeleteLaunchTemplateVersionsResponseErrorItem) SetLaunchTemplateId(v string) *DeleteLaunchTemplateVersionsResponseErrorItem { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *DeleteLaunchTemplateVersionsResponseErrorItem) SetLaunchTemplateName(v string) *DeleteLaunchTemplateVersionsResponseErrorItem { + s.LaunchTemplateName = &v + return s +} + +// SetResponseError sets the ResponseError field's value. +func (s *DeleteLaunchTemplateVersionsResponseErrorItem) SetResponseError(v *ResponseError) *DeleteLaunchTemplateVersionsResponseErrorItem { + s.ResponseError = v + return s +} + +// SetVersionNumber sets the VersionNumber field's value. +func (s *DeleteLaunchTemplateVersionsResponseErrorItem) SetVersionNumber(v int64) *DeleteLaunchTemplateVersionsResponseErrorItem { + s.VersionNumber = &v + return s +} + +// Describes a launch template version that was successfully deleted. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteLaunchTemplateVersionsResponseSuccessItem +type DeleteLaunchTemplateVersionsResponseSuccessItem struct { + _ struct{} `type:"structure"` + + // The ID of the launch template. + LaunchTemplateId *string `locationName:"launchTemplateId" type:"string"` + + // The name of the launch template. + LaunchTemplateName *string `locationName:"launchTemplateName" type:"string"` + + // The version number of the launch template. + VersionNumber *int64 `locationName:"versionNumber" type:"long"` +} + +// String returns the string representation +func (s DeleteLaunchTemplateVersionsResponseSuccessItem) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteLaunchTemplateVersionsResponseSuccessItem) GoString() string { + return s.String() +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *DeleteLaunchTemplateVersionsResponseSuccessItem) SetLaunchTemplateId(v string) *DeleteLaunchTemplateVersionsResponseSuccessItem { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *DeleteLaunchTemplateVersionsResponseSuccessItem) SetLaunchTemplateName(v string) *DeleteLaunchTemplateVersionsResponseSuccessItem { + s.LaunchTemplateName = &v + return s +} + +// SetVersionNumber sets the VersionNumber field's value. +func (s *DeleteLaunchTemplateVersionsResponseSuccessItem) SetVersionNumber(v int64) *DeleteLaunchTemplateVersionsResponseSuccessItem { + s.VersionNumber = &v + return s +} + // Contains the parameters for DeleteNatGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGatewayRequest type DeleteNatGatewayInput struct { _ struct{} `type:"structure"` @@ -27630,7 +31466,7 @@ func (s *DeleteNatGatewayInput) SetNatGatewayId(v string) *DeleteNatGatewayInput } // Contains the output of DeleteNatGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGatewayResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNatGatewayResult type DeleteNatGatewayOutput struct { _ struct{} `type:"structure"` @@ -27655,7 +31491,7 @@ func (s *DeleteNatGatewayOutput) SetNatGatewayId(v string) *DeleteNatGatewayOutp } // Contains the parameters for DeleteNetworkAclEntry. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntryRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntryRequest type DeleteNetworkAclEntryInput struct { _ struct{} `type:"structure"` @@ -27734,7 +31570,7 @@ func (s *DeleteNetworkAclEntryInput) SetRuleNumber(v int64) *DeleteNetworkAclEnt return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntryOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclEntryOutput type DeleteNetworkAclEntryOutput struct { _ struct{} `type:"structure"` } @@ -27750,7 +31586,7 @@ func (s DeleteNetworkAclEntryOutput) GoString() string { } // Contains the parameters for DeleteNetworkAcl. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclRequest type DeleteNetworkAclInput struct { _ struct{} `type:"structure"` @@ -27801,7 +31637,7 @@ func (s *DeleteNetworkAclInput) SetNetworkAclId(v string) *DeleteNetworkAclInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkAclOutput type DeleteNetworkAclOutput struct { _ struct{} `type:"structure"` } @@ -27817,7 +31653,7 @@ func (s DeleteNetworkAclOutput) GoString() string { } // Contains the parameters for DeleteNetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfaceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfaceRequest type DeleteNetworkInterfaceInput struct { _ struct{} `type:"structure"` @@ -27868,7 +31704,7 @@ func (s *DeleteNetworkInterfaceInput) SetNetworkInterfaceId(v string) *DeleteNet return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfaceOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfaceOutput type DeleteNetworkInterfaceOutput struct { _ struct{} `type:"structure"` } @@ -27884,7 +31720,7 @@ func (s DeleteNetworkInterfaceOutput) GoString() string { } // Contains the parameters for DeleteNetworkInterfacePermission. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermissionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermissionRequest type DeleteNetworkInterfacePermissionInput struct { _ struct{} `type:"structure"` @@ -27946,7 +31782,7 @@ func (s *DeleteNetworkInterfacePermissionInput) SetNetworkInterfacePermissionId( } // Contains the output for DeleteNetworkInterfacePermission. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermissionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteNetworkInterfacePermissionResult type DeleteNetworkInterfacePermissionOutput struct { _ struct{} `type:"structure"` @@ -27971,7 +31807,7 @@ func (s *DeleteNetworkInterfacePermissionOutput) SetReturn(v bool) *DeleteNetwor } // Contains the parameters for DeletePlacementGroup. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroupRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroupRequest type DeletePlacementGroupInput struct { _ struct{} `type:"structure"` @@ -28022,7 +31858,7 @@ func (s *DeletePlacementGroupInput) SetGroupName(v string) *DeletePlacementGroup return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroupOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeletePlacementGroupOutput type DeletePlacementGroupOutput struct { _ struct{} `type:"structure"` } @@ -28038,7 +31874,7 @@ func (s DeletePlacementGroupOutput) GoString() string { } // Contains the parameters for DeleteRoute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteRequest type DeleteRouteInput struct { _ struct{} `type:"structure"` @@ -28109,7 +31945,7 @@ func (s *DeleteRouteInput) SetRouteTableId(v string) *DeleteRouteInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteOutput type DeleteRouteOutput struct { _ struct{} `type:"structure"` } @@ -28125,7 +31961,7 @@ func (s DeleteRouteOutput) GoString() string { } // Contains the parameters for DeleteRouteTable. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTableRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTableRequest type DeleteRouteTableInput struct { _ struct{} `type:"structure"` @@ -28176,7 +32012,7 @@ func (s *DeleteRouteTableInput) SetRouteTableId(v string) *DeleteRouteTableInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTableOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteRouteTableOutput type DeleteRouteTableOutput struct { _ struct{} `type:"structure"` } @@ -28192,7 +32028,7 @@ func (s DeleteRouteTableOutput) GoString() string { } // Contains the parameters for DeleteSecurityGroup. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroupRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroupRequest type DeleteSecurityGroupInput struct { _ struct{} `type:"structure"` @@ -28238,7 +32074,7 @@ func (s *DeleteSecurityGroupInput) SetGroupName(v string) *DeleteSecurityGroupIn return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroupOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSecurityGroupOutput type DeleteSecurityGroupOutput struct { _ struct{} `type:"structure"` } @@ -28254,7 +32090,7 @@ func (s DeleteSecurityGroupOutput) GoString() string { } // Contains the parameters for DeleteSnapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshotRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshotRequest type DeleteSnapshotInput struct { _ struct{} `type:"structure"` @@ -28305,7 +32141,7 @@ func (s *DeleteSnapshotInput) SetSnapshotId(v string) *DeleteSnapshotInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshotOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSnapshotOutput type DeleteSnapshotOutput struct { _ struct{} `type:"structure"` } @@ -28321,7 +32157,7 @@ func (s DeleteSnapshotOutput) GoString() string { } // Contains the parameters for DeleteSpotDatafeedSubscription. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscriptionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscriptionRequest type DeleteSpotDatafeedSubscriptionInput struct { _ struct{} `type:"structure"` @@ -28348,7 +32184,7 @@ func (s *DeleteSpotDatafeedSubscriptionInput) SetDryRun(v bool) *DeleteSpotDataf return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscriptionOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSpotDatafeedSubscriptionOutput type DeleteSpotDatafeedSubscriptionOutput struct { _ struct{} `type:"structure"` } @@ -28364,7 +32200,7 @@ func (s DeleteSpotDatafeedSubscriptionOutput) GoString() string { } // Contains the parameters for DeleteSubnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnetRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnetRequest type DeleteSubnetInput struct { _ struct{} `type:"structure"` @@ -28415,7 +32251,7 @@ func (s *DeleteSubnetInput) SetSubnetId(v string) *DeleteSubnetInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnetOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteSubnetOutput type DeleteSubnetOutput struct { _ struct{} `type:"structure"` } @@ -28431,7 +32267,7 @@ func (s DeleteSubnetOutput) GoString() string { } // Contains the parameters for DeleteTags. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTagsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTagsRequest type DeleteTagsInput struct { _ struct{} `type:"structure"` @@ -28441,15 +32277,17 @@ type DeleteTagsInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The ID of the resource. For example, ami-1a2b3c4d. You can specify more than - // one resource ID. + // The IDs of one or more resources. // // Resources is a required field Resources []*string `locationName:"resourceId" type:"list" required:"true"` - // One or more tags to delete. If you omit the value parameter, we delete the - // tag regardless of its value. If you specify this parameter with an empty - // string as the value, we delete the key only if its value is an empty string. + // One or more tags to delete. If you omit this parameter, we delete all tags + // for the specified resources. Specify a tag key and an optional tag value + // to delete specific tags. If you specify a tag key without a tag value, we + // delete any tag with this key regardless of its value. If you specify a tag + // key with an empty string as the tag value, we delete the tag only if its + // value is an empty string. Tags []*Tag `locationName:"tag" locationNameList:"item" type:"list"` } @@ -28494,7 +32332,7 @@ func (s *DeleteTagsInput) SetTags(v []*Tag) *DeleteTagsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTagsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteTagsOutput type DeleteTagsOutput struct { _ struct{} `type:"structure"` } @@ -28510,7 +32348,7 @@ func (s DeleteTagsOutput) GoString() string { } // Contains the parameters for DeleteVolume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolumeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolumeRequest type DeleteVolumeInput struct { _ struct{} `type:"structure"` @@ -28561,7 +32399,7 @@ func (s *DeleteVolumeInput) SetVolumeId(v string) *DeleteVolumeInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolumeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVolumeOutput type DeleteVolumeOutput struct { _ struct{} `type:"structure"` } @@ -28576,8 +32414,158 @@ func (s DeleteVolumeOutput) GoString() string { return s.String() } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointConnectionNotificationsRequest +type DeleteVpcEndpointConnectionNotificationsInput struct { + _ struct{} `type:"structure"` + + // One or more notification IDs. + // + // ConnectionNotificationIds is a required field + ConnectionNotificationIds []*string `locationName:"ConnectionNotificationId" locationNameList:"item" type:"list" required:"true"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` +} + +// String returns the string representation +func (s DeleteVpcEndpointConnectionNotificationsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteVpcEndpointConnectionNotificationsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteVpcEndpointConnectionNotificationsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteVpcEndpointConnectionNotificationsInput"} + if s.ConnectionNotificationIds == nil { + invalidParams.Add(request.NewErrParamRequired("ConnectionNotificationIds")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetConnectionNotificationIds sets the ConnectionNotificationIds field's value. +func (s *DeleteVpcEndpointConnectionNotificationsInput) SetConnectionNotificationIds(v []*string) *DeleteVpcEndpointConnectionNotificationsInput { + s.ConnectionNotificationIds = v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *DeleteVpcEndpointConnectionNotificationsInput) SetDryRun(v bool) *DeleteVpcEndpointConnectionNotificationsInput { + s.DryRun = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointConnectionNotificationsResult +type DeleteVpcEndpointConnectionNotificationsOutput struct { + _ struct{} `type:"structure"` + + // Information about the notifications that could not be deleted successfully. + Unsuccessful []*UnsuccessfulItem `locationName:"unsuccessful" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DeleteVpcEndpointConnectionNotificationsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteVpcEndpointConnectionNotificationsOutput) GoString() string { + return s.String() +} + +// SetUnsuccessful sets the Unsuccessful field's value. +func (s *DeleteVpcEndpointConnectionNotificationsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *DeleteVpcEndpointConnectionNotificationsOutput { + s.Unsuccessful = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointServiceConfigurationsRequest +type DeleteVpcEndpointServiceConfigurationsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The IDs of one or more services. + // + // ServiceIds is a required field + ServiceIds []*string `locationName:"ServiceId" locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s DeleteVpcEndpointServiceConfigurationsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteVpcEndpointServiceConfigurationsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteVpcEndpointServiceConfigurationsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteVpcEndpointServiceConfigurationsInput"} + if s.ServiceIds == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceIds")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *DeleteVpcEndpointServiceConfigurationsInput) SetDryRun(v bool) *DeleteVpcEndpointServiceConfigurationsInput { + s.DryRun = &v + return s +} + +// SetServiceIds sets the ServiceIds field's value. +func (s *DeleteVpcEndpointServiceConfigurationsInput) SetServiceIds(v []*string) *DeleteVpcEndpointServiceConfigurationsInput { + s.ServiceIds = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointServiceConfigurationsResult +type DeleteVpcEndpointServiceConfigurationsOutput struct { + _ struct{} `type:"structure"` + + // Information about the service configurations that were not deleted, if applicable. + Unsuccessful []*UnsuccessfulItem `locationName:"unsuccessful" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DeleteVpcEndpointServiceConfigurationsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteVpcEndpointServiceConfigurationsOutput) GoString() string { + return s.String() +} + +// SetUnsuccessful sets the Unsuccessful field's value. +func (s *DeleteVpcEndpointServiceConfigurationsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *DeleteVpcEndpointServiceConfigurationsOutput { + s.Unsuccessful = v + return s +} + // Contains the parameters for DeleteVpcEndpoints. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointsRequest type DeleteVpcEndpointsInput struct { _ struct{} `type:"structure"` @@ -28587,7 +32575,7 @@ type DeleteVpcEndpointsInput struct { // it is UnauthorizedOperation. DryRun *bool `type:"boolean"` - // One or more endpoint IDs. + // One or more VPC endpoint IDs. // // VpcEndpointIds is a required field VpcEndpointIds []*string `locationName:"VpcEndpointId" locationNameList:"item" type:"list" required:"true"` @@ -28629,11 +32617,11 @@ func (s *DeleteVpcEndpointsInput) SetVpcEndpointIds(v []*string) *DeleteVpcEndpo } // Contains the output of DeleteVpcEndpoints. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcEndpointsResult type DeleteVpcEndpointsOutput struct { _ struct{} `type:"structure"` - // Information about the endpoints that were not successfully deleted. + // Information about the VPC endpoints that were not successfully deleted. Unsuccessful []*UnsuccessfulItem `locationName:"unsuccessful" locationNameList:"item" type:"list"` } @@ -28654,7 +32642,7 @@ func (s *DeleteVpcEndpointsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *Delet } // Contains the parameters for DeleteVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcRequest type DeleteVpcInput struct { _ struct{} `type:"structure"` @@ -28705,7 +32693,7 @@ func (s *DeleteVpcInput) SetVpcId(v string) *DeleteVpcInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcOutput type DeleteVpcOutput struct { _ struct{} `type:"structure"` } @@ -28721,7 +32709,7 @@ func (s DeleteVpcOutput) GoString() string { } // Contains the parameters for DeleteVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnectionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnectionRequest type DeleteVpcPeeringConnectionInput struct { _ struct{} `type:"structure"` @@ -28773,7 +32761,7 @@ func (s *DeleteVpcPeeringConnectionInput) SetVpcPeeringConnectionId(v string) *D } // Contains the output of DeleteVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnectionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpcPeeringConnectionResult type DeleteVpcPeeringConnectionOutput struct { _ struct{} `type:"structure"` @@ -28798,7 +32786,7 @@ func (s *DeleteVpcPeeringConnectionOutput) SetReturn(v bool) *DeleteVpcPeeringCo } // Contains the parameters for DeleteVpnConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRequest type DeleteVpnConnectionInput struct { _ struct{} `type:"structure"` @@ -28849,7 +32837,7 @@ func (s *DeleteVpnConnectionInput) SetVpnConnectionId(v string) *DeleteVpnConnec return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionOutput type DeleteVpnConnectionOutput struct { _ struct{} `type:"structure"` } @@ -28865,7 +32853,7 @@ func (s DeleteVpnConnectionOutput) GoString() string { } // Contains the parameters for DeleteVpnConnectionRoute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRouteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRouteRequest type DeleteVpnConnectionRouteInput struct { _ struct{} `type:"structure"` @@ -28918,7 +32906,7 @@ func (s *DeleteVpnConnectionRouteInput) SetVpnConnectionId(v string) *DeleteVpnC return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRouteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnConnectionRouteOutput type DeleteVpnConnectionRouteOutput struct { _ struct{} `type:"structure"` } @@ -28934,7 +32922,7 @@ func (s DeleteVpnConnectionRouteOutput) GoString() string { } // Contains the parameters for DeleteVpnGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGatewayRequest type DeleteVpnGatewayInput struct { _ struct{} `type:"structure"` @@ -28985,7 +32973,7 @@ func (s *DeleteVpnGatewayInput) SetVpnGatewayId(v string) *DeleteVpnGatewayInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGatewayOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeleteVpnGatewayOutput type DeleteVpnGatewayOutput struct { _ struct{} `type:"structure"` } @@ -29001,7 +32989,7 @@ func (s DeleteVpnGatewayOutput) GoString() string { } // Contains the parameters for DeregisterImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImageRequest type DeregisterImageInput struct { _ struct{} `type:"structure"` @@ -29052,7 +33040,7 @@ func (s *DeregisterImageInput) SetImageId(v string) *DeregisterImageInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImageOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DeregisterImageOutput type DeregisterImageOutput struct { _ struct{} `type:"structure"` } @@ -29068,7 +33056,7 @@ func (s DeregisterImageOutput) GoString() string { } // Contains the parameters for DescribeAccountAttributes. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributesRequest type DescribeAccountAttributesInput struct { _ struct{} `type:"structure"` @@ -29105,7 +33093,7 @@ func (s *DescribeAccountAttributesInput) SetDryRun(v bool) *DescribeAccountAttri } // Contains the output of DescribeAccountAttributes. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAccountAttributesResult type DescribeAccountAttributesOutput struct { _ struct{} `type:"structure"` @@ -29130,7 +33118,7 @@ func (s *DescribeAccountAttributesOutput) SetAccountAttributes(v []*AccountAttri } // Contains the parameters for DescribeAddresses. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddressesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddressesRequest type DescribeAddressesInput struct { _ struct{} `type:"structure"` @@ -29166,6 +33154,18 @@ type DescribeAddressesInput struct { // the Elastic IP address. // // * public-ip - The Elastic IP address. + // + // * tag:key=value - The key/value combination of a tag assigned to the resource. + // Specify the key of the tag in the filter name and the value of the tag + // in the filter value. For example, for the tag Purpose=X, specify tag:Purpose + // for the filter name and X for the filter value. + // + // * tag-key - The key of a tag assigned to the resource. This filter is + // independent of the tag-value filter. For example, if you use both the + // filter "tag-key=Purpose" and the filter "tag-value=X", you get any resources + // assigned both the tag key Purpose (regardless of what the tag's value + // is), and the tag value X (regardless of the tag's key). If you want to + // list only resources where Purpose is X, see the tag:key=value filter. Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` // [EC2-Classic] One or more Elastic IP addresses. @@ -29209,7 +33209,7 @@ func (s *DescribeAddressesInput) SetPublicIps(v []*string) *DescribeAddressesInp } // Contains the output of DescribeAddresses. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddressesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAddressesResult type DescribeAddressesOutput struct { _ struct{} `type:"structure"` @@ -29234,7 +33234,7 @@ func (s *DescribeAddressesOutput) SetAddresses(v []*Address) *DescribeAddressesO } // Contains the parameters for DescribeAvailabilityZones. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZonesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZonesRequest type DescribeAvailabilityZonesInput struct { _ struct{} `type:"structure"` @@ -29290,7 +33290,7 @@ func (s *DescribeAvailabilityZonesInput) SetZoneNames(v []*string) *DescribeAvai } // Contains the output of DescribeAvailabiltyZones. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZonesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeAvailabilityZonesResult type DescribeAvailabilityZonesOutput struct { _ struct{} `type:"structure"` @@ -29315,7 +33315,7 @@ func (s *DescribeAvailabilityZonesOutput) SetAvailabilityZones(v []*Availability } // Contains the parameters for DescribeBundleTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasksRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasksRequest type DescribeBundleTasksInput struct { _ struct{} `type:"structure"` @@ -29385,7 +33385,7 @@ func (s *DescribeBundleTasksInput) SetFilters(v []*Filter) *DescribeBundleTasksI } // Contains the output of DescribeBundleTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasksResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeBundleTasksResult type DescribeBundleTasksOutput struct { _ struct{} `type:"structure"` @@ -29410,7 +33410,7 @@ func (s *DescribeBundleTasksOutput) SetBundleTasks(v []*BundleTask) *DescribeBun } // Contains the parameters for DescribeClassicLinkInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstancesRequest type DescribeClassicLinkInstancesInput struct { _ struct{} `type:"structure"` @@ -29501,7 +33501,7 @@ func (s *DescribeClassicLinkInstancesInput) SetNextToken(v string) *DescribeClas } // Contains the output of DescribeClassicLinkInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeClassicLinkInstancesResult type DescribeClassicLinkInstancesOutput struct { _ struct{} `type:"structure"` @@ -29536,7 +33536,7 @@ func (s *DescribeClassicLinkInstancesOutput) SetNextToken(v string) *DescribeCla } // Contains the parameters for DescribeConversionTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasksRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasksRequest type DescribeConversionTasksInput struct { _ struct{} `type:"structure"` @@ -29573,7 +33573,7 @@ func (s *DescribeConversionTasksInput) SetDryRun(v bool) *DescribeConversionTask } // Contains the output for DescribeConversionTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasksResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeConversionTasksResult type DescribeConversionTasksOutput struct { _ struct{} `type:"structure"` @@ -29598,7 +33598,7 @@ func (s *DescribeConversionTasksOutput) SetConversionTasks(v []*ConversionTask) } // Contains the parameters for DescribeCustomerGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGatewaysRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGatewaysRequest type DescribeCustomerGatewaysInput struct { _ struct{} `type:"structure"` @@ -29676,7 +33676,7 @@ func (s *DescribeCustomerGatewaysInput) SetFilters(v []*Filter) *DescribeCustome } // Contains the output of DescribeCustomerGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGatewaysResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeCustomerGatewaysResult type DescribeCustomerGatewaysOutput struct { _ struct{} `type:"structure"` @@ -29701,7 +33701,7 @@ func (s *DescribeCustomerGatewaysOutput) SetCustomerGateways(v []*CustomerGatewa } // Contains the parameters for DescribeDhcpOptions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptionsRequest type DescribeDhcpOptionsInput struct { _ struct{} `type:"structure"` @@ -29771,7 +33771,7 @@ func (s *DescribeDhcpOptionsInput) SetFilters(v []*Filter) *DescribeDhcpOptionsI } // Contains the output of DescribeDhcpOptions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeDhcpOptionsResult type DescribeDhcpOptionsOutput struct { _ struct{} `type:"structure"` @@ -29795,7 +33795,7 @@ func (s *DescribeDhcpOptionsOutput) SetDhcpOptions(v []*DhcpOptions) *DescribeDh return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGatewaysRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGatewaysRequest type DescribeEgressOnlyInternetGatewaysInput struct { _ struct{} `type:"structure"` @@ -29852,7 +33852,7 @@ func (s *DescribeEgressOnlyInternetGatewaysInput) SetNextToken(v string) *Descri return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGatewaysResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeEgressOnlyInternetGatewaysResult type DescribeEgressOnlyInternetGatewaysOutput struct { _ struct{} `type:"structure"` @@ -29885,7 +33885,7 @@ func (s *DescribeEgressOnlyInternetGatewaysOutput) SetNextToken(v string) *Descr return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpusRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpusRequest type DescribeElasticGpusInput struct { _ struct{} `type:"structure"` @@ -29960,12 +33960,12 @@ func (s *DescribeElasticGpusInput) SetNextToken(v string) *DescribeElasticGpusIn return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpusResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeElasticGpusResult type DescribeElasticGpusOutput struct { _ struct{} `type:"structure"` // Information about the Elastic GPUs. - ElasticGpuSet []*ElasticGpus `locationName:"elasticGpuSet" type:"list"` + ElasticGpuSet []*ElasticGpus `locationName:"elasticGpuSet" locationNameList:"item" type:"list"` // The total number of items to return. If the total number of items available // is more than the value specified in max-items then a Next-Token will be provided @@ -30006,7 +34006,7 @@ func (s *DescribeElasticGpusOutput) SetNextToken(v string) *DescribeElasticGpusO } // Contains the parameters for DescribeExportTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasksRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasksRequest type DescribeExportTasksInput struct { _ struct{} `type:"structure"` @@ -30031,7 +34031,7 @@ func (s *DescribeExportTasksInput) SetExportTaskIds(v []*string) *DescribeExport } // Contains the output for DescribeExportTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasksResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeExportTasksResult type DescribeExportTasksOutput struct { _ struct{} `type:"structure"` @@ -30056,7 +34056,7 @@ func (s *DescribeExportTasksOutput) SetExportTasks(v []*ExportTask) *DescribeExp } // Contains the parameters for DescribeFlowLogs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogsRequest type DescribeFlowLogsInput struct { _ struct{} `type:"structure"` @@ -30122,7 +34122,7 @@ func (s *DescribeFlowLogsInput) SetNextToken(v string) *DescribeFlowLogsInput { } // Contains the output of DescribeFlowLogs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFlowLogsResult type DescribeFlowLogsOutput struct { _ struct{} `type:"structure"` @@ -30156,7 +34156,96 @@ func (s *DescribeFlowLogsOutput) SetNextToken(v string) *DescribeFlowLogsOutput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImagesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImageAttributeRequest +type DescribeFpgaImageAttributeInput struct { + _ struct{} `type:"structure"` + + // The AFI attribute. + // + // Attribute is a required field + Attribute *string `type:"string" required:"true" enum:"FpgaImageAttributeName"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the AFI. + // + // FpgaImageId is a required field + FpgaImageId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s DescribeFpgaImageAttributeInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeFpgaImageAttributeInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DescribeFpgaImageAttributeInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DescribeFpgaImageAttributeInput"} + if s.Attribute == nil { + invalidParams.Add(request.NewErrParamRequired("Attribute")) + } + if s.FpgaImageId == nil { + invalidParams.Add(request.NewErrParamRequired("FpgaImageId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAttribute sets the Attribute field's value. +func (s *DescribeFpgaImageAttributeInput) SetAttribute(v string) *DescribeFpgaImageAttributeInput { + s.Attribute = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeFpgaImageAttributeInput) SetDryRun(v bool) *DescribeFpgaImageAttributeInput { + s.DryRun = &v + return s +} + +// SetFpgaImageId sets the FpgaImageId field's value. +func (s *DescribeFpgaImageAttributeInput) SetFpgaImageId(v string) *DescribeFpgaImageAttributeInput { + s.FpgaImageId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImageAttributeResult +type DescribeFpgaImageAttributeOutput struct { + _ struct{} `type:"structure"` + + // Information about the attribute. + FpgaImageAttribute *FpgaImageAttribute `locationName:"fpgaImageAttribute" type:"structure"` +} + +// String returns the string representation +func (s DescribeFpgaImageAttributeOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeFpgaImageAttributeOutput) GoString() string { + return s.String() +} + +// SetFpgaImageAttribute sets the FpgaImageAttribute field's value. +func (s *DescribeFpgaImageAttributeOutput) SetFpgaImageAttribute(v *FpgaImageAttribute) *DescribeFpgaImageAttributeOutput { + s.FpgaImageAttribute = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImagesRequest type DescribeFpgaImagesInput struct { _ struct{} `type:"structure"` @@ -30280,7 +34369,7 @@ func (s *DescribeFpgaImagesInput) SetOwners(v []*string) *DescribeFpgaImagesInpu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImagesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeFpgaImagesResult type DescribeFpgaImagesOutput struct { _ struct{} `type:"structure"` @@ -30314,7 +34403,7 @@ func (s *DescribeFpgaImagesOutput) SetNextToken(v string) *DescribeFpgaImagesOut return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferingsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferingsRequest type DescribeHostReservationOfferingsInput struct { _ struct{} `type:"structure"` @@ -30398,7 +34487,7 @@ func (s *DescribeHostReservationOfferingsInput) SetOfferingId(v string) *Describ return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferingsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationOfferingsResult type DescribeHostReservationOfferingsOutput struct { _ struct{} `type:"structure"` @@ -30407,7 +34496,7 @@ type DescribeHostReservationOfferingsOutput struct { NextToken *string `locationName:"nextToken" type:"string"` // Information about the offerings. - OfferingSet []*HostOffering `locationName:"offeringSet" type:"list"` + OfferingSet []*HostOffering `locationName:"offeringSet" locationNameList:"item" type:"list"` } // String returns the string representation @@ -30432,7 +34521,7 @@ func (s *DescribeHostReservationOfferingsOutput) SetOfferingSet(v []*HostOfferin return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationsRequest type DescribeHostReservationsInput struct { _ struct{} `type:"structure"` @@ -30493,12 +34582,12 @@ func (s *DescribeHostReservationsInput) SetNextToken(v string) *DescribeHostRese return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostReservationsResult type DescribeHostReservationsOutput struct { _ struct{} `type:"structure"` // Details about the reservation's configuration. - HostReservationSet []*HostReservation `locationName:"hostReservationSet" type:"list"` + HostReservationSet []*HostReservation `locationName:"hostReservationSet" locationNameList:"item" type:"list"` // The token to use to retrieve the next page of results. This value is null // when there are no more results to return. @@ -30528,7 +34617,7 @@ func (s *DescribeHostReservationsOutput) SetNextToken(v string) *DescribeHostRes } // Contains the parameters for DescribeHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostsRequest type DescribeHostsInput struct { _ struct{} `type:"structure"` @@ -30600,7 +34689,7 @@ func (s *DescribeHostsInput) SetNextToken(v string) *DescribeHostsInput { } // Contains the output of DescribeHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeHostsResult type DescribeHostsOutput struct { _ struct{} `type:"structure"` @@ -30634,7 +34723,7 @@ func (s *DescribeHostsOutput) SetNextToken(v string) *DescribeHostsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociationsRequest type DescribeIamInstanceProfileAssociationsInput struct { _ struct{} `type:"structure"` @@ -30707,7 +34796,7 @@ func (s *DescribeIamInstanceProfileAssociationsInput) SetNextToken(v string) *De return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociationsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIamInstanceProfileAssociationsResult type DescribeIamInstanceProfileAssociationsOutput struct { _ struct{} `type:"structure"` @@ -30742,7 +34831,7 @@ func (s *DescribeIamInstanceProfileAssociationsOutput) SetNextToken(v string) *D } // Contains the parameters for DescribeIdFormat. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormatRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormatRequest type DescribeIdFormatInput struct { _ struct{} `type:"structure"` @@ -30767,7 +34856,7 @@ func (s *DescribeIdFormatInput) SetResource(v string) *DescribeIdFormatInput { } // Contains the output of DescribeIdFormat. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormatResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdFormatResult type DescribeIdFormatOutput struct { _ struct{} `type:"structure"` @@ -30792,7 +34881,7 @@ func (s *DescribeIdFormatOutput) SetStatuses(v []*IdFormat) *DescribeIdFormatOut } // Contains the parameters for DescribeIdentityIdFormat. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormatRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormatRequest type DescribeIdentityIdFormatInput struct { _ struct{} `type:"structure"` @@ -30842,7 +34931,7 @@ func (s *DescribeIdentityIdFormatInput) SetResource(v string) *DescribeIdentityI } // Contains the output of DescribeIdentityIdFormat. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormatResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeIdentityIdFormatResult type DescribeIdentityIdFormatOutput struct { _ struct{} `type:"structure"` @@ -30867,7 +34956,7 @@ func (s *DescribeIdentityIdFormatOutput) SetStatuses(v []*IdFormat) *DescribeIde } // Contains the parameters for DescribeImageAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImageAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImageAttributeRequest type DescribeImageAttributeInput struct { _ struct{} `type:"structure"` @@ -30937,7 +35026,7 @@ func (s *DescribeImageAttributeInput) SetImageId(v string) *DescribeImageAttribu } // Describes an image attribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImageAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImageAttribute type DescribeImageAttributeOutput struct { _ struct{} `type:"structure"` @@ -31026,7 +35115,7 @@ func (s *DescribeImageAttributeOutput) SetSriovNetSupport(v *AttributeValue) *De } // Contains the parameters for DescribeImages. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImagesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImagesRequest type DescribeImagesInput struct { _ struct{} `type:"structure"` @@ -31047,8 +35136,8 @@ type DescribeImagesInput struct { // * block-device-mapping.delete-on-termination - A Boolean value that indicates // whether the Amazon EBS volume is deleted on instance termination. // - // * block-device-mapping.device-name - The device name for the EBS volume - // (for example, /dev/sdh). + // * block-device-mapping.device-name - The device name specified in the + // block device mapping (for example, /dev/sdh or xvdh). // // * block-device-mapping.snapshot-id - The ID of the snapshot used for the // EBS volume. @@ -31092,7 +35181,7 @@ type DescribeImagesInput struct { // // * ramdisk-id - The RAM disk ID. // - // * root-device-name - The name of the root device volume (for example, + // * root-device-name - The device name of the root device volume (for example, // /dev/sda1). // // * root-device-type - The type of the root device volume (ebs | instance-store). @@ -31103,6 +35192,9 @@ type DescribeImagesInput struct { // // * state-reason-message - The message for the state change. // + // * sriov-net-support - A value of simple indicates that enhanced networking + // with the Intel 82599 VF interface is enabled. + // // * tag:key=value - The key/value combination of a tag assigned to the resource. // Specify the key of the tag in the filter name and the value of the tag // in the filter value. For example, for the tag Purpose=X, specify tag:Purpose @@ -31175,7 +35267,7 @@ func (s *DescribeImagesInput) SetOwners(v []*string) *DescribeImagesInput { } // Contains the output of DescribeImages. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImagesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImagesResult type DescribeImagesOutput struct { _ struct{} `type:"structure"` @@ -31200,7 +35292,7 @@ func (s *DescribeImagesOutput) SetImages(v []*Image) *DescribeImagesOutput { } // Contains the parameters for DescribeImportImageTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasksRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasksRequest type DescribeImportImageTasksInput struct { _ struct{} `type:"structure"` @@ -31266,7 +35358,7 @@ func (s *DescribeImportImageTasksInput) SetNextToken(v string) *DescribeImportIm } // Contains the output for DescribeImportImageTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasksResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportImageTasksResult type DescribeImportImageTasksOutput struct { _ struct{} `type:"structure"` @@ -31302,7 +35394,7 @@ func (s *DescribeImportImageTasksOutput) SetNextToken(v string) *DescribeImportI } // Contains the parameters for DescribeImportSnapshotTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasksRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasksRequest type DescribeImportSnapshotTasksInput struct { _ struct{} `type:"structure"` @@ -31367,7 +35459,7 @@ func (s *DescribeImportSnapshotTasksInput) SetNextToken(v string) *DescribeImpor } // Contains the output for DescribeImportSnapshotTasks. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasksResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeImportSnapshotTasksResult type DescribeImportSnapshotTasksOutput struct { _ struct{} `type:"structure"` @@ -31403,7 +35495,7 @@ func (s *DescribeImportSnapshotTasksOutput) SetNextToken(v string) *DescribeImpo } // Contains the parameters for DescribeInstanceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceAttributeRequest type DescribeInstanceAttributeInput struct { _ struct{} `type:"structure"` @@ -31471,7 +35563,7 @@ func (s *DescribeInstanceAttributeInput) SetInstanceId(v string) *DescribeInstan } // Describes an instance attribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceAttribute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceAttribute type DescribeInstanceAttributeOutput struct { _ struct{} `type:"structure"` @@ -31482,7 +35574,7 @@ type DescribeInstanceAttributeOutput struct { // EC2 console, CLI, or API; otherwise, you can. DisableApiTermination *AttributeBooleanValue `locationName:"disableApiTermination" type:"structure"` - // Indicates whether the instance is optimized for EBS I/O. + // Indicates whether the instance is optimized for Amazon EBS I/O. EbsOptimized *AttributeBooleanValue `locationName:"ebsOptimized" type:"structure"` // Indicates whether enhanced networking with ENA is enabled. @@ -31510,12 +35602,12 @@ type DescribeInstanceAttributeOutput struct { // The RAM disk ID. RamdiskId *AttributeValue `locationName:"ramdisk" type:"structure"` - // The name of the root device (for example, /dev/sda1 or /dev/xvda). + // The device name of the root device volume (for example, /dev/sda1). RootDeviceName *AttributeValue `locationName:"rootDeviceName" type:"structure"` // Indicates whether source/destination checking is enabled. A value of true - // means checking is enabled, and false means checking is disabled. This value - // must be false for a NAT instance to perform NAT. + // means that checking is enabled, and false means that checking is disabled. + // This value must be false for a NAT instance to perform NAT. SourceDestCheck *AttributeBooleanValue `locationName:"sourceDestCheck" type:"structure"` // Indicates whether enhanced networking with the Intel 82599 Virtual Function @@ -31626,8 +35718,114 @@ func (s *DescribeInstanceAttributeOutput) SetUserData(v *AttributeValue) *Descri return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceCreditSpecificationsRequest +type DescribeInstanceCreditSpecificationsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * instance-id - The ID of the instance. + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // One or more instance IDs. + // + // Default: Describes all your instances. + // + // Constraints: Maximum 1000 explicitly specified instance IDs. + InstanceIds []*string `locationName:"InstanceId" locationNameList:"InstanceId" type:"list"` + + // The maximum number of results to return in a single call. To retrieve the + // remaining results, make another call with the returned NextToken value. This + // value can be between 5 and 1000. You cannot specify this parameter and the + // instance IDs parameter in the same call. + MaxResults *int64 `type:"integer"` + + // The token to retrieve the next page of results. + NextToken *string `type:"string"` +} + +// String returns the string representation +func (s DescribeInstanceCreditSpecificationsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeInstanceCreditSpecificationsInput) GoString() string { + return s.String() +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeInstanceCreditSpecificationsInput) SetDryRun(v bool) *DescribeInstanceCreditSpecificationsInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeInstanceCreditSpecificationsInput) SetFilters(v []*Filter) *DescribeInstanceCreditSpecificationsInput { + s.Filters = v + return s +} + +// SetInstanceIds sets the InstanceIds field's value. +func (s *DescribeInstanceCreditSpecificationsInput) SetInstanceIds(v []*string) *DescribeInstanceCreditSpecificationsInput { + s.InstanceIds = v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeInstanceCreditSpecificationsInput) SetMaxResults(v int64) *DescribeInstanceCreditSpecificationsInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeInstanceCreditSpecificationsInput) SetNextToken(v string) *DescribeInstanceCreditSpecificationsInput { + s.NextToken = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceCreditSpecificationsResult +type DescribeInstanceCreditSpecificationsOutput struct { + _ struct{} `type:"structure"` + + // Information about the credit option for CPU usage of an instance. + InstanceCreditSpecifications []*InstanceCreditSpecification `locationName:"instanceCreditSpecificationSet" locationNameList:"item" type:"list"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` +} + +// String returns the string representation +func (s DescribeInstanceCreditSpecificationsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeInstanceCreditSpecificationsOutput) GoString() string { + return s.String() +} + +// SetInstanceCreditSpecifications sets the InstanceCreditSpecifications field's value. +func (s *DescribeInstanceCreditSpecificationsOutput) SetInstanceCreditSpecifications(v []*InstanceCreditSpecification) *DescribeInstanceCreditSpecificationsOutput { + s.InstanceCreditSpecifications = v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeInstanceCreditSpecificationsOutput) SetNextToken(v string) *DescribeInstanceCreditSpecificationsOutput { + s.NextToken = &v + return s +} + // Contains the parameters for DescribeInstanceStatus. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatusRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatusRequest type DescribeInstanceStatusInput struct { _ struct{} `type:"structure"` @@ -31744,7 +35942,7 @@ func (s *DescribeInstanceStatusInput) SetNextToken(v string) *DescribeInstanceSt } // Contains the output of DescribeInstanceStatus. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatusResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstanceStatusResult type DescribeInstanceStatusOutput struct { _ struct{} `type:"structure"` @@ -31779,7 +35977,7 @@ func (s *DescribeInstanceStatusOutput) SetNextToken(v string) *DescribeInstanceS } // Contains the parameters for DescribeInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstancesRequest type DescribeInstancesInput struct { _ struct{} `type:"structure"` @@ -31804,8 +36002,8 @@ type DescribeInstancesInput struct { // * block-device-mapping.delete-on-termination - A Boolean that indicates // whether the EBS volume is deleted on instance termination. // - // * block-device-mapping.device-name - The device name for the EBS volume - // (for example, /dev/sdh or xvdh). + // * block-device-mapping.device-name - The device name specified in the + // block device mapping (for example, /dev/sdh or xvdh). // // * block-device-mapping.status - The status for the EBS volume (attaching // | attached | detaching | detached). @@ -31946,10 +36144,10 @@ type DescribeInstancesInput struct { // | in-use). // // * network-interface.source-dest-check - Whether the network interface - // performs source/destination checking. A value of true means checking is - // enabled, and false means checking is disabled. The value must be false - // for the network interface to perform network address translation (NAT) - // in your VPC. + // performs source/destination checking. A value of true means that checking + // is enabled, and false means that checking is disabled. The value must + // be false for the network interface to perform network address translation + // (NAT) in your VPC. // // * network-interface.subnet-id - The ID of the subnet for the network interface. // @@ -31984,22 +36182,21 @@ type DescribeInstancesInput struct { // ID is created any time you launch an instance. A reservation ID has a // one-to-one relationship with an instance launch request, but can be associated // with more than one instance if you launch multiple instances using the - // same launch request. For example, if you launch one instance, you'll get + // same launch request. For example, if you launch one instance, you get // one reservation ID. If you launch ten instances using the same launch - // request, you'll also get one reservation ID. + // request, you also get one reservation ID. // - // * root-device-name - The name of the root device for the instance (for - // example, /dev/sda1 or /dev/xvda). + // * root-device-name - The device name of the root device volume (for example, + // /dev/sda1). // - // * root-device-type - The type of root device that the instance uses (ebs - // | instance-store). + // * root-device-type - The type of the root device volume (ebs | instance-store). // // * source-dest-check - Indicates whether the instance performs source/destination // checking. A value of true means that checking is enabled, and false means - // checking is disabled. The value must be false for the instance to perform - // network address translation (NAT) in your VPC. + // that checking is disabled. The value must be false for the instance to + // perform network address translation (NAT) in your VPC. // - // * spot-instance-request-id - The ID of the Spot instance request. + // * spot-instance-request-id - The ID of the Spot Instance request. // // * state-reason-code - The reason code for the state change. // @@ -32016,9 +36213,8 @@ type DescribeInstancesInput struct { // independent of the tag-value filter. For example, if you use both the // filter "tag-key=Purpose" and the filter "tag-value=X", you get any resources // assigned both the tag key Purpose (regardless of what the tag's value - // is), and the tag value X (regardless of what the tag's key is). If you - // want to list only resources where Purpose is X, see the tag:key=value - // filter. + // is), and the tag value X (regardless of the tag's key). If you want to + // list only resources where Purpose is X, see the tag:key=value filter. // // * tag-value - The value of a tag assigned to the resource. This filter // is independent of the tag-key filter. @@ -32087,7 +36283,7 @@ func (s *DescribeInstancesInput) SetNextToken(v string) *DescribeInstancesInput } // Contains the output of DescribeInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInstancesResult type DescribeInstancesOutput struct { _ struct{} `type:"structure"` @@ -32122,7 +36318,7 @@ func (s *DescribeInstancesOutput) SetReservations(v []*Reservation) *DescribeIns } // Contains the parameters for DescribeInternetGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGatewaysRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGatewaysRequest type DescribeInternetGatewaysInput struct { _ struct{} `type:"structure"` @@ -32193,7 +36389,7 @@ func (s *DescribeInternetGatewaysInput) SetInternetGatewayIds(v []*string) *Desc } // Contains the output of DescribeInternetGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGatewaysResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeInternetGatewaysResult type DescribeInternetGatewaysOutput struct { _ struct{} `type:"structure"` @@ -32218,7 +36414,7 @@ func (s *DescribeInternetGatewaysOutput) SetInternetGateways(v []*InternetGatewa } // Contains the parameters for DescribeKeyPairs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairsRequest type DescribeKeyPairsInput struct { _ struct{} `type:"structure"` @@ -32270,7 +36466,7 @@ func (s *DescribeKeyPairsInput) SetKeyNames(v []*string) *DescribeKeyPairsInput } // Contains the output of DescribeKeyPairs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeKeyPairsResult type DescribeKeyPairsOutput struct { _ struct{} `type:"structure"` @@ -32294,8 +36490,300 @@ func (s *DescribeKeyPairsOutput) SetKeyPairs(v []*KeyPairInfo) *DescribeKeyPairs return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplateVersionsRequest +type DescribeLaunchTemplateVersionsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * create-time - The time the launch template version was created. + // + // * ebs-optimized - A boolean that indicates whether the instance is optimized + // for Amazon EBS I/O. + // + // * iam-instance-profile - The ARN of the IAM instance profile. + // + // * image-id - The ID of the AMI. + // + // * instance-type - The instance type. + // + // * is-default-version - A boolean that indicates whether the launch template + // version is the default version. + // + // * kernel-id - The kernel ID. + // + // * ram-disk-id - The RAM disk ID. + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // The ID of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateId *string `type:"string"` + + // The name of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateName *string `min:"3" type:"string"` + + // The maximum number of results to return in a single call. To retrieve the + // remaining results, make another call with the returned NextToken value. This + // value can be between 5 and 1000. + MaxResults *int64 `type:"integer"` + + // The version number up to which to describe launch template versions. + MaxVersion *string `type:"string"` + + // The version number after which to describe launch template versions. + MinVersion *string `type:"string"` + + // The token to request the next page of results. + NextToken *string `type:"string"` + + // One or more versions of the launch template. + Versions []*string `locationName:"LaunchTemplateVersion" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DescribeLaunchTemplateVersionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeLaunchTemplateVersionsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DescribeLaunchTemplateVersionsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DescribeLaunchTemplateVersionsInput"} + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetDryRun(v bool) *DescribeLaunchTemplateVersionsInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetFilters(v []*Filter) *DescribeLaunchTemplateVersionsInput { + s.Filters = v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetLaunchTemplateId(v string) *DescribeLaunchTemplateVersionsInput { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetLaunchTemplateName(v string) *DescribeLaunchTemplateVersionsInput { + s.LaunchTemplateName = &v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetMaxResults(v int64) *DescribeLaunchTemplateVersionsInput { + s.MaxResults = &v + return s +} + +// SetMaxVersion sets the MaxVersion field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetMaxVersion(v string) *DescribeLaunchTemplateVersionsInput { + s.MaxVersion = &v + return s +} + +// SetMinVersion sets the MinVersion field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetMinVersion(v string) *DescribeLaunchTemplateVersionsInput { + s.MinVersion = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetNextToken(v string) *DescribeLaunchTemplateVersionsInput { + s.NextToken = &v + return s +} + +// SetVersions sets the Versions field's value. +func (s *DescribeLaunchTemplateVersionsInput) SetVersions(v []*string) *DescribeLaunchTemplateVersionsInput { + s.Versions = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplateVersionsResult +type DescribeLaunchTemplateVersionsOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch template versions. + LaunchTemplateVersions []*LaunchTemplateVersion `locationName:"launchTemplateVersionSet" locationNameList:"item" type:"list"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` +} + +// String returns the string representation +func (s DescribeLaunchTemplateVersionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeLaunchTemplateVersionsOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplateVersions sets the LaunchTemplateVersions field's value. +func (s *DescribeLaunchTemplateVersionsOutput) SetLaunchTemplateVersions(v []*LaunchTemplateVersion) *DescribeLaunchTemplateVersionsOutput { + s.LaunchTemplateVersions = v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeLaunchTemplateVersionsOutput) SetNextToken(v string) *DescribeLaunchTemplateVersionsOutput { + s.NextToken = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplatesRequest +type DescribeLaunchTemplatesInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * create-time - The time the launch template was created. + // + // * launch-template-name - The name of the launch template. + // + // * tag:key=value - The key/value combination of a tag assigned to the resource. + // Specify the key of the tag in the filter name and the value of the tag + // in the filter value. For example, for the tag Purpose=X, specify tag:Purpose + // for the filter name and X for the filter value. + // + // * tag-key - The key of a tag assigned to the resource. This filter is + // independent of the tag-value filter. For example, if you use both the + // filter "tag-key=Purpose" and the filter "tag-value=X", you get any resources + // assigned both the tag key Purpose (regardless of what the tag's value + // is), and the tag value X (regardless of the tag's key). If you want to + // list only resources where Purpose is X, see the tag:key=value filter. + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // One or more launch template IDs. + LaunchTemplateIds []*string `locationName:"LaunchTemplateId" locationNameList:"item" type:"list"` + + // One or more launch template names. + LaunchTemplateNames []*string `locationName:"LaunchTemplateName" locationNameList:"item" type:"list"` + + // The maximum number of results to return in a single call. To retrieve the + // remaining results, make another call with the returned NextToken value. This + // value can be between 5 and 1000. + MaxResults *int64 `type:"integer"` + + // The token to request the next page of results. + NextToken *string `type:"string"` +} + +// String returns the string representation +func (s DescribeLaunchTemplatesInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeLaunchTemplatesInput) GoString() string { + return s.String() +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeLaunchTemplatesInput) SetDryRun(v bool) *DescribeLaunchTemplatesInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeLaunchTemplatesInput) SetFilters(v []*Filter) *DescribeLaunchTemplatesInput { + s.Filters = v + return s +} + +// SetLaunchTemplateIds sets the LaunchTemplateIds field's value. +func (s *DescribeLaunchTemplatesInput) SetLaunchTemplateIds(v []*string) *DescribeLaunchTemplatesInput { + s.LaunchTemplateIds = v + return s +} + +// SetLaunchTemplateNames sets the LaunchTemplateNames field's value. +func (s *DescribeLaunchTemplatesInput) SetLaunchTemplateNames(v []*string) *DescribeLaunchTemplatesInput { + s.LaunchTemplateNames = v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeLaunchTemplatesInput) SetMaxResults(v int64) *DescribeLaunchTemplatesInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeLaunchTemplatesInput) SetNextToken(v string) *DescribeLaunchTemplatesInput { + s.NextToken = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeLaunchTemplatesResult +type DescribeLaunchTemplatesOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch templates. + LaunchTemplates []*LaunchTemplate `locationName:"launchTemplates" locationNameList:"item" type:"list"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` +} + +// String returns the string representation +func (s DescribeLaunchTemplatesOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeLaunchTemplatesOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplates sets the LaunchTemplates field's value. +func (s *DescribeLaunchTemplatesOutput) SetLaunchTemplates(v []*LaunchTemplate) *DescribeLaunchTemplatesOutput { + s.LaunchTemplates = v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeLaunchTemplatesOutput) SetNextToken(v string) *DescribeLaunchTemplatesOutput { + s.NextToken = &v + return s +} + // Contains the parameters for DescribeMovingAddresses. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddressesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddressesRequest type DescribeMovingAddressesInput struct { _ struct{} `type:"structure"` @@ -32367,7 +36855,7 @@ func (s *DescribeMovingAddressesInput) SetPublicIps(v []*string) *DescribeMoving } // Contains the output of DescribeMovingAddresses. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddressesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeMovingAddressesResult type DescribeMovingAddressesOutput struct { _ struct{} `type:"structure"` @@ -32402,7 +36890,7 @@ func (s *DescribeMovingAddressesOutput) SetNextToken(v string) *DescribeMovingAd } // Contains the parameters for DescribeNatGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGatewaysRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGatewaysRequest type DescribeNatGatewaysInput struct { _ struct{} `type:"structure"` @@ -32415,6 +36903,22 @@ type DescribeNatGatewaysInput struct { // // * subnet-id - The ID of the subnet in which the NAT gateway resides. // + // * tag:key=value - The key/value combination of a tag assigned to the resource. + // Specify the key of the tag in the filter name and the value of the tag + // in the filter value. For example, for the tag Purpose=X, specify tag:Purpose + // for the filter name and X for the filter value. + // + // * tag-key - The key of a tag assigned to the resource. This filter is + // independent of the tag-value filter. For example, if you use both the + // filter "tag-key=Purpose" and the filter "tag-value=X", you get any resources + // assigned both the tag key Purpose (regardless of what the tag's value + // is), and the tag value X (regardless of what the tag's key is). If you + // want to list only resources where Purpose is X, see the tag:key=value + // filter. + // + // * tag-value - The value of a tag assigned to the resource. This filter + // is independent of the tag-key filter. + // // * vpc-id - The ID of the VPC in which the NAT gateway resides. Filter []*Filter `locationNameList:"Filter" type:"list"` @@ -32468,7 +36972,7 @@ func (s *DescribeNatGatewaysInput) SetNextToken(v string) *DescribeNatGatewaysIn } // Contains the output of DescribeNatGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGatewaysResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNatGatewaysResult type DescribeNatGatewaysOutput struct { _ struct{} `type:"structure"` @@ -32503,7 +37007,7 @@ func (s *DescribeNatGatewaysOutput) SetNextToken(v string) *DescribeNatGatewaysO } // Contains the parameters for DescribeNetworkAcls. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAclsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAclsRequest type DescribeNetworkAclsInput struct { _ struct{} `type:"structure"` @@ -32605,7 +37109,7 @@ func (s *DescribeNetworkAclsInput) SetNetworkAclIds(v []*string) *DescribeNetwor } // Contains the output of DescribeNetworkAcls. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAclsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkAclsResult type DescribeNetworkAclsOutput struct { _ struct{} `type:"structure"` @@ -32630,7 +37134,7 @@ func (s *DescribeNetworkAclsOutput) SetNetworkAcls(v []*NetworkAcl) *DescribeNet } // Contains the parameters for DescribeNetworkInterfaceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttributeRequest type DescribeNetworkInterfaceAttributeInput struct { _ struct{} `type:"structure"` @@ -32691,7 +37195,7 @@ func (s *DescribeNetworkInterfaceAttributeInput) SetNetworkInterfaceId(v string) } // Contains the output of DescribeNetworkInterfaceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttributeResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfaceAttributeResult type DescribeNetworkInterfaceAttributeOutput struct { _ struct{} `type:"structure"` @@ -32752,7 +37256,7 @@ func (s *DescribeNetworkInterfaceAttributeOutput) SetSourceDestCheck(v *Attribut } // Contains the parameters for DescribeNetworkInterfacePermissions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissionsRequest type DescribeNetworkInterfacePermissionsInput struct { _ struct{} `type:"structure"` @@ -32819,7 +37323,7 @@ func (s *DescribeNetworkInterfacePermissionsInput) SetNextToken(v string) *Descr } // Contains the output for DescribeNetworkInterfacePermissions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacePermissionsResult type DescribeNetworkInterfacePermissionsOutput struct { _ struct{} `type:"structure"` @@ -32853,7 +37357,7 @@ func (s *DescribeNetworkInterfacePermissionsOutput) SetNextToken(v string) *Desc } // Contains the parameters for DescribeNetworkInterfaces. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacesRequest type DescribeNetworkInterfacesInput struct { _ struct{} `type:"structure"` @@ -33011,7 +37515,7 @@ func (s *DescribeNetworkInterfacesInput) SetNetworkInterfaceIds(v []*string) *De } // Contains the output of DescribeNetworkInterfaces. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeNetworkInterfacesResult type DescribeNetworkInterfacesOutput struct { _ struct{} `type:"structure"` @@ -33036,7 +37540,7 @@ func (s *DescribeNetworkInterfacesOutput) SetNetworkInterfaces(v []*NetworkInter } // Contains the parameters for DescribePlacementGroups. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroupsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroupsRequest type DescribePlacementGroupsInput struct { _ struct{} `type:"structure"` @@ -33053,7 +37557,7 @@ type DescribePlacementGroupsInput struct { // * state - The state of the placement group (pending | available | deleting // | deleted). // - // * strategy - The strategy of the placement group (cluster). + // * strategy - The strategy of the placement group (cluster | spread). Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` // One or more placement group names. @@ -33091,7 +37595,7 @@ func (s *DescribePlacementGroupsInput) SetGroupNames(v []*string) *DescribePlace } // Contains the output of DescribePlacementGroups. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroupsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePlacementGroupsResult type DescribePlacementGroupsOutput struct { _ struct{} `type:"structure"` @@ -33116,7 +37620,7 @@ func (s *DescribePlacementGroupsOutput) SetPlacementGroups(v []*PlacementGroup) } // Contains the parameters for DescribePrefixLists. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixListsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixListsRequest type DescribePrefixListsInput struct { _ struct{} `type:"structure"` @@ -33190,7 +37694,7 @@ func (s *DescribePrefixListsInput) SetPrefixListIds(v []*string) *DescribePrefix } // Contains the output of DescribePrefixLists. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixListsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribePrefixListsResult type DescribePrefixListsOutput struct { _ struct{} `type:"structure"` @@ -33225,7 +37729,7 @@ func (s *DescribePrefixListsOutput) SetPrefixLists(v []*PrefixList) *DescribePre } // Contains the parameters for DescribeRegions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegionsRequest type DescribeRegionsInput struct { _ struct{} `type:"structure"` @@ -33275,7 +37779,7 @@ func (s *DescribeRegionsInput) SetRegionNames(v []*string) *DescribeRegionsInput } // Contains the output of DescribeRegions. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRegionsResult type DescribeRegionsOutput struct { _ struct{} `type:"structure"` @@ -33300,7 +37804,7 @@ func (s *DescribeRegionsOutput) SetRegions(v []*Region) *DescribeRegionsOutput { } // Contains the parameters for DescribeReservedInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesRequest type DescribeReservedInstancesInput struct { _ struct{} `type:"structure"` @@ -33420,7 +37924,7 @@ func (s *DescribeReservedInstancesInput) SetReservedInstancesIds(v []*string) *D } // Contains the parameters for DescribeReservedInstancesListings. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListingsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListingsRequest type DescribeReservedInstancesListingsInput struct { _ struct{} `type:"structure"` @@ -33472,7 +37976,7 @@ func (s *DescribeReservedInstancesListingsInput) SetReservedInstancesListingId(v } // Contains the output of DescribeReservedInstancesListings. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListingsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesListingsResult type DescribeReservedInstancesListingsOutput struct { _ struct{} `type:"structure"` @@ -33497,7 +38001,7 @@ func (s *DescribeReservedInstancesListingsOutput) SetReservedInstancesListings(v } // Contains the parameters for DescribeReservedInstancesModifications. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModificationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModificationsRequest type DescribeReservedInstancesModificationsInput struct { _ struct{} `type:"structure"` @@ -33573,7 +38077,7 @@ func (s *DescribeReservedInstancesModificationsInput) SetReservedInstancesModifi } // Contains the output of DescribeReservedInstancesModifications. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModificationsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesModificationsResult type DescribeReservedInstancesModificationsOutput struct { _ struct{} `type:"structure"` @@ -33608,7 +38112,7 @@ func (s *DescribeReservedInstancesModificationsOutput) SetReservedInstancesModif } // Contains the parameters for DescribeReservedInstancesOfferings. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferingsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferingsRequest type DescribeReservedInstancesOfferingsInput struct { _ struct{} `type:"structure"` @@ -33818,7 +38322,7 @@ func (s *DescribeReservedInstancesOfferingsInput) SetReservedInstancesOfferingId } // Contains the output of DescribeReservedInstancesOfferings. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferingsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesOfferingsResult type DescribeReservedInstancesOfferingsOutput struct { _ struct{} `type:"structure"` @@ -33853,7 +38357,7 @@ func (s *DescribeReservedInstancesOfferingsOutput) SetReservedInstancesOfferings } // Contains the output for DescribeReservedInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeReservedInstancesResult type DescribeReservedInstancesOutput struct { _ struct{} `type:"structure"` @@ -33878,7 +38382,7 @@ func (s *DescribeReservedInstancesOutput) SetReservedInstances(v []*ReservedInst } // Contains the parameters for DescribeRouteTables. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTablesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTablesRequest type DescribeRouteTablesInput struct { _ struct{} `type:"structure"` @@ -33991,7 +38495,7 @@ func (s *DescribeRouteTablesInput) SetRouteTableIds(v []*string) *DescribeRouteT } // Contains the output of DescribeRouteTables. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTablesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeRouteTablesResult type DescribeRouteTablesOutput struct { _ struct{} `type:"structure"` @@ -34016,7 +38520,7 @@ func (s *DescribeRouteTablesOutput) SetRouteTables(v []*RouteTable) *DescribeRou } // Contains the parameters for DescribeScheduledInstanceAvailability. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailabilityRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailabilityRequest type DescribeScheduledInstanceAvailabilityInput struct { _ struct{} `type:"structure"` @@ -34146,7 +38650,7 @@ func (s *DescribeScheduledInstanceAvailabilityInput) SetRecurrence(v *ScheduledI } // Contains the output of DescribeScheduledInstanceAvailability. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailabilityResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstanceAvailabilityResult type DescribeScheduledInstanceAvailabilityOutput struct { _ struct{} `type:"structure"` @@ -34181,7 +38685,7 @@ func (s *DescribeScheduledInstanceAvailabilityOutput) SetScheduledInstanceAvaila } // Contains the parameters for DescribeScheduledInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstancesRequest type DescribeScheduledInstancesInput struct { _ struct{} `type:"structure"` @@ -34264,7 +38768,7 @@ func (s *DescribeScheduledInstancesInput) SetSlotStartTimeRange(v *SlotStartTime } // Contains the output of DescribeScheduledInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeScheduledInstancesResult type DescribeScheduledInstancesOutput struct { _ struct{} `type:"structure"` @@ -34298,7 +38802,7 @@ func (s *DescribeScheduledInstancesOutput) SetScheduledInstanceSet(v []*Schedule return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferencesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferencesRequest type DescribeSecurityGroupReferencesInput struct { _ struct{} `type:"structure"` @@ -34349,7 +38853,7 @@ func (s *DescribeSecurityGroupReferencesInput) SetGroupId(v []*string) *Describe return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferencesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupReferencesResult type DescribeSecurityGroupReferencesOutput struct { _ struct{} `type:"structure"` @@ -34374,7 +38878,7 @@ func (s *DescribeSecurityGroupReferencesOutput) SetSecurityGroupReferenceSet(v [ } // Contains the parameters for DescribeSecurityGroups. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupsRequest type DescribeSecurityGroupsInput struct { _ struct{} `type:"structure"` @@ -34390,36 +38894,63 @@ type DescribeSecurityGroupsInput struct { // // * description - The description of the security group. // + // * egress.ip-permission.cidr - An IPv4 CIDR block for an outbound security + // group rule. + // + // * egress.ip-permission.from-port - For an outbound rule, the start of + // port range for the TCP and UDP protocols, or an ICMP type number. + // + // * egress.ip-permission.group-id - The ID of a security group that has + // been referenced in an outbound security group rule. + // + // * egress.ip-permission.group-name - The name of a security group that + // has been referenced in an outbound security group rule. + // + // * egress.ip-permission.ipv6-cidr - An IPv6 CIDR block for an outbound + // security group rule. + // // * egress.ip-permission.prefix-list-id - The ID (prefix) of the AWS service - // to which the security group allows access. + // to which a security group rule allows outbound access. + // + // * egress.ip-permission.protocol - The IP protocol for an outbound security + // group rule (tcp | udp | icmp or a protocol number). + // + // * egress.ip-permission.to-port - For an outbound rule, the end of port + // range for the TCP and UDP protocols, or an ICMP code. + // + // * egress.ip-permission.user-id - The ID of an AWS account that has been + // referenced in an outbound security group rule. // // * group-id - The ID of the security group. // // * group-name - The name of the security group. // - // * ip-permission.cidr - An IPv4 CIDR range that has been granted permission - // in a security group rule. + // * ip-permission.cidr - An IPv4 CIDR block for an inbound security group + // rule. // - // * ip-permission.from-port - The start of port range for the TCP and UDP - // protocols, or an ICMP type number. + // * ip-permission.from-port - For an inbound rule, the start of port range + // for the TCP and UDP protocols, or an ICMP type number. // - // * ip-permission.group-id - The ID of a security group that has been granted - // permission. + // * ip-permission.group-id - The ID of a security group that has been referenced + // in an inbound security group rule. // // * ip-permission.group-name - The name of a security group that has been - // granted permission. + // referenced in an inbound security group rule. // - // * ip-permission.ipv6-cidr - An IPv6 CIDR range that has been granted permission - // in a security group rule. + // * ip-permission.ipv6-cidr - An IPv6 CIDR block for an inbound security + // group rule. // - // * ip-permission.protocol - The IP protocol for the permission (tcp | udp - // | icmp or a protocol number). + // * ip-permission.prefix-list-id - The ID (prefix) of the AWS service from + // which a security group rule allows inbound access. // - // * ip-permission.to-port - The end of port range for the TCP and UDP protocols, - // or an ICMP code. + // * ip-permission.protocol - The IP protocol for an inbound security group + // rule (tcp | udp | icmp or a protocol number). // - // * ip-permission.user-id - The ID of an AWS account that has been granted - // permission. + // * ip-permission.to-port - For an inbound rule, the end of port range for + // the TCP and UDP protocols, or an ICMP code. + // + // * ip-permission.user-id - The ID of an AWS account that has been referenced + // in an inbound security group rule. // // * owner-id - The AWS account ID of the owner of the security group. // @@ -34443,6 +38974,14 @@ type DescribeSecurityGroupsInput struct { // // Default: Describes all your security groups. GroupNames []*string `locationName:"GroupName" locationNameList:"GroupName" type:"list"` + + // The maximum number of results to return in a single call. To retrieve the + // remaining results, make another request with the returned NextToken value. + // This value can be between 5 and 1000. + MaxResults *int64 `type:"integer"` + + // The token to request the next page of results. + NextToken *string `type:"string"` } // String returns the string representation @@ -34479,11 +39018,27 @@ func (s *DescribeSecurityGroupsInput) SetGroupNames(v []*string) *DescribeSecuri return s } +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeSecurityGroupsInput) SetMaxResults(v int64) *DescribeSecurityGroupsInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeSecurityGroupsInput) SetNextToken(v string) *DescribeSecurityGroupsInput { + s.NextToken = &v + return s +} + // Contains the output of DescribeSecurityGroups. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSecurityGroupsResult type DescribeSecurityGroupsOutput struct { _ struct{} `type:"structure"` + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` + // Information about one or more security groups. SecurityGroups []*SecurityGroup `locationName:"securityGroupInfo" locationNameList:"item" type:"list"` } @@ -34498,6 +39053,12 @@ func (s DescribeSecurityGroupsOutput) GoString() string { return s.String() } +// SetNextToken sets the NextToken field's value. +func (s *DescribeSecurityGroupsOutput) SetNextToken(v string) *DescribeSecurityGroupsOutput { + s.NextToken = &v + return s +} + // SetSecurityGroups sets the SecurityGroups field's value. func (s *DescribeSecurityGroupsOutput) SetSecurityGroups(v []*SecurityGroup) *DescribeSecurityGroupsOutput { s.SecurityGroups = v @@ -34505,7 +39066,7 @@ func (s *DescribeSecurityGroupsOutput) SetSecurityGroups(v []*SecurityGroup) *De } // Contains the parameters for DescribeSnapshotAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttributeRequest type DescribeSnapshotAttributeInput struct { _ struct{} `type:"structure"` @@ -34571,7 +39132,7 @@ func (s *DescribeSnapshotAttributeInput) SetSnapshotId(v string) *DescribeSnapsh } // Contains the output of DescribeSnapshotAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttributeResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotAttributeResult type DescribeSnapshotAttributeOutput struct { _ struct{} `type:"structure"` @@ -34614,7 +39175,7 @@ func (s *DescribeSnapshotAttributeOutput) SetSnapshotId(v string) *DescribeSnaps } // Contains the parameters for DescribeSnapshots. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotsRequest type DescribeSnapshotsInput struct { _ struct{} `type:"structure"` @@ -34748,7 +39309,7 @@ func (s *DescribeSnapshotsInput) SetSnapshotIds(v []*string) *DescribeSnapshotsI } // Contains the output of DescribeSnapshots. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSnapshotsResult type DescribeSnapshotsOutput struct { _ struct{} `type:"structure"` @@ -34785,7 +39346,7 @@ func (s *DescribeSnapshotsOutput) SetSnapshots(v []*Snapshot) *DescribeSnapshots } // Contains the parameters for DescribeSpotDatafeedSubscription. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscriptionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscriptionRequest type DescribeSpotDatafeedSubscriptionInput struct { _ struct{} `type:"structure"` @@ -34813,11 +39374,11 @@ func (s *DescribeSpotDatafeedSubscriptionInput) SetDryRun(v bool) *DescribeSpotD } // Contains the output of DescribeSpotDatafeedSubscription. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscriptionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotDatafeedSubscriptionResult type DescribeSpotDatafeedSubscriptionOutput struct { _ struct{} `type:"structure"` - // The Spot instance data feed subscription. + // The Spot Instance data feed subscription. SpotDatafeedSubscription *SpotDatafeedSubscription `locationName:"spotDatafeedSubscription" type:"structure"` } @@ -34838,7 +39399,7 @@ func (s *DescribeSpotDatafeedSubscriptionOutput) SetSpotDatafeedSubscription(v * } // Contains the parameters for DescribeSpotFleetInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstancesRequest type DescribeSpotFleetInstancesInput struct { _ struct{} `type:"structure"` @@ -34856,7 +39417,7 @@ type DescribeSpotFleetInstancesInput struct { // The token for the next set of results. NextToken *string `locationName:"nextToken" type:"string"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -34910,7 +39471,7 @@ func (s *DescribeSpotFleetInstancesInput) SetSpotFleetRequestId(v string) *Descr } // Contains the output of DescribeSpotFleetInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstancesResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetInstancesResponse type DescribeSpotFleetInstancesOutput struct { _ struct{} `type:"structure"` @@ -34924,7 +39485,7 @@ type DescribeSpotFleetInstancesOutput struct { // when there are no more results to return. NextToken *string `locationName:"nextToken" type:"string"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -34959,7 +39520,7 @@ func (s *DescribeSpotFleetInstancesOutput) SetSpotFleetRequestId(v string) *Desc } // Contains the parameters for DescribeSpotFleetRequestHistory. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistoryRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistoryRequest type DescribeSpotFleetRequestHistoryInput struct { _ struct{} `type:"structure"` @@ -34980,7 +39541,7 @@ type DescribeSpotFleetRequestHistoryInput struct { // The token for the next set of results. NextToken *string `locationName:"nextToken" type:"string"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -35054,11 +39615,11 @@ func (s *DescribeSpotFleetRequestHistoryInput) SetStartTime(v time.Time) *Descri } // Contains the output of DescribeSpotFleetRequestHistory. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistoryResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestHistoryResponse type DescribeSpotFleetRequestHistoryOutput struct { _ struct{} `type:"structure"` - // Information about the events in the history of the Spot fleet request. + // Information about the events in the history of the Spot Fleet request. // // HistoryRecords is a required field HistoryRecords []*HistoryRecord `locationName:"historyRecordSet" locationNameList:"item" type:"list" required:"true"` @@ -35075,7 +39636,7 @@ type DescribeSpotFleetRequestHistoryOutput struct { // when there are no more results to return. NextToken *string `locationName:"nextToken" type:"string"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -35127,7 +39688,7 @@ func (s *DescribeSpotFleetRequestHistoryOutput) SetStartTime(v time.Time) *Descr } // Contains the parameters for DescribeSpotFleetRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestsRequest type DescribeSpotFleetRequestsInput struct { _ struct{} `type:"structure"` @@ -35145,7 +39706,7 @@ type DescribeSpotFleetRequestsInput struct { // The token for the next set of results. NextToken *string `locationName:"nextToken" type:"string"` - // The IDs of the Spot fleet requests. + // The IDs of the Spot Fleet requests. SpotFleetRequestIds []*string `locationName:"spotFleetRequestId" locationNameList:"item" type:"list"` } @@ -35184,7 +39745,7 @@ func (s *DescribeSpotFleetRequestsInput) SetSpotFleetRequestIds(v []*string) *De } // Contains the output of DescribeSpotFleetRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestsResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotFleetRequestsResponse type DescribeSpotFleetRequestsOutput struct { _ struct{} `type:"structure"` @@ -35192,7 +39753,7 @@ type DescribeSpotFleetRequestsOutput struct { // when there are no more results to return. NextToken *string `locationName:"nextToken" type:"string"` - // Information about the configuration of your Spot fleet. + // Information about the configuration of your Spot Fleet. // // SpotFleetRequestConfigs is a required field SpotFleetRequestConfigs []*SpotFleetRequestConfig `locationName:"spotFleetRequestConfigSet" locationNameList:"item" type:"list" required:"true"` @@ -35221,7 +39782,7 @@ func (s *DescribeSpotFleetRequestsOutput) SetSpotFleetRequestConfigs(v []*SpotFl } // Contains the parameters for DescribeSpotInstanceRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequestsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequestsRequest type DescribeSpotInstanceRequestsInput struct { _ struct{} `type:"structure"` @@ -35235,7 +39796,7 @@ type DescribeSpotInstanceRequestsInput struct { // // * availability-zone-group - The Availability Zone group. // - // * create-time - The time stamp when the Spot instance request was created. + // * create-time - The time stamp when the Spot Instance request was created. // // * fault-code - The fault code related to the request. // @@ -35243,23 +39804,23 @@ type DescribeSpotInstanceRequestsInput struct { // // * instance-id - The ID of the instance that fulfilled the request. // - // * launch-group - The Spot instance launch group. + // * launch-group - The Spot Instance launch group. // // * launch.block-device-mapping.delete-on-termination - Indicates whether - // the Amazon EBS volume is deleted on instance termination. + // the EBS volume is deleted on instance termination. // - // * launch.block-device-mapping.device-name - The device name for the Amazon - // EBS volume (for example, /dev/sdh). + // * launch.block-device-mapping.device-name - The device name for the volume + // in the block device mapping (for example, /dev/sdh or xvdh). // - // * launch.block-device-mapping.snapshot-id - The ID of the snapshot used - // for the Amazon EBS volume. + // * launch.block-device-mapping.snapshot-id - The ID of the snapshot for + // the EBS volume. // - // * launch.block-device-mapping.volume-size - The size of the Amazon EBS - // volume, in GiB. + // * launch.block-device-mapping.volume-size - The size of the EBS volume, + // in GiB. // - // * launch.block-device-mapping.volume-type - The type of the Amazon EBS - // volume: gp2 for General Purpose SSD, io1 for Provisioned IOPS SSD, st1 - // for Throughput Optimized HDD, sc1for Cold HDD, or standard for Magnetic. + // * launch.block-device-mapping.volume-type - The type of EBS volume: gp2 + // for General Purpose SSD, io1 for Provisioned IOPS SSD, st1 for Throughput + // Optimized HDD, sc1for Cold HDD, or standard for Magnetic. // // * launch.group-id - The security group for the instance. // @@ -35271,53 +39832,53 @@ type DescribeSpotInstanceRequestsInput struct { // // * launch.key-name - The name of the key pair the instance launched with. // - // * launch.monitoring-enabled - Whether monitoring is enabled for the Spot - // instance. + // * launch.monitoring-enabled - Whether detailed monitoring is enabled for + // the Spot Instance. // // * launch.ramdisk-id - The RAM disk ID. // - // * network-interface.network-interface-id - The ID of the network interface. - // - // * network-interface.device-index - The index of the device for the network - // interface attachment on the instance. - // - // * network-interface.subnet-id - The ID of the subnet for the instance. - // - // * network-interface.description - A description of the network interface. - // - // * network-interface.private-ip-address - The primary private IP address - // of the network interface. - // - // * network-interface.delete-on-termination - Indicates whether the network - // interface is deleted when the instance is terminated. - // - // * network-interface.group-id - The ID of the security group associated - // with the network interface. - // - // * network-interface.group-name - The name of the security group associated - // with the network interface. + // * launched-availability-zone - The Availability Zone in which the request + // is launched. // // * network-interface.addresses.primary - Indicates whether the IP address // is the primary private IP address. // + // * network-interface.delete-on-termination - Indicates whether the network + // interface is deleted when the instance is terminated. + // + // * network-interface.description - A description of the network interface. + // + // * network-interface.device-index - The index of the device for the network + // interface attachment on the instance. + // + // * network-interface.group-id - The ID of the security group associated + // with the network interface. + // + // * network-interface.network-interface-id - The ID of the network interface. + // + // * network-interface.private-ip-address - The primary private IP address + // of the network interface. + // + // * network-interface.subnet-id - The ID of the subnet for the instance. + // // * product-description - The product description associated with the instance // (Linux/UNIX | Windows). // - // * spot-instance-request-id - The Spot instance request ID. + // * spot-instance-request-id - The Spot Instance request ID. // - // * spot-price - The maximum hourly price for any Spot instance launched + // * spot-price - The maximum hourly price for any Spot Instance launched // to fulfill the request. // - // * state - The state of the Spot instance request (open | active | closed - // | cancelled | failed). Spot bid status information can help you track - // your Amazon EC2 Spot instance requests. For more information, see Spot - // Bid Status (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html) + // * state - The state of the Spot Instance request (open | active | closed + // | cancelled | failed). Spot request status information can help you track + // your Amazon EC2 Spot Instance requests. For more information, see Spot + // Request Status (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html) // in the Amazon Elastic Compute Cloud User Guide. // // * status-code - The short code describing the most recent evaluation of - // your Spot instance request. + // your Spot Instance request. // - // * status-message - The message explaining the status of the Spot instance + // * status-message - The message explaining the status of the Spot Instance // request. // // * tag:key=value - The key/value combination of a tag assigned to the resource. @@ -35336,17 +39897,14 @@ type DescribeSpotInstanceRequestsInput struct { // * tag-value - The value of a tag assigned to the resource. This filter // is independent of the tag-key filter. // - // * type - The type of Spot instance request (one-time | persistent). - // - // * launched-availability-zone - The Availability Zone in which the bid - // is launched. + // * type - The type of Spot Instance request (one-time | persistent). // // * valid-from - The start date of the request. // // * valid-until - The end date of the request. Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` - // One or more Spot instance request IDs. + // One or more Spot Instance request IDs. SpotInstanceRequestIds []*string `locationName:"SpotInstanceRequestId" locationNameList:"SpotInstanceRequestId" type:"list"` } @@ -35379,11 +39937,11 @@ func (s *DescribeSpotInstanceRequestsInput) SetSpotInstanceRequestIds(v []*strin } // Contains the output of DescribeSpotInstanceRequests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequestsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotInstanceRequestsResult type DescribeSpotInstanceRequestsOutput struct { _ struct{} `type:"structure"` - // One or more Spot instance requests. + // One or more Spot Instance requests. SpotInstanceRequests []*SpotInstanceRequest `locationName:"spotInstanceRequestSet" locationNameList:"item" type:"list"` } @@ -35404,7 +39962,7 @@ func (s *DescribeSpotInstanceRequestsOutput) SetSpotInstanceRequests(v []*SpotIn } // Contains the parameters for DescribeSpotPriceHistory. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistoryRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistoryRequest type DescribeSpotPriceHistoryInput struct { _ struct{} `type:"structure"` @@ -35440,8 +39998,7 @@ type DescribeSpotPriceHistoryInput struct { // than or less than comparison is not supported. Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` - // Filters the results by the specified instance types. Note that T2 and HS1 - // instance types are not supported. + // Filters the results by the specified instance types. InstanceTypes []*string `locationName:"InstanceType" type:"list"` // The maximum number of results to return in a single call. Specify a value @@ -35525,7 +40082,7 @@ func (s *DescribeSpotPriceHistoryInput) SetStartTime(v time.Time) *DescribeSpotP } // Contains the output of DescribeSpotPriceHistory. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistoryResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSpotPriceHistoryResult type DescribeSpotPriceHistoryOutput struct { _ struct{} `type:"structure"` @@ -35559,7 +40116,7 @@ func (s *DescribeSpotPriceHistoryOutput) SetSpotPriceHistory(v []*SpotPrice) *De return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroupsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroupsRequest type DescribeStaleSecurityGroupsInput struct { _ struct{} `type:"structure"` @@ -35637,7 +40194,7 @@ func (s *DescribeStaleSecurityGroupsInput) SetVpcId(v string) *DescribeStaleSecu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroupsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeStaleSecurityGroupsResult type DescribeStaleSecurityGroupsOutput struct { _ struct{} `type:"structure"` @@ -35672,7 +40229,7 @@ func (s *DescribeStaleSecurityGroupsOutput) SetStaleSecurityGroupSet(v []*StaleS } // Contains the parameters for DescribeSubnets. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnetsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnetsRequest type DescribeSubnetsInput struct { _ struct{} `type:"structure"` @@ -35764,7 +40321,7 @@ func (s *DescribeSubnetsInput) SetSubnetIds(v []*string) *DescribeSubnetsInput { } // Contains the output of DescribeSubnets. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnetsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeSubnetsResult type DescribeSubnetsOutput struct { _ struct{} `type:"structure"` @@ -35789,7 +40346,7 @@ func (s *DescribeSubnetsOutput) SetSubnets(v []*Subnet) *DescribeSubnetsOutput { } // Contains the parameters for DescribeTags. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTagsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTagsRequest type DescribeTagsInput struct { _ struct{} `type:"structure"` @@ -35806,9 +40363,10 @@ type DescribeTagsInput struct { // * resource-id - The resource ID. // // * resource-type - The resource type (customer-gateway | dhcp-options | - // image | instance | internet-gateway | network-acl | network-interface - // | reserved-instances | route-table | security-group | snapshot | spot-instances-request - // | subnet | volume | vpc | vpn-connection | vpn-gateway). + // elastic-ip | fpga-image | image | instance | internet-gateway | launch-template + // | natgateway | network-acl | network-interface | reserved-instances | + // route-table | security-group | snapshot | spot-instances-request | subnet + // | volume | vpc | vpc-peering-connection | vpn-connection | vpn-gateway). // // * value - The tag value. Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` @@ -35857,7 +40415,7 @@ func (s *DescribeTagsInput) SetNextToken(v string) *DescribeTagsInput { } // Contains the output of DescribeTags. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTagsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeTagsResult type DescribeTagsOutput struct { _ struct{} `type:"structure"` @@ -35892,7 +40450,7 @@ func (s *DescribeTagsOutput) SetTags(v []*TagDescription) *DescribeTagsOutput { } // Contains the parameters for DescribeVolumeAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttributeRequest type DescribeVolumeAttributeInput struct { _ struct{} `type:"structure"` @@ -35953,7 +40511,7 @@ func (s *DescribeVolumeAttributeInput) SetVolumeId(v string) *DescribeVolumeAttr } // Contains the output of DescribeVolumeAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttributeResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeAttributeResult type DescribeVolumeAttributeOutput struct { _ struct{} `type:"structure"` @@ -35996,7 +40554,7 @@ func (s *DescribeVolumeAttributeOutput) SetVolumeId(v string) *DescribeVolumeAtt } // Contains the parameters for DescribeVolumeStatus. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatusRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatusRequest type DescribeVolumeStatusInput struct { _ struct{} `type:"structure"` @@ -36102,7 +40660,7 @@ func (s *DescribeVolumeStatusInput) SetVolumeIds(v []*string) *DescribeVolumeSta } // Contains the output of DescribeVolumeStatus. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatusResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumeStatusResult type DescribeVolumeStatusOutput struct { _ struct{} `type:"structure"` @@ -36137,7 +40695,7 @@ func (s *DescribeVolumeStatusOutput) SetVolumeStatuses(v []*VolumeStatusItem) *D } // Contains the parameters for DescribeVolumes. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesRequest type DescribeVolumesInput struct { _ struct{} `type:"structure"` @@ -36154,7 +40712,7 @@ type DescribeVolumesInput struct { // * attachment.delete-on-termination - Whether the volume is deleted on // instance termination. // - // * attachment.device - The device name that is exposed to the instance + // * attachment.device - The device name specified in the block device mapping // (for example, /dev/sda1). // // * attachment.instance-id - The ID of the instance the volume is attached @@ -36260,7 +40818,7 @@ func (s *DescribeVolumesInput) SetVolumeIds(v []*string) *DescribeVolumesInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModificationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModificationsRequest type DescribeVolumesModificationsInput struct { _ struct{} `type:"structure"` @@ -36326,7 +40884,7 @@ func (s *DescribeVolumesModificationsInput) SetVolumeIds(v []*string) *DescribeV return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModificationsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesModificationsResult type DescribeVolumesModificationsOutput struct { _ struct{} `type:"structure"` @@ -36360,7 +40918,7 @@ func (s *DescribeVolumesModificationsOutput) SetVolumesModifications(v []*Volume } // Contains the output of DescribeVolumes. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVolumesResult type DescribeVolumesOutput struct { _ struct{} `type:"structure"` @@ -36397,7 +40955,7 @@ func (s *DescribeVolumesOutput) SetVolumes(v []*Volume) *DescribeVolumesOutput { } // Contains the parameters for DescribeVpcAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttributeRequest type DescribeVpcAttributeInput struct { _ struct{} `type:"structure"` @@ -36463,7 +41021,7 @@ func (s *DescribeVpcAttributeInput) SetVpcId(v string) *DescribeVpcAttributeInpu } // Contains the output of DescribeVpcAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttributeResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcAttributeResult type DescribeVpcAttributeOutput struct { _ struct{} `type:"structure"` @@ -36510,7 +41068,7 @@ func (s *DescribeVpcAttributeOutput) SetVpcId(v string) *DescribeVpcAttributeOut } // Contains the parameters for DescribeVpcClassicLinkDnsSupport. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupportRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupportRequest type DescribeVpcClassicLinkDnsSupportInput struct { _ struct{} `type:"structure"` @@ -36572,7 +41130,7 @@ func (s *DescribeVpcClassicLinkDnsSupportInput) SetVpcIds(v []*string) *Describe } // Contains the output of DescribeVpcClassicLinkDnsSupport. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupportResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkDnsSupportResult type DescribeVpcClassicLinkDnsSupportOutput struct { _ struct{} `type:"structure"` @@ -36606,7 +41164,7 @@ func (s *DescribeVpcClassicLinkDnsSupportOutput) SetVpcs(v []*ClassicLinkDnsSupp } // Contains the parameters for DescribeVpcClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkRequest type DescribeVpcClassicLinkInput struct { _ struct{} `type:"structure"` @@ -36671,7 +41229,7 @@ func (s *DescribeVpcClassicLinkInput) SetVpcIds(v []*string) *DescribeVpcClassic } // Contains the output of DescribeVpcClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcClassicLinkResult type DescribeVpcClassicLinkOutput struct { _ struct{} `type:"structure"` @@ -36695,8 +41253,449 @@ func (s *DescribeVpcClassicLinkOutput) SetVpcs(v []*VpcClassicLink) *DescribeVpc return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnectionNotificationsRequest +type DescribeVpcEndpointConnectionNotificationsInput struct { + _ struct{} `type:"structure"` + + // The ID of the notification. + ConnectionNotificationId *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * connection-notification-arn - The ARN of SNS topic for the notification. + // + // * connection-notification-id - The ID of the notification. + // + // * connection-notification-state - The state of the notification (Enabled + // | Disabled). + // + // * connection-notification-type - The type of notification (Topic). + // + // * service-id - The ID of the endpoint service. + // + // * vpc-endpoint-id - The ID of the VPC endpoint. + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // The maximum number of results to return in a single call. To retrieve the + // remaining results, make another request with the returned NextToken value. + MaxResults *int64 `type:"integer"` + + // The token to request the next page of results. + NextToken *string `type:"string"` +} + +// String returns the string representation +func (s DescribeVpcEndpointConnectionNotificationsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointConnectionNotificationsInput) GoString() string { + return s.String() +} + +// SetConnectionNotificationId sets the ConnectionNotificationId field's value. +func (s *DescribeVpcEndpointConnectionNotificationsInput) SetConnectionNotificationId(v string) *DescribeVpcEndpointConnectionNotificationsInput { + s.ConnectionNotificationId = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeVpcEndpointConnectionNotificationsInput) SetDryRun(v bool) *DescribeVpcEndpointConnectionNotificationsInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeVpcEndpointConnectionNotificationsInput) SetFilters(v []*Filter) *DescribeVpcEndpointConnectionNotificationsInput { + s.Filters = v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeVpcEndpointConnectionNotificationsInput) SetMaxResults(v int64) *DescribeVpcEndpointConnectionNotificationsInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointConnectionNotificationsInput) SetNextToken(v string) *DescribeVpcEndpointConnectionNotificationsInput { + s.NextToken = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnectionNotificationsResult +type DescribeVpcEndpointConnectionNotificationsOutput struct { + _ struct{} `type:"structure"` + + // One or more notifications. + ConnectionNotificationSet []*ConnectionNotification `locationName:"connectionNotificationSet" locationNameList:"item" type:"list"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` +} + +// String returns the string representation +func (s DescribeVpcEndpointConnectionNotificationsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointConnectionNotificationsOutput) GoString() string { + return s.String() +} + +// SetConnectionNotificationSet sets the ConnectionNotificationSet field's value. +func (s *DescribeVpcEndpointConnectionNotificationsOutput) SetConnectionNotificationSet(v []*ConnectionNotification) *DescribeVpcEndpointConnectionNotificationsOutput { + s.ConnectionNotificationSet = v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointConnectionNotificationsOutput) SetNextToken(v string) *DescribeVpcEndpointConnectionNotificationsOutput { + s.NextToken = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnectionsRequest +type DescribeVpcEndpointConnectionsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * service-id - The ID of the service. + // + // * vpc-endpoint-owner - The AWS account number of the owner of the endpoint. + // + // * vpc-endpoint-state - The state of the endpoint (pendingAcceptance | + // pending | available | deleting | deleted | rejected | failed). + // + // * vpc-endpoint-id - The ID of the endpoint. + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // The maximum number of results to return for the request in a single page. + // The remaining results of the initial request can be seen by sending another + // request with the returned NextToken value. This value can be between 5 and + // 1000; if MaxResults is given a value larger than 1000, only 1000 results + // are returned. + MaxResults *int64 `type:"integer"` + + // The token to retrieve the next page of results. + NextToken *string `type:"string"` +} + +// String returns the string representation +func (s DescribeVpcEndpointConnectionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointConnectionsInput) GoString() string { + return s.String() +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeVpcEndpointConnectionsInput) SetDryRun(v bool) *DescribeVpcEndpointConnectionsInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeVpcEndpointConnectionsInput) SetFilters(v []*Filter) *DescribeVpcEndpointConnectionsInput { + s.Filters = v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeVpcEndpointConnectionsInput) SetMaxResults(v int64) *DescribeVpcEndpointConnectionsInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointConnectionsInput) SetNextToken(v string) *DescribeVpcEndpointConnectionsInput { + s.NextToken = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointConnectionsResult +type DescribeVpcEndpointConnectionsOutput struct { + _ struct{} `type:"structure"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` + + // Information about one or more VPC endpoint connections. + VpcEndpointConnections []*VpcEndpointConnection `locationName:"vpcEndpointConnectionSet" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DescribeVpcEndpointConnectionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointConnectionsOutput) GoString() string { + return s.String() +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointConnectionsOutput) SetNextToken(v string) *DescribeVpcEndpointConnectionsOutput { + s.NextToken = &v + return s +} + +// SetVpcEndpointConnections sets the VpcEndpointConnections field's value. +func (s *DescribeVpcEndpointConnectionsOutput) SetVpcEndpointConnections(v []*VpcEndpointConnection) *DescribeVpcEndpointConnectionsOutput { + s.VpcEndpointConnections = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServiceConfigurationsRequest +type DescribeVpcEndpointServiceConfigurationsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * service-name - The name of the service. + // + // * service-id - The ID of the service. + // + // * service-state - The state of the service (Pending | Available | Deleting + // | Deleted | Failed). + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // The maximum number of results to return for the request in a single page. + // The remaining results of the initial request can be seen by sending another + // request with the returned NextToken value. This value can be between 5 and + // 1000; if MaxResults is given a value larger than 1000, only 1000 results + // are returned. + MaxResults *int64 `type:"integer"` + + // The token to retrieve the next page of results. + NextToken *string `type:"string"` + + // The IDs of one or more services. + ServiceIds []*string `locationName:"ServiceId" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DescribeVpcEndpointServiceConfigurationsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointServiceConfigurationsInput) GoString() string { + return s.String() +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeVpcEndpointServiceConfigurationsInput) SetDryRun(v bool) *DescribeVpcEndpointServiceConfigurationsInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeVpcEndpointServiceConfigurationsInput) SetFilters(v []*Filter) *DescribeVpcEndpointServiceConfigurationsInput { + s.Filters = v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeVpcEndpointServiceConfigurationsInput) SetMaxResults(v int64) *DescribeVpcEndpointServiceConfigurationsInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointServiceConfigurationsInput) SetNextToken(v string) *DescribeVpcEndpointServiceConfigurationsInput { + s.NextToken = &v + return s +} + +// SetServiceIds sets the ServiceIds field's value. +func (s *DescribeVpcEndpointServiceConfigurationsInput) SetServiceIds(v []*string) *DescribeVpcEndpointServiceConfigurationsInput { + s.ServiceIds = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServiceConfigurationsResult +type DescribeVpcEndpointServiceConfigurationsOutput struct { + _ struct{} `type:"structure"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` + + // Information about one or more services. + ServiceConfigurations []*ServiceConfiguration `locationName:"serviceConfigurationSet" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s DescribeVpcEndpointServiceConfigurationsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointServiceConfigurationsOutput) GoString() string { + return s.String() +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointServiceConfigurationsOutput) SetNextToken(v string) *DescribeVpcEndpointServiceConfigurationsOutput { + s.NextToken = &v + return s +} + +// SetServiceConfigurations sets the ServiceConfigurations field's value. +func (s *DescribeVpcEndpointServiceConfigurationsOutput) SetServiceConfigurations(v []*ServiceConfiguration) *DescribeVpcEndpointServiceConfigurationsOutput { + s.ServiceConfigurations = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicePermissionsRequest +type DescribeVpcEndpointServicePermissionsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more filters. + // + // * principal - The ARN of the principal. + // + // * principal-type - The principal type (All | Service | OrganizationUnit + // | Account | User | Role). + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + + // The maximum number of results to return for the request in a single page. + // The remaining results of the initial request can be seen by sending another + // request with the returned NextToken value. This value can be between 5 and + // 1000; if MaxResults is given a value larger than 1000, only 1000 results + // are returned. + MaxResults *int64 `type:"integer"` + + // The token to retrieve the next page of results. + NextToken *string `type:"string"` + + // The ID of the service. + // + // ServiceId is a required field + ServiceId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s DescribeVpcEndpointServicePermissionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointServicePermissionsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DescribeVpcEndpointServicePermissionsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DescribeVpcEndpointServicePermissionsInput"} + if s.ServiceId == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *DescribeVpcEndpointServicePermissionsInput) SetDryRun(v bool) *DescribeVpcEndpointServicePermissionsInput { + s.DryRun = &v + return s +} + +// SetFilters sets the Filters field's value. +func (s *DescribeVpcEndpointServicePermissionsInput) SetFilters(v []*Filter) *DescribeVpcEndpointServicePermissionsInput { + s.Filters = v + return s +} + +// SetMaxResults sets the MaxResults field's value. +func (s *DescribeVpcEndpointServicePermissionsInput) SetMaxResults(v int64) *DescribeVpcEndpointServicePermissionsInput { + s.MaxResults = &v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointServicePermissionsInput) SetNextToken(v string) *DescribeVpcEndpointServicePermissionsInput { + s.NextToken = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *DescribeVpcEndpointServicePermissionsInput) SetServiceId(v string) *DescribeVpcEndpointServicePermissionsInput { + s.ServiceId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicePermissionsResult +type DescribeVpcEndpointServicePermissionsOutput struct { + _ struct{} `type:"structure"` + + // Information about one or more allowed principals. + AllowedPrincipals []*AllowedPrincipal `locationName:"allowedPrincipals" locationNameList:"item" type:"list"` + + // The token to use to retrieve the next page of results. This value is null + // when there are no more results to return. + NextToken *string `locationName:"nextToken" type:"string"` +} + +// String returns the string representation +func (s DescribeVpcEndpointServicePermissionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeVpcEndpointServicePermissionsOutput) GoString() string { + return s.String() +} + +// SetAllowedPrincipals sets the AllowedPrincipals field's value. +func (s *DescribeVpcEndpointServicePermissionsOutput) SetAllowedPrincipals(v []*AllowedPrincipal) *DescribeVpcEndpointServicePermissionsOutput { + s.AllowedPrincipals = v + return s +} + +// SetNextToken sets the NextToken field's value. +func (s *DescribeVpcEndpointServicePermissionsOutput) SetNextToken(v string) *DescribeVpcEndpointServicePermissionsOutput { + s.NextToken = &v + return s +} + // Contains the parameters for DescribeVpcEndpointServices. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicesRequest type DescribeVpcEndpointServicesInput struct { _ struct{} `type:"structure"` @@ -36706,6 +41705,11 @@ type DescribeVpcEndpointServicesInput struct { // it is UnauthorizedOperation. DryRun *bool `type:"boolean"` + // One or more filters. + // + // * service-name: The name of the service. + Filters []*Filter `locationName:"Filter" locationNameList:"Filter" type:"list"` + // The maximum number of items to return for this request. The request returns // a token that you can specify in a subsequent call to get the next set of // results. @@ -36716,6 +41720,9 @@ type DescribeVpcEndpointServicesInput struct { // The token for the next set of items to return. (You received this token from // a prior call.) NextToken *string `type:"string"` + + // One or more service names. + ServiceNames []*string `locationName:"ServiceName" locationNameList:"item" type:"list"` } // String returns the string representation @@ -36734,6 +41741,12 @@ func (s *DescribeVpcEndpointServicesInput) SetDryRun(v bool) *DescribeVpcEndpoin return s } +// SetFilters sets the Filters field's value. +func (s *DescribeVpcEndpointServicesInput) SetFilters(v []*Filter) *DescribeVpcEndpointServicesInput { + s.Filters = v + return s +} + // SetMaxResults sets the MaxResults field's value. func (s *DescribeVpcEndpointServicesInput) SetMaxResults(v int64) *DescribeVpcEndpointServicesInput { s.MaxResults = &v @@ -36746,8 +41759,14 @@ func (s *DescribeVpcEndpointServicesInput) SetNextToken(v string) *DescribeVpcEn return s } +// SetServiceNames sets the ServiceNames field's value. +func (s *DescribeVpcEndpointServicesInput) SetServiceNames(v []*string) *DescribeVpcEndpointServicesInput { + s.ServiceNames = v + return s +} + // Contains the output of DescribeVpcEndpointServices. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointServicesResult type DescribeVpcEndpointServicesOutput struct { _ struct{} `type:"structure"` @@ -36755,7 +41774,10 @@ type DescribeVpcEndpointServicesOutput struct { // items to return, the string is empty. NextToken *string `locationName:"nextToken" type:"string"` - // A list of supported AWS services. + // Information about the service. + ServiceDetails []*ServiceDetail `locationName:"serviceDetailSet" locationNameList:"item" type:"list"` + + // A list of supported services. ServiceNames []*string `locationName:"serviceNameSet" locationNameList:"item" type:"list"` } @@ -36775,6 +41797,12 @@ func (s *DescribeVpcEndpointServicesOutput) SetNextToken(v string) *DescribeVpcE return s } +// SetServiceDetails sets the ServiceDetails field's value. +func (s *DescribeVpcEndpointServicesOutput) SetServiceDetails(v []*ServiceDetail) *DescribeVpcEndpointServicesOutput { + s.ServiceDetails = v + return s +} + // SetServiceNames sets the ServiceNames field's value. func (s *DescribeVpcEndpointServicesOutput) SetServiceNames(v []*string) *DescribeVpcEndpointServicesOutput { s.ServiceNames = v @@ -36782,7 +41810,7 @@ func (s *DescribeVpcEndpointServicesOutput) SetServiceNames(v []*string) *Descri } // Contains the parameters for DescribeVpcEndpoints. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointsRequest type DescribeVpcEndpointsInput struct { _ struct{} `type:"structure"` @@ -36794,7 +41822,7 @@ type DescribeVpcEndpointsInput struct { // One or more filters. // - // * service-name: The name of the AWS service. + // * service-name: The name of the service. // // * vpc-id: The ID of the VPC in which the endpoint resides. // @@ -36860,7 +41888,7 @@ func (s *DescribeVpcEndpointsInput) SetVpcEndpointIds(v []*string) *DescribeVpcE } // Contains the output of DescribeVpcEndpoints. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcEndpointsResult type DescribeVpcEndpointsOutput struct { _ struct{} `type:"structure"` @@ -36895,7 +41923,7 @@ func (s *DescribeVpcEndpointsOutput) SetVpcEndpoints(v []*VpcEndpoint) *Describe } // Contains the parameters for DescribeVpcPeeringConnections. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnectionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnectionsRequest type DescribeVpcPeeringConnectionsInput struct { _ struct{} `type:"structure"` @@ -36907,12 +41935,12 @@ type DescribeVpcPeeringConnectionsInput struct { // One or more filters. // - // * accepter-vpc-info.cidr-block - The IPv4 CIDR block of the peer VPC. + // * accepter-vpc-info.cidr-block - The IPv4 CIDR block of the accepter VPC. // // * accepter-vpc-info.owner-id - The AWS account ID of the owner of the - // peer VPC. + // accepter VPC. // - // * accepter-vpc-info.vpc-id - The ID of the peer VPC. + // * accepter-vpc-info.vpc-id - The ID of the accepter VPC. // // * expiration-time - The expiration date and time for the VPC peering connection. // @@ -36925,7 +41953,7 @@ type DescribeVpcPeeringConnectionsInput struct { // * requester-vpc-info.vpc-id - The ID of the requester VPC. // // * status-code - The status of the VPC peering connection (pending-acceptance - // | failed | expired | provisioning | active | deleted | rejected). + // | failed | expired | provisioning | active | deleting | deleted | rejected). // // * status-message - A message that provides more information about the // status of the VPC peering connection, if applicable. @@ -36984,7 +42012,7 @@ func (s *DescribeVpcPeeringConnectionsInput) SetVpcPeeringConnectionIds(v []*str } // Contains the output of DescribeVpcPeeringConnections. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnectionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcPeeringConnectionsResult type DescribeVpcPeeringConnectionsOutput struct { _ struct{} `type:"structure"` @@ -37009,7 +42037,7 @@ func (s *DescribeVpcPeeringConnectionsOutput) SetVpcPeeringConnections(v []*VpcP } // Contains the parameters for DescribeVpcs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcsRequest type DescribeVpcsInput struct { _ struct{} `type:"structure"` @@ -37021,10 +42049,19 @@ type DescribeVpcsInput struct { // One or more filters. // - // * cidr - The IPv4 CIDR block of the VPC. The CIDR block you specify must - // exactly match the VPC's CIDR block for information to be returned for - // the VPC. Must contain the slash followed by one or two digits (for example, - // /28). + // * cidr - The primary IPv4 CIDR block of the VPC. The CIDR block you specify + // must exactly match the VPC's CIDR block for information to be returned + // for the VPC. Must contain the slash followed by one or two digits (for + // example, /28). + // + // * cidr-block-association.cidr-block - An IPv4 CIDR block associated with + // the VPC. + // + // * cidr-block-association.association-id - The association ID for an IPv4 + // CIDR block associated with the VPC. + // + // * cidr-block-association.state - The state of an IPv4 CIDR block associated + // with the VPC. // // * dhcp-options-id - The ID of a set of DHCP options. // @@ -37095,7 +42132,7 @@ func (s *DescribeVpcsInput) SetVpcIds(v []*string) *DescribeVpcsInput { } // Contains the output of DescribeVpcs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpcsResult type DescribeVpcsOutput struct { _ struct{} `type:"structure"` @@ -37120,7 +42157,7 @@ func (s *DescribeVpcsOutput) SetVpcs(v []*Vpc) *DescribeVpcsOutput { } // Contains the parameters for DescribeVpnConnections. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnectionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnectionsRequest type DescribeVpnConnectionsInput struct { _ struct{} `type:"structure"` @@ -37211,7 +42248,7 @@ func (s *DescribeVpnConnectionsInput) SetVpnConnectionIds(v []*string) *Describe } // Contains the output of DescribeVpnConnections. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnectionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnConnectionsResult type DescribeVpnConnectionsOutput struct { _ struct{} `type:"structure"` @@ -37236,7 +42273,7 @@ func (s *DescribeVpnConnectionsOutput) SetVpnConnections(v []*VpnConnection) *De } // Contains the parameters for DescribeVpnGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGatewaysRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGatewaysRequest type DescribeVpnGatewaysInput struct { _ struct{} `type:"structure"` @@ -37248,6 +42285,9 @@ type DescribeVpnGatewaysInput struct { // One or more filters. // + // * amazon-side-asn - The Autonomous System Number (ASN) for the Amazon + // side of the gateway. + // // * attachment.state - The current state of the attachment between the gateway // and the VPC (attaching | attached | detaching | detached). // @@ -37316,7 +42356,7 @@ func (s *DescribeVpnGatewaysInput) SetVpnGatewayIds(v []*string) *DescribeVpnGat } // Contains the output of DescribeVpnGateways. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGatewaysResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DescribeVpnGatewaysResult type DescribeVpnGatewaysOutput struct { _ struct{} `type:"structure"` @@ -37341,7 +42381,7 @@ func (s *DescribeVpnGatewaysOutput) SetVpnGateways(v []*VpnGateway) *DescribeVpn } // Contains the parameters for DetachClassicLinkVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpcRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpcRequest type DetachClassicLinkVpcInput struct { _ struct{} `type:"structure"` @@ -37407,7 +42447,7 @@ func (s *DetachClassicLinkVpcInput) SetVpcId(v string) *DetachClassicLinkVpcInpu } // Contains the output of DetachClassicLinkVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpcResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachClassicLinkVpcResult type DetachClassicLinkVpcOutput struct { _ struct{} `type:"structure"` @@ -37432,7 +42472,7 @@ func (s *DetachClassicLinkVpcOutput) SetReturn(v bool) *DetachClassicLinkVpcOutp } // Contains the parameters for DetachInternetGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGatewayRequest type DetachInternetGatewayInput struct { _ struct{} `type:"structure"` @@ -37497,7 +42537,7 @@ func (s *DetachInternetGatewayInput) SetVpcId(v string) *DetachInternetGatewayIn return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGatewayOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachInternetGatewayOutput type DetachInternetGatewayOutput struct { _ struct{} `type:"structure"` } @@ -37513,7 +42553,7 @@ func (s DetachInternetGatewayOutput) GoString() string { } // Contains the parameters for DetachNetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterfaceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterfaceRequest type DetachNetworkInterfaceInput struct { _ struct{} `type:"structure"` @@ -37573,7 +42613,7 @@ func (s *DetachNetworkInterfaceInput) SetForce(v bool) *DetachNetworkInterfaceIn return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterfaceOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachNetworkInterfaceOutput type DetachNetworkInterfaceOutput struct { _ struct{} `type:"structure"` } @@ -37589,7 +42629,7 @@ func (s DetachNetworkInterfaceOutput) GoString() string { } // Contains the parameters for DetachVolume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVolumeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVolumeRequest type DetachVolumeInput struct { _ struct{} `type:"structure"` @@ -37674,7 +42714,7 @@ func (s *DetachVolumeInput) SetVolumeId(v string) *DetachVolumeInput { } // Contains the parameters for DetachVpnGateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGatewayRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGatewayRequest type DetachVpnGatewayInput struct { _ struct{} `type:"structure"` @@ -37739,7 +42779,7 @@ func (s *DetachVpnGatewayInput) SetVpnGatewayId(v string) *DetachVpnGatewayInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGatewayOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DetachVpnGatewayOutput type DetachVpnGatewayOutput struct { _ struct{} `type:"structure"` } @@ -37755,7 +42795,7 @@ func (s DetachVpnGatewayOutput) GoString() string { } // Describes a DHCP configuration option. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DhcpConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DhcpConfiguration type DhcpConfiguration struct { _ struct{} `type:"structure"` @@ -37789,7 +42829,7 @@ func (s *DhcpConfiguration) SetValues(v []*AttributeValue) *DhcpConfiguration { } // Describes a set of DHCP options. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DhcpOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DhcpOptions type DhcpOptions struct { _ struct{} `type:"structure"` @@ -37832,7 +42872,7 @@ func (s *DhcpOptions) SetTags(v []*Tag) *DhcpOptions { } // Contains the parameters for DisableVgwRoutePropagation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagationRequest type DisableVgwRoutePropagationInput struct { _ struct{} `type:"structure"` @@ -37885,7 +42925,7 @@ func (s *DisableVgwRoutePropagationInput) SetRouteTableId(v string) *DisableVgwR return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVgwRoutePropagationOutput type DisableVgwRoutePropagationOutput struct { _ struct{} `type:"structure"` } @@ -37901,7 +42941,7 @@ func (s DisableVgwRoutePropagationOutput) GoString() string { } // Contains the parameters for DisableVpcClassicLinkDnsSupport. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupportRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupportRequest type DisableVpcClassicLinkDnsSupportInput struct { _ struct{} `type:"structure"` @@ -37926,7 +42966,7 @@ func (s *DisableVpcClassicLinkDnsSupportInput) SetVpcId(v string) *DisableVpcCla } // Contains the output of DisableVpcClassicLinkDnsSupport. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupportResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkDnsSupportResult type DisableVpcClassicLinkDnsSupportOutput struct { _ struct{} `type:"structure"` @@ -37951,7 +42991,7 @@ func (s *DisableVpcClassicLinkDnsSupportOutput) SetReturn(v bool) *DisableVpcCla } // Contains the parameters for DisableVpcClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkRequest type DisableVpcClassicLinkInput struct { _ struct{} `type:"structure"` @@ -38003,7 +43043,7 @@ func (s *DisableVpcClassicLinkInput) SetVpcId(v string) *DisableVpcClassicLinkIn } // Contains the output of DisableVpcClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisableVpcClassicLinkResult type DisableVpcClassicLinkOutput struct { _ struct{} `type:"structure"` @@ -38028,7 +43068,7 @@ func (s *DisableVpcClassicLinkOutput) SetReturn(v bool) *DisableVpcClassicLinkOu } // Contains the parameters for DisassociateAddress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddressRequest type DisassociateAddressInput struct { _ struct{} `type:"structure"` @@ -38073,7 +43113,7 @@ func (s *DisassociateAddressInput) SetPublicIp(v string) *DisassociateAddressInp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddressOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateAddressOutput type DisassociateAddressOutput struct { _ struct{} `type:"structure"` } @@ -38088,7 +43128,7 @@ func (s DisassociateAddressOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfileRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfileRequest type DisassociateIamInstanceProfileInput struct { _ struct{} `type:"structure"` @@ -38127,7 +43167,7 @@ func (s *DisassociateIamInstanceProfileInput) SetAssociationId(v string) *Disass return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfileResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateIamInstanceProfileResult type DisassociateIamInstanceProfileOutput struct { _ struct{} `type:"structure"` @@ -38152,7 +43192,7 @@ func (s *DisassociateIamInstanceProfileOutput) SetIamInstanceProfileAssociation( } // Contains the parameters for DisassociateRouteTable. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTableRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTableRequest type DisassociateRouteTableInput struct { _ struct{} `type:"structure"` @@ -38204,7 +43244,7 @@ func (s *DisassociateRouteTableInput) SetDryRun(v bool) *DisassociateRouteTableI return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTableOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateRouteTableOutput type DisassociateRouteTableOutput struct { _ struct{} `type:"structure"` } @@ -38219,7 +43259,7 @@ func (s DisassociateRouteTableOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlockRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlockRequest type DisassociateSubnetCidrBlockInput struct { _ struct{} `type:"structure"` @@ -38258,7 +43298,7 @@ func (s *DisassociateSubnetCidrBlockInput) SetAssociationId(v string) *Disassoci return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlockResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateSubnetCidrBlockResult type DisassociateSubnetCidrBlockOutput struct { _ struct{} `type:"structure"` @@ -38291,7 +43331,7 @@ func (s *DisassociateSubnetCidrBlockOutput) SetSubnetId(v string) *DisassociateS return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlockRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlockRequest type DisassociateVpcCidrBlockInput struct { _ struct{} `type:"structure"` @@ -38330,10 +43370,13 @@ func (s *DisassociateVpcCidrBlockInput) SetAssociationId(v string) *Disassociate return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlockResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DisassociateVpcCidrBlockResult type DisassociateVpcCidrBlockOutput struct { _ struct{} `type:"structure"` + // Information about the IPv4 CIDR block association. + CidrBlockAssociation *VpcCidrBlockAssociation `locationName:"cidrBlockAssociation" type:"structure"` + // Information about the IPv6 CIDR block association. Ipv6CidrBlockAssociation *VpcIpv6CidrBlockAssociation `locationName:"ipv6CidrBlockAssociation" type:"structure"` @@ -38351,6 +43394,12 @@ func (s DisassociateVpcCidrBlockOutput) GoString() string { return s.String() } +// SetCidrBlockAssociation sets the CidrBlockAssociation field's value. +func (s *DisassociateVpcCidrBlockOutput) SetCidrBlockAssociation(v *VpcCidrBlockAssociation) *DisassociateVpcCidrBlockOutput { + s.CidrBlockAssociation = v + return s +} + // SetIpv6CidrBlockAssociation sets the Ipv6CidrBlockAssociation field's value. func (s *DisassociateVpcCidrBlockOutput) SetIpv6CidrBlockAssociation(v *VpcIpv6CidrBlockAssociation) *DisassociateVpcCidrBlockOutput { s.Ipv6CidrBlockAssociation = v @@ -38364,7 +43413,7 @@ func (s *DisassociateVpcCidrBlockOutput) SetVpcId(v string) *DisassociateVpcCidr } // Describes a disk image. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImage type DiskImage struct { _ struct{} `type:"structure"` @@ -38427,7 +43476,7 @@ func (s *DiskImage) SetVolume(v *VolumeDetail) *DiskImage { } // Describes a disk image. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImageDescription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImageDescription type DiskImageDescription struct { _ struct{} `type:"structure"` @@ -38492,7 +43541,7 @@ func (s *DiskImageDescription) SetSize(v int64) *DiskImageDescription { } // Describes a disk image. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImageDetail +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImageDetail type DiskImageDetail struct { _ struct{} `type:"structure"` @@ -38567,7 +43616,7 @@ func (s *DiskImageDetail) SetImportManifestUrl(v string) *DiskImageDetail { } // Describes a disk image volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImageVolumeDescription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DiskImageVolumeDescription type DiskImageVolumeDescription struct { _ struct{} `type:"structure"` @@ -38602,16 +43651,52 @@ func (s *DiskImageVolumeDescription) SetSize(v int64) *DiskImageVolumeDescriptio return s } +// Describes a DNS entry. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/DnsEntry +type DnsEntry struct { + _ struct{} `type:"structure"` + + // The DNS name. + DnsName *string `locationName:"dnsName" type:"string"` + + // The ID of the private hosted zone. + HostedZoneId *string `locationName:"hostedZoneId" type:"string"` +} + +// String returns the string representation +func (s DnsEntry) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DnsEntry) GoString() string { + return s.String() +} + +// SetDnsName sets the DnsName field's value. +func (s *DnsEntry) SetDnsName(v string) *DnsEntry { + s.DnsName = &v + return s +} + +// SetHostedZoneId sets the HostedZoneId field's value. +func (s *DnsEntry) SetHostedZoneId(v string) *DnsEntry { + s.HostedZoneId = &v + return s +} + // Describes a block device for an EBS volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EbsBlockDevice +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EbsBlockDevice type EbsBlockDevice struct { _ struct{} `type:"structure"` // Indicates whether the EBS volume is deleted on instance termination. DeleteOnTermination *bool `locationName:"deleteOnTermination" type:"boolean"` - // Indicates whether the EBS volume is encrypted. Encrypted Amazon EBS volumes - // may only be attached to instances that support Amazon EBS encryption. + // Indicates whether the EBS volume is encrypted. Encrypted volumes can only + // be attached to instances that support Amazon EBS encryption. If you are creating + // a volume from a snapshot, you can't specify an encryption value. This is + // because only blank volumes can be encrypted on creation. Encrypted *bool `locationName:"encrypted" type:"boolean"` // The number of I/O operations per second (IOPS) that the volume supports. @@ -38629,6 +43714,14 @@ type EbsBlockDevice struct { // it is not used in requests to create gp2, st1, sc1, or standard volumes. Iops *int64 `locationName:"iops" type:"integer"` + // ID for a user-managed CMK under which the EBS volume is encrypted. + // + // Note: This parameter is only supported on BlockDeviceMapping objects called + // by RunInstances (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html), + // RequestSpotFleet (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RequestSpotFleet.html), + // and RequestSpotInstances (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RequestSpotInstances.html). + KmsKeyId *string `type:"string"` + // The ID of the snapshot. SnapshotId *string `locationName:"snapshotId" type:"string"` @@ -38678,6 +43771,12 @@ func (s *EbsBlockDevice) SetIops(v int64) *EbsBlockDevice { return s } +// SetKmsKeyId sets the KmsKeyId field's value. +func (s *EbsBlockDevice) SetKmsKeyId(v string) *EbsBlockDevice { + s.KmsKeyId = &v + return s +} + // SetSnapshotId sets the SnapshotId field's value. func (s *EbsBlockDevice) SetSnapshotId(v string) *EbsBlockDevice { s.SnapshotId = &v @@ -38697,7 +43796,7 @@ func (s *EbsBlockDevice) SetVolumeType(v string) *EbsBlockDevice { } // Describes a parameter used to set up an EBS volume in a block device mapping. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EbsInstanceBlockDevice +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EbsInstanceBlockDevice type EbsInstanceBlockDevice struct { _ struct{} `type:"structure"` @@ -38750,7 +43849,7 @@ func (s *EbsInstanceBlockDevice) SetVolumeId(v string) *EbsInstanceBlockDevice { // Describes information used to set up an EBS volume specified in a block device // mapping. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EbsInstanceBlockDeviceSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EbsInstanceBlockDeviceSpecification type EbsInstanceBlockDeviceSpecification struct { _ struct{} `type:"structure"` @@ -38784,7 +43883,7 @@ func (s *EbsInstanceBlockDeviceSpecification) SetVolumeId(v string) *EbsInstance } // Describes an egress-only Internet gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EgressOnlyInternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EgressOnlyInternetGateway type EgressOnlyInternetGateway struct { _ struct{} `type:"structure"` @@ -38818,7 +43917,7 @@ func (s *EgressOnlyInternetGateway) SetEgressOnlyInternetGatewayId(v string) *Eg } // Describes the association between an instance and an Elastic GPU. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuAssociation type ElasticGpuAssociation struct { _ struct{} `type:"structure"` @@ -38870,7 +43969,7 @@ func (s *ElasticGpuAssociation) SetElasticGpuId(v string) *ElasticGpuAssociation } // Describes the status of an Elastic GPU. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuHealth +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuHealth type ElasticGpuHealth struct { _ struct{} `type:"structure"` @@ -38895,7 +43994,7 @@ func (s *ElasticGpuHealth) SetStatus(v string) *ElasticGpuHealth { } // A specification for an Elastic GPU. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuSpecification type ElasticGpuSpecification struct { _ struct{} `type:"structure"` @@ -38934,8 +44033,33 @@ func (s *ElasticGpuSpecification) SetType(v string) *ElasticGpuSpecification { return s } +// Describes an elastic GPU. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpuSpecificationResponse +type ElasticGpuSpecificationResponse struct { + _ struct{} `type:"structure"` + + // The elastic GPU type. + Type *string `locationName:"type" type:"string"` +} + +// String returns the string representation +func (s ElasticGpuSpecificationResponse) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ElasticGpuSpecificationResponse) GoString() string { + return s.String() +} + +// SetType sets the Type field's value. +func (s *ElasticGpuSpecificationResponse) SetType(v string) *ElasticGpuSpecificationResponse { + s.Type = &v + return s +} + // Describes an Elastic GPU. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ElasticGpus type ElasticGpus struct { _ struct{} `type:"structure"` @@ -39005,7 +44129,7 @@ func (s *ElasticGpus) SetInstanceId(v string) *ElasticGpus { } // Contains the parameters for EnableVgwRoutePropagation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagationRequest type EnableVgwRoutePropagationInput struct { _ struct{} `type:"structure"` @@ -39058,7 +44182,7 @@ func (s *EnableVgwRoutePropagationInput) SetRouteTableId(v string) *EnableVgwRou return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVgwRoutePropagationOutput type EnableVgwRoutePropagationOutput struct { _ struct{} `type:"structure"` } @@ -39074,7 +44198,7 @@ func (s EnableVgwRoutePropagationOutput) GoString() string { } // Contains the parameters for EnableVolumeIO. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIORequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIORequest type EnableVolumeIOInput struct { _ struct{} `type:"structure"` @@ -39125,7 +44249,7 @@ func (s *EnableVolumeIOInput) SetVolumeId(v string) *EnableVolumeIOInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIOOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVolumeIOOutput type EnableVolumeIOOutput struct { _ struct{} `type:"structure"` } @@ -39141,7 +44265,7 @@ func (s EnableVolumeIOOutput) GoString() string { } // Contains the parameters for EnableVpcClassicLinkDnsSupport. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupportRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupportRequest type EnableVpcClassicLinkDnsSupportInput struct { _ struct{} `type:"structure"` @@ -39166,7 +44290,7 @@ func (s *EnableVpcClassicLinkDnsSupportInput) SetVpcId(v string) *EnableVpcClass } // Contains the output of EnableVpcClassicLinkDnsSupport. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupportResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkDnsSupportResult type EnableVpcClassicLinkDnsSupportOutput struct { _ struct{} `type:"structure"` @@ -39191,7 +44315,7 @@ func (s *EnableVpcClassicLinkDnsSupportOutput) SetReturn(v bool) *EnableVpcClass } // Contains the parameters for EnableVpcClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkRequest type EnableVpcClassicLinkInput struct { _ struct{} `type:"structure"` @@ -39243,7 +44367,7 @@ func (s *EnableVpcClassicLinkInput) SetVpcId(v string) *EnableVpcClassicLinkInpu } // Contains the output of EnableVpcClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EnableVpcClassicLinkResult type EnableVpcClassicLinkOutput struct { _ struct{} `type:"structure"` @@ -39267,8 +44391,8 @@ func (s *EnableVpcClassicLinkOutput) SetReturn(v bool) *EnableVpcClassicLinkOutp return s } -// Describes a Spot fleet event. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EventInformation +// Describes a Spot Fleet event. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/EventInformation type EventInformation struct { _ struct{} `type:"structure"` @@ -39277,9 +44401,9 @@ type EventInformation struct { // The event. // - // The following are the error events. + // The following are the error events: // - // * iamFleetRoleInvalid - The Spot fleet did not have the required permissions + // * iamFleetRoleInvalid - The Spot Fleet did not have the required permissions // either to launch or terminate an instance. // // * launchSpecTemporarilyBlacklisted - The configuration is not valid and @@ -39290,43 +44414,52 @@ type EventInformation struct { // For more information, see the description of the event. // // * spotInstanceCountLimitExceeded - You've reached the limit on the number - // of Spot instances that you can launch. + // of Spot Instances that you can launch. // - // The following are the fleetRequestChange events. + // The following are the fleetRequestChange events: // - // * active - The Spot fleet has been validated and Amazon EC2 is attempting - // to maintain the target number of running Spot instances. + // * active - The Spot Fleet has been validated and Amazon EC2 is attempting + // to maintain the target number of running Spot Instances. // - // * cancelled - The Spot fleet is canceled and has no running Spot instances. - // The Spot fleet will be deleted two days after its instances were terminated. + // * cancelled - The Spot Fleet is canceled and has no running Spot Instances. + // The Spot Fleet will be deleted two days after its instances were terminated. // - // * cancelled_running - The Spot fleet is canceled and will not launch additional - // Spot instances, but its existing Spot instances continue to run until + // * cancelled_running - The Spot Fleet is canceled and will not launch additional + // Spot Instances, but its existing Spot Instances continue to run until // they are interrupted or terminated. // - // * cancelled_terminating - The Spot fleet is canceled and its Spot instances + // * cancelled_terminating - The Spot Fleet is canceled and its Spot Instances // are terminating. // - // * expired - The Spot fleet request has expired. A subsequent event indicates + // * expired - The Spot Fleet request has expired. A subsequent event indicates // that the instances were terminated, if the request was created with TerminateInstancesWithExpiration // set. // - // * modify_in_progress - A request to modify the Spot fleet request was + // * modify_in_progress - A request to modify the Spot Fleet request was // accepted and is in progress. // - // * modify_successful - The Spot fleet request was modified. + // * modify_successful - The Spot Fleet request was modified. // - // * price_update - The bid price for a launch configuration was adjusted - // because it was too high. This change is permanent. + // * price_update - The price for a launch configuration was adjusted because + // it was too high. This change is permanent. // - // * submitted - The Spot fleet request is being evaluated and Amazon EC2 - // is preparing to launch the target number of Spot instances. + // * submitted - The Spot Fleet request is being evaluated and Amazon EC2 + // is preparing to launch the target number of Spot Instances. // - // The following are the instanceChange events. + // The following are the instanceChange events: // - // * launched - A bid was fulfilled and a new instance was launched. + // * launched - A request was fulfilled and a new instance was launched. // // * terminated - An instance was terminated by the user. + // + // The following are the Information events: + // + // * launchSpecUnusable - The price in a launch specification is not valid + // because it is below the Spot price or the Spot price is above the On-Demand + // price. + // + // * fleetProgressHalted - The price in every launch specification is not + // valid. A launch specification might become valid if the Spot price changes. EventSubType *string `locationName:"eventSubType" type:"string"` // The ID of the instance. This information is available only for instanceChange @@ -39363,7 +44496,7 @@ func (s *EventInformation) SetInstanceId(v string) *EventInformation { } // Describes an instance export task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ExportTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ExportTask type ExportTask struct { _ struct{} `type:"structure"` @@ -39433,7 +44566,7 @@ func (s *ExportTask) SetStatusMessage(v string) *ExportTask { } // Describes the format and location for an instance export task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ExportToS3Task +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ExportToS3Task type ExportToS3Task struct { _ struct{} `type:"structure"` @@ -39487,7 +44620,7 @@ func (s *ExportToS3Task) SetS3Key(v string) *ExportToS3Task { } // Describes an instance export task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ExportToS3TaskSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ExportToS3TaskSpecification type ExportToS3TaskSpecification struct { _ struct{} `type:"structure"` @@ -39544,7 +44677,7 @@ func (s *ExportToS3TaskSpecification) SetS3Prefix(v string) *ExportToS3TaskSpeci // A filter name and value pair that is used to return a more specific list // of results. Filters can be used to match a set of resources by various criteria, // such as tags, attributes, or IDs. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Filter +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Filter type Filter struct { _ struct{} `type:"structure"` @@ -39577,8 +44710,67 @@ func (s *Filter) SetValues(v []*string) *Filter { return s } +// Describes a launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FleetLaunchTemplateSpecification +type FleetLaunchTemplateSpecification struct { + _ struct{} `type:"structure"` + + // The ID of the launch template. You must specify either a template ID or a + // template name. + LaunchTemplateId *string `locationName:"launchTemplateId" type:"string"` + + // The name of the launch template. You must specify either a template name + // or a template ID. + LaunchTemplateName *string `locationName:"launchTemplateName" min:"3" type:"string"` + + // The version number. By default, the default version of the launch template + // is used. + Version *string `locationName:"version" type:"string"` +} + +// String returns the string representation +func (s FleetLaunchTemplateSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s FleetLaunchTemplateSpecification) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *FleetLaunchTemplateSpecification) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "FleetLaunchTemplateSpecification"} + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *FleetLaunchTemplateSpecification) SetLaunchTemplateId(v string) *FleetLaunchTemplateSpecification { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *FleetLaunchTemplateSpecification) SetLaunchTemplateName(v string) *FleetLaunchTemplateSpecification { + s.LaunchTemplateName = &v + return s +} + +// SetVersion sets the Version field's value. +func (s *FleetLaunchTemplateSpecification) SetVersion(v string) *FleetLaunchTemplateSpecification { + s.Version = &v + return s +} + // Describes a flow log. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FlowLog +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FlowLog type FlowLog struct { _ struct{} `type:"structure"` @@ -39680,7 +44872,7 @@ func (s *FlowLog) SetTrafficType(v string) *FlowLog { } // Describes an Amazon FPGA image (AFI). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FpgaImage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FpgaImage type FpgaImage struct { _ struct{} `type:"structure"` @@ -39711,6 +44903,9 @@ type FpgaImage struct { // The product codes for the AFI. ProductCodes []*ProductCode `locationName:"productCodes" locationNameList:"item" type:"list"` + // Indicates whether the AFI is public. + Public *bool `locationName:"public" type:"boolean"` + // The version of the AWS Shell that was used to create the bitstream. ShellVersion *string `locationName:"shellVersion" type:"string"` @@ -39788,6 +44983,12 @@ func (s *FpgaImage) SetProductCodes(v []*ProductCode) *FpgaImage { return s } +// SetPublic sets the Public field's value. +func (s *FpgaImage) SetPublic(v bool) *FpgaImage { + s.Public = &v + return s +} + // SetShellVersion sets the ShellVersion field's value. func (s *FpgaImage) SetShellVersion(v string) *FpgaImage { s.ShellVersion = &v @@ -39812,9 +45013,70 @@ func (s *FpgaImage) SetUpdateTime(v time.Time) *FpgaImage { return s } +// Describes an Amazon FPGA image (AFI) attribute. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FpgaImageAttribute +type FpgaImageAttribute struct { + _ struct{} `type:"structure"` + + // The description of the AFI. + Description *string `locationName:"description" type:"string"` + + // The ID of the AFI. + FpgaImageId *string `locationName:"fpgaImageId" type:"string"` + + // One or more load permissions. + LoadPermissions []*LoadPermission `locationName:"loadPermissions" locationNameList:"item" type:"list"` + + // The name of the AFI. + Name *string `locationName:"name" type:"string"` + + // One or more product codes. + ProductCodes []*ProductCode `locationName:"productCodes" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s FpgaImageAttribute) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s FpgaImageAttribute) GoString() string { + return s.String() +} + +// SetDescription sets the Description field's value. +func (s *FpgaImageAttribute) SetDescription(v string) *FpgaImageAttribute { + s.Description = &v + return s +} + +// SetFpgaImageId sets the FpgaImageId field's value. +func (s *FpgaImageAttribute) SetFpgaImageId(v string) *FpgaImageAttribute { + s.FpgaImageId = &v + return s +} + +// SetLoadPermissions sets the LoadPermissions field's value. +func (s *FpgaImageAttribute) SetLoadPermissions(v []*LoadPermission) *FpgaImageAttribute { + s.LoadPermissions = v + return s +} + +// SetName sets the Name field's value. +func (s *FpgaImageAttribute) SetName(v string) *FpgaImageAttribute { + s.Name = &v + return s +} + +// SetProductCodes sets the ProductCodes field's value. +func (s *FpgaImageAttribute) SetProductCodes(v []*ProductCode) *FpgaImageAttribute { + s.ProductCodes = v + return s +} + // Describes the state of the bitstream generation process for an Amazon FPGA // image (AFI). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FpgaImageState +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/FpgaImageState type FpgaImageState struct { _ struct{} `type:"structure"` @@ -39856,7 +45118,7 @@ func (s *FpgaImageState) SetMessage(v string) *FpgaImageState { } // Contains the parameters for GetConsoleOutput. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutputRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutputRequest type GetConsoleOutputInput struct { _ struct{} `type:"structure"` @@ -39908,7 +45170,7 @@ func (s *GetConsoleOutputInput) SetInstanceId(v string) *GetConsoleOutputInput { } // Contains the output of GetConsoleOutput. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutputResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleOutputResult type GetConsoleOutputOutput struct { _ struct{} `type:"structure"` @@ -39952,7 +45214,7 @@ func (s *GetConsoleOutputOutput) SetTimestamp(v time.Time) *GetConsoleOutputOutp } // Contains the parameters for the request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshotRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshotRequest type GetConsoleScreenshotInput struct { _ struct{} `type:"structure"` @@ -40014,7 +45276,7 @@ func (s *GetConsoleScreenshotInput) SetWakeUp(v bool) *GetConsoleScreenshotInput } // Contains the output of the request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshotResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetConsoleScreenshotResult type GetConsoleScreenshotOutput struct { _ struct{} `type:"structure"` @@ -40047,7 +45309,7 @@ func (s *GetConsoleScreenshotOutput) SetInstanceId(v string) *GetConsoleScreensh return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreviewRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreviewRequest type GetHostReservationPurchasePreviewInput struct { _ struct{} `type:"structure"` @@ -40101,7 +45363,7 @@ func (s *GetHostReservationPurchasePreviewInput) SetOfferingId(v string) *GetHos return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreviewResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetHostReservationPurchasePreviewResult type GetHostReservationPurchasePreviewOutput struct { _ struct{} `type:"structure"` @@ -40111,7 +45373,7 @@ type GetHostReservationPurchasePreviewOutput struct { // The purchase information of the Dedicated Host Reservation and the Dedicated // Hosts associated with it. - Purchase []*Purchase `locationName:"purchase" type:"list"` + Purchase []*Purchase `locationName:"purchase" locationNameList:"item" type:"list"` // The potential total hourly price of the reservation per hour. TotalHourlyPrice *string `locationName:"totalHourlyPrice" type:"string"` @@ -40154,8 +45416,83 @@ func (s *GetHostReservationPurchasePreviewOutput) SetTotalUpfrontPrice(v string) return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetLaunchTemplateDataRequest +type GetLaunchTemplateDataInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the instance. + // + // InstanceId is a required field + InstanceId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s GetLaunchTemplateDataInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetLaunchTemplateDataInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *GetLaunchTemplateDataInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "GetLaunchTemplateDataInput"} + if s.InstanceId == nil { + invalidParams.Add(request.NewErrParamRequired("InstanceId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *GetLaunchTemplateDataInput) SetDryRun(v bool) *GetLaunchTemplateDataInput { + s.DryRun = &v + return s +} + +// SetInstanceId sets the InstanceId field's value. +func (s *GetLaunchTemplateDataInput) SetInstanceId(v string) *GetLaunchTemplateDataInput { + s.InstanceId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetLaunchTemplateDataResult +type GetLaunchTemplateDataOutput struct { + _ struct{} `type:"structure"` + + // The instance data. + LaunchTemplateData *ResponseLaunchTemplateData `locationName:"launchTemplateData" type:"structure"` +} + +// String returns the string representation +func (s GetLaunchTemplateDataOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetLaunchTemplateDataOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplateData sets the LaunchTemplateData field's value. +func (s *GetLaunchTemplateDataOutput) SetLaunchTemplateData(v *ResponseLaunchTemplateData) *GetLaunchTemplateDataOutput { + s.LaunchTemplateData = v + return s +} + // Contains the parameters for GetPasswordData. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordDataRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordDataRequest type GetPasswordDataInput struct { _ struct{} `type:"structure"` @@ -40207,14 +45544,15 @@ func (s *GetPasswordDataInput) SetInstanceId(v string) *GetPasswordDataInput { } // Contains the output of GetPasswordData. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordDataResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetPasswordDataResult type GetPasswordDataOutput struct { _ struct{} `type:"structure"` // The ID of the Windows instance. InstanceId *string `locationName:"instanceId" type:"string"` - // The password of the instance. + // The password of the instance. Returns an empty string if the password is + // not available. PasswordData *string `locationName:"passwordData" type:"string"` // The time the data was last updated. @@ -40250,7 +45588,7 @@ func (s *GetPasswordDataOutput) SetTimestamp(v time.Time) *GetPasswordDataOutput } // Contains the parameters for GetReservedInstanceExchangeQuote. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuoteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuoteRequest type GetReservedInstancesExchangeQuoteInput struct { _ struct{} `type:"structure"` @@ -40265,7 +45603,7 @@ type GetReservedInstancesExchangeQuoteInput struct { // ReservedInstanceIds is a required field ReservedInstanceIds []*string `locationName:"ReservedInstanceId" locationNameList:"ReservedInstanceId" type:"list" required:"true"` - // The configuration requirements of the Convertible Reserved Instances to exchange + // The configuration of the target Convertible Reserved Instance to exchange // for your current Convertible Reserved Instances. TargetConfigurations []*TargetConfigurationRequest `locationName:"TargetConfiguration" locationNameList:"TargetConfigurationRequest" type:"list"` } @@ -40322,7 +45660,7 @@ func (s *GetReservedInstancesExchangeQuoteInput) SetTargetConfigurations(v []*Ta } // Contains the output of GetReservedInstancesExchangeQuote. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuoteResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GetReservedInstancesExchangeQuoteResult type GetReservedInstancesExchangeQuoteOutput struct { _ struct{} `type:"structure"` @@ -40419,7 +45757,7 @@ func (s *GetReservedInstancesExchangeQuoteOutput) SetValidationFailureReason(v s } // Describes a security group. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GroupIdentifier +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/GroupIdentifier type GroupIdentifier struct { _ struct{} `type:"structure"` @@ -40452,8 +45790,8 @@ func (s *GroupIdentifier) SetGroupName(v string) *GroupIdentifier { return s } -// Describes an event in the history of the Spot fleet request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HistoryRecord +// Describes an event in the history of the Spot Fleet request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HistoryRecord type HistoryRecord struct { _ struct{} `type:"structure"` @@ -40464,12 +45802,14 @@ type HistoryRecord struct { // The event type. // - // * error - Indicates an error with the Spot fleet request. + // * error - An error with the Spot Fleet request. // - // * fleetRequestChange - Indicates a change in the status or configuration - // of the Spot fleet request. + // * fleetRequestChange - A change in the status or configuration of the + // Spot Fleet request. // - // * instanceChange - Indicates that an instance was launched or terminated. + // * instanceChange - An instance was launched or terminated. + // + // * Information - An informational event. // // EventType is a required field EventType *string `locationName:"eventType" type:"string" required:"true" enum:"EventType"` @@ -40509,7 +45849,7 @@ func (s *HistoryRecord) SetTimestamp(v time.Time) *HistoryRecord { } // Describes the properties of the Dedicated Host. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Host +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Host type Host struct { _ struct{} `type:"structure"` @@ -40609,7 +45949,7 @@ func (s *Host) SetState(v string) *Host { } // Describes an instance running on a Dedicated Host. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostInstance type HostInstance struct { _ struct{} `type:"structure"` @@ -40643,7 +45983,7 @@ func (s *HostInstance) SetInstanceType(v string) *HostInstance { } // Details about the Dedicated Host Reservation offering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostOffering +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostOffering type HostOffering struct { _ struct{} `type:"structure"` @@ -40722,7 +46062,7 @@ func (s *HostOffering) SetUpfrontPrice(v string) *HostOffering { } // Describes properties of a Dedicated Host. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostProperties +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostProperties type HostProperties struct { _ struct{} `type:"structure"` @@ -40774,7 +46114,7 @@ func (s *HostProperties) SetTotalVCpus(v int64) *HostProperties { } // Details about the Dedicated Host Reservation and associated Dedicated Hosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostReservation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/HostReservation type HostReservation struct { _ struct{} `type:"structure"` @@ -40912,7 +46252,7 @@ func (s *HostReservation) SetUpfrontPrice(v string) *HostReservation { } // Describes an IAM instance profile. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IamInstanceProfile +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IamInstanceProfile type IamInstanceProfile struct { _ struct{} `type:"structure"` @@ -40946,7 +46286,7 @@ func (s *IamInstanceProfile) SetId(v string) *IamInstanceProfile { } // Describes an association between an IAM instance profile and an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IamInstanceProfileAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IamInstanceProfileAssociation type IamInstanceProfileAssociation struct { _ struct{} `type:"structure"` @@ -41007,7 +46347,7 @@ func (s *IamInstanceProfileAssociation) SetTimestamp(v time.Time) *IamInstancePr } // Describes an IAM instance profile. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IamInstanceProfileSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IamInstanceProfileSpecification type IamInstanceProfileSpecification struct { _ struct{} `type:"structure"` @@ -41041,7 +46381,7 @@ func (s *IamInstanceProfileSpecification) SetName(v string) *IamInstanceProfileS } // Describes the ICMP type and code. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IcmpTypeCode +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IcmpTypeCode type IcmpTypeCode struct { _ struct{} `type:"structure"` @@ -41075,7 +46415,7 @@ func (s *IcmpTypeCode) SetType(v int64) *IcmpTypeCode { } // Describes the ID format for a resource. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IdFormat +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IdFormat type IdFormat struct { _ struct{} `type:"structure"` @@ -41120,7 +46460,7 @@ func (s *IdFormat) SetUseLongIds(v bool) *IdFormat { } // Describes an image. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Image +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Image type Image struct { _ struct{} `type:"structure"` @@ -41180,7 +46520,7 @@ type Image struct { // images. RamdiskId *string `locationName:"ramdiskId" type:"string"` - // The device name of the root device (for example, /dev/sda1 or /dev/xvda). + // The device name of the root device volume (for example, /dev/sda1). RootDeviceName *string `locationName:"rootDeviceName" type:"string"` // The type of root device used by the AMI. The AMI can use an EBS volume or @@ -41360,7 +46700,7 @@ func (s *Image) SetVirtualizationType(v string) *Image { } // Describes the disk container object for an import image task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImageDiskContainer +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImageDiskContainer type ImageDiskContainer struct { _ struct{} `type:"structure"` @@ -41433,7 +46773,7 @@ func (s *ImageDiskContainer) SetUserBucket(v *UserBucket) *ImageDiskContainer { } // Contains the parameters for ImportImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImageRequest type ImportImageInput struct { _ struct{} `type:"structure"` @@ -41555,7 +46895,7 @@ func (s *ImportImageInput) SetRoleName(v string) *ImportImageInput { } // Contains the output for ImportImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImageResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImageResult type ImportImageOutput struct { _ struct{} `type:"structure"` @@ -41670,7 +47010,7 @@ func (s *ImportImageOutput) SetStatusMessage(v string) *ImportImageOutput { } // Describes an import image task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImageTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportImageTask type ImportImageTask struct { _ struct{} `type:"structure"` @@ -41789,7 +47129,7 @@ func (s *ImportImageTask) SetStatusMessage(v string) *ImportImageTask { } // Contains the parameters for ImportInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceRequest type ImportInstanceInput struct { _ struct{} `type:"structure"` @@ -41878,7 +47218,7 @@ func (s *ImportInstanceInput) SetPlatform(v string) *ImportInstanceInput { } // Describes the launch specification for VM import. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceLaunchSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceLaunchSpecification type ImportInstanceLaunchSpecification struct { _ struct{} `type:"structure"` @@ -41998,7 +47338,7 @@ func (s *ImportInstanceLaunchSpecification) SetUserData(v *UserData) *ImportInst } // Contains the output for ImportInstance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceResult type ImportInstanceOutput struct { _ struct{} `type:"structure"` @@ -42023,7 +47363,7 @@ func (s *ImportInstanceOutput) SetConversionTask(v *ConversionTask) *ImportInsta } // Describes an import instance task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceTaskDetails +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceTaskDetails type ImportInstanceTaskDetails struct { _ struct{} `type:"structure"` @@ -42077,7 +47417,7 @@ func (s *ImportInstanceTaskDetails) SetVolumes(v []*ImportInstanceVolumeDetailIt } // Describes an import volume task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceVolumeDetailItem +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportInstanceVolumeDetailItem type ImportInstanceVolumeDetailItem struct { _ struct{} `type:"structure"` @@ -42166,7 +47506,7 @@ func (s *ImportInstanceVolumeDetailItem) SetVolume(v *DiskImageVolumeDescription } // Contains the parameters for ImportKeyPair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPairRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPairRequest type ImportKeyPairInput struct { _ struct{} `type:"structure"` @@ -42235,7 +47575,7 @@ func (s *ImportKeyPairInput) SetPublicKeyMaterial(v []byte) *ImportKeyPairInput } // Contains the output of ImportKeyPair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPairResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportKeyPairResult type ImportKeyPairOutput struct { _ struct{} `type:"structure"` @@ -42269,7 +47609,7 @@ func (s *ImportKeyPairOutput) SetKeyName(v string) *ImportKeyPairOutput { } // Contains the parameters for ImportSnapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshotRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshotRequest type ImportSnapshotInput struct { _ struct{} `type:"structure"` @@ -42342,7 +47682,7 @@ func (s *ImportSnapshotInput) SetRoleName(v string) *ImportSnapshotInput { } // Contains the output for ImportSnapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshotResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshotResult type ImportSnapshotOutput struct { _ struct{} `type:"structure"` @@ -42385,7 +47725,7 @@ func (s *ImportSnapshotOutput) SetSnapshotTaskDetail(v *SnapshotTaskDetail) *Imp } // Describes an import snapshot task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshotTask +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportSnapshotTask type ImportSnapshotTask struct { _ struct{} `type:"structure"` @@ -42428,7 +47768,7 @@ func (s *ImportSnapshotTask) SetSnapshotTaskDetail(v *SnapshotTaskDetail) *Impor } // Contains the parameters for ImportVolume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolumeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolumeRequest type ImportVolumeInput struct { _ struct{} `type:"structure"` @@ -42527,7 +47867,7 @@ func (s *ImportVolumeInput) SetVolume(v *VolumeDetail) *ImportVolumeInput { } // Contains the output for ImportVolume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolumeResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolumeResult type ImportVolumeOutput struct { _ struct{} `type:"structure"` @@ -42552,7 +47892,7 @@ func (s *ImportVolumeOutput) SetConversionTask(v *ConversionTask) *ImportVolumeO } // Describes an import volume task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolumeTaskDetails +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ImportVolumeTaskDetails type ImportVolumeTaskDetails struct { _ struct{} `type:"structure"` @@ -42621,7 +47961,7 @@ func (s *ImportVolumeTaskDetails) SetVolume(v *DiskImageVolumeDescription) *Impo } // Describes an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Instance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Instance type Instance struct { _ struct{} `type:"structure"` @@ -42638,7 +47978,7 @@ type Instance struct { // The idempotency token you provided when you launched the instance, if applicable. ClientToken *string `locationName:"clientToken" type:"string"` - // Indicates whether the instance is optimized for EBS I/O. This optimization + // Indicates whether the instance is optimized for Amazon EBS I/O. This optimization // provides dedicated throughput to Amazon EBS and an optimized configuration // stack to provide optimal I/O performance. This optimization isn't available // with all instance types. Additional usage charges apply when using an EBS @@ -42663,7 +48003,7 @@ type Instance struct { // The ID of the instance. InstanceId *string `locationName:"instanceId" type:"string"` - // Indicates whether this is a Spot instance or a Scheduled Instance. + // Indicates whether this is a Spot Instance or a Scheduled Instance. InstanceLifecycle *string `locationName:"instanceLifecycle" type:"string" enum:"InstanceLifecycleType"` // The instance type. @@ -42695,7 +48035,7 @@ type Instance struct { // DNS hostname can only be used inside the Amazon EC2 network. This name is // not available until the instance enters the running state. // - // [EC2-VPC] The Amazon-provided DNS server will resolve Amazon-provided private + // [EC2-VPC] The Amazon-provided DNS server resolves Amazon-provided private // DNS hostnames if you've enabled DNS resolution and DNS hostnames in your // VPC. If you are not using the Amazon-provided DNS server in your VPC, your // custom domain name servers must resolve the hostname as appropriate. @@ -42718,7 +48058,7 @@ type Instance struct { // The RAM disk associated with this instance, if applicable. RamdiskId *string `locationName:"ramdiskId" type:"string"` - // The root device name (for example, /dev/sda1 or /dev/xvda). + // The device name of the root device volume (for example, /dev/sda1). RootDeviceName *string `locationName:"rootDeviceName" type:"string"` // The root device type used by the AMI. The AMI can use an EBS volume or an @@ -42730,13 +48070,13 @@ type Instance struct { // Specifies whether to enable an instance launched in a VPC to perform NAT. // This controls whether source/destination checking is enabled on the instance. - // A value of true means checking is enabled, and false means checking is disabled. - // The value must be false for the instance to perform NAT. For more information, - // see NAT Instances (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_NAT_Instance.html) + // A value of true means that checking is enabled, and false means that checking + // is disabled. The value must be false for the instance to perform NAT. For + // more information, see NAT Instances (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_NAT_Instance.html) // in the Amazon Virtual Private Cloud User Guide. SourceDestCheck *bool `locationName:"sourceDestCheck" type:"boolean"` - // If the request is a Spot instance request, the ID of the request. + // If the request is a Spot Instance request, the ID of the request. SpotInstanceRequestId *string `locationName:"spotInstanceRequestId" type:"string"` // Specifies whether enhanced networking with the Intel 82599 Virtual Function @@ -43010,11 +48350,11 @@ func (s *Instance) SetVpcId(v string) *Instance { } // Describes a block device mapping. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceBlockDeviceMapping +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceBlockDeviceMapping type InstanceBlockDeviceMapping struct { _ struct{} `type:"structure"` - // The device name exposed to the instance (for example, /dev/sdh or xvdh). + // The device name (for example, /dev/sdh or xvdh). DeviceName *string `locationName:"deviceName" type:"string"` // Parameters used to automatically set up EBS volumes when the instance is @@ -43045,11 +48385,11 @@ func (s *InstanceBlockDeviceMapping) SetEbs(v *EbsInstanceBlockDevice) *Instance } // Describes a block device mapping entry. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceBlockDeviceMappingSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceBlockDeviceMappingSpecification type InstanceBlockDeviceMappingSpecification struct { _ struct{} `type:"structure"` - // The device name exposed to the instance (for example, /dev/sdh or xvdh). + // The device name (for example, /dev/sdh or xvdh). DeviceName *string `locationName:"deviceName" type:"string"` // Parameters used to automatically set up EBS volumes when the instance is @@ -43098,7 +48438,7 @@ func (s *InstanceBlockDeviceMappingSpecification) SetVirtualName(v string) *Inst } // Information about the instance type that the Dedicated Host supports. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceCapacity +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceCapacity type InstanceCapacity struct { _ struct{} `type:"structure"` @@ -43141,7 +48481,7 @@ func (s *InstanceCapacity) SetTotalCapacity(v int64) *InstanceCapacity { } // Describes a Reserved Instance listing state. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceCount +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceCount type InstanceCount struct { _ struct{} `type:"structure"` @@ -43174,8 +48514,78 @@ func (s *InstanceCount) SetState(v string) *InstanceCount { return s } +// Describes the credit option for CPU usage of a T2 instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceCreditSpecification +type InstanceCreditSpecification struct { + _ struct{} `type:"structure"` + + // The credit option for CPU usage of the instance. Valid values are standard + // and unlimited. + CpuCredits *string `locationName:"cpuCredits" type:"string"` + + // The ID of the instance. + InstanceId *string `locationName:"instanceId" type:"string"` +} + +// String returns the string representation +func (s InstanceCreditSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InstanceCreditSpecification) GoString() string { + return s.String() +} + +// SetCpuCredits sets the CpuCredits field's value. +func (s *InstanceCreditSpecification) SetCpuCredits(v string) *InstanceCreditSpecification { + s.CpuCredits = &v + return s +} + +// SetInstanceId sets the InstanceId field's value. +func (s *InstanceCreditSpecification) SetInstanceId(v string) *InstanceCreditSpecification { + s.InstanceId = &v + return s +} + +// Describes the credit option for CPU usage of a T2 instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceCreditSpecificationRequest +type InstanceCreditSpecificationRequest struct { + _ struct{} `type:"structure"` + + // The credit option for CPU usage of the instance. Valid values are standard + // and unlimited. + CpuCredits *string `type:"string"` + + // The ID of the instance. + InstanceId *string `type:"string"` +} + +// String returns the string representation +func (s InstanceCreditSpecificationRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InstanceCreditSpecificationRequest) GoString() string { + return s.String() +} + +// SetCpuCredits sets the CpuCredits field's value. +func (s *InstanceCreditSpecificationRequest) SetCpuCredits(v string) *InstanceCreditSpecificationRequest { + s.CpuCredits = &v + return s +} + +// SetInstanceId sets the InstanceId field's value. +func (s *InstanceCreditSpecificationRequest) SetInstanceId(v string) *InstanceCreditSpecificationRequest { + s.InstanceId = &v + return s +} + // Describes an instance to export. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceExportDetails +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceExportDetails type InstanceExportDetails struct { _ struct{} `type:"structure"` @@ -43209,7 +48619,7 @@ func (s *InstanceExportDetails) SetTargetEnvironment(v string) *InstanceExportDe } // Describes an IPv6 address. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceIpv6Address +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceIpv6Address type InstanceIpv6Address struct { _ struct{} `type:"structure"` @@ -43233,8 +48643,67 @@ func (s *InstanceIpv6Address) SetIpv6Address(v string) *InstanceIpv6Address { return s } +// Describes an IPv6 address. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceIpv6AddressRequest +type InstanceIpv6AddressRequest struct { + _ struct{} `type:"structure"` + + // The IPv6 address. + Ipv6Address *string `type:"string"` +} + +// String returns the string representation +func (s InstanceIpv6AddressRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InstanceIpv6AddressRequest) GoString() string { + return s.String() +} + +// SetIpv6Address sets the Ipv6Address field's value. +func (s *InstanceIpv6AddressRequest) SetIpv6Address(v string) *InstanceIpv6AddressRequest { + s.Ipv6Address = &v + return s +} + +// Describes the market (purchasing) option for the instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceMarketOptionsRequest +type InstanceMarketOptionsRequest struct { + _ struct{} `type:"structure"` + + // The market type. + MarketType *string `type:"string" enum:"MarketType"` + + // The options for Spot Instances. + SpotOptions *SpotMarketOptions `type:"structure"` +} + +// String returns the string representation +func (s InstanceMarketOptionsRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InstanceMarketOptionsRequest) GoString() string { + return s.String() +} + +// SetMarketType sets the MarketType field's value. +func (s *InstanceMarketOptionsRequest) SetMarketType(v string) *InstanceMarketOptionsRequest { + s.MarketType = &v + return s +} + +// SetSpotOptions sets the SpotOptions field's value. +func (s *InstanceMarketOptionsRequest) SetSpotOptions(v *SpotMarketOptions) *InstanceMarketOptionsRequest { + s.SpotOptions = v + return s +} + // Describes the monitoring of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceMonitoring +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceMonitoring type InstanceMonitoring struct { _ struct{} `type:"structure"` @@ -43268,7 +48737,7 @@ func (s *InstanceMonitoring) SetMonitoring(v *Monitoring) *InstanceMonitoring { } // Describes a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterface type InstanceNetworkInterface struct { _ struct{} `type:"structure"` @@ -43420,7 +48889,7 @@ func (s *InstanceNetworkInterface) SetVpcId(v string) *InstanceNetworkInterface } // Describes association information for an Elastic IP address (IPv4). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterfaceAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterfaceAssociation type InstanceNetworkInterfaceAssociation struct { _ struct{} `type:"structure"` @@ -43463,7 +48932,7 @@ func (s *InstanceNetworkInterfaceAssociation) SetPublicIp(v string) *InstanceNet } // Describes a network interface attachment. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterfaceAttachment +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterfaceAttachment type InstanceNetworkInterfaceAttachment struct { _ struct{} `type:"structure"` @@ -43524,7 +48993,7 @@ func (s *InstanceNetworkInterfaceAttachment) SetStatus(v string) *InstanceNetwor } // Describes a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterfaceSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceNetworkInterfaceSpecification type InstanceNetworkInterfaceSpecification struct { _ struct{} `type:"structure"` @@ -43694,7 +49163,7 @@ func (s *InstanceNetworkInterfaceSpecification) SetSubnetId(v string) *InstanceN } // Describes a private IPv4 address. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstancePrivateIpAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstancePrivateIpAddress type InstancePrivateIpAddress struct { _ struct{} `type:"structure"` @@ -43747,7 +49216,7 @@ func (s *InstancePrivateIpAddress) SetPrivateIpAddress(v string) *InstancePrivat } // Describes the current state of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceState +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceState type InstanceState struct { _ struct{} `type:"structure"` @@ -43794,7 +49263,7 @@ func (s *InstanceState) SetName(v string) *InstanceState { } // Describes an instance state change. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStateChange +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStateChange type InstanceStateChange struct { _ struct{} `type:"structure"` @@ -43837,7 +49306,7 @@ func (s *InstanceStateChange) SetPreviousState(v *InstanceState) *InstanceStateC } // Describes the status of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatus type InstanceStatus struct { _ struct{} `type:"structure"` @@ -43911,7 +49380,7 @@ func (s *InstanceStatus) SetSystemStatus(v *InstanceStatusSummary) *InstanceStat } // Describes the instance status. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatusDetails +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatusDetails type InstanceStatusDetails struct { _ struct{} `type:"structure"` @@ -43955,7 +49424,7 @@ func (s *InstanceStatusDetails) SetStatus(v string) *InstanceStatusDetails { } // Describes a scheduled event for an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatusEvent +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatusEvent type InstanceStatusEvent struct { _ struct{} `type:"structure"` @@ -44011,7 +49480,7 @@ func (s *InstanceStatusEvent) SetNotBefore(v time.Time) *InstanceStatusEvent { } // Describes the status of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatusSummary +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InstanceStatusSummary type InstanceStatusSummary struct { _ struct{} `type:"structure"` @@ -44045,7 +49514,7 @@ func (s *InstanceStatusSummary) SetStatus(v string) *InstanceStatusSummary { } // Describes an Internet gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InternetGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InternetGateway type InternetGateway struct { _ struct{} `type:"structure"` @@ -44089,11 +49558,12 @@ func (s *InternetGateway) SetTags(v []*Tag) *InternetGateway { // Describes the attachment of a VPC to an Internet gateway or an egress-only // Internet gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InternetGatewayAttachment +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/InternetGatewayAttachment type InternetGatewayAttachment struct { _ struct{} `type:"structure"` - // The current state of the attachment. + // The current state of the attachment. For an Internet gateway, the state is + // available when attached to a VPC; otherwise, this value is not returned. State *string `locationName:"state" type:"string" enum:"AttachmentStatus"` // The ID of the VPC. @@ -44122,13 +49592,14 @@ func (s *InternetGatewayAttachment) SetVpcId(v string) *InternetGatewayAttachmen return s } -// Describes a security group rule. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IpPermission +// Describes a set of permissions for a security group rule. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IpPermission type IpPermission struct { _ struct{} `type:"structure"` // The start of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 - // type number. A value of -1 indicates all ICMP/ICMPv6 types. + // type number. A value of -1 indicates all ICMP/ICMPv6 types. If you specify + // all ICMP/ICMPv6 types, you must specify all codes. FromPort *int64 `locationName:"fromPort" type:"integer"` // The IP protocol name (tcp, udp, icmp) or number (see Protocol Numbers (http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml)). @@ -44147,14 +49618,16 @@ type IpPermission struct { // [EC2-VPC only] One or more IPv6 ranges. Ipv6Ranges []*Ipv6Range `locationName:"ipv6Ranges" locationNameList:"item" type:"list"` - // (Valid for AuthorizeSecurityGroupEgress, RevokeSecurityGroupEgress and DescribeSecurityGroups - // only) One or more prefix list IDs for an AWS service. In an AuthorizeSecurityGroupEgress - // request, this is the AWS service that you want to access through a VPC endpoint - // from instances associated with the security group. + // (EC2-VPC only; valid for AuthorizeSecurityGroupEgress, RevokeSecurityGroupEgress + // and DescribeSecurityGroups only) One or more prefix list IDs for an AWS service. + // In an AuthorizeSecurityGroupEgress request, this is the AWS service that + // you want to access through a VPC endpoint from instances associated with + // the security group. PrefixListIds []*PrefixListId `locationName:"prefixListIds" locationNameList:"item" type:"list"` // The end of port range for the TCP and UDP protocols, or an ICMP/ICMPv6 code. // A value of -1 indicates all ICMP/ICMPv6 codes for the specified ICMP type. + // If you specify all ICMP/ICMPv6 types, you must specify all codes. ToPort *int64 `locationName:"toPort" type:"integer"` // One or more security group and AWS account ID pairs. @@ -44214,13 +49687,20 @@ func (s *IpPermission) SetUserIdGroupPairs(v []*UserIdGroupPair) *IpPermission { } // Describes an IPv4 range. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IpRange +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/IpRange type IpRange struct { _ struct{} `type:"structure"` // The IPv4 CIDR range. You can either specify a CIDR range or a source security - // group, not both. To specify a single IPv4 address, use the /32 prefix. + // group, not both. To specify a single IPv4 address, use the /32 prefix length. CidrIp *string `locationName:"cidrIp" type:"string"` + + // A description for the security group rule that references this IPv4 address + // range. + // + // Constraints: Up to 255 characters in length. Allowed characters are a-z, + // A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$* + Description *string `locationName:"description" type:"string"` } // String returns the string representation @@ -44239,8 +49719,14 @@ func (s *IpRange) SetCidrIp(v string) *IpRange { return s } +// SetDescription sets the Description field's value. +func (s *IpRange) SetDescription(v string) *IpRange { + s.Description = &v + return s +} + // Describes an IPv6 CIDR block. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Ipv6CidrBlock +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Ipv6CidrBlock type Ipv6CidrBlock struct { _ struct{} `type:"structure"` @@ -44265,13 +49751,20 @@ func (s *Ipv6CidrBlock) SetIpv6CidrBlock(v string) *Ipv6CidrBlock { } // [EC2-VPC only] Describes an IPv6 range. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Ipv6Range +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Ipv6Range type Ipv6Range struct { _ struct{} `type:"structure"` // The IPv6 CIDR range. You can either specify a CIDR range or a source security - // group, not both. To specify a single IPv6 address, use the /128 prefix. + // group, not both. To specify a single IPv6 address, use the /128 prefix length. CidrIpv6 *string `locationName:"cidrIpv6" type:"string"` + + // A description for the security group rule that references this IPv6 address + // range. + // + // Constraints: Up to 255 characters in length. Allowed characters are a-z, + // A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$* + Description *string `locationName:"description" type:"string"` } // String returns the string representation @@ -44290,8 +49783,14 @@ func (s *Ipv6Range) SetCidrIpv6(v string) *Ipv6Range { return s } +// SetDescription sets the Description field's value. +func (s *Ipv6Range) SetDescription(v string) *Ipv6Range { + s.Description = &v + return s +} + // Describes a key pair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/KeyPairInfo +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/KeyPairInfo type KeyPairInfo struct { _ struct{} `type:"structure"` @@ -44328,7 +49827,7 @@ func (s *KeyPairInfo) SetKeyName(v string) *KeyPairInfo { } // Describes a launch permission. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchPermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchPermission type LaunchPermission struct { _ struct{} `type:"structure"` @@ -44362,7 +49861,7 @@ func (s *LaunchPermission) SetUserId(v string) *LaunchPermission { } // Describes a launch permission modification. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchPermissionModifications +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchPermissionModifications type LaunchPermissionModifications struct { _ struct{} `type:"structure"` @@ -44397,7 +49896,7 @@ func (s *LaunchPermissionModifications) SetRemove(v []*LaunchPermission) *Launch } // Describes the launch specification for an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchSpecification type LaunchSpecification struct { _ struct{} `type:"structure"` @@ -44405,9 +49904,6 @@ type LaunchSpecification struct { AddressingType *string `locationName:"addressingType" type:"string"` // One or more block device mapping entries. - // - // Although you can specify encrypted EBS volumes in this block device mapping - // for your Spot Instances, these volumes are not encrypted. BlockDeviceMappings []*BlockDeviceMapping `locationName:"blockDeviceMapping" locationNameList:"item" type:"list"` // Indicates whether the instance is optimized for EBS I/O. This optimization @@ -44561,8 +50057,1727 @@ func (s *LaunchSpecification) SetUserData(v string) *LaunchSpecification { return s } +// Describes a launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplate +type LaunchTemplate struct { + _ struct{} `type:"structure"` + + // The time launch template was created. + CreateTime *time.Time `locationName:"createTime" type:"timestamp" timestampFormat:"iso8601"` + + // The principal that created the launch template. + CreatedBy *string `locationName:"createdBy" type:"string"` + + // The version number of the default version of the launch template. + DefaultVersionNumber *int64 `locationName:"defaultVersionNumber" type:"long"` + + // The version number of the latest version of the launch template. + LatestVersionNumber *int64 `locationName:"latestVersionNumber" type:"long"` + + // The ID of the launch template. + LaunchTemplateId *string `locationName:"launchTemplateId" type:"string"` + + // The name of the launch template. + LaunchTemplateName *string `locationName:"launchTemplateName" min:"3" type:"string"` + + // The tags for the launch template. + Tags []*Tag `locationName:"tagSet" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s LaunchTemplate) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplate) GoString() string { + return s.String() +} + +// SetCreateTime sets the CreateTime field's value. +func (s *LaunchTemplate) SetCreateTime(v time.Time) *LaunchTemplate { + s.CreateTime = &v + return s +} + +// SetCreatedBy sets the CreatedBy field's value. +func (s *LaunchTemplate) SetCreatedBy(v string) *LaunchTemplate { + s.CreatedBy = &v + return s +} + +// SetDefaultVersionNumber sets the DefaultVersionNumber field's value. +func (s *LaunchTemplate) SetDefaultVersionNumber(v int64) *LaunchTemplate { + s.DefaultVersionNumber = &v + return s +} + +// SetLatestVersionNumber sets the LatestVersionNumber field's value. +func (s *LaunchTemplate) SetLatestVersionNumber(v int64) *LaunchTemplate { + s.LatestVersionNumber = &v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *LaunchTemplate) SetLaunchTemplateId(v string) *LaunchTemplate { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *LaunchTemplate) SetLaunchTemplateName(v string) *LaunchTemplate { + s.LaunchTemplateName = &v + return s +} + +// SetTags sets the Tags field's value. +func (s *LaunchTemplate) SetTags(v []*Tag) *LaunchTemplate { + s.Tags = v + return s +} + +// Describes a block device mapping. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateBlockDeviceMapping +type LaunchTemplateBlockDeviceMapping struct { + _ struct{} `type:"structure"` + + // The device name. + DeviceName *string `locationName:"deviceName" type:"string"` + + // Information about the block device for an EBS volume. + Ebs *LaunchTemplateEbsBlockDevice `locationName:"ebs" type:"structure"` + + // Suppresses the specified device included in the block device mapping of the + // AMI. + NoDevice *string `locationName:"noDevice" type:"string"` + + // The virtual device name (ephemeralN). + VirtualName *string `locationName:"virtualName" type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateBlockDeviceMapping) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateBlockDeviceMapping) GoString() string { + return s.String() +} + +// SetDeviceName sets the DeviceName field's value. +func (s *LaunchTemplateBlockDeviceMapping) SetDeviceName(v string) *LaunchTemplateBlockDeviceMapping { + s.DeviceName = &v + return s +} + +// SetEbs sets the Ebs field's value. +func (s *LaunchTemplateBlockDeviceMapping) SetEbs(v *LaunchTemplateEbsBlockDevice) *LaunchTemplateBlockDeviceMapping { + s.Ebs = v + return s +} + +// SetNoDevice sets the NoDevice field's value. +func (s *LaunchTemplateBlockDeviceMapping) SetNoDevice(v string) *LaunchTemplateBlockDeviceMapping { + s.NoDevice = &v + return s +} + +// SetVirtualName sets the VirtualName field's value. +func (s *LaunchTemplateBlockDeviceMapping) SetVirtualName(v string) *LaunchTemplateBlockDeviceMapping { + s.VirtualName = &v + return s +} + +// Describes a block device mapping. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateBlockDeviceMappingRequest +type LaunchTemplateBlockDeviceMappingRequest struct { + _ struct{} `type:"structure"` + + // The device name (for example, /dev/sdh or xvdh). + DeviceName *string `type:"string"` + + // Parameters used to automatically set up EBS volumes when the instance is + // launched. + Ebs *LaunchTemplateEbsBlockDeviceRequest `type:"structure"` + + // Suppresses the specified device included in the block device mapping of the + // AMI. + NoDevice *string `type:"string"` + + // The virtual device name (ephemeralN). Instance store volumes are numbered + // starting from 0. An instance type with 2 available instance store volumes + // can specify mappings for ephemeral0 and ephemeral1. The number of available + // instance store volumes depends on the instance type. After you connect to + // the instance, you must mount the volume. + VirtualName *string `type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateBlockDeviceMappingRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateBlockDeviceMappingRequest) GoString() string { + return s.String() +} + +// SetDeviceName sets the DeviceName field's value. +func (s *LaunchTemplateBlockDeviceMappingRequest) SetDeviceName(v string) *LaunchTemplateBlockDeviceMappingRequest { + s.DeviceName = &v + return s +} + +// SetEbs sets the Ebs field's value. +func (s *LaunchTemplateBlockDeviceMappingRequest) SetEbs(v *LaunchTemplateEbsBlockDeviceRequest) *LaunchTemplateBlockDeviceMappingRequest { + s.Ebs = v + return s +} + +// SetNoDevice sets the NoDevice field's value. +func (s *LaunchTemplateBlockDeviceMappingRequest) SetNoDevice(v string) *LaunchTemplateBlockDeviceMappingRequest { + s.NoDevice = &v + return s +} + +// SetVirtualName sets the VirtualName field's value. +func (s *LaunchTemplateBlockDeviceMappingRequest) SetVirtualName(v string) *LaunchTemplateBlockDeviceMappingRequest { + s.VirtualName = &v + return s +} + +// Describes a launch template and overrides. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateConfig +type LaunchTemplateConfig struct { + _ struct{} `type:"structure"` + + // The launch template. + LaunchTemplateSpecification *FleetLaunchTemplateSpecification `locationName:"launchTemplateSpecification" type:"structure"` + + // Any parameters that you specify override the same parameters in the launch + // template. + Overrides []*LaunchTemplateOverrides `locationName:"overrides" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s LaunchTemplateConfig) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateConfig) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *LaunchTemplateConfig) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "LaunchTemplateConfig"} + if s.LaunchTemplateSpecification != nil { + if err := s.LaunchTemplateSpecification.Validate(); err != nil { + invalidParams.AddNested("LaunchTemplateSpecification", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetLaunchTemplateSpecification sets the LaunchTemplateSpecification field's value. +func (s *LaunchTemplateConfig) SetLaunchTemplateSpecification(v *FleetLaunchTemplateSpecification) *LaunchTemplateConfig { + s.LaunchTemplateSpecification = v + return s +} + +// SetOverrides sets the Overrides field's value. +func (s *LaunchTemplateConfig) SetOverrides(v []*LaunchTemplateOverrides) *LaunchTemplateConfig { + s.Overrides = v + return s +} + +// Describes a block device for an EBS volume. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateEbsBlockDevice +type LaunchTemplateEbsBlockDevice struct { + _ struct{} `type:"structure"` + + // Indicates whether the EBS volume is deleted on instance termination. + DeleteOnTermination *bool `locationName:"deleteOnTermination" type:"boolean"` + + // Indicates whether the EBS volume is encrypted. + Encrypted *bool `locationName:"encrypted" type:"boolean"` + + // The number of I/O operations per second (IOPS) that the volume supports. + Iops *int64 `locationName:"iops" type:"integer"` + + // The ARN of the AWS Key Management Service (AWS KMS) CMK used for encryption. + KmsKeyId *string `locationName:"kmsKeyId" type:"string"` + + // The ID of the snapshot. + SnapshotId *string `locationName:"snapshotId" type:"string"` + + // The size of the volume, in GiB. + VolumeSize *int64 `locationName:"volumeSize" type:"integer"` + + // The volume type. + VolumeType *string `locationName:"volumeType" type:"string" enum:"VolumeType"` +} + +// String returns the string representation +func (s LaunchTemplateEbsBlockDevice) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateEbsBlockDevice) GoString() string { + return s.String() +} + +// SetDeleteOnTermination sets the DeleteOnTermination field's value. +func (s *LaunchTemplateEbsBlockDevice) SetDeleteOnTermination(v bool) *LaunchTemplateEbsBlockDevice { + s.DeleteOnTermination = &v + return s +} + +// SetEncrypted sets the Encrypted field's value. +func (s *LaunchTemplateEbsBlockDevice) SetEncrypted(v bool) *LaunchTemplateEbsBlockDevice { + s.Encrypted = &v + return s +} + +// SetIops sets the Iops field's value. +func (s *LaunchTemplateEbsBlockDevice) SetIops(v int64) *LaunchTemplateEbsBlockDevice { + s.Iops = &v + return s +} + +// SetKmsKeyId sets the KmsKeyId field's value. +func (s *LaunchTemplateEbsBlockDevice) SetKmsKeyId(v string) *LaunchTemplateEbsBlockDevice { + s.KmsKeyId = &v + return s +} + +// SetSnapshotId sets the SnapshotId field's value. +func (s *LaunchTemplateEbsBlockDevice) SetSnapshotId(v string) *LaunchTemplateEbsBlockDevice { + s.SnapshotId = &v + return s +} + +// SetVolumeSize sets the VolumeSize field's value. +func (s *LaunchTemplateEbsBlockDevice) SetVolumeSize(v int64) *LaunchTemplateEbsBlockDevice { + s.VolumeSize = &v + return s +} + +// SetVolumeType sets the VolumeType field's value. +func (s *LaunchTemplateEbsBlockDevice) SetVolumeType(v string) *LaunchTemplateEbsBlockDevice { + s.VolumeType = &v + return s +} + +// The parameters for a block device for an EBS volume. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateEbsBlockDeviceRequest +type LaunchTemplateEbsBlockDeviceRequest struct { + _ struct{} `type:"structure"` + + // Indicates whether the EBS volume is deleted on instance termination. + DeleteOnTermination *bool `type:"boolean"` + + // Indicates whether the EBS volume is encrypted. Encrypted volumes can only + // be attached to instances that support Amazon EBS encryption. If you are creating + // a volume from a snapshot, you can't specify an encryption value. + Encrypted *bool `type:"boolean"` + + // The number of I/O operations per second (IOPS) that the volume supports. + // For io1, this represents the number of IOPS that are provisioned for the + // volume. For gp2, this represents the baseline performance of the volume and + // the rate at which the volume accumulates I/O credits for bursting. For more + // information about General Purpose SSD baseline performance, I/O credits, + // and bursting, see Amazon EBS Volume Types in the Amazon Elastic Compute Cloud + // User Guide. + // + // Condition: This parameter is required for requests to create io1 volumes; + // it is not used in requests to create gp2, st1, sc1, or standard volumes. + Iops *int64 `type:"integer"` + + // The ARN of the AWS Key Management Service (AWS KMS) CMK used for encryption. + KmsKeyId *string `type:"string"` + + // The ID of the snapshot. + SnapshotId *string `type:"string"` + + // The size of the volume, in GiB. + // + // Default: If you're creating the volume from a snapshot and don't specify + // a volume size, the default is the snapshot size. + VolumeSize *int64 `type:"integer"` + + // The volume type. + VolumeType *string `type:"string" enum:"VolumeType"` +} + +// String returns the string representation +func (s LaunchTemplateEbsBlockDeviceRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateEbsBlockDeviceRequest) GoString() string { + return s.String() +} + +// SetDeleteOnTermination sets the DeleteOnTermination field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetDeleteOnTermination(v bool) *LaunchTemplateEbsBlockDeviceRequest { + s.DeleteOnTermination = &v + return s +} + +// SetEncrypted sets the Encrypted field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetEncrypted(v bool) *LaunchTemplateEbsBlockDeviceRequest { + s.Encrypted = &v + return s +} + +// SetIops sets the Iops field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetIops(v int64) *LaunchTemplateEbsBlockDeviceRequest { + s.Iops = &v + return s +} + +// SetKmsKeyId sets the KmsKeyId field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetKmsKeyId(v string) *LaunchTemplateEbsBlockDeviceRequest { + s.KmsKeyId = &v + return s +} + +// SetSnapshotId sets the SnapshotId field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetSnapshotId(v string) *LaunchTemplateEbsBlockDeviceRequest { + s.SnapshotId = &v + return s +} + +// SetVolumeSize sets the VolumeSize field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetVolumeSize(v int64) *LaunchTemplateEbsBlockDeviceRequest { + s.VolumeSize = &v + return s +} + +// SetVolumeType sets the VolumeType field's value. +func (s *LaunchTemplateEbsBlockDeviceRequest) SetVolumeType(v string) *LaunchTemplateEbsBlockDeviceRequest { + s.VolumeType = &v + return s +} + +// Describes an IAM instance profile. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateIamInstanceProfileSpecification +type LaunchTemplateIamInstanceProfileSpecification struct { + _ struct{} `type:"structure"` + + // The Amazon Resource Name (ARN) of the instance profile. + Arn *string `locationName:"arn" type:"string"` + + // The name of the instance profile. + Name *string `locationName:"name" type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateIamInstanceProfileSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateIamInstanceProfileSpecification) GoString() string { + return s.String() +} + +// SetArn sets the Arn field's value. +func (s *LaunchTemplateIamInstanceProfileSpecification) SetArn(v string) *LaunchTemplateIamInstanceProfileSpecification { + s.Arn = &v + return s +} + +// SetName sets the Name field's value. +func (s *LaunchTemplateIamInstanceProfileSpecification) SetName(v string) *LaunchTemplateIamInstanceProfileSpecification { + s.Name = &v + return s +} + +// An IAM instance profile. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateIamInstanceProfileSpecificationRequest +type LaunchTemplateIamInstanceProfileSpecificationRequest struct { + _ struct{} `type:"structure"` + + // The Amazon Resource Name (ARN) of the instance profile. + Arn *string `type:"string"` + + // The name of the instance profile. + Name *string `type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateIamInstanceProfileSpecificationRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateIamInstanceProfileSpecificationRequest) GoString() string { + return s.String() +} + +// SetArn sets the Arn field's value. +func (s *LaunchTemplateIamInstanceProfileSpecificationRequest) SetArn(v string) *LaunchTemplateIamInstanceProfileSpecificationRequest { + s.Arn = &v + return s +} + +// SetName sets the Name field's value. +func (s *LaunchTemplateIamInstanceProfileSpecificationRequest) SetName(v string) *LaunchTemplateIamInstanceProfileSpecificationRequest { + s.Name = &v + return s +} + +// The market (purchasing) option for the instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateInstanceMarketOptions +type LaunchTemplateInstanceMarketOptions struct { + _ struct{} `type:"structure"` + + // The market type. + MarketType *string `locationName:"marketType" type:"string" enum:"MarketType"` + + // The options for Spot Instances. + SpotOptions *LaunchTemplateSpotMarketOptions `locationName:"spotOptions" type:"structure"` +} + +// String returns the string representation +func (s LaunchTemplateInstanceMarketOptions) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateInstanceMarketOptions) GoString() string { + return s.String() +} + +// SetMarketType sets the MarketType field's value. +func (s *LaunchTemplateInstanceMarketOptions) SetMarketType(v string) *LaunchTemplateInstanceMarketOptions { + s.MarketType = &v + return s +} + +// SetSpotOptions sets the SpotOptions field's value. +func (s *LaunchTemplateInstanceMarketOptions) SetSpotOptions(v *LaunchTemplateSpotMarketOptions) *LaunchTemplateInstanceMarketOptions { + s.SpotOptions = v + return s +} + +// The market (purchasing) option for the instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateInstanceMarketOptionsRequest +type LaunchTemplateInstanceMarketOptionsRequest struct { + _ struct{} `type:"structure"` + + // The market type. + MarketType *string `type:"string" enum:"MarketType"` + + // The options for Spot Instances. + SpotOptions *LaunchTemplateSpotMarketOptionsRequest `type:"structure"` +} + +// String returns the string representation +func (s LaunchTemplateInstanceMarketOptionsRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateInstanceMarketOptionsRequest) GoString() string { + return s.String() +} + +// SetMarketType sets the MarketType field's value. +func (s *LaunchTemplateInstanceMarketOptionsRequest) SetMarketType(v string) *LaunchTemplateInstanceMarketOptionsRequest { + s.MarketType = &v + return s +} + +// SetSpotOptions sets the SpotOptions field's value. +func (s *LaunchTemplateInstanceMarketOptionsRequest) SetSpotOptions(v *LaunchTemplateSpotMarketOptionsRequest) *LaunchTemplateInstanceMarketOptionsRequest { + s.SpotOptions = v + return s +} + +// Describes a network interface. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateInstanceNetworkInterfaceSpecification +type LaunchTemplateInstanceNetworkInterfaceSpecification struct { + _ struct{} `type:"structure"` + + // Indicates whether to associate a public IPv4 address with eth0 for a new + // network interface. + AssociatePublicIpAddress *bool `locationName:"associatePublicIpAddress" type:"boolean"` + + // Indicates whether the network interface is deleted when the instance is terminated. + DeleteOnTermination *bool `locationName:"deleteOnTermination" type:"boolean"` + + // A description for the network interface. + Description *string `locationName:"description" type:"string"` + + // The device index for the network interface attachment. + DeviceIndex *int64 `locationName:"deviceIndex" type:"integer"` + + // The IDs of one or more security groups. + Groups []*string `locationName:"groupSet" locationNameList:"groupId" type:"list"` + + // The number of IPv6 addresses for the network interface. + Ipv6AddressCount *int64 `locationName:"ipv6AddressCount" type:"integer"` + + // The IPv6 addresses for the network interface. + Ipv6Addresses []*InstanceIpv6Address `locationName:"ipv6AddressesSet" locationNameList:"item" type:"list"` + + // The ID of the network interface. + NetworkInterfaceId *string `locationName:"networkInterfaceId" type:"string"` + + // The primary private IPv4 address of the network interface. + PrivateIpAddress *string `locationName:"privateIpAddress" type:"string"` + + // One or more private IPv4 addresses. + PrivateIpAddresses []*PrivateIpAddressSpecification `locationName:"privateIpAddressesSet" locationNameList:"item" type:"list"` + + // The number of secondary private IPv4 addresses for the network interface. + SecondaryPrivateIpAddressCount *int64 `locationName:"secondaryPrivateIpAddressCount" type:"integer"` + + // The ID of the subnet for the network interface. + SubnetId *string `locationName:"subnetId" type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateInstanceNetworkInterfaceSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateInstanceNetworkInterfaceSpecification) GoString() string { + return s.String() +} + +// SetAssociatePublicIpAddress sets the AssociatePublicIpAddress field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetAssociatePublicIpAddress(v bool) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.AssociatePublicIpAddress = &v + return s +} + +// SetDeleteOnTermination sets the DeleteOnTermination field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetDeleteOnTermination(v bool) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.DeleteOnTermination = &v + return s +} + +// SetDescription sets the Description field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetDescription(v string) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.Description = &v + return s +} + +// SetDeviceIndex sets the DeviceIndex field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetDeviceIndex(v int64) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.DeviceIndex = &v + return s +} + +// SetGroups sets the Groups field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetGroups(v []*string) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.Groups = v + return s +} + +// SetIpv6AddressCount sets the Ipv6AddressCount field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetIpv6AddressCount(v int64) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.Ipv6AddressCount = &v + return s +} + +// SetIpv6Addresses sets the Ipv6Addresses field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetIpv6Addresses(v []*InstanceIpv6Address) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.Ipv6Addresses = v + return s +} + +// SetNetworkInterfaceId sets the NetworkInterfaceId field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetNetworkInterfaceId(v string) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.NetworkInterfaceId = &v + return s +} + +// SetPrivateIpAddress sets the PrivateIpAddress field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetPrivateIpAddress(v string) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.PrivateIpAddress = &v + return s +} + +// SetPrivateIpAddresses sets the PrivateIpAddresses field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetPrivateIpAddresses(v []*PrivateIpAddressSpecification) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.PrivateIpAddresses = v + return s +} + +// SetSecondaryPrivateIpAddressCount sets the SecondaryPrivateIpAddressCount field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetSecondaryPrivateIpAddressCount(v int64) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.SecondaryPrivateIpAddressCount = &v + return s +} + +// SetSubnetId sets the SubnetId field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetSubnetId(v string) *LaunchTemplateInstanceNetworkInterfaceSpecification { + s.SubnetId = &v + return s +} + +// The parameters for a network interface. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateInstanceNetworkInterfaceSpecificationRequest +type LaunchTemplateInstanceNetworkInterfaceSpecificationRequest struct { + _ struct{} `type:"structure"` + + // Associates a public IPv4 address with eth0 for a new network interface. + AssociatePublicIpAddress *bool `type:"boolean"` + + // Indicates whether the network interface is deleted when the instance is terminated. + DeleteOnTermination *bool `type:"boolean"` + + // A description for the network interface. + Description *string `type:"string"` + + // The device index for the network interface attachment. + DeviceIndex *int64 `type:"integer"` + + // The IDs of one or more security groups. + Groups []*string `locationName:"SecurityGroupId" locationNameList:"SecurityGroupId" type:"list"` + + // The number of IPv6 addresses to assign to a network interface. Amazon EC2 + // automatically selects the IPv6 addresses from the subnet range. You can't + // use this option if specifying specific IPv6 addresses. + Ipv6AddressCount *int64 `type:"integer"` + + // One or more specific IPv6 addresses from the IPv6 CIDR block range of your + // subnet. You can't use this option if you're specifying a number of IPv6 addresses. + Ipv6Addresses []*InstanceIpv6AddressRequest `locationNameList:"InstanceIpv6Address" type:"list"` + + // The ID of the network interface. + NetworkInterfaceId *string `type:"string"` + + // The primary private IPv4 address of the network interface. + PrivateIpAddress *string `type:"string"` + + // One or more private IPv4 addresses. + PrivateIpAddresses []*PrivateIpAddressSpecification `locationNameList:"item" type:"list"` + + // The number of secondary private IPv4 addresses to assign to a network interface. + SecondaryPrivateIpAddressCount *int64 `type:"integer"` + + // The ID of the subnet for the network interface. + SubnetId *string `type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "LaunchTemplateInstanceNetworkInterfaceSpecificationRequest"} + if s.PrivateIpAddresses != nil { + for i, v := range s.PrivateIpAddresses { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "PrivateIpAddresses", i), err.(request.ErrInvalidParams)) + } + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAssociatePublicIpAddress sets the AssociatePublicIpAddress field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetAssociatePublicIpAddress(v bool) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.AssociatePublicIpAddress = &v + return s +} + +// SetDeleteOnTermination sets the DeleteOnTermination field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetDeleteOnTermination(v bool) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.DeleteOnTermination = &v + return s +} + +// SetDescription sets the Description field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetDescription(v string) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.Description = &v + return s +} + +// SetDeviceIndex sets the DeviceIndex field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetDeviceIndex(v int64) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.DeviceIndex = &v + return s +} + +// SetGroups sets the Groups field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetGroups(v []*string) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.Groups = v + return s +} + +// SetIpv6AddressCount sets the Ipv6AddressCount field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetIpv6AddressCount(v int64) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.Ipv6AddressCount = &v + return s +} + +// SetIpv6Addresses sets the Ipv6Addresses field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetIpv6Addresses(v []*InstanceIpv6AddressRequest) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.Ipv6Addresses = v + return s +} + +// SetNetworkInterfaceId sets the NetworkInterfaceId field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetNetworkInterfaceId(v string) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.NetworkInterfaceId = &v + return s +} + +// SetPrivateIpAddress sets the PrivateIpAddress field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetPrivateIpAddress(v string) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.PrivateIpAddress = &v + return s +} + +// SetPrivateIpAddresses sets the PrivateIpAddresses field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetPrivateIpAddresses(v []*PrivateIpAddressSpecification) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.PrivateIpAddresses = v + return s +} + +// SetSecondaryPrivateIpAddressCount sets the SecondaryPrivateIpAddressCount field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetSecondaryPrivateIpAddressCount(v int64) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.SecondaryPrivateIpAddressCount = &v + return s +} + +// SetSubnetId sets the SubnetId field's value. +func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetSubnetId(v string) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest { + s.SubnetId = &v + return s +} + +// Describes overrides for a launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateOverrides +type LaunchTemplateOverrides struct { + _ struct{} `type:"structure"` + + // The Availability Zone in which to launch the instances. + AvailabilityZone *string `locationName:"availabilityZone" type:"string"` + + // The instance type. + InstanceType *string `locationName:"instanceType" type:"string" enum:"InstanceType"` + + // The maximum price per unit hour that you are willing to pay for a Spot Instance. + SpotPrice *string `locationName:"spotPrice" type:"string"` + + // The ID of the subnet in which to launch the instances. + SubnetId *string `locationName:"subnetId" type:"string"` + + // The number of units provided by the specified instance type. + WeightedCapacity *float64 `locationName:"weightedCapacity" type:"double"` +} + +// String returns the string representation +func (s LaunchTemplateOverrides) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateOverrides) GoString() string { + return s.String() +} + +// SetAvailabilityZone sets the AvailabilityZone field's value. +func (s *LaunchTemplateOverrides) SetAvailabilityZone(v string) *LaunchTemplateOverrides { + s.AvailabilityZone = &v + return s +} + +// SetInstanceType sets the InstanceType field's value. +func (s *LaunchTemplateOverrides) SetInstanceType(v string) *LaunchTemplateOverrides { + s.InstanceType = &v + return s +} + +// SetSpotPrice sets the SpotPrice field's value. +func (s *LaunchTemplateOverrides) SetSpotPrice(v string) *LaunchTemplateOverrides { + s.SpotPrice = &v + return s +} + +// SetSubnetId sets the SubnetId field's value. +func (s *LaunchTemplateOverrides) SetSubnetId(v string) *LaunchTemplateOverrides { + s.SubnetId = &v + return s +} + +// SetWeightedCapacity sets the WeightedCapacity field's value. +func (s *LaunchTemplateOverrides) SetWeightedCapacity(v float64) *LaunchTemplateOverrides { + s.WeightedCapacity = &v + return s +} + +// Describes the placement of an instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplatePlacement +type LaunchTemplatePlacement struct { + _ struct{} `type:"structure"` + + // The affinity setting for the instance on the Dedicated Host. + Affinity *string `locationName:"affinity" type:"string"` + + // The Availability Zone of the instance. + AvailabilityZone *string `locationName:"availabilityZone" type:"string"` + + // The name of the placement group for the instance. + GroupName *string `locationName:"groupName" type:"string"` + + // The ID of the Dedicated Host for the instance. + HostId *string `locationName:"hostId" type:"string"` + + // Reserved for future use. + SpreadDomain *string `locationName:"spreadDomain" type:"string"` + + // The tenancy of the instance (if the instance is running in a VPC). An instance + // with a tenancy of dedicated runs on single-tenant hardware. + Tenancy *string `locationName:"tenancy" type:"string" enum:"Tenancy"` +} + +// String returns the string representation +func (s LaunchTemplatePlacement) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplatePlacement) GoString() string { + return s.String() +} + +// SetAffinity sets the Affinity field's value. +func (s *LaunchTemplatePlacement) SetAffinity(v string) *LaunchTemplatePlacement { + s.Affinity = &v + return s +} + +// SetAvailabilityZone sets the AvailabilityZone field's value. +func (s *LaunchTemplatePlacement) SetAvailabilityZone(v string) *LaunchTemplatePlacement { + s.AvailabilityZone = &v + return s +} + +// SetGroupName sets the GroupName field's value. +func (s *LaunchTemplatePlacement) SetGroupName(v string) *LaunchTemplatePlacement { + s.GroupName = &v + return s +} + +// SetHostId sets the HostId field's value. +func (s *LaunchTemplatePlacement) SetHostId(v string) *LaunchTemplatePlacement { + s.HostId = &v + return s +} + +// SetSpreadDomain sets the SpreadDomain field's value. +func (s *LaunchTemplatePlacement) SetSpreadDomain(v string) *LaunchTemplatePlacement { + s.SpreadDomain = &v + return s +} + +// SetTenancy sets the Tenancy field's value. +func (s *LaunchTemplatePlacement) SetTenancy(v string) *LaunchTemplatePlacement { + s.Tenancy = &v + return s +} + +// The placement for the instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplatePlacementRequest +type LaunchTemplatePlacementRequest struct { + _ struct{} `type:"structure"` + + // The affinity setting for an instance on a Dedicated Host. + Affinity *string `type:"string"` + + // The Availability Zone for the instance. + AvailabilityZone *string `type:"string"` + + // The name of the placement group for the instance. + GroupName *string `type:"string"` + + // The ID of the Dedicated Host for the instance. + HostId *string `type:"string"` + + // Reserved for future use. + SpreadDomain *string `type:"string"` + + // The tenancy of the instance (if the instance is running in a VPC). An instance + // with a tenancy of dedicated runs on single-tenant hardware. + Tenancy *string `type:"string" enum:"Tenancy"` +} + +// String returns the string representation +func (s LaunchTemplatePlacementRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplatePlacementRequest) GoString() string { + return s.String() +} + +// SetAffinity sets the Affinity field's value. +func (s *LaunchTemplatePlacementRequest) SetAffinity(v string) *LaunchTemplatePlacementRequest { + s.Affinity = &v + return s +} + +// SetAvailabilityZone sets the AvailabilityZone field's value. +func (s *LaunchTemplatePlacementRequest) SetAvailabilityZone(v string) *LaunchTemplatePlacementRequest { + s.AvailabilityZone = &v + return s +} + +// SetGroupName sets the GroupName field's value. +func (s *LaunchTemplatePlacementRequest) SetGroupName(v string) *LaunchTemplatePlacementRequest { + s.GroupName = &v + return s +} + +// SetHostId sets the HostId field's value. +func (s *LaunchTemplatePlacementRequest) SetHostId(v string) *LaunchTemplatePlacementRequest { + s.HostId = &v + return s +} + +// SetSpreadDomain sets the SpreadDomain field's value. +func (s *LaunchTemplatePlacementRequest) SetSpreadDomain(v string) *LaunchTemplatePlacementRequest { + s.SpreadDomain = &v + return s +} + +// SetTenancy sets the Tenancy field's value. +func (s *LaunchTemplatePlacementRequest) SetTenancy(v string) *LaunchTemplatePlacementRequest { + s.Tenancy = &v + return s +} + +// The launch template to use. You must specify either the launch template ID +// or launch template name in the request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateSpecification +type LaunchTemplateSpecification struct { + _ struct{} `type:"structure"` + + // The ID of the launch template. + LaunchTemplateId *string `type:"string"` + + // The name of the launch template. + LaunchTemplateName *string `type:"string"` + + // The version number of the launch template. + // + // Default: The default version for the launch template. + Version *string `type:"string"` +} + +// String returns the string representation +func (s LaunchTemplateSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateSpecification) GoString() string { + return s.String() +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *LaunchTemplateSpecification) SetLaunchTemplateId(v string) *LaunchTemplateSpecification { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *LaunchTemplateSpecification) SetLaunchTemplateName(v string) *LaunchTemplateSpecification { + s.LaunchTemplateName = &v + return s +} + +// SetVersion sets the Version field's value. +func (s *LaunchTemplateSpecification) SetVersion(v string) *LaunchTemplateSpecification { + s.Version = &v + return s +} + +// The options for Spot Instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateSpotMarketOptions +type LaunchTemplateSpotMarketOptions struct { + _ struct{} `type:"structure"` + + // The required duration for the Spot Instances (also known as Spot blocks), + // in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, + // or 360). + BlockDurationMinutes *int64 `locationName:"blockDurationMinutes" type:"integer"` + + // The behavior when a Spot Instance is interrupted. + InstanceInterruptionBehavior *string `locationName:"instanceInterruptionBehavior" type:"string" enum:"InstanceInterruptionBehavior"` + + // The maximum hourly price you're willing to pay for the Spot Instances. + MaxPrice *string `locationName:"maxPrice" type:"string"` + + // The Spot Instance request type. + SpotInstanceType *string `locationName:"spotInstanceType" type:"string" enum:"SpotInstanceType"` + + // The end date of the request. For a one-time request, the request remains + // active until all instances launch, the request is canceled, or this date + // is reached. If the request is persistent, it remains active until it is canceled + // or this date and time is reached. + ValidUntil *time.Time `locationName:"validUntil" type:"timestamp" timestampFormat:"iso8601"` +} + +// String returns the string representation +func (s LaunchTemplateSpotMarketOptions) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateSpotMarketOptions) GoString() string { + return s.String() +} + +// SetBlockDurationMinutes sets the BlockDurationMinutes field's value. +func (s *LaunchTemplateSpotMarketOptions) SetBlockDurationMinutes(v int64) *LaunchTemplateSpotMarketOptions { + s.BlockDurationMinutes = &v + return s +} + +// SetInstanceInterruptionBehavior sets the InstanceInterruptionBehavior field's value. +func (s *LaunchTemplateSpotMarketOptions) SetInstanceInterruptionBehavior(v string) *LaunchTemplateSpotMarketOptions { + s.InstanceInterruptionBehavior = &v + return s +} + +// SetMaxPrice sets the MaxPrice field's value. +func (s *LaunchTemplateSpotMarketOptions) SetMaxPrice(v string) *LaunchTemplateSpotMarketOptions { + s.MaxPrice = &v + return s +} + +// SetSpotInstanceType sets the SpotInstanceType field's value. +func (s *LaunchTemplateSpotMarketOptions) SetSpotInstanceType(v string) *LaunchTemplateSpotMarketOptions { + s.SpotInstanceType = &v + return s +} + +// SetValidUntil sets the ValidUntil field's value. +func (s *LaunchTemplateSpotMarketOptions) SetValidUntil(v time.Time) *LaunchTemplateSpotMarketOptions { + s.ValidUntil = &v + return s +} + +// The options for Spot Instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateSpotMarketOptionsRequest +type LaunchTemplateSpotMarketOptionsRequest struct { + _ struct{} `type:"structure"` + + // The required duration for the Spot Instances (also known as Spot blocks), + // in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, + // or 360). + BlockDurationMinutes *int64 `type:"integer"` + + // The behavior when a Spot Instance is interrupted. The default is terminate. + InstanceInterruptionBehavior *string `type:"string" enum:"InstanceInterruptionBehavior"` + + // The maximum hourly price you're willing to pay for the Spot Instances. + MaxPrice *string `type:"string"` + + // The Spot Instance request type. + SpotInstanceType *string `type:"string" enum:"SpotInstanceType"` + + // The end date of the request. For a one-time request, the request remains + // active until all instances launch, the request is canceled, or this date + // is reached. If the request is persistent, it remains active until it is canceled + // or this date and time is reached. The default end date is 7 days from the + // current date. + ValidUntil *time.Time `type:"timestamp" timestampFormat:"iso8601"` +} + +// String returns the string representation +func (s LaunchTemplateSpotMarketOptionsRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateSpotMarketOptionsRequest) GoString() string { + return s.String() +} + +// SetBlockDurationMinutes sets the BlockDurationMinutes field's value. +func (s *LaunchTemplateSpotMarketOptionsRequest) SetBlockDurationMinutes(v int64) *LaunchTemplateSpotMarketOptionsRequest { + s.BlockDurationMinutes = &v + return s +} + +// SetInstanceInterruptionBehavior sets the InstanceInterruptionBehavior field's value. +func (s *LaunchTemplateSpotMarketOptionsRequest) SetInstanceInterruptionBehavior(v string) *LaunchTemplateSpotMarketOptionsRequest { + s.InstanceInterruptionBehavior = &v + return s +} + +// SetMaxPrice sets the MaxPrice field's value. +func (s *LaunchTemplateSpotMarketOptionsRequest) SetMaxPrice(v string) *LaunchTemplateSpotMarketOptionsRequest { + s.MaxPrice = &v + return s +} + +// SetSpotInstanceType sets the SpotInstanceType field's value. +func (s *LaunchTemplateSpotMarketOptionsRequest) SetSpotInstanceType(v string) *LaunchTemplateSpotMarketOptionsRequest { + s.SpotInstanceType = &v + return s +} + +// SetValidUntil sets the ValidUntil field's value. +func (s *LaunchTemplateSpotMarketOptionsRequest) SetValidUntil(v time.Time) *LaunchTemplateSpotMarketOptionsRequest { + s.ValidUntil = &v + return s +} + +// The tag specification for the launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateTagSpecification +type LaunchTemplateTagSpecification struct { + _ struct{} `type:"structure"` + + // The type of resource. + ResourceType *string `locationName:"resourceType" type:"string" enum:"ResourceType"` + + // The tags for the resource. + Tags []*Tag `locationName:"tagSet" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s LaunchTemplateTagSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateTagSpecification) GoString() string { + return s.String() +} + +// SetResourceType sets the ResourceType field's value. +func (s *LaunchTemplateTagSpecification) SetResourceType(v string) *LaunchTemplateTagSpecification { + s.ResourceType = &v + return s +} + +// SetTags sets the Tags field's value. +func (s *LaunchTemplateTagSpecification) SetTags(v []*Tag) *LaunchTemplateTagSpecification { + s.Tags = v + return s +} + +// The tags specification for the launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateTagSpecificationRequest +type LaunchTemplateTagSpecificationRequest struct { + _ struct{} `type:"structure"` + + // The type of resource to tag. Currently, the resource types that support tagging + // on creation are instance and volume. + ResourceType *string `type:"string" enum:"ResourceType"` + + // The tags to apply to the resource. + Tags []*Tag `locationName:"Tag" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s LaunchTemplateTagSpecificationRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateTagSpecificationRequest) GoString() string { + return s.String() +} + +// SetResourceType sets the ResourceType field's value. +func (s *LaunchTemplateTagSpecificationRequest) SetResourceType(v string) *LaunchTemplateTagSpecificationRequest { + s.ResourceType = &v + return s +} + +// SetTags sets the Tags field's value. +func (s *LaunchTemplateTagSpecificationRequest) SetTags(v []*Tag) *LaunchTemplateTagSpecificationRequest { + s.Tags = v + return s +} + +// Describes a launch template version. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplateVersion +type LaunchTemplateVersion struct { + _ struct{} `type:"structure"` + + // The time the version was created. + CreateTime *time.Time `locationName:"createTime" type:"timestamp" timestampFormat:"iso8601"` + + // The principal that created the version. + CreatedBy *string `locationName:"createdBy" type:"string"` + + // Indicates whether the version is the default version. + DefaultVersion *bool `locationName:"defaultVersion" type:"boolean"` + + // Information about the launch template. + LaunchTemplateData *ResponseLaunchTemplateData `locationName:"launchTemplateData" type:"structure"` + + // The ID of the launch template. + LaunchTemplateId *string `locationName:"launchTemplateId" type:"string"` + + // The name of the launch template. + LaunchTemplateName *string `locationName:"launchTemplateName" min:"3" type:"string"` + + // The description for the version. + VersionDescription *string `locationName:"versionDescription" type:"string"` + + // The version number. + VersionNumber *int64 `locationName:"versionNumber" type:"long"` +} + +// String returns the string representation +func (s LaunchTemplateVersion) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplateVersion) GoString() string { + return s.String() +} + +// SetCreateTime sets the CreateTime field's value. +func (s *LaunchTemplateVersion) SetCreateTime(v time.Time) *LaunchTemplateVersion { + s.CreateTime = &v + return s +} + +// SetCreatedBy sets the CreatedBy field's value. +func (s *LaunchTemplateVersion) SetCreatedBy(v string) *LaunchTemplateVersion { + s.CreatedBy = &v + return s +} + +// SetDefaultVersion sets the DefaultVersion field's value. +func (s *LaunchTemplateVersion) SetDefaultVersion(v bool) *LaunchTemplateVersion { + s.DefaultVersion = &v + return s +} + +// SetLaunchTemplateData sets the LaunchTemplateData field's value. +func (s *LaunchTemplateVersion) SetLaunchTemplateData(v *ResponseLaunchTemplateData) *LaunchTemplateVersion { + s.LaunchTemplateData = v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *LaunchTemplateVersion) SetLaunchTemplateId(v string) *LaunchTemplateVersion { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *LaunchTemplateVersion) SetLaunchTemplateName(v string) *LaunchTemplateVersion { + s.LaunchTemplateName = &v + return s +} + +// SetVersionDescription sets the VersionDescription field's value. +func (s *LaunchTemplateVersion) SetVersionDescription(v string) *LaunchTemplateVersion { + s.VersionDescription = &v + return s +} + +// SetVersionNumber sets the VersionNumber field's value. +func (s *LaunchTemplateVersion) SetVersionNumber(v int64) *LaunchTemplateVersion { + s.VersionNumber = &v + return s +} + +// Describes the monitoring for the instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplatesMonitoring +type LaunchTemplatesMonitoring struct { + _ struct{} `type:"structure"` + + // Indicates whether detailed monitoring is enabled. Otherwise, basic monitoring + // is enabled. + Enabled *bool `locationName:"enabled" type:"boolean"` +} + +// String returns the string representation +func (s LaunchTemplatesMonitoring) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplatesMonitoring) GoString() string { + return s.String() +} + +// SetEnabled sets the Enabled field's value. +func (s *LaunchTemplatesMonitoring) SetEnabled(v bool) *LaunchTemplatesMonitoring { + s.Enabled = &v + return s +} + +// Describes the monitoring for the instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LaunchTemplatesMonitoringRequest +type LaunchTemplatesMonitoringRequest struct { + _ struct{} `type:"structure"` + + // Specify true to enable detailed monitoring. Otherwise, basic monitoring is + // enabled. + Enabled *bool `type:"boolean"` +} + +// String returns the string representation +func (s LaunchTemplatesMonitoringRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LaunchTemplatesMonitoringRequest) GoString() string { + return s.String() +} + +// SetEnabled sets the Enabled field's value. +func (s *LaunchTemplatesMonitoringRequest) SetEnabled(v bool) *LaunchTemplatesMonitoringRequest { + s.Enabled = &v + return s +} + +// Describes the Classic Load Balancers and target groups to attach to a Spot +// Fleet request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LoadBalancersConfig +type LoadBalancersConfig struct { + _ struct{} `type:"structure"` + + // The Classic Load Balancers. + ClassicLoadBalancersConfig *ClassicLoadBalancersConfig `locationName:"classicLoadBalancersConfig" type:"structure"` + + // The target groups. + TargetGroupsConfig *TargetGroupsConfig `locationName:"targetGroupsConfig" type:"structure"` +} + +// String returns the string representation +func (s LoadBalancersConfig) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LoadBalancersConfig) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *LoadBalancersConfig) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "LoadBalancersConfig"} + if s.ClassicLoadBalancersConfig != nil { + if err := s.ClassicLoadBalancersConfig.Validate(); err != nil { + invalidParams.AddNested("ClassicLoadBalancersConfig", err.(request.ErrInvalidParams)) + } + } + if s.TargetGroupsConfig != nil { + if err := s.TargetGroupsConfig.Validate(); err != nil { + invalidParams.AddNested("TargetGroupsConfig", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClassicLoadBalancersConfig sets the ClassicLoadBalancersConfig field's value. +func (s *LoadBalancersConfig) SetClassicLoadBalancersConfig(v *ClassicLoadBalancersConfig) *LoadBalancersConfig { + s.ClassicLoadBalancersConfig = v + return s +} + +// SetTargetGroupsConfig sets the TargetGroupsConfig field's value. +func (s *LoadBalancersConfig) SetTargetGroupsConfig(v *TargetGroupsConfig) *LoadBalancersConfig { + s.TargetGroupsConfig = v + return s +} + +// Describes a load permission. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LoadPermission +type LoadPermission struct { + _ struct{} `type:"structure"` + + // The name of the group. + Group *string `locationName:"group" type:"string" enum:"PermissionGroup"` + + // The AWS account ID. + UserId *string `locationName:"userId" type:"string"` +} + +// String returns the string representation +func (s LoadPermission) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LoadPermission) GoString() string { + return s.String() +} + +// SetGroup sets the Group field's value. +func (s *LoadPermission) SetGroup(v string) *LoadPermission { + s.Group = &v + return s +} + +// SetUserId sets the UserId field's value. +func (s *LoadPermission) SetUserId(v string) *LoadPermission { + s.UserId = &v + return s +} + +// Describes modifications to the load permissions of an Amazon FPGA image (AFI). +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LoadPermissionModifications +type LoadPermissionModifications struct { + _ struct{} `type:"structure"` + + // The load permissions to add. + Add []*LoadPermissionRequest `locationNameList:"item" type:"list"` + + // The load permissions to remove. + Remove []*LoadPermissionRequest `locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s LoadPermissionModifications) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LoadPermissionModifications) GoString() string { + return s.String() +} + +// SetAdd sets the Add field's value. +func (s *LoadPermissionModifications) SetAdd(v []*LoadPermissionRequest) *LoadPermissionModifications { + s.Add = v + return s +} + +// SetRemove sets the Remove field's value. +func (s *LoadPermissionModifications) SetRemove(v []*LoadPermissionRequest) *LoadPermissionModifications { + s.Remove = v + return s +} + +// Describes a load permission. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/LoadPermissionRequest +type LoadPermissionRequest struct { + _ struct{} `type:"structure"` + + // The name of the group. + Group *string `type:"string" enum:"PermissionGroup"` + + // The AWS account ID. + UserId *string `type:"string"` +} + +// String returns the string representation +func (s LoadPermissionRequest) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s LoadPermissionRequest) GoString() string { + return s.String() +} + +// SetGroup sets the Group field's value. +func (s *LoadPermissionRequest) SetGroup(v string) *LoadPermissionRequest { + s.Group = &v + return s +} + +// SetUserId sets the UserId field's value. +func (s *LoadPermissionRequest) SetUserId(v string) *LoadPermissionRequest { + s.UserId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyFpgaImageAttributeRequest +type ModifyFpgaImageAttributeInput struct { + _ struct{} `type:"structure"` + + // The name of the attribute. + Attribute *string `type:"string" enum:"FpgaImageAttributeName"` + + // A description for the AFI. + Description *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the AFI. + // + // FpgaImageId is a required field + FpgaImageId *string `type:"string" required:"true"` + + // The load permission for the AFI. + LoadPermission *LoadPermissionModifications `type:"structure"` + + // A name for the AFI. + Name *string `type:"string"` + + // The operation type. + OperationType *string `type:"string" enum:"OperationType"` + + // One or more product codes. After you add a product code to an AFI, it can't + // be removed. This parameter is valid only when modifying the productCodes + // attribute. + ProductCodes []*string `locationName:"ProductCode" locationNameList:"ProductCode" type:"list"` + + // One or more user groups. This parameter is valid only when modifying the + // loadPermission attribute. + UserGroups []*string `locationName:"UserGroup" locationNameList:"UserGroup" type:"list"` + + // One or more AWS account IDs. This parameter is valid only when modifying + // the loadPermission attribute. + UserIds []*string `locationName:"UserId" locationNameList:"UserId" type:"list"` +} + +// String returns the string representation +func (s ModifyFpgaImageAttributeInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyFpgaImageAttributeInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyFpgaImageAttributeInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyFpgaImageAttributeInput"} + if s.FpgaImageId == nil { + invalidParams.Add(request.NewErrParamRequired("FpgaImageId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAttribute sets the Attribute field's value. +func (s *ModifyFpgaImageAttributeInput) SetAttribute(v string) *ModifyFpgaImageAttributeInput { + s.Attribute = &v + return s +} + +// SetDescription sets the Description field's value. +func (s *ModifyFpgaImageAttributeInput) SetDescription(v string) *ModifyFpgaImageAttributeInput { + s.Description = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyFpgaImageAttributeInput) SetDryRun(v bool) *ModifyFpgaImageAttributeInput { + s.DryRun = &v + return s +} + +// SetFpgaImageId sets the FpgaImageId field's value. +func (s *ModifyFpgaImageAttributeInput) SetFpgaImageId(v string) *ModifyFpgaImageAttributeInput { + s.FpgaImageId = &v + return s +} + +// SetLoadPermission sets the LoadPermission field's value. +func (s *ModifyFpgaImageAttributeInput) SetLoadPermission(v *LoadPermissionModifications) *ModifyFpgaImageAttributeInput { + s.LoadPermission = v + return s +} + +// SetName sets the Name field's value. +func (s *ModifyFpgaImageAttributeInput) SetName(v string) *ModifyFpgaImageAttributeInput { + s.Name = &v + return s +} + +// SetOperationType sets the OperationType field's value. +func (s *ModifyFpgaImageAttributeInput) SetOperationType(v string) *ModifyFpgaImageAttributeInput { + s.OperationType = &v + return s +} + +// SetProductCodes sets the ProductCodes field's value. +func (s *ModifyFpgaImageAttributeInput) SetProductCodes(v []*string) *ModifyFpgaImageAttributeInput { + s.ProductCodes = v + return s +} + +// SetUserGroups sets the UserGroups field's value. +func (s *ModifyFpgaImageAttributeInput) SetUserGroups(v []*string) *ModifyFpgaImageAttributeInput { + s.UserGroups = v + return s +} + +// SetUserIds sets the UserIds field's value. +func (s *ModifyFpgaImageAttributeInput) SetUserIds(v []*string) *ModifyFpgaImageAttributeInput { + s.UserIds = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyFpgaImageAttributeResult +type ModifyFpgaImageAttributeOutput struct { + _ struct{} `type:"structure"` + + // Information about the attribute. + FpgaImageAttribute *FpgaImageAttribute `locationName:"fpgaImageAttribute" type:"structure"` +} + +// String returns the string representation +func (s ModifyFpgaImageAttributeOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyFpgaImageAttributeOutput) GoString() string { + return s.String() +} + +// SetFpgaImageAttribute sets the FpgaImageAttribute field's value. +func (s *ModifyFpgaImageAttributeOutput) SetFpgaImageAttribute(v *FpgaImageAttribute) *ModifyFpgaImageAttributeOutput { + s.FpgaImageAttribute = v + return s +} + // Contains the parameters for ModifyHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHostsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHostsRequest type ModifyHostsInput struct { _ struct{} `type:"structure"` @@ -44616,7 +51831,7 @@ func (s *ModifyHostsInput) SetHostIds(v []*string) *ModifyHostsInput { } // Contains the output of ModifyHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHostsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyHostsResult type ModifyHostsOutput struct { _ struct{} `type:"structure"` @@ -44651,7 +51866,7 @@ func (s *ModifyHostsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *ModifyHostsO } // Contains the parameters of ModifyIdFormat. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormatRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormatRequest type ModifyIdFormatInput struct { _ struct{} `type:"structure"` @@ -44704,7 +51919,7 @@ func (s *ModifyIdFormatInput) SetUseLongIds(v bool) *ModifyIdFormatInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormatOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdFormatOutput type ModifyIdFormatOutput struct { _ struct{} `type:"structure"` } @@ -44720,7 +51935,7 @@ func (s ModifyIdFormatOutput) GoString() string { } // Contains the parameters of ModifyIdentityIdFormat. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormatRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormatRequest type ModifyIdentityIdFormatInput struct { _ struct{} `type:"structure"` @@ -44789,7 +52004,7 @@ func (s *ModifyIdentityIdFormatInput) SetUseLongIds(v bool) *ModifyIdentityIdFor return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormatOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyIdentityIdFormatOutput type ModifyIdentityIdFormatOutput struct { _ struct{} `type:"structure"` } @@ -44805,14 +52020,15 @@ func (s ModifyIdentityIdFormatOutput) GoString() string { } // Contains the parameters for ModifyImageAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttributeRequest type ModifyImageAttributeInput struct { _ struct{} `type:"structure"` - // The name of the attribute to modify. + // The name of the attribute to modify. The valid values are description, launchPermission, + // and productCodes. Attribute *string `type:"string"` - // A description for the AMI. + // A new description for the AMI. Description *AttributeValue `type:"structure"` // Checks whether you have the required permissions for the action, without @@ -44826,26 +52042,27 @@ type ModifyImageAttributeInput struct { // ImageId is a required field ImageId *string `type:"string" required:"true"` - // A launch permission modification. + // A new launch permission for the AMI. LaunchPermission *LaunchPermissionModifications `type:"structure"` - // The operation type. + // The operation type. This parameter can be used only when the Attribute parameter + // is launchPermission. OperationType *string `type:"string" enum:"OperationType"` - // One or more product codes. After you add a product code to an AMI, it can't - // be removed. This is only valid when modifying the productCodes attribute. + // One or more DevPay product codes. After you add a product code to an AMI, + // it can't be removed. ProductCodes []*string `locationName:"ProductCode" locationNameList:"ProductCode" type:"list"` - // One or more user groups. This is only valid when modifying the launchPermission - // attribute. + // One or more user groups. This parameter can be used only when the Attribute + // parameter is launchPermission. UserGroups []*string `locationName:"UserGroup" locationNameList:"UserGroup" type:"list"` - // One or more AWS account IDs. This is only valid when modifying the launchPermission - // attribute. + // One or more AWS account IDs. This parameter can be used only when the Attribute + // parameter is launchPermission. UserIds []*string `locationName:"UserId" locationNameList:"UserId" type:"list"` - // The value of the attribute being modified. This is only valid when modifying - // the description attribute. + // The value of the attribute being modified. This parameter can be used only + // when the Attribute parameter is description or productCodes. Value *string `type:"string"` } @@ -44932,7 +52149,7 @@ func (s *ModifyImageAttributeInput) SetValue(v string) *ModifyImageAttributeInpu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyImageAttributeOutput type ModifyImageAttributeOutput struct { _ struct{} `type:"structure"` } @@ -44948,7 +52165,7 @@ func (s ModifyImageAttributeOutput) GoString() string { } // Contains the parameters for ModifyInstanceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttributeRequest type ModifyInstanceAttributeInput struct { _ struct{} `type:"structure"` @@ -44977,7 +52194,7 @@ type ModifyInstanceAttributeInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // Specifies whether the instance is optimized for EBS I/O. This optimization + // Specifies whether the instance is optimized for Amazon EBS I/O. This optimization // provides dedicated throughput to Amazon EBS and an optimized configuration // stack to provide optimal EBS I/O performance. This optimization isn't available // with all instance types. Additional usage charges apply when using an EBS @@ -45020,8 +52237,8 @@ type ModifyInstanceAttributeInput struct { Ramdisk *AttributeValue `locationName:"ramdisk" type:"structure"` // Specifies whether source/destination checking is enabled. A value of true - // means that checking is enabled, and false means checking is disabled. This - // value must be false for a NAT instance to perform NAT. + // means that checking is enabled, and false means that checking is disabled. + // This value must be false for a NAT instance to perform NAT. SourceDestCheck *AttributeBooleanValue `type:"structure"` // Set to simple to enable enhanced networking with the Intel 82599 Virtual @@ -45035,8 +52252,8 @@ type ModifyInstanceAttributeInput struct { SriovNetSupport *AttributeValue `locationName:"sriovNetSupport" type:"structure"` // Changes the instance's user data to the specified value. If you are using - // an AWS SDK or command line tool, Base64-encoding is performed for you, and - // you can load the text from a file. Otherwise, you must provide Base64-encoded + // an AWS SDK or command line tool, base64-encoding is performed for you, and + // you can load the text from a file. Otherwise, you must provide base64-encoded // text. UserData *BlobAttributeValue `locationName:"userData" type:"structure"` @@ -45164,7 +52381,7 @@ func (s *ModifyInstanceAttributeInput) SetValue(v string) *ModifyInstanceAttribu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceAttributeOutput type ModifyInstanceAttributeOutput struct { _ struct{} `type:"structure"` } @@ -45179,8 +52396,105 @@ func (s ModifyInstanceAttributeOutput) GoString() string { return s.String() } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceCreditSpecificationRequest +type ModifyInstanceCreditSpecificationInput struct { + _ struct{} `type:"structure"` + + // A unique, case-sensitive token that you provide to ensure idempotency of + // your modification request. For more information, see Ensuring Idempotency + // (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // Information about the credit option for CPU usage. + // + // InstanceCreditSpecifications is a required field + InstanceCreditSpecifications []*InstanceCreditSpecificationRequest `locationName:"InstanceCreditSpecification" locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s ModifyInstanceCreditSpecificationInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyInstanceCreditSpecificationInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyInstanceCreditSpecificationInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyInstanceCreditSpecificationInput"} + if s.InstanceCreditSpecifications == nil { + invalidParams.Add(request.NewErrParamRequired("InstanceCreditSpecifications")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClientToken sets the ClientToken field's value. +func (s *ModifyInstanceCreditSpecificationInput) SetClientToken(v string) *ModifyInstanceCreditSpecificationInput { + s.ClientToken = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyInstanceCreditSpecificationInput) SetDryRun(v bool) *ModifyInstanceCreditSpecificationInput { + s.DryRun = &v + return s +} + +// SetInstanceCreditSpecifications sets the InstanceCreditSpecifications field's value. +func (s *ModifyInstanceCreditSpecificationInput) SetInstanceCreditSpecifications(v []*InstanceCreditSpecificationRequest) *ModifyInstanceCreditSpecificationInput { + s.InstanceCreditSpecifications = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstanceCreditSpecificationResult +type ModifyInstanceCreditSpecificationOutput struct { + _ struct{} `type:"structure"` + + // Information about the instances whose credit option for CPU usage was successfully + // modified. + SuccessfulInstanceCreditSpecifications []*SuccessfulInstanceCreditSpecificationItem `locationName:"successfulInstanceCreditSpecificationSet" locationNameList:"item" type:"list"` + + // Information about the instances whose credit option for CPU usage was not + // modified. + UnsuccessfulInstanceCreditSpecifications []*UnsuccessfulInstanceCreditSpecificationItem `locationName:"unsuccessfulInstanceCreditSpecificationSet" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s ModifyInstanceCreditSpecificationOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyInstanceCreditSpecificationOutput) GoString() string { + return s.String() +} + +// SetSuccessfulInstanceCreditSpecifications sets the SuccessfulInstanceCreditSpecifications field's value. +func (s *ModifyInstanceCreditSpecificationOutput) SetSuccessfulInstanceCreditSpecifications(v []*SuccessfulInstanceCreditSpecificationItem) *ModifyInstanceCreditSpecificationOutput { + s.SuccessfulInstanceCreditSpecifications = v + return s +} + +// SetUnsuccessfulInstanceCreditSpecifications sets the UnsuccessfulInstanceCreditSpecifications field's value. +func (s *ModifyInstanceCreditSpecificationOutput) SetUnsuccessfulInstanceCreditSpecifications(v []*UnsuccessfulInstanceCreditSpecificationItem) *ModifyInstanceCreditSpecificationOutput { + s.UnsuccessfulInstanceCreditSpecifications = v + return s +} + // Contains the parameters for ModifyInstancePlacement. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacementRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacementRequest type ModifyInstancePlacementInput struct { _ struct{} `type:"structure"` @@ -45247,7 +52561,7 @@ func (s *ModifyInstancePlacementInput) SetTenancy(v string) *ModifyInstancePlace } // Contains the output of ModifyInstancePlacement. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacementResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyInstancePlacementResult type ModifyInstancePlacementOutput struct { _ struct{} `type:"structure"` @@ -45271,8 +52585,111 @@ func (s *ModifyInstancePlacementOutput) SetReturn(v bool) *ModifyInstancePlaceme return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyLaunchTemplateRequest +type ModifyLaunchTemplateInput struct { + _ struct{} `type:"structure"` + + // Unique, case-sensitive identifier you provide to ensure the idempotency of + // the request. For more information, see Ensuring Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html). + ClientToken *string `type:"string"` + + // The version number of the launch template to set as the default version. + DefaultVersion *string `locationName:"SetDefaultVersion" type:"string"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateId *string `type:"string"` + + // The name of the launch template. You must specify either the launch template + // ID or launch template name in the request. + LaunchTemplateName *string `min:"3" type:"string"` +} + +// String returns the string representation +func (s ModifyLaunchTemplateInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyLaunchTemplateInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyLaunchTemplateInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyLaunchTemplateInput"} + if s.LaunchTemplateName != nil && len(*s.LaunchTemplateName) < 3 { + invalidParams.Add(request.NewErrParamMinLen("LaunchTemplateName", 3)) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetClientToken sets the ClientToken field's value. +func (s *ModifyLaunchTemplateInput) SetClientToken(v string) *ModifyLaunchTemplateInput { + s.ClientToken = &v + return s +} + +// SetDefaultVersion sets the DefaultVersion field's value. +func (s *ModifyLaunchTemplateInput) SetDefaultVersion(v string) *ModifyLaunchTemplateInput { + s.DefaultVersion = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyLaunchTemplateInput) SetDryRun(v bool) *ModifyLaunchTemplateInput { + s.DryRun = &v + return s +} + +// SetLaunchTemplateId sets the LaunchTemplateId field's value. +func (s *ModifyLaunchTemplateInput) SetLaunchTemplateId(v string) *ModifyLaunchTemplateInput { + s.LaunchTemplateId = &v + return s +} + +// SetLaunchTemplateName sets the LaunchTemplateName field's value. +func (s *ModifyLaunchTemplateInput) SetLaunchTemplateName(v string) *ModifyLaunchTemplateInput { + s.LaunchTemplateName = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyLaunchTemplateResult +type ModifyLaunchTemplateOutput struct { + _ struct{} `type:"structure"` + + // Information about the launch template. + LaunchTemplate *LaunchTemplate `locationName:"launchTemplate" type:"structure"` +} + +// String returns the string representation +func (s ModifyLaunchTemplateOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyLaunchTemplateOutput) GoString() string { + return s.String() +} + +// SetLaunchTemplate sets the LaunchTemplate field's value. +func (s *ModifyLaunchTemplateOutput) SetLaunchTemplate(v *LaunchTemplate) *ModifyLaunchTemplateOutput { + s.LaunchTemplate = v + return s +} + // Contains the parameters for ModifyNetworkInterfaceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttributeRequest type ModifyNetworkInterfaceAttributeInput struct { _ struct{} `type:"structure"` @@ -45367,7 +52784,7 @@ func (s *ModifyNetworkInterfaceAttributeInput) SetSourceDestCheck(v *AttributeBo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyNetworkInterfaceAttributeOutput type ModifyNetworkInterfaceAttributeOutput struct { _ struct{} `type:"structure"` } @@ -45383,7 +52800,7 @@ func (s ModifyNetworkInterfaceAttributeOutput) GoString() string { } // Contains the parameters for ModifyReservedInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstancesRequest type ModifyReservedInstancesInput struct { _ struct{} `type:"structure"` @@ -45447,7 +52864,7 @@ func (s *ModifyReservedInstancesInput) SetTargetConfigurations(v []*ReservedInst } // Contains the output of ModifyReservedInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyReservedInstancesResult type ModifyReservedInstancesOutput struct { _ struct{} `type:"structure"` @@ -45472,7 +52889,7 @@ func (s *ModifyReservedInstancesOutput) SetReservedInstancesModificationId(v str } // Contains the parameters for ModifySnapshotAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttributeRequest type ModifySnapshotAttributeInput struct { _ struct{} `type:"structure"` @@ -45570,7 +52987,7 @@ func (s *ModifySnapshotAttributeInput) SetUserIds(v []*string) *ModifySnapshotAt return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySnapshotAttributeOutput type ModifySnapshotAttributeOutput struct { _ struct{} `type:"structure"` } @@ -45586,16 +53003,16 @@ func (s ModifySnapshotAttributeOutput) GoString() string { } // Contains the parameters for ModifySpotFleetRequest. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequestRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequestRequest type ModifySpotFleetRequestInput struct { _ struct{} `type:"structure"` - // Indicates whether running Spot instances should be terminated if the target - // capacity of the Spot fleet request is decreased below the current size of - // the Spot fleet. + // Indicates whether running Spot Instances should be terminated if the target + // capacity of the Spot Fleet request is decreased below the current size of + // the Spot Fleet. ExcessCapacityTerminationPolicy *string `locationName:"excessCapacityTerminationPolicy" type:"string" enum:"ExcessCapacityTerminationPolicy"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -45646,7 +53063,7 @@ func (s *ModifySpotFleetRequestInput) SetTargetCapacity(v int64) *ModifySpotFlee } // Contains the output of ModifySpotFleetRequest. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequestResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySpotFleetRequestResponse type ModifySpotFleetRequestOutput struct { _ struct{} `type:"structure"` @@ -45671,7 +53088,7 @@ func (s *ModifySpotFleetRequestOutput) SetReturn(v bool) *ModifySpotFleetRequest } // Contains the parameters for ModifySubnetAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttributeRequest type ModifySubnetAttributeInput struct { _ struct{} `type:"structure"` @@ -45738,7 +53155,7 @@ func (s *ModifySubnetAttributeInput) SetSubnetId(v string) *ModifySubnetAttribut return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifySubnetAttributeOutput type ModifySubnetAttributeOutput struct { _ struct{} `type:"structure"` } @@ -45754,7 +53171,7 @@ func (s ModifySubnetAttributeOutput) GoString() string { } // Contains the parameters for ModifyVolumeAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttributeRequest type ModifyVolumeAttributeInput struct { _ struct{} `type:"structure"` @@ -45814,7 +53231,7 @@ func (s *ModifyVolumeAttributeInput) SetVolumeId(v string) *ModifyVolumeAttribut return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeAttributeOutput type ModifyVolumeAttributeOutput struct { _ struct{} `type:"structure"` } @@ -45829,7 +53246,7 @@ func (s ModifyVolumeAttributeOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeRequest type ModifyVolumeInput struct { _ struct{} `type:"structure"` @@ -45921,7 +53338,7 @@ func (s *ModifyVolumeInput) SetVolumeType(v string) *ModifyVolumeInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVolumeResult type ModifyVolumeOutput struct { _ struct{} `type:"structure"` @@ -45946,7 +53363,7 @@ func (s *ModifyVolumeOutput) SetVolumeModification(v *VolumeModification) *Modif } // Contains the parameters for ModifyVpcAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttributeRequest type ModifyVpcAttributeInput struct { _ struct{} `type:"structure"` @@ -46015,7 +53432,7 @@ func (s *ModifyVpcAttributeInput) SetVpcId(v string) *ModifyVpcAttributeInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcAttributeOutput type ModifyVpcAttributeOutput struct { _ struct{} `type:"structure"` } @@ -46030,29 +53447,141 @@ func (s ModifyVpcAttributeOutput) GoString() string { return s.String() } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointConnectionNotificationRequest +type ModifyVpcEndpointConnectionNotificationInput struct { + _ struct{} `type:"structure"` + + // One or more events for the endpoint. Valid values are Accept, Connect, Delete, + // and Reject. + ConnectionEvents []*string `locationNameList:"item" type:"list"` + + // The ARN for the SNS topic for the notification. + ConnectionNotificationArn *string `type:"string"` + + // The ID of the notification. + // + // ConnectionNotificationId is a required field + ConnectionNotificationId *string `type:"string" required:"true"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` +} + +// String returns the string representation +func (s ModifyVpcEndpointConnectionNotificationInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcEndpointConnectionNotificationInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyVpcEndpointConnectionNotificationInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyVpcEndpointConnectionNotificationInput"} + if s.ConnectionNotificationId == nil { + invalidParams.Add(request.NewErrParamRequired("ConnectionNotificationId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetConnectionEvents sets the ConnectionEvents field's value. +func (s *ModifyVpcEndpointConnectionNotificationInput) SetConnectionEvents(v []*string) *ModifyVpcEndpointConnectionNotificationInput { + s.ConnectionEvents = v + return s +} + +// SetConnectionNotificationArn sets the ConnectionNotificationArn field's value. +func (s *ModifyVpcEndpointConnectionNotificationInput) SetConnectionNotificationArn(v string) *ModifyVpcEndpointConnectionNotificationInput { + s.ConnectionNotificationArn = &v + return s +} + +// SetConnectionNotificationId sets the ConnectionNotificationId field's value. +func (s *ModifyVpcEndpointConnectionNotificationInput) SetConnectionNotificationId(v string) *ModifyVpcEndpointConnectionNotificationInput { + s.ConnectionNotificationId = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyVpcEndpointConnectionNotificationInput) SetDryRun(v bool) *ModifyVpcEndpointConnectionNotificationInput { + s.DryRun = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointConnectionNotificationResult +type ModifyVpcEndpointConnectionNotificationOutput struct { + _ struct{} `type:"structure"` + + // Returns true if the request succeeds; otherwise, it returns an error. + ReturnValue *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s ModifyVpcEndpointConnectionNotificationOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcEndpointConnectionNotificationOutput) GoString() string { + return s.String() +} + +// SetReturnValue sets the ReturnValue field's value. +func (s *ModifyVpcEndpointConnectionNotificationOutput) SetReturnValue(v bool) *ModifyVpcEndpointConnectionNotificationOutput { + s.ReturnValue = &v + return s +} + // Contains the parameters for ModifyVpcEndpoint. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointRequest type ModifyVpcEndpointInput struct { _ struct{} `type:"structure"` - // One or more route tables IDs to associate with the endpoint. + // (Gateway endpoint) One or more route tables IDs to associate with the endpoint. AddRouteTableIds []*string `locationName:"AddRouteTableId" locationNameList:"item" type:"list"` + // (Interface endpoint) One or more security group IDs to associate with the + // network interface. + AddSecurityGroupIds []*string `locationName:"AddSecurityGroupId" locationNameList:"item" type:"list"` + + // (Interface endpoint) One or more subnet IDs in which to serve the endpoint. + AddSubnetIds []*string `locationName:"AddSubnetId" locationNameList:"item" type:"list"` + // Checks whether you have the required permissions for the action, without // actually making the request, and provides an error response. If you have // the required permissions, the error response is DryRunOperation. Otherwise, // it is UnauthorizedOperation. DryRun *bool `type:"boolean"` - // A policy document to attach to the endpoint. The policy must be in valid - // JSON format. + // (Gateway endpoint) A policy document to attach to the endpoint. The policy + // must be in valid JSON format. PolicyDocument *string `type:"string"` - // One or more route table IDs to disassociate from the endpoint. + // (Interface endpoint) Indicate whether a private hosted zone is associated + // with the VPC. + PrivateDnsEnabled *bool `type:"boolean"` + + // (Gateway endpoint) One or more route table IDs to disassociate from the endpoint. RemoveRouteTableIds []*string `locationName:"RemoveRouteTableId" locationNameList:"item" type:"list"` - // Specify true to reset the policy document to the default policy. The default - // policy allows access to the service. + // (Interface endpoint) One or more security group IDs to disassociate from + // the network interface. + RemoveSecurityGroupIds []*string `locationName:"RemoveSecurityGroupId" locationNameList:"item" type:"list"` + + // (Interface endpoint) One or more subnets IDs in which to remove the endpoint. + RemoveSubnetIds []*string `locationName:"RemoveSubnetId" locationNameList:"item" type:"list"` + + // (Gateway endpoint) Specify true to reset the policy document to the default + // policy. The default policy allows full access to the service. ResetPolicy *bool `type:"boolean"` // The ID of the endpoint. @@ -46090,6 +53619,18 @@ func (s *ModifyVpcEndpointInput) SetAddRouteTableIds(v []*string) *ModifyVpcEndp return s } +// SetAddSecurityGroupIds sets the AddSecurityGroupIds field's value. +func (s *ModifyVpcEndpointInput) SetAddSecurityGroupIds(v []*string) *ModifyVpcEndpointInput { + s.AddSecurityGroupIds = v + return s +} + +// SetAddSubnetIds sets the AddSubnetIds field's value. +func (s *ModifyVpcEndpointInput) SetAddSubnetIds(v []*string) *ModifyVpcEndpointInput { + s.AddSubnetIds = v + return s +} + // SetDryRun sets the DryRun field's value. func (s *ModifyVpcEndpointInput) SetDryRun(v bool) *ModifyVpcEndpointInput { s.DryRun = &v @@ -46102,12 +53643,30 @@ func (s *ModifyVpcEndpointInput) SetPolicyDocument(v string) *ModifyVpcEndpointI return s } +// SetPrivateDnsEnabled sets the PrivateDnsEnabled field's value. +func (s *ModifyVpcEndpointInput) SetPrivateDnsEnabled(v bool) *ModifyVpcEndpointInput { + s.PrivateDnsEnabled = &v + return s +} + // SetRemoveRouteTableIds sets the RemoveRouteTableIds field's value. func (s *ModifyVpcEndpointInput) SetRemoveRouteTableIds(v []*string) *ModifyVpcEndpointInput { s.RemoveRouteTableIds = v return s } +// SetRemoveSecurityGroupIds sets the RemoveSecurityGroupIds field's value. +func (s *ModifyVpcEndpointInput) SetRemoveSecurityGroupIds(v []*string) *ModifyVpcEndpointInput { + s.RemoveSecurityGroupIds = v + return s +} + +// SetRemoveSubnetIds sets the RemoveSubnetIds field's value. +func (s *ModifyVpcEndpointInput) SetRemoveSubnetIds(v []*string) *ModifyVpcEndpointInput { + s.RemoveSubnetIds = v + return s +} + // SetResetPolicy sets the ResetPolicy field's value. func (s *ModifyVpcEndpointInput) SetResetPolicy(v bool) *ModifyVpcEndpointInput { s.ResetPolicy = &v @@ -46120,8 +53679,7 @@ func (s *ModifyVpcEndpointInput) SetVpcEndpointId(v string) *ModifyVpcEndpointIn return s } -// Contains the output of ModifyVpcEndpoint. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointResult type ModifyVpcEndpointOutput struct { _ struct{} `type:"structure"` @@ -46145,7 +53703,206 @@ func (s *ModifyVpcEndpointOutput) SetReturn(v bool) *ModifyVpcEndpointOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServiceConfigurationRequest +type ModifyVpcEndpointServiceConfigurationInput struct { + _ struct{} `type:"structure"` + + // Indicate whether requests to create an endpoint to your service must be accepted. + AcceptanceRequired *bool `type:"boolean"` + + // The Amazon Resource Names (ARNs) of Network Load Balancers to add to your + // service configuration. + AddNetworkLoadBalancerArns []*string `locationName:"addNetworkLoadBalancerArn" locationNameList:"item" type:"list"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The Amazon Resource Names (ARNs) of Network Load Balancers to remove from + // your service configuration. + RemoveNetworkLoadBalancerArns []*string `locationName:"removeNetworkLoadBalancerArn" locationNameList:"item" type:"list"` + + // The ID of the service. + // + // ServiceId is a required field + ServiceId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s ModifyVpcEndpointServiceConfigurationInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcEndpointServiceConfigurationInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyVpcEndpointServiceConfigurationInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyVpcEndpointServiceConfigurationInput"} + if s.ServiceId == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAcceptanceRequired sets the AcceptanceRequired field's value. +func (s *ModifyVpcEndpointServiceConfigurationInput) SetAcceptanceRequired(v bool) *ModifyVpcEndpointServiceConfigurationInput { + s.AcceptanceRequired = &v + return s +} + +// SetAddNetworkLoadBalancerArns sets the AddNetworkLoadBalancerArns field's value. +func (s *ModifyVpcEndpointServiceConfigurationInput) SetAddNetworkLoadBalancerArns(v []*string) *ModifyVpcEndpointServiceConfigurationInput { + s.AddNetworkLoadBalancerArns = v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyVpcEndpointServiceConfigurationInput) SetDryRun(v bool) *ModifyVpcEndpointServiceConfigurationInput { + s.DryRun = &v + return s +} + +// SetRemoveNetworkLoadBalancerArns sets the RemoveNetworkLoadBalancerArns field's value. +func (s *ModifyVpcEndpointServiceConfigurationInput) SetRemoveNetworkLoadBalancerArns(v []*string) *ModifyVpcEndpointServiceConfigurationInput { + s.RemoveNetworkLoadBalancerArns = v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *ModifyVpcEndpointServiceConfigurationInput) SetServiceId(v string) *ModifyVpcEndpointServiceConfigurationInput { + s.ServiceId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServiceConfigurationResult +type ModifyVpcEndpointServiceConfigurationOutput struct { + _ struct{} `type:"structure"` + + // Returns true if the request succeeds; otherwise, it returns an error. + Return *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s ModifyVpcEndpointServiceConfigurationOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcEndpointServiceConfigurationOutput) GoString() string { + return s.String() +} + +// SetReturn sets the Return field's value. +func (s *ModifyVpcEndpointServiceConfigurationOutput) SetReturn(v bool) *ModifyVpcEndpointServiceConfigurationOutput { + s.Return = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServicePermissionsRequest +type ModifyVpcEndpointServicePermissionsInput struct { + _ struct{} `type:"structure"` + + // One or more Amazon Resource Names (ARNs) of principals for which to allow + // permission. Specify * to allow all principals. + AddAllowedPrincipals []*string `locationNameList:"item" type:"list"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // One or more Amazon Resource Names (ARNs) of principals for which to remove + // permission. + RemoveAllowedPrincipals []*string `locationNameList:"item" type:"list"` + + // The ID of the service. + // + // ServiceId is a required field + ServiceId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s ModifyVpcEndpointServicePermissionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcEndpointServicePermissionsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyVpcEndpointServicePermissionsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyVpcEndpointServicePermissionsInput"} + if s.ServiceId == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAddAllowedPrincipals sets the AddAllowedPrincipals field's value. +func (s *ModifyVpcEndpointServicePermissionsInput) SetAddAllowedPrincipals(v []*string) *ModifyVpcEndpointServicePermissionsInput { + s.AddAllowedPrincipals = v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyVpcEndpointServicePermissionsInput) SetDryRun(v bool) *ModifyVpcEndpointServicePermissionsInput { + s.DryRun = &v + return s +} + +// SetRemoveAllowedPrincipals sets the RemoveAllowedPrincipals field's value. +func (s *ModifyVpcEndpointServicePermissionsInput) SetRemoveAllowedPrincipals(v []*string) *ModifyVpcEndpointServicePermissionsInput { + s.RemoveAllowedPrincipals = v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *ModifyVpcEndpointServicePermissionsInput) SetServiceId(v string) *ModifyVpcEndpointServicePermissionsInput { + s.ServiceId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcEndpointServicePermissionsResult +type ModifyVpcEndpointServicePermissionsOutput struct { + _ struct{} `type:"structure"` + + // Returns true if the request succeeds; otherwise, it returns an error. + ReturnValue *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s ModifyVpcEndpointServicePermissionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcEndpointServicePermissionsOutput) GoString() string { + return s.String() +} + +// SetReturnValue sets the ReturnValue field's value. +func (s *ModifyVpcEndpointServicePermissionsOutput) SetReturnValue(v bool) *ModifyVpcEndpointServicePermissionsOutput { + s.ReturnValue = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptionsRequest type ModifyVpcPeeringConnectionOptionsInput struct { _ struct{} `type:"structure"` @@ -46214,7 +53971,7 @@ func (s *ModifyVpcPeeringConnectionOptionsInput) SetVpcPeeringConnectionId(v str return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptionsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcPeeringConnectionOptionsResult type ModifyVpcPeeringConnectionOptionsOutput struct { _ struct{} `type:"structure"` @@ -46247,8 +54004,99 @@ func (s *ModifyVpcPeeringConnectionOptionsOutput) SetRequesterPeeringConnectionO return s } +// Contains the parameters for ModifyVpcTenancy. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcTenancyRequest +type ModifyVpcTenancyInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the operation, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The instance tenancy attribute for the VPC. + // + // InstanceTenancy is a required field + InstanceTenancy *string `type:"string" required:"true" enum:"VpcTenancy"` + + // The ID of the VPC. + // + // VpcId is a required field + VpcId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s ModifyVpcTenancyInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcTenancyInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ModifyVpcTenancyInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ModifyVpcTenancyInput"} + if s.InstanceTenancy == nil { + invalidParams.Add(request.NewErrParamRequired("InstanceTenancy")) + } + if s.VpcId == nil { + invalidParams.Add(request.NewErrParamRequired("VpcId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *ModifyVpcTenancyInput) SetDryRun(v bool) *ModifyVpcTenancyInput { + s.DryRun = &v + return s +} + +// SetInstanceTenancy sets the InstanceTenancy field's value. +func (s *ModifyVpcTenancyInput) SetInstanceTenancy(v string) *ModifyVpcTenancyInput { + s.InstanceTenancy = &v + return s +} + +// SetVpcId sets the VpcId field's value. +func (s *ModifyVpcTenancyInput) SetVpcId(v string) *ModifyVpcTenancyInput { + s.VpcId = &v + return s +} + +// Contains the output of ModifyVpcTenancy. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ModifyVpcTenancyResult +type ModifyVpcTenancyOutput struct { + _ struct{} `type:"structure"` + + // Returns true if the request succeeds; otherwise, returns an error. + ReturnValue *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s ModifyVpcTenancyOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ModifyVpcTenancyOutput) GoString() string { + return s.String() +} + +// SetReturnValue sets the ReturnValue field's value. +func (s *ModifyVpcTenancyOutput) SetReturnValue(v bool) *ModifyVpcTenancyOutput { + s.ReturnValue = &v + return s +} + // Contains the parameters for MonitorInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstancesRequest type MonitorInstancesInput struct { _ struct{} `type:"structure"` @@ -46300,7 +54148,7 @@ func (s *MonitorInstancesInput) SetInstanceIds(v []*string) *MonitorInstancesInp } // Contains the output of MonitorInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MonitorInstancesResult type MonitorInstancesOutput struct { _ struct{} `type:"structure"` @@ -46325,7 +54173,7 @@ func (s *MonitorInstancesOutput) SetInstanceMonitorings(v []*InstanceMonitoring) } // Describes the monitoring of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Monitoring +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Monitoring type Monitoring struct { _ struct{} `type:"structure"` @@ -46351,7 +54199,7 @@ func (s *Monitoring) SetState(v string) *Monitoring { } // Contains the parameters for MoveAddressToVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpcRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpcRequest type MoveAddressToVpcInput struct { _ struct{} `type:"structure"` @@ -46403,7 +54251,7 @@ func (s *MoveAddressToVpcInput) SetPublicIp(v string) *MoveAddressToVpcInput { } // Contains the output of MoveAddressToVpc. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpcResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MoveAddressToVpcResult type MoveAddressToVpcOutput struct { _ struct{} `type:"structure"` @@ -46437,7 +54285,7 @@ func (s *MoveAddressToVpcOutput) SetStatus(v string) *MoveAddressToVpcOutput { } // Describes the status of a moving Elastic IP address. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MovingAddressStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MovingAddressStatus type MovingAddressStatus struct { _ struct{} `type:"structure"` @@ -46472,7 +54320,7 @@ func (s *MovingAddressStatus) SetPublicIp(v string) *MovingAddressStatus { } // Describes a NAT gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NatGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NatGateway type NatGateway struct { _ struct{} `type:"structure"` @@ -46543,6 +54391,9 @@ type NatGateway struct { // The ID of the subnet in which the NAT gateway is located. SubnetId *string `locationName:"subnetId" type:"string"` + // The tags for the NAT gateway. + Tags []*Tag `locationName:"tagSet" locationNameList:"item" type:"list"` + // The ID of the VPC in which the NAT gateway is located. VpcId *string `locationName:"vpcId" type:"string"` } @@ -46611,6 +54462,12 @@ func (s *NatGateway) SetSubnetId(v string) *NatGateway { return s } +// SetTags sets the Tags field's value. +func (s *NatGateway) SetTags(v []*Tag) *NatGateway { + s.Tags = v + return s +} + // SetVpcId sets the VpcId field's value. func (s *NatGateway) SetVpcId(v string) *NatGateway { s.VpcId = &v @@ -46618,7 +54475,7 @@ func (s *NatGateway) SetVpcId(v string) *NatGateway { } // Describes the IP addresses and network interface associated with a NAT gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NatGatewayAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NatGatewayAddress type NatGatewayAddress struct { _ struct{} `type:"structure"` @@ -46671,7 +54528,7 @@ func (s *NatGatewayAddress) SetPublicIp(v string) *NatGatewayAddress { } // Describes a network ACL. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkAcl type NetworkAcl struct { _ struct{} `type:"structure"` @@ -46741,7 +54598,7 @@ func (s *NetworkAcl) SetVpcId(v string) *NetworkAcl { } // Describes an association between a network ACL and a subnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkAclAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkAclAssociation type NetworkAclAssociation struct { _ struct{} `type:"structure"` @@ -46784,7 +54641,7 @@ func (s *NetworkAclAssociation) SetSubnetId(v string) *NetworkAclAssociation { } // Describes an entry in a network ACL. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkAclEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkAclEntry type NetworkAclEntry struct { _ struct{} `type:"structure"` @@ -46874,7 +54731,7 @@ func (s *NetworkAclEntry) SetRuleNumber(v int64) *NetworkAclEntry { } // Describes a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterface type NetworkInterface struct { _ struct{} `type:"structure"` @@ -47072,7 +54929,7 @@ func (s *NetworkInterface) SetVpcId(v string) *NetworkInterface { } // Describes association information for an Elastic IP address (IPv4 only). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceAssociation type NetworkInterfaceAssociation struct { _ struct{} `type:"structure"` @@ -47133,7 +54990,7 @@ func (s *NetworkInterfaceAssociation) SetPublicIp(v string) *NetworkInterfaceAss } // Describes a network interface attachment. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceAttachment +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceAttachment type NetworkInterfaceAttachment struct { _ struct{} `type:"structure"` @@ -47212,7 +55069,7 @@ func (s *NetworkInterfaceAttachment) SetStatus(v string) *NetworkInterfaceAttach } // Describes an attachment change. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceAttachmentChanges +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceAttachmentChanges type NetworkInterfaceAttachmentChanges struct { _ struct{} `type:"structure"` @@ -47246,7 +55103,7 @@ func (s *NetworkInterfaceAttachmentChanges) SetDeleteOnTermination(v bool) *Netw } // Describes an IPv6 address associated with a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceIpv6Address +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfaceIpv6Address type NetworkInterfaceIpv6Address struct { _ struct{} `type:"structure"` @@ -47271,7 +55128,7 @@ func (s *NetworkInterfaceIpv6Address) SetIpv6Address(v string) *NetworkInterface } // Describes a permission for a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfacePermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfacePermission type NetworkInterfacePermission struct { _ struct{} `type:"structure"` @@ -47341,7 +55198,7 @@ func (s *NetworkInterfacePermission) SetPermissionState(v *NetworkInterfacePermi } // Describes the state of a network interface permission. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfacePermissionState +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfacePermissionState type NetworkInterfacePermissionState struct { _ struct{} `type:"structure"` @@ -47375,7 +55232,7 @@ func (s *NetworkInterfacePermissionState) SetStatusMessage(v string) *NetworkInt } // Describes the private IPv4 address of a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfacePrivateIpAddress +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NetworkInterfacePrivateIpAddress type NetworkInterfacePrivateIpAddress struct { _ struct{} `type:"structure"` @@ -47428,7 +55285,7 @@ func (s *NetworkInterfacePrivateIpAddress) SetPrivateIpAddress(v string) *Networ return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NewDhcpConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/NewDhcpConfiguration type NewDhcpConfiguration struct { _ struct{} `type:"structure"` @@ -47461,7 +55318,7 @@ func (s *NewDhcpConfiguration) SetValues(v []*string) *NewDhcpConfiguration { // Describes the data that identifies an Amazon FPGA image (AFI) on the PCI // bus. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PciId +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PciId type PciId struct { _ struct{} `type:"structure"` @@ -47513,7 +55370,7 @@ func (s *PciId) SetVendorId(v string) *PciId { } // Describes the VPC peering connection options. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PeeringConnectionOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PeeringConnectionOptions type PeeringConnectionOptions struct { _ struct{} `type:"structure"` @@ -47559,7 +55416,7 @@ func (s *PeeringConnectionOptions) SetAllowEgressFromLocalVpcToRemoteClassicLink } // The VPC peering connection options. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PeeringConnectionOptionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PeeringConnectionOptionsRequest type PeeringConnectionOptionsRequest struct { _ struct{} `type:"structure"` @@ -47605,7 +55462,7 @@ func (s *PeeringConnectionOptionsRequest) SetAllowEgressFromLocalVpcToRemoteClas } // Describes the placement of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Placement +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Placement type Placement struct { _ struct{} `type:"structure"` @@ -47679,7 +55536,7 @@ func (s *Placement) SetTenancy(v string) *Placement { } // Describes a placement group. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PlacementGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PlacementGroup type PlacementGroup struct { _ struct{} `type:"structure"` @@ -47722,7 +55579,7 @@ func (s *PlacementGroup) SetStrategy(v string) *PlacementGroup { } // Describes a range of ports. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PortRange +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PortRange type PortRange struct { _ struct{} `type:"structure"` @@ -47756,7 +55613,7 @@ func (s *PortRange) SetTo(v int64) *PortRange { } // Describes prefixes for AWS services. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PrefixList +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PrefixList type PrefixList struct { _ struct{} `type:"structure"` @@ -47798,11 +55655,18 @@ func (s *PrefixList) SetPrefixListName(v string) *PrefixList { return s } -// The ID of the prefix. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PrefixListId +// [EC2-VPC only] The ID of the prefix. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PrefixListId type PrefixListId struct { _ struct{} `type:"structure"` + // A description for the security group rule that references this prefix list + // ID. + // + // Constraints: Up to 255 characters in length. Allowed characters are a-z, + // A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$* + Description *string `locationName:"description" type:"string"` + // The ID of the prefix. PrefixListId *string `locationName:"prefixListId" type:"string"` } @@ -47817,6 +55681,12 @@ func (s PrefixListId) GoString() string { return s.String() } +// SetDescription sets the Description field's value. +func (s *PrefixListId) SetDescription(v string) *PrefixListId { + s.Description = &v + return s +} + // SetPrefixListId sets the PrefixListId field's value. func (s *PrefixListId) SetPrefixListId(v string) *PrefixListId { s.PrefixListId = &v @@ -47824,7 +55694,7 @@ func (s *PrefixListId) SetPrefixListId(v string) *PrefixListId { } // Describes the price for a Reserved Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PriceSchedule +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PriceSchedule type PriceSchedule struct { _ struct{} `type:"structure"` @@ -47887,7 +55757,7 @@ func (s *PriceSchedule) SetTerm(v int64) *PriceSchedule { } // Describes the price for a Reserved Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PriceScheduleSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PriceScheduleSpecification type PriceScheduleSpecification struct { _ struct{} `type:"structure"` @@ -47932,7 +55802,7 @@ func (s *PriceScheduleSpecification) SetTerm(v int64) *PriceScheduleSpecificatio } // Describes a Reserved Instance offering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PricingDetail +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PricingDetail type PricingDetail struct { _ struct{} `type:"structure"` @@ -47966,7 +55836,7 @@ func (s *PricingDetail) SetPrice(v float64) *PricingDetail { } // Describes a secondary private IPv4 address for a network interface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PrivateIpAddressSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PrivateIpAddressSpecification type PrivateIpAddressSpecification struct { _ struct{} `type:"structure"` @@ -48016,7 +55886,7 @@ func (s *PrivateIpAddressSpecification) SetPrivateIpAddress(v string) *PrivateIp } // Describes a product code. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ProductCode +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ProductCode type ProductCode struct { _ struct{} `type:"structure"` @@ -48050,7 +55920,7 @@ func (s *ProductCode) SetProductCodeType(v string) *ProductCode { } // Describes a virtual private gateway propagating route. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PropagatingVgw +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PropagatingVgw type PropagatingVgw struct { _ struct{} `type:"structure"` @@ -48077,7 +55947,7 @@ func (s *PropagatingVgw) SetGatewayId(v string) *PropagatingVgw { // Reserved. If you need to sustain traffic greater than the documented limits // (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-nat-gateway.html), // contact us through the Support Center (https://console.aws.amazon.com/support/home?). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ProvisionedBandwidth +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ProvisionedBandwidth type ProvisionedBandwidth struct { _ struct{} `type:"structure"` @@ -48148,7 +56018,7 @@ func (s *ProvisionedBandwidth) SetStatus(v string) *ProvisionedBandwidth { } // Describes the result of the purchase. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Purchase +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Purchase type Purchase struct { _ struct{} `type:"structure"` @@ -48237,7 +56107,7 @@ func (s *Purchase) SetUpfrontPrice(v string) *Purchase { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservationRequest type PurchaseHostReservationInput struct { _ struct{} `type:"structure"` @@ -48327,7 +56197,7 @@ func (s *PurchaseHostReservationInput) SetOfferingId(v string) *PurchaseHostRese return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservationResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseHostReservationResult type PurchaseHostReservationOutput struct { _ struct{} `type:"structure"` @@ -48341,7 +56211,7 @@ type PurchaseHostReservationOutput struct { CurrencyCode *string `locationName:"currencyCode" type:"string" enum:"CurrencyCodeValues"` // Describes the details of the purchase. - Purchase []*Purchase `locationName:"purchase" type:"list"` + Purchase []*Purchase `locationName:"purchase" locationNameList:"item" type:"list"` // The total hourly price of the reservation calculated per hour. TotalHourlyPrice *string `locationName:"totalHourlyPrice" type:"string"` @@ -48392,7 +56262,7 @@ func (s *PurchaseHostReservationOutput) SetTotalUpfrontPrice(v string) *Purchase } // Describes a request to purchase Scheduled Instances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseRequest type PurchaseRequest struct { _ struct{} `type:"structure"` @@ -48446,7 +56316,7 @@ func (s *PurchaseRequest) SetPurchaseToken(v string) *PurchaseRequest { } // Contains the parameters for PurchaseReservedInstancesOffering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOfferingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOfferingRequest type PurchaseReservedInstancesOfferingInput struct { _ struct{} `type:"structure"` @@ -48523,7 +56393,7 @@ func (s *PurchaseReservedInstancesOfferingInput) SetReservedInstancesOfferingId( } // Contains the output of PurchaseReservedInstancesOffering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOfferingResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseReservedInstancesOfferingResult type PurchaseReservedInstancesOfferingOutput struct { _ struct{} `type:"structure"` @@ -48548,7 +56418,7 @@ func (s *PurchaseReservedInstancesOfferingOutput) SetReservedInstancesId(v strin } // Contains the parameters for PurchaseScheduledInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstancesRequest type PurchaseScheduledInstancesInput struct { _ struct{} `type:"structure"` @@ -48623,7 +56493,7 @@ func (s *PurchaseScheduledInstancesInput) SetPurchaseRequests(v []*PurchaseReque } // Contains the output of PurchaseScheduledInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/PurchaseScheduledInstancesResult type PurchaseScheduledInstancesOutput struct { _ struct{} `type:"structure"` @@ -48648,7 +56518,7 @@ func (s *PurchaseScheduledInstancesOutput) SetScheduledInstanceSet(v []*Schedule } // Contains the parameters for RebootInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstancesRequest type RebootInstancesInput struct { _ struct{} `type:"structure"` @@ -48699,7 +56569,7 @@ func (s *RebootInstancesInput) SetInstanceIds(v []*string) *RebootInstancesInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstancesOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RebootInstancesOutput type RebootInstancesOutput struct { _ struct{} `type:"structure"` } @@ -48715,7 +56585,7 @@ func (s RebootInstancesOutput) GoString() string { } // Describes a recurring charge. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RecurringCharge +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RecurringCharge type RecurringCharge struct { _ struct{} `type:"structure"` @@ -48749,7 +56619,7 @@ func (s *RecurringCharge) SetFrequency(v string) *RecurringCharge { } // Describes a region. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Region +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Region type Region struct { _ struct{} `type:"structure"` @@ -48783,7 +56653,7 @@ func (s *Region) SetRegionName(v string) *Region { } // Contains the parameters for RegisterImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImageRequest type RegisterImageInput struct { _ struct{} `type:"structure"` @@ -48835,7 +56705,7 @@ type RegisterImageInput struct { // The ID of the RAM disk. RamdiskId *string `locationName:"ramdiskId" type:"string"` - // The name of the root device (for example, /dev/sda1, or /dev/xvda). + // The device name of the root device volume (for example, /dev/sda1). RootDeviceName *string `locationName:"rootDeviceName" type:"string"` // Set to simple to enable enhanced networking with the Intel 82599 Virtual @@ -48848,7 +56718,7 @@ type RegisterImageInput struct { // PV AMI can make instances launched from the AMI unreachable. SriovNetSupport *string `locationName:"sriovNetSupport" type:"string"` - // The type of virtualization. + // The type of virtualization (hvm | paravirtual). // // Default: paravirtual VirtualizationType *string `locationName:"virtualizationType" type:"string"` @@ -48956,7 +56826,7 @@ func (s *RegisterImageInput) SetVirtualizationType(v string) *RegisterImageInput } // Contains the output of RegisterImage. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImageResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RegisterImageResult type RegisterImageOutput struct { _ struct{} `type:"structure"` @@ -48980,8 +56850,97 @@ func (s *RegisterImageOutput) SetImageId(v string) *RegisterImageOutput { return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcEndpointConnectionsRequest +type RejectVpcEndpointConnectionsInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the service. + // + // ServiceId is a required field + ServiceId *string `type:"string" required:"true"` + + // The IDs of one or more VPC endpoints. + // + // VpcEndpointIds is a required field + VpcEndpointIds []*string `locationName:"VpcEndpointId" locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s RejectVpcEndpointConnectionsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s RejectVpcEndpointConnectionsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *RejectVpcEndpointConnectionsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "RejectVpcEndpointConnectionsInput"} + if s.ServiceId == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceId")) + } + if s.VpcEndpointIds == nil { + invalidParams.Add(request.NewErrParamRequired("VpcEndpointIds")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *RejectVpcEndpointConnectionsInput) SetDryRun(v bool) *RejectVpcEndpointConnectionsInput { + s.DryRun = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *RejectVpcEndpointConnectionsInput) SetServiceId(v string) *RejectVpcEndpointConnectionsInput { + s.ServiceId = &v + return s +} + +// SetVpcEndpointIds sets the VpcEndpointIds field's value. +func (s *RejectVpcEndpointConnectionsInput) SetVpcEndpointIds(v []*string) *RejectVpcEndpointConnectionsInput { + s.VpcEndpointIds = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcEndpointConnectionsResult +type RejectVpcEndpointConnectionsOutput struct { + _ struct{} `type:"structure"` + + // Information about the endpoints that were not rejected, if applicable. + Unsuccessful []*UnsuccessfulItem `locationName:"unsuccessful" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s RejectVpcEndpointConnectionsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s RejectVpcEndpointConnectionsOutput) GoString() string { + return s.String() +} + +// SetUnsuccessful sets the Unsuccessful field's value. +func (s *RejectVpcEndpointConnectionsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *RejectVpcEndpointConnectionsOutput { + s.Unsuccessful = v + return s +} + // Contains the parameters for RejectVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnectionRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnectionRequest type RejectVpcPeeringConnectionInput struct { _ struct{} `type:"structure"` @@ -49033,7 +56992,7 @@ func (s *RejectVpcPeeringConnectionInput) SetVpcPeeringConnectionId(v string) *R } // Contains the output of RejectVpcPeeringConnection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnectionResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RejectVpcPeeringConnectionResult type RejectVpcPeeringConnectionOutput struct { _ struct{} `type:"structure"` @@ -49058,7 +57017,7 @@ func (s *RejectVpcPeeringConnectionOutput) SetReturn(v bool) *RejectVpcPeeringCo } // Contains the parameters for ReleaseAddress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddressRequest type ReleaseAddressInput struct { _ struct{} `type:"structure"` @@ -49103,7 +57062,7 @@ func (s *ReleaseAddressInput) SetPublicIp(v string) *ReleaseAddressInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddressOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseAddressOutput type ReleaseAddressOutput struct { _ struct{} `type:"structure"` } @@ -49119,7 +57078,7 @@ func (s ReleaseAddressOutput) GoString() string { } // Contains the parameters for ReleaseHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHostsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHostsRequest type ReleaseHostsInput struct { _ struct{} `type:"structure"` @@ -49159,7 +57118,7 @@ func (s *ReleaseHostsInput) SetHostIds(v []*string) *ReleaseHostsInput { } // Contains the output of ReleaseHosts. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHostsResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReleaseHostsResult type ReleaseHostsOutput struct { _ struct{} `type:"structure"` @@ -49193,7 +57152,7 @@ func (s *ReleaseHostsOutput) SetUnsuccessful(v []*UnsuccessfulItem) *ReleaseHost return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociationRequest type ReplaceIamInstanceProfileAssociationInput struct { _ struct{} `type:"structure"` @@ -49246,7 +57205,7 @@ func (s *ReplaceIamInstanceProfileAssociationInput) SetIamInstanceProfile(v *Iam return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociationResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceIamInstanceProfileAssociationResult type ReplaceIamInstanceProfileAssociationOutput struct { _ struct{} `type:"structure"` @@ -49271,7 +57230,7 @@ func (s *ReplaceIamInstanceProfileAssociationOutput) SetIamInstanceProfileAssoci } // Contains the parameters for ReplaceNetworkAclAssociation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociationRequest type ReplaceNetworkAclAssociationInput struct { _ struct{} `type:"structure"` @@ -49338,7 +57297,7 @@ func (s *ReplaceNetworkAclAssociationInput) SetNetworkAclId(v string) *ReplaceNe } // Contains the output of ReplaceNetworkAclAssociation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociationResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclAssociationResult type ReplaceNetworkAclAssociationOutput struct { _ struct{} `type:"structure"` @@ -49363,7 +57322,7 @@ func (s *ReplaceNetworkAclAssociationOutput) SetNewAssociationId(v string) *Repl } // Contains the parameters for ReplaceNetworkAclEntry. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntryRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntryRequest type ReplaceNetworkAclEntryInput struct { _ struct{} `type:"structure"` @@ -49516,7 +57475,7 @@ func (s *ReplaceNetworkAclEntryInput) SetRuleNumber(v int64) *ReplaceNetworkAclE return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntryOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceNetworkAclEntryOutput type ReplaceNetworkAclEntryOutput struct { _ struct{} `type:"structure"` } @@ -49532,7 +57491,7 @@ func (s ReplaceNetworkAclEntryOutput) GoString() string { } // Contains the parameters for ReplaceRoute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteRequest type ReplaceRouteInput struct { _ struct{} `type:"structure"` @@ -49657,7 +57616,7 @@ func (s *ReplaceRouteInput) SetVpcPeeringConnectionId(v string) *ReplaceRouteInp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteOutput type ReplaceRouteOutput struct { _ struct{} `type:"structure"` } @@ -49673,7 +57632,7 @@ func (s ReplaceRouteOutput) GoString() string { } // Contains the parameters for ReplaceRouteTableAssociation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociationRequest type ReplaceRouteTableAssociationInput struct { _ struct{} `type:"structure"` @@ -49739,7 +57698,7 @@ func (s *ReplaceRouteTableAssociationInput) SetRouteTableId(v string) *ReplaceRo } // Contains the output of ReplaceRouteTableAssociation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociationResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReplaceRouteTableAssociationResult type ReplaceRouteTableAssociationOutput struct { _ struct{} `type:"structure"` @@ -49764,7 +57723,7 @@ func (s *ReplaceRouteTableAssociationOutput) SetNewAssociationId(v string) *Repl } // Contains the parameters for ReportInstanceStatus. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatusRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatusRequest type ReportInstanceStatusInput struct { _ struct{} `type:"structure"` @@ -49785,7 +57744,7 @@ type ReportInstanceStatusInput struct { // Instances is a required field Instances []*string `locationName:"instanceId" locationNameList:"InstanceId" type:"list" required:"true"` - // One or more reason codes that describes the health state of your instance. + // One or more reason codes that describe the health state of your instance. // // * instance-stuck-in-state: My instance is stuck in a state. // @@ -49796,13 +57755,13 @@ type ReportInstanceStatusInput struct { // * password-not-available: A password is not available for my instance. // // * performance-network: My instance is experiencing performance problems - // which I believe are network related. + // that I believe are network related. // // * performance-instance-store: My instance is experiencing performance - // problems which I believe are related to the instance stores. + // problems that I believe are related to the instance stores. // // * performance-ebs-volume: My instance is experiencing performance problems - // which I believe are related to an EBS volume. + // that I believe are related to an EBS volume. // // * performance-other: My instance is experiencing performance problems. // @@ -49891,7 +57850,7 @@ func (s *ReportInstanceStatusInput) SetStatus(v string) *ReportInstanceStatusInp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatusOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReportInstanceStatusOutput type ReportInstanceStatusOutput struct { _ struct{} `type:"structure"` } @@ -49906,8 +57865,277 @@ func (s ReportInstanceStatusOutput) GoString() string { return s.String() } +// The information to include in the launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestLaunchTemplateData +type RequestLaunchTemplateData struct { + _ struct{} `type:"structure"` + + // The block device mapping. + // + // Supplying both a snapshot ID and an encryption value as arguments for block-device + // mapping results in an error. This is because only blank volumes can be encrypted + // on start, and these are not created from a snapshot. If a snapshot is the + // basis for the volume, it contains data by definition and its encryption status + // cannot be changed using this action. + BlockDeviceMappings []*LaunchTemplateBlockDeviceMappingRequest `locationName:"BlockDeviceMapping" locationNameList:"BlockDeviceMapping" type:"list"` + + // The credit option for CPU usage of the instance. Valid for T2 instances only. + CreditSpecification *CreditSpecificationRequest `type:"structure"` + + // If set to true, you can't terminate the instance using the Amazon EC2 console, + // CLI, or API. To change this attribute to false after launch, use ModifyInstanceAttribute. + DisableApiTermination *bool `type:"boolean"` + + // Indicates whether the instance is optimized for Amazon EBS I/O. This optimization + // provides dedicated throughput to Amazon EBS and an optimized configuration + // stack to provide optimal Amazon EBS I/O performance. This optimization isn't + // available with all instance types. Additional usage charges apply when using + // an EBS-optimized instance. + EbsOptimized *bool `type:"boolean"` + + // An elastic GPU to associate with the instance. + ElasticGpuSpecifications []*ElasticGpuSpecification `locationName:"ElasticGpuSpecification" locationNameList:"ElasticGpuSpecification" type:"list"` + + // The IAM instance profile. + IamInstanceProfile *LaunchTemplateIamInstanceProfileSpecificationRequest `type:"structure"` + + // The ID of the AMI, which you can get by using DescribeImages. + ImageId *string `type:"string"` + + // Indicates whether an instance stops or terminates when you initiate shutdown + // from the instance (using the operating system command for system shutdown). + // + // Default: stop + InstanceInitiatedShutdownBehavior *string `type:"string" enum:"ShutdownBehavior"` + + // The market (purchasing) option for the instances. + InstanceMarketOptions *LaunchTemplateInstanceMarketOptionsRequest `type:"structure"` + + // The instance type. For more information, see Instance Types (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html) + // in the Amazon Elastic Compute Cloud User Guide. + InstanceType *string `type:"string" enum:"InstanceType"` + + // The ID of the kernel. + // + // We recommend that you use PV-GRUB instead of kernels and RAM disks. For more + // information, see User Provided Kernels (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedkernels.html) + // in the Amazon Elastic Compute Cloud User Guide. + KernelId *string `type:"string"` + + // The name of the key pair. You can create a key pair using CreateKeyPair or + // ImportKeyPair. + // + // If you do not specify a key pair, you can't connect to the instance unless + // you choose an AMI that is configured to allow users another way to log in. + KeyName *string `type:"string"` + + // The monitoring for the instance. + Monitoring *LaunchTemplatesMonitoringRequest `type:"structure"` + + // One or more network interfaces. + NetworkInterfaces []*LaunchTemplateInstanceNetworkInterfaceSpecificationRequest `locationName:"NetworkInterface" locationNameList:"InstanceNetworkInterfaceSpecification" type:"list"` + + // The placement for the instance. + Placement *LaunchTemplatePlacementRequest `type:"structure"` + + // The ID of the RAM disk. + // + // We recommend that you use PV-GRUB instead of kernels and RAM disks. For more + // information, see User Provided Kernels (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/UserProvidedkernels.html) + // in the Amazon Elastic Compute Cloud User Guide. + RamDiskId *string `type:"string"` + + // One or more security group IDs. You can create a security group using CreateSecurityGroup. + // You cannot specify both a security group ID and security name in the same + // request. + SecurityGroupIds []*string `locationName:"SecurityGroupId" locationNameList:"SecurityGroupId" type:"list"` + + // [EC2-Classic, default VPC] One or more security group names. For a nondefault + // VPC, you must use security group IDs instead. You cannot specify both a security + // group ID and security name in the same request. + SecurityGroups []*string `locationName:"SecurityGroup" locationNameList:"SecurityGroup" type:"list"` + + // The tags to apply to the resources during launch. You can tag instances and + // volumes. The specified tags are applied to all instances or volumes that + // are created during launch. + TagSpecifications []*LaunchTemplateTagSpecificationRequest `locationName:"TagSpecification" locationNameList:"LaunchTemplateTagSpecificationRequest" type:"list"` + + // The user data to make available to the instance. For more information, see + // Running Commands on Your Linux Instance at Launch (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) + // (Linux) and Adding User Data (http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-instance-metadata.html#instancedata-add-user-data) + // (Windows). If you are using a command line tool, base64-encoding is performed + // for you and you can load the text from a file. Otherwise, you must provide + // base64-encoded text. + UserData *string `type:"string"` +} + +// String returns the string representation +func (s RequestLaunchTemplateData) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s RequestLaunchTemplateData) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *RequestLaunchTemplateData) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "RequestLaunchTemplateData"} + if s.CreditSpecification != nil { + if err := s.CreditSpecification.Validate(); err != nil { + invalidParams.AddNested("CreditSpecification", err.(request.ErrInvalidParams)) + } + } + if s.ElasticGpuSpecifications != nil { + for i, v := range s.ElasticGpuSpecifications { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "ElasticGpuSpecifications", i), err.(request.ErrInvalidParams)) + } + } + } + if s.NetworkInterfaces != nil { + for i, v := range s.NetworkInterfaces { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "NetworkInterfaces", i), err.(request.ErrInvalidParams)) + } + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetBlockDeviceMappings sets the BlockDeviceMappings field's value. +func (s *RequestLaunchTemplateData) SetBlockDeviceMappings(v []*LaunchTemplateBlockDeviceMappingRequest) *RequestLaunchTemplateData { + s.BlockDeviceMappings = v + return s +} + +// SetCreditSpecification sets the CreditSpecification field's value. +func (s *RequestLaunchTemplateData) SetCreditSpecification(v *CreditSpecificationRequest) *RequestLaunchTemplateData { + s.CreditSpecification = v + return s +} + +// SetDisableApiTermination sets the DisableApiTermination field's value. +func (s *RequestLaunchTemplateData) SetDisableApiTermination(v bool) *RequestLaunchTemplateData { + s.DisableApiTermination = &v + return s +} + +// SetEbsOptimized sets the EbsOptimized field's value. +func (s *RequestLaunchTemplateData) SetEbsOptimized(v bool) *RequestLaunchTemplateData { + s.EbsOptimized = &v + return s +} + +// SetElasticGpuSpecifications sets the ElasticGpuSpecifications field's value. +func (s *RequestLaunchTemplateData) SetElasticGpuSpecifications(v []*ElasticGpuSpecification) *RequestLaunchTemplateData { + s.ElasticGpuSpecifications = v + return s +} + +// SetIamInstanceProfile sets the IamInstanceProfile field's value. +func (s *RequestLaunchTemplateData) SetIamInstanceProfile(v *LaunchTemplateIamInstanceProfileSpecificationRequest) *RequestLaunchTemplateData { + s.IamInstanceProfile = v + return s +} + +// SetImageId sets the ImageId field's value. +func (s *RequestLaunchTemplateData) SetImageId(v string) *RequestLaunchTemplateData { + s.ImageId = &v + return s +} + +// SetInstanceInitiatedShutdownBehavior sets the InstanceInitiatedShutdownBehavior field's value. +func (s *RequestLaunchTemplateData) SetInstanceInitiatedShutdownBehavior(v string) *RequestLaunchTemplateData { + s.InstanceInitiatedShutdownBehavior = &v + return s +} + +// SetInstanceMarketOptions sets the InstanceMarketOptions field's value. +func (s *RequestLaunchTemplateData) SetInstanceMarketOptions(v *LaunchTemplateInstanceMarketOptionsRequest) *RequestLaunchTemplateData { + s.InstanceMarketOptions = v + return s +} + +// SetInstanceType sets the InstanceType field's value. +func (s *RequestLaunchTemplateData) SetInstanceType(v string) *RequestLaunchTemplateData { + s.InstanceType = &v + return s +} + +// SetKernelId sets the KernelId field's value. +func (s *RequestLaunchTemplateData) SetKernelId(v string) *RequestLaunchTemplateData { + s.KernelId = &v + return s +} + +// SetKeyName sets the KeyName field's value. +func (s *RequestLaunchTemplateData) SetKeyName(v string) *RequestLaunchTemplateData { + s.KeyName = &v + return s +} + +// SetMonitoring sets the Monitoring field's value. +func (s *RequestLaunchTemplateData) SetMonitoring(v *LaunchTemplatesMonitoringRequest) *RequestLaunchTemplateData { + s.Monitoring = v + return s +} + +// SetNetworkInterfaces sets the NetworkInterfaces field's value. +func (s *RequestLaunchTemplateData) SetNetworkInterfaces(v []*LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) *RequestLaunchTemplateData { + s.NetworkInterfaces = v + return s +} + +// SetPlacement sets the Placement field's value. +func (s *RequestLaunchTemplateData) SetPlacement(v *LaunchTemplatePlacementRequest) *RequestLaunchTemplateData { + s.Placement = v + return s +} + +// SetRamDiskId sets the RamDiskId field's value. +func (s *RequestLaunchTemplateData) SetRamDiskId(v string) *RequestLaunchTemplateData { + s.RamDiskId = &v + return s +} + +// SetSecurityGroupIds sets the SecurityGroupIds field's value. +func (s *RequestLaunchTemplateData) SetSecurityGroupIds(v []*string) *RequestLaunchTemplateData { + s.SecurityGroupIds = v + return s +} + +// SetSecurityGroups sets the SecurityGroups field's value. +func (s *RequestLaunchTemplateData) SetSecurityGroups(v []*string) *RequestLaunchTemplateData { + s.SecurityGroups = v + return s +} + +// SetTagSpecifications sets the TagSpecifications field's value. +func (s *RequestLaunchTemplateData) SetTagSpecifications(v []*LaunchTemplateTagSpecificationRequest) *RequestLaunchTemplateData { + s.TagSpecifications = v + return s +} + +// SetUserData sets the UserData field's value. +func (s *RequestLaunchTemplateData) SetUserData(v string) *RequestLaunchTemplateData { + s.UserData = &v + return s +} + // Contains the parameters for RequestSpotFleet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleetRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleetRequest type RequestSpotFleetInput struct { _ struct{} `type:"structure"` @@ -49917,7 +58145,7 @@ type RequestSpotFleetInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The configuration for the Spot fleet request. + // The configuration for the Spot Fleet request. // // SpotFleetRequestConfig is a required field SpotFleetRequestConfig *SpotFleetRequestConfigData `locationName:"spotFleetRequestConfig" type:"structure" required:"true"` @@ -49964,11 +58192,11 @@ func (s *RequestSpotFleetInput) SetSpotFleetRequestConfig(v *SpotFleetRequestCon } // Contains the output of RequestSpotFleet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleetResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotFleetResponse type RequestSpotFleetOutput struct { _ struct{} `type:"structure"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` @@ -49991,38 +58219,38 @@ func (s *RequestSpotFleetOutput) SetSpotFleetRequestId(v string) *RequestSpotFle } // Contains the parameters for RequestSpotInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstancesRequest type RequestSpotInstancesInput struct { _ struct{} `type:"structure"` - // The user-specified name for a logical grouping of bids. + // The user-specified name for a logical grouping of requests. // // When you specify an Availability Zone group in a Spot Instance request, all - // Spot instances in the request are launched in the same Availability Zone. + // Spot Instances in the request are launched in the same Availability Zone. // Instance proximity is maintained with this parameter, but the choice of Availability - // Zone is not. The group applies only to bids for Spot Instances of the same - // instance type. Any additional Spot instance requests that are specified with - // the same Availability Zone group name are launched in that same Availability + // Zone is not. The group applies only to requests for Spot Instances of the + // same instance type. Any additional Spot Instance requests that are specified + // with the same Availability Zone group name are launched in that same Availability // Zone, as long as at least one instance from the group is still active. // // If there is no active instance running in the Availability Zone group that - // you specify for a new Spot instance request (all instances are terminated, - // the bid is expired, or the bid falls below current market), then Amazon EC2 - // launches the instance in any Availability Zone where the constraint can be - // met. Consequently, the subsequent set of Spot instances could be placed in - // a different zone from the original request, even if you specified the same - // Availability Zone group. + // you specify for a new Spot Instance request (all instances are terminated, + // the request is expired, or the maximum price you specified falls below current + // Spot price), then Amazon EC2 launches the instance in any Availability Zone + // where the constraint can be met. Consequently, the subsequent set of Spot + // Instances could be placed in a different zone from the original request, + // even if you specified the same Availability Zone group. // // Default: Instances are launched in any available Availability Zone. AvailabilityZoneGroup *string `locationName:"availabilityZoneGroup" type:"string"` - // The required duration for the Spot instances (also known as Spot blocks), + // The required duration for the Spot Instances (also known as Spot blocks), // in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, // or 360). // - // The duration period starts as soon as your Spot instance receives its instance - // ID. At the end of the duration period, Amazon EC2 marks the Spot instance - // for termination and provides a Spot instance termination notice, which gives + // The duration period starts as soon as your Spot Instance receives its instance + // ID. At the end of the duration period, Amazon EC2 marks the Spot Instance + // for termination and provides a Spot Instance termination notice, which gives // the instance a two-minute warning before it terminates. // // Note that you can't specify an Availability Zone group or a launch group @@ -50040,12 +58268,15 @@ type RequestSpotInstancesInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The maximum number of Spot instances to launch. + // The maximum number of Spot Instances to launch. // // Default: 1 InstanceCount *int64 `locationName:"instanceCount" type:"integer"` - // The instance launch group. Launch groups are Spot instances that launch together + // The behavior when a Spot Instance is interrupted. The default is terminate. + InstanceInterruptionBehavior *string `type:"string" enum:"InstanceInterruptionBehavior"` + + // The instance launch group. Launch groups are Spot Instances that launch together // and terminate together. // // Default: Instances are launched and terminated individually @@ -50054,13 +58285,11 @@ type RequestSpotInstancesInput struct { // The launch specification. LaunchSpecification *RequestSpotLaunchSpecification `type:"structure"` - // The maximum hourly price (bid) for any Spot instance launched to fulfill - // the request. - // - // SpotPrice is a required field - SpotPrice *string `locationName:"spotPrice" type:"string" required:"true"` + // The maximum price per hour that you are willing to pay for a Spot Instance. + // The default is the On-Demand price. + SpotPrice *string `locationName:"spotPrice" type:"string"` - // The Spot instance request type. + // The Spot Instance request type. // // Default: one-time Type *string `locationName:"type" type:"string" enum:"SpotInstanceType"` @@ -50070,16 +58299,13 @@ type RequestSpotInstancesInput struct { // launch, the request expires, or the request is canceled. If the request is // persistent, the request becomes active at this date and time and remains // active until it expires or is canceled. - // - // Default: The request is effective indefinitely. ValidFrom *time.Time `locationName:"validFrom" type:"timestamp" timestampFormat:"iso8601"` // The end date of the request. If this is a one-time request, the request remains // active until all instances launch, the request is canceled, or this date // is reached. If the request is persistent, it remains active until it is canceled - // or this date and time is reached. - // - // Default: The request is effective indefinitely. + // or this date is reached. The default end date is 7 days from the current + // date. ValidUntil *time.Time `locationName:"validUntil" type:"timestamp" timestampFormat:"iso8601"` } @@ -50096,9 +58322,6 @@ func (s RequestSpotInstancesInput) GoString() string { // Validate inspects the fields of the type to determine if they are valid. func (s *RequestSpotInstancesInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "RequestSpotInstancesInput"} - if s.SpotPrice == nil { - invalidParams.Add(request.NewErrParamRequired("SpotPrice")) - } if s.LaunchSpecification != nil { if err := s.LaunchSpecification.Validate(); err != nil { invalidParams.AddNested("LaunchSpecification", err.(request.ErrInvalidParams)) @@ -50141,6 +58364,12 @@ func (s *RequestSpotInstancesInput) SetInstanceCount(v int64) *RequestSpotInstan return s } +// SetInstanceInterruptionBehavior sets the InstanceInterruptionBehavior field's value. +func (s *RequestSpotInstancesInput) SetInstanceInterruptionBehavior(v string) *RequestSpotInstancesInput { + s.InstanceInterruptionBehavior = &v + return s +} + // SetLaunchGroup sets the LaunchGroup field's value. func (s *RequestSpotInstancesInput) SetLaunchGroup(v string) *RequestSpotInstancesInput { s.LaunchGroup = &v @@ -50178,11 +58407,11 @@ func (s *RequestSpotInstancesInput) SetValidUntil(v time.Time) *RequestSpotInsta } // Contains the output of RequestSpotInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotInstancesResult type RequestSpotInstancesOutput struct { _ struct{} `type:"structure"` - // One or more Spot instance requests. + // One or more Spot Instance requests. SpotInstanceRequests []*SpotInstanceRequest `locationName:"spotInstanceRequestSet" locationNameList:"item" type:"list"` } @@ -50203,17 +58432,17 @@ func (s *RequestSpotInstancesOutput) SetSpotInstanceRequests(v []*SpotInstanceRe } // Describes the launch specification for an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotLaunchSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RequestSpotLaunchSpecification type RequestSpotLaunchSpecification struct { _ struct{} `type:"structure"` // Deprecated. AddressingType *string `locationName:"addressingType" type:"string"` - // One or more block device mapping entries. - // - // Although you can specify encrypted EBS volumes in this block device mapping - // for your Spot Instances, these volumes are not encrypted. + // One or more block device mapping entries. You can't specify both a snapshot + // ID and an encryption value. This is because only blank volumes can be encrypted + // on creation. If a snapshot is the basis for a volume, it is not blank and + // its encryption status is used for the volume encryption status. BlockDeviceMappings []*BlockDeviceMapping `locationName:"blockDeviceMapping" locationNameList:"item" type:"list"` // Indicates whether the instance is optimized for EBS I/O. This optimization @@ -50404,7 +58633,7 @@ func (s *RequestSpotLaunchSpecification) SetUserData(v string) *RequestSpotLaunc } // Describes a reservation. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Reservation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Reservation type Reservation struct { _ struct{} `type:"structure"` @@ -50466,7 +58695,7 @@ func (s *Reservation) SetReservationId(v string) *Reservation { } // The cost associated with the Reserved Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservationValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservationValue type ReservationValue struct { _ struct{} `type:"structure"` @@ -50510,7 +58739,7 @@ func (s *ReservationValue) SetRemainingUpfrontValue(v string) *ReservationValue } // Describes the limit price of a Reserved Instance offering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstanceLimitPrice +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstanceLimitPrice type ReservedInstanceLimitPrice struct { _ struct{} `type:"structure"` @@ -50546,7 +58775,7 @@ func (s *ReservedInstanceLimitPrice) SetCurrencyCode(v string) *ReservedInstance } // The total value of the Convertible Reserved Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstanceReservationValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstanceReservationValue type ReservedInstanceReservationValue struct { _ struct{} `type:"structure"` @@ -50580,7 +58809,7 @@ func (s *ReservedInstanceReservationValue) SetReservedInstanceId(v string) *Rese } // Describes a Reserved Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstances +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstances type ReservedInstances struct { _ struct{} `type:"structure"` @@ -50759,7 +58988,7 @@ func (s *ReservedInstances) SetUsagePrice(v float64) *ReservedInstances { } // Describes the configuration settings for the modified Reserved Instances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesConfiguration type ReservedInstancesConfiguration struct { _ struct{} `type:"structure"` @@ -50822,7 +59051,7 @@ func (s *ReservedInstancesConfiguration) SetScope(v string) *ReservedInstancesCo } // Describes the ID of a Reserved Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesId +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesId type ReservedInstancesId struct { _ struct{} `type:"structure"` @@ -50847,7 +59076,7 @@ func (s *ReservedInstancesId) SetReservedInstancesId(v string) *ReservedInstance } // Describes a Reserved Instance listing. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesListing +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesListing type ReservedInstancesListing struct { _ struct{} `type:"structure"` @@ -50955,7 +59184,7 @@ func (s *ReservedInstancesListing) SetUpdateDate(v time.Time) *ReservedInstances } // Describes a Reserved Instance modification. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesModification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesModification type ReservedInstancesModification struct { _ struct{} `type:"structure"` @@ -51054,7 +59283,7 @@ func (s *ReservedInstancesModification) SetUpdateDate(v time.Time) *ReservedInst } // Describes the modification request/s. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesModificationResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesModificationResult type ReservedInstancesModificationResult struct { _ struct{} `type:"structure"` @@ -51090,7 +59319,7 @@ func (s *ReservedInstancesModificationResult) SetTargetConfiguration(v *Reserved } // Describes a Reserved Instance offering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesOffering +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ReservedInstancesOffering type ReservedInstancesOffering struct { _ struct{} `type:"structure"` @@ -51248,8 +59477,92 @@ func (s *ReservedInstancesOffering) SetUsagePrice(v float64) *ReservedInstancesO return s } +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetFpgaImageAttributeRequest +type ResetFpgaImageAttributeInput struct { + _ struct{} `type:"structure"` + + // The attribute. + Attribute *string `type:"string" enum:"ResetFpgaImageAttributeName"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the AFI. + // + // FpgaImageId is a required field + FpgaImageId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s ResetFpgaImageAttributeInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ResetFpgaImageAttributeInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ResetFpgaImageAttributeInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ResetFpgaImageAttributeInput"} + if s.FpgaImageId == nil { + invalidParams.Add(request.NewErrParamRequired("FpgaImageId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAttribute sets the Attribute field's value. +func (s *ResetFpgaImageAttributeInput) SetAttribute(v string) *ResetFpgaImageAttributeInput { + s.Attribute = &v + return s +} + +// SetDryRun sets the DryRun field's value. +func (s *ResetFpgaImageAttributeInput) SetDryRun(v bool) *ResetFpgaImageAttributeInput { + s.DryRun = &v + return s +} + +// SetFpgaImageId sets the FpgaImageId field's value. +func (s *ResetFpgaImageAttributeInput) SetFpgaImageId(v string) *ResetFpgaImageAttributeInput { + s.FpgaImageId = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetFpgaImageAttributeResult +type ResetFpgaImageAttributeOutput struct { + _ struct{} `type:"structure"` + + // Is true if the request succeeds, and an error otherwise. + Return *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s ResetFpgaImageAttributeOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ResetFpgaImageAttributeOutput) GoString() string { + return s.String() +} + +// SetReturn sets the Return field's value. +func (s *ResetFpgaImageAttributeOutput) SetReturn(v bool) *ResetFpgaImageAttributeOutput { + s.Return = &v + return s +} + // Contains the parameters for ResetImageAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttributeRequest type ResetImageAttributeInput struct { _ struct{} `type:"structure"` @@ -51315,7 +59628,7 @@ func (s *ResetImageAttributeInput) SetImageId(v string) *ResetImageAttributeInpu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetImageAttributeOutput type ResetImageAttributeOutput struct { _ struct{} `type:"structure"` } @@ -51331,7 +59644,7 @@ func (s ResetImageAttributeOutput) GoString() string { } // Contains the parameters for ResetInstanceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttributeRequest type ResetInstanceAttributeInput struct { _ struct{} `type:"structure"` @@ -51399,7 +59712,7 @@ func (s *ResetInstanceAttributeInput) SetInstanceId(v string) *ResetInstanceAttr return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetInstanceAttributeOutput type ResetInstanceAttributeOutput struct { _ struct{} `type:"structure"` } @@ -51415,7 +59728,7 @@ func (s ResetInstanceAttributeOutput) GoString() string { } // Contains the parameters for ResetNetworkInterfaceAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttributeRequest type ResetNetworkInterfaceAttributeInput struct { _ struct{} `type:"structure"` @@ -51475,7 +59788,7 @@ func (s *ResetNetworkInterfaceAttributeInput) SetSourceDestCheck(v string) *Rese return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetNetworkInterfaceAttributeOutput type ResetNetworkInterfaceAttributeOutput struct { _ struct{} `type:"structure"` } @@ -51491,7 +59804,7 @@ func (s ResetNetworkInterfaceAttributeOutput) GoString() string { } // Contains the parameters for ResetSnapshotAttribute. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttributeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttributeRequest type ResetSnapshotAttributeInput struct { _ struct{} `type:"structure"` @@ -51557,7 +59870,7 @@ func (s *ResetSnapshotAttributeInput) SetSnapshotId(v string) *ResetSnapshotAttr return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttributeOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResetSnapshotAttributeOutput type ResetSnapshotAttributeOutput struct { _ struct{} `type:"structure"` } @@ -51572,8 +59885,241 @@ func (s ResetSnapshotAttributeOutput) GoString() string { return s.String() } +// Describes the error that's returned when you cannot delete a launch template +// version. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResponseError +type ResponseError struct { + _ struct{} `type:"structure"` + + // The error code. + Code *string `locationName:"code" type:"string" enum:"LaunchTemplateErrorCode"` + + // The error message, if applicable. + Message *string `locationName:"message" type:"string"` +} + +// String returns the string representation +func (s ResponseError) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ResponseError) GoString() string { + return s.String() +} + +// SetCode sets the Code field's value. +func (s *ResponseError) SetCode(v string) *ResponseError { + s.Code = &v + return s +} + +// SetMessage sets the Message field's value. +func (s *ResponseError) SetMessage(v string) *ResponseError { + s.Message = &v + return s +} + +// The information for a launch template. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ResponseLaunchTemplateData +type ResponseLaunchTemplateData struct { + _ struct{} `type:"structure"` + + // The block device mappings. + BlockDeviceMappings []*LaunchTemplateBlockDeviceMapping `locationName:"blockDeviceMappingSet" locationNameList:"item" type:"list"` + + // The credit option for CPU usage of the instance. + CreditSpecification *CreditSpecification `locationName:"creditSpecification" type:"structure"` + + // If set to true, indicates that the instance cannot be terminated using the + // Amazon EC2 console, command line tool, or API. + DisableApiTermination *bool `locationName:"disableApiTermination" type:"boolean"` + + // Indicates whether the instance is optimized for Amazon EBS I/O. + EbsOptimized *bool `locationName:"ebsOptimized" type:"boolean"` + + // The elastic GPU specification. + ElasticGpuSpecifications []*ElasticGpuSpecificationResponse `locationName:"elasticGpuSpecificationSet" locationNameList:"item" type:"list"` + + // The IAM instance profile. + IamInstanceProfile *LaunchTemplateIamInstanceProfileSpecification `locationName:"iamInstanceProfile" type:"structure"` + + // The ID of the AMI that was used to launch the instance. + ImageId *string `locationName:"imageId" type:"string"` + + // Indicates whether an instance stops or terminates when you initiate shutdown + // from the instance (using the operating system command for system shutdown). + InstanceInitiatedShutdownBehavior *string `locationName:"instanceInitiatedShutdownBehavior" type:"string" enum:"ShutdownBehavior"` + + // The market (purchasing) option for the instances. + InstanceMarketOptions *LaunchTemplateInstanceMarketOptions `locationName:"instanceMarketOptions" type:"structure"` + + // The instance type. + InstanceType *string `locationName:"instanceType" type:"string" enum:"InstanceType"` + + // The ID of the kernel, if applicable. + KernelId *string `locationName:"kernelId" type:"string"` + + // The name of the key pair. + KeyName *string `locationName:"keyName" type:"string"` + + // The monitoring for the instance. + Monitoring *LaunchTemplatesMonitoring `locationName:"monitoring" type:"structure"` + + // The network interfaces. + NetworkInterfaces []*LaunchTemplateInstanceNetworkInterfaceSpecification `locationName:"networkInterfaceSet" locationNameList:"item" type:"list"` + + // The placement of the instance. + Placement *LaunchTemplatePlacement `locationName:"placement" type:"structure"` + + // The ID of the RAM disk, if applicable. + RamDiskId *string `locationName:"ramDiskId" type:"string"` + + // The security group IDs. + SecurityGroupIds []*string `locationName:"securityGroupIdSet" locationNameList:"item" type:"list"` + + // The security group names. + SecurityGroups []*string `locationName:"securityGroupSet" locationNameList:"item" type:"list"` + + // The tags. + TagSpecifications []*LaunchTemplateTagSpecification `locationName:"tagSpecificationSet" locationNameList:"item" type:"list"` + + // The user data for the instance. + UserData *string `locationName:"userData" type:"string"` +} + +// String returns the string representation +func (s ResponseLaunchTemplateData) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ResponseLaunchTemplateData) GoString() string { + return s.String() +} + +// SetBlockDeviceMappings sets the BlockDeviceMappings field's value. +func (s *ResponseLaunchTemplateData) SetBlockDeviceMappings(v []*LaunchTemplateBlockDeviceMapping) *ResponseLaunchTemplateData { + s.BlockDeviceMappings = v + return s +} + +// SetCreditSpecification sets the CreditSpecification field's value. +func (s *ResponseLaunchTemplateData) SetCreditSpecification(v *CreditSpecification) *ResponseLaunchTemplateData { + s.CreditSpecification = v + return s +} + +// SetDisableApiTermination sets the DisableApiTermination field's value. +func (s *ResponseLaunchTemplateData) SetDisableApiTermination(v bool) *ResponseLaunchTemplateData { + s.DisableApiTermination = &v + return s +} + +// SetEbsOptimized sets the EbsOptimized field's value. +func (s *ResponseLaunchTemplateData) SetEbsOptimized(v bool) *ResponseLaunchTemplateData { + s.EbsOptimized = &v + return s +} + +// SetElasticGpuSpecifications sets the ElasticGpuSpecifications field's value. +func (s *ResponseLaunchTemplateData) SetElasticGpuSpecifications(v []*ElasticGpuSpecificationResponse) *ResponseLaunchTemplateData { + s.ElasticGpuSpecifications = v + return s +} + +// SetIamInstanceProfile sets the IamInstanceProfile field's value. +func (s *ResponseLaunchTemplateData) SetIamInstanceProfile(v *LaunchTemplateIamInstanceProfileSpecification) *ResponseLaunchTemplateData { + s.IamInstanceProfile = v + return s +} + +// SetImageId sets the ImageId field's value. +func (s *ResponseLaunchTemplateData) SetImageId(v string) *ResponseLaunchTemplateData { + s.ImageId = &v + return s +} + +// SetInstanceInitiatedShutdownBehavior sets the InstanceInitiatedShutdownBehavior field's value. +func (s *ResponseLaunchTemplateData) SetInstanceInitiatedShutdownBehavior(v string) *ResponseLaunchTemplateData { + s.InstanceInitiatedShutdownBehavior = &v + return s +} + +// SetInstanceMarketOptions sets the InstanceMarketOptions field's value. +func (s *ResponseLaunchTemplateData) SetInstanceMarketOptions(v *LaunchTemplateInstanceMarketOptions) *ResponseLaunchTemplateData { + s.InstanceMarketOptions = v + return s +} + +// SetInstanceType sets the InstanceType field's value. +func (s *ResponseLaunchTemplateData) SetInstanceType(v string) *ResponseLaunchTemplateData { + s.InstanceType = &v + return s +} + +// SetKernelId sets the KernelId field's value. +func (s *ResponseLaunchTemplateData) SetKernelId(v string) *ResponseLaunchTemplateData { + s.KernelId = &v + return s +} + +// SetKeyName sets the KeyName field's value. +func (s *ResponseLaunchTemplateData) SetKeyName(v string) *ResponseLaunchTemplateData { + s.KeyName = &v + return s +} + +// SetMonitoring sets the Monitoring field's value. +func (s *ResponseLaunchTemplateData) SetMonitoring(v *LaunchTemplatesMonitoring) *ResponseLaunchTemplateData { + s.Monitoring = v + return s +} + +// SetNetworkInterfaces sets the NetworkInterfaces field's value. +func (s *ResponseLaunchTemplateData) SetNetworkInterfaces(v []*LaunchTemplateInstanceNetworkInterfaceSpecification) *ResponseLaunchTemplateData { + s.NetworkInterfaces = v + return s +} + +// SetPlacement sets the Placement field's value. +func (s *ResponseLaunchTemplateData) SetPlacement(v *LaunchTemplatePlacement) *ResponseLaunchTemplateData { + s.Placement = v + return s +} + +// SetRamDiskId sets the RamDiskId field's value. +func (s *ResponseLaunchTemplateData) SetRamDiskId(v string) *ResponseLaunchTemplateData { + s.RamDiskId = &v + return s +} + +// SetSecurityGroupIds sets the SecurityGroupIds field's value. +func (s *ResponseLaunchTemplateData) SetSecurityGroupIds(v []*string) *ResponseLaunchTemplateData { + s.SecurityGroupIds = v + return s +} + +// SetSecurityGroups sets the SecurityGroups field's value. +func (s *ResponseLaunchTemplateData) SetSecurityGroups(v []*string) *ResponseLaunchTemplateData { + s.SecurityGroups = v + return s +} + +// SetTagSpecifications sets the TagSpecifications field's value. +func (s *ResponseLaunchTemplateData) SetTagSpecifications(v []*LaunchTemplateTagSpecification) *ResponseLaunchTemplateData { + s.TagSpecifications = v + return s +} + +// SetUserData sets the UserData field's value. +func (s *ResponseLaunchTemplateData) SetUserData(v string) *ResponseLaunchTemplateData { + s.UserData = &v + return s +} + // Contains the parameters for RestoreAddressToClassic. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassicRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassicRequest type RestoreAddressToClassicInput struct { _ struct{} `type:"structure"` @@ -51625,7 +60171,7 @@ func (s *RestoreAddressToClassicInput) SetPublicIp(v string) *RestoreAddressToCl } // Contains the output of RestoreAddressToClassic. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassicResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RestoreAddressToClassicResult type RestoreAddressToClassicOutput struct { _ struct{} `type:"structure"` @@ -51659,12 +60205,11 @@ func (s *RestoreAddressToClassicOutput) SetStatus(v string) *RestoreAddressToCla } // Contains the parameters for RevokeSecurityGroupEgress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgressRequest type RevokeSecurityGroupEgressInput struct { _ struct{} `type:"structure"` - // The CIDR IP address range. We recommend that you specify the CIDR range in - // a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the CIDR. CidrIp *string `locationName:"cidrIp" type:"string"` // Checks whether you have the required permissions for the action, without @@ -51673,8 +60218,7 @@ type RevokeSecurityGroupEgressInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // The start of port range for the TCP and UDP protocols, or an ICMP type number. - // We recommend that you specify the port range in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the port. FromPort *int64 `locationName:"fromPort" type:"integer"` // The ID of the security group. @@ -51682,26 +60226,23 @@ type RevokeSecurityGroupEgressInput struct { // GroupId is a required field GroupId *string `locationName:"groupId" type:"string" required:"true"` - // A set of IP permissions. You can't specify a destination security group and - // a CIDR IP address range. + // One or more sets of IP permissions. You can't specify a destination security + // group and a CIDR IP address range in the same set of permissions. IpPermissions []*IpPermission `locationName:"ipPermissions" locationNameList:"item" type:"list"` - // The IP protocol name or number. We recommend that you specify the protocol - // in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the protocol name or + // number. IpProtocol *string `locationName:"ipProtocol" type:"string"` - // The name of a destination security group. To revoke outbound access to a - // destination security group, we recommend that you use a set of IP permissions - // instead. + // Not supported. Use a set of IP permissions to specify a destination security + // group. SourceSecurityGroupName *string `locationName:"sourceSecurityGroupName" type:"string"` - // The AWS account number for a destination security group. To revoke outbound - // access to a destination security group, we recommend that you use a set of - // IP permissions instead. + // Not supported. Use a set of IP permissions to specify a destination security + // group. SourceSecurityGroupOwnerId *string `locationName:"sourceSecurityGroupOwnerId" type:"string"` - // The end of port range for the TCP and UDP protocols, or an ICMP type number. - // We recommend that you specify the port range in a set of IP permissions instead. + // Not supported. Use a set of IP permissions to specify the port. ToPort *int64 `locationName:"toPort" type:"integer"` } @@ -51782,7 +60323,7 @@ func (s *RevokeSecurityGroupEgressInput) SetToPort(v int64) *RevokeSecurityGroup return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgressOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupEgressOutput type RevokeSecurityGroupEgressOutput struct { _ struct{} `type:"structure"` } @@ -51798,7 +60339,7 @@ func (s RevokeSecurityGroupEgressOutput) GoString() string { } // Contains the parameters for RevokeSecurityGroupIngress. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngressRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngressRequest type RevokeSecurityGroupIngressInput struct { _ struct{} `type:"structure"` @@ -51816,15 +60357,17 @@ type RevokeSecurityGroupIngressInput struct { // For the ICMP type number, use -1 to specify all ICMP types. FromPort *int64 `type:"integer"` - // The ID of the security group. Required for a security group in a nondefault - // VPC. + // The ID of the security group. You must specify either the security group + // ID or the security group name in the request. For security groups in a nondefault + // VPC, you must specify the security group ID. GroupId *string `type:"string"` - // [EC2-Classic, default VPC] The name of the security group. + // [EC2-Classic, default VPC] The name of the security group. You must specify + // either the security group ID or the security group name in the request. GroupName *string `type:"string"` - // A set of IP permissions. You can't specify a source security group and a - // CIDR IP address range. + // One or more sets of IP permissions. You can't specify a source security group + // and a CIDR IP address range in the same set of permissions. IpPermissions []*IpPermission `locationNameList:"item" type:"list"` // The IP protocol name (tcp, udp, icmp) or number (see Protocol Numbers (http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml)). @@ -51922,7 +60465,7 @@ func (s *RevokeSecurityGroupIngressInput) SetToPort(v int64) *RevokeSecurityGrou return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngressOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RevokeSecurityGroupIngressOutput type RevokeSecurityGroupIngressOutput struct { _ struct{} `type:"structure"` } @@ -51938,7 +60481,7 @@ func (s RevokeSecurityGroupIngressOutput) GoString() string { } // Describes a route in a route table. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Route +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Route type Route struct { _ struct{} `type:"structure"` @@ -52071,7 +60614,7 @@ func (s *Route) SetVpcPeeringConnectionId(v string) *Route { } // Describes a route table. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RouteTable +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RouteTable type RouteTable struct { _ struct{} `type:"structure"` @@ -52141,7 +60684,7 @@ func (s *RouteTable) SetVpcId(v string) *RouteTable { } // Describes an association between a route table and a subnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RouteTableAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RouteTableAssociation type RouteTableAssociation struct { _ struct{} `type:"structure"` @@ -52193,20 +60736,17 @@ func (s *RouteTableAssociation) SetSubnetId(v string) *RouteTableAssociation { } // Contains the parameters for RunInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstancesRequest type RunInstancesInput struct { _ struct{} `type:"structure"` // Reserved. AdditionalInfo *string `locationName:"additionalInfo" type:"string"` - // The block device mapping. - // - // Supplying both a snapshot ID and an encryption value as arguments for block-device - // mapping results in an error. This is because only blank volumes can be encrypted - // on start, and these are not created from a snapshot. If a snapshot is the - // basis for the volume, it contains data by definition and its encryption status - // cannot be changed using this action. + // One or more block device mapping entries. You can't specify both a snapshot + // ID and an encryption value. This is because only blank volumes can be encrypted + // on creation. If a snapshot is the basis for a volume, it is not blank and + // its encryption status is used for the volume encryption status. BlockDeviceMappings []*BlockDeviceMapping `locationName:"BlockDeviceMapping" locationNameList:"BlockDeviceMapping" type:"list"` // Unique, case-sensitive identifier you provide to ensure the idempotency of @@ -52215,6 +60755,14 @@ type RunInstancesInput struct { // Constraints: Maximum 64 ASCII characters ClientToken *string `locationName:"clientToken" type:"string"` + // The credit option for CPU usage of the instance. Valid values are standard + // and unlimited. To change this attribute after launch, use ModifyInstanceCreditSpecification. + // For more information, see T2 Instances (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-instances.html) + // in the Amazon Elastic Compute Cloud User Guide. + // + // Default: standard + CreditSpecification *CreditSpecificationRequest `type:"structure"` + // If you set this parameter to true, you can't terminate the instance using // the Amazon EC2 console, CLI, or API; otherwise, you can. To change this attribute // to false after launch, use ModifyInstanceAttribute. Alternatively, if you @@ -52230,25 +60778,25 @@ type RunInstancesInput struct { // it is UnauthorizedOperation. DryRun *bool `locationName:"dryRun" type:"boolean"` - // Indicates whether the instance is optimized for EBS I/O. This optimization + // Indicates whether the instance is optimized for Amazon EBS I/O. This optimization // provides dedicated throughput to Amazon EBS and an optimized configuration - // stack to provide optimal EBS I/O performance. This optimization isn't available - // with all instance types. Additional usage charges apply when using an EBS-optimized - // instance. + // stack to provide optimal Amazon EBS I/O performance. This optimization isn't + // available with all instance types. Additional usage charges apply when using + // an EBS-optimized instance. // // Default: false EbsOptimized *bool `locationName:"ebsOptimized" type:"boolean"` - // An Elastic GPU to associate with the instance. + // An elastic GPU to associate with the instance. ElasticGpuSpecification []*ElasticGpuSpecification `locationNameList:"item" type:"list"` // The IAM instance profile. IamInstanceProfile *IamInstanceProfileSpecification `locationName:"iamInstanceProfile" type:"structure"` - // The ID of the AMI, which you can get by calling DescribeImages. - // - // ImageId is a required field - ImageId *string `type:"string" required:"true"` + // The ID of the AMI, which you can get by calling DescribeImages. An AMI is + // required to launch an instance and must be specified here or in a launch + // template. + ImageId *string `type:"string"` // Indicates whether an instance stops or terminates when you initiate shutdown // from the instance (using the operating system command for system shutdown). @@ -52256,6 +60804,9 @@ type RunInstancesInput struct { // Default: stop InstanceInitiatedShutdownBehavior *string `locationName:"instanceInitiatedShutdownBehavior" type:"string" enum:"ShutdownBehavior"` + // The market (purchasing) option for the instances. + InstanceMarketOptions *InstanceMarketOptionsRequest `type:"structure"` + // The instance type. For more information, see Instance Types (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html) // in the Amazon Elastic Compute Cloud User Guide. // @@ -52290,6 +60841,10 @@ type RunInstancesInput struct { // you choose an AMI that is configured to allow users another way to log in. KeyName *string `type:"string"` + // The launch template to use to launch the instances. Any parameters that you + // specify in RunInstances override the same parameters in the launch template. + LaunchTemplate *LaunchTemplateSpecification `type:"structure"` + // The maximum number of instances to launch. If you specify more instances // than Amazon EC2 can launch in the target Availability Zone, Amazon EC2 launches // the largest possible number of instances above MinCount. @@ -52361,9 +60916,9 @@ type RunInstancesInput struct { // The user data to make available to the instance. For more information, see // Running Commands on Your Linux Instance at Launch (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) // (Linux) and Adding User Data (http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-instance-metadata.html#instancedata-add-user-data) - // (Windows). If you are using an AWS SDK or command line tool, Base64-encoding - // is performed for you, and you can load the text from a file. Otherwise, you - // must provide Base64-encoded text. + // (Windows). If you are using a command line tool, base64-encoding is performed + // for you, and you can load the text from a file. Otherwise, you must provide + // base64-encoded text. UserData *string `type:"string"` } @@ -52380,15 +60935,17 @@ func (s RunInstancesInput) GoString() string { // Validate inspects the fields of the type to determine if they are valid. func (s *RunInstancesInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "RunInstancesInput"} - if s.ImageId == nil { - invalidParams.Add(request.NewErrParamRequired("ImageId")) - } if s.MaxCount == nil { invalidParams.Add(request.NewErrParamRequired("MaxCount")) } if s.MinCount == nil { invalidParams.Add(request.NewErrParamRequired("MinCount")) } + if s.CreditSpecification != nil { + if err := s.CreditSpecification.Validate(); err != nil { + invalidParams.AddNested("CreditSpecification", err.(request.ErrInvalidParams)) + } + } if s.ElasticGpuSpecification != nil { for i, v := range s.ElasticGpuSpecification { if v == nil { @@ -52439,6 +60996,12 @@ func (s *RunInstancesInput) SetClientToken(v string) *RunInstancesInput { return s } +// SetCreditSpecification sets the CreditSpecification field's value. +func (s *RunInstancesInput) SetCreditSpecification(v *CreditSpecificationRequest) *RunInstancesInput { + s.CreditSpecification = v + return s +} + // SetDisableApiTermination sets the DisableApiTermination field's value. func (s *RunInstancesInput) SetDisableApiTermination(v bool) *RunInstancesInput { s.DisableApiTermination = &v @@ -52481,6 +61044,12 @@ func (s *RunInstancesInput) SetInstanceInitiatedShutdownBehavior(v string) *RunI return s } +// SetInstanceMarketOptions sets the InstanceMarketOptions field's value. +func (s *RunInstancesInput) SetInstanceMarketOptions(v *InstanceMarketOptionsRequest) *RunInstancesInput { + s.InstanceMarketOptions = v + return s +} + // SetInstanceType sets the InstanceType field's value. func (s *RunInstancesInput) SetInstanceType(v string) *RunInstancesInput { s.InstanceType = &v @@ -52511,6 +61080,12 @@ func (s *RunInstancesInput) SetKeyName(v string) *RunInstancesInput { return s } +// SetLaunchTemplate sets the LaunchTemplate field's value. +func (s *RunInstancesInput) SetLaunchTemplate(v *LaunchTemplateSpecification) *RunInstancesInput { + s.LaunchTemplate = v + return s +} + // SetMaxCount sets the MaxCount field's value. func (s *RunInstancesInput) SetMaxCount(v int64) *RunInstancesInput { s.MaxCount = &v @@ -52584,7 +61159,7 @@ func (s *RunInstancesInput) SetUserData(v string) *RunInstancesInput { } // Describes the monitoring of an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstancesMonitoringEnabled +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunInstancesMonitoringEnabled type RunInstancesMonitoringEnabled struct { _ struct{} `type:"structure"` @@ -52625,7 +61200,7 @@ func (s *RunInstancesMonitoringEnabled) SetEnabled(v bool) *RunInstancesMonitori } // Contains the parameters for RunScheduledInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstancesRequest type RunScheduledInstancesInput struct { _ struct{} `type:"structure"` @@ -52718,7 +61293,7 @@ func (s *RunScheduledInstancesInput) SetScheduledInstanceId(v string) *RunSchedu } // Contains the output of RunScheduledInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/RunScheduledInstancesResult type RunScheduledInstancesOutput struct { _ struct{} `type:"structure"` @@ -52744,7 +61319,7 @@ func (s *RunScheduledInstancesOutput) SetInstanceIdSet(v []*string) *RunSchedule // Describes the storage parameters for S3 and S3 buckets for an instance store-backed // AMI. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/S3Storage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/S3Storage type S3Storage struct { _ struct{} `type:"structure"` @@ -52812,7 +61387,7 @@ func (s *S3Storage) SetUploadPolicySignature(v string) *S3Storage { } // Describes a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstance +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstance type ScheduledInstance struct { _ struct{} `type:"structure"` @@ -52963,7 +61538,7 @@ func (s *ScheduledInstance) SetTotalScheduledInstanceHours(v int64) *ScheduledIn } // Describes a schedule that is available for your Scheduled Instances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstanceAvailability +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstanceAvailability type ScheduledInstanceAvailability struct { _ struct{} `type:"structure"` @@ -53097,7 +61672,7 @@ func (s *ScheduledInstanceAvailability) SetTotalScheduledInstanceHours(v int64) } // Describes the recurring schedule for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstanceRecurrence +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstanceRecurrence type ScheduledInstanceRecurrence struct { _ struct{} `type:"structure"` @@ -53162,7 +61737,7 @@ func (s *ScheduledInstanceRecurrence) SetOccurrenceUnit(v string) *ScheduledInst } // Describes the recurring schedule for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstanceRecurrenceRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstanceRecurrenceRequest type ScheduledInstanceRecurrenceRequest struct { _ struct{} `type:"structure"` @@ -53230,11 +61805,11 @@ func (s *ScheduledInstanceRecurrenceRequest) SetOccurrenceUnit(v string) *Schedu } // Describes a block device mapping for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesBlockDeviceMapping +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesBlockDeviceMapping type ScheduledInstancesBlockDeviceMapping struct { _ struct{} `type:"structure"` - // The device name exposed to the instance (for example, /dev/sdh or xvdh). + // The device name (for example, /dev/sdh or xvdh). DeviceName *string `type:"string"` // Parameters used to set up EBS volumes automatically when the instance is @@ -53247,7 +61822,7 @@ type ScheduledInstancesBlockDeviceMapping struct { // The virtual device name (ephemeralN). Instance store volumes are numbered // starting from 0. An instance type with two available instance store volumes - // can specify mappings for ephemeral0 and ephemeral1.The number of available + // can specify mappings for ephemeral0 and ephemeral1. The number of available // instance store volumes depends on the instance type. After you connect to // the instance, you must mount the volume. // @@ -53293,7 +61868,7 @@ func (s *ScheduledInstancesBlockDeviceMapping) SetVirtualName(v string) *Schedul } // Describes an EBS volume for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesEbs +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesEbs type ScheduledInstancesEbs struct { _ struct{} `type:"structure"` @@ -53382,7 +61957,7 @@ func (s *ScheduledInstancesEbs) SetVolumeType(v string) *ScheduledInstancesEbs { } // Describes an IAM instance profile for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesIamInstanceProfile +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesIamInstanceProfile type ScheduledInstancesIamInstanceProfile struct { _ struct{} `type:"structure"` @@ -53416,7 +61991,7 @@ func (s *ScheduledInstancesIamInstanceProfile) SetName(v string) *ScheduledInsta } // Describes an IPv6 address. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesIpv6Address +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesIpv6Address type ScheduledInstancesIpv6Address struct { _ struct{} `type:"structure"` @@ -53445,7 +62020,7 @@ func (s *ScheduledInstancesIpv6Address) SetIpv6Address(v string) *ScheduledInsta // If you are launching the Scheduled Instance in EC2-VPC, you must specify // the ID of the subnet. You can specify the subnet using either SubnetId or // NetworkInterface. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesLaunchSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesLaunchSpecification type ScheduledInstancesLaunchSpecification struct { _ struct{} `type:"structure"` @@ -53608,7 +62183,7 @@ func (s *ScheduledInstancesLaunchSpecification) SetUserData(v string) *Scheduled } // Describes whether monitoring is enabled for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesMonitoring +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesMonitoring type ScheduledInstancesMonitoring struct { _ struct{} `type:"structure"` @@ -53633,7 +62208,7 @@ func (s *ScheduledInstancesMonitoring) SetEnabled(v bool) *ScheduledInstancesMon } // Describes a network interface for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesNetworkInterface +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesNetworkInterface type ScheduledInstancesNetworkInterface struct { _ struct{} `type:"structure"` @@ -53762,7 +62337,7 @@ func (s *ScheduledInstancesNetworkInterface) SetSubnetId(v string) *ScheduledIns } // Describes the placement for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesPlacement +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesPlacement type ScheduledInstancesPlacement struct { _ struct{} `type:"structure"` @@ -53796,7 +62371,7 @@ func (s *ScheduledInstancesPlacement) SetGroupName(v string) *ScheduledInstances } // Describes a private IPv4 address for a Scheduled Instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesPrivateIpAddressConfig +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ScheduledInstancesPrivateIpAddressConfig type ScheduledInstancesPrivateIpAddressConfig struct { _ struct{} `type:"structure"` @@ -53831,7 +62406,7 @@ func (s *ScheduledInstancesPrivateIpAddressConfig) SetPrivateIpAddress(v string) } // Describes a security group -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SecurityGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SecurityGroup type SecurityGroup struct { _ struct{} `type:"structure"` @@ -53918,8 +62493,42 @@ func (s *SecurityGroup) SetVpcId(v string) *SecurityGroup { return s } +// Describes a security group. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SecurityGroupIdentifier +type SecurityGroupIdentifier struct { + _ struct{} `type:"structure"` + + // The ID of the security group. + GroupId *string `locationName:"groupId" type:"string"` + + // The name of the security group. + GroupName *string `locationName:"groupName" type:"string"` +} + +// String returns the string representation +func (s SecurityGroupIdentifier) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SecurityGroupIdentifier) GoString() string { + return s.String() +} + +// SetGroupId sets the GroupId field's value. +func (s *SecurityGroupIdentifier) SetGroupId(v string) *SecurityGroupIdentifier { + s.GroupId = &v + return s +} + +// SetGroupName sets the GroupName field's value. +func (s *SecurityGroupIdentifier) SetGroupName(v string) *SecurityGroupIdentifier { + s.GroupName = &v + return s +} + // Describes a VPC with a security group that references your security group. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SecurityGroupReference +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SecurityGroupReference type SecurityGroupReference struct { _ struct{} `type:"structure"` @@ -53965,9 +62574,221 @@ func (s *SecurityGroupReference) SetVpcPeeringConnectionId(v string) *SecurityGr return s } +// Describes a service configuration for a VPC endpoint service. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ServiceConfiguration +type ServiceConfiguration struct { + _ struct{} `type:"structure"` + + // Indicates whether requests from other AWS accounts to create an endpoint + // to the service must first be accepted. + AcceptanceRequired *bool `locationName:"acceptanceRequired" type:"boolean"` + + // In the Availability Zones in which the service is available. + AvailabilityZones []*string `locationName:"availabilityZoneSet" locationNameList:"item" type:"list"` + + // The DNS names for the service. + BaseEndpointDnsNames []*string `locationName:"baseEndpointDnsNameSet" locationNameList:"item" type:"list"` + + // The Amazon Resource Names (ARNs) of the Network Load Balancers for the service. + NetworkLoadBalancerArns []*string `locationName:"networkLoadBalancerArnSet" locationNameList:"item" type:"list"` + + // The private DNS name for the service. + PrivateDnsName *string `locationName:"privateDnsName" type:"string"` + + // The ID of the service. + ServiceId *string `locationName:"serviceId" type:"string"` + + // The name of the service. + ServiceName *string `locationName:"serviceName" type:"string"` + + // The service state. + ServiceState *string `locationName:"serviceState" type:"string" enum:"ServiceState"` + + // The type of service. + ServiceType []*ServiceTypeDetail `locationName:"serviceType" locationNameList:"item" type:"list"` +} + +// String returns the string representation +func (s ServiceConfiguration) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ServiceConfiguration) GoString() string { + return s.String() +} + +// SetAcceptanceRequired sets the AcceptanceRequired field's value. +func (s *ServiceConfiguration) SetAcceptanceRequired(v bool) *ServiceConfiguration { + s.AcceptanceRequired = &v + return s +} + +// SetAvailabilityZones sets the AvailabilityZones field's value. +func (s *ServiceConfiguration) SetAvailabilityZones(v []*string) *ServiceConfiguration { + s.AvailabilityZones = v + return s +} + +// SetBaseEndpointDnsNames sets the BaseEndpointDnsNames field's value. +func (s *ServiceConfiguration) SetBaseEndpointDnsNames(v []*string) *ServiceConfiguration { + s.BaseEndpointDnsNames = v + return s +} + +// SetNetworkLoadBalancerArns sets the NetworkLoadBalancerArns field's value. +func (s *ServiceConfiguration) SetNetworkLoadBalancerArns(v []*string) *ServiceConfiguration { + s.NetworkLoadBalancerArns = v + return s +} + +// SetPrivateDnsName sets the PrivateDnsName field's value. +func (s *ServiceConfiguration) SetPrivateDnsName(v string) *ServiceConfiguration { + s.PrivateDnsName = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *ServiceConfiguration) SetServiceId(v string) *ServiceConfiguration { + s.ServiceId = &v + return s +} + +// SetServiceName sets the ServiceName field's value. +func (s *ServiceConfiguration) SetServiceName(v string) *ServiceConfiguration { + s.ServiceName = &v + return s +} + +// SetServiceState sets the ServiceState field's value. +func (s *ServiceConfiguration) SetServiceState(v string) *ServiceConfiguration { + s.ServiceState = &v + return s +} + +// SetServiceType sets the ServiceType field's value. +func (s *ServiceConfiguration) SetServiceType(v []*ServiceTypeDetail) *ServiceConfiguration { + s.ServiceType = v + return s +} + +// Describes a VPC endpoint service. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ServiceDetail +type ServiceDetail struct { + _ struct{} `type:"structure"` + + // Indicates whether VPC endpoint connection requests to the service must be + // accepted by the service owner. + AcceptanceRequired *bool `locationName:"acceptanceRequired" type:"boolean"` + + // The Availability Zones in which the service is available. + AvailabilityZones []*string `locationName:"availabilityZoneSet" locationNameList:"item" type:"list"` + + // The DNS names for the service. + BaseEndpointDnsNames []*string `locationName:"baseEndpointDnsNameSet" locationNameList:"item" type:"list"` + + // The AWS account ID of the service owner. + Owner *string `locationName:"owner" type:"string"` + + // The private DNS name for the service. + PrivateDnsName *string `locationName:"privateDnsName" type:"string"` + + // The Amazon Resource Name (ARN) of the service. + ServiceName *string `locationName:"serviceName" type:"string"` + + // The type of service. + ServiceType []*ServiceTypeDetail `locationName:"serviceType" locationNameList:"item" type:"list"` + + // Indicates whether the service supports endpoint policies. + VpcEndpointPolicySupported *bool `locationName:"vpcEndpointPolicySupported" type:"boolean"` +} + +// String returns the string representation +func (s ServiceDetail) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ServiceDetail) GoString() string { + return s.String() +} + +// SetAcceptanceRequired sets the AcceptanceRequired field's value. +func (s *ServiceDetail) SetAcceptanceRequired(v bool) *ServiceDetail { + s.AcceptanceRequired = &v + return s +} + +// SetAvailabilityZones sets the AvailabilityZones field's value. +func (s *ServiceDetail) SetAvailabilityZones(v []*string) *ServiceDetail { + s.AvailabilityZones = v + return s +} + +// SetBaseEndpointDnsNames sets the BaseEndpointDnsNames field's value. +func (s *ServiceDetail) SetBaseEndpointDnsNames(v []*string) *ServiceDetail { + s.BaseEndpointDnsNames = v + return s +} + +// SetOwner sets the Owner field's value. +func (s *ServiceDetail) SetOwner(v string) *ServiceDetail { + s.Owner = &v + return s +} + +// SetPrivateDnsName sets the PrivateDnsName field's value. +func (s *ServiceDetail) SetPrivateDnsName(v string) *ServiceDetail { + s.PrivateDnsName = &v + return s +} + +// SetServiceName sets the ServiceName field's value. +func (s *ServiceDetail) SetServiceName(v string) *ServiceDetail { + s.ServiceName = &v + return s +} + +// SetServiceType sets the ServiceType field's value. +func (s *ServiceDetail) SetServiceType(v []*ServiceTypeDetail) *ServiceDetail { + s.ServiceType = v + return s +} + +// SetVpcEndpointPolicySupported sets the VpcEndpointPolicySupported field's value. +func (s *ServiceDetail) SetVpcEndpointPolicySupported(v bool) *ServiceDetail { + s.VpcEndpointPolicySupported = &v + return s +} + +// Describes the type of service for a VPC endpoint. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/ServiceTypeDetail +type ServiceTypeDetail struct { + _ struct{} `type:"structure"` + + // The type of service. + ServiceType *string `locationName:"serviceType" type:"string" enum:"ServiceType"` +} + +// String returns the string representation +func (s ServiceTypeDetail) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ServiceTypeDetail) GoString() string { + return s.String() +} + +// SetServiceType sets the ServiceType field's value. +func (s *ServiceTypeDetail) SetServiceType(v string) *ServiceTypeDetail { + s.ServiceType = &v + return s +} + // Describes the time period for a Scheduled Instance to start its first schedule. // The time period must span less than one day. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SlotDateTimeRangeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SlotDateTimeRangeRequest type SlotDateTimeRangeRequest struct { _ struct{} `type:"structure"` @@ -54023,7 +62844,7 @@ func (s *SlotDateTimeRangeRequest) SetLatestTime(v time.Time) *SlotDateTimeRange } // Describes the time period for a Scheduled Instance to start its first schedule. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SlotStartTimeRangeRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SlotStartTimeRangeRequest type SlotStartTimeRangeRequest struct { _ struct{} `type:"structure"` @@ -54057,7 +62878,7 @@ func (s *SlotStartTimeRangeRequest) SetLatestTime(v time.Time) *SlotStartTimeRan } // Describes a snapshot. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Snapshot +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Snapshot type Snapshot struct { _ struct{} `type:"structure"` @@ -54215,7 +63036,7 @@ func (s *Snapshot) SetVolumeSize(v int64) *Snapshot { } // Describes the snapshot created from the imported disk. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SnapshotDetail +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SnapshotDetail type SnapshotDetail struct { _ struct{} `type:"structure"` @@ -54321,7 +63142,7 @@ func (s *SnapshotDetail) SetUserBucket(v *UserBucketDetails) *SnapshotDetail { } // The disk container object for the import snapshot request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SnapshotDiskContainer +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SnapshotDiskContainer type SnapshotDiskContainer struct { _ struct{} `type:"structure"` @@ -54376,7 +63197,7 @@ func (s *SnapshotDiskContainer) SetUserBucket(v *UserBucket) *SnapshotDiskContai } // Details about the import snapshot task. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SnapshotTaskDetail +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SnapshotTaskDetail type SnapshotTaskDetail struct { _ struct{} `type:"structure"` @@ -54472,15 +63293,15 @@ func (s *SnapshotTaskDetail) SetUserBucket(v *UserBucketDetails) *SnapshotTaskDe return s } -// Describes the data feed for a Spot instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotDatafeedSubscription +// Describes the data feed for a Spot Instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotDatafeedSubscription type SpotDatafeedSubscription struct { _ struct{} `type:"structure"` - // The Amazon S3 bucket where the Spot instance data feed is located. + // The Amazon S3 bucket where the Spot Instance data feed is located. Bucket *string `locationName:"bucket" type:"string"` - // The fault codes for the Spot instance request, if any. + // The fault codes for the Spot Instance request, if any. Fault *SpotInstanceStateFault `locationName:"fault" type:"structure"` // The AWS account ID of the account. @@ -54489,7 +63310,7 @@ type SpotDatafeedSubscription struct { // The prefix that is prepended to data feed files. Prefix *string `locationName:"prefix" type:"string"` - // The state of the Spot instance data feed subscription. + // The state of the Spot Instance data feed subscription. State *string `locationName:"state" type:"string" enum:"DatafeedSubscriptionState"` } @@ -54533,15 +63354,18 @@ func (s *SpotDatafeedSubscription) SetState(v string) *SpotDatafeedSubscription return s } -// Describes the launch specification for one or more Spot instances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetLaunchSpecification +// Describes the launch specification for one or more Spot Instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetLaunchSpecification type SpotFleetLaunchSpecification struct { _ struct{} `type:"structure"` // Deprecated. AddressingType *string `locationName:"addressingType" type:"string"` - // One or more block device mapping entries. + // One or more block device mapping entries. You can't specify both a snapshot + // ID and an encryption value. This is because only blank volumes can be encrypted + // on creation. If a snapshot is the basis for a volume, it is not blank and + // its encryption status is used for the volume encryption status. BlockDeviceMappings []*BlockDeviceMapping `locationName:"blockDeviceMapping" locationNameList:"item" type:"list"` // Indicates whether the instances are optimized for EBS I/O. This optimization @@ -54559,7 +63383,7 @@ type SpotFleetLaunchSpecification struct { // The ID of the AMI. ImageId *string `locationName:"imageId" type:"string"` - // The instance type. Note that T2 and HS1 instance types are not supported. + // The instance type. InstanceType *string `locationName:"instanceType" type:"string" enum:"InstanceType"` // The ID of the kernel. @@ -54586,10 +63410,10 @@ type SpotFleetLaunchSpecification struct { // you can specify the names or the IDs of the security groups. SecurityGroups []*GroupIdentifier `locationName:"groupSet" locationNameList:"item" type:"list"` - // The bid price per unit hour for the specified instance type. If this value - // is not specified, the default is the Spot bid price specified for the fleet. - // To determine the bid price per unit hour, divide the Spot bid price by the - // value of WeightedCapacity. + // The maximum price per unit hour that you are willing to pay for a Spot Instance. + // If this value is not specified, the default is the Spot price specified for + // the fleet. To determine the Spot price per unit hour, divide the Spot price + // by the value of WeightedCapacity. SpotPrice *string `locationName:"spotPrice" type:"string"` // The ID of the subnet in which to launch the instances. To specify multiple @@ -54753,7 +63577,7 @@ func (s *SpotFleetLaunchSpecification) SetWeightedCapacity(v float64) *SpotFleet } // Describes whether monitoring is enabled. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetMonitoring +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetMonitoring type SpotFleetMonitoring struct { _ struct{} `type:"structure"` @@ -54779,16 +63603,16 @@ func (s *SpotFleetMonitoring) SetEnabled(v bool) *SpotFleetMonitoring { return s } -// Describes a Spot fleet request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetRequestConfig +// Describes a Spot Fleet request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetRequestConfig type SpotFleetRequestConfig struct { _ struct{} `type:"structure"` - // The progress of the Spot fleet request. If there is an error, the status - // is error. After all bids are placed, the status is pending_fulfillment. If - // the size of the fleet is equal to or greater than its target capacity, the - // status is fulfilled. If the size of the fleet is decreased, the status is - // pending_termination while Spot instances are terminating. + // The progress of the Spot Fleet request. If there is an error, the status + // is error. After all requests are placed, the status is pending_fulfillment. + // If the size of the fleet is equal to or greater than its target capacity, + // the status is fulfilled. If the size of the fleet is decreased, the status + // is pending_termination while Spot Instances are terminating. ActivityStatus *string `locationName:"activityStatus" type:"string" enum:"ActivityStatus"` // The creation date and time of the request. @@ -54796,17 +63620,17 @@ type SpotFleetRequestConfig struct { // CreateTime is a required field CreateTime *time.Time `locationName:"createTime" type:"timestamp" timestampFormat:"iso8601" required:"true"` - // Information about the configuration of the Spot fleet request. + // The configuration of the Spot Fleet request. // // SpotFleetRequestConfig is a required field SpotFleetRequestConfig *SpotFleetRequestConfigData `locationName:"spotFleetRequestConfig" type:"structure" required:"true"` - // The ID of the Spot fleet request. + // The ID of the Spot Fleet request. // // SpotFleetRequestId is a required field SpotFleetRequestId *string `locationName:"spotFleetRequestId" type:"string" required:"true"` - // The state of the Spot fleet request. + // The state of the Spot Fleet request. // // SpotFleetRequestState is a required field SpotFleetRequestState *string `locationName:"spotFleetRequestState" type:"string" required:"true" enum:"BatchState"` @@ -54852,13 +63676,13 @@ func (s *SpotFleetRequestConfig) SetSpotFleetRequestState(v string) *SpotFleetRe return s } -// Describes the configuration of a Spot fleet request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetRequestConfigData +// Describes the configuration of a Spot Fleet request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetRequestConfigData type SpotFleetRequestConfigData struct { _ struct{} `type:"structure"` // Indicates how to allocate the target capacity across the Spot pools specified - // by the Spot fleet request. The default is lowestPrice. + // by the Spot Fleet request. The default is lowestPrice. AllocationStrategy *string `locationName:"allocationStrategy" type:"string" enum:"AllocationStrategy"` // A unique, case-sensitive identifier you provide to ensure idempotency of @@ -54866,54 +63690,68 @@ type SpotFleetRequestConfigData struct { // see Ensuring Idempotency (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html). ClientToken *string `locationName:"clientToken" type:"string"` - // Indicates whether running Spot instances should be terminated if the target - // capacity of the Spot fleet request is decreased below the current size of - // the Spot fleet. + // Indicates whether running Spot Instances should be terminated if the target + // capacity of the Spot Fleet request is decreased below the current size of + // the Spot Fleet. ExcessCapacityTerminationPolicy *string `locationName:"excessCapacityTerminationPolicy" type:"string" enum:"ExcessCapacityTerminationPolicy"` // The number of units fulfilled by this request compared to the set target // capacity. FulfilledCapacity *float64 `locationName:"fulfilledCapacity" type:"double"` - // Grants the Spot fleet permission to terminate Spot instances on your behalf - // when you cancel its Spot fleet request using CancelSpotFleetRequests or when - // the Spot fleet request expires, if you set terminateInstancesWithExpiration. + // Grants the Spot Fleet permission to terminate Spot Instances on your behalf + // when you cancel its Spot Fleet request using CancelSpotFleetRequests or when + // the Spot Fleet request expires, if you set terminateInstancesWithExpiration. // // IamFleetRole is a required field IamFleetRole *string `locationName:"iamFleetRole" type:"string" required:"true"` - // Information about the launch specifications for the Spot fleet request. - // - // LaunchSpecifications is a required field - LaunchSpecifications []*SpotFleetLaunchSpecification `locationName:"launchSpecifications" locationNameList:"item" min:"1" type:"list" required:"true"` + // The behavior when a Spot Instance is interrupted. The default is terminate. + InstanceInterruptionBehavior *string `locationName:"instanceInterruptionBehavior" type:"string" enum:"InstanceInterruptionBehavior"` - // Indicates whether Spot fleet should replace unhealthy instances. + // The launch specifications for the Spot Fleet request. + LaunchSpecifications []*SpotFleetLaunchSpecification `locationName:"launchSpecifications" locationNameList:"item" type:"list"` + + // The launch template and overrides. + LaunchTemplateConfigs []*LaunchTemplateConfig `locationName:"launchTemplateConfigs" locationNameList:"item" type:"list"` + + // One or more Classic Load Balancers and target groups to attach to the Spot + // Fleet request. Spot Fleet registers the running Spot Instances with the specified + // Classic Load Balancers and target groups. + // + // With Network Load Balancers, Spot Fleet cannot register instances that have + // the following instance types: C1, CC1, CC2, CG1, CG2, CR1, CS1, G1, G2, HI1, + // HS1, M1, M2, M3, and T1. + LoadBalancersConfig *LoadBalancersConfig `locationName:"loadBalancersConfig" type:"structure"` + + // Indicates whether Spot Fleet should replace unhealthy instances. ReplaceUnhealthyInstances *bool `locationName:"replaceUnhealthyInstances" type:"boolean"` - // The bid price per unit hour. - // - // SpotPrice is a required field - SpotPrice *string `locationName:"spotPrice" type:"string" required:"true"` + // The maximum price per unit hour that you are willing to pay for a Spot Instance. + // The default is the On-Demand price. + SpotPrice *string `locationName:"spotPrice" type:"string"` // The number of units to request. You can choose to set the target capacity // in terms of instances or a performance characteristic that is important to - // your application workload, such as vCPUs, memory, or I/O. + // your application workload, such as vCPUs, memory, or I/O. If the request + // type is maintain, you can specify a target capacity of 0 and add capacity + // later. // // TargetCapacity is a required field TargetCapacity *int64 `locationName:"targetCapacity" type:"integer" required:"true"` - // Indicates whether running Spot instances should be terminated when the Spot - // fleet request expires. + // Indicates whether running Spot Instances should be terminated when the Spot + // Fleet request expires. TerminateInstancesWithExpiration *bool `locationName:"terminateInstancesWithExpiration" type:"boolean"` // The type of request. Indicates whether the fleet will only request the target // capacity or also attempt to maintain it. When you request a certain target - // capacity, the fleet will only place the required bids. It will not attempt - // to replenish Spot instances if capacity is diminished, nor will it submit - // bids in alternative Spot pools if capacity is not available. When you want - // to maintain a certain target capacity, fleet will place the required bids - // to meet this target capacity. It will also automatically replenish any interrupted - // instances. Default: maintain. + // capacity, the fleet will only place the required requests. It will not attempt + // to replenish Spot Instances if capacity is diminished, nor will it submit + // requests in alternative Spot pools if capacity is not available. When you + // want to maintain a certain target capacity, fleet will place the required + // requests to meet this target capacity. It will also automatically replenish + // any interrupted instances. Default: maintain. Type *string `locationName:"type" type:"string" enum:"FleetType"` // The start date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). @@ -54921,8 +63759,8 @@ type SpotFleetRequestConfigData struct { ValidFrom *time.Time `locationName:"validFrom" type:"timestamp" timestampFormat:"iso8601"` // The end date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). - // At this point, no new Spot instance requests are placed or enabled to fulfill - // the request. + // At this point, no new Spot Instance requests are placed or able to fulfill + // the request. The default end date is 7 days from the current date. ValidUntil *time.Time `locationName:"validUntil" type:"timestamp" timestampFormat:"iso8601"` } @@ -54942,15 +63780,6 @@ func (s *SpotFleetRequestConfigData) Validate() error { if s.IamFleetRole == nil { invalidParams.Add(request.NewErrParamRequired("IamFleetRole")) } - if s.LaunchSpecifications == nil { - invalidParams.Add(request.NewErrParamRequired("LaunchSpecifications")) - } - if s.LaunchSpecifications != nil && len(s.LaunchSpecifications) < 1 { - invalidParams.Add(request.NewErrParamMinLen("LaunchSpecifications", 1)) - } - if s.SpotPrice == nil { - invalidParams.Add(request.NewErrParamRequired("SpotPrice")) - } if s.TargetCapacity == nil { invalidParams.Add(request.NewErrParamRequired("TargetCapacity")) } @@ -54964,6 +63793,21 @@ func (s *SpotFleetRequestConfigData) Validate() error { } } } + if s.LaunchTemplateConfigs != nil { + for i, v := range s.LaunchTemplateConfigs { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "LaunchTemplateConfigs", i), err.(request.ErrInvalidParams)) + } + } + } + if s.LoadBalancersConfig != nil { + if err := s.LoadBalancersConfig.Validate(); err != nil { + invalidParams.AddNested("LoadBalancersConfig", err.(request.ErrInvalidParams)) + } + } if invalidParams.Len() > 0 { return invalidParams @@ -55001,12 +63845,30 @@ func (s *SpotFleetRequestConfigData) SetIamFleetRole(v string) *SpotFleetRequest return s } +// SetInstanceInterruptionBehavior sets the InstanceInterruptionBehavior field's value. +func (s *SpotFleetRequestConfigData) SetInstanceInterruptionBehavior(v string) *SpotFleetRequestConfigData { + s.InstanceInterruptionBehavior = &v + return s +} + // SetLaunchSpecifications sets the LaunchSpecifications field's value. func (s *SpotFleetRequestConfigData) SetLaunchSpecifications(v []*SpotFleetLaunchSpecification) *SpotFleetRequestConfigData { s.LaunchSpecifications = v return s } +// SetLaunchTemplateConfigs sets the LaunchTemplateConfigs field's value. +func (s *SpotFleetRequestConfigData) SetLaunchTemplateConfigs(v []*LaunchTemplateConfig) *SpotFleetRequestConfigData { + s.LaunchTemplateConfigs = v + return s +} + +// SetLoadBalancersConfig sets the LoadBalancersConfig field's value. +func (s *SpotFleetRequestConfigData) SetLoadBalancersConfig(v *LoadBalancersConfig) *SpotFleetRequestConfigData { + s.LoadBalancersConfig = v + return s +} + // SetReplaceUnhealthyInstances sets the ReplaceUnhealthyInstances field's value. func (s *SpotFleetRequestConfigData) SetReplaceUnhealthyInstances(v bool) *SpotFleetRequestConfigData { s.ReplaceUnhealthyInstances = &v @@ -55049,8 +63911,8 @@ func (s *SpotFleetRequestConfigData) SetValidUntil(v time.Time) *SpotFleetReques return s } -// The tags for a Spot fleet resource. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetTagSpecification +// The tags for a Spot Fleet resource. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotFleetTagSpecification type SpotFleetTagSpecification struct { _ struct{} `type:"structure"` @@ -55084,67 +63946,69 @@ func (s *SpotFleetTagSpecification) SetTags(v []*Tag) *SpotFleetTagSpecification return s } -// Describes a Spot instance request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotInstanceRequest +// Describes a Spot Instance request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotInstanceRequest type SpotInstanceRequest struct { _ struct{} `type:"structure"` - // If you specified a duration and your Spot instance request was fulfilled, - // this is the fixed hourly price in effect for the Spot instance while it runs. + // If you specified a duration and your Spot Instance request was fulfilled, + // this is the fixed hourly price in effect for the Spot Instance while it runs. ActualBlockHourlyPrice *string `locationName:"actualBlockHourlyPrice" type:"string"` // The Availability Zone group. If you specify the same Availability Zone group - // for all Spot instance requests, all Spot instances are launched in the same + // for all Spot Instance requests, all Spot Instances are launched in the same // Availability Zone. AvailabilityZoneGroup *string `locationName:"availabilityZoneGroup" type:"string"` - // The duration for the Spot instance, in minutes. + // The duration for the Spot Instance, in minutes. BlockDurationMinutes *int64 `locationName:"blockDurationMinutes" type:"integer"` - // The date and time when the Spot instance request was created, in UTC format + // The date and time when the Spot Instance request was created, in UTC format // (for example, YYYY-MM-DDTHH:MM:SSZ). CreateTime *time.Time `locationName:"createTime" type:"timestamp" timestampFormat:"iso8601"` - // The fault codes for the Spot instance request, if any. + // The fault codes for the Spot Instance request, if any. Fault *SpotInstanceStateFault `locationName:"fault" type:"structure"` - // The instance ID, if an instance has been launched to fulfill the Spot instance + // The instance ID, if an instance has been launched to fulfill the Spot Instance // request. InstanceId *string `locationName:"instanceId" type:"string"` - // The instance launch group. Launch groups are Spot instances that launch together + // The behavior when a Spot Instance is interrupted. + InstanceInterruptionBehavior *string `locationName:"instanceInterruptionBehavior" type:"string" enum:"InstanceInterruptionBehavior"` + + // The instance launch group. Launch groups are Spot Instances that launch together // and terminate together. LaunchGroup *string `locationName:"launchGroup" type:"string"` // Additional information for launching instances. LaunchSpecification *LaunchSpecification `locationName:"launchSpecification" type:"structure"` - // The Availability Zone in which the bid is launched. + // The Availability Zone in which the request is launched. LaunchedAvailabilityZone *string `locationName:"launchedAvailabilityZone" type:"string"` - // The product description associated with the Spot instance. + // The product description associated with the Spot Instance. ProductDescription *string `locationName:"productDescription" type:"string" enum:"RIProductDescription"` - // The ID of the Spot instance request. + // The ID of the Spot Instance request. SpotInstanceRequestId *string `locationName:"spotInstanceRequestId" type:"string"` - // The maximum hourly price (bid) for the Spot instance launched to fulfill - // the request. + // The maximum price per hour that you are willing to pay for a Spot Instance. SpotPrice *string `locationName:"spotPrice" type:"string"` - // The state of the Spot instance request. Spot bid status information can help - // you track your Spot instance requests. For more information, see Spot Bid - // Status (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html) + // The state of the Spot Instance request. Spot status information can help + // you track your Spot Instance requests. For more information, see Spot Status + // (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html) // in the Amazon Elastic Compute Cloud User Guide. State *string `locationName:"state" type:"string" enum:"SpotInstanceState"` - // The status code and status message describing the Spot instance request. + // The status code and status message describing the Spot Instance request. Status *SpotInstanceStatus `locationName:"status" type:"structure"` // Any tags assigned to the resource. Tags []*Tag `locationName:"tagSet" locationNameList:"item" type:"list"` - // The Spot instance request type. + // The Spot Instance request type. Type *string `locationName:"type" type:"string" enum:"SpotInstanceType"` // The start date of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). @@ -55154,7 +64018,8 @@ type SpotInstanceRequest struct { // The end date of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). // If this is a one-time request, it remains active until all instances launch, // the request is canceled, or this date is reached. If the request is persistent, - // it remains active until it is canceled or this date is reached. + // it remains active until it is canceled or this date is reached. The default + // end date is 7 days from the current date. ValidUntil *time.Time `locationName:"validUntil" type:"timestamp" timestampFormat:"iso8601"` } @@ -55204,6 +64069,12 @@ func (s *SpotInstanceRequest) SetInstanceId(v string) *SpotInstanceRequest { return s } +// SetInstanceInterruptionBehavior sets the InstanceInterruptionBehavior field's value. +func (s *SpotInstanceRequest) SetInstanceInterruptionBehavior(v string) *SpotInstanceRequest { + s.InstanceInterruptionBehavior = &v + return s +} + // SetLaunchGroup sets the LaunchGroup field's value. func (s *SpotInstanceRequest) SetLaunchGroup(v string) *SpotInstanceRequest { s.LaunchGroup = &v @@ -55276,15 +64147,15 @@ func (s *SpotInstanceRequest) SetValidUntil(v time.Time) *SpotInstanceRequest { return s } -// Describes a Spot instance state change. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotInstanceStateFault +// Describes a Spot Instance state change. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotInstanceStateFault type SpotInstanceStateFault struct { _ struct{} `type:"structure"` - // The reason code for the Spot instance state change. + // The reason code for the Spot Instance state change. Code *string `locationName:"code" type:"string"` - // The message for the Spot instance state change. + // The message for the Spot Instance state change. Message *string `locationName:"message" type:"string"` } @@ -55310,12 +64181,12 @@ func (s *SpotInstanceStateFault) SetMessage(v string) *SpotInstanceStateFault { return s } -// Describes the status of a Spot instance request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotInstanceStatus +// Describes the status of a Spot Instance request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotInstanceStatus type SpotInstanceStatus struct { _ struct{} `type:"structure"` - // The status code. For a list of status codes, see Spot Bid Status Codes (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html#spot-instance-bid-status-understand) + // The status code. For a list of status codes, see Spot Status Codes (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html#spot-instance-bid-status-understand) // in the Amazon Elastic Compute Cloud User Guide. Code *string `locationName:"code" type:"string"` @@ -55355,23 +64226,91 @@ func (s *SpotInstanceStatus) SetUpdateTime(v time.Time) *SpotInstanceStatus { return s } -// Describes Spot instance placement. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotPlacement +// The options for Spot Instances. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotMarketOptions +type SpotMarketOptions struct { + _ struct{} `type:"structure"` + + // The required duration for the Spot Instances (also known as Spot blocks), + // in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, + // or 360). + BlockDurationMinutes *int64 `type:"integer"` + + // The behavior when a Spot Instance is interrupted. The default is terminate. + InstanceInterruptionBehavior *string `type:"string" enum:"InstanceInterruptionBehavior"` + + // The maximum hourly price you're willing to pay for the Spot Instances. The + // default is the On-Demand price. + MaxPrice *string `type:"string"` + + // The Spot Instance request type. + SpotInstanceType *string `type:"string" enum:"SpotInstanceType"` + + // The end date of the request. For a one-time request, the request remains + // active until all instances launch, the request is canceled, or this date + // is reached. If the request is persistent, it remains active until it is canceled + // or this date and time is reached. The default end date is 7 days from the + // current date. + ValidUntil *time.Time `type:"timestamp" timestampFormat:"iso8601"` +} + +// String returns the string representation +func (s SpotMarketOptions) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SpotMarketOptions) GoString() string { + return s.String() +} + +// SetBlockDurationMinutes sets the BlockDurationMinutes field's value. +func (s *SpotMarketOptions) SetBlockDurationMinutes(v int64) *SpotMarketOptions { + s.BlockDurationMinutes = &v + return s +} + +// SetInstanceInterruptionBehavior sets the InstanceInterruptionBehavior field's value. +func (s *SpotMarketOptions) SetInstanceInterruptionBehavior(v string) *SpotMarketOptions { + s.InstanceInterruptionBehavior = &v + return s +} + +// SetMaxPrice sets the MaxPrice field's value. +func (s *SpotMarketOptions) SetMaxPrice(v string) *SpotMarketOptions { + s.MaxPrice = &v + return s +} + +// SetSpotInstanceType sets the SpotInstanceType field's value. +func (s *SpotMarketOptions) SetSpotInstanceType(v string) *SpotMarketOptions { + s.SpotInstanceType = &v + return s +} + +// SetValidUntil sets the ValidUntil field's value. +func (s *SpotMarketOptions) SetValidUntil(v time.Time) *SpotMarketOptions { + s.ValidUntil = &v + return s +} + +// Describes Spot Instance placement. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotPlacement type SpotPlacement struct { _ struct{} `type:"structure"` // The Availability Zone. // - // [Spot fleet only] To specify multiple Availability Zones, separate them using + // [Spot Fleet only] To specify multiple Availability Zones, separate them using // commas; for example, "us-west-2a, us-west-2b". AvailabilityZone *string `locationName:"availabilityZone" type:"string"` - // The name of the placement group (for cluster instances). + // The name of the placement group. GroupName *string `locationName:"groupName" type:"string"` // The tenancy of the instance (if the instance is running in a VPC). An instance // with a tenancy of dedicated runs on single-tenant hardware. The host tenancy - // is not supported for Spot instances. + // is not supported for Spot Instances. Tenancy *string `locationName:"tenancy" type:"string" enum:"Tenancy"` } @@ -55403,22 +64342,22 @@ func (s *SpotPlacement) SetTenancy(v string) *SpotPlacement { return s } -// Describes the maximum hourly price (bid) for any Spot instance launched to -// fulfill the request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotPrice +// Describes the maximum price per hour that you are willing to pay for a Spot +// Instance. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SpotPrice type SpotPrice struct { _ struct{} `type:"structure"` // The Availability Zone. AvailabilityZone *string `locationName:"availabilityZone" type:"string"` - // The instance type. Note that T2 and HS1 instance types are not supported. + // The instance type. InstanceType *string `locationName:"instanceType" type:"string" enum:"InstanceType"` // A general description of the AMI. ProductDescription *string `locationName:"productDescription" type:"string" enum:"RIProductDescription"` - // The maximum price (bid) that you are willing to pay for a Spot instance. + // The maximum price per hour that you are willing to pay for a Spot Instance. SpotPrice *string `locationName:"spotPrice" type:"string"` // The date and time the request was created, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). @@ -55466,7 +64405,7 @@ func (s *SpotPrice) SetTimestamp(v time.Time) *SpotPrice { } // Describes a stale rule in a security group. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StaleIpPermission +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StaleIpPermission type StaleIpPermission struct { _ struct{} `type:"structure"` @@ -55541,7 +64480,7 @@ func (s *StaleIpPermission) SetUserIdGroupPairs(v []*UserIdGroupPair) *StaleIpPe } // Describes a stale security group (a security group that contains stale rules). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StaleSecurityGroup +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StaleSecurityGroup type StaleSecurityGroup struct { _ struct{} `type:"structure"` @@ -55613,7 +64552,7 @@ func (s *StaleSecurityGroup) SetVpcId(v string) *StaleSecurityGroup { } // Contains the parameters for StartInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstancesRequest type StartInstancesInput struct { _ struct{} `type:"structure"` @@ -55674,7 +64613,7 @@ func (s *StartInstancesInput) SetInstanceIds(v []*string) *StartInstancesInput { } // Contains the output of StartInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StartInstancesResult type StartInstancesOutput struct { _ struct{} `type:"structure"` @@ -55699,7 +64638,7 @@ func (s *StartInstancesOutput) SetStartingInstances(v []*InstanceStateChange) *S } // Describes a state change. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StateReason +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StateReason type StateReason struct { _ struct{} `type:"structure"` @@ -55716,8 +64655,8 @@ type StateReason struct { // // * Server.ScheduledStop: The instance was stopped due to a scheduled retirement. // - // * Server.SpotInstanceTermination: A Spot instance was terminated due to - // an increase in the market price. + // * Server.SpotInstanceTermination: A Spot Instance was terminated due to + // an increase in the Spot price. // // * Client.InternalError: A client error caused the instance to terminate // on launch. @@ -55725,6 +64664,9 @@ type StateReason struct { // * Client.InstanceInitiatedShutdown: The instance was shut down using the // shutdown -h command from the instance. // + // * Client.InstanceTerminated: The instance was terminated or rebooted during + // AMI creation. + // // * Client.UserInitiatedShutdown: The instance was shut down using the Amazon // EC2 API. // @@ -55759,7 +64701,7 @@ func (s *StateReason) SetMessage(v string) *StateReason { } // Contains the parameters for StopInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstancesRequest type StopInstancesInput struct { _ struct{} `type:"structure"` @@ -55825,7 +64767,7 @@ func (s *StopInstancesInput) SetInstanceIds(v []*string) *StopInstancesInput { } // Contains the output of StopInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StopInstancesResult type StopInstancesOutput struct { _ struct{} `type:"structure"` @@ -55850,7 +64792,7 @@ func (s *StopInstancesOutput) SetStoppingInstances(v []*InstanceStateChange) *St } // Describes the storage location for an instance store-backed AMI. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Storage +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Storage type Storage struct { _ struct{} `type:"structure"` @@ -55875,7 +64817,7 @@ func (s *Storage) SetS3(v *S3Storage) *Storage { } // Describes a storage location in Amazon S3. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StorageLocation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/StorageLocation type StorageLocation struct { _ struct{} `type:"structure"` @@ -55909,7 +64851,7 @@ func (s *StorageLocation) SetKey(v string) *StorageLocation { } // Describes a subnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Subnet +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Subnet type Subnet struct { _ struct{} `type:"structure"` @@ -56027,7 +64969,7 @@ func (s *Subnet) SetVpcId(v string) *Subnet { } // Describes the state of a CIDR block. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SubnetCidrBlockState +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SubnetCidrBlockState type SubnetCidrBlockState struct { _ struct{} `type:"structure"` @@ -56061,7 +65003,7 @@ func (s *SubnetCidrBlockState) SetStatusMessage(v string) *SubnetCidrBlockState } // Describes an IPv6 CIDR block associated with a subnet. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SubnetIpv6CidrBlockAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SubnetIpv6CidrBlockAssociation type SubnetIpv6CidrBlockAssociation struct { _ struct{} `type:"structure"` @@ -56103,8 +65045,34 @@ func (s *SubnetIpv6CidrBlockAssociation) SetIpv6CidrBlockState(v *SubnetCidrBloc return s } +// Describes the T2 instance whose credit option for CPU usage was successfully +// modified. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/SuccessfulInstanceCreditSpecificationItem +type SuccessfulInstanceCreditSpecificationItem struct { + _ struct{} `type:"structure"` + + // The ID of the instance. + InstanceId *string `locationName:"instanceId" type:"string"` +} + +// String returns the string representation +func (s SuccessfulInstanceCreditSpecificationItem) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SuccessfulInstanceCreditSpecificationItem) GoString() string { + return s.String() +} + +// SetInstanceId sets the InstanceId field's value. +func (s *SuccessfulInstanceCreditSpecificationItem) SetInstanceId(v string) *SuccessfulInstanceCreditSpecificationItem { + s.InstanceId = &v + return s +} + // Describes a tag. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Tag +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Tag type Tag struct { _ struct{} `type:"structure"` @@ -56144,7 +65112,7 @@ func (s *Tag) SetValue(v string) *Tag { } // Describes a tag. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TagDescription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TagDescription type TagDescription struct { _ struct{} `type:"structure"` @@ -56196,7 +65164,7 @@ func (s *TagDescription) SetValue(v string) *TagDescription { } // The tags to apply to a resource when the resource is being created. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TagSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TagSpecification type TagSpecification struct { _ struct{} `type:"structure"` @@ -56231,7 +65199,7 @@ func (s *TagSpecification) SetTags(v []*Tag) *TagSpecification { } // Information about the Convertible Reserved Instance offering. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetConfiguration type TargetConfiguration struct { _ struct{} `type:"structure"` @@ -56266,7 +65234,7 @@ func (s *TargetConfiguration) SetOfferingId(v string) *TargetConfiguration { } // Details about the target configuration. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetConfigurationRequest type TargetConfigurationRequest struct { _ struct{} `type:"structure"` @@ -56315,8 +65283,102 @@ func (s *TargetConfigurationRequest) SetOfferingId(v string) *TargetConfiguratio return s } +// Describes a load balancer target group. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetGroup +type TargetGroup struct { + _ struct{} `type:"structure"` + + // The Amazon Resource Name (ARN) of the target group. + // + // Arn is a required field + Arn *string `locationName:"arn" type:"string" required:"true"` +} + +// String returns the string representation +func (s TargetGroup) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s TargetGroup) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *TargetGroup) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "TargetGroup"} + if s.Arn == nil { + invalidParams.Add(request.NewErrParamRequired("Arn")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetArn sets the Arn field's value. +func (s *TargetGroup) SetArn(v string) *TargetGroup { + s.Arn = &v + return s +} + +// Describes the target groups to attach to a Spot Fleet. Spot Fleet registers +// the running Spot Instances with these target groups. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetGroupsConfig +type TargetGroupsConfig struct { + _ struct{} `type:"structure"` + + // One or more target groups. + // + // TargetGroups is a required field + TargetGroups []*TargetGroup `locationName:"targetGroups" locationNameList:"item" min:"1" type:"list" required:"true"` +} + +// String returns the string representation +func (s TargetGroupsConfig) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s TargetGroupsConfig) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *TargetGroupsConfig) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "TargetGroupsConfig"} + if s.TargetGroups == nil { + invalidParams.Add(request.NewErrParamRequired("TargetGroups")) + } + if s.TargetGroups != nil && len(s.TargetGroups) < 1 { + invalidParams.Add(request.NewErrParamMinLen("TargetGroups", 1)) + } + if s.TargetGroups != nil { + for i, v := range s.TargetGroups { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "TargetGroups", i), err.(request.ErrInvalidParams)) + } + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetTargetGroups sets the TargetGroups field's value. +func (s *TargetGroupsConfig) SetTargetGroups(v []*TargetGroup) *TargetGroupsConfig { + s.TargetGroups = v + return s +} + // The total value of the new Convertible Reserved Instances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetReservationValue +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TargetReservationValue type TargetReservationValue struct { _ struct{} `type:"structure"` @@ -56353,7 +65415,7 @@ func (s *TargetReservationValue) SetTargetConfiguration(v *TargetConfiguration) } // Contains the parameters for TerminateInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstancesRequest type TerminateInstancesInput struct { _ struct{} `type:"structure"` @@ -56408,7 +65470,7 @@ func (s *TerminateInstancesInput) SetInstanceIds(v []*string) *TerminateInstance } // Contains the output of TerminateInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/TerminateInstancesResult type TerminateInstancesOutput struct { _ struct{} `type:"structure"` @@ -56432,7 +65494,7 @@ func (s *TerminateInstancesOutput) SetTerminatingInstances(v []*InstanceStateCha return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6AddressesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6AddressesRequest type UnassignIpv6AddressesInput struct { _ struct{} `type:"structure"` @@ -56485,7 +65547,7 @@ func (s *UnassignIpv6AddressesInput) SetNetworkInterfaceId(v string) *UnassignIp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6AddressesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignIpv6AddressesResult type UnassignIpv6AddressesOutput struct { _ struct{} `type:"structure"` @@ -56519,7 +65581,7 @@ func (s *UnassignIpv6AddressesOutput) SetUnassignedIpv6Addresses(v []*string) *U } // Contains the parameters for UnassignPrivateIpAddresses. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddressesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddressesRequest type UnassignPrivateIpAddressesInput struct { _ struct{} `type:"structure"` @@ -56573,7 +65635,7 @@ func (s *UnassignPrivateIpAddressesInput) SetPrivateIpAddresses(v []*string) *Un return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddressesOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnassignPrivateIpAddressesOutput type UnassignPrivateIpAddressesOutput struct { _ struct{} `type:"structure"` } @@ -56589,7 +65651,7 @@ func (s UnassignPrivateIpAddressesOutput) GoString() string { } // Contains the parameters for UnmonitorInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstancesRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstancesRequest type UnmonitorInstancesInput struct { _ struct{} `type:"structure"` @@ -56641,7 +65703,7 @@ func (s *UnmonitorInstancesInput) SetInstanceIds(v []*string) *UnmonitorInstance } // Contains the output of UnmonitorInstances. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstancesResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnmonitorInstancesResult type UnmonitorInstancesOutput struct { _ struct{} `type:"structure"` @@ -56665,8 +65727,78 @@ func (s *UnmonitorInstancesOutput) SetInstanceMonitorings(v []*InstanceMonitorin return s } +// Describes the T2 instance whose credit option for CPU usage was not modified. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnsuccessfulInstanceCreditSpecificationItem +type UnsuccessfulInstanceCreditSpecificationItem struct { + _ struct{} `type:"structure"` + + // The applicable error for the T2 instance whose credit option for CPU usage + // was not modified. + Error *UnsuccessfulInstanceCreditSpecificationItemError `locationName:"error" type:"structure"` + + // The ID of the instance. + InstanceId *string `locationName:"instanceId" type:"string"` +} + +// String returns the string representation +func (s UnsuccessfulInstanceCreditSpecificationItem) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UnsuccessfulInstanceCreditSpecificationItem) GoString() string { + return s.String() +} + +// SetError sets the Error field's value. +func (s *UnsuccessfulInstanceCreditSpecificationItem) SetError(v *UnsuccessfulInstanceCreditSpecificationItemError) *UnsuccessfulInstanceCreditSpecificationItem { + s.Error = v + return s +} + +// SetInstanceId sets the InstanceId field's value. +func (s *UnsuccessfulInstanceCreditSpecificationItem) SetInstanceId(v string) *UnsuccessfulInstanceCreditSpecificationItem { + s.InstanceId = &v + return s +} + +// Information about the error for the T2 instance whose credit option for CPU +// usage was not modified. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnsuccessfulInstanceCreditSpecificationItemError +type UnsuccessfulInstanceCreditSpecificationItemError struct { + _ struct{} `type:"structure"` + + // The error code. + Code *string `locationName:"code" type:"string" enum:"UnsuccessfulInstanceCreditSpecificationErrorCode"` + + // The applicable error message. + Message *string `locationName:"message" type:"string"` +} + +// String returns the string representation +func (s UnsuccessfulInstanceCreditSpecificationItemError) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UnsuccessfulInstanceCreditSpecificationItemError) GoString() string { + return s.String() +} + +// SetCode sets the Code field's value. +func (s *UnsuccessfulInstanceCreditSpecificationItemError) SetCode(v string) *UnsuccessfulInstanceCreditSpecificationItemError { + s.Code = &v + return s +} + +// SetMessage sets the Message field's value. +func (s *UnsuccessfulInstanceCreditSpecificationItemError) SetMessage(v string) *UnsuccessfulInstanceCreditSpecificationItemError { + s.Message = &v + return s +} + // Information about items that were not successfully processed in a batch call. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnsuccessfulItem +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnsuccessfulItem type UnsuccessfulItem struct { _ struct{} `type:"structure"` @@ -56703,7 +65835,7 @@ func (s *UnsuccessfulItem) SetResourceId(v string) *UnsuccessfulItem { // Information about the error that occurred. For more information about errors, // see Error Codes (http://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html). -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnsuccessfulItemError +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UnsuccessfulItemError type UnsuccessfulItemError struct { _ struct{} `type:"structure"` @@ -56740,8 +65872,204 @@ func (s *UnsuccessfulItemError) SetMessage(v string) *UnsuccessfulItemError { return s } +// Contains the parameters for UpdateSecurityGroupRuleDescriptionsEgress. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsEgressRequest +type UpdateSecurityGroupRuleDescriptionsEgressInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the security group. You must specify either the security group + // ID or the security group name in the request. For security groups in a nondefault + // VPC, you must specify the security group ID. + GroupId *string `type:"string"` + + // [Default VPC] The name of the security group. You must specify either the + // security group ID or the security group name in the request. + GroupName *string `type:"string"` + + // The IP permissions for the security group rule. + // + // IpPermissions is a required field + IpPermissions []*IpPermission `locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsEgressInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsEgressInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *UpdateSecurityGroupRuleDescriptionsEgressInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "UpdateSecurityGroupRuleDescriptionsEgressInput"} + if s.IpPermissions == nil { + invalidParams.Add(request.NewErrParamRequired("IpPermissions")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *UpdateSecurityGroupRuleDescriptionsEgressInput) SetDryRun(v bool) *UpdateSecurityGroupRuleDescriptionsEgressInput { + s.DryRun = &v + return s +} + +// SetGroupId sets the GroupId field's value. +func (s *UpdateSecurityGroupRuleDescriptionsEgressInput) SetGroupId(v string) *UpdateSecurityGroupRuleDescriptionsEgressInput { + s.GroupId = &v + return s +} + +// SetGroupName sets the GroupName field's value. +func (s *UpdateSecurityGroupRuleDescriptionsEgressInput) SetGroupName(v string) *UpdateSecurityGroupRuleDescriptionsEgressInput { + s.GroupName = &v + return s +} + +// SetIpPermissions sets the IpPermissions field's value. +func (s *UpdateSecurityGroupRuleDescriptionsEgressInput) SetIpPermissions(v []*IpPermission) *UpdateSecurityGroupRuleDescriptionsEgressInput { + s.IpPermissions = v + return s +} + +// Contains the output of UpdateSecurityGroupRuleDescriptionsEgress. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsEgressResult +type UpdateSecurityGroupRuleDescriptionsEgressOutput struct { + _ struct{} `type:"structure"` + + // Returns true if the request succeeds; otherwise, returns an error. + Return *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsEgressOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsEgressOutput) GoString() string { + return s.String() +} + +// SetReturn sets the Return field's value. +func (s *UpdateSecurityGroupRuleDescriptionsEgressOutput) SetReturn(v bool) *UpdateSecurityGroupRuleDescriptionsEgressOutput { + s.Return = &v + return s +} + +// Contains the parameters for UpdateSecurityGroupRuleDescriptionsIngress. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsIngressRequest +type UpdateSecurityGroupRuleDescriptionsIngressInput struct { + _ struct{} `type:"structure"` + + // Checks whether you have the required permissions for the action, without + // actually making the request, and provides an error response. If you have + // the required permissions, the error response is DryRunOperation. Otherwise, + // it is UnauthorizedOperation. + DryRun *bool `type:"boolean"` + + // The ID of the security group. You must specify either the security group + // ID or the security group name in the request. For security groups in a nondefault + // VPC, you must specify the security group ID. + GroupId *string `type:"string"` + + // [EC2-Classic, default VPC] The name of the security group. You must specify + // either the security group ID or the security group name in the request. + GroupName *string `type:"string"` + + // The IP permissions for the security group rule. + // + // IpPermissions is a required field + IpPermissions []*IpPermission `locationNameList:"item" type:"list" required:"true"` +} + +// String returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsIngressInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsIngressInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *UpdateSecurityGroupRuleDescriptionsIngressInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "UpdateSecurityGroupRuleDescriptionsIngressInput"} + if s.IpPermissions == nil { + invalidParams.Add(request.NewErrParamRequired("IpPermissions")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetDryRun sets the DryRun field's value. +func (s *UpdateSecurityGroupRuleDescriptionsIngressInput) SetDryRun(v bool) *UpdateSecurityGroupRuleDescriptionsIngressInput { + s.DryRun = &v + return s +} + +// SetGroupId sets the GroupId field's value. +func (s *UpdateSecurityGroupRuleDescriptionsIngressInput) SetGroupId(v string) *UpdateSecurityGroupRuleDescriptionsIngressInput { + s.GroupId = &v + return s +} + +// SetGroupName sets the GroupName field's value. +func (s *UpdateSecurityGroupRuleDescriptionsIngressInput) SetGroupName(v string) *UpdateSecurityGroupRuleDescriptionsIngressInput { + s.GroupName = &v + return s +} + +// SetIpPermissions sets the IpPermissions field's value. +func (s *UpdateSecurityGroupRuleDescriptionsIngressInput) SetIpPermissions(v []*IpPermission) *UpdateSecurityGroupRuleDescriptionsIngressInput { + s.IpPermissions = v + return s +} + +// Contains the output of UpdateSecurityGroupRuleDescriptionsIngress. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UpdateSecurityGroupRuleDescriptionsIngressResult +type UpdateSecurityGroupRuleDescriptionsIngressOutput struct { + _ struct{} `type:"structure"` + + // Returns true if the request succeeds; otherwise, returns an error. + Return *bool `locationName:"return" type:"boolean"` +} + +// String returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsIngressOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s UpdateSecurityGroupRuleDescriptionsIngressOutput) GoString() string { + return s.String() +} + +// SetReturn sets the Return field's value. +func (s *UpdateSecurityGroupRuleDescriptionsIngressOutput) SetReturn(v bool) *UpdateSecurityGroupRuleDescriptionsIngressOutput { + s.Return = &v + return s +} + // Describes the S3 bucket for the disk image. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserBucket type UserBucket struct { _ struct{} `type:"structure"` @@ -56775,7 +66103,7 @@ func (s *UserBucket) SetS3Key(v string) *UserBucket { } // Describes the S3 bucket for the disk image. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserBucketDetails +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserBucketDetails type UserBucketDetails struct { _ struct{} `type:"structure"` @@ -56809,7 +66137,7 @@ func (s *UserBucketDetails) SetS3Key(v string) *UserBucketDetails { } // Describes the user data for an instance. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserData +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserData type UserData struct { _ struct{} `type:"structure"` @@ -56836,23 +66164,36 @@ func (s *UserData) SetData(v string) *UserData { } // Describes a security group and AWS account ID pair. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserIdGroupPair +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/UserIdGroupPair type UserIdGroupPair struct { _ struct{} `type:"structure"` + // A description for the security group rule that references this user ID group + // pair. + // + // Constraints: Up to 255 characters in length. Allowed characters are a-z, + // A-Z, 0-9, spaces, and ._-:/()#,@[]+=;{}!$* + Description *string `locationName:"description" type:"string"` + // The ID of the security group. GroupId *string `locationName:"groupId" type:"string"` // The name of the security group. In a request, use this parameter for a security // group in EC2-Classic or a default VPC only. For a security group in a nondefault // VPC, use the security group ID. + // + // For a referenced security group in another VPC, this value is not returned + // if the referenced security group is deleted. GroupName *string `locationName:"groupName" type:"string"` // The status of a VPC peering connection, if applicable. PeeringStatus *string `locationName:"peeringStatus" type:"string"` - // The ID of an AWS account. For a referenced security group in another VPC, - // the account ID of the referenced security group is returned. + // The ID of an AWS account. + // + // For a referenced security group in another VPC, the account ID of the referenced + // security group is returned in the response. If the referenced security group + // is deleted, this value is not returned. // // [EC2-Classic] Required when adding or removing rules that reference a security // group in another AWS account. @@ -56875,6 +66216,12 @@ func (s UserIdGroupPair) GoString() string { return s.String() } +// SetDescription sets the Description field's value. +func (s *UserIdGroupPair) SetDescription(v string) *UserIdGroupPair { + s.Description = &v + return s +} + // SetGroupId sets the GroupId field's value. func (s *UserIdGroupPair) SetGroupId(v string) *UserIdGroupPair { s.GroupId = &v @@ -56912,7 +66259,7 @@ func (s *UserIdGroupPair) SetVpcPeeringConnectionId(v string) *UserIdGroupPair { } // Describes telemetry for a VPN tunnel. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VgwTelemetry +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VgwTelemetry type VgwTelemetry struct { _ struct{} `type:"structure"` @@ -56974,7 +66321,7 @@ func (s *VgwTelemetry) SetStatusMessage(v string) *VgwTelemetry { } // Describes a volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Volume +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Volume type Volume struct { _ struct{} `type:"structure"` @@ -57113,7 +66460,7 @@ func (s *Volume) SetVolumeType(v string) *Volume { } // Describes volume attachment details. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeAttachment +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeAttachment type VolumeAttachment struct { _ struct{} `type:"structure"` @@ -57183,7 +66530,7 @@ func (s *VolumeAttachment) SetVolumeId(v string) *VolumeAttachment { } // Describes an EBS volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeDetail +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeDetail type VolumeDetail struct { _ struct{} `type:"structure"` @@ -57225,7 +66572,7 @@ func (s *VolumeDetail) SetSize(v int64) *VolumeDetail { // Describes the modification status of an EBS volume. // // If the volume has never been modified, some element values will be null. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeModification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeModification type VolumeModification struct { _ struct{} `type:"structure"` @@ -57350,7 +66697,7 @@ func (s *VolumeModification) SetVolumeId(v string) *VolumeModification { } // Describes a volume status operation code. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusAction +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusAction type VolumeStatusAction struct { _ struct{} `type:"structure"` @@ -57402,7 +66749,7 @@ func (s *VolumeStatusAction) SetEventType(v string) *VolumeStatusAction { } // Describes a volume status. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusDetails +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusDetails type VolumeStatusDetails struct { _ struct{} `type:"structure"` @@ -57436,7 +66783,7 @@ func (s *VolumeStatusDetails) SetStatus(v string) *VolumeStatusDetails { } // Describes a volume status event. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusEvent +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusEvent type VolumeStatusEvent struct { _ struct{} `type:"structure"` @@ -57497,7 +66844,7 @@ func (s *VolumeStatusEvent) SetNotBefore(v time.Time) *VolumeStatusEvent { } // Describes the status of a volume. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusInfo +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusInfo type VolumeStatusInfo struct { _ struct{} `type:"structure"` @@ -57531,7 +66878,7 @@ func (s *VolumeStatusInfo) SetStatus(v string) *VolumeStatusInfo { } // Describes the volume status. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusItem +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VolumeStatusItem type VolumeStatusItem struct { _ struct{} `type:"structure"` @@ -57592,13 +66939,16 @@ func (s *VolumeStatusItem) SetVolumeStatus(v *VolumeStatusInfo) *VolumeStatusIte } // Describes a VPC. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Vpc +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/Vpc type Vpc struct { _ struct{} `type:"structure"` - // The IPv4 CIDR block for the VPC. + // The primary IPv4 CIDR block for the VPC. CidrBlock *string `locationName:"cidrBlock" type:"string"` + // Information about the IPv4 CIDR blocks associated with the VPC. + CidrBlockAssociationSet []*VpcCidrBlockAssociation `locationName:"cidrBlockAssociationSet" locationNameList:"item" type:"list"` + // The ID of the set of DHCP options you've associated with the VPC (or default // if the default options are associated with the VPC). DhcpOptionsId *string `locationName:"dhcpOptionsId" type:"string"` @@ -57638,6 +66988,12 @@ func (s *Vpc) SetCidrBlock(v string) *Vpc { return s } +// SetCidrBlockAssociationSet sets the CidrBlockAssociationSet field's value. +func (s *Vpc) SetCidrBlockAssociationSet(v []*VpcCidrBlockAssociation) *Vpc { + s.CidrBlockAssociationSet = v + return s +} + // SetDhcpOptionsId sets the DhcpOptionsId field's value. func (s *Vpc) SetDhcpOptionsId(v string) *Vpc { s.DhcpOptionsId = &v @@ -57681,7 +67037,7 @@ func (s *Vpc) SetVpcId(v string) *Vpc { } // Describes an attachment between a virtual private gateway and a VPC. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcAttachment +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcAttachment type VpcAttachment struct { _ struct{} `type:"structure"` @@ -57714,8 +67070,51 @@ func (s *VpcAttachment) SetVpcId(v string) *VpcAttachment { return s } +// Describes an IPv4 CIDR block associated with a VPC. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcCidrBlockAssociation +type VpcCidrBlockAssociation struct { + _ struct{} `type:"structure"` + + // The association ID for the IPv4 CIDR block. + AssociationId *string `locationName:"associationId" type:"string"` + + // The IPv4 CIDR block. + CidrBlock *string `locationName:"cidrBlock" type:"string"` + + // Information about the state of the CIDR block. + CidrBlockState *VpcCidrBlockState `locationName:"cidrBlockState" type:"structure"` +} + +// String returns the string representation +func (s VpcCidrBlockAssociation) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s VpcCidrBlockAssociation) GoString() string { + return s.String() +} + +// SetAssociationId sets the AssociationId field's value. +func (s *VpcCidrBlockAssociation) SetAssociationId(v string) *VpcCidrBlockAssociation { + s.AssociationId = &v + return s +} + +// SetCidrBlock sets the CidrBlock field's value. +func (s *VpcCidrBlockAssociation) SetCidrBlock(v string) *VpcCidrBlockAssociation { + s.CidrBlock = &v + return s +} + +// SetCidrBlockState sets the CidrBlockState field's value. +func (s *VpcCidrBlockAssociation) SetCidrBlockState(v *VpcCidrBlockState) *VpcCidrBlockAssociation { + s.CidrBlockState = v + return s +} + // Describes the state of a CIDR block. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcCidrBlockState +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcCidrBlockState type VpcCidrBlockState struct { _ struct{} `type:"structure"` @@ -57749,7 +67148,7 @@ func (s *VpcCidrBlockState) SetStatusMessage(v string) *VpcCidrBlockState { } // Describes whether a VPC is enabled for ClassicLink. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcClassicLink +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcClassicLink type VpcClassicLink struct { _ struct{} `type:"structure"` @@ -57792,28 +67191,48 @@ func (s *VpcClassicLink) SetVpcId(v string) *VpcClassicLink { } // Describes a VPC endpoint. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcEndpoint +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcEndpoint type VpcEndpoint struct { _ struct{} `type:"structure"` // The date and time the VPC endpoint was created. CreationTimestamp *time.Time `locationName:"creationTimestamp" type:"timestamp" timestampFormat:"iso8601"` - // The policy document associated with the endpoint. + // (Interface endpoint) The DNS entries for the endpoint. + DnsEntries []*DnsEntry `locationName:"dnsEntrySet" locationNameList:"item" type:"list"` + + // (Interface endpoint) Information about the security groups associated with + // the network interface. + Groups []*SecurityGroupIdentifier `locationName:"groupSet" locationNameList:"item" type:"list"` + + // (Interface endpoint) One or more network interfaces for the endpoint. + NetworkInterfaceIds []*string `locationName:"networkInterfaceIdSet" locationNameList:"item" type:"list"` + + // The policy document associated with the endpoint, if applicable. PolicyDocument *string `locationName:"policyDocument" type:"string"` - // One or more route tables associated with the endpoint. + // (Interface endpoint) Indicates whether the VPC is associated with a private + // hosted zone. + PrivateDnsEnabled *bool `locationName:"privateDnsEnabled" type:"boolean"` + + // (Gateway endpoint) One or more route tables associated with the endpoint. RouteTableIds []*string `locationName:"routeTableIdSet" locationNameList:"item" type:"list"` - // The name of the AWS service to which the endpoint is associated. + // The name of the service to which the endpoint is associated. ServiceName *string `locationName:"serviceName" type:"string"` // The state of the VPC endpoint. State *string `locationName:"state" type:"string" enum:"State"` + // (Interface endpoint) One or more subnets in which the endpoint is located. + SubnetIds []*string `locationName:"subnetIdSet" locationNameList:"item" type:"list"` + // The ID of the VPC endpoint. VpcEndpointId *string `locationName:"vpcEndpointId" type:"string"` + // The type of endpoint. + VpcEndpointType *string `locationName:"vpcEndpointType" type:"string" enum:"VpcEndpointType"` + // The ID of the VPC to which the endpoint is associated. VpcId *string `locationName:"vpcId" type:"string"` } @@ -57834,12 +67253,36 @@ func (s *VpcEndpoint) SetCreationTimestamp(v time.Time) *VpcEndpoint { return s } +// SetDnsEntries sets the DnsEntries field's value. +func (s *VpcEndpoint) SetDnsEntries(v []*DnsEntry) *VpcEndpoint { + s.DnsEntries = v + return s +} + +// SetGroups sets the Groups field's value. +func (s *VpcEndpoint) SetGroups(v []*SecurityGroupIdentifier) *VpcEndpoint { + s.Groups = v + return s +} + +// SetNetworkInterfaceIds sets the NetworkInterfaceIds field's value. +func (s *VpcEndpoint) SetNetworkInterfaceIds(v []*string) *VpcEndpoint { + s.NetworkInterfaceIds = v + return s +} + // SetPolicyDocument sets the PolicyDocument field's value. func (s *VpcEndpoint) SetPolicyDocument(v string) *VpcEndpoint { s.PolicyDocument = &v return s } +// SetPrivateDnsEnabled sets the PrivateDnsEnabled field's value. +func (s *VpcEndpoint) SetPrivateDnsEnabled(v bool) *VpcEndpoint { + s.PrivateDnsEnabled = &v + return s +} + // SetRouteTableIds sets the RouteTableIds field's value. func (s *VpcEndpoint) SetRouteTableIds(v []*string) *VpcEndpoint { s.RouteTableIds = v @@ -57858,20 +67301,93 @@ func (s *VpcEndpoint) SetState(v string) *VpcEndpoint { return s } +// SetSubnetIds sets the SubnetIds field's value. +func (s *VpcEndpoint) SetSubnetIds(v []*string) *VpcEndpoint { + s.SubnetIds = v + return s +} + // SetVpcEndpointId sets the VpcEndpointId field's value. func (s *VpcEndpoint) SetVpcEndpointId(v string) *VpcEndpoint { s.VpcEndpointId = &v return s } +// SetVpcEndpointType sets the VpcEndpointType field's value. +func (s *VpcEndpoint) SetVpcEndpointType(v string) *VpcEndpoint { + s.VpcEndpointType = &v + return s +} + // SetVpcId sets the VpcId field's value. func (s *VpcEndpoint) SetVpcId(v string) *VpcEndpoint { s.VpcId = &v return s } +// Describes a VPC endpoint connection to a service. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcEndpointConnection +type VpcEndpointConnection struct { + _ struct{} `type:"structure"` + + // The date and time the VPC endpoint was created. + CreationTimestamp *time.Time `locationName:"creationTimestamp" type:"timestamp" timestampFormat:"iso8601"` + + // The ID of the service to which the endpoint is connected. + ServiceId *string `locationName:"serviceId" type:"string"` + + // The ID of the VPC endpoint. + VpcEndpointId *string `locationName:"vpcEndpointId" type:"string"` + + // The AWS account ID of the owner of the VPC endpoint. + VpcEndpointOwner *string `locationName:"vpcEndpointOwner" type:"string"` + + // The state of the VPC endpoint. + VpcEndpointState *string `locationName:"vpcEndpointState" type:"string" enum:"State"` +} + +// String returns the string representation +func (s VpcEndpointConnection) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s VpcEndpointConnection) GoString() string { + return s.String() +} + +// SetCreationTimestamp sets the CreationTimestamp field's value. +func (s *VpcEndpointConnection) SetCreationTimestamp(v time.Time) *VpcEndpointConnection { + s.CreationTimestamp = &v + return s +} + +// SetServiceId sets the ServiceId field's value. +func (s *VpcEndpointConnection) SetServiceId(v string) *VpcEndpointConnection { + s.ServiceId = &v + return s +} + +// SetVpcEndpointId sets the VpcEndpointId field's value. +func (s *VpcEndpointConnection) SetVpcEndpointId(v string) *VpcEndpointConnection { + s.VpcEndpointId = &v + return s +} + +// SetVpcEndpointOwner sets the VpcEndpointOwner field's value. +func (s *VpcEndpointConnection) SetVpcEndpointOwner(v string) *VpcEndpointConnection { + s.VpcEndpointOwner = &v + return s +} + +// SetVpcEndpointState sets the VpcEndpointState field's value. +func (s *VpcEndpointConnection) SetVpcEndpointState(v string) *VpcEndpointConnection { + s.VpcEndpointState = &v + return s +} + // Describes an IPv6 CIDR block associated with a VPC. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcIpv6CidrBlockAssociation +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcIpv6CidrBlockAssociation type VpcIpv6CidrBlockAssociation struct { _ struct{} `type:"structure"` @@ -57914,7 +67430,7 @@ func (s *VpcIpv6CidrBlockAssociation) SetIpv6CidrBlockState(v *VpcCidrBlockState } // Describes a VPC peering connection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnection type VpcPeeringConnection struct { _ struct{} `type:"structure"` @@ -57986,7 +67502,7 @@ func (s *VpcPeeringConnection) SetVpcPeeringConnectionId(v string) *VpcPeeringCo } // Describes the VPC peering connection options. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnectionOptionsDescription +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnectionOptionsDescription type VpcPeeringConnectionOptionsDescription struct { _ struct{} `type:"structure"` @@ -58032,7 +67548,7 @@ func (s *VpcPeeringConnectionOptionsDescription) SetAllowEgressFromLocalVpcToRem } // Describes the status of a VPC peering connection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnectionStateReason +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnectionStateReason type VpcPeeringConnectionStateReason struct { _ struct{} `type:"structure"` @@ -58066,13 +67582,16 @@ func (s *VpcPeeringConnectionStateReason) SetMessage(v string) *VpcPeeringConnec } // Describes a VPC in a VPC peering connection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnectionVpcInfo +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpcPeeringConnectionVpcInfo type VpcPeeringConnectionVpcInfo struct { _ struct{} `type:"structure"` // The IPv4 CIDR block for the VPC. CidrBlock *string `locationName:"cidrBlock" type:"string"` + // Information about the IPv4 CIDR blocks for the VPC. + CidrBlockSet []*CidrBlock `locationName:"cidrBlockSet" locationNameList:"item" type:"list"` + // The IPv6 CIDR block for the VPC. Ipv6CidrBlockSet []*Ipv6CidrBlock `locationName:"ipv6CidrBlockSet" locationNameList:"item" type:"list"` @@ -58083,6 +67602,9 @@ type VpcPeeringConnectionVpcInfo struct { // requester VPC. PeeringOptions *VpcPeeringConnectionOptionsDescription `locationName:"peeringOptions" type:"structure"` + // The region in which the VPC is located. + Region *string `locationName:"region" type:"string"` + // The ID of the VPC. VpcId *string `locationName:"vpcId" type:"string"` } @@ -58103,6 +67625,12 @@ func (s *VpcPeeringConnectionVpcInfo) SetCidrBlock(v string) *VpcPeeringConnecti return s } +// SetCidrBlockSet sets the CidrBlockSet field's value. +func (s *VpcPeeringConnectionVpcInfo) SetCidrBlockSet(v []*CidrBlock) *VpcPeeringConnectionVpcInfo { + s.CidrBlockSet = v + return s +} + // SetIpv6CidrBlockSet sets the Ipv6CidrBlockSet field's value. func (s *VpcPeeringConnectionVpcInfo) SetIpv6CidrBlockSet(v []*Ipv6CidrBlock) *VpcPeeringConnectionVpcInfo { s.Ipv6CidrBlockSet = v @@ -58121,6 +67649,12 @@ func (s *VpcPeeringConnectionVpcInfo) SetPeeringOptions(v *VpcPeeringConnectionO return s } +// SetRegion sets the Region field's value. +func (s *VpcPeeringConnectionVpcInfo) SetRegion(v string) *VpcPeeringConnectionVpcInfo { + s.Region = &v + return s +} + // SetVpcId sets the VpcId field's value. func (s *VpcPeeringConnectionVpcInfo) SetVpcId(v string) *VpcPeeringConnectionVpcInfo { s.VpcId = &v @@ -58128,10 +67662,16 @@ func (s *VpcPeeringConnectionVpcInfo) SetVpcId(v string) *VpcPeeringConnectionVp } // Describes a VPN connection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnConnection +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnConnection type VpnConnection struct { _ struct{} `type:"structure"` + // The category of the VPN connection. A value of VPN indicates an AWS VPN connection. + // A value of VPN-Classic indicates an AWS Classic VPN connection. For more + // information, see AWS Managed VPN Categories (http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html#vpn-categories) + // in the Amazon Virtual Private Cloud User Guide. + Category *string `locationName:"category" type:"string"` + // The configuration information for the VPN connection's customer gateway (in // the native XML format). This element is always present in the CreateVpnConnection // response; however, it's present in the DescribeVpnConnections response only @@ -58176,6 +67716,12 @@ func (s VpnConnection) GoString() string { return s.String() } +// SetCategory sets the Category field's value. +func (s *VpnConnection) SetCategory(v string) *VpnConnection { + s.Category = &v + return s +} + // SetCustomerGatewayConfiguration sets the CustomerGatewayConfiguration field's value. func (s *VpnConnection) SetCustomerGatewayConfiguration(v string) *VpnConnection { s.CustomerGatewayConfiguration = &v @@ -58237,7 +67783,7 @@ func (s *VpnConnection) SetVpnGatewayId(v string) *VpnConnection { } // Describes VPN connection options. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnConnectionOptions +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnConnectionOptions type VpnConnectionOptions struct { _ struct{} `type:"structure"` @@ -58263,13 +67809,19 @@ func (s *VpnConnectionOptions) SetStaticRoutesOnly(v bool) *VpnConnectionOptions } // Describes VPN connection options. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnConnectionOptionsSpecification +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnConnectionOptionsSpecification type VpnConnectionOptionsSpecification struct { _ struct{} `type:"structure"` - // Indicates whether the VPN connection uses static routes only. Static routes - // must be used for devices that don't support BGP. + // Indicate whether the VPN connection uses static routes only. If you are creating + // a VPN connection for a device that does not support BGP, you must specify + // true. + // + // Default: false StaticRoutesOnly *bool `locationName:"staticRoutesOnly" type:"boolean"` + + // The tunnel options for the VPN connection. + TunnelOptions []*VpnTunnelOptionsSpecification `locationNameList:"item" type:"list"` } // String returns the string representation @@ -58288,11 +67840,20 @@ func (s *VpnConnectionOptionsSpecification) SetStaticRoutesOnly(v bool) *VpnConn return s } +// SetTunnelOptions sets the TunnelOptions field's value. +func (s *VpnConnectionOptionsSpecification) SetTunnelOptions(v []*VpnTunnelOptionsSpecification) *VpnConnectionOptionsSpecification { + s.TunnelOptions = v + return s +} + // Describes a virtual private gateway. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnGateway +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnGateway type VpnGateway struct { _ struct{} `type:"structure"` + // The private Autonomous System Number (ASN) for the Amazon side of a BGP session. + AmazonSideAsn *int64 `locationName:"amazonSideAsn" type:"long"` + // The Availability Zone where the virtual private gateway was created, if applicable. // This field may be empty or not returned. AvailabilityZone *string `locationName:"availabilityZone" type:"string"` @@ -58323,6 +67884,12 @@ func (s VpnGateway) GoString() string { return s.String() } +// SetAmazonSideAsn sets the AmazonSideAsn field's value. +func (s *VpnGateway) SetAmazonSideAsn(v int64) *VpnGateway { + s.AmazonSideAsn = &v + return s +} + // SetAvailabilityZone sets the AvailabilityZone field's value. func (s *VpnGateway) SetAvailabilityZone(v string) *VpnGateway { s.AvailabilityZone = &v @@ -58360,7 +67927,7 @@ func (s *VpnGateway) SetVpnGatewayId(v string) *VpnGateway { } // Describes a static route for a VPN connection. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnStaticRoute +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnStaticRoute type VpnStaticRoute struct { _ struct{} `type:"structure"` @@ -58402,6 +67969,63 @@ func (s *VpnStaticRoute) SetState(v string) *VpnStaticRoute { return s } +// The tunnel options for a VPN connection. +// See also, https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/VpnTunnelOptionsSpecification +type VpnTunnelOptionsSpecification struct { + _ struct{} `type:"structure"` + + // The pre-shared key (PSK) to establish initial authentication between the + // virtual private gateway and customer gateway. + // + // Constraints: Allowed characters are alphanumeric characters and ._. Must + // be between 8 and 64 characters in length and cannot start with zero (0). + PreSharedKey *string `type:"string"` + + // The range of inside IP addresses for the tunnel. Any specified CIDR blocks + // must be unique across all VPN connections that use the same virtual private + // gateway. + // + // Constraints: A size /30 CIDR block from the 169.254.0.0/16 range. The following + // CIDR blocks are reserved and cannot be used: + // + // * 169.254.0.0/30 + // + // * 169.254.1.0/30 + // + // * 169.254.2.0/30 + // + // * 169.254.3.0/30 + // + // * 169.254.4.0/30 + // + // * 169.254.5.0/30 + // + // * 169.254.169.252/30 + TunnelInsideCidr *string `type:"string"` +} + +// String returns the string representation +func (s VpnTunnelOptionsSpecification) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s VpnTunnelOptionsSpecification) GoString() string { + return s.String() +} + +// SetPreSharedKey sets the PreSharedKey field's value. +func (s *VpnTunnelOptionsSpecification) SetPreSharedKey(v string) *VpnTunnelOptionsSpecification { + s.PreSharedKey = &v + return s +} + +// SetTunnelInsideCidr sets the TunnelInsideCidr field's value. +func (s *VpnTunnelOptionsSpecification) SetTunnelInsideCidr(v string) *VpnTunnelOptionsSpecification { + s.TunnelInsideCidr = &v + return s +} + const ( // AccountAttributeNameSupportedPlatforms is a AccountAttributeName enum value AccountAttributeNameSupportedPlatforms = "supported-platforms" @@ -58578,6 +68202,19 @@ const ( CancelSpotInstanceRequestStateCompleted = "completed" ) +const ( + // ConnectionNotificationStateEnabled is a ConnectionNotificationState enum value + ConnectionNotificationStateEnabled = "Enabled" + + // ConnectionNotificationStateDisabled is a ConnectionNotificationState enum value + ConnectionNotificationStateDisabled = "Disabled" +) + +const ( + // ConnectionNotificationTypeTopic is a ConnectionNotificationType enum value + ConnectionNotificationTypeTopic = "Topic" +) + const ( // ContainerFormatOva is a ContainerFormat enum value ContainerFormatOva = "ova" @@ -58730,6 +68367,20 @@ const ( FlowLogsResourceTypeNetworkInterface = "NetworkInterface" ) +const ( + // FpgaImageAttributeNameDescription is a FpgaImageAttributeName enum value + FpgaImageAttributeNameDescription = "description" + + // FpgaImageAttributeNameName is a FpgaImageAttributeName enum value + FpgaImageAttributeNameName = "name" + + // FpgaImageAttributeNameLoadPermission is a FpgaImageAttributeName enum value + FpgaImageAttributeNameLoadPermission = "loadPermission" + + // FpgaImageAttributeNameProductCodes is a FpgaImageAttributeName enum value + FpgaImageAttributeNameProductCodes = "productCodes" +) + const ( // FpgaImageStateCodePending is a FpgaImageStateCode enum value FpgaImageStateCodePending = "pending" @@ -58888,6 +68539,17 @@ const ( InstanceHealthStatusUnhealthy = "unhealthy" ) +const ( + // InstanceInterruptionBehaviorHibernate is a InstanceInterruptionBehavior enum value + InstanceInterruptionBehaviorHibernate = "hibernate" + + // InstanceInterruptionBehaviorStop is a InstanceInterruptionBehavior enum value + InstanceInterruptionBehaviorStop = "stop" + + // InstanceInterruptionBehaviorTerminate is a InstanceInterruptionBehavior enum value + InstanceInterruptionBehaviorTerminate = "terminate" +) + const ( // InstanceLifecycleTypeSpot is a InstanceLifecycleType enum value InstanceLifecycleTypeSpot = "spot" @@ -59034,6 +68696,24 @@ const ( // InstanceTypeX132xlarge is a InstanceType enum value InstanceTypeX132xlarge = "x1.32xlarge" + // InstanceTypeX1eXlarge is a InstanceType enum value + InstanceTypeX1eXlarge = "x1e.xlarge" + + // InstanceTypeX1e2xlarge is a InstanceType enum value + InstanceTypeX1e2xlarge = "x1e.2xlarge" + + // InstanceTypeX1e4xlarge is a InstanceType enum value + InstanceTypeX1e4xlarge = "x1e.4xlarge" + + // InstanceTypeX1e8xlarge is a InstanceType enum value + InstanceTypeX1e8xlarge = "x1e.8xlarge" + + // InstanceTypeX1e16xlarge is a InstanceType enum value + InstanceTypeX1e16xlarge = "x1e.16xlarge" + + // InstanceTypeX1e32xlarge is a InstanceType enum value + InstanceTypeX1e32xlarge = "x1e.32xlarge" + // InstanceTypeI2Xlarge is a InstanceType enum value InstanceTypeI2Xlarge = "i2.xlarge" @@ -59106,6 +68786,24 @@ const ( // InstanceTypeC48xlarge is a InstanceType enum value InstanceTypeC48xlarge = "c4.8xlarge" + // InstanceTypeC5Large is a InstanceType enum value + InstanceTypeC5Large = "c5.large" + + // InstanceTypeC5Xlarge is a InstanceType enum value + InstanceTypeC5Xlarge = "c5.xlarge" + + // InstanceTypeC52xlarge is a InstanceType enum value + InstanceTypeC52xlarge = "c5.2xlarge" + + // InstanceTypeC54xlarge is a InstanceType enum value + InstanceTypeC54xlarge = "c5.4xlarge" + + // InstanceTypeC59xlarge is a InstanceType enum value + InstanceTypeC59xlarge = "c5.9xlarge" + + // InstanceTypeC518xlarge is a InstanceType enum value + InstanceTypeC518xlarge = "c5.18xlarge" + // InstanceTypeCc14xlarge is a InstanceType enum value InstanceTypeCc14xlarge = "cc1.4xlarge" @@ -59139,6 +68837,15 @@ const ( // InstanceTypeP216xlarge is a InstanceType enum value InstanceTypeP216xlarge = "p2.16xlarge" + // InstanceTypeP32xlarge is a InstanceType enum value + InstanceTypeP32xlarge = "p3.2xlarge" + + // InstanceTypeP38xlarge is a InstanceType enum value + InstanceTypeP38xlarge = "p3.8xlarge" + + // InstanceTypeP316xlarge is a InstanceType enum value + InstanceTypeP316xlarge = "p3.16xlarge" + // InstanceTypeD2Xlarge is a InstanceType enum value InstanceTypeD2Xlarge = "d2.xlarge" @@ -59156,6 +68863,36 @@ const ( // InstanceTypeF116xlarge is a InstanceType enum value InstanceTypeF116xlarge = "f1.16xlarge" + + // InstanceTypeM5Large is a InstanceType enum value + InstanceTypeM5Large = "m5.large" + + // InstanceTypeM5Xlarge is a InstanceType enum value + InstanceTypeM5Xlarge = "m5.xlarge" + + // InstanceTypeM52xlarge is a InstanceType enum value + InstanceTypeM52xlarge = "m5.2xlarge" + + // InstanceTypeM54xlarge is a InstanceType enum value + InstanceTypeM54xlarge = "m5.4xlarge" + + // InstanceTypeM512xlarge is a InstanceType enum value + InstanceTypeM512xlarge = "m5.12xlarge" + + // InstanceTypeM524xlarge is a InstanceType enum value + InstanceTypeM524xlarge = "m5.24xlarge" + + // InstanceTypeH12xlarge is a InstanceType enum value + InstanceTypeH12xlarge = "h1.2xlarge" + + // InstanceTypeH14xlarge is a InstanceType enum value + InstanceTypeH14xlarge = "h1.4xlarge" + + // InstanceTypeH18xlarge is a InstanceType enum value + InstanceTypeH18xlarge = "h1.8xlarge" + + // InstanceTypeH116xlarge is a InstanceType enum value + InstanceTypeH116xlarge = "h1.16xlarge" ) const ( @@ -59166,6 +68903,26 @@ const ( InterfacePermissionTypeEipAssociate = "EIP-ASSOCIATE" ) +const ( + // LaunchTemplateErrorCodeLaunchTemplateIdDoesNotExist is a LaunchTemplateErrorCode enum value + LaunchTemplateErrorCodeLaunchTemplateIdDoesNotExist = "launchTemplateIdDoesNotExist" + + // LaunchTemplateErrorCodeLaunchTemplateIdMalformed is a LaunchTemplateErrorCode enum value + LaunchTemplateErrorCodeLaunchTemplateIdMalformed = "launchTemplateIdMalformed" + + // LaunchTemplateErrorCodeLaunchTemplateNameDoesNotExist is a LaunchTemplateErrorCode enum value + LaunchTemplateErrorCodeLaunchTemplateNameDoesNotExist = "launchTemplateNameDoesNotExist" + + // LaunchTemplateErrorCodeLaunchTemplateNameMalformed is a LaunchTemplateErrorCode enum value + LaunchTemplateErrorCodeLaunchTemplateNameMalformed = "launchTemplateNameMalformed" + + // LaunchTemplateErrorCodeLaunchTemplateVersionDoesNotExist is a LaunchTemplateErrorCode enum value + LaunchTemplateErrorCodeLaunchTemplateVersionDoesNotExist = "launchTemplateVersionDoesNotExist" + + // LaunchTemplateErrorCodeUnexpectedError is a LaunchTemplateErrorCode enum value + LaunchTemplateErrorCodeUnexpectedError = "unexpectedError" +) + const ( // ListingStateAvailable is a ListingState enum value ListingStateAvailable = "available" @@ -59194,6 +68951,11 @@ const ( ListingStatusClosed = "closed" ) +const ( + // MarketTypeSpot is a MarketType enum value + MarketTypeSpot = "spot" +) + const ( // MonitoringStateDisabled is a MonitoringState enum value MonitoringStateDisabled = "disabled" @@ -59352,6 +69114,9 @@ const ( const ( // PlacementStrategyCluster is a PlacementStrategy enum value PlacementStrategyCluster = "cluster" + + // PlacementStrategySpread is a PlacementStrategy enum value + PlacementStrategySpread = "spread" ) const ( @@ -59359,6 +69124,26 @@ const ( PlatformValuesWindows = "Windows" ) +const ( + // PrincipalTypeAll is a PrincipalType enum value + PrincipalTypeAll = "All" + + // PrincipalTypeService is a PrincipalType enum value + PrincipalTypeService = "Service" + + // PrincipalTypeOrganizationUnit is a PrincipalType enum value + PrincipalTypeOrganizationUnit = "OrganizationUnit" + + // PrincipalTypeAccount is a PrincipalType enum value + PrincipalTypeAccount = "Account" + + // PrincipalTypeUser is a PrincipalType enum value + PrincipalTypeUser = "User" + + // PrincipalTypeRole is a PrincipalType enum value + PrincipalTypeRole = "Role" +) + const ( // ProductCodeValuesDevpay is a ProductCodeValues enum value ProductCodeValuesDevpay = "devpay" @@ -59451,6 +69236,11 @@ const ( ReservedInstanceStateRetired = "retired" ) +const ( + // ResetFpgaImageAttributeNameLoadPermission is a ResetFpgaImageAttributeName enum value + ResetFpgaImageAttributeNameLoadPermission = "loadPermission" +) + const ( // ResetImageAttributeNameLaunchPermission is a ResetImageAttributeName enum value ResetImageAttributeNameLaunchPermission = "launchPermission" @@ -59536,6 +69326,31 @@ const ( RuleActionDeny = "deny" ) +const ( + // ServiceStatePending is a ServiceState enum value + ServiceStatePending = "Pending" + + // ServiceStateAvailable is a ServiceState enum value + ServiceStateAvailable = "Available" + + // ServiceStateDeleting is a ServiceState enum value + ServiceStateDeleting = "Deleting" + + // ServiceStateDeleted is a ServiceState enum value + ServiceStateDeleted = "Deleted" + + // ServiceStateFailed is a ServiceState enum value + ServiceStateFailed = "Failed" +) + +const ( + // ServiceTypeInterface is a ServiceType enum value + ServiceTypeInterface = "Interface" + + // ServiceTypeGateway is a ServiceType enum value + ServiceTypeGateway = "Gateway" +) + const ( // ShutdownBehaviorStop is a ShutdownBehavior enum value ShutdownBehaviorStop = "stop" @@ -59589,6 +69404,9 @@ const ( ) const ( + // StatePendingAcceptance is a State enum value + StatePendingAcceptance = "PendingAcceptance" + // StatePending is a State enum value StatePending = "Pending" @@ -59600,6 +69418,15 @@ const ( // StateDeleted is a State enum value StateDeleted = "Deleted" + + // StateRejected is a State enum value + StateRejected = "Rejected" + + // StateFailed is a State enum value + StateFailed = "Failed" + + // StateExpired is a State enum value + StateExpired = "Expired" ) const ( @@ -59707,6 +69534,20 @@ const ( TrafficTypeAll = "ALL" ) +const ( + // UnsuccessfulInstanceCreditSpecificationErrorCodeInvalidInstanceIdMalformed is a UnsuccessfulInstanceCreditSpecificationErrorCode enum value + UnsuccessfulInstanceCreditSpecificationErrorCodeInvalidInstanceIdMalformed = "InvalidInstanceID.Malformed" + + // UnsuccessfulInstanceCreditSpecificationErrorCodeInvalidInstanceIdNotFound is a UnsuccessfulInstanceCreditSpecificationErrorCode enum value + UnsuccessfulInstanceCreditSpecificationErrorCodeInvalidInstanceIdNotFound = "InvalidInstanceID.NotFound" + + // UnsuccessfulInstanceCreditSpecificationErrorCodeIncorrectInstanceState is a UnsuccessfulInstanceCreditSpecificationErrorCode enum value + UnsuccessfulInstanceCreditSpecificationErrorCodeIncorrectInstanceState = "IncorrectInstanceState" + + // UnsuccessfulInstanceCreditSpecificationErrorCodeInstanceCreditSpecificationNotSupported is a UnsuccessfulInstanceCreditSpecificationErrorCode enum value + UnsuccessfulInstanceCreditSpecificationErrorCodeInstanceCreditSpecificationNotSupported = "InstanceCreditSpecification.NotSupported" +) + const ( // VirtualizationTypeHvm is a VirtualizationType enum value VirtualizationTypeHvm = "hvm" @@ -59727,6 +69568,9 @@ const ( // VolumeAttachmentStateDetached is a VolumeAttachmentState enum value VolumeAttachmentStateDetached = "detached" + + // VolumeAttachmentStateBusy is a VolumeAttachmentState enum value + VolumeAttachmentStateBusy = "busy" ) const ( @@ -59835,6 +69679,14 @@ const ( VpcCidrBlockStateCodeFailed = "failed" ) +const ( + // VpcEndpointTypeInterface is a VpcEndpointType enum value + VpcEndpointTypeInterface = "Interface" + + // VpcEndpointTypeGateway is a VpcEndpointType enum value + VpcEndpointTypeGateway = "Gateway" +) + const ( // VpcPeeringConnectionStateReasonCodeInitiatingRequest is a VpcPeeringConnectionStateReasonCode enum value VpcPeeringConnectionStateReasonCodeInitiatingRequest = "initiating-request" @@ -59872,6 +69724,11 @@ const ( VpcStateAvailable = "available" ) +const ( + // VpcTenancyDefault is a VpcTenancy enum value + VpcTenancyDefault = "default" +) + const ( // VpnStatePending is a VpnState enum value VpnStatePending = "pending" diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/doc.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/doc.go index 4aa6618b466..432a54df4e7 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/ec2/doc.go +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/doc.go @@ -4,9 +4,8 @@ // requests to Amazon Elastic Compute Cloud. // // Amazon Elastic Compute Cloud (Amazon EC2) provides resizable computing capacity -// in the Amazon Web Services (AWS) cloud. Using Amazon EC2 eliminates your -// need to invest in hardware up front, so you can develop and deploy applications -// faster. +// in the AWS Cloud. Using Amazon EC2 eliminates your need to invest in hardware +// up front, so you can develop and deploy applications faster. // // See https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15 for more information on this service. // @@ -15,69 +14,17 @@ // // Using the Client // -// To use the client for Amazon Elastic Compute Cloud you will first need -// to create a new instance of it. +// To contact Amazon Elastic Compute Cloud with the SDK use the New function to create +// a new service client. With that client you can make API requests to the service. +// These clients are safe to use concurrently. // -// When creating a client for an AWS service you'll first need to have a Session -// already created. The Session provides configuration that can be shared -// between multiple service clients. Additional configuration can be applied to -// the Session and service's client when they are constructed. The aws package's -// Config type contains several fields such as Region for the AWS Region the -// client should make API requests too. The optional Config value can be provided -// as the variadic argument for Sessions and client creation. -// -// Once the service's client is created you can use it to make API requests the -// AWS service. These clients are safe to use concurrently. -// -// // Create a session to share configuration, and load external configuration. -// sess := session.Must(session.NewSession()) -// -// // Create the service's client with the session. -// svc := ec2.New(sess) -// -// See the SDK's documentation for more information on how to use service clients. +// See the SDK's documentation for more information on how to use the SDK. // https://docs.aws.amazon.com/sdk-for-go/api/ // -// See aws package's Config type for more information on configuration options. +// See aws.Config documentation for more information on configuring SDK clients. // https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config // // See the Amazon Elastic Compute Cloud client EC2 for more -// information on creating the service's client. +// information on creating client for this service. // https://docs.aws.amazon.com/sdk-for-go/api/service/ec2/#New -// -// Once the client is created you can make an API request to the service. -// Each API method takes a input parameter, and returns the service response -// and an error. -// -// The API method will document which error codes the service can be returned -// by the operation if the service models the API operation's errors. These -// errors will also be available as const strings prefixed with "ErrCode". -// -// result, err := svc.AcceptReservedInstancesExchangeQuote(params) -// if err != nil { -// // Cast err to awserr.Error to handle specific error codes. -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == { -// // Specific error code handling -// } -// return err -// } -// -// fmt.Println("AcceptReservedInstancesExchangeQuote result:") -// fmt.Println(result) -// -// Using the Client with Context -// -// The service's client also provides methods to make API requests with a Context -// value. This allows you to control the timeout, and cancellation of pending -// requests. These methods also take request Option as variadic parameter to apply -// additional configuration to the API request. -// -// ctx := context.Background() -// -// result, err := svc.AcceptReservedInstancesExchangeQuoteWithContext(ctx, params) -// -// See the request package documentation for more information on using Context pattern -// with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/ package ec2 diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go index 77882a6b505..37688ed46b9 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface/interface.go @@ -21,7 +21,7 @@ import ( // // The best way to use this interface is so the SDK's service client's calls // can be stubbed out for unit testing your code with the SDK without needing -// to inject custom request handlers into the the SDK's request pipeline. +// to inject custom request handlers into the SDK's request pipeline. // // // myFunc uses an SDK service client to make a request to // // Amazon Elastic Compute Cloud. @@ -64,6 +64,10 @@ type EC2API interface { AcceptReservedInstancesExchangeQuoteWithContext(aws.Context, *ec2.AcceptReservedInstancesExchangeQuoteInput, ...request.Option) (*ec2.AcceptReservedInstancesExchangeQuoteOutput, error) AcceptReservedInstancesExchangeQuoteRequest(*ec2.AcceptReservedInstancesExchangeQuoteInput) (*request.Request, *ec2.AcceptReservedInstancesExchangeQuoteOutput) + AcceptVpcEndpointConnections(*ec2.AcceptVpcEndpointConnectionsInput) (*ec2.AcceptVpcEndpointConnectionsOutput, error) + AcceptVpcEndpointConnectionsWithContext(aws.Context, *ec2.AcceptVpcEndpointConnectionsInput, ...request.Option) (*ec2.AcceptVpcEndpointConnectionsOutput, error) + AcceptVpcEndpointConnectionsRequest(*ec2.AcceptVpcEndpointConnectionsInput) (*request.Request, *ec2.AcceptVpcEndpointConnectionsOutput) + AcceptVpcPeeringConnection(*ec2.AcceptVpcPeeringConnectionInput) (*ec2.AcceptVpcPeeringConnectionOutput, error) AcceptVpcPeeringConnectionWithContext(aws.Context, *ec2.AcceptVpcPeeringConnectionInput, ...request.Option) (*ec2.AcceptVpcPeeringConnectionOutput, error) AcceptVpcPeeringConnectionRequest(*ec2.AcceptVpcPeeringConnectionInput) (*request.Request, *ec2.AcceptVpcPeeringConnectionOutput) @@ -172,6 +176,10 @@ type EC2API interface { ConfirmProductInstanceWithContext(aws.Context, *ec2.ConfirmProductInstanceInput, ...request.Option) (*ec2.ConfirmProductInstanceOutput, error) ConfirmProductInstanceRequest(*ec2.ConfirmProductInstanceInput) (*request.Request, *ec2.ConfirmProductInstanceOutput) + CopyFpgaImage(*ec2.CopyFpgaImageInput) (*ec2.CopyFpgaImageOutput, error) + CopyFpgaImageWithContext(aws.Context, *ec2.CopyFpgaImageInput, ...request.Option) (*ec2.CopyFpgaImageOutput, error) + CopyFpgaImageRequest(*ec2.CopyFpgaImageInput) (*request.Request, *ec2.CopyFpgaImageOutput) + CopyImage(*ec2.CopyImageInput) (*ec2.CopyImageOutput, error) CopyImageWithContext(aws.Context, *ec2.CopyImageInput, ...request.Option) (*ec2.CopyImageOutput, error) CopyImageRequest(*ec2.CopyImageInput) (*request.Request, *ec2.CopyImageOutput) @@ -184,6 +192,10 @@ type EC2API interface { CreateCustomerGatewayWithContext(aws.Context, *ec2.CreateCustomerGatewayInput, ...request.Option) (*ec2.CreateCustomerGatewayOutput, error) CreateCustomerGatewayRequest(*ec2.CreateCustomerGatewayInput) (*request.Request, *ec2.CreateCustomerGatewayOutput) + CreateDefaultSubnet(*ec2.CreateDefaultSubnetInput) (*ec2.CreateDefaultSubnetOutput, error) + CreateDefaultSubnetWithContext(aws.Context, *ec2.CreateDefaultSubnetInput, ...request.Option) (*ec2.CreateDefaultSubnetOutput, error) + CreateDefaultSubnetRequest(*ec2.CreateDefaultSubnetInput) (*request.Request, *ec2.CreateDefaultSubnetOutput) + CreateDefaultVpc(*ec2.CreateDefaultVpcInput) (*ec2.CreateDefaultVpcOutput, error) CreateDefaultVpcWithContext(aws.Context, *ec2.CreateDefaultVpcInput, ...request.Option) (*ec2.CreateDefaultVpcOutput, error) CreateDefaultVpcRequest(*ec2.CreateDefaultVpcInput) (*request.Request, *ec2.CreateDefaultVpcOutput) @@ -220,6 +232,14 @@ type EC2API interface { CreateKeyPairWithContext(aws.Context, *ec2.CreateKeyPairInput, ...request.Option) (*ec2.CreateKeyPairOutput, error) CreateKeyPairRequest(*ec2.CreateKeyPairInput) (*request.Request, *ec2.CreateKeyPairOutput) + CreateLaunchTemplate(*ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error) + CreateLaunchTemplateWithContext(aws.Context, *ec2.CreateLaunchTemplateInput, ...request.Option) (*ec2.CreateLaunchTemplateOutput, error) + CreateLaunchTemplateRequest(*ec2.CreateLaunchTemplateInput) (*request.Request, *ec2.CreateLaunchTemplateOutput) + + CreateLaunchTemplateVersion(*ec2.CreateLaunchTemplateVersionInput) (*ec2.CreateLaunchTemplateVersionOutput, error) + CreateLaunchTemplateVersionWithContext(aws.Context, *ec2.CreateLaunchTemplateVersionInput, ...request.Option) (*ec2.CreateLaunchTemplateVersionOutput, error) + CreateLaunchTemplateVersionRequest(*ec2.CreateLaunchTemplateVersionInput) (*request.Request, *ec2.CreateLaunchTemplateVersionOutput) + CreateNatGateway(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error) CreateNatGatewayWithContext(aws.Context, *ec2.CreateNatGatewayInput, ...request.Option) (*ec2.CreateNatGatewayOutput, error) CreateNatGatewayRequest(*ec2.CreateNatGatewayInput) (*request.Request, *ec2.CreateNatGatewayOutput) @@ -288,6 +308,14 @@ type EC2API interface { CreateVpcEndpointWithContext(aws.Context, *ec2.CreateVpcEndpointInput, ...request.Option) (*ec2.CreateVpcEndpointOutput, error) CreateVpcEndpointRequest(*ec2.CreateVpcEndpointInput) (*request.Request, *ec2.CreateVpcEndpointOutput) + CreateVpcEndpointConnectionNotification(*ec2.CreateVpcEndpointConnectionNotificationInput) (*ec2.CreateVpcEndpointConnectionNotificationOutput, error) + CreateVpcEndpointConnectionNotificationWithContext(aws.Context, *ec2.CreateVpcEndpointConnectionNotificationInput, ...request.Option) (*ec2.CreateVpcEndpointConnectionNotificationOutput, error) + CreateVpcEndpointConnectionNotificationRequest(*ec2.CreateVpcEndpointConnectionNotificationInput) (*request.Request, *ec2.CreateVpcEndpointConnectionNotificationOutput) + + CreateVpcEndpointServiceConfiguration(*ec2.CreateVpcEndpointServiceConfigurationInput) (*ec2.CreateVpcEndpointServiceConfigurationOutput, error) + CreateVpcEndpointServiceConfigurationWithContext(aws.Context, *ec2.CreateVpcEndpointServiceConfigurationInput, ...request.Option) (*ec2.CreateVpcEndpointServiceConfigurationOutput, error) + CreateVpcEndpointServiceConfigurationRequest(*ec2.CreateVpcEndpointServiceConfigurationInput) (*request.Request, *ec2.CreateVpcEndpointServiceConfigurationOutput) + CreateVpcPeeringConnection(*ec2.CreateVpcPeeringConnectionInput) (*ec2.CreateVpcPeeringConnectionOutput, error) CreateVpcPeeringConnectionWithContext(aws.Context, *ec2.CreateVpcPeeringConnectionInput, ...request.Option) (*ec2.CreateVpcPeeringConnectionOutput, error) CreateVpcPeeringConnectionRequest(*ec2.CreateVpcPeeringConnectionInput) (*request.Request, *ec2.CreateVpcPeeringConnectionOutput) @@ -320,6 +348,10 @@ type EC2API interface { DeleteFlowLogsWithContext(aws.Context, *ec2.DeleteFlowLogsInput, ...request.Option) (*ec2.DeleteFlowLogsOutput, error) DeleteFlowLogsRequest(*ec2.DeleteFlowLogsInput) (*request.Request, *ec2.DeleteFlowLogsOutput) + DeleteFpgaImage(*ec2.DeleteFpgaImageInput) (*ec2.DeleteFpgaImageOutput, error) + DeleteFpgaImageWithContext(aws.Context, *ec2.DeleteFpgaImageInput, ...request.Option) (*ec2.DeleteFpgaImageOutput, error) + DeleteFpgaImageRequest(*ec2.DeleteFpgaImageInput) (*request.Request, *ec2.DeleteFpgaImageOutput) + DeleteInternetGateway(*ec2.DeleteInternetGatewayInput) (*ec2.DeleteInternetGatewayOutput, error) DeleteInternetGatewayWithContext(aws.Context, *ec2.DeleteInternetGatewayInput, ...request.Option) (*ec2.DeleteInternetGatewayOutput, error) DeleteInternetGatewayRequest(*ec2.DeleteInternetGatewayInput) (*request.Request, *ec2.DeleteInternetGatewayOutput) @@ -328,6 +360,14 @@ type EC2API interface { DeleteKeyPairWithContext(aws.Context, *ec2.DeleteKeyPairInput, ...request.Option) (*ec2.DeleteKeyPairOutput, error) DeleteKeyPairRequest(*ec2.DeleteKeyPairInput) (*request.Request, *ec2.DeleteKeyPairOutput) + DeleteLaunchTemplate(*ec2.DeleteLaunchTemplateInput) (*ec2.DeleteLaunchTemplateOutput, error) + DeleteLaunchTemplateWithContext(aws.Context, *ec2.DeleteLaunchTemplateInput, ...request.Option) (*ec2.DeleteLaunchTemplateOutput, error) + DeleteLaunchTemplateRequest(*ec2.DeleteLaunchTemplateInput) (*request.Request, *ec2.DeleteLaunchTemplateOutput) + + DeleteLaunchTemplateVersions(*ec2.DeleteLaunchTemplateVersionsInput) (*ec2.DeleteLaunchTemplateVersionsOutput, error) + DeleteLaunchTemplateVersionsWithContext(aws.Context, *ec2.DeleteLaunchTemplateVersionsInput, ...request.Option) (*ec2.DeleteLaunchTemplateVersionsOutput, error) + DeleteLaunchTemplateVersionsRequest(*ec2.DeleteLaunchTemplateVersionsInput) (*request.Request, *ec2.DeleteLaunchTemplateVersionsOutput) + DeleteNatGateway(*ec2.DeleteNatGatewayInput) (*ec2.DeleteNatGatewayOutput, error) DeleteNatGatewayWithContext(aws.Context, *ec2.DeleteNatGatewayInput, ...request.Option) (*ec2.DeleteNatGatewayOutput, error) DeleteNatGatewayRequest(*ec2.DeleteNatGatewayInput) (*request.Request, *ec2.DeleteNatGatewayOutput) @@ -388,6 +428,14 @@ type EC2API interface { DeleteVpcWithContext(aws.Context, *ec2.DeleteVpcInput, ...request.Option) (*ec2.DeleteVpcOutput, error) DeleteVpcRequest(*ec2.DeleteVpcInput) (*request.Request, *ec2.DeleteVpcOutput) + DeleteVpcEndpointConnectionNotifications(*ec2.DeleteVpcEndpointConnectionNotificationsInput) (*ec2.DeleteVpcEndpointConnectionNotificationsOutput, error) + DeleteVpcEndpointConnectionNotificationsWithContext(aws.Context, *ec2.DeleteVpcEndpointConnectionNotificationsInput, ...request.Option) (*ec2.DeleteVpcEndpointConnectionNotificationsOutput, error) + DeleteVpcEndpointConnectionNotificationsRequest(*ec2.DeleteVpcEndpointConnectionNotificationsInput) (*request.Request, *ec2.DeleteVpcEndpointConnectionNotificationsOutput) + + DeleteVpcEndpointServiceConfigurations(*ec2.DeleteVpcEndpointServiceConfigurationsInput) (*ec2.DeleteVpcEndpointServiceConfigurationsOutput, error) + DeleteVpcEndpointServiceConfigurationsWithContext(aws.Context, *ec2.DeleteVpcEndpointServiceConfigurationsInput, ...request.Option) (*ec2.DeleteVpcEndpointServiceConfigurationsOutput, error) + DeleteVpcEndpointServiceConfigurationsRequest(*ec2.DeleteVpcEndpointServiceConfigurationsInput) (*request.Request, *ec2.DeleteVpcEndpointServiceConfigurationsOutput) + DeleteVpcEndpoints(*ec2.DeleteVpcEndpointsInput) (*ec2.DeleteVpcEndpointsOutput, error) DeleteVpcEndpointsWithContext(aws.Context, *ec2.DeleteVpcEndpointsInput, ...request.Option) (*ec2.DeleteVpcEndpointsOutput, error) DeleteVpcEndpointsRequest(*ec2.DeleteVpcEndpointsInput) (*request.Request, *ec2.DeleteVpcEndpointsOutput) @@ -460,6 +508,10 @@ type EC2API interface { DescribeFlowLogsWithContext(aws.Context, *ec2.DescribeFlowLogsInput, ...request.Option) (*ec2.DescribeFlowLogsOutput, error) DescribeFlowLogsRequest(*ec2.DescribeFlowLogsInput) (*request.Request, *ec2.DescribeFlowLogsOutput) + DescribeFpgaImageAttribute(*ec2.DescribeFpgaImageAttributeInput) (*ec2.DescribeFpgaImageAttributeOutput, error) + DescribeFpgaImageAttributeWithContext(aws.Context, *ec2.DescribeFpgaImageAttributeInput, ...request.Option) (*ec2.DescribeFpgaImageAttributeOutput, error) + DescribeFpgaImageAttributeRequest(*ec2.DescribeFpgaImageAttributeInput) (*request.Request, *ec2.DescribeFpgaImageAttributeOutput) + DescribeFpgaImages(*ec2.DescribeFpgaImagesInput) (*ec2.DescribeFpgaImagesOutput, error) DescribeFpgaImagesWithContext(aws.Context, *ec2.DescribeFpgaImagesInput, ...request.Option) (*ec2.DescribeFpgaImagesOutput, error) DescribeFpgaImagesRequest(*ec2.DescribeFpgaImagesInput) (*request.Request, *ec2.DescribeFpgaImagesOutput) @@ -508,6 +560,10 @@ type EC2API interface { DescribeInstanceAttributeWithContext(aws.Context, *ec2.DescribeInstanceAttributeInput, ...request.Option) (*ec2.DescribeInstanceAttributeOutput, error) DescribeInstanceAttributeRequest(*ec2.DescribeInstanceAttributeInput) (*request.Request, *ec2.DescribeInstanceAttributeOutput) + DescribeInstanceCreditSpecifications(*ec2.DescribeInstanceCreditSpecificationsInput) (*ec2.DescribeInstanceCreditSpecificationsOutput, error) + DescribeInstanceCreditSpecificationsWithContext(aws.Context, *ec2.DescribeInstanceCreditSpecificationsInput, ...request.Option) (*ec2.DescribeInstanceCreditSpecificationsOutput, error) + DescribeInstanceCreditSpecificationsRequest(*ec2.DescribeInstanceCreditSpecificationsInput) (*request.Request, *ec2.DescribeInstanceCreditSpecificationsOutput) + DescribeInstanceStatus(*ec2.DescribeInstanceStatusInput) (*ec2.DescribeInstanceStatusOutput, error) DescribeInstanceStatusWithContext(aws.Context, *ec2.DescribeInstanceStatusInput, ...request.Option) (*ec2.DescribeInstanceStatusOutput, error) DescribeInstanceStatusRequest(*ec2.DescribeInstanceStatusInput) (*request.Request, *ec2.DescribeInstanceStatusOutput) @@ -530,6 +586,14 @@ type EC2API interface { DescribeKeyPairsWithContext(aws.Context, *ec2.DescribeKeyPairsInput, ...request.Option) (*ec2.DescribeKeyPairsOutput, error) DescribeKeyPairsRequest(*ec2.DescribeKeyPairsInput) (*request.Request, *ec2.DescribeKeyPairsOutput) + DescribeLaunchTemplateVersions(*ec2.DescribeLaunchTemplateVersionsInput) (*ec2.DescribeLaunchTemplateVersionsOutput, error) + DescribeLaunchTemplateVersionsWithContext(aws.Context, *ec2.DescribeLaunchTemplateVersionsInput, ...request.Option) (*ec2.DescribeLaunchTemplateVersionsOutput, error) + DescribeLaunchTemplateVersionsRequest(*ec2.DescribeLaunchTemplateVersionsInput) (*request.Request, *ec2.DescribeLaunchTemplateVersionsOutput) + + DescribeLaunchTemplates(*ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error) + DescribeLaunchTemplatesWithContext(aws.Context, *ec2.DescribeLaunchTemplatesInput, ...request.Option) (*ec2.DescribeLaunchTemplatesOutput, error) + DescribeLaunchTemplatesRequest(*ec2.DescribeLaunchTemplatesInput) (*request.Request, *ec2.DescribeLaunchTemplatesOutput) + DescribeMovingAddresses(*ec2.DescribeMovingAddressesInput) (*ec2.DescribeMovingAddressesOutput, error) DescribeMovingAddressesWithContext(aws.Context, *ec2.DescribeMovingAddressesInput, ...request.Option) (*ec2.DescribeMovingAddressesOutput, error) DescribeMovingAddressesRequest(*ec2.DescribeMovingAddressesInput) (*request.Request, *ec2.DescribeMovingAddressesOutput) @@ -701,6 +765,22 @@ type EC2API interface { DescribeVpcClassicLinkDnsSupportWithContext(aws.Context, *ec2.DescribeVpcClassicLinkDnsSupportInput, ...request.Option) (*ec2.DescribeVpcClassicLinkDnsSupportOutput, error) DescribeVpcClassicLinkDnsSupportRequest(*ec2.DescribeVpcClassicLinkDnsSupportInput) (*request.Request, *ec2.DescribeVpcClassicLinkDnsSupportOutput) + DescribeVpcEndpointConnectionNotifications(*ec2.DescribeVpcEndpointConnectionNotificationsInput) (*ec2.DescribeVpcEndpointConnectionNotificationsOutput, error) + DescribeVpcEndpointConnectionNotificationsWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionNotificationsInput, ...request.Option) (*ec2.DescribeVpcEndpointConnectionNotificationsOutput, error) + DescribeVpcEndpointConnectionNotificationsRequest(*ec2.DescribeVpcEndpointConnectionNotificationsInput) (*request.Request, *ec2.DescribeVpcEndpointConnectionNotificationsOutput) + + DescribeVpcEndpointConnections(*ec2.DescribeVpcEndpointConnectionsInput) (*ec2.DescribeVpcEndpointConnectionsOutput, error) + DescribeVpcEndpointConnectionsWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionsInput, ...request.Option) (*ec2.DescribeVpcEndpointConnectionsOutput, error) + DescribeVpcEndpointConnectionsRequest(*ec2.DescribeVpcEndpointConnectionsInput) (*request.Request, *ec2.DescribeVpcEndpointConnectionsOutput) + + DescribeVpcEndpointServiceConfigurations(*ec2.DescribeVpcEndpointServiceConfigurationsInput) (*ec2.DescribeVpcEndpointServiceConfigurationsOutput, error) + DescribeVpcEndpointServiceConfigurationsWithContext(aws.Context, *ec2.DescribeVpcEndpointServiceConfigurationsInput, ...request.Option) (*ec2.DescribeVpcEndpointServiceConfigurationsOutput, error) + DescribeVpcEndpointServiceConfigurationsRequest(*ec2.DescribeVpcEndpointServiceConfigurationsInput) (*request.Request, *ec2.DescribeVpcEndpointServiceConfigurationsOutput) + + DescribeVpcEndpointServicePermissions(*ec2.DescribeVpcEndpointServicePermissionsInput) (*ec2.DescribeVpcEndpointServicePermissionsOutput, error) + DescribeVpcEndpointServicePermissionsWithContext(aws.Context, *ec2.DescribeVpcEndpointServicePermissionsInput, ...request.Option) (*ec2.DescribeVpcEndpointServicePermissionsOutput, error) + DescribeVpcEndpointServicePermissionsRequest(*ec2.DescribeVpcEndpointServicePermissionsInput) (*request.Request, *ec2.DescribeVpcEndpointServicePermissionsOutput) + DescribeVpcEndpointServices(*ec2.DescribeVpcEndpointServicesInput) (*ec2.DescribeVpcEndpointServicesOutput, error) DescribeVpcEndpointServicesWithContext(aws.Context, *ec2.DescribeVpcEndpointServicesInput, ...request.Option) (*ec2.DescribeVpcEndpointServicesOutput, error) DescribeVpcEndpointServicesRequest(*ec2.DescribeVpcEndpointServicesInput) (*request.Request, *ec2.DescribeVpcEndpointServicesOutput) @@ -805,6 +885,10 @@ type EC2API interface { GetHostReservationPurchasePreviewWithContext(aws.Context, *ec2.GetHostReservationPurchasePreviewInput, ...request.Option) (*ec2.GetHostReservationPurchasePreviewOutput, error) GetHostReservationPurchasePreviewRequest(*ec2.GetHostReservationPurchasePreviewInput) (*request.Request, *ec2.GetHostReservationPurchasePreviewOutput) + GetLaunchTemplateData(*ec2.GetLaunchTemplateDataInput) (*ec2.GetLaunchTemplateDataOutput, error) + GetLaunchTemplateDataWithContext(aws.Context, *ec2.GetLaunchTemplateDataInput, ...request.Option) (*ec2.GetLaunchTemplateDataOutput, error) + GetLaunchTemplateDataRequest(*ec2.GetLaunchTemplateDataInput) (*request.Request, *ec2.GetLaunchTemplateDataOutput) + GetPasswordData(*ec2.GetPasswordDataInput) (*ec2.GetPasswordDataOutput, error) GetPasswordDataWithContext(aws.Context, *ec2.GetPasswordDataInput, ...request.Option) (*ec2.GetPasswordDataOutput, error) GetPasswordDataRequest(*ec2.GetPasswordDataInput) (*request.Request, *ec2.GetPasswordDataOutput) @@ -833,6 +917,10 @@ type EC2API interface { ImportVolumeWithContext(aws.Context, *ec2.ImportVolumeInput, ...request.Option) (*ec2.ImportVolumeOutput, error) ImportVolumeRequest(*ec2.ImportVolumeInput) (*request.Request, *ec2.ImportVolumeOutput) + ModifyFpgaImageAttribute(*ec2.ModifyFpgaImageAttributeInput) (*ec2.ModifyFpgaImageAttributeOutput, error) + ModifyFpgaImageAttributeWithContext(aws.Context, *ec2.ModifyFpgaImageAttributeInput, ...request.Option) (*ec2.ModifyFpgaImageAttributeOutput, error) + ModifyFpgaImageAttributeRequest(*ec2.ModifyFpgaImageAttributeInput) (*request.Request, *ec2.ModifyFpgaImageAttributeOutput) + ModifyHosts(*ec2.ModifyHostsInput) (*ec2.ModifyHostsOutput, error) ModifyHostsWithContext(aws.Context, *ec2.ModifyHostsInput, ...request.Option) (*ec2.ModifyHostsOutput, error) ModifyHostsRequest(*ec2.ModifyHostsInput) (*request.Request, *ec2.ModifyHostsOutput) @@ -853,10 +941,18 @@ type EC2API interface { ModifyInstanceAttributeWithContext(aws.Context, *ec2.ModifyInstanceAttributeInput, ...request.Option) (*ec2.ModifyInstanceAttributeOutput, error) ModifyInstanceAttributeRequest(*ec2.ModifyInstanceAttributeInput) (*request.Request, *ec2.ModifyInstanceAttributeOutput) + ModifyInstanceCreditSpecification(*ec2.ModifyInstanceCreditSpecificationInput) (*ec2.ModifyInstanceCreditSpecificationOutput, error) + ModifyInstanceCreditSpecificationWithContext(aws.Context, *ec2.ModifyInstanceCreditSpecificationInput, ...request.Option) (*ec2.ModifyInstanceCreditSpecificationOutput, error) + ModifyInstanceCreditSpecificationRequest(*ec2.ModifyInstanceCreditSpecificationInput) (*request.Request, *ec2.ModifyInstanceCreditSpecificationOutput) + ModifyInstancePlacement(*ec2.ModifyInstancePlacementInput) (*ec2.ModifyInstancePlacementOutput, error) ModifyInstancePlacementWithContext(aws.Context, *ec2.ModifyInstancePlacementInput, ...request.Option) (*ec2.ModifyInstancePlacementOutput, error) ModifyInstancePlacementRequest(*ec2.ModifyInstancePlacementInput) (*request.Request, *ec2.ModifyInstancePlacementOutput) + ModifyLaunchTemplate(*ec2.ModifyLaunchTemplateInput) (*ec2.ModifyLaunchTemplateOutput, error) + ModifyLaunchTemplateWithContext(aws.Context, *ec2.ModifyLaunchTemplateInput, ...request.Option) (*ec2.ModifyLaunchTemplateOutput, error) + ModifyLaunchTemplateRequest(*ec2.ModifyLaunchTemplateInput) (*request.Request, *ec2.ModifyLaunchTemplateOutput) + ModifyNetworkInterfaceAttribute(*ec2.ModifyNetworkInterfaceAttributeInput) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) ModifyNetworkInterfaceAttributeWithContext(aws.Context, *ec2.ModifyNetworkInterfaceAttributeInput, ...request.Option) (*ec2.ModifyNetworkInterfaceAttributeOutput, error) ModifyNetworkInterfaceAttributeRequest(*ec2.ModifyNetworkInterfaceAttributeInput) (*request.Request, *ec2.ModifyNetworkInterfaceAttributeOutput) @@ -893,10 +989,26 @@ type EC2API interface { ModifyVpcEndpointWithContext(aws.Context, *ec2.ModifyVpcEndpointInput, ...request.Option) (*ec2.ModifyVpcEndpointOutput, error) ModifyVpcEndpointRequest(*ec2.ModifyVpcEndpointInput) (*request.Request, *ec2.ModifyVpcEndpointOutput) + ModifyVpcEndpointConnectionNotification(*ec2.ModifyVpcEndpointConnectionNotificationInput) (*ec2.ModifyVpcEndpointConnectionNotificationOutput, error) + ModifyVpcEndpointConnectionNotificationWithContext(aws.Context, *ec2.ModifyVpcEndpointConnectionNotificationInput, ...request.Option) (*ec2.ModifyVpcEndpointConnectionNotificationOutput, error) + ModifyVpcEndpointConnectionNotificationRequest(*ec2.ModifyVpcEndpointConnectionNotificationInput) (*request.Request, *ec2.ModifyVpcEndpointConnectionNotificationOutput) + + ModifyVpcEndpointServiceConfiguration(*ec2.ModifyVpcEndpointServiceConfigurationInput) (*ec2.ModifyVpcEndpointServiceConfigurationOutput, error) + ModifyVpcEndpointServiceConfigurationWithContext(aws.Context, *ec2.ModifyVpcEndpointServiceConfigurationInput, ...request.Option) (*ec2.ModifyVpcEndpointServiceConfigurationOutput, error) + ModifyVpcEndpointServiceConfigurationRequest(*ec2.ModifyVpcEndpointServiceConfigurationInput) (*request.Request, *ec2.ModifyVpcEndpointServiceConfigurationOutput) + + ModifyVpcEndpointServicePermissions(*ec2.ModifyVpcEndpointServicePermissionsInput) (*ec2.ModifyVpcEndpointServicePermissionsOutput, error) + ModifyVpcEndpointServicePermissionsWithContext(aws.Context, *ec2.ModifyVpcEndpointServicePermissionsInput, ...request.Option) (*ec2.ModifyVpcEndpointServicePermissionsOutput, error) + ModifyVpcEndpointServicePermissionsRequest(*ec2.ModifyVpcEndpointServicePermissionsInput) (*request.Request, *ec2.ModifyVpcEndpointServicePermissionsOutput) + ModifyVpcPeeringConnectionOptions(*ec2.ModifyVpcPeeringConnectionOptionsInput) (*ec2.ModifyVpcPeeringConnectionOptionsOutput, error) ModifyVpcPeeringConnectionOptionsWithContext(aws.Context, *ec2.ModifyVpcPeeringConnectionOptionsInput, ...request.Option) (*ec2.ModifyVpcPeeringConnectionOptionsOutput, error) ModifyVpcPeeringConnectionOptionsRequest(*ec2.ModifyVpcPeeringConnectionOptionsInput) (*request.Request, *ec2.ModifyVpcPeeringConnectionOptionsOutput) + ModifyVpcTenancy(*ec2.ModifyVpcTenancyInput) (*ec2.ModifyVpcTenancyOutput, error) + ModifyVpcTenancyWithContext(aws.Context, *ec2.ModifyVpcTenancyInput, ...request.Option) (*ec2.ModifyVpcTenancyOutput, error) + ModifyVpcTenancyRequest(*ec2.ModifyVpcTenancyInput) (*request.Request, *ec2.ModifyVpcTenancyOutput) + MonitorInstances(*ec2.MonitorInstancesInput) (*ec2.MonitorInstancesOutput, error) MonitorInstancesWithContext(aws.Context, *ec2.MonitorInstancesInput, ...request.Option) (*ec2.MonitorInstancesOutput, error) MonitorInstancesRequest(*ec2.MonitorInstancesInput) (*request.Request, *ec2.MonitorInstancesOutput) @@ -925,6 +1037,10 @@ type EC2API interface { RegisterImageWithContext(aws.Context, *ec2.RegisterImageInput, ...request.Option) (*ec2.RegisterImageOutput, error) RegisterImageRequest(*ec2.RegisterImageInput) (*request.Request, *ec2.RegisterImageOutput) + RejectVpcEndpointConnections(*ec2.RejectVpcEndpointConnectionsInput) (*ec2.RejectVpcEndpointConnectionsOutput, error) + RejectVpcEndpointConnectionsWithContext(aws.Context, *ec2.RejectVpcEndpointConnectionsInput, ...request.Option) (*ec2.RejectVpcEndpointConnectionsOutput, error) + RejectVpcEndpointConnectionsRequest(*ec2.RejectVpcEndpointConnectionsInput) (*request.Request, *ec2.RejectVpcEndpointConnectionsOutput) + RejectVpcPeeringConnection(*ec2.RejectVpcPeeringConnectionInput) (*ec2.RejectVpcPeeringConnectionOutput, error) RejectVpcPeeringConnectionWithContext(aws.Context, *ec2.RejectVpcPeeringConnectionInput, ...request.Option) (*ec2.RejectVpcPeeringConnectionOutput, error) RejectVpcPeeringConnectionRequest(*ec2.RejectVpcPeeringConnectionInput) (*request.Request, *ec2.RejectVpcPeeringConnectionOutput) @@ -969,6 +1085,10 @@ type EC2API interface { RequestSpotInstancesWithContext(aws.Context, *ec2.RequestSpotInstancesInput, ...request.Option) (*ec2.RequestSpotInstancesOutput, error) RequestSpotInstancesRequest(*ec2.RequestSpotInstancesInput) (*request.Request, *ec2.RequestSpotInstancesOutput) + ResetFpgaImageAttribute(*ec2.ResetFpgaImageAttributeInput) (*ec2.ResetFpgaImageAttributeOutput, error) + ResetFpgaImageAttributeWithContext(aws.Context, *ec2.ResetFpgaImageAttributeInput, ...request.Option) (*ec2.ResetFpgaImageAttributeOutput, error) + ResetFpgaImageAttributeRequest(*ec2.ResetFpgaImageAttributeInput) (*request.Request, *ec2.ResetFpgaImageAttributeOutput) + ResetImageAttribute(*ec2.ResetImageAttributeInput) (*ec2.ResetImageAttributeOutput, error) ResetImageAttributeWithContext(aws.Context, *ec2.ResetImageAttributeInput, ...request.Option) (*ec2.ResetImageAttributeOutput, error) ResetImageAttributeRequest(*ec2.ResetImageAttributeInput) (*request.Request, *ec2.ResetImageAttributeOutput) @@ -1029,6 +1149,14 @@ type EC2API interface { UnmonitorInstancesWithContext(aws.Context, *ec2.UnmonitorInstancesInput, ...request.Option) (*ec2.UnmonitorInstancesOutput, error) UnmonitorInstancesRequest(*ec2.UnmonitorInstancesInput) (*request.Request, *ec2.UnmonitorInstancesOutput) + UpdateSecurityGroupRuleDescriptionsEgress(*ec2.UpdateSecurityGroupRuleDescriptionsEgressInput) (*ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput, error) + UpdateSecurityGroupRuleDescriptionsEgressWithContext(aws.Context, *ec2.UpdateSecurityGroupRuleDescriptionsEgressInput, ...request.Option) (*ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput, error) + UpdateSecurityGroupRuleDescriptionsEgressRequest(*ec2.UpdateSecurityGroupRuleDescriptionsEgressInput) (*request.Request, *ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput) + + UpdateSecurityGroupRuleDescriptionsIngress(*ec2.UpdateSecurityGroupRuleDescriptionsIngressInput) (*ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput, error) + UpdateSecurityGroupRuleDescriptionsIngressWithContext(aws.Context, *ec2.UpdateSecurityGroupRuleDescriptionsIngressInput, ...request.Option) (*ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput, error) + UpdateSecurityGroupRuleDescriptionsIngressRequest(*ec2.UpdateSecurityGroupRuleDescriptionsIngressInput) (*request.Request, *ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput) + WaitUntilBundleTaskComplete(*ec2.DescribeBundleTasksInput) error WaitUntilBundleTaskCompleteWithContext(aws.Context, *ec2.DescribeBundleTasksInput, ...request.WaiterOption) error diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/waiters.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/waiters.go index c0a655fa0f0..0469f0f01a1 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/ec2/waiters.go +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/waiters.go @@ -11,7 +11,7 @@ import ( // WaitUntilBundleTaskComplete uses the Amazon EC2 API operation // DescribeBundleTasks to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilBundleTaskComplete(input *DescribeBundleTasksInput) error { return c.WaitUntilBundleTaskCompleteWithContext(aws.BackgroundContext(), input) @@ -62,7 +62,7 @@ func (c *EC2) WaitUntilBundleTaskCompleteWithContext(ctx aws.Context, input *Des // WaitUntilConversionTaskCancelled uses the Amazon EC2 API operation // DescribeConversionTasks to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilConversionTaskCancelled(input *DescribeConversionTasksInput) error { return c.WaitUntilConversionTaskCancelledWithContext(aws.BackgroundContext(), input) @@ -108,7 +108,7 @@ func (c *EC2) WaitUntilConversionTaskCancelledWithContext(ctx aws.Context, input // WaitUntilConversionTaskCompleted uses the Amazon EC2 API operation // DescribeConversionTasks to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilConversionTaskCompleted(input *DescribeConversionTasksInput) error { return c.WaitUntilConversionTaskCompletedWithContext(aws.BackgroundContext(), input) @@ -164,7 +164,7 @@ func (c *EC2) WaitUntilConversionTaskCompletedWithContext(ctx aws.Context, input // WaitUntilConversionTaskDeleted uses the Amazon EC2 API operation // DescribeConversionTasks to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilConversionTaskDeleted(input *DescribeConversionTasksInput) error { return c.WaitUntilConversionTaskDeletedWithContext(aws.BackgroundContext(), input) @@ -210,7 +210,7 @@ func (c *EC2) WaitUntilConversionTaskDeletedWithContext(ctx aws.Context, input * // WaitUntilCustomerGatewayAvailable uses the Amazon EC2 API operation // DescribeCustomerGateways to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilCustomerGatewayAvailable(input *DescribeCustomerGatewaysInput) error { return c.WaitUntilCustomerGatewayAvailableWithContext(aws.BackgroundContext(), input) @@ -266,7 +266,7 @@ func (c *EC2) WaitUntilCustomerGatewayAvailableWithContext(ctx aws.Context, inpu // WaitUntilExportTaskCancelled uses the Amazon EC2 API operation // DescribeExportTasks to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilExportTaskCancelled(input *DescribeExportTasksInput) error { return c.WaitUntilExportTaskCancelledWithContext(aws.BackgroundContext(), input) @@ -312,7 +312,7 @@ func (c *EC2) WaitUntilExportTaskCancelledWithContext(ctx aws.Context, input *De // WaitUntilExportTaskCompleted uses the Amazon EC2 API operation // DescribeExportTasks to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilExportTaskCompleted(input *DescribeExportTasksInput) error { return c.WaitUntilExportTaskCompletedWithContext(aws.BackgroundContext(), input) @@ -358,7 +358,7 @@ func (c *EC2) WaitUntilExportTaskCompletedWithContext(ctx aws.Context, input *De // WaitUntilImageAvailable uses the Amazon EC2 API operation // DescribeImages to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilImageAvailable(input *DescribeImagesInput) error { return c.WaitUntilImageAvailableWithContext(aws.BackgroundContext(), input) @@ -409,7 +409,7 @@ func (c *EC2) WaitUntilImageAvailableWithContext(ctx aws.Context, input *Describ // WaitUntilImageExists uses the Amazon EC2 API operation // DescribeImages to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilImageExists(input *DescribeImagesInput) error { return c.WaitUntilImageExistsWithContext(aws.BackgroundContext(), input) @@ -460,7 +460,7 @@ func (c *EC2) WaitUntilImageExistsWithContext(ctx aws.Context, input *DescribeIm // WaitUntilInstanceExists uses the Amazon EC2 API operation // DescribeInstances to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilInstanceExists(input *DescribeInstancesInput) error { return c.WaitUntilInstanceExistsWithContext(aws.BackgroundContext(), input) @@ -511,7 +511,7 @@ func (c *EC2) WaitUntilInstanceExistsWithContext(ctx aws.Context, input *Describ // WaitUntilInstanceRunning uses the Amazon EC2 API operation // DescribeInstances to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilInstanceRunning(input *DescribeInstancesInput) error { return c.WaitUntilInstanceRunningWithContext(aws.BackgroundContext(), input) @@ -577,7 +577,7 @@ func (c *EC2) WaitUntilInstanceRunningWithContext(ctx aws.Context, input *Descri // WaitUntilInstanceStatusOk uses the Amazon EC2 API operation // DescribeInstanceStatus to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilInstanceStatusOk(input *DescribeInstanceStatusInput) error { return c.WaitUntilInstanceStatusOkWithContext(aws.BackgroundContext(), input) @@ -628,7 +628,7 @@ func (c *EC2) WaitUntilInstanceStatusOkWithContext(ctx aws.Context, input *Descr // WaitUntilInstanceStopped uses the Amazon EC2 API operation // DescribeInstances to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilInstanceStopped(input *DescribeInstancesInput) error { return c.WaitUntilInstanceStoppedWithContext(aws.BackgroundContext(), input) @@ -684,7 +684,7 @@ func (c *EC2) WaitUntilInstanceStoppedWithContext(ctx aws.Context, input *Descri // WaitUntilInstanceTerminated uses the Amazon EC2 API operation // DescribeInstances to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilInstanceTerminated(input *DescribeInstancesInput) error { return c.WaitUntilInstanceTerminatedWithContext(aws.BackgroundContext(), input) @@ -740,7 +740,7 @@ func (c *EC2) WaitUntilInstanceTerminatedWithContext(ctx aws.Context, input *Des // WaitUntilKeyPairExists uses the Amazon EC2 API operation // DescribeKeyPairs to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilKeyPairExists(input *DescribeKeyPairsInput) error { return c.WaitUntilKeyPairExistsWithContext(aws.BackgroundContext(), input) @@ -791,7 +791,7 @@ func (c *EC2) WaitUntilKeyPairExistsWithContext(ctx aws.Context, input *Describe // WaitUntilNatGatewayAvailable uses the Amazon EC2 API operation // DescribeNatGateways to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilNatGatewayAvailable(input *DescribeNatGatewaysInput) error { return c.WaitUntilNatGatewayAvailableWithContext(aws.BackgroundContext(), input) @@ -857,7 +857,7 @@ func (c *EC2) WaitUntilNatGatewayAvailableWithContext(ctx aws.Context, input *De // WaitUntilNetworkInterfaceAvailable uses the Amazon EC2 API operation // DescribeNetworkInterfaces to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilNetworkInterfaceAvailable(input *DescribeNetworkInterfacesInput) error { return c.WaitUntilNetworkInterfaceAvailableWithContext(aws.BackgroundContext(), input) @@ -908,7 +908,7 @@ func (c *EC2) WaitUntilNetworkInterfaceAvailableWithContext(ctx aws.Context, inp // WaitUntilPasswordDataAvailable uses the Amazon EC2 API operation // GetPasswordData to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilPasswordDataAvailable(input *GetPasswordDataInput) error { return c.WaitUntilPasswordDataAvailableWithContext(aws.BackgroundContext(), input) @@ -954,7 +954,7 @@ func (c *EC2) WaitUntilPasswordDataAvailableWithContext(ctx aws.Context, input * // WaitUntilSnapshotCompleted uses the Amazon EC2 API operation // DescribeSnapshots to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilSnapshotCompleted(input *DescribeSnapshotsInput) error { return c.WaitUntilSnapshotCompletedWithContext(aws.BackgroundContext(), input) @@ -1000,7 +1000,7 @@ func (c *EC2) WaitUntilSnapshotCompletedWithContext(ctx aws.Context, input *Desc // WaitUntilSpotInstanceRequestFulfilled uses the Amazon EC2 API operation // DescribeSpotInstanceRequests to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilSpotInstanceRequestFulfilled(input *DescribeSpotInstanceRequestsInput) error { return c.WaitUntilSpotInstanceRequestFulfilledWithContext(aws.BackgroundContext(), input) @@ -1025,6 +1025,11 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilledWithContext(ctx aws.Context, Matcher: request.PathAllWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code", Expected: "fulfilled", }, + { + State: request.SuccessWaiterState, + Matcher: request.PathAllWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code", + Expected: "request-canceled-and-instance-running", + }, { State: request.FailureWaiterState, Matcher: request.PathAnyWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code", @@ -1045,6 +1050,11 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilledWithContext(ctx aws.Context, Matcher: request.PathAnyWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code", Expected: "system-error", }, + { + State: request.RetryWaiterState, + Matcher: request.ErrorWaiterMatch, + Expected: "InvalidSpotInstanceRequestID.NotFound", + }, }, Logger: c.Config.Logger, NewRequest: func(opts []request.Option) (*request.Request, error) { @@ -1066,7 +1076,7 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilledWithContext(ctx aws.Context, // WaitUntilSubnetAvailable uses the Amazon EC2 API operation // DescribeSubnets to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilSubnetAvailable(input *DescribeSubnetsInput) error { return c.WaitUntilSubnetAvailableWithContext(aws.BackgroundContext(), input) @@ -1112,7 +1122,7 @@ func (c *EC2) WaitUntilSubnetAvailableWithContext(ctx aws.Context, input *Descri // WaitUntilSystemStatusOk uses the Amazon EC2 API operation // DescribeInstanceStatus to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilSystemStatusOk(input *DescribeInstanceStatusInput) error { return c.WaitUntilSystemStatusOkWithContext(aws.BackgroundContext(), input) @@ -1158,7 +1168,7 @@ func (c *EC2) WaitUntilSystemStatusOkWithContext(ctx aws.Context, input *Describ // WaitUntilVolumeAvailable uses the Amazon EC2 API operation // DescribeVolumes to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVolumeAvailable(input *DescribeVolumesInput) error { return c.WaitUntilVolumeAvailableWithContext(aws.BackgroundContext(), input) @@ -1209,7 +1219,7 @@ func (c *EC2) WaitUntilVolumeAvailableWithContext(ctx aws.Context, input *Descri // WaitUntilVolumeDeleted uses the Amazon EC2 API operation // DescribeVolumes to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVolumeDeleted(input *DescribeVolumesInput) error { return c.WaitUntilVolumeDeletedWithContext(aws.BackgroundContext(), input) @@ -1260,7 +1270,7 @@ func (c *EC2) WaitUntilVolumeDeletedWithContext(ctx aws.Context, input *Describe // WaitUntilVolumeInUse uses the Amazon EC2 API operation // DescribeVolumes to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVolumeInUse(input *DescribeVolumesInput) error { return c.WaitUntilVolumeInUseWithContext(aws.BackgroundContext(), input) @@ -1311,7 +1321,7 @@ func (c *EC2) WaitUntilVolumeInUseWithContext(ctx aws.Context, input *DescribeVo // WaitUntilVpcAvailable uses the Amazon EC2 API operation // DescribeVpcs to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVpcAvailable(input *DescribeVpcsInput) error { return c.WaitUntilVpcAvailableWithContext(aws.BackgroundContext(), input) @@ -1357,7 +1367,7 @@ func (c *EC2) WaitUntilVpcAvailableWithContext(ctx aws.Context, input *DescribeV // WaitUntilVpcExists uses the Amazon EC2 API operation // DescribeVpcs to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVpcExists(input *DescribeVpcsInput) error { return c.WaitUntilVpcExistsWithContext(aws.BackgroundContext(), input) @@ -1408,7 +1418,7 @@ func (c *EC2) WaitUntilVpcExistsWithContext(ctx aws.Context, input *DescribeVpcs // WaitUntilVpcPeeringConnectionDeleted uses the Amazon EC2 API operation // DescribeVpcPeeringConnections to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVpcPeeringConnectionDeleted(input *DescribeVpcPeeringConnectionsInput) error { return c.WaitUntilVpcPeeringConnectionDeletedWithContext(aws.BackgroundContext(), input) @@ -1459,7 +1469,7 @@ func (c *EC2) WaitUntilVpcPeeringConnectionDeletedWithContext(ctx aws.Context, i // WaitUntilVpcPeeringConnectionExists uses the Amazon EC2 API operation // DescribeVpcPeeringConnections to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVpcPeeringConnectionExists(input *DescribeVpcPeeringConnectionsInput) error { return c.WaitUntilVpcPeeringConnectionExistsWithContext(aws.BackgroundContext(), input) @@ -1510,7 +1520,7 @@ func (c *EC2) WaitUntilVpcPeeringConnectionExistsWithContext(ctx aws.Context, in // WaitUntilVpnConnectionAvailable uses the Amazon EC2 API operation // DescribeVpnConnections to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVpnConnectionAvailable(input *DescribeVpnConnectionsInput) error { return c.WaitUntilVpnConnectionAvailableWithContext(aws.BackgroundContext(), input) @@ -1566,7 +1576,7 @@ func (c *EC2) WaitUntilVpnConnectionAvailableWithContext(ctx aws.Context, input // WaitUntilVpnConnectionDeleted uses the Amazon EC2 API operation // DescribeVpnConnections to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *EC2) WaitUntilVpnConnectionDeleted(input *DescribeVpnConnectionsInput) error { return c.WaitUntilVpnConnectionDeletedWithContext(aws.BackgroundContext(), input) diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/api.go b/vendor/github.com/aws/aws-sdk-go/service/s3/api.go index 8a5fd8e17ef..0d852f59c80 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/api.go +++ b/vendor/github.com/aws/aws-sdk-go/service/s3/api.go @@ -18,19 +18,18 @@ const opAbortMultipartUpload = "AbortMultipartUpload" // AbortMultipartUploadRequest generates a "aws/request.Request" representing the // client's request for the AbortMultipartUpload operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AbortMultipartUpload for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AbortMultipartUpload method directly -// instead. +// See AbortMultipartUpload for more information on using the AbortMultipartUpload +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AbortMultipartUploadRequest method. // req, resp := client.AbortMultipartUploadRequest(params) @@ -40,7 +39,7 @@ const opAbortMultipartUpload = "AbortMultipartUpload" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload func (c *S3) AbortMultipartUploadRequest(input *AbortMultipartUploadInput) (req *request.Request, output *AbortMultipartUploadOutput) { op := &request.Operation{ Name: opAbortMultipartUpload, @@ -76,7 +75,7 @@ func (c *S3) AbortMultipartUploadRequest(input *AbortMultipartUploadInput) (req // * ErrCodeNoSuchUpload "NoSuchUpload" // The specified multipart upload does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload func (c *S3) AbortMultipartUpload(input *AbortMultipartUploadInput) (*AbortMultipartUploadOutput, error) { req, out := c.AbortMultipartUploadRequest(input) return out, req.Send() @@ -102,19 +101,18 @@ const opCompleteMultipartUpload = "CompleteMultipartUpload" // CompleteMultipartUploadRequest generates a "aws/request.Request" representing the // client's request for the CompleteMultipartUpload operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CompleteMultipartUpload for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CompleteMultipartUpload method directly -// instead. +// See CompleteMultipartUpload for more information on using the CompleteMultipartUpload +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CompleteMultipartUploadRequest method. // req, resp := client.CompleteMultipartUploadRequest(params) @@ -124,7 +122,7 @@ const opCompleteMultipartUpload = "CompleteMultipartUpload" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload func (c *S3) CompleteMultipartUploadRequest(input *CompleteMultipartUploadInput) (req *request.Request, output *CompleteMultipartUploadOutput) { op := &request.Operation{ Name: opCompleteMultipartUpload, @@ -151,7 +149,7 @@ func (c *S3) CompleteMultipartUploadRequest(input *CompleteMultipartUploadInput) // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation CompleteMultipartUpload for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload func (c *S3) CompleteMultipartUpload(input *CompleteMultipartUploadInput) (*CompleteMultipartUploadOutput, error) { req, out := c.CompleteMultipartUploadRequest(input) return out, req.Send() @@ -177,19 +175,18 @@ const opCopyObject = "CopyObject" // CopyObjectRequest generates a "aws/request.Request" representing the // client's request for the CopyObject operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CopyObject for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CopyObject method directly -// instead. +// See CopyObject for more information on using the CopyObject +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CopyObjectRequest method. // req, resp := client.CopyObjectRequest(params) @@ -199,7 +196,7 @@ const opCopyObject = "CopyObject" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObject func (c *S3) CopyObjectRequest(input *CopyObjectInput) (req *request.Request, output *CopyObjectOutput) { op := &request.Operation{ Name: opCopyObject, @@ -232,7 +229,7 @@ func (c *S3) CopyObjectRequest(input *CopyObjectInput) (req *request.Request, ou // The source object of the COPY operation is not in the active tier and is // only stored in Amazon Glacier. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObject func (c *S3) CopyObject(input *CopyObjectInput) (*CopyObjectOutput, error) { req, out := c.CopyObjectRequest(input) return out, req.Send() @@ -258,19 +255,18 @@ const opCreateBucket = "CreateBucket" // CreateBucketRequest generates a "aws/request.Request" representing the // client's request for the CreateBucket operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateBucket for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateBucket method directly -// instead. +// See CreateBucket for more information on using the CreateBucket +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateBucketRequest method. // req, resp := client.CreateBucketRequest(params) @@ -280,7 +276,7 @@ const opCreateBucket = "CreateBucket" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket func (c *S3) CreateBucketRequest(input *CreateBucketInput) (req *request.Request, output *CreateBucketOutput) { op := &request.Operation{ Name: opCreateBucket, @@ -315,7 +311,7 @@ func (c *S3) CreateBucketRequest(input *CreateBucketInput) (req *request.Request // // * ErrCodeBucketAlreadyOwnedByYou "BucketAlreadyOwnedByYou" // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket func (c *S3) CreateBucket(input *CreateBucketInput) (*CreateBucketOutput, error) { req, out := c.CreateBucketRequest(input) return out, req.Send() @@ -341,19 +337,18 @@ const opCreateMultipartUpload = "CreateMultipartUpload" // CreateMultipartUploadRequest generates a "aws/request.Request" representing the // client's request for the CreateMultipartUpload operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See CreateMultipartUpload for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the CreateMultipartUpload method directly -// instead. +// See CreateMultipartUpload for more information on using the CreateMultipartUpload +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the CreateMultipartUploadRequest method. // req, resp := client.CreateMultipartUploadRequest(params) @@ -363,7 +358,7 @@ const opCreateMultipartUpload = "CreateMultipartUpload" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUpload func (c *S3) CreateMultipartUploadRequest(input *CreateMultipartUploadInput) (req *request.Request, output *CreateMultipartUploadOutput) { op := &request.Operation{ Name: opCreateMultipartUpload, @@ -396,7 +391,7 @@ func (c *S3) CreateMultipartUploadRequest(input *CreateMultipartUploadInput) (re // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation CreateMultipartUpload for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUpload func (c *S3) CreateMultipartUpload(input *CreateMultipartUploadInput) (*CreateMultipartUploadOutput, error) { req, out := c.CreateMultipartUploadRequest(input) return out, req.Send() @@ -422,19 +417,18 @@ const opDeleteBucket = "DeleteBucket" // DeleteBucketRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucket operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucket for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucket method directly -// instead. +// See DeleteBucket for more information on using the DeleteBucket +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketRequest method. // req, resp := client.DeleteBucketRequest(params) @@ -444,7 +438,7 @@ const opDeleteBucket = "DeleteBucket" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket func (c *S3) DeleteBucketRequest(input *DeleteBucketInput) (req *request.Request, output *DeleteBucketOutput) { op := &request.Operation{ Name: opDeleteBucket, @@ -474,7 +468,7 @@ func (c *S3) DeleteBucketRequest(input *DeleteBucketInput) (req *request.Request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucket for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket func (c *S3) DeleteBucket(input *DeleteBucketInput) (*DeleteBucketOutput, error) { req, out := c.DeleteBucketRequest(input) return out, req.Send() @@ -500,19 +494,18 @@ const opDeleteBucketAnalyticsConfiguration = "DeleteBucketAnalyticsConfiguration // DeleteBucketAnalyticsConfigurationRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketAnalyticsConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketAnalyticsConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketAnalyticsConfiguration method directly -// instead. +// See DeleteBucketAnalyticsConfiguration for more information on using the DeleteBucketAnalyticsConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketAnalyticsConfigurationRequest method. // req, resp := client.DeleteBucketAnalyticsConfigurationRequest(params) @@ -522,7 +515,7 @@ const opDeleteBucketAnalyticsConfiguration = "DeleteBucketAnalyticsConfiguration // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfiguration func (c *S3) DeleteBucketAnalyticsConfigurationRequest(input *DeleteBucketAnalyticsConfigurationInput) (req *request.Request, output *DeleteBucketAnalyticsConfigurationOutput) { op := &request.Operation{ Name: opDeleteBucketAnalyticsConfiguration, @@ -552,7 +545,7 @@ func (c *S3) DeleteBucketAnalyticsConfigurationRequest(input *DeleteBucketAnalyt // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketAnalyticsConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfiguration func (c *S3) DeleteBucketAnalyticsConfiguration(input *DeleteBucketAnalyticsConfigurationInput) (*DeleteBucketAnalyticsConfigurationOutput, error) { req, out := c.DeleteBucketAnalyticsConfigurationRequest(input) return out, req.Send() @@ -578,19 +571,18 @@ const opDeleteBucketCors = "DeleteBucketCors" // DeleteBucketCorsRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketCors operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketCors for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketCors method directly -// instead. +// See DeleteBucketCors for more information on using the DeleteBucketCors +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketCorsRequest method. // req, resp := client.DeleteBucketCorsRequest(params) @@ -600,7 +592,7 @@ const opDeleteBucketCors = "DeleteBucketCors" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCors +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCors func (c *S3) DeleteBucketCorsRequest(input *DeleteBucketCorsInput) (req *request.Request, output *DeleteBucketCorsOutput) { op := &request.Operation{ Name: opDeleteBucketCors, @@ -629,7 +621,7 @@ func (c *S3) DeleteBucketCorsRequest(input *DeleteBucketCorsInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketCors for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCors +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCors func (c *S3) DeleteBucketCors(input *DeleteBucketCorsInput) (*DeleteBucketCorsOutput, error) { req, out := c.DeleteBucketCorsRequest(input) return out, req.Send() @@ -651,23 +643,98 @@ func (c *S3) DeleteBucketCorsWithContext(ctx aws.Context, input *DeleteBucketCor return out, req.Send() } +const opDeleteBucketEncryption = "DeleteBucketEncryption" + +// DeleteBucketEncryptionRequest generates a "aws/request.Request" representing the +// client's request for the DeleteBucketEncryption operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See DeleteBucketEncryption for more information on using the DeleteBucketEncryption +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the DeleteBucketEncryptionRequest method. +// req, resp := client.DeleteBucketEncryptionRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketEncryption +func (c *S3) DeleteBucketEncryptionRequest(input *DeleteBucketEncryptionInput) (req *request.Request, output *DeleteBucketEncryptionOutput) { + op := &request.Operation{ + Name: opDeleteBucketEncryption, + HTTPMethod: "DELETE", + HTTPPath: "/{Bucket}?encryption", + } + + if input == nil { + input = &DeleteBucketEncryptionInput{} + } + + output = &DeleteBucketEncryptionOutput{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(restxml.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// DeleteBucketEncryption API operation for Amazon Simple Storage Service. +// +// Deletes the server-side encryption configuration from the bucket. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Simple Storage Service's +// API operation DeleteBucketEncryption for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketEncryption +func (c *S3) DeleteBucketEncryption(input *DeleteBucketEncryptionInput) (*DeleteBucketEncryptionOutput, error) { + req, out := c.DeleteBucketEncryptionRequest(input) + return out, req.Send() +} + +// DeleteBucketEncryptionWithContext is the same as DeleteBucketEncryption with the addition of +// the ability to pass a context and additional request options. +// +// See DeleteBucketEncryption for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *S3) DeleteBucketEncryptionWithContext(ctx aws.Context, input *DeleteBucketEncryptionInput, opts ...request.Option) (*DeleteBucketEncryptionOutput, error) { + req, out := c.DeleteBucketEncryptionRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opDeleteBucketInventoryConfiguration = "DeleteBucketInventoryConfiguration" // DeleteBucketInventoryConfigurationRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketInventoryConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketInventoryConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketInventoryConfiguration method directly -// instead. +// See DeleteBucketInventoryConfiguration for more information on using the DeleteBucketInventoryConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketInventoryConfigurationRequest method. // req, resp := client.DeleteBucketInventoryConfigurationRequest(params) @@ -677,7 +744,7 @@ const opDeleteBucketInventoryConfiguration = "DeleteBucketInventoryConfiguration // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfiguration func (c *S3) DeleteBucketInventoryConfigurationRequest(input *DeleteBucketInventoryConfigurationInput) (req *request.Request, output *DeleteBucketInventoryConfigurationOutput) { op := &request.Operation{ Name: opDeleteBucketInventoryConfiguration, @@ -707,7 +774,7 @@ func (c *S3) DeleteBucketInventoryConfigurationRequest(input *DeleteBucketInvent // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketInventoryConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfiguration func (c *S3) DeleteBucketInventoryConfiguration(input *DeleteBucketInventoryConfigurationInput) (*DeleteBucketInventoryConfigurationOutput, error) { req, out := c.DeleteBucketInventoryConfigurationRequest(input) return out, req.Send() @@ -733,19 +800,18 @@ const opDeleteBucketLifecycle = "DeleteBucketLifecycle" // DeleteBucketLifecycleRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketLifecycle operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketLifecycle for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketLifecycle method directly -// instead. +// See DeleteBucketLifecycle for more information on using the DeleteBucketLifecycle +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketLifecycleRequest method. // req, resp := client.DeleteBucketLifecycleRequest(params) @@ -755,7 +821,7 @@ const opDeleteBucketLifecycle = "DeleteBucketLifecycle" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycle +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycle func (c *S3) DeleteBucketLifecycleRequest(input *DeleteBucketLifecycleInput) (req *request.Request, output *DeleteBucketLifecycleOutput) { op := &request.Operation{ Name: opDeleteBucketLifecycle, @@ -784,7 +850,7 @@ func (c *S3) DeleteBucketLifecycleRequest(input *DeleteBucketLifecycleInput) (re // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketLifecycle for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycle +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycle func (c *S3) DeleteBucketLifecycle(input *DeleteBucketLifecycleInput) (*DeleteBucketLifecycleOutput, error) { req, out := c.DeleteBucketLifecycleRequest(input) return out, req.Send() @@ -810,19 +876,18 @@ const opDeleteBucketMetricsConfiguration = "DeleteBucketMetricsConfiguration" // DeleteBucketMetricsConfigurationRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketMetricsConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketMetricsConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketMetricsConfiguration method directly -// instead. +// See DeleteBucketMetricsConfiguration for more information on using the DeleteBucketMetricsConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketMetricsConfigurationRequest method. // req, resp := client.DeleteBucketMetricsConfigurationRequest(params) @@ -832,7 +897,7 @@ const opDeleteBucketMetricsConfiguration = "DeleteBucketMetricsConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfiguration func (c *S3) DeleteBucketMetricsConfigurationRequest(input *DeleteBucketMetricsConfigurationInput) (req *request.Request, output *DeleteBucketMetricsConfigurationOutput) { op := &request.Operation{ Name: opDeleteBucketMetricsConfiguration, @@ -862,7 +927,7 @@ func (c *S3) DeleteBucketMetricsConfigurationRequest(input *DeleteBucketMetricsC // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketMetricsConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfiguration func (c *S3) DeleteBucketMetricsConfiguration(input *DeleteBucketMetricsConfigurationInput) (*DeleteBucketMetricsConfigurationOutput, error) { req, out := c.DeleteBucketMetricsConfigurationRequest(input) return out, req.Send() @@ -888,19 +953,18 @@ const opDeleteBucketPolicy = "DeleteBucketPolicy" // DeleteBucketPolicyRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketPolicy operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketPolicy for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketPolicy method directly -// instead. +// See DeleteBucketPolicy for more information on using the DeleteBucketPolicy +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketPolicyRequest method. // req, resp := client.DeleteBucketPolicyRequest(params) @@ -910,7 +974,7 @@ const opDeleteBucketPolicy = "DeleteBucketPolicy" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicy func (c *S3) DeleteBucketPolicyRequest(input *DeleteBucketPolicyInput) (req *request.Request, output *DeleteBucketPolicyOutput) { op := &request.Operation{ Name: opDeleteBucketPolicy, @@ -939,7 +1003,7 @@ func (c *S3) DeleteBucketPolicyRequest(input *DeleteBucketPolicyInput) (req *req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketPolicy for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicy func (c *S3) DeleteBucketPolicy(input *DeleteBucketPolicyInput) (*DeleteBucketPolicyOutput, error) { req, out := c.DeleteBucketPolicyRequest(input) return out, req.Send() @@ -965,19 +1029,18 @@ const opDeleteBucketReplication = "DeleteBucketReplication" // DeleteBucketReplicationRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketReplication operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketReplication for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketReplication method directly -// instead. +// See DeleteBucketReplication for more information on using the DeleteBucketReplication +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketReplicationRequest method. // req, resp := client.DeleteBucketReplicationRequest(params) @@ -987,7 +1050,7 @@ const opDeleteBucketReplication = "DeleteBucketReplication" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplication +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplication func (c *S3) DeleteBucketReplicationRequest(input *DeleteBucketReplicationInput) (req *request.Request, output *DeleteBucketReplicationOutput) { op := &request.Operation{ Name: opDeleteBucketReplication, @@ -1016,7 +1079,7 @@ func (c *S3) DeleteBucketReplicationRequest(input *DeleteBucketReplicationInput) // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketReplication for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplication +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplication func (c *S3) DeleteBucketReplication(input *DeleteBucketReplicationInput) (*DeleteBucketReplicationOutput, error) { req, out := c.DeleteBucketReplicationRequest(input) return out, req.Send() @@ -1042,19 +1105,18 @@ const opDeleteBucketTagging = "DeleteBucketTagging" // DeleteBucketTaggingRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketTagging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketTagging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketTagging method directly -// instead. +// See DeleteBucketTagging for more information on using the DeleteBucketTagging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketTaggingRequest method. // req, resp := client.DeleteBucketTaggingRequest(params) @@ -1064,7 +1126,7 @@ const opDeleteBucketTagging = "DeleteBucketTagging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTagging func (c *S3) DeleteBucketTaggingRequest(input *DeleteBucketTaggingInput) (req *request.Request, output *DeleteBucketTaggingOutput) { op := &request.Operation{ Name: opDeleteBucketTagging, @@ -1093,7 +1155,7 @@ func (c *S3) DeleteBucketTaggingRequest(input *DeleteBucketTaggingInput) (req *r // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketTagging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTagging func (c *S3) DeleteBucketTagging(input *DeleteBucketTaggingInput) (*DeleteBucketTaggingOutput, error) { req, out := c.DeleteBucketTaggingRequest(input) return out, req.Send() @@ -1119,19 +1181,18 @@ const opDeleteBucketWebsite = "DeleteBucketWebsite" // DeleteBucketWebsiteRequest generates a "aws/request.Request" representing the // client's request for the DeleteBucketWebsite operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteBucketWebsite for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteBucketWebsite method directly -// instead. +// See DeleteBucketWebsite for more information on using the DeleteBucketWebsite +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteBucketWebsiteRequest method. // req, resp := client.DeleteBucketWebsiteRequest(params) @@ -1141,7 +1202,7 @@ const opDeleteBucketWebsite = "DeleteBucketWebsite" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsite +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsite func (c *S3) DeleteBucketWebsiteRequest(input *DeleteBucketWebsiteInput) (req *request.Request, output *DeleteBucketWebsiteOutput) { op := &request.Operation{ Name: opDeleteBucketWebsite, @@ -1170,7 +1231,7 @@ func (c *S3) DeleteBucketWebsiteRequest(input *DeleteBucketWebsiteInput) (req *r // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteBucketWebsite for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsite +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsite func (c *S3) DeleteBucketWebsite(input *DeleteBucketWebsiteInput) (*DeleteBucketWebsiteOutput, error) { req, out := c.DeleteBucketWebsiteRequest(input) return out, req.Send() @@ -1196,19 +1257,18 @@ const opDeleteObject = "DeleteObject" // DeleteObjectRequest generates a "aws/request.Request" representing the // client's request for the DeleteObject operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteObject for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteObject method directly -// instead. +// See DeleteObject for more information on using the DeleteObject +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteObjectRequest method. // req, resp := client.DeleteObjectRequest(params) @@ -1218,7 +1278,7 @@ const opDeleteObject = "DeleteObject" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject func (c *S3) DeleteObjectRequest(input *DeleteObjectInput) (req *request.Request, output *DeleteObjectOutput) { op := &request.Operation{ Name: opDeleteObject, @@ -1247,7 +1307,7 @@ func (c *S3) DeleteObjectRequest(input *DeleteObjectInput) (req *request.Request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteObject for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject func (c *S3) DeleteObject(input *DeleteObjectInput) (*DeleteObjectOutput, error) { req, out := c.DeleteObjectRequest(input) return out, req.Send() @@ -1273,19 +1333,18 @@ const opDeleteObjectTagging = "DeleteObjectTagging" // DeleteObjectTaggingRequest generates a "aws/request.Request" representing the // client's request for the DeleteObjectTagging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteObjectTagging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteObjectTagging method directly -// instead. +// See DeleteObjectTagging for more information on using the DeleteObjectTagging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteObjectTaggingRequest method. // req, resp := client.DeleteObjectTaggingRequest(params) @@ -1295,7 +1354,7 @@ const opDeleteObjectTagging = "DeleteObjectTagging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTagging func (c *S3) DeleteObjectTaggingRequest(input *DeleteObjectTaggingInput) (req *request.Request, output *DeleteObjectTaggingOutput) { op := &request.Operation{ Name: opDeleteObjectTagging, @@ -1322,7 +1381,7 @@ func (c *S3) DeleteObjectTaggingRequest(input *DeleteObjectTaggingInput) (req *r // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteObjectTagging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTagging func (c *S3) DeleteObjectTagging(input *DeleteObjectTaggingInput) (*DeleteObjectTaggingOutput, error) { req, out := c.DeleteObjectTaggingRequest(input) return out, req.Send() @@ -1348,19 +1407,18 @@ const opDeleteObjects = "DeleteObjects" // DeleteObjectsRequest generates a "aws/request.Request" representing the // client's request for the DeleteObjects operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DeleteObjects for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DeleteObjects method directly -// instead. +// See DeleteObjects for more information on using the DeleteObjects +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DeleteObjectsRequest method. // req, resp := client.DeleteObjectsRequest(params) @@ -1370,7 +1428,7 @@ const opDeleteObjects = "DeleteObjects" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjects +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjects func (c *S3) DeleteObjectsRequest(input *DeleteObjectsInput) (req *request.Request, output *DeleteObjectsOutput) { op := &request.Operation{ Name: opDeleteObjects, @@ -1398,7 +1456,7 @@ func (c *S3) DeleteObjectsRequest(input *DeleteObjectsInput) (req *request.Reque // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation DeleteObjects for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjects +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjects func (c *S3) DeleteObjects(input *DeleteObjectsInput) (*DeleteObjectsOutput, error) { req, out := c.DeleteObjectsRequest(input) return out, req.Send() @@ -1424,19 +1482,18 @@ const opGetBucketAccelerateConfiguration = "GetBucketAccelerateConfiguration" // GetBucketAccelerateConfigurationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketAccelerateConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketAccelerateConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketAccelerateConfiguration method directly -// instead. +// See GetBucketAccelerateConfiguration for more information on using the GetBucketAccelerateConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketAccelerateConfigurationRequest method. // req, resp := client.GetBucketAccelerateConfigurationRequest(params) @@ -1446,7 +1503,7 @@ const opGetBucketAccelerateConfiguration = "GetBucketAccelerateConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfiguration func (c *S3) GetBucketAccelerateConfigurationRequest(input *GetBucketAccelerateConfigurationInput) (req *request.Request, output *GetBucketAccelerateConfigurationOutput) { op := &request.Operation{ Name: opGetBucketAccelerateConfiguration, @@ -1473,7 +1530,7 @@ func (c *S3) GetBucketAccelerateConfigurationRequest(input *GetBucketAccelerateC // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketAccelerateConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfiguration func (c *S3) GetBucketAccelerateConfiguration(input *GetBucketAccelerateConfigurationInput) (*GetBucketAccelerateConfigurationOutput, error) { req, out := c.GetBucketAccelerateConfigurationRequest(input) return out, req.Send() @@ -1499,19 +1556,18 @@ const opGetBucketAcl = "GetBucketAcl" // GetBucketAclRequest generates a "aws/request.Request" representing the // client's request for the GetBucketAcl operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketAcl for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketAcl method directly -// instead. +// See GetBucketAcl for more information on using the GetBucketAcl +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketAclRequest method. // req, resp := client.GetBucketAclRequest(params) @@ -1521,7 +1577,7 @@ const opGetBucketAcl = "GetBucketAcl" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAcl func (c *S3) GetBucketAclRequest(input *GetBucketAclInput) (req *request.Request, output *GetBucketAclOutput) { op := &request.Operation{ Name: opGetBucketAcl, @@ -1548,7 +1604,7 @@ func (c *S3) GetBucketAclRequest(input *GetBucketAclInput) (req *request.Request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketAcl for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAcl func (c *S3) GetBucketAcl(input *GetBucketAclInput) (*GetBucketAclOutput, error) { req, out := c.GetBucketAclRequest(input) return out, req.Send() @@ -1574,19 +1630,18 @@ const opGetBucketAnalyticsConfiguration = "GetBucketAnalyticsConfiguration" // GetBucketAnalyticsConfigurationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketAnalyticsConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketAnalyticsConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketAnalyticsConfiguration method directly -// instead. +// See GetBucketAnalyticsConfiguration for more information on using the GetBucketAnalyticsConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketAnalyticsConfigurationRequest method. // req, resp := client.GetBucketAnalyticsConfigurationRequest(params) @@ -1596,7 +1651,7 @@ const opGetBucketAnalyticsConfiguration = "GetBucketAnalyticsConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfiguration func (c *S3) GetBucketAnalyticsConfigurationRequest(input *GetBucketAnalyticsConfigurationInput) (req *request.Request, output *GetBucketAnalyticsConfigurationOutput) { op := &request.Operation{ Name: opGetBucketAnalyticsConfiguration, @@ -1624,7 +1679,7 @@ func (c *S3) GetBucketAnalyticsConfigurationRequest(input *GetBucketAnalyticsCon // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketAnalyticsConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfiguration func (c *S3) GetBucketAnalyticsConfiguration(input *GetBucketAnalyticsConfigurationInput) (*GetBucketAnalyticsConfigurationOutput, error) { req, out := c.GetBucketAnalyticsConfigurationRequest(input) return out, req.Send() @@ -1650,19 +1705,18 @@ const opGetBucketCors = "GetBucketCors" // GetBucketCorsRequest generates a "aws/request.Request" representing the // client's request for the GetBucketCors operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketCors for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketCors method directly -// instead. +// See GetBucketCors for more information on using the GetBucketCors +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketCorsRequest method. // req, resp := client.GetBucketCorsRequest(params) @@ -1672,7 +1726,7 @@ const opGetBucketCors = "GetBucketCors" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCors +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCors func (c *S3) GetBucketCorsRequest(input *GetBucketCorsInput) (req *request.Request, output *GetBucketCorsOutput) { op := &request.Operation{ Name: opGetBucketCors, @@ -1699,7 +1753,7 @@ func (c *S3) GetBucketCorsRequest(input *GetBucketCorsInput) (req *request.Reque // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketCors for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCors +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCors func (c *S3) GetBucketCors(input *GetBucketCorsInput) (*GetBucketCorsOutput, error) { req, out := c.GetBucketCorsRequest(input) return out, req.Send() @@ -1721,23 +1775,96 @@ func (c *S3) GetBucketCorsWithContext(ctx aws.Context, input *GetBucketCorsInput return out, req.Send() } +const opGetBucketEncryption = "GetBucketEncryption" + +// GetBucketEncryptionRequest generates a "aws/request.Request" representing the +// client's request for the GetBucketEncryption operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See GetBucketEncryption for more information on using the GetBucketEncryption +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the GetBucketEncryptionRequest method. +// req, resp := client.GetBucketEncryptionRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketEncryption +func (c *S3) GetBucketEncryptionRequest(input *GetBucketEncryptionInput) (req *request.Request, output *GetBucketEncryptionOutput) { + op := &request.Operation{ + Name: opGetBucketEncryption, + HTTPMethod: "GET", + HTTPPath: "/{Bucket}?encryption", + } + + if input == nil { + input = &GetBucketEncryptionInput{} + } + + output = &GetBucketEncryptionOutput{} + req = c.newRequest(op, input, output) + return +} + +// GetBucketEncryption API operation for Amazon Simple Storage Service. +// +// Returns the server-side encryption configuration of a bucket. +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Simple Storage Service's +// API operation GetBucketEncryption for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketEncryption +func (c *S3) GetBucketEncryption(input *GetBucketEncryptionInput) (*GetBucketEncryptionOutput, error) { + req, out := c.GetBucketEncryptionRequest(input) + return out, req.Send() +} + +// GetBucketEncryptionWithContext is the same as GetBucketEncryption with the addition of +// the ability to pass a context and additional request options. +// +// See GetBucketEncryption for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *S3) GetBucketEncryptionWithContext(ctx aws.Context, input *GetBucketEncryptionInput, opts ...request.Option) (*GetBucketEncryptionOutput, error) { + req, out := c.GetBucketEncryptionRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opGetBucketInventoryConfiguration = "GetBucketInventoryConfiguration" // GetBucketInventoryConfigurationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketInventoryConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketInventoryConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketInventoryConfiguration method directly -// instead. +// See GetBucketInventoryConfiguration for more information on using the GetBucketInventoryConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketInventoryConfigurationRequest method. // req, resp := client.GetBucketInventoryConfigurationRequest(params) @@ -1747,7 +1874,7 @@ const opGetBucketInventoryConfiguration = "GetBucketInventoryConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfiguration func (c *S3) GetBucketInventoryConfigurationRequest(input *GetBucketInventoryConfigurationInput) (req *request.Request, output *GetBucketInventoryConfigurationOutput) { op := &request.Operation{ Name: opGetBucketInventoryConfiguration, @@ -1775,7 +1902,7 @@ func (c *S3) GetBucketInventoryConfigurationRequest(input *GetBucketInventoryCon // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketInventoryConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfiguration func (c *S3) GetBucketInventoryConfiguration(input *GetBucketInventoryConfigurationInput) (*GetBucketInventoryConfigurationOutput, error) { req, out := c.GetBucketInventoryConfigurationRequest(input) return out, req.Send() @@ -1801,19 +1928,18 @@ const opGetBucketLifecycle = "GetBucketLifecycle" // GetBucketLifecycleRequest generates a "aws/request.Request" representing the // client's request for the GetBucketLifecycle operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketLifecycle for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketLifecycle method directly -// instead. +// See GetBucketLifecycle for more information on using the GetBucketLifecycle +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketLifecycleRequest method. // req, resp := client.GetBucketLifecycleRequest(params) @@ -1823,7 +1949,7 @@ const opGetBucketLifecycle = "GetBucketLifecycle" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycle +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycle func (c *S3) GetBucketLifecycleRequest(input *GetBucketLifecycleInput) (req *request.Request, output *GetBucketLifecycleOutput) { if c.Client.Config.Logger != nil { c.Client.Config.Logger.Log("This operation, GetBucketLifecycle, has been deprecated") @@ -1853,7 +1979,7 @@ func (c *S3) GetBucketLifecycleRequest(input *GetBucketLifecycleInput) (req *req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketLifecycle for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycle +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycle func (c *S3) GetBucketLifecycle(input *GetBucketLifecycleInput) (*GetBucketLifecycleOutput, error) { req, out := c.GetBucketLifecycleRequest(input) return out, req.Send() @@ -1879,19 +2005,18 @@ const opGetBucketLifecycleConfiguration = "GetBucketLifecycleConfiguration" // GetBucketLifecycleConfigurationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketLifecycleConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketLifecycleConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketLifecycleConfiguration method directly -// instead. +// See GetBucketLifecycleConfiguration for more information on using the GetBucketLifecycleConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketLifecycleConfigurationRequest method. // req, resp := client.GetBucketLifecycleConfigurationRequest(params) @@ -1901,7 +2026,7 @@ const opGetBucketLifecycleConfiguration = "GetBucketLifecycleConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfiguration func (c *S3) GetBucketLifecycleConfigurationRequest(input *GetBucketLifecycleConfigurationInput) (req *request.Request, output *GetBucketLifecycleConfigurationOutput) { op := &request.Operation{ Name: opGetBucketLifecycleConfiguration, @@ -1928,7 +2053,7 @@ func (c *S3) GetBucketLifecycleConfigurationRequest(input *GetBucketLifecycleCon // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketLifecycleConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfiguration func (c *S3) GetBucketLifecycleConfiguration(input *GetBucketLifecycleConfigurationInput) (*GetBucketLifecycleConfigurationOutput, error) { req, out := c.GetBucketLifecycleConfigurationRequest(input) return out, req.Send() @@ -1954,19 +2079,18 @@ const opGetBucketLocation = "GetBucketLocation" // GetBucketLocationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketLocation operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketLocation for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketLocation method directly -// instead. +// See GetBucketLocation for more information on using the GetBucketLocation +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketLocationRequest method. // req, resp := client.GetBucketLocationRequest(params) @@ -1976,7 +2100,7 @@ const opGetBucketLocation = "GetBucketLocation" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocation +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocation func (c *S3) GetBucketLocationRequest(input *GetBucketLocationInput) (req *request.Request, output *GetBucketLocationOutput) { op := &request.Operation{ Name: opGetBucketLocation, @@ -2003,7 +2127,7 @@ func (c *S3) GetBucketLocationRequest(input *GetBucketLocationInput) (req *reque // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketLocation for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocation +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocation func (c *S3) GetBucketLocation(input *GetBucketLocationInput) (*GetBucketLocationOutput, error) { req, out := c.GetBucketLocationRequest(input) return out, req.Send() @@ -2029,19 +2153,18 @@ const opGetBucketLogging = "GetBucketLogging" // GetBucketLoggingRequest generates a "aws/request.Request" representing the // client's request for the GetBucketLogging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketLogging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketLogging method directly -// instead. +// See GetBucketLogging for more information on using the GetBucketLogging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketLoggingRequest method. // req, resp := client.GetBucketLoggingRequest(params) @@ -2051,7 +2174,7 @@ const opGetBucketLogging = "GetBucketLogging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLogging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLogging func (c *S3) GetBucketLoggingRequest(input *GetBucketLoggingInput) (req *request.Request, output *GetBucketLoggingOutput) { op := &request.Operation{ Name: opGetBucketLogging, @@ -2079,7 +2202,7 @@ func (c *S3) GetBucketLoggingRequest(input *GetBucketLoggingInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketLogging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLogging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLogging func (c *S3) GetBucketLogging(input *GetBucketLoggingInput) (*GetBucketLoggingOutput, error) { req, out := c.GetBucketLoggingRequest(input) return out, req.Send() @@ -2105,19 +2228,18 @@ const opGetBucketMetricsConfiguration = "GetBucketMetricsConfiguration" // GetBucketMetricsConfigurationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketMetricsConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketMetricsConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketMetricsConfiguration method directly -// instead. +// See GetBucketMetricsConfiguration for more information on using the GetBucketMetricsConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketMetricsConfigurationRequest method. // req, resp := client.GetBucketMetricsConfigurationRequest(params) @@ -2127,7 +2249,7 @@ const opGetBucketMetricsConfiguration = "GetBucketMetricsConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfiguration func (c *S3) GetBucketMetricsConfigurationRequest(input *GetBucketMetricsConfigurationInput) (req *request.Request, output *GetBucketMetricsConfigurationOutput) { op := &request.Operation{ Name: opGetBucketMetricsConfiguration, @@ -2155,7 +2277,7 @@ func (c *S3) GetBucketMetricsConfigurationRequest(input *GetBucketMetricsConfigu // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketMetricsConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfiguration func (c *S3) GetBucketMetricsConfiguration(input *GetBucketMetricsConfigurationInput) (*GetBucketMetricsConfigurationOutput, error) { req, out := c.GetBucketMetricsConfigurationRequest(input) return out, req.Send() @@ -2181,19 +2303,18 @@ const opGetBucketNotification = "GetBucketNotification" // GetBucketNotificationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketNotification operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketNotification for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketNotification method directly -// instead. +// See GetBucketNotification for more information on using the GetBucketNotification +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketNotificationRequest method. // req, resp := client.GetBucketNotificationRequest(params) @@ -2203,7 +2324,7 @@ const opGetBucketNotification = "GetBucketNotification" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotification +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotification func (c *S3) GetBucketNotificationRequest(input *GetBucketNotificationConfigurationRequest) (req *request.Request, output *NotificationConfigurationDeprecated) { if c.Client.Config.Logger != nil { c.Client.Config.Logger.Log("This operation, GetBucketNotification, has been deprecated") @@ -2233,7 +2354,7 @@ func (c *S3) GetBucketNotificationRequest(input *GetBucketNotificationConfigurat // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketNotification for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotification +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotification func (c *S3) GetBucketNotification(input *GetBucketNotificationConfigurationRequest) (*NotificationConfigurationDeprecated, error) { req, out := c.GetBucketNotificationRequest(input) return out, req.Send() @@ -2259,19 +2380,18 @@ const opGetBucketNotificationConfiguration = "GetBucketNotificationConfiguration // GetBucketNotificationConfigurationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketNotificationConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketNotificationConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketNotificationConfiguration method directly -// instead. +// See GetBucketNotificationConfiguration for more information on using the GetBucketNotificationConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketNotificationConfigurationRequest method. // req, resp := client.GetBucketNotificationConfigurationRequest(params) @@ -2281,7 +2401,7 @@ const opGetBucketNotificationConfiguration = "GetBucketNotificationConfiguration // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfiguration func (c *S3) GetBucketNotificationConfigurationRequest(input *GetBucketNotificationConfigurationRequest) (req *request.Request, output *NotificationConfiguration) { op := &request.Operation{ Name: opGetBucketNotificationConfiguration, @@ -2308,7 +2428,7 @@ func (c *S3) GetBucketNotificationConfigurationRequest(input *GetBucketNotificat // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketNotificationConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfiguration func (c *S3) GetBucketNotificationConfiguration(input *GetBucketNotificationConfigurationRequest) (*NotificationConfiguration, error) { req, out := c.GetBucketNotificationConfigurationRequest(input) return out, req.Send() @@ -2334,19 +2454,18 @@ const opGetBucketPolicy = "GetBucketPolicy" // GetBucketPolicyRequest generates a "aws/request.Request" representing the // client's request for the GetBucketPolicy operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketPolicy for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketPolicy method directly -// instead. +// See GetBucketPolicy for more information on using the GetBucketPolicy +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketPolicyRequest method. // req, resp := client.GetBucketPolicyRequest(params) @@ -2356,7 +2475,7 @@ const opGetBucketPolicy = "GetBucketPolicy" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicy func (c *S3) GetBucketPolicyRequest(input *GetBucketPolicyInput) (req *request.Request, output *GetBucketPolicyOutput) { op := &request.Operation{ Name: opGetBucketPolicy, @@ -2383,7 +2502,7 @@ func (c *S3) GetBucketPolicyRequest(input *GetBucketPolicyInput) (req *request.R // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketPolicy for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicy func (c *S3) GetBucketPolicy(input *GetBucketPolicyInput) (*GetBucketPolicyOutput, error) { req, out := c.GetBucketPolicyRequest(input) return out, req.Send() @@ -2409,19 +2528,18 @@ const opGetBucketReplication = "GetBucketReplication" // GetBucketReplicationRequest generates a "aws/request.Request" representing the // client's request for the GetBucketReplication operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketReplication for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketReplication method directly -// instead. +// See GetBucketReplication for more information on using the GetBucketReplication +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketReplicationRequest method. // req, resp := client.GetBucketReplicationRequest(params) @@ -2431,7 +2549,7 @@ const opGetBucketReplication = "GetBucketReplication" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplication +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplication func (c *S3) GetBucketReplicationRequest(input *GetBucketReplicationInput) (req *request.Request, output *GetBucketReplicationOutput) { op := &request.Operation{ Name: opGetBucketReplication, @@ -2458,7 +2576,7 @@ func (c *S3) GetBucketReplicationRequest(input *GetBucketReplicationInput) (req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketReplication for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplication +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplication func (c *S3) GetBucketReplication(input *GetBucketReplicationInput) (*GetBucketReplicationOutput, error) { req, out := c.GetBucketReplicationRequest(input) return out, req.Send() @@ -2484,19 +2602,18 @@ const opGetBucketRequestPayment = "GetBucketRequestPayment" // GetBucketRequestPaymentRequest generates a "aws/request.Request" representing the // client's request for the GetBucketRequestPayment operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketRequestPayment for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketRequestPayment method directly -// instead. +// See GetBucketRequestPayment for more information on using the GetBucketRequestPayment +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketRequestPaymentRequest method. // req, resp := client.GetBucketRequestPaymentRequest(params) @@ -2506,7 +2623,7 @@ const opGetBucketRequestPayment = "GetBucketRequestPayment" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPayment +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPayment func (c *S3) GetBucketRequestPaymentRequest(input *GetBucketRequestPaymentInput) (req *request.Request, output *GetBucketRequestPaymentOutput) { op := &request.Operation{ Name: opGetBucketRequestPayment, @@ -2533,7 +2650,7 @@ func (c *S3) GetBucketRequestPaymentRequest(input *GetBucketRequestPaymentInput) // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketRequestPayment for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPayment +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPayment func (c *S3) GetBucketRequestPayment(input *GetBucketRequestPaymentInput) (*GetBucketRequestPaymentOutput, error) { req, out := c.GetBucketRequestPaymentRequest(input) return out, req.Send() @@ -2559,19 +2676,18 @@ const opGetBucketTagging = "GetBucketTagging" // GetBucketTaggingRequest generates a "aws/request.Request" representing the // client's request for the GetBucketTagging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketTagging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketTagging method directly -// instead. +// See GetBucketTagging for more information on using the GetBucketTagging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketTaggingRequest method. // req, resp := client.GetBucketTaggingRequest(params) @@ -2581,7 +2697,7 @@ const opGetBucketTagging = "GetBucketTagging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTagging func (c *S3) GetBucketTaggingRequest(input *GetBucketTaggingInput) (req *request.Request, output *GetBucketTaggingOutput) { op := &request.Operation{ Name: opGetBucketTagging, @@ -2608,7 +2724,7 @@ func (c *S3) GetBucketTaggingRequest(input *GetBucketTaggingInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketTagging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTagging func (c *S3) GetBucketTagging(input *GetBucketTaggingInput) (*GetBucketTaggingOutput, error) { req, out := c.GetBucketTaggingRequest(input) return out, req.Send() @@ -2634,19 +2750,18 @@ const opGetBucketVersioning = "GetBucketVersioning" // GetBucketVersioningRequest generates a "aws/request.Request" representing the // client's request for the GetBucketVersioning operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketVersioning for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketVersioning method directly -// instead. +// See GetBucketVersioning for more information on using the GetBucketVersioning +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketVersioningRequest method. // req, resp := client.GetBucketVersioningRequest(params) @@ -2656,7 +2771,7 @@ const opGetBucketVersioning = "GetBucketVersioning" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioning +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioning func (c *S3) GetBucketVersioningRequest(input *GetBucketVersioningInput) (req *request.Request, output *GetBucketVersioningOutput) { op := &request.Operation{ Name: opGetBucketVersioning, @@ -2683,7 +2798,7 @@ func (c *S3) GetBucketVersioningRequest(input *GetBucketVersioningInput) (req *r // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketVersioning for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioning +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioning func (c *S3) GetBucketVersioning(input *GetBucketVersioningInput) (*GetBucketVersioningOutput, error) { req, out := c.GetBucketVersioningRequest(input) return out, req.Send() @@ -2709,19 +2824,18 @@ const opGetBucketWebsite = "GetBucketWebsite" // GetBucketWebsiteRequest generates a "aws/request.Request" representing the // client's request for the GetBucketWebsite operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetBucketWebsite for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetBucketWebsite method directly -// instead. +// See GetBucketWebsite for more information on using the GetBucketWebsite +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetBucketWebsiteRequest method. // req, resp := client.GetBucketWebsiteRequest(params) @@ -2731,7 +2845,7 @@ const opGetBucketWebsite = "GetBucketWebsite" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsite +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsite func (c *S3) GetBucketWebsiteRequest(input *GetBucketWebsiteInput) (req *request.Request, output *GetBucketWebsiteOutput) { op := &request.Operation{ Name: opGetBucketWebsite, @@ -2758,7 +2872,7 @@ func (c *S3) GetBucketWebsiteRequest(input *GetBucketWebsiteInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetBucketWebsite for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsite +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsite func (c *S3) GetBucketWebsite(input *GetBucketWebsiteInput) (*GetBucketWebsiteOutput, error) { req, out := c.GetBucketWebsiteRequest(input) return out, req.Send() @@ -2784,19 +2898,18 @@ const opGetObject = "GetObject" // GetObjectRequest generates a "aws/request.Request" representing the // client's request for the GetObject operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetObject for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetObject method directly -// instead. +// See GetObject for more information on using the GetObject +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetObjectRequest method. // req, resp := client.GetObjectRequest(params) @@ -2806,7 +2919,7 @@ const opGetObject = "GetObject" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject func (c *S3) GetObjectRequest(input *GetObjectInput) (req *request.Request, output *GetObjectOutput) { op := &request.Operation{ Name: opGetObject, @@ -2838,7 +2951,7 @@ func (c *S3) GetObjectRequest(input *GetObjectInput) (req *request.Request, outp // * ErrCodeNoSuchKey "NoSuchKey" // The specified key does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject func (c *S3) GetObject(input *GetObjectInput) (*GetObjectOutput, error) { req, out := c.GetObjectRequest(input) return out, req.Send() @@ -2864,19 +2977,18 @@ const opGetObjectAcl = "GetObjectAcl" // GetObjectAclRequest generates a "aws/request.Request" representing the // client's request for the GetObjectAcl operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetObjectAcl for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetObjectAcl method directly -// instead. +// See GetObjectAcl for more information on using the GetObjectAcl +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetObjectAclRequest method. // req, resp := client.GetObjectAclRequest(params) @@ -2886,7 +2998,7 @@ const opGetObjectAcl = "GetObjectAcl" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAcl func (c *S3) GetObjectAclRequest(input *GetObjectAclInput) (req *request.Request, output *GetObjectAclOutput) { op := &request.Operation{ Name: opGetObjectAcl, @@ -2918,7 +3030,7 @@ func (c *S3) GetObjectAclRequest(input *GetObjectAclInput) (req *request.Request // * ErrCodeNoSuchKey "NoSuchKey" // The specified key does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAcl func (c *S3) GetObjectAcl(input *GetObjectAclInput) (*GetObjectAclOutput, error) { req, out := c.GetObjectAclRequest(input) return out, req.Send() @@ -2944,19 +3056,18 @@ const opGetObjectTagging = "GetObjectTagging" // GetObjectTaggingRequest generates a "aws/request.Request" representing the // client's request for the GetObjectTagging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetObjectTagging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetObjectTagging method directly -// instead. +// See GetObjectTagging for more information on using the GetObjectTagging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetObjectTaggingRequest method. // req, resp := client.GetObjectTaggingRequest(params) @@ -2966,7 +3077,7 @@ const opGetObjectTagging = "GetObjectTagging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTagging func (c *S3) GetObjectTaggingRequest(input *GetObjectTaggingInput) (req *request.Request, output *GetObjectTaggingOutput) { op := &request.Operation{ Name: opGetObjectTagging, @@ -2993,7 +3104,7 @@ func (c *S3) GetObjectTaggingRequest(input *GetObjectTaggingInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetObjectTagging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTagging func (c *S3) GetObjectTagging(input *GetObjectTaggingInput) (*GetObjectTaggingOutput, error) { req, out := c.GetObjectTaggingRequest(input) return out, req.Send() @@ -3019,19 +3130,18 @@ const opGetObjectTorrent = "GetObjectTorrent" // GetObjectTorrentRequest generates a "aws/request.Request" representing the // client's request for the GetObjectTorrent operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetObjectTorrent for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetObjectTorrent method directly -// instead. +// See GetObjectTorrent for more information on using the GetObjectTorrent +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetObjectTorrentRequest method. // req, resp := client.GetObjectTorrentRequest(params) @@ -3041,7 +3151,7 @@ const opGetObjectTorrent = "GetObjectTorrent" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrent +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrent func (c *S3) GetObjectTorrentRequest(input *GetObjectTorrentInput) (req *request.Request, output *GetObjectTorrentOutput) { op := &request.Operation{ Name: opGetObjectTorrent, @@ -3068,7 +3178,7 @@ func (c *S3) GetObjectTorrentRequest(input *GetObjectTorrentInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation GetObjectTorrent for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrent +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrent func (c *S3) GetObjectTorrent(input *GetObjectTorrentInput) (*GetObjectTorrentOutput, error) { req, out := c.GetObjectTorrentRequest(input) return out, req.Send() @@ -3094,19 +3204,18 @@ const opHeadBucket = "HeadBucket" // HeadBucketRequest generates a "aws/request.Request" representing the // client's request for the HeadBucket operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See HeadBucket for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the HeadBucket method directly -// instead. +// See HeadBucket for more information on using the HeadBucket +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the HeadBucketRequest method. // req, resp := client.HeadBucketRequest(params) @@ -3116,7 +3225,7 @@ const opHeadBucket = "HeadBucket" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucket func (c *S3) HeadBucketRequest(input *HeadBucketInput) (req *request.Request, output *HeadBucketOutput) { op := &request.Operation{ Name: opHeadBucket, @@ -3151,7 +3260,7 @@ func (c *S3) HeadBucketRequest(input *HeadBucketInput) (req *request.Request, ou // * ErrCodeNoSuchBucket "NoSuchBucket" // The specified bucket does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucket func (c *S3) HeadBucket(input *HeadBucketInput) (*HeadBucketOutput, error) { req, out := c.HeadBucketRequest(input) return out, req.Send() @@ -3177,19 +3286,18 @@ const opHeadObject = "HeadObject" // HeadObjectRequest generates a "aws/request.Request" representing the // client's request for the HeadObject operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See HeadObject for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the HeadObject method directly -// instead. +// See HeadObject for more information on using the HeadObject +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the HeadObjectRequest method. // req, resp := client.HeadObjectRequest(params) @@ -3199,7 +3307,7 @@ const opHeadObject = "HeadObject" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObject func (c *S3) HeadObjectRequest(input *HeadObjectInput) (req *request.Request, output *HeadObjectOutput) { op := &request.Operation{ Name: opHeadObject, @@ -3231,7 +3339,7 @@ func (c *S3) HeadObjectRequest(input *HeadObjectInput) (req *request.Request, ou // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation HeadObject for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObject func (c *S3) HeadObject(input *HeadObjectInput) (*HeadObjectOutput, error) { req, out := c.HeadObjectRequest(input) return out, req.Send() @@ -3257,19 +3365,18 @@ const opListBucketAnalyticsConfigurations = "ListBucketAnalyticsConfigurations" // ListBucketAnalyticsConfigurationsRequest generates a "aws/request.Request" representing the // client's request for the ListBucketAnalyticsConfigurations operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListBucketAnalyticsConfigurations for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListBucketAnalyticsConfigurations method directly -// instead. +// See ListBucketAnalyticsConfigurations for more information on using the ListBucketAnalyticsConfigurations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListBucketAnalyticsConfigurationsRequest method. // req, resp := client.ListBucketAnalyticsConfigurationsRequest(params) @@ -3279,7 +3386,7 @@ const opListBucketAnalyticsConfigurations = "ListBucketAnalyticsConfigurations" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurations +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurations func (c *S3) ListBucketAnalyticsConfigurationsRequest(input *ListBucketAnalyticsConfigurationsInput) (req *request.Request, output *ListBucketAnalyticsConfigurationsOutput) { op := &request.Operation{ Name: opListBucketAnalyticsConfigurations, @@ -3306,7 +3413,7 @@ func (c *S3) ListBucketAnalyticsConfigurationsRequest(input *ListBucketAnalytics // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListBucketAnalyticsConfigurations for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurations +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurations func (c *S3) ListBucketAnalyticsConfigurations(input *ListBucketAnalyticsConfigurationsInput) (*ListBucketAnalyticsConfigurationsOutput, error) { req, out := c.ListBucketAnalyticsConfigurationsRequest(input) return out, req.Send() @@ -3332,19 +3439,18 @@ const opListBucketInventoryConfigurations = "ListBucketInventoryConfigurations" // ListBucketInventoryConfigurationsRequest generates a "aws/request.Request" representing the // client's request for the ListBucketInventoryConfigurations operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListBucketInventoryConfigurations for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListBucketInventoryConfigurations method directly -// instead. +// See ListBucketInventoryConfigurations for more information on using the ListBucketInventoryConfigurations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListBucketInventoryConfigurationsRequest method. // req, resp := client.ListBucketInventoryConfigurationsRequest(params) @@ -3354,7 +3460,7 @@ const opListBucketInventoryConfigurations = "ListBucketInventoryConfigurations" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurations +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurations func (c *S3) ListBucketInventoryConfigurationsRequest(input *ListBucketInventoryConfigurationsInput) (req *request.Request, output *ListBucketInventoryConfigurationsOutput) { op := &request.Operation{ Name: opListBucketInventoryConfigurations, @@ -3381,7 +3487,7 @@ func (c *S3) ListBucketInventoryConfigurationsRequest(input *ListBucketInventory // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListBucketInventoryConfigurations for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurations +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurations func (c *S3) ListBucketInventoryConfigurations(input *ListBucketInventoryConfigurationsInput) (*ListBucketInventoryConfigurationsOutput, error) { req, out := c.ListBucketInventoryConfigurationsRequest(input) return out, req.Send() @@ -3407,19 +3513,18 @@ const opListBucketMetricsConfigurations = "ListBucketMetricsConfigurations" // ListBucketMetricsConfigurationsRequest generates a "aws/request.Request" representing the // client's request for the ListBucketMetricsConfigurations operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListBucketMetricsConfigurations for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListBucketMetricsConfigurations method directly -// instead. +// See ListBucketMetricsConfigurations for more information on using the ListBucketMetricsConfigurations +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListBucketMetricsConfigurationsRequest method. // req, resp := client.ListBucketMetricsConfigurationsRequest(params) @@ -3429,7 +3534,7 @@ const opListBucketMetricsConfigurations = "ListBucketMetricsConfigurations" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurations +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurations func (c *S3) ListBucketMetricsConfigurationsRequest(input *ListBucketMetricsConfigurationsInput) (req *request.Request, output *ListBucketMetricsConfigurationsOutput) { op := &request.Operation{ Name: opListBucketMetricsConfigurations, @@ -3456,7 +3561,7 @@ func (c *S3) ListBucketMetricsConfigurationsRequest(input *ListBucketMetricsConf // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListBucketMetricsConfigurations for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurations +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurations func (c *S3) ListBucketMetricsConfigurations(input *ListBucketMetricsConfigurationsInput) (*ListBucketMetricsConfigurationsOutput, error) { req, out := c.ListBucketMetricsConfigurationsRequest(input) return out, req.Send() @@ -3482,19 +3587,18 @@ const opListBuckets = "ListBuckets" // ListBucketsRequest generates a "aws/request.Request" representing the // client's request for the ListBuckets operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListBuckets for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListBuckets method directly -// instead. +// See ListBuckets for more information on using the ListBuckets +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListBucketsRequest method. // req, resp := client.ListBucketsRequest(params) @@ -3504,7 +3608,7 @@ const opListBuckets = "ListBuckets" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets func (c *S3) ListBucketsRequest(input *ListBucketsInput) (req *request.Request, output *ListBucketsOutput) { op := &request.Operation{ Name: opListBuckets, @@ -3531,7 +3635,7 @@ func (c *S3) ListBucketsRequest(input *ListBucketsInput) (req *request.Request, // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListBuckets for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets func (c *S3) ListBuckets(input *ListBucketsInput) (*ListBucketsOutput, error) { req, out := c.ListBucketsRequest(input) return out, req.Send() @@ -3557,19 +3661,18 @@ const opListMultipartUploads = "ListMultipartUploads" // ListMultipartUploadsRequest generates a "aws/request.Request" representing the // client's request for the ListMultipartUploads operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListMultipartUploads for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListMultipartUploads method directly -// instead. +// See ListMultipartUploads for more information on using the ListMultipartUploads +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListMultipartUploadsRequest method. // req, resp := client.ListMultipartUploadsRequest(params) @@ -3579,7 +3682,7 @@ const opListMultipartUploads = "ListMultipartUploads" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploads +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploads func (c *S3) ListMultipartUploadsRequest(input *ListMultipartUploadsInput) (req *request.Request, output *ListMultipartUploadsOutput) { op := &request.Operation{ Name: opListMultipartUploads, @@ -3612,7 +3715,7 @@ func (c *S3) ListMultipartUploadsRequest(input *ListMultipartUploadsInput) (req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListMultipartUploads for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploads +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploads func (c *S3) ListMultipartUploads(input *ListMultipartUploadsInput) (*ListMultipartUploadsOutput, error) { req, out := c.ListMultipartUploadsRequest(input) return out, req.Send() @@ -3688,19 +3791,18 @@ const opListObjectVersions = "ListObjectVersions" // ListObjectVersionsRequest generates a "aws/request.Request" representing the // client's request for the ListObjectVersions operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListObjectVersions for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListObjectVersions method directly -// instead. +// See ListObjectVersions for more information on using the ListObjectVersions +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListObjectVersionsRequest method. // req, resp := client.ListObjectVersionsRequest(params) @@ -3710,7 +3812,7 @@ const opListObjectVersions = "ListObjectVersions" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersions +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersions func (c *S3) ListObjectVersionsRequest(input *ListObjectVersionsInput) (req *request.Request, output *ListObjectVersionsOutput) { op := &request.Operation{ Name: opListObjectVersions, @@ -3743,7 +3845,7 @@ func (c *S3) ListObjectVersionsRequest(input *ListObjectVersionsInput) (req *req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListObjectVersions for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersions +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersions func (c *S3) ListObjectVersions(input *ListObjectVersionsInput) (*ListObjectVersionsOutput, error) { req, out := c.ListObjectVersionsRequest(input) return out, req.Send() @@ -3819,19 +3921,18 @@ const opListObjects = "ListObjects" // ListObjectsRequest generates a "aws/request.Request" representing the // client's request for the ListObjects operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListObjects for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListObjects method directly -// instead. +// See ListObjects for more information on using the ListObjects +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListObjectsRequest method. // req, resp := client.ListObjectsRequest(params) @@ -3841,7 +3942,7 @@ const opListObjects = "ListObjects" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects func (c *S3) ListObjectsRequest(input *ListObjectsInput) (req *request.Request, output *ListObjectsOutput) { op := &request.Operation{ Name: opListObjects, @@ -3881,7 +3982,7 @@ func (c *S3) ListObjectsRequest(input *ListObjectsInput) (req *request.Request, // * ErrCodeNoSuchBucket "NoSuchBucket" // The specified bucket does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects func (c *S3) ListObjects(input *ListObjectsInput) (*ListObjectsOutput, error) { req, out := c.ListObjectsRequest(input) return out, req.Send() @@ -3957,19 +4058,18 @@ const opListObjectsV2 = "ListObjectsV2" // ListObjectsV2Request generates a "aws/request.Request" representing the // client's request for the ListObjectsV2 operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListObjectsV2 for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListObjectsV2 method directly -// instead. +// See ListObjectsV2 for more information on using the ListObjectsV2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListObjectsV2Request method. // req, resp := client.ListObjectsV2Request(params) @@ -3979,7 +4079,7 @@ const opListObjectsV2 = "ListObjectsV2" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2 +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2 func (c *S3) ListObjectsV2Request(input *ListObjectsV2Input) (req *request.Request, output *ListObjectsV2Output) { op := &request.Operation{ Name: opListObjectsV2, @@ -4020,7 +4120,7 @@ func (c *S3) ListObjectsV2Request(input *ListObjectsV2Input) (req *request.Reque // * ErrCodeNoSuchBucket "NoSuchBucket" // The specified bucket does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2 +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2 func (c *S3) ListObjectsV2(input *ListObjectsV2Input) (*ListObjectsV2Output, error) { req, out := c.ListObjectsV2Request(input) return out, req.Send() @@ -4096,19 +4196,18 @@ const opListParts = "ListParts" // ListPartsRequest generates a "aws/request.Request" representing the // client's request for the ListParts operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See ListParts for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the ListParts method directly -// instead. +// See ListParts for more information on using the ListParts +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the ListPartsRequest method. // req, resp := client.ListPartsRequest(params) @@ -4118,7 +4217,7 @@ const opListParts = "ListParts" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListParts +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListParts func (c *S3) ListPartsRequest(input *ListPartsInput) (req *request.Request, output *ListPartsOutput) { op := &request.Operation{ Name: opListParts, @@ -4151,7 +4250,7 @@ func (c *S3) ListPartsRequest(input *ListPartsInput) (req *request.Request, outp // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation ListParts for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListParts +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListParts func (c *S3) ListParts(input *ListPartsInput) (*ListPartsOutput, error) { req, out := c.ListPartsRequest(input) return out, req.Send() @@ -4227,19 +4326,18 @@ const opPutBucketAccelerateConfiguration = "PutBucketAccelerateConfiguration" // PutBucketAccelerateConfigurationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketAccelerateConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketAccelerateConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketAccelerateConfiguration method directly -// instead. +// See PutBucketAccelerateConfiguration for more information on using the PutBucketAccelerateConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketAccelerateConfigurationRequest method. // req, resp := client.PutBucketAccelerateConfigurationRequest(params) @@ -4249,7 +4347,7 @@ const opPutBucketAccelerateConfiguration = "PutBucketAccelerateConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfiguration func (c *S3) PutBucketAccelerateConfigurationRequest(input *PutBucketAccelerateConfigurationInput) (req *request.Request, output *PutBucketAccelerateConfigurationOutput) { op := &request.Operation{ Name: opPutBucketAccelerateConfiguration, @@ -4278,7 +4376,7 @@ func (c *S3) PutBucketAccelerateConfigurationRequest(input *PutBucketAccelerateC // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketAccelerateConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfiguration func (c *S3) PutBucketAccelerateConfiguration(input *PutBucketAccelerateConfigurationInput) (*PutBucketAccelerateConfigurationOutput, error) { req, out := c.PutBucketAccelerateConfigurationRequest(input) return out, req.Send() @@ -4304,19 +4402,18 @@ const opPutBucketAcl = "PutBucketAcl" // PutBucketAclRequest generates a "aws/request.Request" representing the // client's request for the PutBucketAcl operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketAcl for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketAcl method directly -// instead. +// See PutBucketAcl for more information on using the PutBucketAcl +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketAclRequest method. // req, resp := client.PutBucketAclRequest(params) @@ -4326,7 +4423,7 @@ const opPutBucketAcl = "PutBucketAcl" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAcl func (c *S3) PutBucketAclRequest(input *PutBucketAclInput) (req *request.Request, output *PutBucketAclOutput) { op := &request.Operation{ Name: opPutBucketAcl, @@ -4355,7 +4452,7 @@ func (c *S3) PutBucketAclRequest(input *PutBucketAclInput) (req *request.Request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketAcl for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAcl func (c *S3) PutBucketAcl(input *PutBucketAclInput) (*PutBucketAclOutput, error) { req, out := c.PutBucketAclRequest(input) return out, req.Send() @@ -4381,19 +4478,18 @@ const opPutBucketAnalyticsConfiguration = "PutBucketAnalyticsConfiguration" // PutBucketAnalyticsConfigurationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketAnalyticsConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketAnalyticsConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketAnalyticsConfiguration method directly -// instead. +// See PutBucketAnalyticsConfiguration for more information on using the PutBucketAnalyticsConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketAnalyticsConfigurationRequest method. // req, resp := client.PutBucketAnalyticsConfigurationRequest(params) @@ -4403,7 +4499,7 @@ const opPutBucketAnalyticsConfiguration = "PutBucketAnalyticsConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfiguration func (c *S3) PutBucketAnalyticsConfigurationRequest(input *PutBucketAnalyticsConfigurationInput) (req *request.Request, output *PutBucketAnalyticsConfigurationOutput) { op := &request.Operation{ Name: opPutBucketAnalyticsConfiguration, @@ -4433,7 +4529,7 @@ func (c *S3) PutBucketAnalyticsConfigurationRequest(input *PutBucketAnalyticsCon // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketAnalyticsConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfiguration func (c *S3) PutBucketAnalyticsConfiguration(input *PutBucketAnalyticsConfigurationInput) (*PutBucketAnalyticsConfigurationOutput, error) { req, out := c.PutBucketAnalyticsConfigurationRequest(input) return out, req.Send() @@ -4459,19 +4555,18 @@ const opPutBucketCors = "PutBucketCors" // PutBucketCorsRequest generates a "aws/request.Request" representing the // client's request for the PutBucketCors operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketCors for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketCors method directly -// instead. +// See PutBucketCors for more information on using the PutBucketCors +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketCorsRequest method. // req, resp := client.PutBucketCorsRequest(params) @@ -4481,7 +4576,7 @@ const opPutBucketCors = "PutBucketCors" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCors +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCors func (c *S3) PutBucketCorsRequest(input *PutBucketCorsInput) (req *request.Request, output *PutBucketCorsOutput) { op := &request.Operation{ Name: opPutBucketCors, @@ -4510,7 +4605,7 @@ func (c *S3) PutBucketCorsRequest(input *PutBucketCorsInput) (req *request.Reque // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketCors for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCors +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCors func (c *S3) PutBucketCors(input *PutBucketCorsInput) (*PutBucketCorsOutput, error) { req, out := c.PutBucketCorsRequest(input) return out, req.Send() @@ -4532,23 +4627,99 @@ func (c *S3) PutBucketCorsWithContext(ctx aws.Context, input *PutBucketCorsInput return out, req.Send() } +const opPutBucketEncryption = "PutBucketEncryption" + +// PutBucketEncryptionRequest generates a "aws/request.Request" representing the +// client's request for the PutBucketEncryption operation. The "output" return +// value will be populated with the request's response once the request complets +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See PutBucketEncryption for more information on using the PutBucketEncryption +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the PutBucketEncryptionRequest method. +// req, resp := client.PutBucketEncryptionRequest(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +// +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketEncryption +func (c *S3) PutBucketEncryptionRequest(input *PutBucketEncryptionInput) (req *request.Request, output *PutBucketEncryptionOutput) { + op := &request.Operation{ + Name: opPutBucketEncryption, + HTTPMethod: "PUT", + HTTPPath: "/{Bucket}?encryption", + } + + if input == nil { + input = &PutBucketEncryptionInput{} + } + + output = &PutBucketEncryptionOutput{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(restxml.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// PutBucketEncryption API operation for Amazon Simple Storage Service. +// +// Creates a new server-side encryption configuration (or replaces an existing +// one, if present). +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for Amazon Simple Storage Service's +// API operation PutBucketEncryption for usage and error information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketEncryption +func (c *S3) PutBucketEncryption(input *PutBucketEncryptionInput) (*PutBucketEncryptionOutput, error) { + req, out := c.PutBucketEncryptionRequest(input) + return out, req.Send() +} + +// PutBucketEncryptionWithContext is the same as PutBucketEncryption with the addition of +// the ability to pass a context and additional request options. +// +// See PutBucketEncryption for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *S3) PutBucketEncryptionWithContext(ctx aws.Context, input *PutBucketEncryptionInput, opts ...request.Option) (*PutBucketEncryptionOutput, error) { + req, out := c.PutBucketEncryptionRequest(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + const opPutBucketInventoryConfiguration = "PutBucketInventoryConfiguration" // PutBucketInventoryConfigurationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketInventoryConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketInventoryConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketInventoryConfiguration method directly -// instead. +// See PutBucketInventoryConfiguration for more information on using the PutBucketInventoryConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketInventoryConfigurationRequest method. // req, resp := client.PutBucketInventoryConfigurationRequest(params) @@ -4558,7 +4729,7 @@ const opPutBucketInventoryConfiguration = "PutBucketInventoryConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfiguration func (c *S3) PutBucketInventoryConfigurationRequest(input *PutBucketInventoryConfigurationInput) (req *request.Request, output *PutBucketInventoryConfigurationOutput) { op := &request.Operation{ Name: opPutBucketInventoryConfiguration, @@ -4588,7 +4759,7 @@ func (c *S3) PutBucketInventoryConfigurationRequest(input *PutBucketInventoryCon // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketInventoryConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfiguration func (c *S3) PutBucketInventoryConfiguration(input *PutBucketInventoryConfigurationInput) (*PutBucketInventoryConfigurationOutput, error) { req, out := c.PutBucketInventoryConfigurationRequest(input) return out, req.Send() @@ -4614,19 +4785,18 @@ const opPutBucketLifecycle = "PutBucketLifecycle" // PutBucketLifecycleRequest generates a "aws/request.Request" representing the // client's request for the PutBucketLifecycle operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketLifecycle for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketLifecycle method directly -// instead. +// See PutBucketLifecycle for more information on using the PutBucketLifecycle +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketLifecycleRequest method. // req, resp := client.PutBucketLifecycleRequest(params) @@ -4636,7 +4806,7 @@ const opPutBucketLifecycle = "PutBucketLifecycle" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycle +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycle func (c *S3) PutBucketLifecycleRequest(input *PutBucketLifecycleInput) (req *request.Request, output *PutBucketLifecycleOutput) { if c.Client.Config.Logger != nil { c.Client.Config.Logger.Log("This operation, PutBucketLifecycle, has been deprecated") @@ -4668,7 +4838,7 @@ func (c *S3) PutBucketLifecycleRequest(input *PutBucketLifecycleInput) (req *req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketLifecycle for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycle +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycle func (c *S3) PutBucketLifecycle(input *PutBucketLifecycleInput) (*PutBucketLifecycleOutput, error) { req, out := c.PutBucketLifecycleRequest(input) return out, req.Send() @@ -4694,19 +4864,18 @@ const opPutBucketLifecycleConfiguration = "PutBucketLifecycleConfiguration" // PutBucketLifecycleConfigurationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketLifecycleConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketLifecycleConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketLifecycleConfiguration method directly -// instead. +// See PutBucketLifecycleConfiguration for more information on using the PutBucketLifecycleConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketLifecycleConfigurationRequest method. // req, resp := client.PutBucketLifecycleConfigurationRequest(params) @@ -4716,7 +4885,7 @@ const opPutBucketLifecycleConfiguration = "PutBucketLifecycleConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfiguration func (c *S3) PutBucketLifecycleConfigurationRequest(input *PutBucketLifecycleConfigurationInput) (req *request.Request, output *PutBucketLifecycleConfigurationOutput) { op := &request.Operation{ Name: opPutBucketLifecycleConfiguration, @@ -4746,7 +4915,7 @@ func (c *S3) PutBucketLifecycleConfigurationRequest(input *PutBucketLifecycleCon // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketLifecycleConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfiguration func (c *S3) PutBucketLifecycleConfiguration(input *PutBucketLifecycleConfigurationInput) (*PutBucketLifecycleConfigurationOutput, error) { req, out := c.PutBucketLifecycleConfigurationRequest(input) return out, req.Send() @@ -4772,19 +4941,18 @@ const opPutBucketLogging = "PutBucketLogging" // PutBucketLoggingRequest generates a "aws/request.Request" representing the // client's request for the PutBucketLogging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketLogging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketLogging method directly -// instead. +// See PutBucketLogging for more information on using the PutBucketLogging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketLoggingRequest method. // req, resp := client.PutBucketLoggingRequest(params) @@ -4794,7 +4962,7 @@ const opPutBucketLogging = "PutBucketLogging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLogging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLogging func (c *S3) PutBucketLoggingRequest(input *PutBucketLoggingInput) (req *request.Request, output *PutBucketLoggingOutput) { op := &request.Operation{ Name: opPutBucketLogging, @@ -4825,7 +4993,7 @@ func (c *S3) PutBucketLoggingRequest(input *PutBucketLoggingInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketLogging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLogging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLogging func (c *S3) PutBucketLogging(input *PutBucketLoggingInput) (*PutBucketLoggingOutput, error) { req, out := c.PutBucketLoggingRequest(input) return out, req.Send() @@ -4851,19 +5019,18 @@ const opPutBucketMetricsConfiguration = "PutBucketMetricsConfiguration" // PutBucketMetricsConfigurationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketMetricsConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketMetricsConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketMetricsConfiguration method directly -// instead. +// See PutBucketMetricsConfiguration for more information on using the PutBucketMetricsConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketMetricsConfigurationRequest method. // req, resp := client.PutBucketMetricsConfigurationRequest(params) @@ -4873,7 +5040,7 @@ const opPutBucketMetricsConfiguration = "PutBucketMetricsConfiguration" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfiguration func (c *S3) PutBucketMetricsConfigurationRequest(input *PutBucketMetricsConfigurationInput) (req *request.Request, output *PutBucketMetricsConfigurationOutput) { op := &request.Operation{ Name: opPutBucketMetricsConfiguration, @@ -4903,7 +5070,7 @@ func (c *S3) PutBucketMetricsConfigurationRequest(input *PutBucketMetricsConfigu // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketMetricsConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfiguration func (c *S3) PutBucketMetricsConfiguration(input *PutBucketMetricsConfigurationInput) (*PutBucketMetricsConfigurationOutput, error) { req, out := c.PutBucketMetricsConfigurationRequest(input) return out, req.Send() @@ -4929,19 +5096,18 @@ const opPutBucketNotification = "PutBucketNotification" // PutBucketNotificationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketNotification operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketNotification for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketNotification method directly -// instead. +// See PutBucketNotification for more information on using the PutBucketNotification +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketNotificationRequest method. // req, resp := client.PutBucketNotificationRequest(params) @@ -4951,7 +5117,7 @@ const opPutBucketNotification = "PutBucketNotification" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotification +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotification func (c *S3) PutBucketNotificationRequest(input *PutBucketNotificationInput) (req *request.Request, output *PutBucketNotificationOutput) { if c.Client.Config.Logger != nil { c.Client.Config.Logger.Log("This operation, PutBucketNotification, has been deprecated") @@ -4983,7 +5149,7 @@ func (c *S3) PutBucketNotificationRequest(input *PutBucketNotificationInput) (re // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketNotification for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotification +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotification func (c *S3) PutBucketNotification(input *PutBucketNotificationInput) (*PutBucketNotificationOutput, error) { req, out := c.PutBucketNotificationRequest(input) return out, req.Send() @@ -5009,19 +5175,18 @@ const opPutBucketNotificationConfiguration = "PutBucketNotificationConfiguration // PutBucketNotificationConfigurationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketNotificationConfiguration operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketNotificationConfiguration for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketNotificationConfiguration method directly -// instead. +// See PutBucketNotificationConfiguration for more information on using the PutBucketNotificationConfiguration +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketNotificationConfigurationRequest method. // req, resp := client.PutBucketNotificationConfigurationRequest(params) @@ -5031,7 +5196,7 @@ const opPutBucketNotificationConfiguration = "PutBucketNotificationConfiguration // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfiguration func (c *S3) PutBucketNotificationConfigurationRequest(input *PutBucketNotificationConfigurationInput) (req *request.Request, output *PutBucketNotificationConfigurationOutput) { op := &request.Operation{ Name: opPutBucketNotificationConfiguration, @@ -5060,7 +5225,7 @@ func (c *S3) PutBucketNotificationConfigurationRequest(input *PutBucketNotificat // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketNotificationConfiguration for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfiguration func (c *S3) PutBucketNotificationConfiguration(input *PutBucketNotificationConfigurationInput) (*PutBucketNotificationConfigurationOutput, error) { req, out := c.PutBucketNotificationConfigurationRequest(input) return out, req.Send() @@ -5086,19 +5251,18 @@ const opPutBucketPolicy = "PutBucketPolicy" // PutBucketPolicyRequest generates a "aws/request.Request" representing the // client's request for the PutBucketPolicy operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketPolicy for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketPolicy method directly -// instead. +// See PutBucketPolicy for more information on using the PutBucketPolicy +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketPolicyRequest method. // req, resp := client.PutBucketPolicyRequest(params) @@ -5108,7 +5272,7 @@ const opPutBucketPolicy = "PutBucketPolicy" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicy func (c *S3) PutBucketPolicyRequest(input *PutBucketPolicyInput) (req *request.Request, output *PutBucketPolicyOutput) { op := &request.Operation{ Name: opPutBucketPolicy, @@ -5138,7 +5302,7 @@ func (c *S3) PutBucketPolicyRequest(input *PutBucketPolicyInput) (req *request.R // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketPolicy for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicy func (c *S3) PutBucketPolicy(input *PutBucketPolicyInput) (*PutBucketPolicyOutput, error) { req, out := c.PutBucketPolicyRequest(input) return out, req.Send() @@ -5164,19 +5328,18 @@ const opPutBucketReplication = "PutBucketReplication" // PutBucketReplicationRequest generates a "aws/request.Request" representing the // client's request for the PutBucketReplication operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketReplication for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketReplication method directly -// instead. +// See PutBucketReplication for more information on using the PutBucketReplication +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketReplicationRequest method. // req, resp := client.PutBucketReplicationRequest(params) @@ -5186,7 +5349,7 @@ const opPutBucketReplication = "PutBucketReplication" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplication +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplication func (c *S3) PutBucketReplicationRequest(input *PutBucketReplicationInput) (req *request.Request, output *PutBucketReplicationOutput) { op := &request.Operation{ Name: opPutBucketReplication, @@ -5216,7 +5379,7 @@ func (c *S3) PutBucketReplicationRequest(input *PutBucketReplicationInput) (req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketReplication for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplication +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplication func (c *S3) PutBucketReplication(input *PutBucketReplicationInput) (*PutBucketReplicationOutput, error) { req, out := c.PutBucketReplicationRequest(input) return out, req.Send() @@ -5242,19 +5405,18 @@ const opPutBucketRequestPayment = "PutBucketRequestPayment" // PutBucketRequestPaymentRequest generates a "aws/request.Request" representing the // client's request for the PutBucketRequestPayment operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketRequestPayment for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketRequestPayment method directly -// instead. +// See PutBucketRequestPayment for more information on using the PutBucketRequestPayment +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketRequestPaymentRequest method. // req, resp := client.PutBucketRequestPaymentRequest(params) @@ -5264,7 +5426,7 @@ const opPutBucketRequestPayment = "PutBucketRequestPayment" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPayment +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPayment func (c *S3) PutBucketRequestPaymentRequest(input *PutBucketRequestPaymentInput) (req *request.Request, output *PutBucketRequestPaymentOutput) { op := &request.Operation{ Name: opPutBucketRequestPayment, @@ -5297,7 +5459,7 @@ func (c *S3) PutBucketRequestPaymentRequest(input *PutBucketRequestPaymentInput) // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketRequestPayment for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPayment +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPayment func (c *S3) PutBucketRequestPayment(input *PutBucketRequestPaymentInput) (*PutBucketRequestPaymentOutput, error) { req, out := c.PutBucketRequestPaymentRequest(input) return out, req.Send() @@ -5323,19 +5485,18 @@ const opPutBucketTagging = "PutBucketTagging" // PutBucketTaggingRequest generates a "aws/request.Request" representing the // client's request for the PutBucketTagging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketTagging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketTagging method directly -// instead. +// See PutBucketTagging for more information on using the PutBucketTagging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketTaggingRequest method. // req, resp := client.PutBucketTaggingRequest(params) @@ -5345,7 +5506,7 @@ const opPutBucketTagging = "PutBucketTagging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTagging func (c *S3) PutBucketTaggingRequest(input *PutBucketTaggingInput) (req *request.Request, output *PutBucketTaggingOutput) { op := &request.Operation{ Name: opPutBucketTagging, @@ -5374,7 +5535,7 @@ func (c *S3) PutBucketTaggingRequest(input *PutBucketTaggingInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketTagging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTagging func (c *S3) PutBucketTagging(input *PutBucketTaggingInput) (*PutBucketTaggingOutput, error) { req, out := c.PutBucketTaggingRequest(input) return out, req.Send() @@ -5400,19 +5561,18 @@ const opPutBucketVersioning = "PutBucketVersioning" // PutBucketVersioningRequest generates a "aws/request.Request" representing the // client's request for the PutBucketVersioning operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketVersioning for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketVersioning method directly -// instead. +// See PutBucketVersioning for more information on using the PutBucketVersioning +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketVersioningRequest method. // req, resp := client.PutBucketVersioningRequest(params) @@ -5422,7 +5582,7 @@ const opPutBucketVersioning = "PutBucketVersioning" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioning +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioning func (c *S3) PutBucketVersioningRequest(input *PutBucketVersioningInput) (req *request.Request, output *PutBucketVersioningOutput) { op := &request.Operation{ Name: opPutBucketVersioning, @@ -5452,7 +5612,7 @@ func (c *S3) PutBucketVersioningRequest(input *PutBucketVersioningInput) (req *r // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketVersioning for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioning +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioning func (c *S3) PutBucketVersioning(input *PutBucketVersioningInput) (*PutBucketVersioningOutput, error) { req, out := c.PutBucketVersioningRequest(input) return out, req.Send() @@ -5478,19 +5638,18 @@ const opPutBucketWebsite = "PutBucketWebsite" // PutBucketWebsiteRequest generates a "aws/request.Request" representing the // client's request for the PutBucketWebsite operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutBucketWebsite for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutBucketWebsite method directly -// instead. +// See PutBucketWebsite for more information on using the PutBucketWebsite +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutBucketWebsiteRequest method. // req, resp := client.PutBucketWebsiteRequest(params) @@ -5500,7 +5659,7 @@ const opPutBucketWebsite = "PutBucketWebsite" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsite +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsite func (c *S3) PutBucketWebsiteRequest(input *PutBucketWebsiteInput) (req *request.Request, output *PutBucketWebsiteOutput) { op := &request.Operation{ Name: opPutBucketWebsite, @@ -5529,7 +5688,7 @@ func (c *S3) PutBucketWebsiteRequest(input *PutBucketWebsiteInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutBucketWebsite for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsite +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsite func (c *S3) PutBucketWebsite(input *PutBucketWebsiteInput) (*PutBucketWebsiteOutput, error) { req, out := c.PutBucketWebsiteRequest(input) return out, req.Send() @@ -5555,19 +5714,18 @@ const opPutObject = "PutObject" // PutObjectRequest generates a "aws/request.Request" representing the // client's request for the PutObject operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutObject for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutObject method directly -// instead. +// See PutObject for more information on using the PutObject +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutObjectRequest method. // req, resp := client.PutObjectRequest(params) @@ -5577,7 +5735,7 @@ const opPutObject = "PutObject" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject func (c *S3) PutObjectRequest(input *PutObjectInput) (req *request.Request, output *PutObjectOutput) { op := &request.Operation{ Name: opPutObject, @@ -5604,7 +5762,7 @@ func (c *S3) PutObjectRequest(input *PutObjectInput) (req *request.Request, outp // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutObject for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject func (c *S3) PutObject(input *PutObjectInput) (*PutObjectOutput, error) { req, out := c.PutObjectRequest(input) return out, req.Send() @@ -5630,19 +5788,18 @@ const opPutObjectAcl = "PutObjectAcl" // PutObjectAclRequest generates a "aws/request.Request" representing the // client's request for the PutObjectAcl operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutObjectAcl for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutObjectAcl method directly -// instead. +// See PutObjectAcl for more information on using the PutObjectAcl +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutObjectAclRequest method. // req, resp := client.PutObjectAclRequest(params) @@ -5652,7 +5809,7 @@ const opPutObjectAcl = "PutObjectAcl" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAcl func (c *S3) PutObjectAclRequest(input *PutObjectAclInput) (req *request.Request, output *PutObjectAclOutput) { op := &request.Operation{ Name: opPutObjectAcl, @@ -5685,7 +5842,7 @@ func (c *S3) PutObjectAclRequest(input *PutObjectAclInput) (req *request.Request // * ErrCodeNoSuchKey "NoSuchKey" // The specified key does not exist. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAcl +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAcl func (c *S3) PutObjectAcl(input *PutObjectAclInput) (*PutObjectAclOutput, error) { req, out := c.PutObjectAclRequest(input) return out, req.Send() @@ -5711,19 +5868,18 @@ const opPutObjectTagging = "PutObjectTagging" // PutObjectTaggingRequest generates a "aws/request.Request" representing the // client's request for the PutObjectTagging operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See PutObjectTagging for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the PutObjectTagging method directly -// instead. +// See PutObjectTagging for more information on using the PutObjectTagging +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the PutObjectTaggingRequest method. // req, resp := client.PutObjectTaggingRequest(params) @@ -5733,7 +5889,7 @@ const opPutObjectTagging = "PutObjectTagging" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTagging func (c *S3) PutObjectTaggingRequest(input *PutObjectTaggingInput) (req *request.Request, output *PutObjectTaggingOutput) { op := &request.Operation{ Name: opPutObjectTagging, @@ -5760,7 +5916,7 @@ func (c *S3) PutObjectTaggingRequest(input *PutObjectTaggingInput) (req *request // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation PutObjectTagging for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTagging func (c *S3) PutObjectTagging(input *PutObjectTaggingInput) (*PutObjectTaggingOutput, error) { req, out := c.PutObjectTaggingRequest(input) return out, req.Send() @@ -5786,19 +5942,18 @@ const opRestoreObject = "RestoreObject" // RestoreObjectRequest generates a "aws/request.Request" representing the // client's request for the RestoreObject operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See RestoreObject for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the RestoreObject method directly -// instead. +// See RestoreObject for more information on using the RestoreObject +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the RestoreObjectRequest method. // req, resp := client.RestoreObjectRequest(params) @@ -5808,7 +5963,7 @@ const opRestoreObject = "RestoreObject" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObject func (c *S3) RestoreObjectRequest(input *RestoreObjectInput) (req *request.Request, output *RestoreObjectOutput) { op := &request.Operation{ Name: opRestoreObject, @@ -5840,7 +5995,7 @@ func (c *S3) RestoreObjectRequest(input *RestoreObjectInput) (req *request.Reque // * ErrCodeObjectAlreadyInActiveTierError "ObjectAlreadyInActiveTierError" // This operation is not allowed against this storage tier // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObject func (c *S3) RestoreObject(input *RestoreObjectInput) (*RestoreObjectOutput, error) { req, out := c.RestoreObjectRequest(input) return out, req.Send() @@ -5866,19 +6021,18 @@ const opUploadPart = "UploadPart" // UploadPartRequest generates a "aws/request.Request" representing the // client's request for the UploadPart operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See UploadPart for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the UploadPart method directly -// instead. +// See UploadPart for more information on using the UploadPart +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the UploadPartRequest method. // req, resp := client.UploadPartRequest(params) @@ -5888,7 +6042,7 @@ const opUploadPart = "UploadPart" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart func (c *S3) UploadPartRequest(input *UploadPartInput) (req *request.Request, output *UploadPartOutput) { op := &request.Operation{ Name: opUploadPart, @@ -5921,7 +6075,7 @@ func (c *S3) UploadPartRequest(input *UploadPartInput) (req *request.Request, ou // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation UploadPart for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart func (c *S3) UploadPart(input *UploadPartInput) (*UploadPartOutput, error) { req, out := c.UploadPartRequest(input) return out, req.Send() @@ -5947,19 +6101,18 @@ const opUploadPartCopy = "UploadPartCopy" // UploadPartCopyRequest generates a "aws/request.Request" representing the // client's request for the UploadPartCopy operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See UploadPartCopy for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the UploadPartCopy method directly -// instead. +// See UploadPartCopy for more information on using the UploadPartCopy +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the UploadPartCopyRequest method. // req, resp := client.UploadPartCopyRequest(params) @@ -5969,7 +6122,7 @@ const opUploadPartCopy = "UploadPartCopy" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopy func (c *S3) UploadPartCopyRequest(input *UploadPartCopyInput) (req *request.Request, output *UploadPartCopyOutput) { op := &request.Operation{ Name: opUploadPartCopy, @@ -5996,7 +6149,7 @@ func (c *S3) UploadPartCopyRequest(input *UploadPartCopyInput) (req *request.Req // // See the AWS API reference guide for Amazon Simple Storage Service's // API operation UploadPartCopy for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopy func (c *S3) UploadPartCopy(input *UploadPartCopyInput) (*UploadPartCopyOutput, error) { req, out := c.UploadPartCopyRequest(input) return out, req.Send() @@ -6020,7 +6173,7 @@ func (c *S3) UploadPartCopyWithContext(ctx aws.Context, input *UploadPartCopyInp // Specifies the days since the initiation of an Incomplete Multipart Upload // that Lifecycle will wait before permanently removing all parts of the upload. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortIncompleteMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortIncompleteMultipartUpload type AbortIncompleteMultipartUpload struct { _ struct{} `type:"structure"` @@ -6045,7 +6198,7 @@ func (s *AbortIncompleteMultipartUpload) SetDaysAfterInitiation(v int64) *AbortI return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUploadRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUploadRequest type AbortMultipartUploadInput struct { _ struct{} `type:"structure"` @@ -6128,7 +6281,7 @@ func (s *AbortMultipartUploadInput) SetUploadId(v string) *AbortMultipartUploadI return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUploadOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUploadOutput type AbortMultipartUploadOutput struct { _ struct{} `type:"structure"` @@ -6153,7 +6306,7 @@ func (s *AbortMultipartUploadOutput) SetRequestCharged(v string) *AbortMultipart return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AccelerateConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AccelerateConfiguration type AccelerateConfiguration struct { _ struct{} `type:"structure"` @@ -6177,7 +6330,7 @@ func (s *AccelerateConfiguration) SetStatus(v string) *AccelerateConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AccessControlPolicy +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AccessControlPolicy type AccessControlPolicy struct { _ struct{} `type:"structure"` @@ -6229,7 +6382,47 @@ func (s *AccessControlPolicy) SetOwner(v *Owner) *AccessControlPolicy { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsAndOperator +// Container for information regarding the access control for replicas. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AccessControlTranslation +type AccessControlTranslation struct { + _ struct{} `type:"structure"` + + // The override value for the owner of the replica object. + // + // Owner is a required field + Owner *string `type:"string" required:"true" enum:"OwnerOverride"` +} + +// String returns the string representation +func (s AccessControlTranslation) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s AccessControlTranslation) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *AccessControlTranslation) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "AccessControlTranslation"} + if s.Owner == nil { + invalidParams.Add(request.NewErrParamRequired("Owner")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetOwner sets the Owner field's value. +func (s *AccessControlTranslation) SetOwner(v string) *AccessControlTranslation { + s.Owner = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsAndOperator type AnalyticsAndOperator struct { _ struct{} `type:"structure"` @@ -6282,7 +6475,7 @@ func (s *AnalyticsAndOperator) SetTags(v []*Tag) *AnalyticsAndOperator { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsConfiguration type AnalyticsConfiguration struct { _ struct{} `type:"structure"` @@ -6357,7 +6550,7 @@ func (s *AnalyticsConfiguration) SetStorageClassAnalysis(v *StorageClassAnalysis return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsExportDestination +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsExportDestination type AnalyticsExportDestination struct { _ struct{} `type:"structure"` @@ -6401,7 +6594,7 @@ func (s *AnalyticsExportDestination) SetS3BucketDestination(v *AnalyticsS3Bucket return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsFilter +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsFilter type AnalyticsFilter struct { _ struct{} `type:"structure"` @@ -6464,7 +6657,7 @@ func (s *AnalyticsFilter) SetTag(v *Tag) *AnalyticsFilter { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsS3BucketDestination +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AnalyticsS3BucketDestination type AnalyticsS3BucketDestination struct { _ struct{} `type:"structure"` @@ -6544,7 +6737,7 @@ func (s *AnalyticsS3BucketDestination) SetPrefix(v string) *AnalyticsS3BucketDes return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Bucket +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Bucket type Bucket struct { _ struct{} `type:"structure"` @@ -6577,7 +6770,7 @@ func (s *Bucket) SetName(v string) *Bucket { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/BucketLifecycleConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/BucketLifecycleConfiguration type BucketLifecycleConfiguration struct { _ struct{} `type:"structure"` @@ -6624,7 +6817,7 @@ func (s *BucketLifecycleConfiguration) SetRules(v []*LifecycleRule) *BucketLifec return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/BucketLoggingStatus +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/BucketLoggingStatus type BucketLoggingStatus struct { _ struct{} `type:"structure"` @@ -6662,7 +6855,7 @@ func (s *BucketLoggingStatus) SetLoggingEnabled(v *LoggingEnabled) *BucketLoggin return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CORSConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CORSConfiguration type CORSConfiguration struct { _ struct{} `type:"structure"` @@ -6709,7 +6902,7 @@ func (s *CORSConfiguration) SetCORSRules(v []*CORSRule) *CORSConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CORSRule +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CORSRule type CORSRule struct { _ struct{} `type:"structure"` @@ -6793,7 +6986,141 @@ func (s *CORSRule) SetMaxAgeSeconds(v int64) *CORSRule { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CloudFunctionConfiguration +// Describes how a CSV-formatted input object is formatted. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CSVInput +type CSVInput struct { + _ struct{} `type:"structure"` + + // Single character used to indicate a row should be ignored when present at + // the start of a row. + Comments *string `type:"string"` + + // Value used to separate individual fields in a record. + FieldDelimiter *string `type:"string"` + + // Describes the first line of input. Valid values: None, Ignore, Use. + FileHeaderInfo *string `type:"string" enum:"FileHeaderInfo"` + + // Value used for escaping where the field delimiter is part of the value. + QuoteCharacter *string `type:"string"` + + // Single character used for escaping the quote character inside an already + // escaped value. + QuoteEscapeCharacter *string `type:"string"` + + // Value used to separate individual records. + RecordDelimiter *string `type:"string"` +} + +// String returns the string representation +func (s CSVInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CSVInput) GoString() string { + return s.String() +} + +// SetComments sets the Comments field's value. +func (s *CSVInput) SetComments(v string) *CSVInput { + s.Comments = &v + return s +} + +// SetFieldDelimiter sets the FieldDelimiter field's value. +func (s *CSVInput) SetFieldDelimiter(v string) *CSVInput { + s.FieldDelimiter = &v + return s +} + +// SetFileHeaderInfo sets the FileHeaderInfo field's value. +func (s *CSVInput) SetFileHeaderInfo(v string) *CSVInput { + s.FileHeaderInfo = &v + return s +} + +// SetQuoteCharacter sets the QuoteCharacter field's value. +func (s *CSVInput) SetQuoteCharacter(v string) *CSVInput { + s.QuoteCharacter = &v + return s +} + +// SetQuoteEscapeCharacter sets the QuoteEscapeCharacter field's value. +func (s *CSVInput) SetQuoteEscapeCharacter(v string) *CSVInput { + s.QuoteEscapeCharacter = &v + return s +} + +// SetRecordDelimiter sets the RecordDelimiter field's value. +func (s *CSVInput) SetRecordDelimiter(v string) *CSVInput { + s.RecordDelimiter = &v + return s +} + +// Describes how CSV-formatted results are formatted. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CSVOutput +type CSVOutput struct { + _ struct{} `type:"structure"` + + // Value used to separate individual fields in a record. + FieldDelimiter *string `type:"string"` + + // Value used for escaping where the field delimiter is part of the value. + QuoteCharacter *string `type:"string"` + + // Single character used for escaping the quote character inside an already + // escaped value. + QuoteEscapeCharacter *string `type:"string"` + + // Indicates whether or not all output fields should be quoted. + QuoteFields *string `type:"string" enum:"QuoteFields"` + + // Value used to separate individual records. + RecordDelimiter *string `type:"string"` +} + +// String returns the string representation +func (s CSVOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s CSVOutput) GoString() string { + return s.String() +} + +// SetFieldDelimiter sets the FieldDelimiter field's value. +func (s *CSVOutput) SetFieldDelimiter(v string) *CSVOutput { + s.FieldDelimiter = &v + return s +} + +// SetQuoteCharacter sets the QuoteCharacter field's value. +func (s *CSVOutput) SetQuoteCharacter(v string) *CSVOutput { + s.QuoteCharacter = &v + return s +} + +// SetQuoteEscapeCharacter sets the QuoteEscapeCharacter field's value. +func (s *CSVOutput) SetQuoteEscapeCharacter(v string) *CSVOutput { + s.QuoteEscapeCharacter = &v + return s +} + +// SetQuoteFields sets the QuoteFields field's value. +func (s *CSVOutput) SetQuoteFields(v string) *CSVOutput { + s.QuoteFields = &v + return s +} + +// SetRecordDelimiter sets the RecordDelimiter field's value. +func (s *CSVOutput) SetRecordDelimiter(v string) *CSVOutput { + s.RecordDelimiter = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CloudFunctionConfiguration type CloudFunctionConfiguration struct { _ struct{} `type:"structure"` @@ -6851,7 +7178,7 @@ func (s *CloudFunctionConfiguration) SetInvocationRole(v string) *CloudFunctionC return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CommonPrefix +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CommonPrefix type CommonPrefix struct { _ struct{} `type:"structure"` @@ -6874,7 +7201,7 @@ func (s *CommonPrefix) SetPrefix(v string) *CommonPrefix { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUploadRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUploadRequest type CompleteMultipartUploadInput struct { _ struct{} `type:"structure" payload:"MultipartUpload"` @@ -6965,7 +7292,7 @@ func (s *CompleteMultipartUploadInput) SetUploadId(v string) *CompleteMultipartU return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUploadOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUploadOutput type CompleteMultipartUploadOutput struct { _ struct{} `type:"structure"` @@ -7069,7 +7396,7 @@ func (s *CompleteMultipartUploadOutput) SetVersionId(v string) *CompleteMultipar return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompletedMultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompletedMultipartUpload type CompletedMultipartUpload struct { _ struct{} `type:"structure"` @@ -7092,7 +7419,7 @@ func (s *CompletedMultipartUpload) SetParts(v []*CompletedPart) *CompletedMultip return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompletedPart +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompletedPart type CompletedPart struct { _ struct{} `type:"structure"` @@ -7126,7 +7453,7 @@ func (s *CompletedPart) SetPartNumber(v int64) *CompletedPart { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Condition +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Condition type Condition struct { _ struct{} `type:"structure"` @@ -7169,7 +7496,7 @@ func (s *Condition) SetKeyPrefixEquals(v string) *Condition { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObjectRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObjectRequest type CopyObjectInput struct { _ struct{} `type:"structure"` @@ -7553,7 +7880,7 @@ func (s *CopyObjectInput) SetWebsiteRedirectLocation(v string) *CopyObjectInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObjectOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObjectOutput type CopyObjectOutput struct { _ struct{} `type:"structure" payload:"CopyObjectResult"` @@ -7654,7 +7981,7 @@ func (s *CopyObjectOutput) SetVersionId(v string) *CopyObjectOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObjectResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyObjectResult type CopyObjectResult struct { _ struct{} `type:"structure"` @@ -7685,7 +8012,7 @@ func (s *CopyObjectResult) SetLastModified(v time.Time) *CopyObjectResult { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyPartResult +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CopyPartResult type CopyPartResult struct { _ struct{} `type:"structure"` @@ -7718,7 +8045,7 @@ func (s *CopyPartResult) SetLastModified(v time.Time) *CopyPartResult { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucketConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucketConfiguration type CreateBucketConfiguration struct { _ struct{} `type:"structure"` @@ -7743,7 +8070,7 @@ func (s *CreateBucketConfiguration) SetLocationConstraint(v string) *CreateBucke return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucketRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucketRequest type CreateBucketInput struct { _ struct{} `type:"structure" payload:"CreateBucketConfiguration"` @@ -7850,7 +8177,7 @@ func (s *CreateBucketInput) SetGrantWriteACP(v string) *CreateBucketInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucketOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucketOutput type CreateBucketOutput struct { _ struct{} `type:"structure"` @@ -7873,7 +8200,7 @@ func (s *CreateBucketOutput) SetLocation(v string) *CreateBucketOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUploadRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUploadRequest type CreateMultipartUploadInput struct { _ struct{} `type:"structure"` @@ -8145,7 +8472,7 @@ func (s *CreateMultipartUploadInput) SetWebsiteRedirectLocation(v string) *Creat return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUploadOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateMultipartUploadOutput type CreateMultipartUploadOutput struct { _ struct{} `type:"structure"` @@ -8265,7 +8592,7 @@ func (s *CreateMultipartUploadOutput) SetUploadId(v string) *CreateMultipartUplo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Delete +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Delete type Delete struct { _ struct{} `type:"structure"` @@ -8322,7 +8649,7 @@ func (s *Delete) SetQuiet(v bool) *Delete { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfigurationRequest type DeleteBucketAnalyticsConfigurationInput struct { _ struct{} `type:"structure"` @@ -8382,7 +8709,7 @@ func (s *DeleteBucketAnalyticsConfigurationInput) SetId(v string) *DeleteBucketA return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketAnalyticsConfigurationOutput type DeleteBucketAnalyticsConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -8397,7 +8724,7 @@ func (s DeleteBucketAnalyticsConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCorsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCorsRequest type DeleteBucketCorsInput struct { _ struct{} `type:"structure"` @@ -8441,7 +8768,7 @@ func (s *DeleteBucketCorsInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCorsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketCorsOutput type DeleteBucketCorsOutput struct { _ struct{} `type:"structure"` } @@ -8456,7 +8783,69 @@ func (s DeleteBucketCorsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketEncryptionRequest +type DeleteBucketEncryptionInput struct { + _ struct{} `type:"structure"` + + // The name of the bucket containing the server-side encryption configuration + // to delete. + // + // Bucket is a required field + Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` +} + +// String returns the string representation +func (s DeleteBucketEncryptionInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteBucketEncryptionInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeleteBucketEncryptionInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeleteBucketEncryptionInput"} + if s.Bucket == nil { + invalidParams.Add(request.NewErrParamRequired("Bucket")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetBucket sets the Bucket field's value. +func (s *DeleteBucketEncryptionInput) SetBucket(v string) *DeleteBucketEncryptionInput { + s.Bucket = &v + return s +} + +func (s *DeleteBucketEncryptionInput) getBucket() (v string) { + if s.Bucket == nil { + return v + } + return *s.Bucket +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketEncryptionOutput +type DeleteBucketEncryptionOutput struct { + _ struct{} `type:"structure"` +} + +// String returns the string representation +func (s DeleteBucketEncryptionOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteBucketEncryptionOutput) GoString() string { + return s.String() +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketRequest type DeleteBucketInput struct { _ struct{} `type:"structure"` @@ -8500,7 +8889,7 @@ func (s *DeleteBucketInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfigurationRequest type DeleteBucketInventoryConfigurationInput struct { _ struct{} `type:"structure"` @@ -8560,7 +8949,7 @@ func (s *DeleteBucketInventoryConfigurationInput) SetId(v string) *DeleteBucketI return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketInventoryConfigurationOutput type DeleteBucketInventoryConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -8575,7 +8964,7 @@ func (s DeleteBucketInventoryConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycleRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycleRequest type DeleteBucketLifecycleInput struct { _ struct{} `type:"structure"` @@ -8619,7 +9008,7 @@ func (s *DeleteBucketLifecycleInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycleOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketLifecycleOutput type DeleteBucketLifecycleOutput struct { _ struct{} `type:"structure"` } @@ -8634,7 +9023,7 @@ func (s DeleteBucketLifecycleOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfigurationRequest type DeleteBucketMetricsConfigurationInput struct { _ struct{} `type:"structure"` @@ -8694,7 +9083,7 @@ func (s *DeleteBucketMetricsConfigurationInput) SetId(v string) *DeleteBucketMet return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketMetricsConfigurationOutput type DeleteBucketMetricsConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -8709,7 +9098,7 @@ func (s DeleteBucketMetricsConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketOutput type DeleteBucketOutput struct { _ struct{} `type:"structure"` } @@ -8724,7 +9113,7 @@ func (s DeleteBucketOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicyRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicyRequest type DeleteBucketPolicyInput struct { _ struct{} `type:"structure"` @@ -8768,7 +9157,7 @@ func (s *DeleteBucketPolicyInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicyOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketPolicyOutput type DeleteBucketPolicyOutput struct { _ struct{} `type:"structure"` } @@ -8783,7 +9172,7 @@ func (s DeleteBucketPolicyOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplicationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplicationRequest type DeleteBucketReplicationInput struct { _ struct{} `type:"structure"` @@ -8827,7 +9216,7 @@ func (s *DeleteBucketReplicationInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplicationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketReplicationOutput type DeleteBucketReplicationOutput struct { _ struct{} `type:"structure"` } @@ -8842,7 +9231,7 @@ func (s DeleteBucketReplicationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTaggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTaggingRequest type DeleteBucketTaggingInput struct { _ struct{} `type:"structure"` @@ -8886,7 +9275,7 @@ func (s *DeleteBucketTaggingInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTaggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketTaggingOutput type DeleteBucketTaggingOutput struct { _ struct{} `type:"structure"` } @@ -8901,7 +9290,7 @@ func (s DeleteBucketTaggingOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsiteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsiteRequest type DeleteBucketWebsiteInput struct { _ struct{} `type:"structure"` @@ -8945,7 +9334,7 @@ func (s *DeleteBucketWebsiteInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsiteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucketWebsiteOutput type DeleteBucketWebsiteOutput struct { _ struct{} `type:"structure"` } @@ -8960,7 +9349,7 @@ func (s DeleteBucketWebsiteOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteMarkerEntry +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteMarkerEntry type DeleteMarkerEntry struct { _ struct{} `type:"structure"` @@ -9020,7 +9409,7 @@ func (s *DeleteMarkerEntry) SetVersionId(v string) *DeleteMarkerEntry { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectRequest type DeleteObjectInput struct { _ struct{} `type:"structure"` @@ -9110,7 +9499,7 @@ func (s *DeleteObjectInput) SetVersionId(v string) *DeleteObjectInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectOutput type DeleteObjectOutput struct { _ struct{} `type:"structure"` @@ -9155,7 +9544,7 @@ func (s *DeleteObjectOutput) SetVersionId(v string) *DeleteObjectOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTaggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTaggingRequest type DeleteObjectTaggingInput struct { _ struct{} `type:"structure"` @@ -9223,7 +9612,7 @@ func (s *DeleteObjectTaggingInput) SetVersionId(v string) *DeleteObjectTaggingIn return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTaggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectTaggingOutput type DeleteObjectTaggingOutput struct { _ struct{} `type:"structure"` @@ -9247,7 +9636,7 @@ func (s *DeleteObjectTaggingOutput) SetVersionId(v string) *DeleteObjectTaggingO return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectsRequest type DeleteObjectsInput struct { _ struct{} `type:"structure" payload:"Delete"` @@ -9330,7 +9719,7 @@ func (s *DeleteObjectsInput) SetRequestPayer(v string) *DeleteObjectsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObjectsOutput type DeleteObjectsOutput struct { _ struct{} `type:"structure"` @@ -9371,7 +9760,7 @@ func (s *DeleteObjectsOutput) SetRequestCharged(v string) *DeleteObjectsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeletedObject +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeletedObject type DeletedObject struct { _ struct{} `type:"structure"` @@ -9418,16 +9807,27 @@ func (s *DeletedObject) SetVersionId(v string) *DeletedObject { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Destination +// Container for replication destination information. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Destination type Destination struct { _ struct{} `type:"structure"` + // Container for information regarding the access control for replicas. + AccessControlTranslation *AccessControlTranslation `type:"structure"` + + // Account ID of the destination bucket. Currently this is only being verified + // if Access Control Translation is enabled + Account *string `type:"string"` + // Amazon resource name (ARN) of the bucket where you want Amazon S3 to store // replicas of the object identified by the rule. // // Bucket is a required field Bucket *string `type:"string" required:"true"` + // Container for information regarding encryption based configuration for replicas. + EncryptionConfiguration *EncryptionConfiguration `type:"structure"` + // The class of storage used to store the object. StorageClass *string `type:"string" enum:"StorageClass"` } @@ -9448,6 +9848,11 @@ func (s *Destination) Validate() error { if s.Bucket == nil { invalidParams.Add(request.NewErrParamRequired("Bucket")) } + if s.AccessControlTranslation != nil { + if err := s.AccessControlTranslation.Validate(); err != nil { + invalidParams.AddNested("AccessControlTranslation", err.(request.ErrInvalidParams)) + } + } if invalidParams.Len() > 0 { return invalidParams @@ -9455,6 +9860,18 @@ func (s *Destination) Validate() error { return nil } +// SetAccessControlTranslation sets the AccessControlTranslation field's value. +func (s *Destination) SetAccessControlTranslation(v *AccessControlTranslation) *Destination { + s.AccessControlTranslation = v + return s +} + +// SetAccount sets the Account field's value. +func (s *Destination) SetAccount(v string) *Destination { + s.Account = &v + return s +} + // SetBucket sets the Bucket field's value. func (s *Destination) SetBucket(v string) *Destination { s.Bucket = &v @@ -9468,13 +9885,106 @@ func (s *Destination) getBucket() (v string) { return *s.Bucket } +// SetEncryptionConfiguration sets the EncryptionConfiguration field's value. +func (s *Destination) SetEncryptionConfiguration(v *EncryptionConfiguration) *Destination { + s.EncryptionConfiguration = v + return s +} + // SetStorageClass sets the StorageClass field's value. func (s *Destination) SetStorageClass(v string) *Destination { s.StorageClass = &v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Error +// Describes the server-side encryption that will be applied to the restore +// results. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Encryption +type Encryption struct { + _ struct{} `type:"structure"` + + // The server-side encryption algorithm used when storing job results in Amazon + // S3 (e.g., AES256, aws:kms). + // + // EncryptionType is a required field + EncryptionType *string `type:"string" required:"true" enum:"ServerSideEncryption"` + + // If the encryption type is aws:kms, this optional value can be used to specify + // the encryption context for the restore results. + KMSContext *string `type:"string"` + + // If the encryption type is aws:kms, this optional value specifies the AWS + // KMS key ID to use for encryption of job results. + KMSKeyId *string `type:"string"` +} + +// String returns the string representation +func (s Encryption) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s Encryption) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *Encryption) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "Encryption"} + if s.EncryptionType == nil { + invalidParams.Add(request.NewErrParamRequired("EncryptionType")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetEncryptionType sets the EncryptionType field's value. +func (s *Encryption) SetEncryptionType(v string) *Encryption { + s.EncryptionType = &v + return s +} + +// SetKMSContext sets the KMSContext field's value. +func (s *Encryption) SetKMSContext(v string) *Encryption { + s.KMSContext = &v + return s +} + +// SetKMSKeyId sets the KMSKeyId field's value. +func (s *Encryption) SetKMSKeyId(v string) *Encryption { + s.KMSKeyId = &v + return s +} + +// Container for information regarding encryption based configuration for replicas. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/EncryptionConfiguration +type EncryptionConfiguration struct { + _ struct{} `type:"structure"` + + // The id of the KMS key used to encrypt the replica object. + ReplicaKmsKeyID *string `type:"string"` +} + +// String returns the string representation +func (s EncryptionConfiguration) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s EncryptionConfiguration) GoString() string { + return s.String() +} + +// SetReplicaKmsKeyID sets the ReplicaKmsKeyID field's value. +func (s *EncryptionConfiguration) SetReplicaKmsKeyID(v string) *EncryptionConfiguration { + s.ReplicaKmsKeyID = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Error type Error struct { _ struct{} `type:"structure"` @@ -9521,7 +10031,7 @@ func (s *Error) SetVersionId(v string) *Error { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ErrorDocument +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ErrorDocument type ErrorDocument struct { _ struct{} `type:"structure"` @@ -9564,7 +10074,7 @@ func (s *ErrorDocument) SetKey(v string) *ErrorDocument { } // Container for key value pair that defines the criteria for the filter rule. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/FilterRule +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/FilterRule type FilterRule struct { _ struct{} `type:"structure"` @@ -9599,7 +10109,7 @@ func (s *FilterRule) SetValue(v string) *FilterRule { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfigurationRequest type GetBucketAccelerateConfigurationInput struct { _ struct{} `type:"structure"` @@ -9645,7 +10155,7 @@ func (s *GetBucketAccelerateConfigurationInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAccelerateConfigurationOutput type GetBucketAccelerateConfigurationOutput struct { _ struct{} `type:"structure"` @@ -9669,7 +10179,7 @@ func (s *GetBucketAccelerateConfigurationOutput) SetStatus(v string) *GetBucketA return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAclRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAclRequest type GetBucketAclInput struct { _ struct{} `type:"structure"` @@ -9713,7 +10223,7 @@ func (s *GetBucketAclInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAclOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAclOutput type GetBucketAclOutput struct { _ struct{} `type:"structure"` @@ -9745,7 +10255,7 @@ func (s *GetBucketAclOutput) SetOwner(v *Owner) *GetBucketAclOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfigurationRequest type GetBucketAnalyticsConfigurationInput struct { _ struct{} `type:"structure"` @@ -9805,7 +10315,7 @@ func (s *GetBucketAnalyticsConfigurationInput) SetId(v string) *GetBucketAnalyti return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketAnalyticsConfigurationOutput type GetBucketAnalyticsConfigurationOutput struct { _ struct{} `type:"structure" payload:"AnalyticsConfiguration"` @@ -9829,7 +10339,7 @@ func (s *GetBucketAnalyticsConfigurationOutput) SetAnalyticsConfiguration(v *Ana return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCorsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCorsRequest type GetBucketCorsInput struct { _ struct{} `type:"structure"` @@ -9873,7 +10383,7 @@ func (s *GetBucketCorsInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCorsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketCorsOutput type GetBucketCorsOutput struct { _ struct{} `type:"structure"` @@ -9896,7 +10406,79 @@ func (s *GetBucketCorsOutput) SetCORSRules(v []*CORSRule) *GetBucketCorsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketEncryptionRequest +type GetBucketEncryptionInput struct { + _ struct{} `type:"structure"` + + // The name of the bucket from which the server-side encryption configuration + // is retrieved. + // + // Bucket is a required field + Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` +} + +// String returns the string representation +func (s GetBucketEncryptionInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetBucketEncryptionInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *GetBucketEncryptionInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "GetBucketEncryptionInput"} + if s.Bucket == nil { + invalidParams.Add(request.NewErrParamRequired("Bucket")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetBucket sets the Bucket field's value. +func (s *GetBucketEncryptionInput) SetBucket(v string) *GetBucketEncryptionInput { + s.Bucket = &v + return s +} + +func (s *GetBucketEncryptionInput) getBucket() (v string) { + if s.Bucket == nil { + return v + } + return *s.Bucket +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketEncryptionOutput +type GetBucketEncryptionOutput struct { + _ struct{} `type:"structure" payload:"ServerSideEncryptionConfiguration"` + + // Container for server-side encryption configuration rules. Currently S3 supports + // one rule only. + ServerSideEncryptionConfiguration *ServerSideEncryptionConfiguration `type:"structure"` +} + +// String returns the string representation +func (s GetBucketEncryptionOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s GetBucketEncryptionOutput) GoString() string { + return s.String() +} + +// SetServerSideEncryptionConfiguration sets the ServerSideEncryptionConfiguration field's value. +func (s *GetBucketEncryptionOutput) SetServerSideEncryptionConfiguration(v *ServerSideEncryptionConfiguration) *GetBucketEncryptionOutput { + s.ServerSideEncryptionConfiguration = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfigurationRequest type GetBucketInventoryConfigurationInput struct { _ struct{} `type:"structure"` @@ -9956,7 +10538,7 @@ func (s *GetBucketInventoryConfigurationInput) SetId(v string) *GetBucketInvento return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketInventoryConfigurationOutput type GetBucketInventoryConfigurationOutput struct { _ struct{} `type:"structure" payload:"InventoryConfiguration"` @@ -9980,7 +10562,7 @@ func (s *GetBucketInventoryConfigurationOutput) SetInventoryConfiguration(v *Inv return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfigurationRequest type GetBucketLifecycleConfigurationInput struct { _ struct{} `type:"structure"` @@ -10024,7 +10606,7 @@ func (s *GetBucketLifecycleConfigurationInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleConfigurationOutput type GetBucketLifecycleConfigurationOutput struct { _ struct{} `type:"structure"` @@ -10047,7 +10629,7 @@ func (s *GetBucketLifecycleConfigurationOutput) SetRules(v []*LifecycleRule) *Ge return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleRequest type GetBucketLifecycleInput struct { _ struct{} `type:"structure"` @@ -10091,7 +10673,7 @@ func (s *GetBucketLifecycleInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLifecycleOutput type GetBucketLifecycleOutput struct { _ struct{} `type:"structure"` @@ -10114,7 +10696,7 @@ func (s *GetBucketLifecycleOutput) SetRules(v []*Rule) *GetBucketLifecycleOutput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocationRequest type GetBucketLocationInput struct { _ struct{} `type:"structure"` @@ -10158,7 +10740,7 @@ func (s *GetBucketLocationInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLocationOutput type GetBucketLocationOutput struct { _ struct{} `type:"structure"` @@ -10181,7 +10763,7 @@ func (s *GetBucketLocationOutput) SetLocationConstraint(v string) *GetBucketLoca return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLoggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLoggingRequest type GetBucketLoggingInput struct { _ struct{} `type:"structure"` @@ -10225,7 +10807,7 @@ func (s *GetBucketLoggingInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLoggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketLoggingOutput type GetBucketLoggingOutput struct { _ struct{} `type:"structure"` @@ -10248,7 +10830,7 @@ func (s *GetBucketLoggingOutput) SetLoggingEnabled(v *LoggingEnabled) *GetBucket return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfigurationRequest type GetBucketMetricsConfigurationInput struct { _ struct{} `type:"structure"` @@ -10308,7 +10890,7 @@ func (s *GetBucketMetricsConfigurationInput) SetId(v string) *GetBucketMetricsCo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketMetricsConfigurationOutput type GetBucketMetricsConfigurationOutput struct { _ struct{} `type:"structure" payload:"MetricsConfiguration"` @@ -10332,7 +10914,7 @@ func (s *GetBucketMetricsConfigurationOutput) SetMetricsConfiguration(v *Metrics return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketNotificationConfigurationRequest type GetBucketNotificationConfigurationRequest struct { _ struct{} `type:"structure"` @@ -10378,7 +10960,7 @@ func (s *GetBucketNotificationConfigurationRequest) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicyRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicyRequest type GetBucketPolicyInput struct { _ struct{} `type:"structure"` @@ -10422,7 +11004,7 @@ func (s *GetBucketPolicyInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicyOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketPolicyOutput type GetBucketPolicyOutput struct { _ struct{} `type:"structure" payload:"Policy"` @@ -10446,7 +11028,7 @@ func (s *GetBucketPolicyOutput) SetPolicy(v string) *GetBucketPolicyOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplicationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplicationRequest type GetBucketReplicationInput struct { _ struct{} `type:"structure"` @@ -10490,7 +11072,7 @@ func (s *GetBucketReplicationInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplicationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketReplicationOutput type GetBucketReplicationOutput struct { _ struct{} `type:"structure" payload:"ReplicationConfiguration"` @@ -10515,7 +11097,7 @@ func (s *GetBucketReplicationOutput) SetReplicationConfiguration(v *ReplicationC return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPaymentRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPaymentRequest type GetBucketRequestPaymentInput struct { _ struct{} `type:"structure"` @@ -10559,7 +11141,7 @@ func (s *GetBucketRequestPaymentInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPaymentOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketRequestPaymentOutput type GetBucketRequestPaymentOutput struct { _ struct{} `type:"structure"` @@ -10583,7 +11165,7 @@ func (s *GetBucketRequestPaymentOutput) SetPayer(v string) *GetBucketRequestPaym return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTaggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTaggingRequest type GetBucketTaggingInput struct { _ struct{} `type:"structure"` @@ -10627,7 +11209,7 @@ func (s *GetBucketTaggingInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTaggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketTaggingOutput type GetBucketTaggingOutput struct { _ struct{} `type:"structure"` @@ -10651,7 +11233,7 @@ func (s *GetBucketTaggingOutput) SetTagSet(v []*Tag) *GetBucketTaggingOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioningRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioningRequest type GetBucketVersioningInput struct { _ struct{} `type:"structure"` @@ -10695,7 +11277,7 @@ func (s *GetBucketVersioningInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioningOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketVersioningOutput type GetBucketVersioningOutput struct { _ struct{} `type:"structure"` @@ -10730,7 +11312,7 @@ func (s *GetBucketVersioningOutput) SetStatus(v string) *GetBucketVersioningOutp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsiteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsiteRequest type GetBucketWebsiteInput struct { _ struct{} `type:"structure"` @@ -10774,7 +11356,7 @@ func (s *GetBucketWebsiteInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsiteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetBucketWebsiteOutput type GetBucketWebsiteOutput struct { _ struct{} `type:"structure"` @@ -10821,7 +11403,7 @@ func (s *GetBucketWebsiteOutput) SetRoutingRules(v []*RoutingRule) *GetBucketWeb return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAclRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAclRequest type GetObjectAclInput struct { _ struct{} `type:"structure"` @@ -10901,7 +11483,7 @@ func (s *GetObjectAclInput) SetVersionId(v string) *GetObjectAclInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAclOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectAclOutput type GetObjectAclOutput struct { _ struct{} `type:"structure"` @@ -10943,7 +11525,7 @@ func (s *GetObjectAclOutput) SetRequestCharged(v string) *GetObjectAclOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectRequest type GetObjectInput struct { _ struct{} `type:"structure"` @@ -11178,7 +11760,7 @@ func (s *GetObjectInput) SetVersionId(v string) *GetObjectInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectOutput type GetObjectOutput struct { _ struct{} `type:"structure" payload:"Body"` @@ -11462,7 +12044,7 @@ func (s *GetObjectOutput) SetWebsiteRedirectLocation(v string) *GetObjectOutput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTaggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTaggingRequest type GetObjectTaggingInput struct { _ struct{} `type:"structure"` @@ -11529,7 +12111,7 @@ func (s *GetObjectTaggingInput) SetVersionId(v string) *GetObjectTaggingInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTaggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTaggingOutput type GetObjectTaggingOutput struct { _ struct{} `type:"structure"` @@ -11561,7 +12143,7 @@ func (s *GetObjectTaggingOutput) SetVersionId(v string) *GetObjectTaggingOutput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrentRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrentRequest type GetObjectTorrentInput struct { _ struct{} `type:"structure"` @@ -11632,7 +12214,7 @@ func (s *GetObjectTorrentInput) SetRequestPayer(v string) *GetObjectTorrentInput return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrentOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObjectTorrentOutput type GetObjectTorrentOutput struct { _ struct{} `type:"structure" payload:"Body"` @@ -11665,7 +12247,7 @@ func (s *GetObjectTorrentOutput) SetRequestCharged(v string) *GetObjectTorrentOu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GlacierJobParameters +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GlacierJobParameters type GlacierJobParameters struct { _ struct{} `type:"structure"` @@ -11704,7 +12286,7 @@ func (s *GlacierJobParameters) SetTier(v string) *GlacierJobParameters { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Grant +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Grant type Grant struct { _ struct{} `type:"structure"` @@ -11751,7 +12333,7 @@ func (s *Grant) SetPermission(v string) *Grant { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Grantee +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Grantee type Grantee struct { _ struct{} `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` @@ -11826,7 +12408,7 @@ func (s *Grantee) SetURI(v string) *Grantee { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucketRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucketRequest type HeadBucketInput struct { _ struct{} `type:"structure"` @@ -11870,7 +12452,7 @@ func (s *HeadBucketInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucketOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadBucketOutput type HeadBucketOutput struct { _ struct{} `type:"structure"` } @@ -11885,7 +12467,7 @@ func (s HeadBucketOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObjectRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObjectRequest type HeadObjectInput struct { _ struct{} `type:"structure"` @@ -12067,7 +12649,7 @@ func (s *HeadObjectInput) SetVersionId(v string) *HeadObjectInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObjectOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/HeadObjectOutput type HeadObjectOutput struct { _ struct{} `type:"structure"` @@ -12324,7 +12906,7 @@ func (s *HeadObjectOutput) SetWebsiteRedirectLocation(v string) *HeadObjectOutpu return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/IndexDocument +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/IndexDocument type IndexDocument struct { _ struct{} `type:"structure"` @@ -12366,7 +12948,7 @@ func (s *IndexDocument) SetSuffix(v string) *IndexDocument { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Initiator +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Initiator type Initiator struct { _ struct{} `type:"structure"` @@ -12400,7 +12982,32 @@ func (s *Initiator) SetID(v string) *Initiator { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryConfiguration +// Describes the serialization format of the object. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InputSerialization +type InputSerialization struct { + _ struct{} `type:"structure"` + + // Describes the serialization of a CSV-encoded object. + CSV *CSVInput `type:"structure"` +} + +// String returns the string representation +func (s InputSerialization) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InputSerialization) GoString() string { + return s.String() +} + +// SetCSV sets the CSV field's value. +func (s *InputSerialization) SetCSV(v *CSVInput) *InputSerialization { + s.CSV = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryConfiguration type InventoryConfiguration struct { _ struct{} `type:"structure"` @@ -12529,7 +13136,7 @@ func (s *InventoryConfiguration) SetSchedule(v *InventorySchedule) *InventoryCon return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryDestination +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryDestination type InventoryDestination struct { _ struct{} `type:"structure"` @@ -12574,7 +13181,57 @@ func (s *InventoryDestination) SetS3BucketDestination(v *InventoryS3BucketDestin return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryFilter +// Contains the type of server-side encryption used to encrypt the inventory +// results. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryEncryption +type InventoryEncryption struct { + _ struct{} `type:"structure"` + + // Specifies the use of SSE-KMS to encrypt delievered Inventory reports. + SSEKMS *SSEKMS `locationName:"SSE-KMS" type:"structure"` + + // Specifies the use of SSE-S3 to encrypt delievered Inventory reports. + SSES3 *SSES3 `locationName:"SSE-S3" type:"structure"` +} + +// String returns the string representation +func (s InventoryEncryption) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s InventoryEncryption) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *InventoryEncryption) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "InventoryEncryption"} + if s.SSEKMS != nil { + if err := s.SSEKMS.Validate(); err != nil { + invalidParams.AddNested("SSEKMS", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetSSEKMS sets the SSEKMS field's value. +func (s *InventoryEncryption) SetSSEKMS(v *SSEKMS) *InventoryEncryption { + s.SSEKMS = v + return s +} + +// SetSSES3 sets the SSES3 field's value. +func (s *InventoryEncryption) SetSSES3(v *SSES3) *InventoryEncryption { + s.SSES3 = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryFilter type InventoryFilter struct { _ struct{} `type:"structure"` @@ -12613,7 +13270,7 @@ func (s *InventoryFilter) SetPrefix(v string) *InventoryFilter { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryS3BucketDestination +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventoryS3BucketDestination type InventoryS3BucketDestination struct { _ struct{} `type:"structure"` @@ -12626,6 +13283,10 @@ type InventoryS3BucketDestination struct { // Bucket is a required field Bucket *string `type:"string" required:"true"` + // Contains the type of server-side encryption used to encrypt the inventory + // results. + Encryption *InventoryEncryption `type:"structure"` + // Specifies the output format of the inventory results. // // Format is a required field @@ -12654,6 +13315,11 @@ func (s *InventoryS3BucketDestination) Validate() error { if s.Format == nil { invalidParams.Add(request.NewErrParamRequired("Format")) } + if s.Encryption != nil { + if err := s.Encryption.Validate(); err != nil { + invalidParams.AddNested("Encryption", err.(request.ErrInvalidParams)) + } + } if invalidParams.Len() > 0 { return invalidParams @@ -12680,6 +13346,12 @@ func (s *InventoryS3BucketDestination) getBucket() (v string) { return *s.Bucket } +// SetEncryption sets the Encryption field's value. +func (s *InventoryS3BucketDestination) SetEncryption(v *InventoryEncryption) *InventoryS3BucketDestination { + s.Encryption = v + return s +} + // SetFormat sets the Format field's value. func (s *InventoryS3BucketDestination) SetFormat(v string) *InventoryS3BucketDestination { s.Format = &v @@ -12692,7 +13364,7 @@ func (s *InventoryS3BucketDestination) SetPrefix(v string) *InventoryS3BucketDes return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventorySchedule +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/InventorySchedule type InventorySchedule struct { _ struct{} `type:"structure"` @@ -12732,7 +13404,7 @@ func (s *InventorySchedule) SetFrequency(v string) *InventorySchedule { } // Container for object key name prefix and suffix filtering rules. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/S3KeyFilter +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/S3KeyFilter type KeyFilter struct { _ struct{} `type:"structure"` @@ -12758,7 +13430,7 @@ func (s *KeyFilter) SetFilterRules(v []*FilterRule) *KeyFilter { } // Container for specifying the AWS Lambda notification configuration. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LambdaFunctionConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LambdaFunctionConfiguration type LambdaFunctionConfiguration struct { _ struct{} `type:"structure"` @@ -12830,7 +13502,7 @@ func (s *LambdaFunctionConfiguration) SetLambdaFunctionArn(v string) *LambdaFunc return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleConfiguration type LifecycleConfiguration struct { _ struct{} `type:"structure"` @@ -12877,7 +13549,7 @@ func (s *LifecycleConfiguration) SetRules(v []*Rule) *LifecycleConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleExpiration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleExpiration type LifecycleExpiration struct { _ struct{} `type:"structure"` @@ -12924,7 +13596,7 @@ func (s *LifecycleExpiration) SetExpiredObjectDeleteMarker(v bool) *LifecycleExp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleRule +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleRule type LifecycleRule struct { _ struct{} `type:"structure"` @@ -13048,7 +13720,7 @@ func (s *LifecycleRule) SetTransitions(v []*Transition) *LifecycleRule { // This is used in a Lifecycle Rule Filter to apply a logical AND to two or // more predicates. The Lifecycle Rule will apply to any object matching all // of the predicates configured inside the And operator. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleRuleAndOperator +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleRuleAndOperator type LifecycleRuleAndOperator struct { _ struct{} `type:"structure"` @@ -13103,7 +13775,7 @@ func (s *LifecycleRuleAndOperator) SetTags(v []*Tag) *LifecycleRuleAndOperator { // The Filter is used to identify objects that a Lifecycle Rule applies to. // A Filter must have exactly one of Prefix, Tag, or And specified. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleRuleFilter +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LifecycleRuleFilter type LifecycleRuleFilter struct { _ struct{} `type:"structure"` @@ -13167,7 +13839,7 @@ func (s *LifecycleRuleFilter) SetTag(v *Tag) *LifecycleRuleFilter { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurationsRequest type ListBucketAnalyticsConfigurationsInput struct { _ struct{} `type:"structure"` @@ -13223,7 +13895,7 @@ func (s *ListBucketAnalyticsConfigurationsInput) SetContinuationToken(v string) return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurationsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketAnalyticsConfigurationsOutput type ListBucketAnalyticsConfigurationsOutput struct { _ struct{} `type:"structure"` @@ -13278,7 +13950,7 @@ func (s *ListBucketAnalyticsConfigurationsOutput) SetNextContinuationToken(v str return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurationsRequest type ListBucketInventoryConfigurationsInput struct { _ struct{} `type:"structure"` @@ -13336,7 +14008,7 @@ func (s *ListBucketInventoryConfigurationsInput) SetContinuationToken(v string) return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurationsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketInventoryConfigurationsOutput type ListBucketInventoryConfigurationsOutput struct { _ struct{} `type:"structure"` @@ -13391,7 +14063,7 @@ func (s *ListBucketInventoryConfigurationsOutput) SetNextContinuationToken(v str return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurationsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurationsRequest type ListBucketMetricsConfigurationsInput struct { _ struct{} `type:"structure"` @@ -13449,7 +14121,7 @@ func (s *ListBucketMetricsConfigurationsInput) SetContinuationToken(v string) *L return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurationsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketMetricsConfigurationsOutput type ListBucketMetricsConfigurationsOutput struct { _ struct{} `type:"structure"` @@ -13506,7 +14178,7 @@ func (s *ListBucketMetricsConfigurationsOutput) SetNextContinuationToken(v strin return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketsInput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketsInput type ListBucketsInput struct { _ struct{} `type:"structure"` } @@ -13521,7 +14193,7 @@ func (s ListBucketsInput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBucketsOutput type ListBucketsOutput struct { _ struct{} `type:"structure"` @@ -13552,7 +14224,7 @@ func (s *ListBucketsOutput) SetOwner(v *Owner) *ListBucketsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploadsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploadsRequest type ListMultipartUploadsInput struct { _ struct{} `type:"structure"` @@ -13661,7 +14333,7 @@ func (s *ListMultipartUploadsInput) SetUploadIdMarker(v string) *ListMultipartUp return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploadsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListMultipartUploadsOutput type ListMultipartUploadsOutput struct { _ struct{} `type:"structure"` @@ -13795,7 +14467,7 @@ func (s *ListMultipartUploadsOutput) SetUploads(v []*MultipartUpload) *ListMulti return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersionsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersionsRequest type ListObjectVersionsInput struct { _ struct{} `type:"structure"` @@ -13899,7 +14571,7 @@ func (s *ListObjectVersionsInput) SetVersionIdMarker(v string) *ListObjectVersio return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersionsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectVersionsOutput type ListObjectVersionsOutput struct { _ struct{} `type:"structure"` @@ -14027,7 +14699,7 @@ func (s *ListObjectVersionsOutput) SetVersions(v []*ObjectVersion) *ListObjectVe return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsRequest type ListObjectsInput struct { _ struct{} `type:"structure"` @@ -14133,7 +14805,7 @@ func (s *ListObjectsInput) SetRequestPayer(v string) *ListObjectsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsOutput type ListObjectsOutput struct { _ struct{} `type:"structure"` @@ -14238,7 +14910,7 @@ func (s *ListObjectsOutput) SetPrefix(v string) *ListObjectsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2Request +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2Request type ListObjectsV2Input struct { _ struct{} `type:"structure"` @@ -14364,7 +15036,7 @@ func (s *ListObjectsV2Input) SetStartAfter(v string) *ListObjectsV2Input { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2Output +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjectsV2Output type ListObjectsV2Output struct { _ struct{} `type:"structure"` @@ -14498,7 +15170,7 @@ func (s *ListObjectsV2Output) SetStartAfter(v string) *ListObjectsV2Output { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListPartsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListPartsRequest type ListPartsInput struct { _ struct{} `type:"structure"` @@ -14602,7 +15274,7 @@ func (s *ListPartsInput) SetUploadId(v string) *ListPartsInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListPartsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListPartsOutput type ListPartsOutput struct { _ struct{} `type:"structure"` @@ -14752,7 +15424,136 @@ func (s *ListPartsOutput) SetUploadId(v string) *ListPartsOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LoggingEnabled +// Describes an S3 location that will receive the results of the restore request. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/S3Location +type Location struct { + _ struct{} `type:"structure"` + + // A list of grants that control access to the staged results. + AccessControlList []*Grant `locationNameList:"Grant" type:"list"` + + // The name of the bucket where the restore results will be placed. + // + // BucketName is a required field + BucketName *string `type:"string" required:"true"` + + // The canned ACL to apply to the restore results. + CannedACL *string `type:"string" enum:"ObjectCannedACL"` + + // Describes the server-side encryption that will be applied to the restore + // results. + Encryption *Encryption `type:"structure"` + + // The prefix that is prepended to the restore results for this request. + // + // Prefix is a required field + Prefix *string `type:"string" required:"true"` + + // The class of storage used to store the restore results. + StorageClass *string `type:"string" enum:"StorageClass"` + + // The tag-set that is applied to the restore results. + Tagging *Tagging `type:"structure"` + + // A list of metadata to store with the restore results in S3. + UserMetadata []*MetadataEntry `locationNameList:"MetadataEntry" type:"list"` +} + +// String returns the string representation +func (s Location) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s Location) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *Location) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "Location"} + if s.BucketName == nil { + invalidParams.Add(request.NewErrParamRequired("BucketName")) + } + if s.Prefix == nil { + invalidParams.Add(request.NewErrParamRequired("Prefix")) + } + if s.AccessControlList != nil { + for i, v := range s.AccessControlList { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "AccessControlList", i), err.(request.ErrInvalidParams)) + } + } + } + if s.Encryption != nil { + if err := s.Encryption.Validate(); err != nil { + invalidParams.AddNested("Encryption", err.(request.ErrInvalidParams)) + } + } + if s.Tagging != nil { + if err := s.Tagging.Validate(); err != nil { + invalidParams.AddNested("Tagging", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetAccessControlList sets the AccessControlList field's value. +func (s *Location) SetAccessControlList(v []*Grant) *Location { + s.AccessControlList = v + return s +} + +// SetBucketName sets the BucketName field's value. +func (s *Location) SetBucketName(v string) *Location { + s.BucketName = &v + return s +} + +// SetCannedACL sets the CannedACL field's value. +func (s *Location) SetCannedACL(v string) *Location { + s.CannedACL = &v + return s +} + +// SetEncryption sets the Encryption field's value. +func (s *Location) SetEncryption(v *Encryption) *Location { + s.Encryption = v + return s +} + +// SetPrefix sets the Prefix field's value. +func (s *Location) SetPrefix(v string) *Location { + s.Prefix = &v + return s +} + +// SetStorageClass sets the StorageClass field's value. +func (s *Location) SetStorageClass(v string) *Location { + s.StorageClass = &v + return s +} + +// SetTagging sets the Tagging field's value. +func (s *Location) SetTagging(v *Tagging) *Location { + s.Tagging = v + return s +} + +// SetUserMetadata sets the UserMetadata field's value. +func (s *Location) SetUserMetadata(v []*MetadataEntry) *Location { + s.UserMetadata = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/LoggingEnabled type LoggingEnabled struct { _ struct{} `type:"structure"` @@ -14819,7 +15620,39 @@ func (s *LoggingEnabled) SetTargetPrefix(v string) *LoggingEnabled { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetricsAndOperator +// A metadata key-value pair to store with an object. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetadataEntry +type MetadataEntry struct { + _ struct{} `type:"structure"` + + Name *string `type:"string"` + + Value *string `type:"string"` +} + +// String returns the string representation +func (s MetadataEntry) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s MetadataEntry) GoString() string { + return s.String() +} + +// SetName sets the Name field's value. +func (s *MetadataEntry) SetName(v string) *MetadataEntry { + s.Name = &v + return s +} + +// SetValue sets the Value field's value. +func (s *MetadataEntry) SetValue(v string) *MetadataEntry { + s.Value = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetricsAndOperator type MetricsAndOperator struct { _ struct{} `type:"structure"` @@ -14872,7 +15705,7 @@ func (s *MetricsAndOperator) SetTags(v []*Tag) *MetricsAndOperator { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetricsConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetricsConfiguration type MetricsConfiguration struct { _ struct{} `type:"structure"` @@ -14927,7 +15760,7 @@ func (s *MetricsConfiguration) SetId(v string) *MetricsConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetricsFilter +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MetricsFilter type MetricsFilter struct { _ struct{} `type:"structure"` @@ -14991,7 +15824,7 @@ func (s *MetricsFilter) SetTag(v *Tag) *MetricsFilter { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MultipartUpload +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/MultipartUpload type MultipartUpload struct { _ struct{} `type:"structure"` @@ -15064,7 +15897,7 @@ func (s *MultipartUpload) SetUploadId(v string) *MultipartUpload { // configuration action on a bucket that has versioning enabled (or suspended) // to request that Amazon S3 delete noncurrent object versions at a specific // period in the object's lifetime. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NoncurrentVersionExpiration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NoncurrentVersionExpiration type NoncurrentVersionExpiration struct { _ struct{} `type:"structure"` @@ -15096,7 +15929,7 @@ func (s *NoncurrentVersionExpiration) SetNoncurrentDays(v int64) *NoncurrentVers // versioning-enabled (or versioning is suspended), you can set this action // to request that Amazon S3 transition noncurrent object versions to the STANDARD_IA // or GLACIER storage class at a specific period in the object's lifetime. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NoncurrentVersionTransition +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NoncurrentVersionTransition type NoncurrentVersionTransition struct { _ struct{} `type:"structure"` @@ -15134,7 +15967,7 @@ func (s *NoncurrentVersionTransition) SetStorageClass(v string) *NoncurrentVersi // Container for specifying the notification configuration of the bucket. If // this element is empty, notifications are turned off on the bucket. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NotificationConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NotificationConfiguration type NotificationConfiguration struct { _ struct{} `type:"structure"` @@ -15213,7 +16046,7 @@ func (s *NotificationConfiguration) SetTopicConfigurations(v []*TopicConfigurati return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NotificationConfigurationDeprecated +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NotificationConfigurationDeprecated type NotificationConfigurationDeprecated struct { _ struct{} `type:"structure"` @@ -15254,7 +16087,7 @@ func (s *NotificationConfigurationDeprecated) SetTopicConfiguration(v *TopicConf // Container for object key name filtering rules. For information about key // name filtering, go to Configuring Event Notifications (http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NotificationConfigurationFilter +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/NotificationConfigurationFilter type NotificationConfigurationFilter struct { _ struct{} `type:"structure"` @@ -15278,7 +16111,7 @@ func (s *NotificationConfigurationFilter) SetKey(v *KeyFilter) *NotificationConf return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Object +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Object type Object struct { _ struct{} `type:"structure"` @@ -15342,7 +16175,7 @@ func (s *Object) SetStorageClass(v string) *Object { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ObjectIdentifier +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ObjectIdentifier type ObjectIdentifier struct { _ struct{} `type:"structure"` @@ -15393,7 +16226,7 @@ func (s *ObjectIdentifier) SetVersionId(v string) *ObjectIdentifier { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ObjectVersion +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ObjectVersion type ObjectVersion struct { _ struct{} `type:"structure"` @@ -15479,7 +16312,72 @@ func (s *ObjectVersion) SetVersionId(v string) *ObjectVersion { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Owner +// Describes the location where the restore job's output is stored. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/OutputLocation +type OutputLocation struct { + _ struct{} `type:"structure"` + + // Describes an S3 location that will receive the results of the restore request. + S3 *Location `type:"structure"` +} + +// String returns the string representation +func (s OutputLocation) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s OutputLocation) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *OutputLocation) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "OutputLocation"} + if s.S3 != nil { + if err := s.S3.Validate(); err != nil { + invalidParams.AddNested("S3", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetS3 sets the S3 field's value. +func (s *OutputLocation) SetS3(v *Location) *OutputLocation { + s.S3 = v + return s +} + +// Describes how results of the Select job are serialized. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/OutputSerialization +type OutputSerialization struct { + _ struct{} `type:"structure"` + + // Describes the serialization of CSV-encoded Select results. + CSV *CSVOutput `type:"structure"` +} + +// String returns the string representation +func (s OutputSerialization) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s OutputSerialization) GoString() string { + return s.String() +} + +// SetCSV sets the CSV field's value. +func (s *OutputSerialization) SetCSV(v *CSVOutput) *OutputSerialization { + s.CSV = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Owner type Owner struct { _ struct{} `type:"structure"` @@ -15510,7 +16408,7 @@ func (s *Owner) SetID(v string) *Owner { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Part +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Part type Part struct { _ struct{} `type:"structure"` @@ -15562,7 +16460,7 @@ func (s *Part) SetSize(v int64) *Part { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfigurationRequest type PutBucketAccelerateConfigurationInput struct { _ struct{} `type:"structure" payload:"AccelerateConfiguration"` @@ -15622,7 +16520,7 @@ func (s *PutBucketAccelerateConfigurationInput) getBucket() (v string) { return *s.Bucket } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAccelerateConfigurationOutput type PutBucketAccelerateConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -15637,7 +16535,7 @@ func (s PutBucketAccelerateConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAclRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAclRequest type PutBucketAclInput struct { _ struct{} `type:"structure" payload:"AccessControlPolicy"` @@ -15749,7 +16647,7 @@ func (s *PutBucketAclInput) SetGrantWriteACP(v string) *PutBucketAclInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAclOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAclOutput type PutBucketAclOutput struct { _ struct{} `type:"structure"` } @@ -15764,7 +16662,7 @@ func (s PutBucketAclOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfigurationRequest type PutBucketAnalyticsConfigurationInput struct { _ struct{} `type:"structure" payload:"AnalyticsConfiguration"` @@ -15843,7 +16741,7 @@ func (s *PutBucketAnalyticsConfigurationInput) SetId(v string) *PutBucketAnalyti return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketAnalyticsConfigurationOutput type PutBucketAnalyticsConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -15858,7 +16756,7 @@ func (s PutBucketAnalyticsConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCorsRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCorsRequest type PutBucketCorsInput struct { _ struct{} `type:"structure" payload:"CORSConfiguration"` @@ -15919,7 +16817,7 @@ func (s *PutBucketCorsInput) SetCORSConfiguration(v *CORSConfiguration) *PutBuck return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCorsOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketCorsOutput type PutBucketCorsOutput struct { _ struct{} `type:"structure"` } @@ -15934,7 +16832,89 @@ func (s PutBucketCorsOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketEncryptionRequest +type PutBucketEncryptionInput struct { + _ struct{} `type:"structure" payload:"ServerSideEncryptionConfiguration"` + + // The name of the bucket for which the server-side encryption configuration + // is set. + // + // Bucket is a required field + Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` + + // Container for server-side encryption configuration rules. Currently S3 supports + // one rule only. + // + // ServerSideEncryptionConfiguration is a required field + ServerSideEncryptionConfiguration *ServerSideEncryptionConfiguration `locationName:"ServerSideEncryptionConfiguration" type:"structure" required:"true" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` +} + +// String returns the string representation +func (s PutBucketEncryptionInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s PutBucketEncryptionInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *PutBucketEncryptionInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "PutBucketEncryptionInput"} + if s.Bucket == nil { + invalidParams.Add(request.NewErrParamRequired("Bucket")) + } + if s.ServerSideEncryptionConfiguration == nil { + invalidParams.Add(request.NewErrParamRequired("ServerSideEncryptionConfiguration")) + } + if s.ServerSideEncryptionConfiguration != nil { + if err := s.ServerSideEncryptionConfiguration.Validate(); err != nil { + invalidParams.AddNested("ServerSideEncryptionConfiguration", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetBucket sets the Bucket field's value. +func (s *PutBucketEncryptionInput) SetBucket(v string) *PutBucketEncryptionInput { + s.Bucket = &v + return s +} + +func (s *PutBucketEncryptionInput) getBucket() (v string) { + if s.Bucket == nil { + return v + } + return *s.Bucket +} + +// SetServerSideEncryptionConfiguration sets the ServerSideEncryptionConfiguration field's value. +func (s *PutBucketEncryptionInput) SetServerSideEncryptionConfiguration(v *ServerSideEncryptionConfiguration) *PutBucketEncryptionInput { + s.ServerSideEncryptionConfiguration = v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketEncryptionOutput +type PutBucketEncryptionOutput struct { + _ struct{} `type:"structure"` +} + +// String returns the string representation +func (s PutBucketEncryptionOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s PutBucketEncryptionOutput) GoString() string { + return s.String() +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfigurationRequest type PutBucketInventoryConfigurationInput struct { _ struct{} `type:"structure" payload:"InventoryConfiguration"` @@ -16013,7 +16993,7 @@ func (s *PutBucketInventoryConfigurationInput) SetInventoryConfiguration(v *Inve return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketInventoryConfigurationOutput type PutBucketInventoryConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -16028,7 +17008,7 @@ func (s PutBucketInventoryConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfigurationRequest type PutBucketLifecycleConfigurationInput struct { _ struct{} `type:"structure" payload:"LifecycleConfiguration"` @@ -16085,7 +17065,7 @@ func (s *PutBucketLifecycleConfigurationInput) SetLifecycleConfiguration(v *Buck return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleConfigurationOutput type PutBucketLifecycleConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -16100,7 +17080,7 @@ func (s PutBucketLifecycleConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleRequest type PutBucketLifecycleInput struct { _ struct{} `type:"structure" payload:"LifecycleConfiguration"` @@ -16157,7 +17137,7 @@ func (s *PutBucketLifecycleInput) SetLifecycleConfiguration(v *LifecycleConfigur return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLifecycleOutput type PutBucketLifecycleOutput struct { _ struct{} `type:"structure"` } @@ -16172,7 +17152,7 @@ func (s PutBucketLifecycleOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLoggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLoggingRequest type PutBucketLoggingInput struct { _ struct{} `type:"structure" payload:"BucketLoggingStatus"` @@ -16233,7 +17213,7 @@ func (s *PutBucketLoggingInput) SetBucketLoggingStatus(v *BucketLoggingStatus) * return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLoggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketLoggingOutput type PutBucketLoggingOutput struct { _ struct{} `type:"structure"` } @@ -16248,7 +17228,7 @@ func (s PutBucketLoggingOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfigurationRequest type PutBucketMetricsConfigurationInput struct { _ struct{} `type:"structure" payload:"MetricsConfiguration"` @@ -16327,7 +17307,7 @@ func (s *PutBucketMetricsConfigurationInput) SetMetricsConfiguration(v *MetricsC return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketMetricsConfigurationOutput type PutBucketMetricsConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -16342,7 +17322,7 @@ func (s PutBucketMetricsConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfigurationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfigurationRequest type PutBucketNotificationConfigurationInput struct { _ struct{} `type:"structure" payload:"NotificationConfiguration"` @@ -16406,7 +17386,7 @@ func (s *PutBucketNotificationConfigurationInput) SetNotificationConfiguration(v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfigurationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationConfigurationOutput type PutBucketNotificationConfigurationOutput struct { _ struct{} `type:"structure"` } @@ -16421,7 +17401,7 @@ func (s PutBucketNotificationConfigurationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationRequest type PutBucketNotificationInput struct { _ struct{} `type:"structure" payload:"NotificationConfiguration"` @@ -16477,7 +17457,7 @@ func (s *PutBucketNotificationInput) SetNotificationConfiguration(v *Notificatio return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketNotificationOutput type PutBucketNotificationOutput struct { _ struct{} `type:"structure"` } @@ -16492,13 +17472,17 @@ func (s PutBucketNotificationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicyRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicyRequest type PutBucketPolicyInput struct { _ struct{} `type:"structure" payload:"Policy"` // Bucket is a required field Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"` + // Set this parameter to true to confirm that you want to remove your permissions + // to change this bucket policy in the future. + ConfirmRemoveSelfBucketAccess *bool `location:"header" locationName:"x-amz-confirm-remove-self-bucket-access" type:"boolean"` + // The bucket policy as a JSON document. // // Policy is a required field @@ -16544,13 +17528,19 @@ func (s *PutBucketPolicyInput) getBucket() (v string) { return *s.Bucket } +// SetConfirmRemoveSelfBucketAccess sets the ConfirmRemoveSelfBucketAccess field's value. +func (s *PutBucketPolicyInput) SetConfirmRemoveSelfBucketAccess(v bool) *PutBucketPolicyInput { + s.ConfirmRemoveSelfBucketAccess = &v + return s +} + // SetPolicy sets the Policy field's value. func (s *PutBucketPolicyInput) SetPolicy(v string) *PutBucketPolicyInput { s.Policy = &v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicyOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketPolicyOutput type PutBucketPolicyOutput struct { _ struct{} `type:"structure"` } @@ -16565,7 +17555,7 @@ func (s PutBucketPolicyOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplicationRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplicationRequest type PutBucketReplicationInput struct { _ struct{} `type:"structure" payload:"ReplicationConfiguration"` @@ -16629,7 +17619,7 @@ func (s *PutBucketReplicationInput) SetReplicationConfiguration(v *ReplicationCo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplicationOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketReplicationOutput type PutBucketReplicationOutput struct { _ struct{} `type:"structure"` } @@ -16644,7 +17634,7 @@ func (s PutBucketReplicationOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPaymentRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPaymentRequest type PutBucketRequestPaymentInput struct { _ struct{} `type:"structure" payload:"RequestPaymentConfiguration"` @@ -16705,7 +17695,7 @@ func (s *PutBucketRequestPaymentInput) SetRequestPaymentConfiguration(v *Request return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPaymentOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketRequestPaymentOutput type PutBucketRequestPaymentOutput struct { _ struct{} `type:"structure"` } @@ -16720,7 +17710,7 @@ func (s PutBucketRequestPaymentOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTaggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTaggingRequest type PutBucketTaggingInput struct { _ struct{} `type:"structure" payload:"Tagging"` @@ -16781,7 +17771,7 @@ func (s *PutBucketTaggingInput) SetTagging(v *Tagging) *PutBucketTaggingInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTaggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketTaggingOutput type PutBucketTaggingOutput struct { _ struct{} `type:"structure"` } @@ -16796,7 +17786,7 @@ func (s PutBucketTaggingOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioningRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioningRequest type PutBucketVersioningInput struct { _ struct{} `type:"structure" payload:"VersioningConfiguration"` @@ -16862,7 +17852,7 @@ func (s *PutBucketVersioningInput) SetVersioningConfiguration(v *VersioningConfi return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioningOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketVersioningOutput type PutBucketVersioningOutput struct { _ struct{} `type:"structure"` } @@ -16877,7 +17867,7 @@ func (s PutBucketVersioningOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsiteRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsiteRequest type PutBucketWebsiteInput struct { _ struct{} `type:"structure" payload:"WebsiteConfiguration"` @@ -16938,7 +17928,7 @@ func (s *PutBucketWebsiteInput) SetWebsiteConfiguration(v *WebsiteConfiguration) return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsiteOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutBucketWebsiteOutput type PutBucketWebsiteOutput struct { _ struct{} `type:"structure"` } @@ -16953,7 +17943,7 @@ func (s PutBucketWebsiteOutput) GoString() string { return s.String() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAclRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAclRequest type PutObjectAclInput struct { _ struct{} `type:"structure" payload:"AccessControlPolicy"` @@ -17101,7 +18091,7 @@ func (s *PutObjectAclInput) SetVersionId(v string) *PutObjectAclInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAclOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectAclOutput type PutObjectAclOutput struct { _ struct{} `type:"structure"` @@ -17126,7 +18116,7 @@ func (s *PutObjectAclOutput) SetRequestCharged(v string) *PutObjectAclOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectRequest type PutObjectInput struct { _ struct{} `type:"structure" payload:"Body"` @@ -17159,6 +18149,9 @@ type PutObjectInput struct { // body cannot be determined automatically. ContentLength *int64 `location:"header" locationName:"Content-Length" type:"long"` + // The base64-encoded 128-bit MD5 digest of the part data. + ContentMD5 *string `location:"header" locationName:"Content-MD5" type:"string"` + // A standard MIME type describing the format of the object data. ContentType *string `location:"header" locationName:"Content-Type" type:"string"` @@ -17312,6 +18305,12 @@ func (s *PutObjectInput) SetContentLength(v int64) *PutObjectInput { return s } +// SetContentMD5 sets the ContentMD5 field's value. +func (s *PutObjectInput) SetContentMD5(v string) *PutObjectInput { + s.ContentMD5 = &v + return s +} + // SetContentType sets the ContentType field's value. func (s *PutObjectInput) SetContentType(v string) *PutObjectInput { s.ContentType = &v @@ -17421,7 +18420,7 @@ func (s *PutObjectInput) SetWebsiteRedirectLocation(v string) *PutObjectInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectOutput type PutObjectOutput struct { _ struct{} `type:"structure"` @@ -17516,7 +18515,7 @@ func (s *PutObjectOutput) SetVersionId(v string) *PutObjectOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTaggingRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTaggingRequest type PutObjectTaggingInput struct { _ struct{} `type:"structure" payload:"Tagging"` @@ -17600,7 +18599,7 @@ func (s *PutObjectTaggingInput) SetVersionId(v string) *PutObjectTaggingInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTaggingOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObjectTaggingOutput type PutObjectTaggingOutput struct { _ struct{} `type:"structure"` @@ -17625,7 +18624,7 @@ func (s *PutObjectTaggingOutput) SetVersionId(v string) *PutObjectTaggingOutput // Container for specifying an configuration when you want Amazon S3 to publish // events to an Amazon Simple Queue Service (Amazon SQS) queue. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/QueueConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/QueueConfiguration type QueueConfiguration struct { _ struct{} `type:"structure"` @@ -17697,7 +18696,7 @@ func (s *QueueConfiguration) SetQueueArn(v string) *QueueConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/QueueConfigurationDeprecated +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/QueueConfigurationDeprecated type QueueConfigurationDeprecated struct { _ struct{} `type:"structure"` @@ -17747,7 +18746,7 @@ func (s *QueueConfigurationDeprecated) SetQueue(v string) *QueueConfigurationDep return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Redirect +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Redirect type Redirect struct { _ struct{} `type:"structure"` @@ -17816,7 +18815,7 @@ func (s *Redirect) SetReplaceKeyWith(v string) *Redirect { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RedirectAllRequestsTo +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RedirectAllRequestsTo type RedirectAllRequestsTo struct { _ struct{} `type:"structure"` @@ -17867,7 +18866,7 @@ func (s *RedirectAllRequestsTo) SetProtocol(v string) *RedirectAllRequestsTo { // Container for replication rules. You can add as many as 1,000 rules. Total // replication configuration size can be up to 2 MB. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ReplicationConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ReplicationConfiguration type ReplicationConfiguration struct { _ struct{} `type:"structure"` @@ -17932,10 +18931,13 @@ func (s *ReplicationConfiguration) SetRules(v []*ReplicationRule) *ReplicationCo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ReplicationRule +// Container for information about a particular replication rule. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ReplicationRule type ReplicationRule struct { _ struct{} `type:"structure"` + // Container for replication destination information. + // // Destination is a required field Destination *Destination `type:"structure" required:"true"` @@ -17949,6 +18951,9 @@ type ReplicationRule struct { // Prefix is a required field Prefix *string `type:"string" required:"true"` + // Container for filters that define which source objects should be replicated. + SourceSelectionCriteria *SourceSelectionCriteria `type:"structure"` + // The rule is ignored if status is not Enabled. // // Status is a required field @@ -17982,6 +18987,11 @@ func (s *ReplicationRule) Validate() error { invalidParams.AddNested("Destination", err.(request.ErrInvalidParams)) } } + if s.SourceSelectionCriteria != nil { + if err := s.SourceSelectionCriteria.Validate(); err != nil { + invalidParams.AddNested("SourceSelectionCriteria", err.(request.ErrInvalidParams)) + } + } if invalidParams.Len() > 0 { return invalidParams @@ -18007,13 +19017,19 @@ func (s *ReplicationRule) SetPrefix(v string) *ReplicationRule { return s } +// SetSourceSelectionCriteria sets the SourceSelectionCriteria field's value. +func (s *ReplicationRule) SetSourceSelectionCriteria(v *SourceSelectionCriteria) *ReplicationRule { + s.SourceSelectionCriteria = v + return s +} + // SetStatus sets the Status field's value. func (s *ReplicationRule) SetStatus(v string) *ReplicationRule { s.Status = &v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RequestPaymentConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RequestPaymentConfiguration type RequestPaymentConfiguration struct { _ struct{} `type:"structure"` @@ -18052,7 +19068,7 @@ func (s *RequestPaymentConfiguration) SetPayer(v string) *RequestPaymentConfigur return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObjectRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObjectRequest type RestoreObjectInput struct { _ struct{} `type:"structure" payload:"RestoreRequest"` @@ -18068,6 +19084,7 @@ type RestoreObjectInput struct { // at http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string" enum:"RequestPayer"` + // Container for restore job parameters. RestoreRequest *RestoreRequest `locationName:"RestoreRequest" type:"structure" xmlURI:"http://s3.amazonaws.com/doc/2006-03-01/"` VersionId *string `location:"querystring" locationName:"versionId" type:"string"` @@ -18144,13 +19161,17 @@ func (s *RestoreObjectInput) SetVersionId(v string) *RestoreObjectInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObjectOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreObjectOutput type RestoreObjectOutput struct { _ struct{} `type:"structure"` // If present, indicates that the requester was successfully charged for the // request. RequestCharged *string `location:"header" locationName:"x-amz-request-charged" type:"string" enum:"RequestCharged"` + + // Indicates the path in the provided S3 output location where Select results + // will be restored to. + RestoreOutputPath *string `location:"header" locationName:"x-amz-restore-output-path" type:"string"` } // String returns the string representation @@ -18169,17 +19190,39 @@ func (s *RestoreObjectOutput) SetRequestCharged(v string) *RestoreObjectOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreRequest +// SetRestoreOutputPath sets the RestoreOutputPath field's value. +func (s *RestoreObjectOutput) SetRestoreOutputPath(v string) *RestoreObjectOutput { + s.RestoreOutputPath = &v + return s +} + +// Container for restore job parameters. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RestoreRequest type RestoreRequest struct { _ struct{} `type:"structure"` - // Lifetime of the active copy in days - // - // Days is a required field - Days *int64 `type:"integer" required:"true"` + // Lifetime of the active copy in days. Do not use with restores that specify + // OutputLocation. + Days *int64 `type:"integer"` - // Glacier related prameters pertaining to this job. + // The optional description for the job. + Description *string `type:"string"` + + // Glacier related parameters pertaining to this job. Do not use with restores + // that specify OutputLocation. GlacierJobParameters *GlacierJobParameters `type:"structure"` + + // Describes the location where the restore job's output is stored. + OutputLocation *OutputLocation `type:"structure"` + + // Describes the parameters for Select job types. + SelectParameters *SelectParameters `type:"structure"` + + // Glacier retrieval tier at which the restore will be processed. + Tier *string `type:"string" enum:"Tier"` + + // Type of restore request. + Type *string `type:"string" enum:"RestoreRequestType"` } // String returns the string representation @@ -18195,14 +19238,21 @@ func (s RestoreRequest) GoString() string { // Validate inspects the fields of the type to determine if they are valid. func (s *RestoreRequest) Validate() error { invalidParams := request.ErrInvalidParams{Context: "RestoreRequest"} - if s.Days == nil { - invalidParams.Add(request.NewErrParamRequired("Days")) - } if s.GlacierJobParameters != nil { if err := s.GlacierJobParameters.Validate(); err != nil { invalidParams.AddNested("GlacierJobParameters", err.(request.ErrInvalidParams)) } } + if s.OutputLocation != nil { + if err := s.OutputLocation.Validate(); err != nil { + invalidParams.AddNested("OutputLocation", err.(request.ErrInvalidParams)) + } + } + if s.SelectParameters != nil { + if err := s.SelectParameters.Validate(); err != nil { + invalidParams.AddNested("SelectParameters", err.(request.ErrInvalidParams)) + } + } if invalidParams.Len() > 0 { return invalidParams @@ -18216,13 +19266,43 @@ func (s *RestoreRequest) SetDays(v int64) *RestoreRequest { return s } +// SetDescription sets the Description field's value. +func (s *RestoreRequest) SetDescription(v string) *RestoreRequest { + s.Description = &v + return s +} + // SetGlacierJobParameters sets the GlacierJobParameters field's value. func (s *RestoreRequest) SetGlacierJobParameters(v *GlacierJobParameters) *RestoreRequest { s.GlacierJobParameters = v return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RoutingRule +// SetOutputLocation sets the OutputLocation field's value. +func (s *RestoreRequest) SetOutputLocation(v *OutputLocation) *RestoreRequest { + s.OutputLocation = v + return s +} + +// SetSelectParameters sets the SelectParameters field's value. +func (s *RestoreRequest) SetSelectParameters(v *SelectParameters) *RestoreRequest { + s.SelectParameters = v + return s +} + +// SetTier sets the Tier field's value. +func (s *RestoreRequest) SetTier(v string) *RestoreRequest { + s.Tier = &v + return s +} + +// SetType sets the Type field's value. +func (s *RestoreRequest) SetType(v string) *RestoreRequest { + s.Type = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/RoutingRule type RoutingRule struct { _ struct{} `type:"structure"` @@ -18275,7 +19355,7 @@ func (s *RoutingRule) SetRedirect(v *Redirect) *RoutingRule { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Rule +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Rule type Rule struct { _ struct{} `type:"structure"` @@ -18390,7 +19470,374 @@ func (s *Rule) SetTransition(v *Transition) *Rule { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/StorageClassAnalysis +// Specifies the use of SSE-KMS to encrypt delievered Inventory reports. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SSEKMS +type SSEKMS struct { + _ struct{} `locationName:"SSE-KMS" type:"structure"` + + // Specifies the ID of the AWS Key Management Service (KMS) master encryption + // key to use for encrypting Inventory reports. + // + // KeyId is a required field + KeyId *string `type:"string" required:"true"` +} + +// String returns the string representation +func (s SSEKMS) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SSEKMS) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *SSEKMS) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "SSEKMS"} + if s.KeyId == nil { + invalidParams.Add(request.NewErrParamRequired("KeyId")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetKeyId sets the KeyId field's value. +func (s *SSEKMS) SetKeyId(v string) *SSEKMS { + s.KeyId = &v + return s +} + +// Specifies the use of SSE-S3 to encrypt delievered Inventory reports. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SSES3 +type SSES3 struct { + _ struct{} `locationName:"SSE-S3" type:"structure"` +} + +// String returns the string representation +func (s SSES3) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SSES3) GoString() string { + return s.String() +} + +// Describes the parameters for Select job types. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SelectParameters +type SelectParameters struct { + _ struct{} `type:"structure"` + + // The expression that is used to query the object. + // + // Expression is a required field + Expression *string `type:"string" required:"true"` + + // The type of the provided expression (e.g., SQL). + // + // ExpressionType is a required field + ExpressionType *string `type:"string" required:"true" enum:"ExpressionType"` + + // Describes the serialization format of the object. + // + // InputSerialization is a required field + InputSerialization *InputSerialization `type:"structure" required:"true"` + + // Describes how the results of the Select job are serialized. + // + // OutputSerialization is a required field + OutputSerialization *OutputSerialization `type:"structure" required:"true"` +} + +// String returns the string representation +func (s SelectParameters) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SelectParameters) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *SelectParameters) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "SelectParameters"} + if s.Expression == nil { + invalidParams.Add(request.NewErrParamRequired("Expression")) + } + if s.ExpressionType == nil { + invalidParams.Add(request.NewErrParamRequired("ExpressionType")) + } + if s.InputSerialization == nil { + invalidParams.Add(request.NewErrParamRequired("InputSerialization")) + } + if s.OutputSerialization == nil { + invalidParams.Add(request.NewErrParamRequired("OutputSerialization")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetExpression sets the Expression field's value. +func (s *SelectParameters) SetExpression(v string) *SelectParameters { + s.Expression = &v + return s +} + +// SetExpressionType sets the ExpressionType field's value. +func (s *SelectParameters) SetExpressionType(v string) *SelectParameters { + s.ExpressionType = &v + return s +} + +// SetInputSerialization sets the InputSerialization field's value. +func (s *SelectParameters) SetInputSerialization(v *InputSerialization) *SelectParameters { + s.InputSerialization = v + return s +} + +// SetOutputSerialization sets the OutputSerialization field's value. +func (s *SelectParameters) SetOutputSerialization(v *OutputSerialization) *SelectParameters { + s.OutputSerialization = v + return s +} + +// Describes the default server-side encryption to apply to new objects in the +// bucket. If Put Object request does not specify any server-side encryption, +// this default encryption will be applied. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ServerSideEncryptionByDefault +type ServerSideEncryptionByDefault struct { + _ struct{} `type:"structure"` + + // KMS master key ID to use for the default encryption. This parameter is allowed + // if SSEAlgorithm is aws:kms. + KMSMasterKeyID *string `type:"string"` + + // Server-side encryption algorithm to use for the default encryption. + // + // SSEAlgorithm is a required field + SSEAlgorithm *string `type:"string" required:"true" enum:"ServerSideEncryption"` +} + +// String returns the string representation +func (s ServerSideEncryptionByDefault) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ServerSideEncryptionByDefault) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ServerSideEncryptionByDefault) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ServerSideEncryptionByDefault"} + if s.SSEAlgorithm == nil { + invalidParams.Add(request.NewErrParamRequired("SSEAlgorithm")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetKMSMasterKeyID sets the KMSMasterKeyID field's value. +func (s *ServerSideEncryptionByDefault) SetKMSMasterKeyID(v string) *ServerSideEncryptionByDefault { + s.KMSMasterKeyID = &v + return s +} + +// SetSSEAlgorithm sets the SSEAlgorithm field's value. +func (s *ServerSideEncryptionByDefault) SetSSEAlgorithm(v string) *ServerSideEncryptionByDefault { + s.SSEAlgorithm = &v + return s +} + +// Container for server-side encryption configuration rules. Currently S3 supports +// one rule only. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ServerSideEncryptionConfiguration +type ServerSideEncryptionConfiguration struct { + _ struct{} `type:"structure"` + + // Container for information about a particular server-side encryption configuration + // rule. + // + // Rules is a required field + Rules []*ServerSideEncryptionRule `locationName:"Rule" type:"list" flattened:"true" required:"true"` +} + +// String returns the string representation +func (s ServerSideEncryptionConfiguration) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ServerSideEncryptionConfiguration) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ServerSideEncryptionConfiguration) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ServerSideEncryptionConfiguration"} + if s.Rules == nil { + invalidParams.Add(request.NewErrParamRequired("Rules")) + } + if s.Rules != nil { + for i, v := range s.Rules { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Rules", i), err.(request.ErrInvalidParams)) + } + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetRules sets the Rules field's value. +func (s *ServerSideEncryptionConfiguration) SetRules(v []*ServerSideEncryptionRule) *ServerSideEncryptionConfiguration { + s.Rules = v + return s +} + +// Container for information about a particular server-side encryption configuration +// rule. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ServerSideEncryptionRule +type ServerSideEncryptionRule struct { + _ struct{} `type:"structure"` + + // Describes the default server-side encryption to apply to new objects in the + // bucket. If Put Object request does not specify any server-side encryption, + // this default encryption will be applied. + ApplyServerSideEncryptionByDefault *ServerSideEncryptionByDefault `type:"structure"` +} + +// String returns the string representation +func (s ServerSideEncryptionRule) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ServerSideEncryptionRule) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *ServerSideEncryptionRule) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ServerSideEncryptionRule"} + if s.ApplyServerSideEncryptionByDefault != nil { + if err := s.ApplyServerSideEncryptionByDefault.Validate(); err != nil { + invalidParams.AddNested("ApplyServerSideEncryptionByDefault", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetApplyServerSideEncryptionByDefault sets the ApplyServerSideEncryptionByDefault field's value. +func (s *ServerSideEncryptionRule) SetApplyServerSideEncryptionByDefault(v *ServerSideEncryptionByDefault) *ServerSideEncryptionRule { + s.ApplyServerSideEncryptionByDefault = v + return s +} + +// Container for filters that define which source objects should be replicated. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SourceSelectionCriteria +type SourceSelectionCriteria struct { + _ struct{} `type:"structure"` + + // Container for filter information of selection of KMS Encrypted S3 objects. + SseKmsEncryptedObjects *SseKmsEncryptedObjects `type:"structure"` +} + +// String returns the string representation +func (s SourceSelectionCriteria) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SourceSelectionCriteria) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *SourceSelectionCriteria) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "SourceSelectionCriteria"} + if s.SseKmsEncryptedObjects != nil { + if err := s.SseKmsEncryptedObjects.Validate(); err != nil { + invalidParams.AddNested("SseKmsEncryptedObjects", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetSseKmsEncryptedObjects sets the SseKmsEncryptedObjects field's value. +func (s *SourceSelectionCriteria) SetSseKmsEncryptedObjects(v *SseKmsEncryptedObjects) *SourceSelectionCriteria { + s.SseKmsEncryptedObjects = v + return s +} + +// Container for filter information of selection of KMS Encrypted S3 objects. +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/SseKmsEncryptedObjects +type SseKmsEncryptedObjects struct { + _ struct{} `type:"structure"` + + // The replication for KMS encrypted S3 objects is disabled if status is not + // Enabled. + // + // Status is a required field + Status *string `type:"string" required:"true" enum:"SseKmsEncryptedObjectsStatus"` +} + +// String returns the string representation +func (s SseKmsEncryptedObjects) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s SseKmsEncryptedObjects) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *SseKmsEncryptedObjects) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "SseKmsEncryptedObjects"} + if s.Status == nil { + invalidParams.Add(request.NewErrParamRequired("Status")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// SetStatus sets the Status field's value. +func (s *SseKmsEncryptedObjects) SetStatus(v string) *SseKmsEncryptedObjects { + s.Status = &v + return s +} + +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/StorageClassAnalysis type StorageClassAnalysis struct { _ struct{} `type:"structure"` @@ -18430,7 +19877,7 @@ func (s *StorageClassAnalysis) SetDataExport(v *StorageClassAnalysisDataExport) return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/StorageClassAnalysisDataExport +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/StorageClassAnalysisDataExport type StorageClassAnalysisDataExport struct { _ struct{} `type:"structure"` @@ -18488,7 +19935,7 @@ func (s *StorageClassAnalysisDataExport) SetOutputSchemaVersion(v string) *Stora return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Tag +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Tag type Tag struct { _ struct{} `type:"structure"` @@ -18544,7 +19991,7 @@ func (s *Tag) SetValue(v string) *Tag { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Tagging +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Tagging type Tagging struct { _ struct{} `type:"structure"` @@ -18591,7 +20038,7 @@ func (s *Tagging) SetTagSet(v []*Tag) *Tagging { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/TargetGrant +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/TargetGrant type TargetGrant struct { _ struct{} `type:"structure"` @@ -18640,7 +20087,7 @@ func (s *TargetGrant) SetPermission(v string) *TargetGrant { // Container for specifying the configuration when you want Amazon S3 to publish // events to an Amazon Simple Notification Service (Amazon SNS) topic. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/TopicConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/TopicConfiguration type TopicConfiguration struct { _ struct{} `type:"structure"` @@ -18712,7 +20159,7 @@ func (s *TopicConfiguration) SetTopicArn(v string) *TopicConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/TopicConfigurationDeprecated +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/TopicConfigurationDeprecated type TopicConfigurationDeprecated struct { _ struct{} `type:"structure"` @@ -18764,7 +20211,7 @@ func (s *TopicConfigurationDeprecated) SetTopic(v string) *TopicConfigurationDep return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Transition +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/Transition type Transition struct { _ struct{} `type:"structure"` @@ -18808,7 +20255,7 @@ func (s *Transition) SetStorageClass(v string) *Transition { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopyRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopyRequest type UploadPartCopyInput struct { _ struct{} `type:"structure"` @@ -19052,7 +20499,7 @@ func (s *UploadPartCopyInput) SetUploadId(v string) *UploadPartCopyInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopyOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartCopyOutput type UploadPartCopyOutput struct { _ struct{} `type:"structure" payload:"CopyPartResult"` @@ -19137,7 +20584,7 @@ func (s *UploadPartCopyOutput) SetServerSideEncryption(v string) *UploadPartCopy return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartRequest type UploadPartInput struct { _ struct{} `type:"structure" payload:"Body"` @@ -19153,6 +20600,9 @@ type UploadPartInput struct { // body cannot be determined automatically. ContentLength *int64 `location:"header" locationName:"Content-Length" type:"long"` + // The base64-encoded 128-bit MD5 digest of the part data. + ContentMD5 *string `location:"header" locationName:"Content-MD5" type:"string"` + // Object key for which the multipart upload was initiated. // // Key is a required field @@ -19252,6 +20702,12 @@ func (s *UploadPartInput) SetContentLength(v int64) *UploadPartInput { return s } +// SetContentMD5 sets the ContentMD5 field's value. +func (s *UploadPartInput) SetContentMD5(v string) *UploadPartInput { + s.ContentMD5 = &v + return s +} + // SetKey sets the Key field's value. func (s *UploadPartInput) SetKey(v string) *UploadPartInput { s.Key = &v @@ -19301,7 +20757,7 @@ func (s *UploadPartInput) SetUploadId(v string) *UploadPartInput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartOutput +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPartOutput type UploadPartOutput struct { _ struct{} `type:"structure"` @@ -19377,7 +20833,7 @@ func (s *UploadPartOutput) SetServerSideEncryption(v string) *UploadPartOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/VersioningConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/VersioningConfiguration type VersioningConfiguration struct { _ struct{} `type:"structure"` @@ -19412,7 +20868,7 @@ func (s *VersioningConfiguration) SetStatus(v string) *VersioningConfiguration { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/WebsiteConfiguration +// See also, https://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/WebsiteConfiguration type WebsiteConfiguration struct { _ struct{} `type:"structure"` @@ -19624,6 +21080,22 @@ const ( ExpirationStatusDisabled = "Disabled" ) +const ( + // ExpressionTypeSql is a ExpressionType enum value + ExpressionTypeSql = "SQL" +) + +const ( + // FileHeaderInfoUse is a FileHeaderInfo enum value + FileHeaderInfoUse = "USE" + + // FileHeaderInfoIgnore is a FileHeaderInfo enum value + FileHeaderInfoIgnore = "IGNORE" + + // FileHeaderInfoNone is a FileHeaderInfo enum value + FileHeaderInfoNone = "NONE" +) + const ( // FilterRuleNamePrefix is a FilterRuleName enum value FilterRuleNamePrefix = "prefix" @@ -19635,6 +21107,9 @@ const ( const ( // InventoryFormatCsv is a InventoryFormat enum value InventoryFormatCsv = "CSV" + + // InventoryFormatOrc is a InventoryFormat enum value + InventoryFormatOrc = "ORC" ) const ( @@ -19671,6 +21146,9 @@ const ( // InventoryOptionalFieldReplicationStatus is a InventoryOptionalField enum value InventoryOptionalFieldReplicationStatus = "ReplicationStatus" + + // InventoryOptionalFieldEncryptionStatus is a InventoryOptionalField enum value + InventoryOptionalFieldEncryptionStatus = "EncryptionStatus" ) const ( @@ -19736,6 +21214,11 @@ const ( ObjectVersionStorageClassStandard = "STANDARD" ) +const ( + // OwnerOverrideDestination is a OwnerOverride enum value + OwnerOverrideDestination = "Destination" +) + const ( // PayerRequester is a Payer enum value PayerRequester = "Requester" @@ -19769,6 +21252,14 @@ const ( ProtocolHttps = "https" ) +const ( + // QuoteFieldsAlways is a QuoteFields enum value + QuoteFieldsAlways = "ALWAYS" + + // QuoteFieldsAsneeded is a QuoteFields enum value + QuoteFieldsAsneeded = "ASNEEDED" +) + const ( // ReplicationRuleStatusEnabled is a ReplicationRuleStatus enum value ReplicationRuleStatusEnabled = "Enabled" @@ -19807,6 +21298,11 @@ const ( RequestPayerRequester = "requester" ) +const ( + // RestoreRequestTypeSelect is a RestoreRequestType enum value + RestoreRequestTypeSelect = "SELECT" +) + const ( // ServerSideEncryptionAes256 is a ServerSideEncryption enum value ServerSideEncryptionAes256 = "AES256" @@ -19815,6 +21311,14 @@ const ( ServerSideEncryptionAwsKms = "aws:kms" ) +const ( + // SseKmsEncryptedObjectsStatusEnabled is a SseKmsEncryptedObjectsStatus enum value + SseKmsEncryptedObjectsStatusEnabled = "Enabled" + + // SseKmsEncryptedObjectsStatusDisabled is a SseKmsEncryptedObjectsStatus enum value + SseKmsEncryptedObjectsStatusDisabled = "Disabled" +) + const ( // StorageClassStandard is a StorageClass enum value StorageClassStandard = "STANDARD" diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go b/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go index f045fd0db9d..0def02255ac 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go +++ b/vendor/github.com/aws/aws-sdk-go/service/s3/doc.go @@ -10,69 +10,17 @@ // // Using the Client // -// To use the client for Amazon Simple Storage Service you will first need -// to create a new instance of it. +// To contact Amazon Simple Storage Service with the SDK use the New function to create +// a new service client. With that client you can make API requests to the service. +// These clients are safe to use concurrently. // -// When creating a client for an AWS service you'll first need to have a Session -// already created. The Session provides configuration that can be shared -// between multiple service clients. Additional configuration can be applied to -// the Session and service's client when they are constructed. The aws package's -// Config type contains several fields such as Region for the AWS Region the -// client should make API requests too. The optional Config value can be provided -// as the variadic argument for Sessions and client creation. -// -// Once the service's client is created you can use it to make API requests the -// AWS service. These clients are safe to use concurrently. -// -// // Create a session to share configuration, and load external configuration. -// sess := session.Must(session.NewSession()) -// -// // Create the service's client with the session. -// svc := s3.New(sess) -// -// See the SDK's documentation for more information on how to use service clients. +// See the SDK's documentation for more information on how to use the SDK. // https://docs.aws.amazon.com/sdk-for-go/api/ // -// See aws package's Config type for more information on configuration options. +// See aws.Config documentation for more information on configuring SDK clients. // https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config // // See the Amazon Simple Storage Service client S3 for more -// information on creating the service's client. +// information on creating client for this service. // https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#New -// -// Once the client is created you can make an API request to the service. -// Each API method takes a input parameter, and returns the service response -// and an error. -// -// The API method will document which error codes the service can be returned -// by the operation if the service models the API operation's errors. These -// errors will also be available as const strings prefixed with "ErrCode". -// -// result, err := svc.AbortMultipartUpload(params) -// if err != nil { -// // Cast err to awserr.Error to handle specific error codes. -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == { -// // Specific error code handling -// } -// return err -// } -// -// fmt.Println("AbortMultipartUpload result:") -// fmt.Println(result) -// -// Using the Client with Context -// -// The service's client also provides methods to make API requests with a Context -// value. This allows you to control the timeout, and cancellation of pending -// requests. These methods also take request Option as variadic parameter to apply -// additional configuration to the API request. -// -// ctx := context.Background() -// -// result, err := svc.AbortMultipartUploadWithContext(ctx, params) -// -// See the request package documentation for more information on using Context pattern -// with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/ package s3 diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go b/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go index b794a63ba20..39b912c260b 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go +++ b/vendor/github.com/aws/aws-sdk-go/service/s3/doc_custom.go @@ -35,7 +35,7 @@ // // The s3manager package's Downloader provides concurrently downloading of Objects // from S3. The Downloader will write S3 Object content with an io.WriterAt. -// Once the Downloader instance is created you can call Upload concurrently from +// Once the Downloader instance is created you can call Download concurrently from // multiple goroutines safely. // // // The session the S3 Downloader will use @@ -56,7 +56,7 @@ // Key: aws.String(myString), // }) // if err != nil { -// return fmt.Errorf("failed to upload file, %v", err) +// return fmt.Errorf("failed to download file, %v", err) // } // fmt.Printf("file downloaded, %d bytes\n", n) // diff --git a/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go b/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go index cccfa8c2b3f..2596c694b50 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go +++ b/vendor/github.com/aws/aws-sdk-go/service/s3/waiters.go @@ -11,7 +11,7 @@ import ( // WaitUntilBucketExists uses the Amazon S3 API operation // HeadBucket to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *S3) WaitUntilBucketExists(input *HeadBucketInput) error { return c.WaitUntilBucketExistsWithContext(aws.BackgroundContext(), input) @@ -72,7 +72,7 @@ func (c *S3) WaitUntilBucketExistsWithContext(ctx aws.Context, input *HeadBucket // WaitUntilBucketNotExists uses the Amazon S3 API operation // HeadBucket to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *S3) WaitUntilBucketNotExists(input *HeadBucketInput) error { return c.WaitUntilBucketNotExistsWithContext(aws.BackgroundContext(), input) @@ -118,7 +118,7 @@ func (c *S3) WaitUntilBucketNotExistsWithContext(ctx aws.Context, input *HeadBuc // WaitUntilObjectExists uses the Amazon S3 API operation // HeadObject to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *S3) WaitUntilObjectExists(input *HeadObjectInput) error { return c.WaitUntilObjectExistsWithContext(aws.BackgroundContext(), input) @@ -169,7 +169,7 @@ func (c *S3) WaitUntilObjectExistsWithContext(ctx aws.Context, input *HeadObject // WaitUntilObjectNotExists uses the Amazon S3 API operation // HeadObject to wait for a condition to be met before returning. -// If the condition is not meet within the max attempt window an error will +// If the condition is not met within the max attempt window, an error will // be returned. func (c *S3) WaitUntilObjectNotExists(input *HeadObjectInput) error { return c.WaitUntilObjectNotExistsWithContext(aws.BackgroundContext(), input) diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/api.go b/vendor/github.com/aws/aws-sdk-go/service/sts/api.go index e5c105fed80..23f0a06db8a 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/api.go +++ b/vendor/github.com/aws/aws-sdk-go/service/sts/api.go @@ -14,19 +14,18 @@ const opAssumeRole = "AssumeRole" // AssumeRoleRequest generates a "aws/request.Request" representing the // client's request for the AssumeRole operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssumeRole for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssumeRole method directly -// instead. +// See AssumeRole for more information on using the AssumeRole +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssumeRoleRequest method. // req, resp := client.AssumeRoleRequest(params) @@ -36,7 +35,7 @@ const opAssumeRole = "AssumeRole" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, output *AssumeRoleOutput) { op := &request.Operation{ Name: opAssumeRole, @@ -169,7 +168,7 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o // and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRole func (c *STS) AssumeRole(input *AssumeRoleInput) (*AssumeRoleOutput, error) { req, out := c.AssumeRoleRequest(input) return out, req.Send() @@ -195,19 +194,18 @@ const opAssumeRoleWithSAML = "AssumeRoleWithSAML" // AssumeRoleWithSAMLRequest generates a "aws/request.Request" representing the // client's request for the AssumeRoleWithSAML operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssumeRoleWithSAML for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssumeRoleWithSAML method directly -// instead. +// See AssumeRoleWithSAML for more information on using the AssumeRoleWithSAML +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssumeRoleWithSAMLRequest method. // req, resp := client.AssumeRoleWithSAMLRequest(params) @@ -217,7 +215,7 @@ const opAssumeRoleWithSAML = "AssumeRoleWithSAML" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *request.Request, output *AssumeRoleWithSAMLOutput) { op := &request.Operation{ Name: opAssumeRoleWithSAML, @@ -343,7 +341,7 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML func (c *STS) AssumeRoleWithSAML(input *AssumeRoleWithSAMLInput) (*AssumeRoleWithSAMLOutput, error) { req, out := c.AssumeRoleWithSAMLRequest(input) return out, req.Send() @@ -369,19 +367,18 @@ const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity" // AssumeRoleWithWebIdentityRequest generates a "aws/request.Request" representing the // client's request for the AssumeRoleWithWebIdentity operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See AssumeRoleWithWebIdentity for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the AssumeRoleWithWebIdentity method directly -// instead. +// See AssumeRoleWithWebIdentity for more information on using the AssumeRoleWithWebIdentity +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the AssumeRoleWithWebIdentityRequest method. // req, resp := client.AssumeRoleWithWebIdentityRequest(params) @@ -391,7 +388,7 @@ const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityInput) (req *request.Request, output *AssumeRoleWithWebIdentityOutput) { op := &request.Operation{ Name: opAssumeRoleWithWebIdentity, @@ -546,7 +543,7 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity func (c *STS) AssumeRoleWithWebIdentity(input *AssumeRoleWithWebIdentityInput) (*AssumeRoleWithWebIdentityOutput, error) { req, out := c.AssumeRoleWithWebIdentityRequest(input) return out, req.Send() @@ -572,19 +569,18 @@ const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage" // DecodeAuthorizationMessageRequest generates a "aws/request.Request" representing the // client's request for the DecodeAuthorizationMessage operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See DecodeAuthorizationMessage for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the DecodeAuthorizationMessage method directly -// instead. +// See DecodeAuthorizationMessage for more information on using the DecodeAuthorizationMessage +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the DecodeAuthorizationMessageRequest method. // req, resp := client.DecodeAuthorizationMessageRequest(params) @@ -594,7 +590,7 @@ const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessageInput) (req *request.Request, output *DecodeAuthorizationMessageOutput) { op := &request.Operation{ Name: opDecodeAuthorizationMessage, @@ -659,7 +655,7 @@ func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessag // invalid. This can happen if the token contains invalid characters, such as // linebreaks. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessage func (c *STS) DecodeAuthorizationMessage(input *DecodeAuthorizationMessageInput) (*DecodeAuthorizationMessageOutput, error) { req, out := c.DecodeAuthorizationMessageRequest(input) return out, req.Send() @@ -685,19 +681,18 @@ const opGetCallerIdentity = "GetCallerIdentity" // GetCallerIdentityRequest generates a "aws/request.Request" representing the // client's request for the GetCallerIdentity operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetCallerIdentity for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetCallerIdentity method directly -// instead. +// See GetCallerIdentity for more information on using the GetCallerIdentity +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetCallerIdentityRequest method. // req, resp := client.GetCallerIdentityRequest(params) @@ -707,7 +702,7 @@ const opGetCallerIdentity = "GetCallerIdentity" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *request.Request, output *GetCallerIdentityOutput) { op := &request.Operation{ Name: opGetCallerIdentity, @@ -735,7 +730,7 @@ func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *requ // // See the AWS API reference guide for AWS Security Token Service's // API operation GetCallerIdentity for usage and error information. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentity func (c *STS) GetCallerIdentity(input *GetCallerIdentityInput) (*GetCallerIdentityOutput, error) { req, out := c.GetCallerIdentityRequest(input) return out, req.Send() @@ -761,19 +756,18 @@ const opGetFederationToken = "GetFederationToken" // GetFederationTokenRequest generates a "aws/request.Request" representing the // client's request for the GetFederationToken operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetFederationToken for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetFederationToken method directly -// instead. +// See GetFederationToken for more information on using the GetFederationToken +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetFederationTokenRequest method. // req, resp := client.GetFederationTokenRequest(params) @@ -783,7 +777,7 @@ const opGetFederationToken = "GetFederationToken" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *request.Request, output *GetFederationTokenOutput) { op := &request.Operation{ Name: opGetFederationToken, @@ -905,7 +899,7 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken func (c *STS) GetFederationToken(input *GetFederationTokenInput) (*GetFederationTokenOutput, error) { req, out := c.GetFederationTokenRequest(input) return out, req.Send() @@ -931,19 +925,18 @@ const opGetSessionToken = "GetSessionToken" // GetSessionTokenRequest generates a "aws/request.Request" representing the // client's request for the GetSessionToken operation. The "output" return -// value can be used to capture response data after the request's "Send" method -// is called. +// value will be populated with the request's response once the request complets +// successfuly. // -// See GetSessionToken for usage and error information. +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. // -// Creating a request object using this method should be used when you want to inject -// custom logic into the request's lifecycle using a custom handler, or if you want to -// access properties on the request object before or after sending the request. If -// you just want the service response, call the GetSessionToken method directly -// instead. +// See GetSessionToken for more information on using the GetSessionToken +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. // -// Note: You must call the "Send" method on the returned request object in order -// to execute the request. // // // Example sending a request using the GetSessionTokenRequest method. // req, resp := client.GetSessionTokenRequest(params) @@ -953,7 +946,7 @@ const opGetSessionToken = "GetSessionToken" // fmt.Println(resp) // } // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.Request, output *GetSessionTokenOutput) { op := &request.Operation{ Name: opGetSessionToken, @@ -1034,7 +1027,7 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request. // and Deactivating AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken func (c *STS) GetSessionToken(input *GetSessionTokenInput) (*GetSessionTokenOutput, error) { req, out := c.GetSessionTokenRequest(input) return out, req.Send() @@ -1056,7 +1049,7 @@ func (c *STS) GetSessionTokenWithContext(ctx aws.Context, input *GetSessionToken return out, req.Send() } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleRequest type AssumeRoleInput struct { _ struct{} `type:"structure"` @@ -1248,7 +1241,7 @@ func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput { // Contains the response to a successful AssumeRole request, including temporary // AWS credentials that can be used to make AWS requests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleResponse type AssumeRoleOutput struct { _ struct{} `type:"structure"` @@ -1302,7 +1295,7 @@ func (s *AssumeRoleOutput) SetPackedPolicySize(v int64) *AssumeRoleOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAMLRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAMLRequest type AssumeRoleWithSAMLInput struct { _ struct{} `type:"structure"` @@ -1443,7 +1436,7 @@ func (s *AssumeRoleWithSAMLInput) SetSAMLAssertion(v string) *AssumeRoleWithSAML // Contains the response to a successful AssumeRoleWithSAML request, including // temporary AWS credentials that can be used to make AWS requests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAMLResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAMLResponse type AssumeRoleWithSAMLOutput struct { _ struct{} `type:"structure"` @@ -1555,7 +1548,7 @@ func (s *AssumeRoleWithSAMLOutput) SetSubjectType(v string) *AssumeRoleWithSAMLO return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentityRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentityRequest type AssumeRoleWithWebIdentityInput struct { _ struct{} `type:"structure"` @@ -1718,7 +1711,7 @@ func (s *AssumeRoleWithWebIdentityInput) SetWebIdentityToken(v string) *AssumeRo // Contains the response to a successful AssumeRoleWithWebIdentity request, // including temporary AWS credentials that can be used to make AWS requests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentityResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentityResponse type AssumeRoleWithWebIdentityOutput struct { _ struct{} `type:"structure"` @@ -1811,7 +1804,7 @@ func (s *AssumeRoleWithWebIdentityOutput) SetSubjectFromWebIdentityToken(v strin // The identifiers for the temporary security credentials that the operation // returns. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser type AssumedRoleUser struct { _ struct{} `type:"structure"` @@ -1854,7 +1847,7 @@ func (s *AssumedRoleUser) SetAssumedRoleId(v string) *AssumedRoleUser { } // AWS credentials for API authentication. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/Credentials +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/Credentials type Credentials struct { _ struct{} `type:"structure"` @@ -1913,7 +1906,7 @@ func (s *Credentials) SetSessionToken(v string) *Credentials { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessageRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessageRequest type DecodeAuthorizationMessageInput struct { _ struct{} `type:"structure"` @@ -1958,7 +1951,7 @@ func (s *DecodeAuthorizationMessageInput) SetEncodedMessage(v string) *DecodeAut // A document that contains additional information about the authorization status // of a request from an encoded message that is returned in response to an AWS // request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessageResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/DecodeAuthorizationMessageResponse type DecodeAuthorizationMessageOutput struct { _ struct{} `type:"structure"` @@ -1983,7 +1976,7 @@ func (s *DecodeAuthorizationMessageOutput) SetDecodedMessage(v string) *DecodeAu } // Identifiers for the federated user that is associated with the credentials. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/FederatedUser +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/FederatedUser type FederatedUser struct { _ struct{} `type:"structure"` @@ -2024,7 +2017,7 @@ func (s *FederatedUser) SetFederatedUserId(v string) *FederatedUser { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentityRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentityRequest type GetCallerIdentityInput struct { _ struct{} `type:"structure"` } @@ -2041,7 +2034,7 @@ func (s GetCallerIdentityInput) GoString() string { // Contains the response to a successful GetCallerIdentity request, including // information about the entity making the request. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentityResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetCallerIdentityResponse type GetCallerIdentityOutput struct { _ struct{} `type:"structure"` @@ -2087,7 +2080,7 @@ func (s *GetCallerIdentityOutput) SetUserId(v string) *GetCallerIdentityOutput { return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationTokenRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationTokenRequest type GetFederationTokenInput struct { _ struct{} `type:"structure"` @@ -2196,7 +2189,7 @@ func (s *GetFederationTokenInput) SetPolicy(v string) *GetFederationTokenInput { // Contains the response to a successful GetFederationToken request, including // temporary AWS credentials that can be used to make AWS requests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationTokenResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationTokenResponse type GetFederationTokenOutput struct { _ struct{} `type:"structure"` @@ -2249,7 +2242,7 @@ func (s *GetFederationTokenOutput) SetPackedPolicySize(v int64) *GetFederationTo return s } -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionTokenRequest +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionTokenRequest type GetSessionTokenInput struct { _ struct{} `type:"structure"` @@ -2334,7 +2327,7 @@ func (s *GetSessionTokenInput) SetTokenCode(v string) *GetSessionTokenInput { // Contains the response to a successful GetSessionToken request, including // temporary AWS credentials that can be used to make AWS requests. -// Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionTokenResponse +// See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionTokenResponse type GetSessionTokenOutput struct { _ struct{} `type:"structure"` diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go b/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go index d2af518cfad..ef681ab0c63 100644 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go +++ b/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go @@ -56,69 +56,17 @@ // // Using the Client // -// To use the client for AWS Security Token Service you will first need -// to create a new instance of it. +// To contact AWS Security Token Service with the SDK use the New function to create +// a new service client. With that client you can make API requests to the service. +// These clients are safe to use concurrently. // -// When creating a client for an AWS service you'll first need to have a Session -// already created. The Session provides configuration that can be shared -// between multiple service clients. Additional configuration can be applied to -// the Session and service's client when they are constructed. The aws package's -// Config type contains several fields such as Region for the AWS Region the -// client should make API requests too. The optional Config value can be provided -// as the variadic argument for Sessions and client creation. -// -// Once the service's client is created you can use it to make API requests the -// AWS service. These clients are safe to use concurrently. -// -// // Create a session to share configuration, and load external configuration. -// sess := session.Must(session.NewSession()) -// -// // Create the service's client with the session. -// svc := sts.New(sess) -// -// See the SDK's documentation for more information on how to use service clients. +// See the SDK's documentation for more information on how to use the SDK. // https://docs.aws.amazon.com/sdk-for-go/api/ // -// See aws package's Config type for more information on configuration options. +// See aws.Config documentation for more information on configuring SDK clients. // https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config // // See the AWS Security Token Service client STS for more -// information on creating the service's client. +// information on creating client for this service. // https://docs.aws.amazon.com/sdk-for-go/api/service/sts/#New -// -// Once the client is created you can make an API request to the service. -// Each API method takes a input parameter, and returns the service response -// and an error. -// -// The API method will document which error codes the service can be returned -// by the operation if the service models the API operation's errors. These -// errors will also be available as const strings prefixed with "ErrCode". -// -// result, err := svc.AssumeRole(params) -// if err != nil { -// // Cast err to awserr.Error to handle specific error codes. -// aerr, ok := err.(awserr.Error) -// if ok && aerr.Code() == { -// // Specific error code handling -// } -// return err -// } -// -// fmt.Println("AssumeRole result:") -// fmt.Println(result) -// -// Using the Client with Context -// -// The service's client also provides methods to make API requests with a Context -// value. This allows you to control the timeout, and cancellation of pending -// requests. These methods also take request Option as variadic parameter to apply -// additional configuration to the API request. -// -// ctx := context.Background() -// -// result, err := svc.AssumeRoleWithContext(ctx, params) -// -// See the request package documentation for more information on using Context pattern -// with the SDK. -// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/ package sts diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go deleted file mode 100644 index 99531316c95..00000000000 --- a/vendor/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go +++ /dev/null @@ -1,92 +0,0 @@ -// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. - -// Package stsiface provides an interface to enable mocking the AWS Security Token Service service client -// for testing your code. -// -// It is important to note that this interface will have breaking changes -// when the service model is updated and adds new API operations, paginators, -// and waiters. -package stsiface - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/sts" -) - -// STSAPI provides an interface to enable mocking the -// sts.STS service client's API operation, -// paginators, and waiters. This make unit testing your code that calls out -// to the SDK's service client's calls easier. -// -// The best way to use this interface is so the SDK's service client's calls -// can be stubbed out for unit testing your code with the SDK without needing -// to inject custom request handlers into the the SDK's request pipeline. -// -// // myFunc uses an SDK service client to make a request to -// // AWS Security Token Service. -// func myFunc(svc stsiface.STSAPI) bool { -// // Make svc.AssumeRole request -// } -// -// func main() { -// sess := session.New() -// svc := sts.New(sess) -// -// myFunc(svc) -// } -// -// In your _test.go file: -// -// // Define a mock struct to be used in your unit tests of myFunc. -// type mockSTSClient struct { -// stsiface.STSAPI -// } -// func (m *mockSTSClient) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) { -// // mock response/functionality -// } -// -// func TestMyFunc(t *testing.T) { -// // Setup Test -// mockSvc := &mockSTSClient{} -// -// myfunc(mockSvc) -// -// // Verify myFunc's functionality -// } -// -// It is important to note that this interface will have breaking changes -// when the service model is updated and adds new API operations, paginators, -// and waiters. Its suggested to use the pattern above for testing, or using -// tooling to generate mocks to satisfy the interfaces. -type STSAPI interface { - AssumeRole(*sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) - AssumeRoleWithContext(aws.Context, *sts.AssumeRoleInput, ...request.Option) (*sts.AssumeRoleOutput, error) - AssumeRoleRequest(*sts.AssumeRoleInput) (*request.Request, *sts.AssumeRoleOutput) - - AssumeRoleWithSAML(*sts.AssumeRoleWithSAMLInput) (*sts.AssumeRoleWithSAMLOutput, error) - AssumeRoleWithSAMLWithContext(aws.Context, *sts.AssumeRoleWithSAMLInput, ...request.Option) (*sts.AssumeRoleWithSAMLOutput, error) - AssumeRoleWithSAMLRequest(*sts.AssumeRoleWithSAMLInput) (*request.Request, *sts.AssumeRoleWithSAMLOutput) - - AssumeRoleWithWebIdentity(*sts.AssumeRoleWithWebIdentityInput) (*sts.AssumeRoleWithWebIdentityOutput, error) - AssumeRoleWithWebIdentityWithContext(aws.Context, *sts.AssumeRoleWithWebIdentityInput, ...request.Option) (*sts.AssumeRoleWithWebIdentityOutput, error) - AssumeRoleWithWebIdentityRequest(*sts.AssumeRoleWithWebIdentityInput) (*request.Request, *sts.AssumeRoleWithWebIdentityOutput) - - DecodeAuthorizationMessage(*sts.DecodeAuthorizationMessageInput) (*sts.DecodeAuthorizationMessageOutput, error) - DecodeAuthorizationMessageWithContext(aws.Context, *sts.DecodeAuthorizationMessageInput, ...request.Option) (*sts.DecodeAuthorizationMessageOutput, error) - DecodeAuthorizationMessageRequest(*sts.DecodeAuthorizationMessageInput) (*request.Request, *sts.DecodeAuthorizationMessageOutput) - - GetCallerIdentity(*sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) - GetCallerIdentityWithContext(aws.Context, *sts.GetCallerIdentityInput, ...request.Option) (*sts.GetCallerIdentityOutput, error) - GetCallerIdentityRequest(*sts.GetCallerIdentityInput) (*request.Request, *sts.GetCallerIdentityOutput) - - GetFederationToken(*sts.GetFederationTokenInput) (*sts.GetFederationTokenOutput, error) - GetFederationTokenWithContext(aws.Context, *sts.GetFederationTokenInput, ...request.Option) (*sts.GetFederationTokenOutput, error) - GetFederationTokenRequest(*sts.GetFederationTokenInput) (*request.Request, *sts.GetFederationTokenOutput) - - GetSessionToken(*sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error) - GetSessionTokenWithContext(aws.Context, *sts.GetSessionTokenInput, ...request.Option) (*sts.GetSessionTokenOutput, error) - GetSessionTokenRequest(*sts.GetSessionTokenInput) (*request.Request, *sts.GetSessionTokenOutput) -} - -var _ STSAPI = (*sts.STS)(nil) diff --git a/vendor/github.com/benbjohnson/clock/README.md b/vendor/github.com/benbjohnson/clock/README.md deleted file mode 100644 index 5d4f4fe72e7..00000000000 --- a/vendor/github.com/benbjohnson/clock/README.md +++ /dev/null @@ -1,104 +0,0 @@ -clock [![Build Status](https://drone.io/github.com/benbjohnson/clock/status.png)](https://drone.io/github.com/benbjohnson/clock/latest) [![Coverage Status](https://coveralls.io/repos/benbjohnson/clock/badge.png?branch=master)](https://coveralls.io/r/benbjohnson/clock?branch=master) [![GoDoc](https://godoc.org/github.com/benbjohnson/clock?status.png)](https://godoc.org/github.com/benbjohnson/clock) ![Project status](http://img.shields.io/status/experimental.png?color=red) -===== - -Clock is a small library for mocking time in Go. It provides an interface -around the standard library's [`time`][time] package so that the application -can use the realtime clock while tests can use the mock clock. - -[time]: http://golang.org/pkg/time/ - - -## Usage - -### Realtime Clock - -Your application can maintain a `Clock` variable that will allow realtime and -mock clocks to be interchangable. For example, if you had an `Application` type: - -```go -import "github.com/benbjohnson/clock" - -type Application struct { - Clock clock.Clock -} -``` - -You could initialize it to use the realtime clock like this: - -```go -var app Application -app.Clock = clock.New() -... -``` - -Then all timers and time-related functionality should be performed from the -`Clock` variable. - - -### Mocking time - -In your tests, you will want to use a `Mock` clock: - -```go -import ( - "testing" - - "github.com/benbjohnson/clock" -) - -func TestApplication_DoSomething(t *testing.T) { - mock := clock.NewMock() - app := Application{Clock: mock} - ... -} -``` - -Now that you've initialized your application to use the mock clock, you can -adjust the time programmatically. The mock clock always starts from the Unix -epoch (midnight, Jan 1, 1970 UTC). - - -### Controlling time - -The mock clock provides the same functions that the standard library's `time` -package provides. For example, to find the current time, you use the `Now()` -function: - -```go -mock := clock.NewMock() - -// Find the current time. -mock.Now().UTC() // 1970-01-01 00:00:00 +0000 UTC - -// Move the clock forward. -mock.Add(2 * time.Hour) - -// Check the time again. It's 2 hours later! -mock.Now().UTC() // 1970-01-01 02:00:00 +0000 UTC -``` - -Timers and Tickers are also controlled by this same mock clock. They will only -execute when the clock is moved forward: - -``` -mock := clock.NewMock() -count := 0 - -// Kick off a timer to increment every 1 mock second. -go func() { - ticker := clock.Ticker(1 * time.Second) - for { - <-ticker.C - count++ - } -}() -runtime.Gosched() - -// Move the clock forward 10 second. -mock.Add(10 * time.Second) - -// This prints 10. -fmt.Println(count) -``` - - diff --git a/vendor/github.com/benbjohnson/clock/clock.go b/vendor/github.com/benbjohnson/clock/clock.go index 518178d6dea..c4c52309ef1 100644 --- a/vendor/github.com/benbjohnson/clock/clock.go +++ b/vendor/github.com/benbjohnson/clock/clock.go @@ -15,6 +15,7 @@ type Clock interface { After(d time.Duration) <-chan time.Time AfterFunc(d time.Duration, f func()) *Timer Now() time.Time + Since(t time.Time) time.Duration Sleep(d time.Duration) Tick(d time.Duration) <-chan time.Time Ticker(d time.Duration) *Ticker @@ -37,6 +38,8 @@ func (c *clock) AfterFunc(d time.Duration, f func()) *Timer { func (c *clock) Now() time.Time { return time.Now() } +func (c *clock) Since(t time.Time) time.Duration { return time.Since(t) } + func (c *clock) Sleep(d time.Duration) { time.Sleep(d) } func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) } @@ -87,7 +90,7 @@ func (m *Mock) Add(d time.Duration) { gosched() } -// Sets the current time of the mock clock to a specific one. +// Set sets the current time of the mock clock to a specific one. // This should only be called from a single goroutine at a time. func (m *Mock) Set(t time.Time) { // Continue to execute timers until there are no more before the new time. @@ -158,6 +161,11 @@ func (m *Mock) Now() time.Time { return m.now } +// Since returns time since the mock clocks wall time. +func (m *Mock) Since(t time.Time) time.Duration { + return m.Now().Sub(t) +} + // Sleep pauses the goroutine for the given duration on the mock clock. // The clock must be moved forward in a separate goroutine. func (m *Mock) Sleep(d time.Duration) { diff --git a/vendor/github.com/beorn7/perks/quantile/exampledata.txt b/vendor/github.com/beorn7/perks/quantile/exampledata.txt deleted file mode 100644 index 1602287d7ce..00000000000 --- a/vendor/github.com/beorn7/perks/quantile/exampledata.txt +++ /dev/null @@ -1,2388 +0,0 @@ -8 -5 -26 -12 -5 -235 -13 -6 -28 -30 -3 -3 -3 -3 -5 -2 -33 -7 -2 -4 -7 -12 -14 -5 -8 -3 -10 -4 -5 -3 -6 -6 -209 -20 -3 -10 -14 -3 -4 -6 -8 -5 -11 -7 -3 -2 -3 -3 -212 -5 -222 -4 -10 -10 -5 -6 -3 -8 -3 -10 -254 -220 -2 -3 -5 -24 -5 -4 -222 -7 -3 -3 -223 -8 -15 -12 -14 -14 -3 -2 -2 -3 -13 -3 -11 -4 -4 -6 -5 -7 -13 -5 -3 -5 -2 -5 -3 -5 -2 -7 -15 -17 -14 -3 -6 -6 -3 -17 -5 -4 -7 -6 -4 -4 -8 -6 -8 -3 -9 -3 -6 -3 -4 -5 -3 -3 -660 -4 -6 -10 -3 -6 -3 -2 -5 -13 -2 -4 -4 -10 -4 -8 -4 -3 -7 -9 -9 -3 -10 -37 -3 -13 -4 -12 -3 -6 -10 -8 -5 -21 -2 -3 -8 -3 -2 -3 -3 -4 -12 -2 -4 -8 -8 -4 -3 -2 -20 -1 -6 -32 -2 -11 -6 -18 -3 -8 -11 -3 -212 -3 -4 -2 -6 -7 -12 -11 -3 -2 -16 -10 -6 -4 -6 -3 -2 -7 -3 -2 -2 -2 -2 -5 -6 -4 -3 -10 -3 -4 -6 -5 -3 -4 -4 -5 -6 -4 -3 -4 -4 -5 -7 -5 -5 -3 -2 -7 -2 -4 -12 -4 -5 -6 -2 -4 -4 -8 -4 -15 -13 -7 -16 -5 -3 -23 -5 -5 -7 -3 -2 -9 -8 -7 -5 -8 -11 -4 -10 -76 -4 -47 -4 -3 -2 -7 -4 -2 -3 -37 -10 -4 -2 -20 -5 -4 -4 -10 -10 -4 -3 -7 -23 -240 -7 -13 -5 -5 -3 -3 -2 -5 -4 -2 -8 -7 -19 -2 -23 -8 -7 -2 -5 -3 -8 -3 -8 -13 -5 -5 -5 -2 -3 -23 -4 -9 -8 -4 -3 -3 -5 -220 -2 -3 -4 -6 -14 -3 -53 -6 -2 -5 -18 -6 -3 -219 -6 -5 -2 -5 -3 -6 -5 -15 -4 -3 -17 -3 -2 -4 -7 -2 -3 -3 -4 -4 -3 -2 -664 -6 -3 -23 -5 -5 -16 -5 -8 -2 -4 -2 -24 -12 -3 -2 -3 -5 -8 -3 -5 -4 -3 -14 -3 -5 -8 -2 -3 -7 -9 -4 -2 -3 -6 -8 -4 -3 -4 -6 -5 -3 -3 -6 -3 -19 -4 -4 -6 -3 -6 -3 -5 -22 -5 -4 -4 -3 -8 -11 -4 -9 -7 -6 -13 -4 -4 -4 -6 -17 -9 -3 -3 -3 -4 -3 -221 -5 -11 -3 -4 -2 -12 -6 -3 -5 -7 -5 -7 -4 -9 -7 -14 -37 -19 -217 -16 -3 -5 -2 -2 -7 -19 -7 -6 -7 -4 -24 -5 -11 -4 -7 -7 -9 -13 -3 -4 -3 -6 -28 -4 -4 -5 -5 -2 -5 -6 -4 -4 -6 -10 -5 -4 -3 -2 -3 -3 -6 -5 -5 -4 -3 -2 -3 -7 -4 -6 -18 -16 -8 -16 -4 -5 -8 -6 -9 -13 -1545 -6 -215 -6 -5 -6 -3 -45 -31 -5 -2 -2 -4 -3 -3 -2 -5 -4 -3 -5 -7 -7 -4 -5 -8 -5 -4 -749 -2 -31 -9 -11 -2 -11 -5 -4 -4 -7 -9 -11 -4 -5 -4 -7 -3 -4 -6 -2 -15 -3 -4 -3 -4 -3 -5 -2 -13 -5 -5 -3 -3 -23 -4 -4 -5 -7 -4 -13 -2 -4 -3 -4 -2 -6 -2 -7 -3 -5 -5 -3 -29 -5 -4 -4 -3 -10 -2 -3 -79 -16 -6 -6 -7 -7 -3 -5 -5 -7 -4 -3 -7 -9 -5 -6 -5 -9 -6 -3 -6 -4 -17 -2 -10 -9 -3 -6 -2 -3 -21 -22 -5 -11 -4 -2 -17 -2 -224 -2 -14 -3 -4 -4 -2 -4 -4 -4 -4 -5 -3 -4 -4 -10 -2 -6 -3 -3 -5 -7 -2 -7 -5 -6 -3 -218 -2 -2 -5 -2 -6 -3 -5 -222 -14 -6 -33 -3 -2 -5 -3 -3 -3 -9 -5 -3 -3 -2 -7 -4 -3 -4 -3 -5 -6 -5 -26 -4 -13 -9 -7 -3 -221 -3 -3 -4 -4 -4 -4 -2 -18 -5 -3 -7 -9 -6 -8 -3 -10 -3 -11 -9 -5 -4 -17 -5 -5 -6 -6 -3 -2 -4 -12 -17 -6 -7 -218 -4 -2 -4 -10 -3 -5 -15 -3 -9 -4 -3 -3 -6 -29 -3 -3 -4 -5 -5 -3 -8 -5 -6 -6 -7 -5 -3 -5 -3 -29 -2 -31 -5 -15 -24 -16 -5 -207 -4 -3 -3 -2 -15 -4 -4 -13 -5 -5 -4 -6 -10 -2 -7 -8 -4 -6 -20 -5 -3 -4 -3 -12 -12 -5 -17 -7 -3 -3 -3 -6 -10 -3 -5 -25 -80 -4 -9 -3 -2 -11 -3 -3 -2 -3 -8 -7 -5 -5 -19 -5 -3 -3 -12 -11 -2 -6 -5 -5 -5 -3 -3 -3 -4 -209 -14 -3 -2 -5 -19 -4 -4 -3 -4 -14 -5 -6 -4 -13 -9 -7 -4 -7 -10 -2 -9 -5 -7 -2 -8 -4 -6 -5 -5 -222 -8 -7 -12 -5 -216 -3 -4 -4 -6 -3 -14 -8 -7 -13 -4 -3 -3 -3 -3 -17 -5 -4 -3 -33 -6 -6 -33 -7 -5 -3 -8 -7 -5 -2 -9 -4 -2 -233 -24 -7 -4 -8 -10 -3 -4 -15 -2 -16 -3 -3 -13 -12 -7 -5 -4 -207 -4 -2 -4 -27 -15 -2 -5 -2 -25 -6 -5 -5 -6 -13 -6 -18 -6 -4 -12 -225 -10 -7 -5 -2 -2 -11 -4 -14 -21 -8 -10 -3 -5 -4 -232 -2 -5 -5 -3 -7 -17 -11 -6 -6 -23 -4 -6 -3 -5 -4 -2 -17 -3 -6 -5 -8 -3 -2 -2 -14 -9 -4 -4 -2 -5 -5 -3 -7 -6 -12 -6 -10 -3 -6 -2 -2 -19 -5 -4 -4 -9 -2 -4 -13 -3 -5 -6 -3 -6 -5 -4 -9 -6 -3 -5 -7 -3 -6 -6 -4 -3 -10 -6 -3 -221 -3 -5 -3 -6 -4 -8 -5 -3 -6 -4 -4 -2 -54 -5 -6 -11 -3 -3 -4 -4 -4 -3 -7 -3 -11 -11 -7 -10 -6 -13 -223 -213 -15 -231 -7 -3 -7 -228 -2 -3 -4 -4 -5 -6 -7 -4 -13 -3 -4 -5 -3 -6 -4 -6 -7 -2 -4 -3 -4 -3 -3 -6 -3 -7 -3 -5 -18 -5 -6 -8 -10 -3 -3 -3 -2 -4 -2 -4 -4 -5 -6 -6 -4 -10 -13 -3 -12 -5 -12 -16 -8 -4 -19 -11 -2 -4 -5 -6 -8 -5 -6 -4 -18 -10 -4 -2 -216 -6 -6 -6 -2 -4 -12 -8 -3 -11 -5 -6 -14 -5 -3 -13 -4 -5 -4 -5 -3 -28 -6 -3 -7 -219 -3 -9 -7 -3 -10 -6 -3 -4 -19 -5 -7 -11 -6 -15 -19 -4 -13 -11 -3 -7 -5 -10 -2 -8 -11 -2 -6 -4 -6 -24 -6 -3 -3 -3 -3 -6 -18 -4 -11 -4 -2 -5 -10 -8 -3 -9 -5 -3 -4 -5 -6 -2 -5 -7 -4 -4 -14 -6 -4 -4 -5 -5 -7 -2 -4 -3 -7 -3 -3 -6 -4 -5 -4 -4 -4 -3 -3 -3 -3 -8 -14 -2 -3 -5 -3 -2 -4 -5 -3 -7 -3 -3 -18 -3 -4 -4 -5 -7 -3 -3 -3 -13 -5 -4 -8 -211 -5 -5 -3 -5 -2 -5 -4 -2 -655 -6 -3 -5 -11 -2 -5 -3 -12 -9 -15 -11 -5 -12 -217 -2 -6 -17 -3 -3 -207 -5 -5 -4 -5 -9 -3 -2 -8 -5 -4 -3 -2 -5 -12 -4 -14 -5 -4 -2 -13 -5 -8 -4 -225 -4 -3 -4 -5 -4 -3 -3 -6 -23 -9 -2 -6 -7 -233 -4 -4 -6 -18 -3 -4 -6 -3 -4 -4 -2 -3 -7 -4 -13 -227 -4 -3 -5 -4 -2 -12 -9 -17 -3 -7 -14 -6 -4 -5 -21 -4 -8 -9 -2 -9 -25 -16 -3 -6 -4 -7 -8 -5 -2 -3 -5 -4 -3 -3 -5 -3 -3 -3 -2 -3 -19 -2 -4 -3 -4 -2 -3 -4 -4 -2 -4 -3 -3 -3 -2 -6 -3 -17 -5 -6 -4 -3 -13 -5 -3 -3 -3 -4 -9 -4 -2 -14 -12 -4 -5 -24 -4 -3 -37 -12 -11 -21 -3 -4 -3 -13 -4 -2 -3 -15 -4 -11 -4 -4 -3 -8 -3 -4 -4 -12 -8 -5 -3 -3 -4 -2 -220 -3 -5 -223 -3 -3 -3 -10 -3 -15 -4 -241 -9 -7 -3 -6 -6 -23 -4 -13 -7 -3 -4 -7 -4 -9 -3 -3 -4 -10 -5 -5 -1 -5 -24 -2 -4 -5 -5 -6 -14 -3 -8 -2 -3 -5 -13 -13 -3 -5 -2 -3 -15 -3 -4 -2 -10 -4 -4 -4 -5 -5 -3 -5 -3 -4 -7 -4 -27 -3 -6 -4 -15 -3 -5 -6 -6 -5 -4 -8 -3 -9 -2 -6 -3 -4 -3 -7 -4 -18 -3 -11 -3 -3 -8 -9 -7 -24 -3 -219 -7 -10 -4 -5 -9 -12 -2 -5 -4 -4 -4 -3 -3 -19 -5 -8 -16 -8 -6 -22 -3 -23 -3 -242 -9 -4 -3 -3 -5 -7 -3 -3 -5 -8 -3 -7 -5 -14 -8 -10 -3 -4 -3 -7 -4 -6 -7 -4 -10 -4 -3 -11 -3 -7 -10 -3 -13 -6 -8 -12 -10 -5 -7 -9 -3 -4 -7 -7 -10 -8 -30 -9 -19 -4 -3 -19 -15 -4 -13 -3 -215 -223 -4 -7 -4 -8 -17 -16 -3 -7 -6 -5 -5 -4 -12 -3 -7 -4 -4 -13 -4 -5 -2 -5 -6 -5 -6 -6 -7 -10 -18 -23 -9 -3 -3 -6 -5 -2 -4 -2 -7 -3 -3 -2 -5 -5 -14 -10 -224 -6 -3 -4 -3 -7 -5 -9 -3 -6 -4 -2 -5 -11 -4 -3 -3 -2 -8 -4 -7 -4 -10 -7 -3 -3 -18 -18 -17 -3 -3 -3 -4 -5 -3 -3 -4 -12 -7 -3 -11 -13 -5 -4 -7 -13 -5 -4 -11 -3 -12 -3 -6 -4 -4 -21 -4 -6 -9 -5 -3 -10 -8 -4 -6 -4 -4 -6 -5 -4 -8 -6 -4 -6 -4 -4 -5 -9 -6 -3 -4 -2 -9 -3 -18 -2 -4 -3 -13 -3 -6 -6 -8 -7 -9 -3 -2 -16 -3 -4 -6 -3 -2 -33 -22 -14 -4 -9 -12 -4 -5 -6 -3 -23 -9 -4 -3 -5 -5 -3 -4 -5 -3 -5 -3 -10 -4 -5 -5 -8 -4 -4 -6 -8 -5 -4 -3 -4 -6 -3 -3 -3 -5 -9 -12 -6 -5 -9 -3 -5 -3 -2 -2 -2 -18 -3 -2 -21 -2 -5 -4 -6 -4 -5 -10 -3 -9 -3 -2 -10 -7 -3 -6 -6 -4 -4 -8 -12 -7 -3 -7 -3 -3 -9 -3 -4 -5 -4 -4 -5 -5 -10 -15 -4 -4 -14 -6 -227 -3 -14 -5 -216 -22 -5 -4 -2 -2 -6 -3 -4 -2 -9 -9 -4 -3 -28 -13 -11 -4 -5 -3 -3 -2 -3 -3 -5 -3 -4 -3 -5 -23 -26 -3 -4 -5 -6 -4 -6 -3 -5 -5 -3 -4 -3 -2 -2 -2 -7 -14 -3 -6 -7 -17 -2 -2 -15 -14 -16 -4 -6 -7 -13 -6 -4 -5 -6 -16 -3 -3 -28 -3 -6 -15 -3 -9 -2 -4 -6 -3 -3 -22 -4 -12 -6 -7 -2 -5 -4 -10 -3 -16 -6 -9 -2 -5 -12 -7 -5 -5 -5 -5 -2 -11 -9 -17 -4 -3 -11 -7 -3 -5 -15 -4 -3 -4 -211 -8 -7 -5 -4 -7 -6 -7 -6 -3 -6 -5 -6 -5 -3 -4 -4 -26 -4 -6 -10 -4 -4 -3 -2 -3 -3 -4 -5 -9 -3 -9 -4 -4 -5 -5 -8 -2 -4 -2 -3 -8 -4 -11 -19 -5 -8 -6 -3 -5 -6 -12 -3 -2 -4 -16 -12 -3 -4 -4 -8 -6 -5 -6 -6 -219 -8 -222 -6 -16 -3 -13 -19 -5 -4 -3 -11 -6 -10 -4 -7 -7 -12 -5 -3 -3 -5 -6 -10 -3 -8 -2 -5 -4 -7 -2 -4 -4 -2 -12 -9 -6 -4 -2 -40 -2 -4 -10 -4 -223 -4 -2 -20 -6 -7 -24 -5 -4 -5 -2 -20 -16 -6 -5 -13 -2 -3 -3 -19 -3 -2 -4 -5 -6 -7 -11 -12 -5 -6 -7 -7 -3 -5 -3 -5 -3 -14 -3 -4 -4 -2 -11 -1 -7 -3 -9 -6 -11 -12 -5 -8 -6 -221 -4 -2 -12 -4 -3 -15 -4 -5 -226 -7 -218 -7 -5 -4 -5 -18 -4 -5 -9 -4 -4 -2 -9 -18 -18 -9 -5 -6 -6 -3 -3 -7 -3 -5 -4 -4 -4 -12 -3 -6 -31 -5 -4 -7 -3 -6 -5 -6 -5 -11 -2 -2 -11 -11 -6 -7 -5 -8 -7 -10 -5 -23 -7 -4 -3 -5 -34 -2 -5 -23 -7 -3 -6 -8 -4 -4 -4 -2 -5 -3 -8 -5 -4 -8 -25 -2 -3 -17 -8 -3 -4 -8 -7 -3 -15 -6 -5 -7 -21 -9 -5 -6 -6 -5 -3 -2 -3 -10 -3 -6 -3 -14 -7 -4 -4 -8 -7 -8 -2 -6 -12 -4 -213 -6 -5 -21 -8 -2 -5 -23 -3 -11 -2 -3 -6 -25 -2 -3 -6 -7 -6 -6 -4 -4 -6 -3 -17 -9 -7 -6 -4 -3 -10 -7 -2 -3 -3 -3 -11 -8 -3 -7 -6 -4 -14 -36 -3 -4 -3 -3 -22 -13 -21 -4 -2 -7 -4 -4 -17 -15 -3 -7 -11 -2 -4 -7 -6 -209 -6 -3 -2 -2 -24 -4 -9 -4 -3 -3 -3 -29 -2 -2 -4 -3 -3 -5 -4 -6 -3 -3 -2 -4 diff --git a/vendor/github.com/bmizerany/assert/.gitignore b/vendor/github.com/bmizerany/assert/.gitignore deleted file mode 100644 index b6fadf4ebe7..00000000000 --- a/vendor/github.com/bmizerany/assert/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -_go_.* -_gotest_.* -_obj -_test -_testmain.go -*.out -*.[568] diff --git a/vendor/github.com/bmizerany/assert/README.md b/vendor/github.com/bmizerany/assert/README.md deleted file mode 100644 index 8b6b6fc4fc6..00000000000 --- a/vendor/github.com/bmizerany/assert/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Assert (c) Blake Mizerany and Keith Rarick -- MIT LICENCE - -## Assertions for Go tests - -## Install - - $ go get github.com/bmizerany/assert - -## Use - -**point.go** - - package point - - type Point struct { - x, y int - } - -**point_test.go** - - - package point - - import ( - "testing" - "github.com/bmizerany/assert" - ) - - func TestAsserts(t *testing.T) { - p1 := Point{1, 1} - p2 := Point{2, 1} - - assert.Equal(t, p1, p2) - } - -**output** - $ go test - --- FAIL: TestAsserts (0.00 seconds) - assert.go:15: /Users/flavio.barbosa/dev/stewie/src/point_test.go:12 - assert.go:24: ! X: 1 != 2 - FAIL - -## Docs - - http://github.com/bmizerany/assert diff --git a/vendor/github.com/bmizerany/assert/assert_test.go b/vendor/github.com/bmizerany/assert/assert_test.go deleted file mode 100644 index 162a590c62f..00000000000 --- a/vendor/github.com/bmizerany/assert/assert_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package assert - -import ( - "testing" -) - -func TestLineNumbers(t *testing.T) { - Equal(t, "foo", "foo", "msg!") - //Equal(t, "foo", "bar", "this should blow up") -} - -func TestNotEqual(t *testing.T) { - NotEqual(t, "foo", "bar", "msg!") - //NotEqual(t, "foo", "foo", "this should blow up") -} diff --git a/vendor/github.com/bmizerany/assert/example/point.go b/vendor/github.com/bmizerany/assert/example/point.go deleted file mode 100644 index 15789fe10f4..00000000000 --- a/vendor/github.com/bmizerany/assert/example/point.go +++ /dev/null @@ -1,5 +0,0 @@ -package point - -type Point struct { - X, Y int -} diff --git a/vendor/github.com/bmizerany/assert/example/point_test.go b/vendor/github.com/bmizerany/assert/example/point_test.go deleted file mode 100644 index 34e791a43c9..00000000000 --- a/vendor/github.com/bmizerany/assert/example/point_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package point - -import ( - "testing" - "assert" -) - -func TestAsserts(t *testing.T) { - p1 := Point{1, 1} - p2 := Point{2, 1} - - assert.Equal(t, p1, p2) -} diff --git a/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go b/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go index 6eed4fbe003..b98a7653467 100644 --- a/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go +++ b/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go @@ -56,7 +56,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 +64,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 +92,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 +136,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 @@ -147,9 +158,6 @@ type Item struct { // Value is the Item's value. Value []byte - // Object is the Item's value for use with a Codec. - Object interface{} - // Flags are server-opaque flags whose semantics are entirely // up to the app. Flags uint32 @@ -199,7 +207,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 } @@ -228,6 +236,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. diff --git a/vendor/github.com/bradfitz/gomemcache/memcache/selector.go b/vendor/github.com/bradfitz/gomemcache/memcache/selector.go index 10b04d349fe..89ad81e0d83 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/codahale/hdrhistogram/README.md b/vendor/github.com/codahale/hdrhistogram/README.md deleted file mode 100644 index 614b197c3dd..00000000000 --- a/vendor/github.com/codahale/hdrhistogram/README.md +++ /dev/null @@ -1,15 +0,0 @@ -hdrhistogram -============ - -[![Build Status](https://travis-ci.org/codahale/hdrhistogram.png?branch=master)](https://travis-ci.org/codahale/hdrhistogram) - -A pure Go implementation of the [HDR Histogram](https://github.com/HdrHistogram/HdrHistogram). - -> A Histogram that supports recording and analyzing sampled data value counts -> across a configurable integer value range with configurable value precision -> within the range. Value precision is expressed as the number of significant -> digits in the value recording, and provides control over value quantization -> behavior across the value range and the subsequent value resolution at any -> given level. - -For documentation, check [godoc](http://godoc.org/github.com/codahale/hdrhistogram). diff --git a/vendor/github.com/codegangsta/cli/.travis.yml b/vendor/github.com/codegangsta/cli/.travis.yml deleted file mode 100644 index 87ba52f98ea..00000000000 --- a/vendor/github.com/codegangsta/cli/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go -sudo: false - -go: -- 1.0.3 -- 1.1.2 -- 1.2.2 -- 1.3.3 -- 1.4.2 -- 1.5.1 -- tip - -matrix: - allow_failures: - - go: tip - -script: -- go vet ./... -- go test -v ./... diff --git a/vendor/github.com/codegangsta/cli/LICENSE b/vendor/github.com/codegangsta/cli/LICENSE index 5515ccfb716..42a597e29bb 100644 --- a/vendor/github.com/codegangsta/cli/LICENSE +++ b/vendor/github.com/codegangsta/cli/LICENSE @@ -1,21 +1,21 @@ -Copyright (C) 2013 Jeremy Saenz -All Rights Reserved. +MIT License -MIT LICENSE +Copyright (c) 2016 Jeremy Saenz & Contributors -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/codegangsta/cli/README.md b/vendor/github.com/codegangsta/cli/README.md deleted file mode 100644 index 26a183865dc..00000000000 --- a/vendor/github.com/codegangsta/cli/README.md +++ /dev/null @@ -1,341 +0,0 @@ -[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli) -[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli) -[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli) - -# cli.go -`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. - -## Overview -Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app. - -**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive! - -## Installation -Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html). - -To install `cli.go`, simply run: -``` -$ go get github.com/codegangsta/cli -``` - -Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used: -``` -export PATH=$PATH:$GOPATH/bin -``` - -## Getting Started -One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`. - -``` go -package main - -import ( - "os" - "github.com/codegangsta/cli" -) - -func main() { - cli.NewApp().Run(os.Args) -} -``` - -This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation: - -``` go -package main - -import ( - "os" - "github.com/codegangsta/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "boom" - app.Usage = "make an explosive entrance" - app.Action = func(c *cli.Context) { - println("boom! I say!") - } - - app.Run(os.Args) -} -``` - -Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below. - -## Example - -Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness! - -Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it: - -``` go -package main - -import ( - "os" - "github.com/codegangsta/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "greet" - app.Usage = "fight the loneliness!" - app.Action = func(c *cli.Context) { - println("Hello friend!") - } - - app.Run(os.Args) -} -``` - -Install our command to the `$GOPATH/bin` directory: - -``` -$ go install -``` - -Finally run our new command: - -``` -$ greet -Hello friend! -``` - -`cli.go` also generates neat help text: - -``` -$ greet help -NAME: - greet - fight the loneliness! - -USAGE: - greet [global options] command [command options] [arguments...] - -VERSION: - 0.0.0 - -COMMANDS: - help, h Shows a list of commands or help for one command - -GLOBAL OPTIONS - --version Shows version information -``` - -### Arguments -You can lookup arguments by calling the `Args` function on `cli.Context`. - -``` go -... -app.Action = func(c *cli.Context) { - println("Hello", c.Args()[0]) -} -... -``` - -### Flags -Setting and querying flags is simple. -``` go -... -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - }, -} -app.Action = func(c *cli.Context) { - name := "someone" - if len(c.Args()) > 0 { - name = c.Args()[0] - } - if c.String("lang") == "spanish" { - println("Hola", name) - } else { - println("Hello", name) - } -} -... -``` - -You can also set a destination variable for a flag, to which the content will be scanned. -``` go -... -var language string -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - Destination: &language, - }, -} -app.Action = func(c *cli.Context) { - name := "someone" - if len(c.Args()) > 0 { - name = c.Args()[0] - } - if language == "spanish" { - println("Hola", name) - } else { - println("Hello", name) - } -} -... -``` - -See full list of flags at http://godoc.org/github.com/codegangsta/cli - -#### Alternate Names - -You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g. - -``` go -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - }, -} -``` - -That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. - -#### Values from the Environment - -You can also have the default value set from the environment via `EnvVar`. e.g. - -``` go -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "APP_LANG", - }, -} -``` - -The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default. - -``` go -app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", - }, -} -``` - -### Subcommands - -Subcommands can be defined for a more git-like command line app. -```go -... -app.Commands = []cli.Command{ - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) { - println("added task: ", c.Args().First()) - }, - }, - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) { - println("completed task: ", c.Args().First()) - }, - }, - { - Name: "template", - Aliases: []string{"r"}, - Usage: "options for task templates", - Subcommands: []cli.Command{ - { - Name: "add", - Usage: "add a new template", - Action: func(c *cli.Context) { - println("new task template: ", c.Args().First()) - }, - }, - { - Name: "remove", - Usage: "remove an existing template", - Action: func(c *cli.Context) { - println("removed task template: ", c.Args().First()) - }, - }, - }, - }, -} -... -``` - -### Bash Completion - -You can enable completion commands by setting the `EnableBashCompletion` -flag on the `App` object. By default, this setting will only auto-complete to -show an app's subcommands, but you can write your own completion methods for -the App or its subcommands. -```go -... -var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} -app := cli.NewApp() -app.EnableBashCompletion = true -app.Commands = []cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) { - println("completed task: ", c.Args().First()) - }, - BashComplete: func(c *cli.Context) { - // This will complete if no args are passed - if len(c.Args()) > 0 { - return - } - for _, t := range tasks { - fmt.Println(t) - } - }, - } -} -... -``` - -#### To Enable - -Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while -setting the `PROG` variable to the name of your program: - -`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` - -#### To Distribute - -Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename -it to the name of the program you wish to add autocomplete support for (or -automatically install it there if you are distributing a package). Don't forget -to source the file to make it active in the current shell. - -``` - sudo cp src/bash_autocomplete /etc/bash_completion.d/ - source /etc/bash_completion.d/ -``` - -Alternatively, you can just document that users should source the generic -`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set -to the name of their program (as above). - -## Contribution Guidelines -Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch. - -If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together. - -If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out. diff --git a/vendor/github.com/codegangsta/cli/app.go b/vendor/github.com/codegangsta/cli/app.go index 2f992d0d7a7..51fc45d8781 100644 --- a/vendor/github.com/codegangsta/cli/app.go +++ b/vendor/github.com/codegangsta/cli/app.go @@ -5,11 +5,24 @@ import ( "io" "io/ioutil" "os" - "path" + "path/filepath" + "sort" "time" ) -// App is the main structure of a cli application. It is recomended that +var ( + changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" + appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) + runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL) + + contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." + + errInvalidActionType = NewExitError("ERROR invalid Action type. "+ + fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ + fmt.Sprintf("See %s", appActionDeprecationURL), 2) +) + +// App is the main structure of a cli application. It is recommended that // an app be created with the cli.NewApp() function type App struct { // The name of the program. Defaults to path.Base(os.Args[0]) @@ -18,10 +31,14 @@ type App struct { HelpName string // Description of the program. Usage string + // Text to override the USAGE section of help + UsageText string // Description of the program argument format. ArgsUsage string // Version of the program Version string + // Description of the program + Description string // List of commands to execute Commands []Command // List of flags to parse @@ -30,20 +47,28 @@ type App struct { EnableBashCompletion bool // Boolean to hide built-in help command HideHelp bool - // Boolean to hide built-in version flag + // Boolean to hide built-in version flag and the VERSION section of help HideVersion bool + // Populate on app startup, only gettable through method Categories() + categories CommandCategories // An action to execute when the bash-completion flag is set - BashComplete func(context *Context) + BashComplete BashCompleteFunc // An action to execute before any subcommands are run, but after the context is ready // If a non-nil error is returned, no subcommands are run - Before func(context *Context) error + Before BeforeFunc // An action to execute after any subcommands are run, but after the subcommand has finished // It is run even if Action() panics - After func(context *Context) error + After AfterFunc + // The action to execute when no subcommands are specified - Action func(context *Context) + // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` + // *Note*: support for the deprecated `Action` signature will be removed in a future version + Action interface{} + // Execute this function if the proper command cannot be found - CommandNotFound func(context *Context, command string) + CommandNotFound CommandNotFoundFunc + // Execute this function if an usage error occurs + OnUsageError OnUsageErrorFunc // Compilation date Compiled time.Time // List of all authors who contributed @@ -56,6 +81,18 @@ type App struct { Email string // Writer writer to write output to Writer io.Writer + // ErrWriter writes error output + ErrWriter io.Writer + // Other custom info + Metadata map[string]interface{} + // Carries a function which returns app specific info. + ExtraInfo func() map[string]string + // CustomAppHelpTemplate the text template for app help topic. + // cli.go uses text/template to render templates. You can + // render custom help text by setting this variable. + CustomAppHelpTemplate string + + didSetup bool } // Tries to find out when this binary was compiled. @@ -68,12 +105,14 @@ func compileTime() time.Time { return info.ModTime() } -// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. +// NewApp creates a new cli Application with some reasonable defaults for Name, +// Usage, Version and Action. func NewApp() *App { return &App{ - Name: path.Base(os.Args[0]), - HelpName: path.Base(os.Args[0]), + Name: filepath.Base(os.Args[0]), + HelpName: filepath.Base(os.Args[0]), Usage: "A new cli application", + UsageText: "", Version: "0.0.0", BashComplete: DefaultAppComplete, Action: helpCommand.Action, @@ -82,8 +121,16 @@ func NewApp() *App { } } -// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination -func (a *App) Run(arguments []string) (err error) { +// Setup runs initialization code to ensure all data structures are ready for +// `Run` or inspection prior to `Run`. It is internally called by `Run`, but +// will return early if setup has already happened. +func (a *App) Setup() { + if a.didSetup { + return + } + + a.didSetup = true + if a.Author != "" || a.Email != "" { a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) } @@ -97,7 +144,6 @@ func (a *App) Run(arguments []string) (err error) { } a.Commands = newCmds - // append help to commands if a.Command(helpCommand.Name) == nil && !a.HideHelp { a.Commands = append(a.Commands, helpCommand) if (HelpFlag != BoolFlag{}) { @@ -105,35 +151,66 @@ func (a *App) Run(arguments []string) (err error) { } } - //append version/help flags - if a.EnableBashCompletion { - a.appendFlag(BashCompletionFlag) - } - if !a.HideVersion { a.appendFlag(VersionFlag) } + a.categories = CommandCategories{} + for _, command := range a.Commands { + a.categories = a.categories.AddCommand(command.Category, command) + } + sort.Sort(a.categories) + + if a.Metadata == nil { + a.Metadata = make(map[string]interface{}) + } + + if a.Writer == nil { + a.Writer = os.Stdout + } +} + +// Run is the entry point to the cli app. Parses the arguments slice and routes +// to the proper flag/args combination +func (a *App) Run(arguments []string) (err error) { + a.Setup() + + // handle the completion flag separately from the flagset since + // completion could be attempted after a flag, but before its value was put + // on the command line. this causes the flagset to interpret the completion + // flag name as the value of the flag before it which is undesirable + // note that we can only do this because the shell autocomplete function + // always appends the completion flag at the end of the command + shellComplete, arguments := checkShellCompleteFlag(a, arguments) + // parse flags - set := flagSet(a.Name, a.Flags) + set, err := flagSet(a.Name, a.Flags) + if err != nil { + return err + } + set.SetOutput(ioutil.Discard) err = set.Parse(arguments[1:]) nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, nil) if nerr != nil { fmt.Fprintln(a.Writer, nerr) - context := NewContext(a, set, nil) ShowAppHelp(context) return nerr } - context := NewContext(a, set, nil) + context.shellComplete = shellComplete if checkCompletions(context) { return nil } if err != nil { - fmt.Fprintln(a.Writer, "Incorrect Usage.") - fmt.Fprintln(a.Writer) + if a.OnUsageError != nil { + err := a.OnUsageError(context, err, false) + HandleExitCoder(err) + return err + } + fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) ShowAppHelp(context) return err } @@ -150,8 +227,7 @@ func (a *App) Run(arguments []string) (err error) { if a.After != nil { defer func() { - afterErr := a.After(context) - if afterErr != nil { + if afterErr := a.After(context); afterErr != nil { if err != nil { err = NewMultiError(err, afterErr) } else { @@ -162,8 +238,11 @@ func (a *App) Run(arguments []string) (err error) { } if a.Before != nil { - err := a.Before(context) - if err != nil { + beforeErr := a.Before(context) + if beforeErr != nil { + ShowAppHelp(context) + HandleExitCoder(beforeErr) + err = beforeErr return err } } @@ -177,20 +256,31 @@ func (a *App) Run(arguments []string) (err error) { } } + if a.Action == nil { + a.Action = helpCommand.Action + } + // Run default Action - a.Action(context) - return nil + err = HandleAction(a.Action, context) + + HandleExitCoder(err) + return err } -// Another entry point to the cli app, takes care of passing arguments and error handling +// RunAndExitOnError calls .Run() and exits non-zero if an error was returned +// +// Deprecated: instead you should return an error that fulfills cli.ExitCoder +// to cli.App.Run. This will cause the application to exit with the given eror +// code in the cli.ExitCoder func (a *App) RunAndExitOnError() { if err := a.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + fmt.Fprintln(a.errWriter(), err) + OsExiter(1) } } -// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags +// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to +// generate command-specific flags func (a *App) RunAsSubcommand(ctx *Context) (err error) { // append help to commands if len(a.Commands) > 0 { @@ -211,13 +301,12 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } a.Commands = newCmds - // append flags - if a.EnableBashCompletion { - a.appendFlag(BashCompletionFlag) + // parse flags + set, err := flagSet(a.Name, a.Flags) + if err != nil { + return err } - // parse flags - set := flagSet(a.Name, a.Flags) set.SetOutput(ioutil.Discard) err = set.Parse(ctx.Args().Tail()) nerr := normalizeFlags(a.Flags, set) @@ -239,8 +328,12 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } if err != nil { - fmt.Fprintln(a.Writer, "Incorrect Usage.") - fmt.Fprintln(a.Writer) + if a.OnUsageError != nil { + err = a.OnUsageError(context, err, true) + HandleExitCoder(err) + return err + } + fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) ShowSubcommandHelp(context) return err } @@ -259,6 +352,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { defer func() { afterErr := a.After(context) if afterErr != nil { + HandleExitCoder(err) if err != nil { err = NewMultiError(err, afterErr) } else { @@ -269,8 +363,10 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } if a.Before != nil { - err := a.Before(context) - if err != nil { + beforeErr := a.Before(context) + if beforeErr != nil { + HandleExitCoder(beforeErr) + err = beforeErr return err } } @@ -285,12 +381,13 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } // Run default Action - a.Action(context) + err = HandleAction(a.Action, context) - return nil + HandleExitCoder(err) + return err } -// Returns the named command on App. Returns nil if the command does not exist +// Command returns the named command on App. Returns nil if the command does not exist func (a *App) Command(name string) *Command { for _, c := range a.Commands { if c.HasName(name) { @@ -301,6 +398,46 @@ func (a *App) Command(name string) *Command { return nil } +// Categories returns a slice containing all the categories with the commands they contain +func (a *App) Categories() CommandCategories { + return a.categories +} + +// VisibleCategories returns a slice of categories and commands that are +// Hidden=false +func (a *App) VisibleCategories() []*CommandCategory { + ret := []*CommandCategory{} + for _, category := range a.categories { + if visible := func() *CommandCategory { + for _, command := range category.Commands { + if !command.Hidden { + return category + } + } + return nil + }(); visible != nil { + ret = append(ret, visible) + } + } + return ret +} + +// VisibleCommands returns a slice of the Commands with Hidden=false +func (a *App) VisibleCommands() []Command { + ret := []Command{} + for _, command := range a.Commands { + if !command.Hidden { + ret = append(ret, command) + } + } + return ret +} + +// VisibleFlags returns a slice of the Flags with Hidden=false +func (a *App) VisibleFlags() []Flag { + return visibleFlags(a.Flags) +} + func (a *App) hasFlag(flag Flag) bool { for _, f := range a.Flags { if flag == f { @@ -311,6 +448,16 @@ func (a *App) hasFlag(flag Flag) bool { return false } +func (a *App) errWriter() io.Writer { + + // When the app ErrWriter is nil use the package level one. + if a.ErrWriter == nil { + return ErrWriter + } + + return a.ErrWriter +} + func (a *App) appendFlag(flag Flag) { if !a.hasFlag(flag) { a.Flags = append(a.Flags, flag) @@ -327,8 +474,24 @@ type Author struct { func (a Author) String() string { e := "" if a.Email != "" { - e = "<" + a.Email + "> " + e = " <" + a.Email + ">" } - return fmt.Sprintf("%v %v", a.Name, e) + return fmt.Sprintf("%v%v", a.Name, e) +} + +// HandleAction attempts to figure out which Action signature was used. If +// it's an ActionFunc or a func with the legacy signature for Action, the func +// is run! +func HandleAction(action interface{}, context *Context) (err error) { + if a, ok := action.(ActionFunc); ok { + return a(context) + } else if a, ok := action.(func(*Context) error); ok { + return a(context) + } else if a, ok := action.(func(*Context)); ok { // deprecated function signature + a(context) + return nil + } else { + return errInvalidActionType + } } diff --git a/vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete b/vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete deleted file mode 100644 index 21a232f1f55..00000000000 --- a/vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/bash - -: ${PROG:=$(basename ${BASH_SOURCE})} - -_cli_bash_autocomplete() { - local cur opts base - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - return 0 - } - - complete -F _cli_bash_autocomplete $PROG diff --git a/vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete b/vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete deleted file mode 100644 index 5430a18f957..00000000000 --- a/vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete +++ /dev/null @@ -1,5 +0,0 @@ -autoload -U compinit && compinit -autoload -U bashcompinit && bashcompinit - -script_dir=$(dirname $0) -source ${script_dir}/bash_autocomplete diff --git a/vendor/github.com/codegangsta/cli/category.go b/vendor/github.com/codegangsta/cli/category.go new file mode 100644 index 00000000000..1a6055023e7 --- /dev/null +++ b/vendor/github.com/codegangsta/cli/category.go @@ -0,0 +1,44 @@ +package cli + +// CommandCategories is a slice of *CommandCategory. +type CommandCategories []*CommandCategory + +// CommandCategory is a category containing commands. +type CommandCategory struct { + Name string + Commands Commands +} + +func (c CommandCategories) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c CommandCategories) Len() int { + return len(c) +} + +func (c CommandCategories) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +// AddCommand adds a command to a category. +func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { + for _, commandCategory := range c { + if commandCategory.Name == category { + commandCategory.Commands = append(commandCategory.Commands, command) + return c + } + } + return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) +} + +// VisibleCommands returns a slice of the Commands with Hidden=false +func (c *CommandCategory) VisibleCommands() []Command { + ret := []Command{} + for _, command := range c.Commands { + if !command.Hidden { + ret = append(ret, command) + } + } + return ret +} diff --git a/vendor/github.com/codegangsta/cli/cli.go b/vendor/github.com/codegangsta/cli/cli.go index 31dc9124d1e..90c07eb8ef9 100644 --- a/vendor/github.com/codegangsta/cli/cli.go +++ b/vendor/github.com/codegangsta/cli/cli.go @@ -10,31 +10,13 @@ // app := cli.NewApp() // app.Name = "greet" // app.Usage = "say a greeting" -// app.Action = func(c *cli.Context) { +// app.Action = func(c *cli.Context) error { // println("Greetings") +// return nil // } // // app.Run(os.Args) // } package cli -import ( - "strings" -) - -type MultiError struct { - Errors []error -} - -func NewMultiError(err ...error) MultiError { - return MultiError{Errors: err} -} - -func (m MultiError) Error() string { - errs := make([]string, len(m.Errors)) - for i, err := range m.Errors { - errs[i] = err.Error() - } - - return strings.Join(errs, "\n") -} +//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go diff --git a/vendor/github.com/codegangsta/cli/command.go b/vendor/github.com/codegangsta/cli/command.go index 824e77bae3f..23de2944bea 100644 --- a/vendor/github.com/codegangsta/cli/command.go +++ b/vendor/github.com/codegangsta/cli/command.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "io/ioutil" + "sort" "strings" ) @@ -16,35 +17,70 @@ type Command struct { Aliases []string // A short description of the usage of this command Usage string + // Custom text to show on USAGE section of help + UsageText string // A longer explanation of how the command works Description string // A short description of the arguments of this command ArgsUsage string + // The category the command is part of + Category string // The function to call when checking for bash command completions - BashComplete func(context *Context) + BashComplete BashCompleteFunc // An action to execute before any sub-subcommands are run, but after the context is ready // If a non-nil error is returned, no sub-subcommands are run - Before func(context *Context) error + Before BeforeFunc // An action to execute after any subcommands are run, but after the subcommand has finished // It is run even if Action() panics - After func(context *Context) error + After AfterFunc // The function to call when this command is invoked - Action func(context *Context) + Action interface{} + // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind + // of deprecation period has passed, maybe? + + // Execute this function if a usage error occurs. + OnUsageError OnUsageErrorFunc // List of child commands - Subcommands []Command + Subcommands Commands // List of flags to parse Flags []Flag // Treat all flags as normal arguments if true SkipFlagParsing bool + // Skip argument reordering which attempts to move flags before arguments, + // but only works if all flags appear after all arguments. This behavior was + // removed n version 2 since it only works under specific conditions so we + // backport here by exposing it as an option for compatibility. + SkipArgReorder bool // Boolean to hide built-in help command HideHelp bool + // Boolean to hide this command from help or completion + Hidden bool // Full name of command for help, defaults to full command name, including parent commands. HelpName string commandNamePath []string + + // CustomHelpTemplate the text template for the command help topic. + // cli.go uses text/template to render templates. You can + // render custom help text by setting this variable. + CustomHelpTemplate string } -// Returns the full name of the command. +type CommandsByName []Command + +func (c CommandsByName) Len() int { + return len(c) +} + +func (c CommandsByName) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c CommandsByName) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +// FullName returns the full name of the command. // For subcommands this ensures that parent commands are part of the command path func (c Command) FullName() string { if c.commandNamePath == nil { @@ -53,9 +89,12 @@ func (c Command) FullName() string { return strings.Join(c.commandNamePath, " ") } -// Invokes the command given the context, parses ctx.Args() to generate command-specific flags -func (c Command) Run(ctx *Context) error { - if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil { +// Commands is a slice of Command +type Commands []Command + +// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags +func (c Command) Run(ctx *Context) (err error) { + if len(c.Subcommands) > 0 { return c.startApp(ctx) } @@ -67,21 +106,24 @@ func (c Command) Run(ctx *Context) error { ) } - if ctx.App.EnableBashCompletion { - c.Flags = append(c.Flags, BashCompletionFlag) + set, err := flagSet(c.Name, c.Flags) + if err != nil { + return err } - - set := flagSet(c.Name, c.Flags) set.SetOutput(ioutil.Discard) - var err error - if !c.SkipFlagParsing { + if c.SkipFlagParsing { + err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) + } else if !c.SkipArgReorder { firstFlagIndex := -1 terminatorIndex := -1 for index, arg := range ctx.Args() { if arg == "--" { terminatorIndex = index break + } else if arg == "-" { + // Do nothing. A dash alone is not really a flag. + continue } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { firstFlagIndex = index } @@ -105,16 +147,7 @@ func (c Command) Run(ctx *Context) error { err = set.Parse(ctx.Args().Tail()) } } else { - if c.SkipFlagParsing { - err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) - } - } - - if err != nil { - fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return err + err = set.Parse(ctx.Args().Tail()) } nerr := normalizeFlags(c.Flags, set) @@ -124,20 +157,65 @@ func (c Command) Run(ctx *Context) error { ShowCommandHelp(ctx, c.Name) return nerr } - context := NewContext(ctx.App, set, ctx) + context := NewContext(ctx.App, set, ctx) + context.Command = c if checkCommandCompletions(context, c.Name) { return nil } + if err != nil { + if c.OnUsageError != nil { + err := c.OnUsageError(context, err, false) + HandleExitCoder(err) + return err + } + fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) + fmt.Fprintln(context.App.Writer) + ShowCommandHelp(context, c.Name) + return err + } + if checkCommandHelp(context, c.Name) { return nil } - context.Command = c - c.Action(context) - return nil + + if c.After != nil { + defer func() { + afterErr := c.After(context) + if afterErr != nil { + HandleExitCoder(err) + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if c.Before != nil { + err = c.Before(context) + if err != nil { + ShowCommandHelp(context, c.Name) + HandleExitCoder(err) + return err + } + } + + if c.Action == nil { + c.Action = helpSubcommand.Action + } + + err = HandleAction(c.Action, context) + + if err != nil { + HandleExitCoder(err) + } + return err } +// Names returns the names including short names and aliases. func (c Command) Names() []string { names := []string{c.Name} @@ -148,7 +226,7 @@ func (c Command) Names() []string { return append(names, c.Aliases...) } -// Returns true if Command.Name or Command.ShortName matches given name +// HasName returns true if Command.Name or Command.ShortName matches given name func (c Command) HasName(name string) bool { for _, n := range c.Names() { if n == name { @@ -160,23 +238,22 @@ func (c Command) HasName(name string) bool { func (c Command) startApp(ctx *Context) error { app := NewApp() - + app.Metadata = ctx.App.Metadata // set the name and usage app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) if c.HelpName == "" { app.HelpName = c.HelpName } else { - app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) + app.HelpName = app.Name } - if c.Description != "" { - app.Usage = c.Description - } else { - app.Usage = c.Usage - } + app.Usage = c.Usage + app.Description = c.Description + app.ArgsUsage = c.ArgsUsage // set CommandNotFound app.CommandNotFound = ctx.App.CommandNotFound + app.CustomAppHelpTemplate = c.CustomHelpTemplate // set the flags and commands app.Commands = c.Subcommands @@ -189,6 +266,14 @@ func (c Command) startApp(ctx *Context) error { app.Author = ctx.App.Author app.Email = ctx.App.Email app.Writer = ctx.App.Writer + app.ErrWriter = ctx.App.ErrWriter + + app.categories = CommandCategories{} + for _, command := range c.Subcommands { + app.categories = app.categories.AddCommand(command.Category, command) + } + + sort.Sort(app.categories) // bash completion app.EnableBashCompletion = ctx.App.EnableBashCompletion @@ -204,13 +289,16 @@ func (c Command) startApp(ctx *Context) error { } else { app.Action = helpSubcommand.Action } + app.OnUsageError = c.OnUsageError - var newCmds []Command - for _, cc := range app.Commands { - cc.commandNamePath = []string{c.Name, cc.Name} - newCmds = append(newCmds, cc) + for index, cc := range app.Commands { + app.Commands[index].commandNamePath = []string{c.Name, cc.Name} } - app.Commands = newCmds return app.RunAsSubcommand(ctx) } + +// VisibleFlags returns a slice of the Flags with Hidden=false +func (c Command) VisibleFlags() []Flag { + return visibleFlags(c.Flags) +} diff --git a/vendor/github.com/codegangsta/cli/context.go b/vendor/github.com/codegangsta/cli/context.go index 0513d34f61e..db94191e2af 100644 --- a/vendor/github.com/codegangsta/cli/context.go +++ b/vendor/github.com/codegangsta/cli/context.go @@ -3,9 +3,9 @@ package cli import ( "errors" "flag" - "strconv" + "reflect" "strings" - "time" + "syscall" ) // Context is a type that is passed through to @@ -13,154 +13,121 @@ import ( // can be used to retrieve context-specific Args and // parsed command-line options. type Context struct { - App *App - Command Command - flagSet *flag.FlagSet - setFlags map[string]bool - globalSetFlags map[string]bool - parentContext *Context + App *App + Command Command + shellComplete bool + flagSet *flag.FlagSet + setFlags map[string]bool + parentContext *Context } -// Creates a new context. For use in when invoking an App or Command action. +// NewContext creates a new context. For use in when invoking an App or Command action. func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - return &Context{App: app, flagSet: set, parentContext: parentCtx} -} + c := &Context{App: app, flagSet: set, parentContext: parentCtx} -// Looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists -func (c *Context) Duration(name string) time.Duration { - return lookupDuration(name, c.flagSet) -} - -// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists -func (c *Context) Float64(name string) float64 { - return lookupFloat64(name, c.flagSet) -} - -// Looks up the value of a local bool flag, returns false if no bool flag exists -func (c *Context) Bool(name string) bool { - return lookupBool(name, c.flagSet) -} - -// Looks up the value of a local boolT flag, returns false if no bool flag exists -func (c *Context) BoolT(name string) bool { - return lookupBoolT(name, c.flagSet) -} - -// Looks up the value of a local string flag, returns "" if no string flag exists -func (c *Context) String(name string) string { - return lookupString(name, c.flagSet) -} - -// Looks up the value of a local string slice flag, returns nil if no string slice flag exists -func (c *Context) StringSlice(name string) []string { - return lookupStringSlice(name, c.flagSet) -} - -// Looks up the value of a local int slice flag, returns nil if no int slice flag exists -func (c *Context) IntSlice(name string) []int { - return lookupIntSlice(name, c.flagSet) -} - -// Looks up the value of a local generic flag, returns nil if no generic flag exists -func (c *Context) Generic(name string) interface{} { - return lookupGeneric(name, c.flagSet) -} - -// Looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalInt(name string) int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt(name, fs) + if parentCtx != nil { + c.shellComplete = parentCtx.shellComplete } - return 0 + + return c } -// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists -func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupDuration(name, fs) - } - return 0 -} - -// Looks up the value of a global bool flag, returns false if no bool flag exists -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -// Looks up the value of a global string flag, returns "" if no string flag exists -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -// Looks up the value of a global string slice flag, returns nil if no string slice flag exists -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -// Looks up the value of a global int slice flag, returns nil if no int slice flag exists -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -// Looks up the value of a global generic flag, returns nil if no generic flag exists -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil -} - -// Returns the number of flags set +// NumFlags returns the number of flags set func (c *Context) NumFlags() int { return c.flagSet.NFlag() } -// Determines if the flag was actually set +// Set sets a context flag to a value. +func (c *Context) Set(name, value string) error { + c.setFlags = nil + return c.flagSet.Set(name, value) +} + +// GlobalSet sets a context flag to a value on the global flagset +func (c *Context) GlobalSet(name, value string) error { + globalContext(c).setFlags = nil + return globalContext(c).flagSet.Set(name, value) +} + +// IsSet determines if the flag was actually set func (c *Context) IsSet(name string) bool { if c.setFlags == nil { c.setFlags = make(map[string]bool) + c.flagSet.Visit(func(f *flag.Flag) { c.setFlags[f.Name] = true }) - } - return c.setFlags[name] == true -} -// Determines if the global flag was actually set -func (c *Context) GlobalIsSet(name string) bool { - if c.globalSetFlags == nil { - c.globalSetFlags = make(map[string]bool) - ctx := c - if ctx.parentContext != nil { - ctx = ctx.parentContext + c.flagSet.VisitAll(func(f *flag.Flag) { + if _, ok := c.setFlags[f.Name]; ok { + return + } + c.setFlags[f.Name] = false + }) + + // XXX hack to support IsSet for flags with EnvVar + // + // There isn't an easy way to do this with the current implementation since + // whether a flag was set via an environment variable is very difficult to + // determine here. Instead, we intend to introduce a backwards incompatible + // change in version 2 to add `IsSet` to the Flag interface to push the + // responsibility closer to where the information required to determine + // whether a flag is set by non-standard means such as environment + // variables is avaliable. + // + // See https://github.com/urfave/cli/issues/294 for additional discussion + flags := c.Command.Flags + if c.Command.Name == "" { // cannot == Command{} since it contains slice types + if c.App != nil { + flags = c.App.Flags + } } - for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext { - ctx.flagSet.Visit(func(f *flag.Flag) { - c.globalSetFlags[f.Name] = true + for _, f := range flags { + eachName(f.GetName(), func(name string) { + if isSet, ok := c.setFlags[name]; isSet || !ok { + return + } + + val := reflect.ValueOf(f) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + envVarValue := val.FieldByName("EnvVar") + if !envVarValue.IsValid() { + return + } + + eachName(envVarValue.String(), func(envVar string) { + envVar = strings.TrimSpace(envVar) + if _, ok := syscall.Getenv(envVar); ok { + c.setFlags[name] = true + return + } + }) }) } } - return c.globalSetFlags[name] + + return c.setFlags[name] } -// Returns a slice of flag names used in this context. +// GlobalIsSet determines if the global flag was actually set +func (c *Context) GlobalIsSet(name string) bool { + ctx := c + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + + for ; ctx != nil; ctx = ctx.parentContext { + if ctx.IsSet(name) { + return true + } + } + return false +} + +// FlagNames returns a slice of flag names used in this context. func (c *Context) FlagNames() (names []string) { for _, flag := range c.Command.Flags { name := strings.Split(flag.GetName(), ",")[0] @@ -172,7 +139,7 @@ func (c *Context) FlagNames() (names []string) { return } -// Returns a slice of global flag names used by the app. +// GlobalFlagNames returns a slice of global flag names used by the app. func (c *Context) GlobalFlagNames() (names []string) { for _, flag := range c.App.Flags { name := strings.Split(flag.GetName(), ",")[0] @@ -184,20 +151,31 @@ func (c *Context) GlobalFlagNames() (names []string) { return } -// Returns the parent context, if any +// Parent returns the parent context, if any func (c *Context) Parent() *Context { return c.parentContext } +// value returns the value of the flag coressponding to `name` +func (c *Context) value(name string) interface{} { + return c.flagSet.Lookup(name).Value.(flag.Getter).Get() +} + +// Args contains apps console arguments type Args []string -// Returns the command line arguments associated with the context. +// Args returns the command line arguments associated with the context. func (c *Context) Args() Args { args := Args(c.flagSet.Args()) return args } -// Returns the nth argument, or else a blank string +// NArg returns the number of the command line arguments. +func (c *Context) NArg() int { + return len(c.Args()) +} + +// Get returns the nth argument, or else a blank string func (a Args) Get(n int) string { if len(a) > n { return a[n] @@ -205,12 +183,12 @@ func (a Args) Get(n int) string { return "" } -// Returns the first argument, or else a blank string +// First returns the first argument, or else a blank string func (a Args) First() string { return a.Get(0) } -// Return the rest of the arguments (not the first one) +// Tail returns the rest of the arguments (not the first one) // or else an empty string slice func (a Args) Tail() []string { if len(a) >= 2 { @@ -219,12 +197,12 @@ func (a Args) Tail() []string { return []string{} } -// Checks if there are any arguments present +// Present checks if there are any arguments present func (a Args) Present() bool { return len(a) != 0 } -// Swaps arguments at the given indexes +// Swap swaps arguments at the given indexes func (a Args) Swap(from, to int) error { if from >= len(a) || to >= len(a) { return errors.New("index out of range") @@ -233,6 +211,19 @@ func (a Args) Swap(from, to int) error { return nil } +func globalContext(ctx *Context) *Context { + if ctx == nil { + return nil + } + + for { + if ctx.parentContext == nil { + return ctx + } + ctx = ctx.parentContext + } +} + func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { if ctx.parentContext != nil { ctx = ctx.parentContext @@ -245,107 +236,6 @@ func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { return nil } -func lookupInt(name string, set *flag.FlagSet) int { - f := set.Lookup(name) - if f != nil { - val, err := strconv.Atoi(f.Value.String()) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupDuration(name string, set *flag.FlagSet) time.Duration { - f := set.Lookup(name) - if f != nil { - val, err := time.ParseDuration(f.Value.String()) - if err == nil { - return val - } - } - - return 0 -} - -func lookupFloat64(name string, set *flag.FlagSet) float64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseFloat(f.Value.String(), 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - return f.Value.String() - } - - return "" -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*StringSlice)).Value() - - } - - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*IntSlice)).Value() - - } - - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - return f.Value - } - return nil -} - -func lookupBool(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return val - } - - return false -} - -func lookupBoolT(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return true - } - return val - } - - return false -} - func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { switch ff.Value.(type) { case *StringSlice: diff --git a/vendor/github.com/codegangsta/cli/errors.go b/vendor/github.com/codegangsta/cli/errors.go new file mode 100644 index 00000000000..562b2953cf2 --- /dev/null +++ b/vendor/github.com/codegangsta/cli/errors.go @@ -0,0 +1,115 @@ +package cli + +import ( + "fmt" + "io" + "os" + "strings" +) + +// OsExiter is the function used when the app exits. If not set defaults to os.Exit. +var OsExiter = os.Exit + +// ErrWriter is used to write errors to the user. This can be anything +// implementing the io.Writer interface and defaults to os.Stderr. +var ErrWriter io.Writer = os.Stderr + +// MultiError is an error that wraps multiple errors. +type MultiError struct { + Errors []error +} + +// NewMultiError creates a new MultiError. Pass in one or more errors. +func NewMultiError(err ...error) MultiError { + return MultiError{Errors: err} +} + +// Error implements the error interface. +func (m MultiError) Error() string { + errs := make([]string, len(m.Errors)) + for i, err := range m.Errors { + errs[i] = err.Error() + } + + return strings.Join(errs, "\n") +} + +type ErrorFormatter interface { + Format(s fmt.State, verb rune) +} + +// ExitCoder is the interface checked by `App` and `Command` for a custom exit +// code +type ExitCoder interface { + error + ExitCode() int +} + +// ExitError fulfills both the builtin `error` interface and `ExitCoder` +type ExitError struct { + exitCode int + message interface{} +} + +// NewExitError makes a new *ExitError +func NewExitError(message interface{}, exitCode int) *ExitError { + return &ExitError{ + exitCode: exitCode, + message: message, + } +} + +// Error returns the string message, fulfilling the interface required by +// `error` +func (ee *ExitError) Error() string { + return fmt.Sprintf("%v", ee.message) +} + +// ExitCode returns the exit code, fulfilling the interface required by +// `ExitCoder` +func (ee *ExitError) ExitCode() int { + return ee.exitCode +} + +// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if +// so prints the error to stderr (if it is non-empty) and calls OsExiter with the +// given exit code. If the given error is a MultiError, then this func is +// called on all members of the Errors slice and calls OsExiter with the last exit code. +func HandleExitCoder(err error) { + if err == nil { + return + } + + if exitErr, ok := err.(ExitCoder); ok { + if err.Error() != "" { + if _, ok := exitErr.(ErrorFormatter); ok { + fmt.Fprintf(ErrWriter, "%+v\n", err) + } else { + fmt.Fprintln(ErrWriter, err) + } + } + OsExiter(exitErr.ExitCode()) + return + } + + if multiErr, ok := err.(MultiError); ok { + code := handleMultiError(multiErr) + OsExiter(code) + return + } +} + +func handleMultiError(multiErr MultiError) int { + code := 1 + for _, merr := range multiErr.Errors { + if multiErr2, ok := merr.(MultiError); ok { + code = handleMultiError(multiErr2) + } else { + fmt.Fprintln(ErrWriter, merr) + if exitErr, ok := merr.(ExitCoder); ok { + code = exitErr.ExitCode() + } + } + } + return code +} diff --git a/vendor/github.com/codegangsta/cli/flag.go b/vendor/github.com/codegangsta/cli/flag.go index 49f30994ea6..877ff3523db 100644 --- a/vendor/github.com/codegangsta/cli/flag.go +++ b/vendor/github.com/codegangsta/cli/flag.go @@ -3,33 +3,57 @@ package cli import ( "flag" "fmt" - "os" + "reflect" + "runtime" "strconv" "strings" + "syscall" "time" ) -// This flag enables bash-completion for all commands and subcommands -var BashCompletionFlag = BoolFlag{ - Name: "generate-bash-completion", +const defaultPlaceholder = "value" + +// BashCompletionFlag enables bash-completion for all commands and subcommands +var BashCompletionFlag Flag = BoolFlag{ + Name: "generate-bash-completion", + Hidden: true, } -// This flag prints the version for the application -var VersionFlag = BoolFlag{ +// VersionFlag prints the version for the application +var VersionFlag Flag = BoolFlag{ Name: "version, v", Usage: "print the version", } -// This flag prints the help for all commands and subcommands +// HelpFlag prints the help for all commands and subcommands // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand // unless HideHelp is set to true) -var HelpFlag = BoolFlag{ +var HelpFlag Flag = BoolFlag{ Name: "help, h", Usage: "show help", } +// FlagStringer converts a flag definition to a string. This is used by help +// to display a flag. +var FlagStringer FlagStringFunc = stringifyFlag + +// FlagsByName is a slice of Flag. +type FlagsByName []Flag + +func (f FlagsByName) Len() int { + return len(f) +} + +func (f FlagsByName) Less(i, j int) bool { + return f[i].GetName() < f[j].GetName() +} + +func (f FlagsByName) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + // Flag is a common interface related to parsing flags in cli. -// For more advanced flag parsing techniques, it is recomended that +// For more advanced flag parsing techniques, it is recommended that // this interface be implemented. type Flag interface { fmt.Stringer @@ -38,13 +62,29 @@ type Flag interface { GetName() string } -func flagSet(name string, flags []Flag) *flag.FlagSet { +// errorableFlag is an interface that allows us to return errors during apply +// it allows flags defined in this library to return errors in a fashion backwards compatible +// TODO remove in v2 and modify the existing Flag interface to return errors +type errorableFlag interface { + Flag + + ApplyWithError(*flag.FlagSet) error +} + +func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { set := flag.NewFlagSet(name, flag.ContinueOnError) for _, f := range flags { - f.Apply(set) + //TODO remove in v2 when errorableFlag is removed + if ef, ok := f.(errorableFlag); ok { + if err := ef.ApplyWithError(set); err != nil { + return nil, err + } + } else { + f.Apply(set) + } } - return set + return set, nil } func eachName(longName string, fn func(string)) { @@ -61,30 +101,24 @@ type Generic interface { String() string } -// GenericFlag is the flag type for types implementing Generic -type GenericFlag struct { - Name string - Value Generic - Usage string - EnvVar string -} - -// String returns the string representation of the generic flag to display the -// help text to the user (uses the String() method of the generic flag to show -// the value) -func (f GenericFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage)) -} - // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag +// Ignores parsing errors func (f GenericFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error { val := f.Value if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - val.Set(envVal) + if envVal, ok := syscall.Getenv(envVar); ok { + if err := val.Set(envVal); err != nil { + return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err) + } break } } @@ -93,13 +127,11 @@ func (f GenericFlag) Apply(set *flag.FlagSet) { eachName(f.Name, func(name string) { set.Var(f.Value, name, f.Usage) }) + + return nil } -func (f GenericFlag) GetName() string { - return f.Name -} - -// StringSlice is an opaque type for []string to satisfy flag.Value +// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter type StringSlice []string // Set appends the string value to the list of values @@ -118,32 +150,29 @@ func (f *StringSlice) Value() []string { return *f } -// StringSlice is a string flag that can be specified multiple times on the -// command-line -type StringSliceFlag struct { - Name string - Value *StringSlice - Usage string - EnvVar string -} - -// String returns the usage -func (f StringSliceFlag) String() string { - firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") - pref := prefixFor(firstName) - return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +// Get returns the slice of strings set by this flag +func (f *StringSlice) Get() interface{} { + return *f } // Apply populates the flag given the flag set and environment +// Ignores errors func (f StringSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { newVal := &StringSlice{} for _, s := range strings.Split(envVal, ",") { s = strings.TrimSpace(s) - newVal.Set(s) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) + } } f.Value = newVal break @@ -157,13 +186,11 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) { } set.Var(f.Value, name, f.Usage) }) + + return nil } -func (f StringSliceFlag) GetName() string { - return f.Name -} - -// StringSlice is an opaque type for []int to satisfy flag.Value +// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter type IntSlice []int // Set parses the value into an integer and appends it to the list of values @@ -171,15 +198,14 @@ func (f *IntSlice) Set(value string) error { tmp, err := strconv.Atoi(value) if err != nil { return err - } else { - *f = append(*f, tmp) } + *f = append(*f, tmp) return nil } // String returns a readable representation of this value (for usage defaults) func (f *IntSlice) String() string { - return fmt.Sprintf("%d", *f) + return fmt.Sprintf("%#v", *f) } // Value returns the slice of ints set by this flag @@ -187,34 +213,28 @@ func (f *IntSlice) Value() []int { return *f } -// IntSliceFlag is an int flag that can be specified multiple times on the -// command-line -type IntSliceFlag struct { - Name string - Value *IntSlice - Usage string - EnvVar string -} - -// String returns the usage -func (f IntSliceFlag) String() string { - firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") - pref := prefixFor(firstName) - return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +// Get returns the slice of ints set by this flag +func (f *IntSlice) Get() interface{} { + return *f } // Apply populates the flag given the flag set and environment +// Ignores errors func (f IntSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { newVal := &IntSlice{} for _, s := range strings.Split(envVal, ",") { s = strings.TrimSpace(s) - err := newVal.Set(s) - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) } } f.Value = newVal @@ -229,36 +249,96 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) { } set.Var(f.Value, name, f.Usage) }) + + return nil } -func (f IntSliceFlag) GetName() string { - return f.Name -} +// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter +type Int64Slice []int64 -// BoolFlag is a switch that defaults to false -type BoolFlag struct { - Name string - Usage string - EnvVar string - Destination *bool +// Set parses the value into an integer and appends it to the list of values +func (f *Int64Slice) Set(value string) error { + tmp, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + *f = append(*f, tmp) + return nil } // String returns a readable representation of this value (for usage defaults) -func (f BoolFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +func (f *Int64Slice) String() string { + return fmt.Sprintf("%#v", *f) +} + +// Value returns the slice of ints set by this flag +func (f *Int64Slice) Value() []int64 { + return *f +} + +// Get returns the slice of ints set by this flag +func (f *Int64Slice) Get() interface{} { + return *f } // Apply populates the flag given the flag set and environment +// Ignores errors +func (f Int64SliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + newVal := &Int64Slice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Value == nil { + f.Value = &Int64Slice{} + } + set.Var(f.Value, name, f.Usage) + }) + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors func (f BoolFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { val := false if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValBool, err := strconv.ParseBool(envVal) - if err == nil { - val = envValBool + if envVal, ok := syscall.Getenv(envVar); ok { + if envVal == "" { + val = false + break } + + envValBool, err := strconv.ParseBool(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) + } + + val = envValBool break } } @@ -271,38 +351,35 @@ func (f BoolFlag) Apply(set *flag.FlagSet) { } set.Bool(name, val, f.Usage) }) -} -func (f BoolFlag) GetName() string { - return f.Name -} - -// BoolTFlag this represents a boolean flag that is true by default, but can -// still be set to false by --some-flag=false -type BoolTFlag struct { - Name string - Usage string - EnvVar string - Destination *bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolTFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f BoolTFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { val := true if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValBool, err := strconv.ParseBool(envVal) - if err == nil { - val = envValBool + if envVal, ok := syscall.Getenv(envVar); ok { + if envVal == "" { + val = false break } + + envValBool, err := strconv.ParseBool(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) + } + + val = envValBool + break } } } @@ -314,41 +391,22 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) { } set.Bool(name, val, f.Usage) }) -} -func (f BoolTFlag) GetName() string { - return f.Name -} - -// StringFlag represents a flag that takes as string value -type StringFlag struct { - Name string - Value string - Usage string - EnvVar string - Destination *string -} - -// String returns the usage -func (f StringFlag) String() string { - var fmtString string - fmtString = "%s %v\t%v" - - if len(f.Value) > 0 { - fmtString = "%s \"%v\"\t%v" - } else { - fmtString = "%s %v\t%v" - } - - return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f StringFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { f.Value = envVal break } @@ -362,38 +420,28 @@ func (f StringFlag) Apply(set *flag.FlagSet) { } set.String(name, f.Value, f.Usage) }) -} -func (f StringFlag) GetName() string { - return f.Name -} - -// IntFlag is a flag that takes an integer -// Errors if the value provided cannot be parsed -type IntFlag struct { - Name string - Value int - Usage string - EnvVar string - Destination *int -} - -// String returns the usage -func (f IntFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f IntFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err == nil { - f.Value = int(envValInt) - break + if err != nil { + return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) } + f.Value = int(envValInt) + break } } } @@ -405,38 +453,131 @@ func (f IntFlag) Apply(set *flag.FlagSet) { } set.Int(name, f.Value, f.Usage) }) -} -func (f IntFlag) GetName() string { - return f.Name -} - -// DurationFlag is a flag that takes a duration specified in Go's duration -// format: https://golang.org/pkg/time/#ParseDuration -type DurationFlag struct { - Name string - Value time.Duration - Usage string - EnvVar string - Destination *time.Duration -} - -// String returns a readable representation of this value (for usage defaults) -func (f DurationFlag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) + return nil } // Apply populates the flag given the flag set and environment -func (f DurationFlag) Apply(set *flag.FlagSet) { +// Ignores errors +func (f Int64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValDuration, err := time.ParseDuration(envVal) - if err == nil { - f.Value = envValDuration - break + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseInt(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) } + + f.Value = envValInt + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.Int64Var(f.Destination, name, f.Value, f.Usage) + return + } + set.Int64(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f UintFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseUint(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) + } + + f.Value = uint(envValInt) + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.UintVar(f.Destination, name, f.Value, f.Usage) + return + } + set.Uint(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f Uint64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseUint(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) + } + + f.Value = uint64(envValInt) + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.Uint64Var(f.Destination, name, f.Value, f.Usage) + return + } + set.Uint64(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f DurationFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValDuration, err := time.ParseDuration(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) + } + + f.Value = envValDuration + break } } } @@ -448,37 +589,29 @@ func (f DurationFlag) Apply(set *flag.FlagSet) { } set.Duration(name, f.Value, f.Usage) }) -} -func (f DurationFlag) GetName() string { - return f.Name -} - -// Float64Flag is a flag that takes an float value -// Errors if the value provided cannot be parsed -type Float64Flag struct { - Name string - Value float64 - Usage string - EnvVar string - Destination *float64 -} - -// String returns the usage -func (f Float64Flag) String() string { - return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f Float64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValFloat, err := strconv.ParseFloat(envVal, 10) - if err == nil { - f.Value = float64(envValFloat) + if err != nil { + return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) } + + f.Value = float64(envValFloat) + break } } } @@ -490,10 +623,19 @@ func (f Float64Flag) Apply(set *flag.FlagSet) { } set.Float64(name, f.Value, f.Usage) }) + + return nil } -func (f Float64Flag) GetName() string { - return f.Name +func visibleFlags(fl []Flag) []Flag { + visible := []Flag{} + for _, flag := range fl { + field := flagValue(flag).FieldByName("Hidden") + if !field.IsValid() || !field.Bool() { + visible = append(visible, flag) + } + } + return visible } func prefixFor(name string) (prefix string) { @@ -506,22 +648,152 @@ func prefixFor(name string) (prefix string) { return } -func prefixedNames(fullName string) (prefixed string) { +// Returns the placeholder, if any, and the unquoted usage string. +func unquoteUsage(usage string) (string, string) { + for i := 0; i < len(usage); i++ { + if usage[i] == '`' { + for j := i + 1; j < len(usage); j++ { + if usage[j] == '`' { + name := usage[i+1 : j] + usage = usage[:i] + name + usage[j+1:] + return name, usage + } + } + break + } + } + return "", usage +} + +func prefixedNames(fullName, placeholder string) string { + var prefixed string parts := strings.Split(fullName, ",") for i, name := range parts { name = strings.Trim(name, " ") prefixed += prefixFor(name) + name + if placeholder != "" { + prefixed += " " + placeholder + } if i < len(parts)-1 { prefixed += ", " } } - return + return prefixed } func withEnvHint(envVar, str string) string { envText := "" if envVar != "" { - envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $")) + prefix := "$" + suffix := "" + sep := ", $" + if runtime.GOOS == "windows" { + prefix = "%" + suffix = "%" + sep = "%, %" + } + envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix) } return str + envText } + +func flagValue(f Flag) reflect.Value { + fv := reflect.ValueOf(f) + for fv.Kind() == reflect.Ptr { + fv = reflect.Indirect(fv) + } + return fv +} + +func stringifyFlag(f Flag) string { + fv := flagValue(f) + + switch f.(type) { + case IntSliceFlag: + return withEnvHint(fv.FieldByName("EnvVar").String(), + stringifyIntSliceFlag(f.(IntSliceFlag))) + case Int64SliceFlag: + return withEnvHint(fv.FieldByName("EnvVar").String(), + stringifyInt64SliceFlag(f.(Int64SliceFlag))) + case StringSliceFlag: + return withEnvHint(fv.FieldByName("EnvVar").String(), + stringifyStringSliceFlag(f.(StringSliceFlag))) + } + + placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) + + needsPlaceholder := false + defaultValueString := "" + + if val := fv.FieldByName("Value"); val.IsValid() { + needsPlaceholder = true + defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) + + if val.Kind() == reflect.String && val.String() != "" { + defaultValueString = fmt.Sprintf(" (default: %q)", val.String()) + } + } + + if defaultValueString == " (default: )" { + defaultValueString = "" + } + + if needsPlaceholder && placeholder == "" { + placeholder = defaultPlaceholder + } + + usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString)) + + return withEnvHint(fv.FieldByName("EnvVar").String(), + fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault)) +} + +func stringifyIntSliceFlag(f IntSliceFlag) string { + defaultVals := []string{} + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) + } + } + + return stringifySliceFlag(f.Usage, f.Name, defaultVals) +} + +func stringifyInt64SliceFlag(f Int64SliceFlag) string { + defaultVals := []string{} + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) + } + } + + return stringifySliceFlag(f.Usage, f.Name, defaultVals) +} + +func stringifyStringSliceFlag(f StringSliceFlag) string { + defaultVals := []string{} + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, s := range f.Value.Value() { + if len(s) > 0 { + defaultVals = append(defaultVals, fmt.Sprintf("%q", s)) + } + } + } + + return stringifySliceFlag(f.Usage, f.Name, defaultVals) +} + +func stringifySliceFlag(usage, name string, defaultVals []string) string { + placeholder, usage := unquoteUsage(usage) + if placeholder == "" { + placeholder = defaultPlaceholder + } + + defaultVal := "" + if len(defaultVals) > 0 { + defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) + } + + usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) + return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault) +} diff --git a/vendor/github.com/codegangsta/cli/flag_generated.go b/vendor/github.com/codegangsta/cli/flag_generated.go new file mode 100644 index 00000000000..491b61956c7 --- /dev/null +++ b/vendor/github.com/codegangsta/cli/flag_generated.go @@ -0,0 +1,627 @@ +package cli + +import ( + "flag" + "strconv" + "time" +) + +// WARNING: This file is generated! + +// BoolFlag is a flag with type bool +type BoolFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolFlag) GetName() string { + return f.Name +} + +// Bool looks up the value of a local BoolFlag, returns +// false if not found +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// GlobalBool looks up the value of a global BoolFlag, returns +// false if not found +func (c *Context) GlobalBool(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBool(name, fs) + } + return false +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + +// BoolTFlag is a flag with type bool that is true by default +type BoolTFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolTFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolTFlag) GetName() string { + return f.Name +} + +// BoolT looks up the value of a local BoolTFlag, returns +// false if not found +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// GlobalBoolT looks up the value of a global BoolTFlag, returns +// false if not found +func (c *Context) GlobalBoolT(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBoolT(name, fs) + } + return false +} + +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + +// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) +type DurationFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value time.Duration + Destination *time.Duration +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f DurationFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f DurationFlag) GetName() string { + return f.Name +} + +// Duration looks up the value of a local DurationFlag, returns +// 0 if not found +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// GlobalDuration looks up the value of a global DurationFlag, returns +// 0 if not found +func (c *Context) GlobalDuration(name string) time.Duration { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupDuration(name, fs) + } + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + parsed, err := time.ParseDuration(f.Value.String()) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// Float64Flag is a flag with type float64 +type Float64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value float64 + Destination *float64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Float64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Float64Flag) GetName() string { + return f.Name +} + +// Float64 looks up the value of a local Float64Flag, returns +// 0 if not found +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// GlobalFloat64 looks up the value of a global Float64Flag, returns +// 0 if not found +func (c *Context) GlobalFloat64(name string) float64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupFloat64(name, fs) + } + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// GenericFlag is a flag with type Generic +type GenericFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value Generic +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f GenericFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f GenericFlag) GetName() string { + return f.Name +} + +// Generic looks up the value of a local GenericFlag, returns +// nil if not found +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// GlobalGeneric looks up the value of a global GenericFlag, returns +// nil if not found +func (c *Context) GlobalGeneric(name string) interface{} { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupGeneric(name, fs) + } + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value, error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Int64Flag is a flag with type int64 +type Int64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int64 + Destination *int64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64Flag) GetName() string { + return f.Name +} + +// Int64 looks up the value of a local Int64Flag, returns +// 0 if not found +func (c *Context) Int64(name string) int64 { + return lookupInt64(name, c.flagSet) +} + +// GlobalInt64 looks up the value of a global Int64Flag, returns +// 0 if not found +func (c *Context) GlobalInt64(name string) int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64(name, fs) + } + return 0 +} + +func lookupInt64(name string, set *flag.FlagSet) int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// IntFlag is a flag with type int +type IntFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int + Destination *int +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntFlag) GetName() string { + return f.Name +} + +// Int looks up the value of a local IntFlag, returns +// 0 if not found +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// GlobalInt looks up the value of a global IntFlag, returns +// 0 if not found +func (c *Context) GlobalInt(name string) int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt(name, fs) + } + return 0 +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return int(parsed) + } + return 0 +} + +// IntSliceFlag is a flag with type *IntSlice +type IntSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *IntSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntSliceFlag) GetName() string { + return f.Name +} + +// IntSlice looks up the value of a local IntSliceFlag, returns +// nil if not found +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// GlobalIntSlice looks up the value of a global IntSliceFlag, returns +// nil if not found +func (c *Context) GlobalIntSlice(name string) []int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupIntSlice(name, fs) + } + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Int64SliceFlag is a flag with type *Int64Slice +type Int64SliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *Int64Slice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64SliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64SliceFlag) GetName() string { + return f.Name +} + +// Int64Slice looks up the value of a local Int64SliceFlag, returns +// nil if not found +func (c *Context) Int64Slice(name string) []int64 { + return lookupInt64Slice(name, c.flagSet) +} + +// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns +// nil if not found +func (c *Context) GlobalInt64Slice(name string) []int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64Slice(name, fs) + } + return nil +} + +func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// StringFlag is a flag with type string +type StringFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value string + Destination *string +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringFlag) GetName() string { + return f.Name +} + +// String looks up the value of a local StringFlag, returns +// "" if not found +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// GlobalString looks up the value of a global StringFlag, returns +// "" if not found +func (c *Context) GlobalString(name string) string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupString(name, fs) + } + return "" +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value.String(), error(nil) + if err != nil { + return "" + } + return parsed + } + return "" +} + +// StringSliceFlag is a flag with type *StringSlice +type StringSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *StringSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringSliceFlag) GetName() string { + return f.Name +} + +// StringSlice looks up the value of a local StringSliceFlag, returns +// nil if not found +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// GlobalStringSlice looks up the value of a global StringSliceFlag, returns +// nil if not found +func (c *Context) GlobalStringSlice(name string) []string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupStringSlice(name, fs) + } + return nil +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Uint64Flag is a flag with type uint64 +type Uint64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint64 + Destination *uint64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Uint64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Uint64Flag) GetName() string { + return f.Name +} + +// Uint64 looks up the value of a local Uint64Flag, returns +// 0 if not found +func (c *Context) Uint64(name string) uint64 { + return lookupUint64(name, c.flagSet) +} + +// GlobalUint64 looks up the value of a global Uint64Flag, returns +// 0 if not found +func (c *Context) GlobalUint64(name string) uint64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupUint64(name, fs) + } + return 0 +} + +func lookupUint64(name string, set *flag.FlagSet) uint64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// UintFlag is a flag with type uint +type UintFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint + Destination *uint +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f UintFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f UintFlag) GetName() string { + return f.Name +} + +// Uint looks up the value of a local UintFlag, returns +// 0 if not found +func (c *Context) Uint(name string) uint { + return lookupUint(name, c.flagSet) +} + +// GlobalUint looks up the value of a global UintFlag, returns +// 0 if not found +func (c *Context) GlobalUint(name string) uint { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupUint(name, fs) + } + return 0 +} + +func lookupUint(name string, set *flag.FlagSet) uint { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return uint(parsed) + } + return 0 +} diff --git a/vendor/github.com/codegangsta/cli/funcs.go b/vendor/github.com/codegangsta/cli/funcs.go new file mode 100644 index 00000000000..cba5e6cb0cc --- /dev/null +++ b/vendor/github.com/codegangsta/cli/funcs.go @@ -0,0 +1,28 @@ +package cli + +// BashCompleteFunc is an action to execute when the bash-completion flag is set +type BashCompleteFunc func(*Context) + +// BeforeFunc is an action to execute before any subcommands are run, but after +// the context is ready if a non-nil error is returned, no subcommands are run +type BeforeFunc func(*Context) error + +// AfterFunc is an action to execute after any subcommands are run, but after the +// subcommand has finished it is run even if Action() panics +type AfterFunc func(*Context) error + +// ActionFunc is the action to execute when no subcommands are specified +type ActionFunc func(*Context) error + +// CommandNotFoundFunc is executed if the proper command cannot be found +type CommandNotFoundFunc func(*Context, string) + +// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying +// customized usage error messages. This function is able to replace the +// original error messages. If this function is not set, the "Incorrect usage" +// is displayed and the execution is interrupted. +type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error + +// FlagStringFunc is used by the help generation to display a flag, which is +// expected to be a single line. +type FlagStringFunc func(Flag) string diff --git a/vendor/github.com/codegangsta/cli/help.go b/vendor/github.com/codegangsta/cli/help.go index a246f63ac4d..57ec98d58ad 100644 --- a/vendor/github.com/codegangsta/cli/help.go +++ b/vendor/github.com/codegangsta/cli/help.go @@ -3,68 +3,78 @@ package cli import ( "fmt" "io" + "os" "strings" "text/tabwriter" "text/template" ) -// The text template for the Default help topic. +// AppHelpTemplate is the text template for the Default help topic. // cli.go uses text/template to render templates. You can // render custom help text by setting this variable. var AppHelpTemplate = `NAME: - {{.Name}} - {{.Usage}} + {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} USAGE: - {{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if .Version}} + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + VERSION: - {{.Version}} - {{end}}{{if len .Authors}} -AUTHOR(S): - {{range .Authors}}{{ . }}{{end}} - {{end}}{{if .Commands}} -COMMANDS: - {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .Flags}} + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if len .Authors}} + +AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: + {{range $index, $author := .Authors}}{{if $index}} + {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{range .VisibleCategories}}{{if .Name}} + {{.Name}}:{{end}}{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} + GLOBAL OPTIONS: - {{range .Flags}}{{.}} - {{end}}{{end}}{{if .Copyright }} + {{range $index, $option := .VisibleFlags}}{{if $index}} + {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} + COPYRIGHT: - {{.Copyright}} - {{end}} + {{.Copyright}}{{end}} ` -// The text template for the command help topic. +// CommandHelpTemplate is the text template for the command help topic. // cli.go uses text/template to render templates. You can // render custom help text by setting this variable. var CommandHelpTemplate = `NAME: {{.HelpName}} - {{.Usage}} USAGE: - {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}} + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} DESCRIPTION: - {{.Description}}{{end}}{{if .Flags}} + {{.Description}}{{end}}{{if .VisibleFlags}} OPTIONS: - {{range .Flags}}{{.}} - {{end}}{{ end }} + {{range .VisibleFlags}}{{.}} + {{end}}{{end}} ` -// The text template for the subcommand help topic. +// SubcommandHelpTemplate is the text template for the subcommand help topic. // cli.go uses text/template to render templates. You can // render custom help text by setting this variable. var SubcommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} + {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} USAGE: - {{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} -COMMANDS: - {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{if .Flags}} +COMMANDS:{{range .VisibleCategories}}{{if .Name}} + {{.Name}}:{{end}}{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} +{{end}}{{if .VisibleFlags}} OPTIONS: - {{range .Flags}}{{.}} + {{range .VisibleFlags}}{{.}} {{end}}{{end}} ` @@ -73,13 +83,14 @@ var helpCommand = Command{ Aliases: []string{"h"}, Usage: "Shows a list of commands or help for one command", ArgsUsage: "[command]", - Action: func(c *Context) { + Action: func(c *Context) error { args := c.Args() if args.Present() { - ShowCommandHelp(c, args.First()) - } else { - ShowAppHelp(c) + return ShowCommandHelp(c, args.First()) } + + ShowAppHelp(c) + return nil }, } @@ -88,65 +99,109 @@ var helpSubcommand = Command{ Aliases: []string{"h"}, Usage: "Shows a list of commands or help for one command", ArgsUsage: "[command]", - Action: func(c *Context) { + Action: func(c *Context) error { args := c.Args() if args.Present() { - ShowCommandHelp(c, args.First()) - } else { - ShowSubcommandHelp(c) + return ShowCommandHelp(c, args.First()) } + + return ShowSubcommandHelp(c) }, } // Prints help for the App or Command type helpPrinter func(w io.Writer, templ string, data interface{}) +// Prints help for the App or Command with custom template function. +type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) + +// HelpPrinter is a function that writes the help output. If not set a default +// is used. The function signature is: +// func(w io.Writer, templ string, data interface{}) var HelpPrinter helpPrinter = printHelp -// Prints version for the App +// HelpPrinterCustom is same as HelpPrinter but +// takes a custom function for template function map. +var HelpPrinterCustom helpPrinterCustom = printHelpCustom + +// VersionPrinter prints the version for the App var VersionPrinter = printVersion -func ShowAppHelp(c *Context) { - HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) +// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. +func ShowAppHelpAndExit(c *Context, exitCode int) { + ShowAppHelp(c) + os.Exit(exitCode) } -// Prints the list of subcommands as the default app completion method +// ShowAppHelp is an action that displays the help. +func ShowAppHelp(c *Context) (err error) { + if c.App.CustomAppHelpTemplate == "" { + HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) + return + } + customAppData := func() map[string]interface{} { + if c.App.ExtraInfo == nil { + return nil + } + return map[string]interface{}{ + "ExtraInfo": c.App.ExtraInfo, + } + } + HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData()) + return nil +} + +// DefaultAppComplete prints the list of subcommands as the default app completion method func DefaultAppComplete(c *Context) { for _, command := range c.App.Commands { + if command.Hidden { + continue + } for _, name := range command.Names() { fmt.Fprintln(c.App.Writer, name) } } } -// Prints help for the given command -func ShowCommandHelp(ctx *Context, command string) { +// ShowCommandHelpAndExit - exits with code after showing help +func ShowCommandHelpAndExit(c *Context, command string, code int) { + ShowCommandHelp(c, command) + os.Exit(code) +} + +// ShowCommandHelp prints help for the given command +func ShowCommandHelp(ctx *Context, command string) error { // show the subcommand help for a command with subcommands if command == "" { HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) - return + return nil } for _, c := range ctx.App.Commands { if c.HasName(command) { - HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) - return + if c.CustomHelpTemplate != "" { + HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil) + } else { + HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) + } + return nil } } - if ctx.App.CommandNotFound != nil { - ctx.App.CommandNotFound(ctx, command) - } else { - fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command) + if ctx.App.CommandNotFound == nil { + return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) } + + ctx.App.CommandNotFound(ctx, command) + return nil } -// Prints help for the given subcommand -func ShowSubcommandHelp(c *Context) { - ShowCommandHelp(c, c.Command.Name) +// ShowSubcommandHelp prints help for the given subcommand +func ShowSubcommandHelp(c *Context) error { + return ShowCommandHelp(c, c.Command.Name) } -// Prints the version number of the App +// ShowVersion prints the version number of the App func ShowVersion(c *Context) { VersionPrinter(c) } @@ -155,7 +210,7 @@ func printVersion(c *Context) { fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) } -// Prints the lists of commands within a given context +// ShowCompletions prints the lists of commands within a given context func ShowCompletions(c *Context) { a := c.App if a != nil && a.BashComplete != nil { @@ -163,7 +218,7 @@ func ShowCompletions(c *Context) { } } -// Prints the custom completions for a given command +// ShowCommandCompletions prints the custom completions for a given command func ShowCommandCompletions(ctx *Context, command string) { c := ctx.App.Command(command) if c != nil && c.BashComplete != nil { @@ -171,24 +226,38 @@ func ShowCommandCompletions(ctx *Context, command string) { } } -func printHelp(out io.Writer, templ string, data interface{}) { +func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { funcMap := template.FuncMap{ "join": strings.Join, } + if customFunc != nil { + for key, value := range customFunc { + funcMap[key] = value + } + } - w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0) + w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) err := t.Execute(w, data) if err != nil { - panic(err) + // If the writer is closed, t.Execute will fail, and there's nothing + // we can do to recover. + if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { + fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) + } + return } w.Flush() } +func printHelp(out io.Writer, templ string, data interface{}) { + printHelpCustom(out, templ, data, nil) +} + func checkVersion(c *Context) bool { found := false - if VersionFlag.Name != "" { - eachName(VersionFlag.Name, func(name string) { + if VersionFlag.GetName() != "" { + eachName(VersionFlag.GetName(), func(name string) { if c.GlobalBool(name) || c.Bool(name) { found = true } @@ -199,8 +268,8 @@ func checkVersion(c *Context) bool { func checkHelp(c *Context) bool { found := false - if HelpFlag.Name != "" { - eachName(HelpFlag.Name, func(name string) { + if HelpFlag.GetName() != "" { + eachName(HelpFlag.GetName(), func(name string) { if c.GlobalBool(name) || c.Bool(name) { found = true } @@ -219,7 +288,7 @@ func checkCommandHelp(c *Context, name string) bool { } func checkSubcommandHelp(c *Context) bool { - if c.GlobalBool("h") || c.GlobalBool("help") { + if c.Bool("h") || c.Bool("help") { ShowSubcommandHelp(c) return true } @@ -227,20 +296,43 @@ func checkSubcommandHelp(c *Context) bool { return false } -func checkCompletions(c *Context) bool { - if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { - ShowCompletions(c) - return true +func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { + if !a.EnableBashCompletion { + return false, arguments } - return false + pos := len(arguments) - 1 + lastArg := arguments[pos] + + if lastArg != "--"+BashCompletionFlag.GetName() { + return false, arguments + } + + return true, arguments[:pos] +} + +func checkCompletions(c *Context) bool { + if !c.shellComplete { + return false + } + + if args := c.Args(); args.Present() { + name := args.First() + if cmd := c.App.Command(name); cmd != nil { + // let the command handle the completion + return false + } + } + + ShowCompletions(c) + return true } func checkCommandCompletions(c *Context, name string) bool { - if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { - ShowCommandCompletions(c, name) - return true + if !c.shellComplete { + return false } - return false + ShowCommandCompletions(c, name) + return true } diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE new file mode 100644 index 00000000000..c836416192d --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012-2016 Dave Collins + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go index a8d27a3f677..8a4a6589a2d 100644 --- a/vendor/github.com/davecgh/go-spew/spew/bypass.go +++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Dave Collins +// Copyright (c) 2015-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -13,9 +13,10 @@ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled -// when the code is not running on Google App Engine and "-tags disableunsafe" -// is not added to the go build command line. -// +build !appengine,!disableunsafe +// when the code is not running on Google App Engine, compiled by GopherJS, and +// "-tags safe" is not added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// +build !js,!appengine,!safe,!disableunsafe package spew @@ -91,6 +92,21 @@ func init() { flagKindShift = 0 flagRO = 1 << 5 flagIndir = 1 << 6 + + // Commit adf9b30e5594 modified the flags to separate the + // flagRO flag into two bits which specifies whether or not the + // field is embedded. This causes flagIndir to move over a bit + // and means that flagRO is the combination of either of the + // original flagRO bit and the new bit. + // + // This code detects the change by extracting what used to be + // the indirect bit to ensure it's set. When it's not, the flag + // order has been changed to the newer format, so the flags are + // updated accordingly. + if upfv&flagIndir == 0 { + flagRO = 3 << 5 + flagIndir = 1 << 7 + } } } diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go index 457e41235ed..1fe3cf3d5d1 100644 --- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go +++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Dave Collins +// Copyright (c) 2015-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -13,9 +13,10 @@ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // NOTE: Due to the following build constraints, this file will only be compiled -// when either the code is running on Google App Engine or "-tags disableunsafe" -// is added to the go build command line. -// +build appengine disableunsafe +// when the code is running on Google App Engine, compiled by GopherJS, or +// "-tags safe" is added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// +build js appengine safe disableunsafe package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go index 14f02dc15b7..7c519ff47ac 100644 --- a/vendor/github.com/davecgh/go-spew/spew/common.go +++ b/vendor/github.com/davecgh/go-spew/spew/common.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go deleted file mode 100644 index 39b7525b3d1..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/common_test.go +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2013 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew_test - -import ( - "fmt" - "reflect" - "testing" - - "github.com/davecgh/go-spew/spew" -) - -// custom type to test Stinger interface on non-pointer receiver. -type stringer string - -// String implements the Stringer interface for testing invocation of custom -// stringers on types with non-pointer receivers. -func (s stringer) String() string { - return "stringer " + string(s) -} - -// custom type to test Stinger interface on pointer receiver. -type pstringer string - -// String implements the Stringer interface for testing invocation of custom -// stringers on types with only pointer receivers. -func (s *pstringer) String() string { - return "stringer " + string(*s) -} - -// xref1 and xref2 are cross referencing structs for testing circular reference -// detection. -type xref1 struct { - ps2 *xref2 -} -type xref2 struct { - ps1 *xref1 -} - -// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular -// reference for testing detection. -type indirCir1 struct { - ps2 *indirCir2 -} -type indirCir2 struct { - ps3 *indirCir3 -} -type indirCir3 struct { - ps1 *indirCir1 -} - -// embed is used to test embedded structures. -type embed struct { - a string -} - -// embedwrap is used to test embedded structures. -type embedwrap struct { - *embed - e *embed -} - -// panicer is used to intentionally cause a panic for testing spew properly -// handles them -type panicer int - -func (p panicer) String() string { - panic("test panic") -} - -// customError is used to test custom error interface invocation. -type customError int - -func (e customError) Error() string { - return fmt.Sprintf("error: %d", int(e)) -} - -// stringizeWants converts a slice of wanted test output into a format suitable -// for a test error message. -func stringizeWants(wants []string) string { - s := "" - for i, want := range wants { - if i > 0 { - s += fmt.Sprintf("want%d: %s", i+1, want) - } else { - s += "want: " + want - } - } - return s -} - -// testFailed returns whether or not a test failed by checking if the result -// of the test is in the slice of wanted strings. -func testFailed(result string, wants []string) bool { - for _, want := range wants { - if result == want { - return false - } - } - return true -} - -type sortableStruct struct { - x int -} - -func (ss sortableStruct) String() string { - return fmt.Sprintf("ss.%d", ss.x) -} - -type unsortableStruct struct { - x int -} - -type sortTestCase struct { - input []reflect.Value - expected []reflect.Value -} - -func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) { - getInterfaces := func(values []reflect.Value) []interface{} { - interfaces := []interface{}{} - for _, v := range values { - interfaces = append(interfaces, v.Interface()) - } - return interfaces - } - - for _, test := range tests { - spew.SortValues(test.input, cs) - // reflect.DeepEqual cannot really make sense of reflect.Value, - // probably because of all the pointer tricks. For instance, - // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} - // instead. - input := getInterfaces(test.input) - expected := getInterfaces(test.expected) - if !reflect.DeepEqual(input, expected) { - t.Errorf("Sort mismatch:\n %v != %v", input, expected) - } - } -} - -// TestSortValues ensures the sort functionality for relect.Value based sorting -// works as intended. -func TestSortValues(t *testing.T) { - v := reflect.ValueOf - - a := v("a") - b := v("b") - c := v("c") - embedA := v(embed{"a"}) - embedB := v(embed{"b"}) - embedC := v(embed{"c"}) - tests := []sortTestCase{ - // No values. - { - []reflect.Value{}, - []reflect.Value{}, - }, - // Bools. - { - []reflect.Value{v(false), v(true), v(false)}, - []reflect.Value{v(false), v(false), v(true)}, - }, - // Ints. - { - []reflect.Value{v(2), v(1), v(3)}, - []reflect.Value{v(1), v(2), v(3)}, - }, - // Uints. - { - []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, - []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, - }, - // Floats. - { - []reflect.Value{v(2.0), v(1.0), v(3.0)}, - []reflect.Value{v(1.0), v(2.0), v(3.0)}, - }, - // Strings. - { - []reflect.Value{b, a, c}, - []reflect.Value{a, b, c}, - }, - // Array - { - []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})}, - []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})}, - }, - // Uintptrs. - { - []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, - []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, - }, - // SortableStructs. - { - // Note: not sorted - DisableMethods is set. - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - }, - // UnsortableStructs. - { - // Note: not sorted - SpewKeys is false. - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - }, - // Invalid. - { - []reflect.Value{embedB, embedA, embedC}, - []reflect.Value{embedB, embedA, embedC}, - }, - } - cs := spew.ConfigState{DisableMethods: true, SpewKeys: false} - helpTestSortValues(tests, &cs, t) -} - -// TestSortValuesWithMethods ensures the sort functionality for relect.Value -// based sorting works as intended when using string methods. -func TestSortValuesWithMethods(t *testing.T) { - v := reflect.ValueOf - - a := v("a") - b := v("b") - c := v("c") - tests := []sortTestCase{ - // Ints. - { - []reflect.Value{v(2), v(1), v(3)}, - []reflect.Value{v(1), v(2), v(3)}, - }, - // Strings. - { - []reflect.Value{b, a, c}, - []reflect.Value{a, b, c}, - }, - // SortableStructs. - { - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, - }, - // UnsortableStructs. - { - // Note: not sorted - SpewKeys is false. - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - }, - } - cs := spew.ConfigState{DisableMethods: false, SpewKeys: false} - helpTestSortValues(tests, &cs, t) -} - -// TestSortValuesWithSpew ensures the sort functionality for relect.Value -// based sorting works as intended when using spew to stringify keys. -func TestSortValuesWithSpew(t *testing.T) { - v := reflect.ValueOf - - a := v("a") - b := v("b") - c := v("c") - tests := []sortTestCase{ - // Ints. - { - []reflect.Value{v(2), v(1), v(3)}, - []reflect.Value{v(1), v(2), v(3)}, - }, - // Strings. - { - []reflect.Value{b, a, c}, - []reflect.Value{a, b, c}, - }, - // SortableStructs. - { - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, - }, - // UnsortableStructs. - { - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})}, - }, - } - cs := spew.ConfigState{DisableMethods: true, SpewKeys: true} - helpTestSortValues(tests, &cs, t) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go index ee1ab07b3fd..2e3d22f3120 100644 --- a/vendor/github.com/davecgh/go-spew/spew/config.go +++ b/vendor/github.com/davecgh/go-spew/spew/config.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -64,9 +64,18 @@ type ConfigState struct { // inside these interface methods. As a result, this option relies on // access to the unsafe package, so it will not have any effect when // running in environments without access to the unsafe package such as - // Google App Engine or with the "disableunsafe" build tag specified. + // Google App Engine or with the "safe" build tag specified. DisablePointerMethods bool + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + // ContinueOnMethod specifies whether or not recursion should continue once // a custom error or Stringer interface is invoked. The default, false, // means it will print the results of invoking the custom error or Stringer diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go index 5be0c406090..aacaac6f1e1 100644 --- a/vendor/github.com/davecgh/go-spew/spew/doc.go +++ b/vendor/github.com/davecgh/go-spew/spew/doc.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -91,6 +91,15 @@ The following configuration options are available: which only accept pointer receivers from non-pointer variables. Pointer method invocation is enabled by default. + * DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + + * DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. + * ContinueOnMethod Enables recursion into types after invoking error and Stringer interface methods. Recursion after method invocation is disabled by default. diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go index 36a2b6cc9b2..df1d582a728 100644 --- a/vendor/github.com/davecgh/go-spew/spew/dump.go +++ b/vendor/github.com/davecgh/go-spew/spew/dump.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -129,7 +129,7 @@ func (d *dumpState) dumpPtr(v reflect.Value) { d.w.Write(closeParenBytes) // Display pointer information. - if len(pointerChain) > 0 { + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { d.w.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { @@ -181,8 +181,6 @@ func (d *dumpState) dumpSlice(v reflect.Value) { // Try to use existing uint8 slices and fall back to converting // and copying if that fails. case vt.Kind() == reflect.Uint8: - // TODO(davec): Fix up the disableUnsafe bits... - // We need an addressable interface to convert the type // to a byte slice. However, the reflect package won't // give us an interface on certain things like @@ -284,13 +282,13 @@ func (d *dumpState) dump(v reflect.Value) { case reflect.Map, reflect.String: valueLen = v.Len() } - if valueLen != 0 || valueCap != 0 { + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { d.w.Write(openParenBytes) if valueLen != 0 { d.w.Write(lenEqualsBytes) printInt(d.w, int64(valueLen), 10) } - if valueCap != 0 { + if !d.cs.DisableCapacities && valueCap != 0 { if valueLen != 0 { d.w.Write(spaceBytes) } diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go deleted file mode 100644 index 2b320401dfa..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/dump_test.go +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * Copyright (c) 2013 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* -Test Summary: -NOTE: For each test, a nil pointer, a single pointer and double pointer to the -base test element are also tested to ensure proper indirection across all types. - -- Max int8, int16, int32, int64, int -- Max uint8, uint16, uint32, uint64, uint -- Boolean true and false -- Standard complex64 and complex128 -- Array containing standard ints -- Array containing type with custom formatter on pointer receiver only -- Array containing interfaces -- Array containing bytes -- Slice containing standard float32 values -- Slice containing type with custom formatter on pointer receiver only -- Slice containing interfaces -- Slice containing bytes -- Nil slice -- Standard string -- Nil interface -- Sub-interface -- Map with string keys and int vals -- Map with custom formatter type on pointer receiver only keys and vals -- Map with interface keys and values -- Map with nil interface value -- Struct with primitives -- Struct that contains another struct -- Struct that contains custom type with Stringer pointer interface via both - exported and unexported fields -- Struct that contains embedded struct and field to same struct -- Uintptr to 0 (null pointer) -- Uintptr address of real variable -- Unsafe.Pointer to 0 (null pointer) -- Unsafe.Pointer to address of real variable -- Nil channel -- Standard int channel -- Function with no params and no returns -- Function with param and no returns -- Function with multiple params and multiple returns -- Struct that is circular through self referencing -- Structs that are circular through cross referencing -- Structs that are indirectly circular -- Type that panics in its Stringer interface -*/ - -package spew_test - -import ( - "bytes" - "fmt" - "testing" - "unsafe" - - "github.com/davecgh/go-spew/spew" -) - -// dumpTest is used to describe a test to be perfomed against the Dump method. -type dumpTest struct { - in interface{} - wants []string -} - -// dumpTests houses all of the tests to be performed against the Dump method. -var dumpTests = make([]dumpTest, 0) - -// addDumpTest is a helper method to append the passed input and desired result -// to dumpTests -func addDumpTest(in interface{}, wants ...string) { - test := dumpTest{in, wants} - dumpTests = append(dumpTests, test) -} - -func addIntDumpTests() { - // Max int8. - v := int8(127) - nv := (*int8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "int8" - vs := "127" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Max int16. - v2 := int16(32767) - nv2 := (*int16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "int16" - v2s := "32767" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Max int32. - v3 := int32(2147483647) - nv3 := (*int32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "int32" - v3s := "2147483647" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Max int64. - v4 := int64(9223372036854775807) - nv4 := (*int64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "int64" - v4s := "9223372036854775807" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") - - // Max int. - v5 := int(2147483647) - nv5 := (*int)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "int" - v5s := "2147483647" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") - addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") - addDumpTest(nv5, "(*"+v5t+")()\n") -} - -func addUintDumpTests() { - // Max uint8. - v := uint8(255) - nv := (*uint8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uint8" - vs := "255" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Max uint16. - v2 := uint16(65535) - nv2 := (*uint16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Max uint32. - v3 := uint32(4294967295) - nv3 := (*uint32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "uint32" - v3s := "4294967295" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Max uint64. - v4 := uint64(18446744073709551615) - nv4 := (*uint64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "uint64" - v4s := "18446744073709551615" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") - - // Max uint. - v5 := uint(4294967295) - nv5 := (*uint)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "uint" - v5s := "4294967295" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") - addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") - addDumpTest(nv5, "(*"+v5t+")()\n") -} - -func addBoolDumpTests() { - // Boolean true. - v := bool(true) - nv := (*bool)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "bool" - vs := "true" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Boolean false. - v2 := bool(false) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "bool" - v2s := "false" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") -} - -func addFloatDumpTests() { - // Standard float32. - v := float32(3.1415) - nv := (*float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "float32" - vs := "3.1415" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Standard float64. - v2 := float64(3.1415926) - nv2 := (*float64)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "float64" - v2s := "3.1415926" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") -} - -func addComplexDumpTests() { - // Standard complex64. - v := complex(float32(6), -2) - nv := (*complex64)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "complex64" - vs := "(6-2i)" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Standard complex128. - v2 := complex(float64(-6), 2) - nv2 := (*complex128)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "complex128" - v2s := "(-6+2i)" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") -} - -func addArrayDumpTests() { - // Array containing standard ints. - v := [3]int{1, 2, 3} - vLen := fmt.Sprintf("%d", len(v)) - vCap := fmt.Sprintf("%d", cap(v)) - nv := (*[3]int)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "int" - vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + - vt + ") 2,\n (" + vt + ") 3\n}" - addDumpTest(v, "([3]"+vt+") "+vs+"\n") - addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*[3]"+vt+")()\n") - - // Array containing type with custom formatter on pointer receiver only. - v2i0 := pstringer("1") - v2i1 := pstringer("2") - v2i2 := pstringer("3") - v2 := [3]pstringer{v2i0, v2i1, v2i2} - v2i0Len := fmt.Sprintf("%d", len(v2i0)) - v2i1Len := fmt.Sprintf("%d", len(v2i1)) - v2i2Len := fmt.Sprintf("%d", len(v2i2)) - v2Len := fmt.Sprintf("%d", len(v2)) - v2Cap := fmt.Sprintf("%d", cap(v2)) - nv2 := (*[3]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.pstringer" - v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + - ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + - ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + - ") (len=" + v2i2Len + ") " + "stringer 3\n}" - v2s := v2sp - if spew.UnsafeDisabled { - v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + - ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" + - v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len + - ") " + "\"3\"\n}" - } - addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n") - addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n") - addDumpTest(nv2, "(*[3]"+v2t+")()\n") - - // Array containing interfaces. - v3i0 := "one" - v3 := [3]interface{}{v3i0, int(2), uint(3)} - v3i0Len := fmt.Sprintf("%d", len(v3i0)) - v3Len := fmt.Sprintf("%d", len(v3)) - v3Cap := fmt.Sprintf("%d", cap(v3)) - nv3 := (*[3]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[3]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + - "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + - v3t4 + ") 3\n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Array containing bytes. - v4 := [34]byte{ - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, - } - v4Len := fmt.Sprintf("%d", len(v4)) - v4Cap := fmt.Sprintf("%d", cap(v4)) - nv4 := (*[34]byte)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "[34]uint8" - v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + - "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + - " |............... |\n" + - " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + - " |!\"#$%&'()*+,-./0|\n" + - " 00000020 31 32 " + - " |12|\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") -} - -func addSliceDumpTests() { - // Slice containing standard float32 values. - v := []float32{3.14, 6.28, 12.56} - vLen := fmt.Sprintf("%d", len(v)) - vCap := fmt.Sprintf("%d", cap(v)) - nv := (*[]float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "float32" - vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + - vt + ") 6.28,\n (" + vt + ") 12.56\n}" - addDumpTest(v, "([]"+vt+") "+vs+"\n") - addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*[]"+vt+")()\n") - - // Slice containing type with custom formatter on pointer receiver only. - v2i0 := pstringer("1") - v2i1 := pstringer("2") - v2i2 := pstringer("3") - v2 := []pstringer{v2i0, v2i1, v2i2} - v2i0Len := fmt.Sprintf("%d", len(v2i0)) - v2i1Len := fmt.Sprintf("%d", len(v2i1)) - v2i2Len := fmt.Sprintf("%d", len(v2i2)) - v2Len := fmt.Sprintf("%d", len(v2)) - v2Cap := fmt.Sprintf("%d", cap(v2)) - nv2 := (*[]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.pstringer" - v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + - v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + - ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + - "stringer 3\n}" - addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*[]"+v2t+")()\n") - - // Slice containing interfaces. - v3i0 := "one" - v3 := []interface{}{v3i0, int(2), uint(3), nil} - v3i0Len := fmt.Sprintf("%d", len(v3i0)) - v3Len := fmt.Sprintf("%d", len(v3)) - v3Cap := fmt.Sprintf("%d", cap(v3)) - nv3 := (*[]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3t5 := "interface {}" - v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + - "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + - v3t4 + ") 3,\n (" + v3t5 + ") \n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Slice containing bytes. - v4 := []byte{ - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, - } - v4Len := fmt.Sprintf("%d", len(v4)) - v4Cap := fmt.Sprintf("%d", cap(v4)) - nv4 := (*[]byte)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "[]uint8" - v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + - "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + - " |............... |\n" + - " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + - " |!\"#$%&'()*+,-./0|\n" + - " 00000020 31 32 " + - " |12|\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") - - // Nil slice. - v5 := []int(nil) - nv5 := (*[]int)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "[]int" - v5s := "" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") - addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") - addDumpTest(nv5, "(*"+v5t+")()\n") -} - -func addStringDumpTests() { - // Standard string. - v := "test" - vLen := fmt.Sprintf("%d", len(v)) - nv := (*string)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "string" - vs := "(len=" + vLen + ") \"test\"" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -func addInterfaceDumpTests() { - // Nil interface. - var v interface{} - nv := (*interface{})(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "interface {}" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Sub-interface. - v2 := interface{}(uint16(65535)) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") -} - -func addMapDumpTests() { - // Map with string keys and int vals. - k := "one" - kk := "two" - m := map[string]int{k: 1, kk: 2} - klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up - kkLen := fmt.Sprintf("%d", len(kk)) - mLen := fmt.Sprintf("%d", len(m)) - nilMap := map[string]int(nil) - nm := (*map[string]int)(nil) - pm := &m - mAddr := fmt.Sprintf("%p", pm) - pmAddr := fmt.Sprintf("%p", &pm) - mt := "map[string]int" - mt1 := "string" - mt2 := "int" - ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + - "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + - ") \"two\": (" + mt2 + ") 2\n}" - ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + - "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + - ") \"one\": (" + mt2 + ") 1\n}" - addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") - addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", - "(*"+mt+")("+mAddr+")("+ms2+")\n") - addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", - "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") - addDumpTest(nm, "(*"+mt+")()\n") - addDumpTest(nilMap, "("+mt+") \n") - - // Map with custom formatter type on pointer receiver only keys and vals. - k2 := pstringer("one") - v2 := pstringer("1") - m2 := map[pstringer]pstringer{k2: v2} - k2Len := fmt.Sprintf("%d", len(k2)) - v2Len := fmt.Sprintf("%d", len(v2)) - m2Len := fmt.Sprintf("%d", len(m2)) - nilMap2 := map[pstringer]pstringer(nil) - nm2 := (*map[pstringer]pstringer)(nil) - pm2 := &m2 - m2Addr := fmt.Sprintf("%p", pm2) - pm2Addr := fmt.Sprintf("%p", &pm2) - m2t := "map[spew_test.pstringer]spew_test.pstringer" - m2t1 := "spew_test.pstringer" - m2t2 := "spew_test.pstringer" - m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + - "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" - if spew.UnsafeDisabled { - m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + - ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len + - ") \"1\"\n}" - } - addDumpTest(m2, "("+m2t+") "+m2s+"\n") - addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") - addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") - addDumpTest(nm2, "(*"+m2t+")()\n") - addDumpTest(nilMap2, "("+m2t+") \n") - - // Map with interface keys and values. - k3 := "one" - k3Len := fmt.Sprintf("%d", len(k3)) - m3 := map[interface{}]interface{}{k3: 1} - m3Len := fmt.Sprintf("%d", len(m3)) - nilMap3 := map[interface{}]interface{}(nil) - nm3 := (*map[interface{}]interface{})(nil) - pm3 := &m3 - m3Addr := fmt.Sprintf("%p", pm3) - pm3Addr := fmt.Sprintf("%p", &pm3) - m3t := "map[interface {}]interface {}" - m3t1 := "string" - m3t2 := "int" - m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + - "\"one\": (" + m3t2 + ") 1\n}" - addDumpTest(m3, "("+m3t+") "+m3s+"\n") - addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") - addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") - addDumpTest(nm3, "(*"+m3t+")()\n") - addDumpTest(nilMap3, "("+m3t+") \n") - - // Map with nil interface value. - k4 := "nil" - k4Len := fmt.Sprintf("%d", len(k4)) - m4 := map[string]interface{}{k4: nil} - m4Len := fmt.Sprintf("%d", len(m4)) - nilMap4 := map[string]interface{}(nil) - nm4 := (*map[string]interface{})(nil) - pm4 := &m4 - m4Addr := fmt.Sprintf("%p", pm4) - pm4Addr := fmt.Sprintf("%p", &pm4) - m4t := "map[string]interface {}" - m4t1 := "string" - m4t2 := "interface {}" - m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + - " \"nil\": (" + m4t2 + ") \n}" - addDumpTest(m4, "("+m4t+") "+m4s+"\n") - addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") - addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") - addDumpTest(nm4, "(*"+m4t+")()\n") - addDumpTest(nilMap4, "("+m4t+") \n") -} - -func addStructDumpTests() { - // Struct with primitives. - type s1 struct { - a int8 - b uint8 - } - v := s1{127, 255} - nv := (*s1)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.s1" - vt2 := "int8" - vt3 := "uint8" - vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Struct that contains another struct. - type s2 struct { - s1 s1 - b bool - } - v2 := s2{s1{127, 255}, true} - nv2 := (*s2)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.s2" - v2t2 := "spew_test.s1" - v2t3 := "int8" - v2t4 := "uint8" - v2t5 := "bool" - v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + - v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Struct that contains custom type with Stringer pointer interface via both - // exported and unexported fields. - type s3 struct { - s pstringer - S pstringer - } - v3 := s3{"test", "test2"} - nv3 := (*s3)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.s3" - v3t2 := "spew_test.pstringer" - v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + - ") (len=5) stringer test2\n}" - v3sp := v3s - if spew.UnsafeDisabled { - v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + - v3t2 + ") (len=5) \"test2\"\n}" - v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + - v3t2 + ") (len=5) stringer test2\n}" - } - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Struct that contains embedded struct and field to same struct. - e := embed{"embedstr"} - eLen := fmt.Sprintf("%d", len("embedstr")) - v4 := embedwrap{embed: &e, e: &e} - nv4 := (*embedwrap)(nil) - pv4 := &v4 - eAddr := fmt.Sprintf("%p", &e) - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "spew_test.embedwrap" - v4t2 := "spew_test.embed" - v4t3 := "string" - v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + - ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + - ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + - " \"embedstr\"\n })\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") -} - -func addUintptrDumpTests() { - // Null pointer. - v := uintptr(0) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uintptr" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - - // Address of real variable. - i := 1 - v2 := uintptr(unsafe.Pointer(&i)) - nv2 := (*uintptr)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uintptr" - v2s := fmt.Sprintf("%p", &i) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") -} - -func addUnsafePointerDumpTests() { - // Null pointer. - v := unsafe.Pointer(uintptr(0)) - nv := (*unsafe.Pointer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "unsafe.Pointer" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Address of real variable. - i := 1 - v2 := unsafe.Pointer(&i) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "unsafe.Pointer" - v2s := fmt.Sprintf("%p", &i) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -func addChanDumpTests() { - // Nil channel. - var v chan int - pv := &v - nv := (*chan int)(nil) - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "chan int" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Real channel. - v2 := make(chan int) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "chan int" - v2s := fmt.Sprintf("%p", v2) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") -} - -func addFuncDumpTests() { - // Function with no params and no returns. - v := addIntDumpTests - nv := (*func())(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "func()" - vs := fmt.Sprintf("%p", v) - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Function with param and no returns. - v2 := TestDump - nv2 := (*func(*testing.T))(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "func(*testing.T)" - v2s := fmt.Sprintf("%p", v2) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Function with multiple params and multiple returns. - var v3 = func(i int, s string) (b bool, err error) { - return true, nil - } - nv3 := (*func(int, string) (bool, error))(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "func(int, string) (bool, error)" - v3s := fmt.Sprintf("%p", v3) - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") -} - -func addCircularDumpTests() { - // Struct that is circular through self referencing. - type circular struct { - c *circular - } - v := circular{nil} - v.c = &v - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.circular" - vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + - vAddr + ")()\n })\n}" - vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") - - // Structs that are circular through cross referencing. - v2 := xref1{nil} - ts2 := xref2{&v2} - v2.ps2 = &ts2 - pv2 := &v2 - ts2Addr := fmt.Sprintf("%p", &ts2) - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.xref1" - v2t2 := "spew_test.xref2" - v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + - ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + - ")()\n })\n })\n}" - v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + - ")(" + v2Addr + ")()\n })\n}" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") - - // Structs that are indirectly circular. - v3 := indirCir1{nil} - tic2 := indirCir2{nil} - tic3 := indirCir3{&v3} - tic2.ps3 = &tic3 - v3.ps2 = &tic2 - pv3 := &v3 - tic2Addr := fmt.Sprintf("%p", &tic2) - tic3Addr := fmt.Sprintf("%p", &tic3) - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.indirCir1" - v3t2 := "spew_test.indirCir2" - v3t3 := "spew_test.indirCir3" - v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + - ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + - ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + - ")()\n })\n })\n })\n}" - v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + - ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + - ")()\n })\n })\n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") -} - -func addPanicDumpTests() { - // Type that panics in its Stringer interface. - v := panicer(127) - nv := (*panicer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.panicer" - vs := "(PANIC=test panic)127" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -func addErrorDumpTests() { - // Type that has a custom Error interface. - v := customError(127) - nv := (*customError)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.customError" - vs := "error: 127" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -// TestDump executes all of the tests described by dumpTests. -func TestDump(t *testing.T) { - // Setup tests. - addIntDumpTests() - addUintDumpTests() - addBoolDumpTests() - addFloatDumpTests() - addComplexDumpTests() - addArrayDumpTests() - addSliceDumpTests() - addStringDumpTests() - addInterfaceDumpTests() - addMapDumpTests() - addStructDumpTests() - addUintptrDumpTests() - addUnsafePointerDumpTests() - addChanDumpTests() - addFuncDumpTests() - addCircularDumpTests() - addPanicDumpTests() - addErrorDumpTests() - addCgoDumpTests() - - t.Logf("Running %d tests", len(dumpTests)) - for i, test := range dumpTests { - buf := new(bytes.Buffer) - spew.Fdump(buf, test.in) - s := buf.String() - if testFailed(s, test.wants) { - t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) - continue - } - } -} - -func TestDumpSortedKeys(t *testing.T) { - cfg := spew.ConfigState{SortKeys: true} - s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) - expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " + - "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " + - "(len=1) \"3\"\n" + - "}\n" - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - - s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2}) - expected = "(map[spew_test.stringer]int) (len=3) {\n" + - "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" + - "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" + - "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" + - "}\n" - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - - s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) - expected = "(map[spew_test.pstringer]int) (len=3) {\n" + - "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" + - "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" + - "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" + - "}\n" - if spew.UnsafeDisabled { - expected = "(map[spew_test.pstringer]int) (len=3) {\n" + - "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" + - "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" + - "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" + - "}\n" - } - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - - s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) - expected = "(map[spew_test.customError]int) (len=3) {\n" + - "(spew_test.customError) error: 1: (int) 1,\n" + - "(spew_test.customError) error: 2: (int) 2,\n" + - "(spew_test.customError) error: 3: (int) 3\n" + - "}\n" - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - -} diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go deleted file mode 100644 index 18a38358e05..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2013 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when both cgo is supported and "-tags testcgo" is added to the go test -// command line. This means the cgo tests are only added (and hence run) when -// specifially requested. This configuration is used because spew itself -// does not require cgo to run even though it does handle certain cgo types -// specially. Rather than forcing all clients to require cgo and an external -// C compiler just to run the tests, this scheme makes them optional. -// +build cgo,testcgo - -package spew_test - -import ( - "fmt" - - "github.com/davecgh/go-spew/spew/testdata" -) - -func addCgoDumpTests() { - // C char pointer. - v := testdata.GetCgoCharPointer() - nv := testdata.GetCgoNullCharPointer() - pv := &v - vcAddr := fmt.Sprintf("%p", v) - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "*testdata._Ctype_char" - vs := "116" - addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") - addDumpTest(nv, "("+vt+")()\n") - - // C char array. - v2, v2l, v2c := testdata.GetCgoCharArray() - v2Len := fmt.Sprintf("%d", v2l) - v2Cap := fmt.Sprintf("%d", v2c) - v2t := "[6]testdata._Ctype_char" - v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + - "{\n 00000000 74 65 73 74 32 00 " + - " |test2.|\n}" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - - // C unsigned char array. - v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() - v3Len := fmt.Sprintf("%d", v3l) - v3Cap := fmt.Sprintf("%d", v3c) - v3t := "[6]testdata._Ctype_unsignedchar" - v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + - "{\n 00000000 74 65 73 74 33 00 " + - " |test3.|\n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - - // C signed char array. - v4, v4l, v4c := testdata.GetCgoSignedCharArray() - v4Len := fmt.Sprintf("%d", v4l) - v4Cap := fmt.Sprintf("%d", v4c) - v4t := "[6]testdata._Ctype_schar" - v4t2 := "testdata._Ctype_schar" - v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + - "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + - ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + - ") 0\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - - // C uint8_t array. - v5, v5l, v5c := testdata.GetCgoUint8tArray() - v5Len := fmt.Sprintf("%d", v5l) - v5Cap := fmt.Sprintf("%d", v5c) - v5t := "[6]testdata._Ctype_uint8_t" - v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + - "{\n 00000000 74 65 73 74 35 00 " + - " |test5.|\n}" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - - // C typedefed unsigned char array. - v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() - v6Len := fmt.Sprintf("%d", v6l) - v6Cap := fmt.Sprintf("%d", v6c) - v6t := "[6]testdata._Ctype_custom_uchar_t" - v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + - "{\n 00000000 74 65 73 74 36 00 " + - " |test6.|\n}" - addDumpTest(v6, "("+v6t+") "+v6s+"\n") -} diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go deleted file mode 100644 index 52a0971fb3f..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2013 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when either cgo is not supported or "-tags testcgo" is not added to the go -// test command line. This file intentionally does not setup any cgo tests in -// this scenario. -// +build !cgo !testcgo - -package spew_test - -func addCgoDumpTests() { - // Don't add any tests for cgo since this file is only compiled when - // there should not be any cgo tests. -} diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go deleted file mode 100644 index de6c4e3097d..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/example_test.go +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2013 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew_test - -import ( - "fmt" - - "github.com/davecgh/go-spew/spew" -) - -type Flag int - -const ( - flagOne Flag = iota - flagTwo -) - -var flagStrings = map[Flag]string{ - flagOne: "flagOne", - flagTwo: "flagTwo", -} - -func (f Flag) String() string { - if s, ok := flagStrings[f]; ok { - return s - } - return fmt.Sprintf("Unknown flag (%d)", int(f)) -} - -type Bar struct { - data uintptr -} - -type Foo struct { - unexportedField Bar - ExportedField map[interface{}]interface{} -} - -// This example demonstrates how to use Dump to dump variables to stdout. -func ExampleDump() { - // The following package level declarations are assumed for this example: - /* - type Flag int - - const ( - flagOne Flag = iota - flagTwo - ) - - var flagStrings = map[Flag]string{ - flagOne: "flagOne", - flagTwo: "flagTwo", - } - - func (f Flag) String() string { - if s, ok := flagStrings[f]; ok { - return s - } - return fmt.Sprintf("Unknown flag (%d)", int(f)) - } - - type Bar struct { - data uintptr - } - - type Foo struct { - unexportedField Bar - ExportedField map[interface{}]interface{} - } - */ - - // Setup some sample data structures for the example. - bar := Bar{uintptr(0)} - s1 := Foo{bar, map[interface{}]interface{}{"one": true}} - f := Flag(5) - b := []byte{ - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, - } - - // Dump! - spew.Dump(s1, f, b) - - // Output: - // (spew_test.Foo) { - // unexportedField: (spew_test.Bar) { - // data: (uintptr) - // }, - // ExportedField: (map[interface {}]interface {}) (len=1) { - // (string) (len=3) "one": (bool) true - // } - // } - // (spew_test.Flag) Unknown flag (5) - // ([]uint8) (len=34 cap=34) { - // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | - // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| - // 00000020 31 32 |12| - // } - // -} - -// This example demonstrates how to use Printf to display a variable with a -// format string and inline formatting. -func ExamplePrintf() { - // Create a double pointer to a uint 8. - ui8 := uint8(5) - pui8 := &ui8 - ppui8 := &pui8 - - // Create a circular data type. - type circular struct { - ui8 uint8 - c *circular - } - c := circular{ui8: 1} - c.c = &c - - // Print! - spew.Printf("ppui8: %v\n", ppui8) - spew.Printf("circular: %v\n", c) - - // Output: - // ppui8: <**>5 - // circular: {1 <*>{1 <*>}} -} - -// This example demonstrates how to use a ConfigState. -func ExampleConfigState() { - // Modify the indent level of the ConfigState only. The global - // configuration is not modified. - scs := spew.ConfigState{Indent: "\t"} - - // Output using the ConfigState instance. - v := map[string]int{"one": 1} - scs.Printf("v: %v\n", v) - scs.Dump(v) - - // Output: - // v: map[one:1] - // (map[string]int) (len=1) { - // (string) (len=3) "one": (int) 1 - // } -} - -// This example demonstrates how to use ConfigState.Dump to dump variables to -// stdout -func ExampleConfigState_Dump() { - // See the top-level Dump example for details on the types used in this - // example. - - // Create two ConfigState instances with different indentation. - scs := spew.ConfigState{Indent: "\t"} - scs2 := spew.ConfigState{Indent: " "} - - // Setup some sample data structures for the example. - bar := Bar{uintptr(0)} - s1 := Foo{bar, map[interface{}]interface{}{"one": true}} - - // Dump using the ConfigState instances. - scs.Dump(s1) - scs2.Dump(s1) - - // Output: - // (spew_test.Foo) { - // unexportedField: (spew_test.Bar) { - // data: (uintptr) - // }, - // ExportedField: (map[interface {}]interface {}) (len=1) { - // (string) (len=3) "one": (bool) true - // } - // } - // (spew_test.Foo) { - // unexportedField: (spew_test.Bar) { - // data: (uintptr) - // }, - // ExportedField: (map[interface {}]interface {}) (len=1) { - // (string) (len=3) "one": (bool) true - // } - // } - // -} - -// This example demonstrates how to use ConfigState.Printf to display a variable -// with a format string and inline formatting. -func ExampleConfigState_Printf() { - // See the top-level Dump example for details on the types used in this - // example. - - // Create two ConfigState instances and modify the method handling of the - // first ConfigState only. - scs := spew.NewDefaultConfig() - scs2 := spew.NewDefaultConfig() - scs.DisableMethods = true - - // Alternatively - // scs := spew.ConfigState{Indent: " ", DisableMethods: true} - // scs2 := spew.ConfigState{Indent: " "} - - // This is of type Flag which implements a Stringer and has raw value 1. - f := flagTwo - - // Dump using the ConfigState instances. - scs.Printf("f: %v\n", f) - scs2.Printf("f: %v\n", f) - - // Output: - // f: 1 - // f: flagTwo -} diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go index ecf3b80e24b..c49875bacbb 100644 --- a/vendor/github.com/davecgh/go-spew/spew/format.go +++ b/vendor/github.com/davecgh/go-spew/spew/format.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go deleted file mode 100644 index b664b3f135f..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/format_test.go +++ /dev/null @@ -1,1558 +0,0 @@ -/* - * Copyright (c) 2013 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* -Test Summary: -NOTE: For each test, a nil pointer, a single pointer and double pointer to the -base test element are also tested to ensure proper indirection across all types. - -- Max int8, int16, int32, int64, int -- Max uint8, uint16, uint32, uint64, uint -- Boolean true and false -- Standard complex64 and complex128 -- Array containing standard ints -- Array containing type with custom formatter on pointer receiver only -- Array containing interfaces -- Slice containing standard float32 values -- Slice containing type with custom formatter on pointer receiver only -- Slice containing interfaces -- Nil slice -- Standard string -- Nil interface -- Sub-interface -- Map with string keys and int vals -- Map with custom formatter type on pointer receiver only keys and vals -- Map with interface keys and values -- Map with nil interface value -- Struct with primitives -- Struct that contains another struct -- Struct that contains custom type with Stringer pointer interface via both - exported and unexported fields -- Struct that contains embedded struct and field to same struct -- Uintptr to 0 (null pointer) -- Uintptr address of real variable -- Unsafe.Pointer to 0 (null pointer) -- Unsafe.Pointer to address of real variable -- Nil channel -- Standard int channel -- Function with no params and no returns -- Function with param and no returns -- Function with multiple params and multiple returns -- Struct that is circular through self referencing -- Structs that are circular through cross referencing -- Structs that are indirectly circular -- Type that panics in its Stringer interface -- Type that has a custom Error interface -- %x passthrough with uint -- %#x passthrough with uint -- %f passthrough with precision -- %f passthrough with width and precision -- %d passthrough with width -- %q passthrough with string -*/ - -package spew_test - -import ( - "bytes" - "fmt" - "testing" - "unsafe" - - "github.com/davecgh/go-spew/spew" -) - -// formatterTest is used to describe a test to be perfomed against NewFormatter. -type formatterTest struct { - format string - in interface{} - wants []string -} - -// formatterTests houses all of the tests to be performed against NewFormatter. -var formatterTests = make([]formatterTest, 0) - -// addFormatterTest is a helper method to append the passed input and desired -// result to formatterTests. -func addFormatterTest(format string, in interface{}, wants ...string) { - test := formatterTest{format, in, wants} - formatterTests = append(formatterTests, test) -} - -func addIntFormatterTests() { - // Max int8. - v := int8(127) - nv := (*int8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "int8" - vs := "127" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Max int16. - v2 := int16(32767) - nv2 := (*int16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "int16" - v2s := "32767" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Max int32. - v3 := int32(2147483647) - nv3 := (*int32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "int32" - v3s := "2147483647" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - - // Max int64. - v4 := int64(9223372036854775807) - nv4 := (*int64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "int64" - v4s := "9223372036854775807" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") - - // Max int. - v5 := int(2147483647) - nv5 := (*int)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "int" - v5s := "2147483647" - addFormatterTest("%v", v5, v5s) - addFormatterTest("%v", pv5, "<*>"+v5s) - addFormatterTest("%v", &pv5, "<**>"+v5s) - addFormatterTest("%v", nv5, "") - addFormatterTest("%+v", v5, v5s) - addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) - addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%+v", nv5, "") - addFormatterTest("%#v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) - addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) - addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") - addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) - addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") -} - -func addUintFormatterTests() { - // Max uint8. - v := uint8(255) - nv := (*uint8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uint8" - vs := "255" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Max uint16. - v2 := uint16(65535) - nv2 := (*uint16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Max uint32. - v3 := uint32(4294967295) - nv3 := (*uint32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "uint32" - v3s := "4294967295" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - - // Max uint64. - v4 := uint64(18446744073709551615) - nv4 := (*uint64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "uint64" - v4s := "18446744073709551615" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") - - // Max uint. - v5 := uint(4294967295) - nv5 := (*uint)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "uint" - v5s := "4294967295" - addFormatterTest("%v", v5, v5s) - addFormatterTest("%v", pv5, "<*>"+v5s) - addFormatterTest("%v", &pv5, "<**>"+v5s) - addFormatterTest("%v", nv5, "") - addFormatterTest("%+v", v5, v5s) - addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) - addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%+v", nv5, "") - addFormatterTest("%#v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) - addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) - addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") - addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) - addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") -} - -func addBoolFormatterTests() { - // Boolean true. - v := bool(true) - nv := (*bool)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "bool" - vs := "true" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Boolean false. - v2 := bool(false) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "bool" - v2s := "false" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addFloatFormatterTests() { - // Standard float32. - v := float32(3.1415) - nv := (*float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "float32" - vs := "3.1415" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Standard float64. - v2 := float64(3.1415926) - nv2 := (*float64)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "float64" - v2s := "3.1415926" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") -} - -func addComplexFormatterTests() { - // Standard complex64. - v := complex(float32(6), -2) - nv := (*complex64)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "complex64" - vs := "(6-2i)" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Standard complex128. - v2 := complex(float64(-6), 2) - nv2 := (*complex128)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "complex128" - v2s := "(-6+2i)" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") -} - -func addArrayFormatterTests() { - // Array containing standard ints. - v := [3]int{1, 2, 3} - nv := (*[3]int)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "[3]int" - vs := "[1 2 3]" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Array containing type with custom formatter on pointer receiver only. - v2 := [3]pstringer{"1", "2", "3"} - nv2 := (*[3]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "[3]spew_test.pstringer" - v2sp := "[stringer 1 stringer 2 stringer 3]" - v2s := v2sp - if spew.UnsafeDisabled { - v2s = "[1 2 3]" - } - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2sp) - addFormatterTest("%v", &pv2, "<**>"+v2sp) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Array containing interfaces. - v3 := [3]interface{}{"one", int(2), uint(3)} - nv3 := (*[3]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[3]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3s := "[one 2 3]" - v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") -} - -func addSliceFormatterTests() { - // Slice containing standard float32 values. - v := []float32{3.14, 6.28, 12.56} - nv := (*[]float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "[]float32" - vs := "[3.14 6.28 12.56]" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Slice containing type with custom formatter on pointer receiver only. - v2 := []pstringer{"1", "2", "3"} - nv2 := (*[]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "[]spew_test.pstringer" - v2s := "[stringer 1 stringer 2 stringer 3]" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Slice containing interfaces. - v3 := []interface{}{"one", int(2), uint(3), nil} - nv3 := (*[]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3t5 := "interface {}" - v3s := "[one 2 3 ]" - v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + - ")]" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") - - // Nil slice. - var v4 []int - nv4 := (*[]int)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "[]int" - v4s := "" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") -} - -func addStringFormatterTests() { - // Standard string. - v := "test" - nv := (*string)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "string" - vs := "test" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") -} - -func addInterfaceFormatterTests() { - // Nil interface. - var v interface{} - nv := (*interface{})(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "interface {}" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Sub-interface. - v2 := interface{}(uint16(65535)) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addMapFormatterTests() { - // Map with string keys and int vals. - v := map[string]int{"one": 1, "two": 2} - nilMap := map[string]int(nil) - nv := (*map[string]int)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "map[string]int" - vs := "map[one:1 two:2]" - vs2 := "map[two:2 one:1]" - addFormatterTest("%v", v, vs, vs2) - addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) - addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) - addFormatterTest("%+v", nilMap, "") - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs, vs2) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, - "<**>("+pvAddr+"->"+vAddr+")"+vs2) - addFormatterTest("%+v", nilMap, "") - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) - addFormatterTest("%#v", nilMap, "("+vt+")"+"") - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, - "(*"+vt+")("+vAddr+")"+vs2) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, - "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) - addFormatterTest("%#+v", nilMap, "("+vt+")"+"") - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Map with custom formatter type on pointer receiver only keys and vals. - v2 := map[pstringer]pstringer{"one": "1"} - nv2 := (*map[pstringer]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "map[spew_test.pstringer]spew_test.pstringer" - v2s := "map[stringer one:stringer 1]" - if spew.UnsafeDisabled { - v2s = "map[one:1]" - } - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Map with interface keys and values. - v3 := map[interface{}]interface{}{"one": 1} - nv3 := (*map[interface{}]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "map[interface {}]interface {}" - v3t1 := "string" - v3t2 := "int" - v3s := "map[one:1]" - v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") - - // Map with nil interface value - v4 := map[string]interface{}{"nil": nil} - nv4 := (*map[string]interface{})(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "map[string]interface {}" - v4t1 := "interface {}" - v4s := "map[nil:]" - v4s2 := "map[nil:(" + v4t1 + ")]" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") -} - -func addStructFormatterTests() { - // Struct with primitives. - type s1 struct { - a int8 - b uint8 - } - v := s1{127, 255} - nv := (*s1)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.s1" - vt2 := "int8" - vt3 := "uint8" - vs := "{127 255}" - vs2 := "{a:127 b:255}" - vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs2) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs3) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs3) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Struct that contains another struct. - type s2 struct { - s1 s1 - b bool - } - v2 := s2{s1{127, 255}, true} - nv2 := (*s2)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.s2" - v2t2 := "spew_test.s1" - v2t3 := "int8" - v2t4 := "uint8" - v2t5 := "bool" - v2s := "{{127 255} true}" - v2s2 := "{s1:{a:127 b:255} b:true}" - v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + - v2t5 + ")true}" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s2) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Struct that contains custom type with Stringer pointer interface via both - // exported and unexported fields. - type s3 struct { - s pstringer - S pstringer - } - v3 := s3{"test", "test2"} - nv3 := (*s3)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.s3" - v3t2 := "spew_test.pstringer" - v3s := "{stringer test stringer test2}" - v3sp := v3s - v3s2 := "{s:stringer test S:stringer test2}" - v3s2p := v3s2 - v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" - v3s3p := v3s3 - if spew.UnsafeDisabled { - v3s = "{test test2}" - v3sp = "{test stringer test2}" - v3s2 = "{s:test S:test2}" - v3s2p = "{s:test S:stringer test2}" - v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}" - v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}" - } - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3sp) - addFormatterTest("%v", &pv3, "<**>"+v3sp) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s2) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") - - // Struct that contains embedded struct and field to same struct. - e := embed{"embedstr"} - v4 := embedwrap{embed: &e, e: &e} - nv4 := (*embedwrap)(nil) - pv4 := &v4 - eAddr := fmt.Sprintf("%p", &e) - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "spew_test.embedwrap" - v4t2 := "spew_test.embed" - v4t3 := "string" - v4s := "{<*>{embedstr} <*>{embedstr}}" - v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + - "){a:embedstr}}" - v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + - "){a:(" + v4t3 + ")embedstr}}" - v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + - ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%+v", v4, v4s2) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") -} - -func addUintptrFormatterTests() { - // Null pointer. - v := uintptr(0) - nv := (*uintptr)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uintptr" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Address of real variable. - i := 1 - v2 := uintptr(unsafe.Pointer(&i)) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uintptr" - v2s := fmt.Sprintf("%p", &i) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addUnsafePointerFormatterTests() { - // Null pointer. - v := unsafe.Pointer(uintptr(0)) - nv := (*unsafe.Pointer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "unsafe.Pointer" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Address of real variable. - i := 1 - v2 := unsafe.Pointer(&i) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "unsafe.Pointer" - v2s := fmt.Sprintf("%p", &i) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addChanFormatterTests() { - // Nil channel. - var v chan int - pv := &v - nv := (*chan int)(nil) - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "chan int" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Real channel. - v2 := make(chan int) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "chan int" - v2s := fmt.Sprintf("%p", v2) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addFuncFormatterTests() { - // Function with no params and no returns. - v := addIntFormatterTests - nv := (*func())(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "func()" - vs := fmt.Sprintf("%p", v) - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Function with param and no returns. - v2 := TestFormatter - nv2 := (*func(*testing.T))(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "func(*testing.T)" - v2s := fmt.Sprintf("%p", v2) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Function with multiple params and multiple returns. - var v3 = func(i int, s string) (b bool, err error) { - return true, nil - } - nv3 := (*func(int, string) (bool, error))(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "func(int, string) (bool, error)" - v3s := fmt.Sprintf("%p", v3) - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") -} - -func addCircularFormatterTests() { - // Struct that is circular through self referencing. - type circular struct { - c *circular - } - v := circular{nil} - v.c = &v - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.circular" - vs := "{<*>{<*>}}" - vs2 := "{<*>}" - vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" - vs4 := "{c:<*>(" + vAddr + ")}" - vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" - vs6 := "{c:(*" + vt + ")}" - vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + - ")}}" - vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs2) - addFormatterTest("%v", &pv, "<**>"+vs2) - addFormatterTest("%+v", v, vs3) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4) - addFormatterTest("%#v", v, "("+vt+")"+vs5) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) - addFormatterTest("%#+v", v, "("+vt+")"+vs7) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) - - // Structs that are circular through cross referencing. - v2 := xref1{nil} - ts2 := xref2{&v2} - v2.ps2 = &ts2 - pv2 := &v2 - ts2Addr := fmt.Sprintf("%p", &ts2) - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.xref1" - v2t2 := "spew_test.xref2" - v2s := "{<*>{<*>{<*>}}}" - v2s2 := "{<*>{<*>}}" - v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + - ts2Addr + ")}}}" - v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" - v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + - ")}}}" - v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" - v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + - ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + - ")}}}" - v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + - ")(" + v2Addr + ")}}" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s2) - addFormatterTest("%v", &pv2, "<**>"+v2s2) - addFormatterTest("%+v", v2, v2s3) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) - - // Structs that are indirectly circular. - v3 := indirCir1{nil} - tic2 := indirCir2{nil} - tic3 := indirCir3{&v3} - tic2.ps3 = &tic3 - v3.ps2 = &tic2 - pv3 := &v3 - tic2Addr := fmt.Sprintf("%p", &tic2) - tic3Addr := fmt.Sprintf("%p", &tic3) - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.indirCir1" - v3t2 := "spew_test.indirCir2" - v3t3 := "spew_test.indirCir3" - v3s := "{<*>{<*>{<*>{<*>}}}}" - v3s2 := "{<*>{<*>{<*>}}}" - v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + - v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" - v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + - v3Addr + ")}}}" - v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + - "){ps2:(*" + v3t2 + ")}}}}" - v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + - ")}}}" - v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + - tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + - ")(" + tic2Addr + ")}}}}" - v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + - tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s2) - addFormatterTest("%v", &pv3, "<**>"+v3s2) - addFormatterTest("%+v", v3, v3s3) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4) - addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) -} - -func addPanicFormatterTests() { - // Type that panics in its Stringer interface. - v := panicer(127) - nv := (*panicer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.panicer" - vs := "(PANIC=test panic)127" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") -} - -func addErrorFormatterTests() { - // Type that has a custom Error interface. - v := customError(127) - nv := (*customError)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.customError" - vs := "error: 127" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") -} - -func addPassthroughFormatterTests() { - // %x passthrough with uint. - v := uint(4294967295) - pv := &v - vAddr := fmt.Sprintf("%x", pv) - pvAddr := fmt.Sprintf("%x", &pv) - vs := "ffffffff" - addFormatterTest("%x", v, vs) - addFormatterTest("%x", pv, vAddr) - addFormatterTest("%x", &pv, pvAddr) - - // %#x passthrough with uint. - v2 := int(2147483647) - pv2 := &v2 - v2Addr := fmt.Sprintf("%#x", pv2) - pv2Addr := fmt.Sprintf("%#x", &pv2) - v2s := "0x7fffffff" - addFormatterTest("%#x", v2, v2s) - addFormatterTest("%#x", pv2, v2Addr) - addFormatterTest("%#x", &pv2, pv2Addr) - - // %f passthrough with precision. - addFormatterTest("%.2f", 3.1415, "3.14") - addFormatterTest("%.3f", 3.1415, "3.142") - addFormatterTest("%.4f", 3.1415, "3.1415") - - // %f passthrough with width and precision. - addFormatterTest("%5.2f", 3.1415, " 3.14") - addFormatterTest("%6.3f", 3.1415, " 3.142") - addFormatterTest("%7.4f", 3.1415, " 3.1415") - - // %d passthrough with width. - addFormatterTest("%3d", 127, "127") - addFormatterTest("%4d", 127, " 127") - addFormatterTest("%5d", 127, " 127") - - // %q passthrough with string. - addFormatterTest("%q", "test", "\"test\"") -} - -// TestFormatter executes all of the tests described by formatterTests. -func TestFormatter(t *testing.T) { - // Setup tests. - addIntFormatterTests() - addUintFormatterTests() - addBoolFormatterTests() - addFloatFormatterTests() - addComplexFormatterTests() - addArrayFormatterTests() - addSliceFormatterTests() - addStringFormatterTests() - addInterfaceFormatterTests() - addMapFormatterTests() - addStructFormatterTests() - addUintptrFormatterTests() - addUnsafePointerFormatterTests() - addChanFormatterTests() - addFuncFormatterTests() - addCircularFormatterTests() - addPanicFormatterTests() - addErrorFormatterTests() - addPassthroughFormatterTests() - - t.Logf("Running %d tests", len(formatterTests)) - for i, test := range formatterTests { - buf := new(bytes.Buffer) - spew.Fprintf(buf, test.format, test.in) - s := buf.String() - if testFailed(s, test.wants) { - t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, - stringizeWants(test.wants)) - continue - } - } -} - -type testStruct struct { - x int -} - -func (ts testStruct) String() string { - return fmt.Sprintf("ts.%d", ts.x) -} - -type testStructP struct { - x int -} - -func (ts *testStructP) String() string { - return fmt.Sprintf("ts.%d", ts.x) -} - -func TestPrintSortedKeys(t *testing.T) { - cfg := spew.ConfigState{SortKeys: true} - s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) - expected := "map[1:1 2:2 3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 1:\n %v %v", s, expected) - } - - s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2}) - expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 2:\n %v %v", s, expected) - } - - s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) - expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" - if spew.UnsafeDisabled { - expected = "map[1:1 2:2 3:3]" - } - if s != expected { - t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) - } - - s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) - expected = "map[ts.1:1 ts.2:2 ts.3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) - } - - if !spew.UnsafeDisabled { - s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) - expected = "map[ts.1:1 ts.2:2 ts.3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) - } - } - - s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) - expected = "map[error: 1:1 error: 2:2 error: 3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 6:\n %v %v", s, expected) - } -} diff --git a/vendor/github.com/davecgh/go-spew/spew/internal_test.go b/vendor/github.com/davecgh/go-spew/spew/internal_test.go deleted file mode 100644 index 1069ee21c1f..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/internal_test.go +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2013 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* -This test file is part of the spew package rather than than the spew_test -package because it needs access to internals to properly test certain cases -which are not possible via the public interface since they should never happen. -*/ - -package spew - -import ( - "bytes" - "reflect" - "testing" -) - -// dummyFmtState implements a fake fmt.State to use for testing invalid -// reflect.Value handling. This is necessary because the fmt package catches -// invalid values before invoking the formatter on them. -type dummyFmtState struct { - bytes.Buffer -} - -func (dfs *dummyFmtState) Flag(f int) bool { - if f == int('+') { - return true - } - return false -} - -func (dfs *dummyFmtState) Precision() (int, bool) { - return 0, false -} - -func (dfs *dummyFmtState) Width() (int, bool) { - return 0, false -} - -// TestInvalidReflectValue ensures the dump and formatter code handles an -// invalid reflect value properly. This needs access to internal state since it -// should never happen in real code and therefore can't be tested via the public -// API. -func TestInvalidReflectValue(t *testing.T) { - i := 1 - - // Dump invalid reflect value. - v := new(reflect.Value) - buf := new(bytes.Buffer) - d := dumpState{w: buf, cs: &Config} - d.dump(*v) - s := buf.String() - want := "" - if s != want { - t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) - } - i++ - - // Formatter invalid reflect value. - buf2 := new(dummyFmtState) - f := formatState{value: *v, cs: &Config, fs: buf2} - f.format(*v) - s = buf2.String() - want = "" - if s != want { - t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) - } -} - -// SortValues makes the internal sortValues function available to the test -// package. -func SortValues(values []reflect.Value, cs *ConfigState) { - sortValues(values, cs) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go b/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go deleted file mode 100644 index 83e070e9a86..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2013-2015 Dave Collins - -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. - -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when the code is not running on Google App Engine and "-tags disableunsafe" -// is not added to the go build command line. -// +build !appengine,!disableunsafe - -/* -This test file is part of the spew package rather than than the spew_test -package because it needs access to internals to properly test certain cases -which are not possible via the public interface since they should never happen. -*/ - -package spew - -import ( - "bytes" - "reflect" - "testing" - "unsafe" -) - -// changeKind uses unsafe to intentionally change the kind of a reflect.Value to -// the maximum kind value which does not exist. This is needed to test the -// fallback code which punts to the standard fmt library for new types that -// might get added to the language. -func changeKind(v *reflect.Value, readOnly bool) { - rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) - *rvf = *rvf | ((1< + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/spew_test.go b/vendor/github.com/davecgh/go-spew/spew/spew_test.go deleted file mode 100644 index dbbc0856792..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/spew_test.go +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (c) 2013 Dave Collins - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package spew_test - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/davecgh/go-spew/spew" -) - -// spewFunc is used to identify which public function of the spew package or -// ConfigState a test applies to. -type spewFunc int - -const ( - fCSFdump spewFunc = iota - fCSFprint - fCSFprintf - fCSFprintln - fCSPrint - fCSPrintln - fCSSdump - fCSSprint - fCSSprintf - fCSSprintln - fCSErrorf - fCSNewFormatter - fErrorf - fFprint - fFprintln - fPrint - fPrintln - fSdump - fSprint - fSprintf - fSprintln -) - -// Map of spewFunc values to names for pretty printing. -var spewFuncStrings = map[spewFunc]string{ - fCSFdump: "ConfigState.Fdump", - fCSFprint: "ConfigState.Fprint", - fCSFprintf: "ConfigState.Fprintf", - fCSFprintln: "ConfigState.Fprintln", - fCSSdump: "ConfigState.Sdump", - fCSPrint: "ConfigState.Print", - fCSPrintln: "ConfigState.Println", - fCSSprint: "ConfigState.Sprint", - fCSSprintf: "ConfigState.Sprintf", - fCSSprintln: "ConfigState.Sprintln", - fCSErrorf: "ConfigState.Errorf", - fCSNewFormatter: "ConfigState.NewFormatter", - fErrorf: "spew.Errorf", - fFprint: "spew.Fprint", - fFprintln: "spew.Fprintln", - fPrint: "spew.Print", - fPrintln: "spew.Println", - fSdump: "spew.Sdump", - fSprint: "spew.Sprint", - fSprintf: "spew.Sprintf", - fSprintln: "spew.Sprintln", -} - -func (f spewFunc) String() string { - if s, ok := spewFuncStrings[f]; ok { - return s - } - return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) -} - -// spewTest is used to describe a test to be performed against the public -// functions of the spew package or ConfigState. -type spewTest struct { - cs *spew.ConfigState - f spewFunc - format string - in interface{} - want string -} - -// spewTests houses the tests to be performed against the public functions of -// the spew package and ConfigState. -// -// These tests are only intended to ensure the public functions are exercised -// and are intentionally not exhaustive of types. The exhaustive type -// tests are handled in the dump and format tests. -var spewTests []spewTest - -// redirStdout is a helper function to return the standard output from f as a -// byte slice. -func redirStdout(f func()) ([]byte, error) { - tempFile, err := ioutil.TempFile("", "ss-test") - if err != nil { - return nil, err - } - fileName := tempFile.Name() - defer os.Remove(fileName) // Ignore error - - origStdout := os.Stdout - os.Stdout = tempFile - f() - os.Stdout = origStdout - tempFile.Close() - - return ioutil.ReadFile(fileName) -} - -func initSpewTests() { - // Config states with various settings. - scsDefault := spew.NewDefaultConfig() - scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} - scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} - scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} - scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} - - // Variables for tests on types which implement Stringer interface with and - // without a pointer receiver. - ts := stringer("test") - tps := pstringer("test") - - // depthTester is used to test max depth handling for structs, array, slices - // and maps. - type depthTester struct { - ic indirCir1 - arr [1]string - slice []string - m map[string]int - } - dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, - map[string]int{"one": 1}} - - // Variable for tests on types which implement error interface. - te := customError(10) - - spewTests = []spewTest{ - {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, - {scsDefault, fCSFprint, "", int16(32767), "32767"}, - {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, - {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, - {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, - {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, - {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, - {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, - {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, - {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, - {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, - {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, - {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, - {scsDefault, fFprint, "", float32(3.14), "3.14"}, - {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, - {scsDefault, fPrint, "", true, "true"}, - {scsDefault, fPrintln, "", false, "false\n"}, - {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, - {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, - {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, - {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, - {scsNoMethods, fCSFprint, "", ts, "test"}, - {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, - {scsNoMethods, fCSFprint, "", tps, "test"}, - {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, - {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, - {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, - {scsNoPmethods, fCSFprint, "", tps, "test"}, - {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, - {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, - {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + - " ic: (spew_test.indirCir1) {\n \n },\n" + - " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + - " slice: ([]string) (len=1 cap=1) {\n \n },\n" + - " m: (map[string]int) (len=1) {\n \n }\n}\n"}, - {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, - {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + - "(len=4) (stringer test) \"test\"\n"}, - {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, - {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + - "(error: 10) 10\n"}, - } -} - -// TestSpew executes all of the tests described by spewTests. -func TestSpew(t *testing.T) { - initSpewTests() - - t.Logf("Running %d tests", len(spewTests)) - for i, test := range spewTests { - buf := new(bytes.Buffer) - switch test.f { - case fCSFdump: - test.cs.Fdump(buf, test.in) - - case fCSFprint: - test.cs.Fprint(buf, test.in) - - case fCSFprintf: - test.cs.Fprintf(buf, test.format, test.in) - - case fCSFprintln: - test.cs.Fprintln(buf, test.in) - - case fCSPrint: - b, err := redirStdout(func() { test.cs.Print(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fCSPrintln: - b, err := redirStdout(func() { test.cs.Println(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fCSSdump: - str := test.cs.Sdump(test.in) - buf.WriteString(str) - - case fCSSprint: - str := test.cs.Sprint(test.in) - buf.WriteString(str) - - case fCSSprintf: - str := test.cs.Sprintf(test.format, test.in) - buf.WriteString(str) - - case fCSSprintln: - str := test.cs.Sprintln(test.in) - buf.WriteString(str) - - case fCSErrorf: - err := test.cs.Errorf(test.format, test.in) - buf.WriteString(err.Error()) - - case fCSNewFormatter: - fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) - - case fErrorf: - err := spew.Errorf(test.format, test.in) - buf.WriteString(err.Error()) - - case fFprint: - spew.Fprint(buf, test.in) - - case fFprintln: - spew.Fprintln(buf, test.in) - - case fPrint: - b, err := redirStdout(func() { spew.Print(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fPrintln: - b, err := redirStdout(func() { spew.Println(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fSdump: - str := spew.Sdump(test.in) - buf.WriteString(str) - - case fSprint: - str := spew.Sprint(test.in) - buf.WriteString(str) - - case fSprintf: - str := spew.Sprintf(test.format, test.in) - buf.WriteString(str) - - case fSprintln: - str := spew.Sprintln(test.in) - buf.WriteString(str) - - default: - t.Errorf("%v #%d unrecognized function", test.f, i) - continue - } - s := buf.String() - if test.want != s { - t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) - continue - } - } -} diff --git a/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go b/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go deleted file mode 100644 index 5c87dd456ed..00000000000 --- a/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2013 Dave Collins -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when both cgo is supported and "-tags testcgo" is added to the go test -// command line. This code should really only be in the dumpcgo_test.go file, -// but unfortunately Go will not allow cgo in test files, so this is a -// workaround to allow cgo types to be tested. This configuration is used -// because spew itself does not require cgo to run even though it does handle -// certain cgo types specially. Rather than forcing all clients to require cgo -// and an external C compiler just to run the tests, this scheme makes them -// optional. -// +build cgo,testcgo - -package testdata - -/* -#include -typedef unsigned char custom_uchar_t; - -char *ncp = 0; -char *cp = "test"; -char ca[6] = {'t', 'e', 's', 't', '2', '\0'}; -unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'}; -signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'}; -uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'}; -custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'}; -*/ -import "C" - -// GetCgoNullCharPointer returns a null char pointer via cgo. This is only -// used for tests. -func GetCgoNullCharPointer() interface{} { - return C.ncp -} - -// GetCgoCharPointer returns a char pointer via cgo. This is only used for -// tests. -func GetCgoCharPointer() interface{} { - return C.cp -} - -// GetCgoCharArray returns a char array via cgo and the array's len and cap. -// This is only used for tests. -func GetCgoCharArray() (interface{}, int, int) { - return C.ca, len(C.ca), cap(C.ca) -} - -// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the -// array's len and cap. This is only used for tests. -func GetCgoUnsignedCharArray() (interface{}, int, int) { - return C.uca, len(C.uca), cap(C.uca) -} - -// GetCgoSignedCharArray returns a signed char array via cgo and the array's len -// and cap. This is only used for tests. -func GetCgoSignedCharArray() (interface{}, int, int) { - return C.sca, len(C.sca), cap(C.sca) -} - -// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and -// cap. This is only used for tests. -func GetCgoUint8tArray() (interface{}, int, int) { - return C.ui8ta, len(C.ui8ta), cap(C.ui8ta) -} - -// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via -// cgo and the array's len and cap. This is only used for tests. -func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) { - return C.tuca, len(C.tuca), cap(C.tuca) -} diff --git a/vendor/github.com/fatih/color/.travis.yml b/vendor/github.com/fatih/color/.travis.yml deleted file mode 100644 index 4f203dd1931..00000000000 --- a/vendor/github.com/fatih/color/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: go -go: 1.6 - diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md deleted file mode 100644 index 0921f98a5f3..00000000000 --- a/vendor/github.com/fatih/color/README.md +++ /dev/null @@ -1,154 +0,0 @@ -# Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color) - - - -Color lets you use colorized outputs in terms of [ANSI Escape -Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It -has support for Windows too! The API can be used in several ways, pick one that -suits you. - - - -![Color](http://i.imgur.com/c1JI0lA.png) - - -## Install - -```bash -go get github.com/fatih/color -``` - -## Examples - -### Standard colors - -```go -// Print with default helper functions -color.Cyan("Prints text in cyan.") - -// A newline will be appended automatically -color.Blue("Prints %s in blue.", "text") - -// These are using the default foreground colors -color.Red("We have red") -color.Magenta("And many others ..") - -``` - -### Mix and reuse colors - -```go -// Create a new color object -c := color.New(color.FgCyan).Add(color.Underline) -c.Println("Prints cyan text with an underline.") - -// Or just add them to New() -d := color.New(color.FgCyan, color.Bold) -d.Printf("This prints bold cyan %s\n", "too!.") - -// Mix up foreground and background colors, create new mixes! -red := color.New(color.FgRed) - -boldRed := red.Add(color.Bold) -boldRed.Println("This will print text in bold red.") - -whiteBackground := red.Add(color.BgWhite) -whiteBackground.Println("Red text with white background.") -``` - -### Custom print functions (PrintFunc) - -```go -// Create a custom print function for convenience -red := color.New(color.FgRed).PrintfFunc() -red("Warning") -red("Error: %s", err) - -// Mix up multiple attributes -notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() -notice("Don't forget this...") -``` - -### Insert into noncolor strings (SprintFunc) - -```go -// Create SprintXxx functions to mix strings with other non-colorized strings: -yellow := color.New(color.FgYellow).SprintFunc() -red := color.New(color.FgRed).SprintFunc() -fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error")) - -info := color.New(color.FgWhite, color.BgGreen).SprintFunc() -fmt.Printf("This %s rocks!\n", info("package")) - -// Use helper functions -fmt.Printf("This", color.RedString("warning"), "should be not neglected.") -fmt.Printf(color.GreenString("Info:"), "an important message." ) - -// Windows supported too! Just don't forget to change the output to color.Output -fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) -``` - -### Plug into existing code - -```go -// Use handy standard colors -color.Set(color.FgYellow) - -fmt.Println("Existing text will now be in yellow") -fmt.Printf("This one %s\n", "too") - -color.Unset() // Don't forget to unset - -// You can mix up parameters -color.Set(color.FgMagenta, color.Bold) -defer color.Unset() // Use it in your function - -fmt.Println("All text will now be bold magenta.") -``` - -### Disable color - -There might be a case where you want to disable color output (for example to -pipe the standard output of your app to somewhere else). `Color` has support to -disable colors both globally and for single color definition. For example -suppose you have a CLI app and a `--no-color` bool flag. You can easily disable -the color output with: - -```go - -var flagNoColor = flag.Bool("no-color", false, "Disable color output") - -if *flagNoColor { - color.NoColor = true // disables colorized output -} -``` - -It also has support for single color definitions (local). You can -disable/enable color output on the fly: - -```go -c := color.New(color.FgCyan) -c.Println("Prints cyan text") - -c.DisableColor() -c.Println("This is printed without any color") - -c.EnableColor() -c.Println("This prints again cyan...") -``` - -## Todo - -* Save/Return previous values -* Evaluate fmt.Formatter interface - - -## Credits - - * [Fatih Arslan](https://github.com/fatih) - * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) - -## License - -The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details - diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index e3e997284d0..7b5f3146d33 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -2,19 +2,33 @@ package color import ( "fmt" + "io" "os" "strconv" "strings" + "sync" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" ) -// NoColor defines if the output is colorized or not. It's dynamically set to -// false or true based on the stdout's file descriptor referring to a terminal -// or not. This is a global option and affects all colors. For more control -// over each color block use the methods DisableColor() individually. -var NoColor = !isatty.IsTerminal(os.Stdout.Fd()) +var ( + // NoColor defines if the output is colorized or not. It's dynamically set to + // false or true based on the stdout's file descriptor referring to a terminal + // or not. This is a global option and affects all colors. For more control + // over each color block use the methods DisableColor() individually. + NoColor = os.Getenv("TERM") == "dumb" || + (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) + + // Output defines the standard output of the print functions. By default + // os.Stdout is used. + Output = colorable.NewColorableStdout() + + // colorsCache is used to reduce the count of created Color objects and + // allows to reuse already created objects with required Attribute. + colorsCache = make(map[Attribute]*Color) + colorsCacheMu sync.Mutex // protects colorsCache +) // Color defines a custom color object which is defined by SGR parameters. type Color struct { @@ -132,6 +146,27 @@ func (c *Color) unset() { Unset() } +func (c *Color) setWriter(w io.Writer) *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(w, c.format()) + return c +} + +func (c *Color) unsetWriter(w io.Writer) { + if c.isNoColorSet() { + return + } + + if NoColor { + return + } + + fmt.Fprintf(w, "%s[%dm", escape, Reset) +} + // Add is used to chain SGR parameters. Use as many as parameters to combine // and create custom color objects. Example: Add(color.FgRed, color.Underline). func (c *Color) Add(value ...Attribute) *Color { @@ -145,9 +180,17 @@ func (c *Color) prepend(value Attribute) { c.params[0] = value } -// Output defines the standard output of the print functions. By default -// os.Stdout is used. -var Output = colorable.NewColorableStdout() +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprint(w, a...) +} // Print formats using the default formats for its operands and writes to // standard output. Spaces are added between operands when neither is a @@ -161,6 +204,17 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { return fmt.Fprint(Output, a...) } +// Fprintf formats according to a format specifier and writes to w. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintf(w, format, a...) +} + // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. // This is the standard fmt.Printf() method wrapped with the given color. @@ -171,6 +225,17 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(Output, format, a...) } +// Fprintln formats using the default formats for its operands and writes to w. +// Spaces are always added between operands and a newline is appended. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintln(w, a...) +} + // Println formats using the default formats for its operands and writes to // standard output. Spaces are always added between operands and a newline is // appended. It returns the number of bytes written and any write error @@ -183,27 +248,72 @@ func (c *Color) Println(a ...interface{}) (n int, err error) { return fmt.Fprintln(Output, a...) } +// Sprint is just like Print, but returns a string instead of printing it. +func (c *Color) Sprint(a ...interface{}) string { + return c.wrap(fmt.Sprint(a...)) +} + +// Sprintln is just like Println, but returns a string instead of printing it. +func (c *Color) Sprintln(a ...interface{}) string { + return c.wrap(fmt.Sprintln(a...)) +} + +// Sprintf is just like Printf, but returns a string instead of printing it. +func (c *Color) Sprintf(format string, a ...interface{}) string { + return c.wrap(fmt.Sprintf(format, a...)) +} + +// FprintFunc returns a new function that prints the passed arguments as +// colorized with color.Fprint(). +func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprint(w, a...) + } +} + // PrintFunc returns a new function that prints the passed arguments as // colorized with color.Print(). func (c *Color) PrintFunc() func(a ...interface{}) { - return func(a ...interface{}) { c.Print(a...) } + return func(a ...interface{}) { + c.Print(a...) + } +} + +// FprintfFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintf(). +func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { + return func(w io.Writer, format string, a ...interface{}) { + c.Fprintf(w, format, a...) + } } // PrintfFunc returns a new function that prints the passed arguments as // colorized with color.Printf(). func (c *Color) PrintfFunc() func(format string, a ...interface{}) { - return func(format string, a ...interface{}) { c.Printf(format, a...) } + return func(format string, a ...interface{}) { + c.Printf(format, a...) + } +} + +// FprintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintln(). +func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprintln(w, a...) + } } // PrintlnFunc returns a new function that prints the passed arguments as // colorized with color.Println(). func (c *Color) PrintlnFunc() func(a ...interface{}) { - return func(a ...interface{}) { c.Println(a...) } + return func(a ...interface{}) { + c.Println(a...) + } } // SprintFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprint(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output, example: +// string. Windows users should use this in conjunction with color.Output, example: // // put := New(FgYellow).SprintFunc() // fmt.Fprintf(color.Output, "This is a %s", put("warning")) @@ -215,7 +325,7 @@ func (c *Color) SprintFunc() func(a ...interface{}) string { // SprintfFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprintf(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output. +// string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { return func(format string, a ...interface{}) string { return c.wrap(fmt.Sprintf(format, a...)) @@ -224,7 +334,7 @@ func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { // SprintlnFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprintln(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output. +// string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintlnFunc() func(a ...interface{}) string { return func(a ...interface{}) string { return c.wrap(fmt.Sprintln(a...)) @@ -267,7 +377,7 @@ func (c *Color) DisableColor() { c.noColor = boolPtr(true) } -// EnableColor enables the color output. Use it in conjuction with +// EnableColor enables the color output. Use it in conjunction with // DisableColor(). Otherwise this method has no side effects. func (c *Color) EnableColor() { c.noColor = boolPtr(false) @@ -312,91 +422,179 @@ func boolPtr(v bool) *bool { return &v } -// Black is an convenient helper function to print with black foreground. A -// newline is appended to format by default. -func Black(format string, a ...interface{}) { printColor(format, FgBlack, a...) } +func getCachedColor(p Attribute) *Color { + colorsCacheMu.Lock() + defer colorsCacheMu.Unlock() -// Red is an convenient helper function to print with red foreground. A -// newline is appended to format by default. -func Red(format string, a ...interface{}) { printColor(format, FgRed, a...) } + c, ok := colorsCache[p] + if !ok { + c = New(p) + colorsCache[p] = c + } -// Green is an convenient helper function to print with green foreground. A -// newline is appended to format by default. -func Green(format string, a ...interface{}) { printColor(format, FgGreen, a...) } + return c +} -// Yellow is an convenient helper function to print with yellow foreground. -// A newline is appended to format by default. -func Yellow(format string, a ...interface{}) { printColor(format, FgYellow, a...) } +func colorPrint(format string, p Attribute, a ...interface{}) { + c := getCachedColor(p) -// Blue is an convenient helper function to print with blue foreground. A -// newline is appended to format by default. -func Blue(format string, a ...interface{}) { printColor(format, FgBlue, a...) } - -// Magenta is an convenient helper function to print with magenta foreground. -// A newline is appended to format by default. -func Magenta(format string, a ...interface{}) { printColor(format, FgMagenta, a...) } - -// Cyan is an convenient helper function to print with cyan foreground. A -// newline is appended to format by default. -func Cyan(format string, a ...interface{}) { printColor(format, FgCyan, a...) } - -// White is an convenient helper function to print with white foreground. A -// newline is appended to format by default. -func White(format string, a ...interface{}) { printColor(format, FgWhite, a...) } - -func printColor(format string, p Attribute, a ...interface{}) { if !strings.HasSuffix(format, "\n") { format += "\n" } - c := &Color{params: []Attribute{p}} - c.Printf(format, a...) + if len(a) == 0 { + c.Print(format) + } else { + c.Printf(format, a...) + } } -// BlackString is an convenient helper function to return a string with black +func colorString(format string, p Attribute, a ...interface{}) string { + c := getCachedColor(p) + + if len(a) == 0 { + return c.SprintFunc()(format) + } + + return c.SprintfFunc()(format, a...) +} + +// Black is a convenient helper function to print with black foreground. A +// newline is appended to format by default. +func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } + +// Red is a convenient helper function to print with red foreground. A +// newline is appended to format by default. +func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } + +// Green is a convenient helper function to print with green foreground. A +// newline is appended to format by default. +func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } + +// Yellow is a convenient helper function to print with yellow foreground. +// A newline is appended to format by default. +func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } + +// Blue is a convenient helper function to print with blue foreground. A +// newline is appended to format by default. +func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } + +// Magenta is a convenient helper function to print with magenta foreground. +// A newline is appended to format by default. +func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } + +// Cyan is a convenient helper function to print with cyan foreground. A +// newline is appended to format by default. +func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } + +// White is a convenient helper function to print with white foreground. A +// newline is appended to format by default. +func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } + +// BlackString is a convenient helper function to return a string with black // foreground. -func BlackString(format string, a ...interface{}) string { - return New(FgBlack).SprintfFunc()(format, a...) -} +func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } -// RedString is an convenient helper function to return a string with red +// RedString is a convenient helper function to return a string with red // foreground. -func RedString(format string, a ...interface{}) string { - return New(FgRed).SprintfFunc()(format, a...) -} +func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } -// GreenString is an convenient helper function to return a string with green +// GreenString is a convenient helper function to return a string with green // foreground. -func GreenString(format string, a ...interface{}) string { - return New(FgGreen).SprintfFunc()(format, a...) -} +func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } -// YellowString is an convenient helper function to return a string with yellow +// YellowString is a convenient helper function to return a string with yellow // foreground. -func YellowString(format string, a ...interface{}) string { - return New(FgYellow).SprintfFunc()(format, a...) -} +func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } -// BlueString is an convenient helper function to return a string with blue +// BlueString is a convenient helper function to return a string with blue // foreground. -func BlueString(format string, a ...interface{}) string { - return New(FgBlue).SprintfFunc()(format, a...) -} +func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } -// MagentaString is an convenient helper function to return a string with magenta +// MagentaString is a convenient helper function to return a string with magenta // foreground. func MagentaString(format string, a ...interface{}) string { - return New(FgMagenta).SprintfFunc()(format, a...) + return colorString(format, FgMagenta, a...) } -// CyanString is an convenient helper function to return a string with cyan +// CyanString is a convenient helper function to return a string with cyan // foreground. -func CyanString(format string, a ...interface{}) string { - return New(FgCyan).SprintfFunc()(format, a...) +func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } + +// WhiteString is a convenient helper function to return a string with white +// foreground. +func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } + +// HiBlack is a convenient helper function to print with hi-intensity black foreground. A +// newline is appended to format by default. +func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) } + +// HiRed is a convenient helper function to print with hi-intensity red foreground. A +// newline is appended to format by default. +func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) } + +// HiGreen is a convenient helper function to print with hi-intensity green foreground. A +// newline is appended to format by default. +func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) } + +// HiYellow is a convenient helper function to print with hi-intensity yellow foreground. +// A newline is appended to format by default. +func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) } + +// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A +// newline is appended to format by default. +func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) } + +// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground. +// A newline is appended to format by default. +func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) } + +// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A +// newline is appended to format by default. +func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) } + +// HiWhite is a convenient helper function to print with hi-intensity white foreground. A +// newline is appended to format by default. +func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) } + +// HiBlackString is a convenient helper function to return a string with hi-intensity black +// foreground. +func HiBlackString(format string, a ...interface{}) string { + return colorString(format, FgHiBlack, a...) } -// WhiteString is an convenient helper function to return a string with white +// HiRedString is a convenient helper function to return a string with hi-intensity red // foreground. -func WhiteString(format string, a ...interface{}) string { - return New(FgWhite).SprintfFunc()(format, a...) +func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) } + +// HiGreenString is a convenient helper function to return a string with hi-intensity green +// foreground. +func HiGreenString(format string, a ...interface{}) string { + return colorString(format, FgHiGreen, a...) +} + +// HiYellowString is a convenient helper function to return a string with hi-intensity yellow +// foreground. +func HiYellowString(format string, a ...interface{}) string { + return colorString(format, FgHiYellow, a...) +} + +// HiBlueString is a convenient helper function to return a string with hi-intensity blue +// foreground. +func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) } + +// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta +// foreground. +func HiMagentaString(format string, a ...interface{}) string { + return colorString(format, FgHiMagenta, a...) +} + +// HiCyanString is a convenient helper function to return a string with hi-intensity cyan +// foreground. +func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) } + +// HiWhiteString is a convenient helper function to return a string with hi-intensity white +// foreground. +func HiWhiteString(format string, a ...interface{}) string { + return colorString(format, FgHiWhite, a...) } diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index 17908787c99..cf1e96500f4 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -15,6 +15,11 @@ Use simple and default helper functions with predefined foreground colors: color.Yellow("Yellow color too!") color.Magenta("And many others ..") + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") + However there are times where custom color mixes are required. Below are some examples to create custom color objects and use the print functions of each separate color object. @@ -37,6 +42,11 @@ separate color object. whiteBackground := red.Add(color.BgWhite) whiteBackground.Println("Red text with White background.") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: @@ -49,6 +59,15 @@ You can create PrintXxx functions to simplify even more: notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() notice("don't forget this...") +You can also FprintXxx functions to pass your own io.Writer: + + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") + Or create SprintXxx functions to mix strings with other non-colorized strings: @@ -60,7 +79,7 @@ Or create SprintXxx functions to mix strings with other non-colorized strings: info := New(FgWhite, BgGreen).SprintFunc() fmt.Printf("this %s rocks!\n", info("package")) -Windows support is enabled by default. All Print functions works as intended. +Windows support is enabled by default. All Print functions work as intended. However only for color.SprintXXX functions, user should use fmt.FprintXXX and set the output to color.Output: diff --git a/vendor/github.com/go-ini/ini/LICENSE b/vendor/github.com/go-ini/ini/LICENSE index 37ec93a14fd..d361bbcdf5c 100644 --- a/vendor/github.com/go-ini/ini/LICENSE +++ b/vendor/github.com/go-ini/ini/LICENSE @@ -176,7 +176,7 @@ 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] + Copyright 2014 Unknwon Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/go-ini/ini/Makefile b/vendor/github.com/go-ini/ini/Makefile deleted file mode 100644 index ac034e5258f..00000000000 --- a/vendor/github.com/go-ini/ini/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -.PHONY: build test bench vet - -build: vet bench - -test: - go test -v -cover -race - -bench: - go test -v -cover -race -test.bench=. -test.benchmem - -vet: - go vet diff --git a/vendor/github.com/go-ini/ini/README.md b/vendor/github.com/go-ini/ini/README.md deleted file mode 100644 index a939d75e9f2..00000000000 --- a/vendor/github.com/go-ini/ini/README.md +++ /dev/null @@ -1,703 +0,0 @@ -INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini) -=== - -![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) - -Package ini provides INI file read and write functionality in Go. - -[简体中文](README_ZH.md) - -## Feature - -- Load multiple data sources(`[]byte` or file) with overwrites. -- Read with recursion values. -- Read with parent-child sections. -- Read with auto-increment key names. -- Read with multiple-line values. -- Read with tons of helper methods. -- Read and convert values to Go types. -- Read and **WRITE** comments of sections and keys. -- Manipulate sections, keys and comments with ease. -- Keep sections and keys in order as you parse and save. - -## Installation - -To use a tagged revision: - - go get gopkg.in/ini.v1 - -To use with latest changes: - - go get github.com/go-ini/ini - -Please add `-u` flag to update in the future. - -### Testing - -If you want to test on your machine, please apply `-t` flag: - - go get -t gopkg.in/ini.v1 - -Please add `-u` flag to update in the future. - -## Getting Started - -### Loading from data sources - -A **Data Source** is either raw data in type `[]byte` or a file name with type `string` and you can load **as many data sources as you want**. Passing other types will simply return an error. - -```go -cfg, err := ini.Load([]byte("raw data"), "filename") -``` - -Or start with an empty object: - -```go -cfg := ini.Empty() -``` - -When you cannot decide how many data sources to load at the beginning, you will still be able to **Append()** them later. - -```go -err := cfg.Append("other file", []byte("other raw data")) -``` - -If you have a list of files with possibilities that some of them may not available at the time, and you don't know exactly which ones, you can use `LooseLoad` to ignore nonexistent files without returning error. - -```go -cfg, err := ini.LooseLoad("filename", "filename_404") -``` - -The cool thing is, whenever the file is available to load while you're calling `Reload` method, it will be counted as usual. - -#### Ignore cases of key name - -When you do not care about cases of section and key names, you can use `InsensitiveLoad` to force all names to be lowercased while parsing. - -```go -cfg, err := ini.InsensitiveLoad("filename") -//... - -// sec1 and sec2 are the exactly same section object -sec1, err := cfg.GetSection("Section") -sec2, err := cfg.GetSection("SecTIOn") - -// key1 and key2 are the exactly same key object -key1, err := cfg.GetKey("Key") -key2, err := cfg.GetKey("KeY") -``` - -#### MySQL-like boolean key - -MySQL's configuration allows a key without value as follows: - -```ini -[mysqld] -... -skip-host-cache -skip-name-resolve -``` - -By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options: - -```go -cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf")) -``` - -The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read. - -### Working with sections - -To get a section, you would need to: - -```go -section, err := cfg.GetSection("section name") -``` - -For a shortcut for default section, just give an empty string as name: - -```go -section, err := cfg.GetSection("") -``` - -When you're pretty sure the section exists, following code could make your life easier: - -```go -section := cfg.Section("") -``` - -What happens when the section somehow does not exist? Don't panic, it automatically creates and returns a new section to you. - -To create a new section: - -```go -err := cfg.NewSection("new section") -``` - -To get a list of sections or section names: - -```go -sections := cfg.Sections() -names := cfg.SectionStrings() -``` - -### Working with keys - -To get a key under a section: - -```go -key, err := cfg.Section("").GetKey("key name") -``` - -Same rule applies to key operations: - -```go -key := cfg.Section("").Key("key name") -``` - -To check if a key exists: - -```go -yes := cfg.Section("").HasKey("key name") -``` - -To create a new key: - -```go -err := cfg.Section("").NewKey("name", "value") -``` - -To get a list of keys or key names: - -```go -keys := cfg.Section("").Keys() -names := cfg.Section("").KeyStrings() -``` - -To get a clone hash of keys and corresponding values: - -```go -hash := cfg.Section("").KeysHash() -``` - -### Working with values - -To get a string value: - -```go -val := cfg.Section("").Key("key name").String() -``` - -To validate key value on the fly: - -```go -val := cfg.Section("").Key("key name").Validate(func(in string) string { - if len(in) == 0 { - return "default" - } - return in -}) -``` - -If you do not want any auto-transformation (such as recursive read) for the values, you can get raw value directly (this way you get much better performance): - -```go -val := cfg.Section("").Key("key name").Value() -``` - -To check if raw value exists: - -```go -yes := cfg.Section("").HasValue("test value") -``` - -To get value with types: - -```go -// For boolean values: -// true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On -// false when value is: 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off -v, err = cfg.Section("").Key("BOOL").Bool() -v, err = cfg.Section("").Key("FLOAT64").Float64() -v, err = cfg.Section("").Key("INT").Int() -v, err = cfg.Section("").Key("INT64").Int64() -v, err = cfg.Section("").Key("UINT").Uint() -v, err = cfg.Section("").Key("UINT64").Uint64() -v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) -v, err = cfg.Section("").Key("TIME").Time() // RFC3339 - -v = cfg.Section("").Key("BOOL").MustBool() -v = cfg.Section("").Key("FLOAT64").MustFloat64() -v = cfg.Section("").Key("INT").MustInt() -v = cfg.Section("").Key("INT64").MustInt64() -v = cfg.Section("").Key("UINT").MustUint() -v = cfg.Section("").Key("UINT64").MustUint64() -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) -v = cfg.Section("").Key("TIME").MustTime() // RFC3339 - -// Methods start with Must also accept one argument for default value -// when key not found or fail to parse value to given type. -// Except method MustString, which you have to pass a default value. - -v = cfg.Section("").Key("String").MustString("default") -v = cfg.Section("").Key("BOOL").MustBool(true) -v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) -v = cfg.Section("").Key("INT").MustInt(10) -v = cfg.Section("").Key("INT64").MustInt64(99) -v = cfg.Section("").Key("UINT").MustUint(3) -v = cfg.Section("").Key("UINT64").MustUint64(6) -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) -v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 -``` - -What if my value is three-line long? - -```ini -[advance] -ADDRESS = """404 road, -NotFound, State, 5000 -Earth""" -``` - -Not a problem! - -```go -cfg.Section("advance").Key("ADDRESS").String() - -/* --- start --- -404 road, -NotFound, State, 5000 -Earth ------- end --- */ -``` - -That's cool, how about continuation lines? - -```ini -[advance] -two_lines = how about \ - continuation lines? -lots_of_lines = 1 \ - 2 \ - 3 \ - 4 -``` - -Piece of cake! - -```go -cfg.Section("advance").Key("two_lines").String() // how about continuation lines? -cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 -``` - -Well, I hate continuation lines, how do I disable that? - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{ - IgnoreContinuation: true, -}, "filename") -``` - -Holy crap! - -Note that single quotes around values will be stripped: - -```ini -foo = "some value" // foo: some value -bar = 'some value' // bar: some value -``` - -That's all? Hmm, no. - -#### Helper methods of working with values - -To get value with given candidates: - -```go -v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) -v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) -v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) -v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) -v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) -v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) -v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) -v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 -``` - -Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates. - -To validate value in a given range: - -```go -vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) -vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) -vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) -vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) -vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) -vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) -vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 -``` - -##### Auto-split values into a slice - -To use zero value of type for invalid inputs: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] -vals = cfg.Section("").Key("STRINGS").Strings(",") -vals = cfg.Section("").Key("FLOAT64S").Float64s(",") -vals = cfg.Section("").Key("INTS").Ints(",") -vals = cfg.Section("").Key("INT64S").Int64s(",") -vals = cfg.Section("").Key("UINTS").Uints(",") -vals = cfg.Section("").Key("UINT64S").Uint64s(",") -vals = cfg.Section("").Key("TIMES").Times(",") -``` - -To exclude invalid values out of result slice: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [2.2] -vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") -vals = cfg.Section("").Key("INTS").ValidInts(",") -vals = cfg.Section("").Key("INT64S").ValidInt64s(",") -vals = cfg.Section("").Key("UINTS").ValidUints(",") -vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") -vals = cfg.Section("").Key("TIMES").ValidTimes(",") -``` - -Or to return nothing but error when have invalid inputs: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> error -vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") -vals = cfg.Section("").Key("INTS").StrictInts(",") -vals = cfg.Section("").Key("INT64S").StrictInt64s(",") -vals = cfg.Section("").Key("UINTS").StrictUints(",") -vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") -vals = cfg.Section("").Key("TIMES").StrictTimes(",") -``` - -### Save your configuration - -Finally, it's time to save your configuration to somewhere. - -A typical way to save configuration is writing it to a file: - -```go -// ... -err = cfg.SaveTo("my.ini") -err = cfg.SaveToIndent("my.ini", "\t") -``` - -Another way to save is writing to a `io.Writer` interface: - -```go -// ... -cfg.WriteTo(writer) -cfg.WriteToIndent(writer, "\t") -``` - -## Advanced Usage - -### Recursive Values - -For all value of keys, there is a special syntax `%()s`, where `` is the key name in same section or default section, and `%()s` will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions. - -```ini -NAME = ini - -[author] -NAME = Unknwon -GITHUB = https://github.com/%(NAME)s - -[package] -FULL_NAME = github.com/go-ini/%(NAME)s -``` - -```go -cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon -cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini -``` - -### Parent-child Sections - -You can use `.` in section name to indicate parent-child relationship between two or more sections. If the key not found in the child section, library will try again on its parent section until there is no parent section. - -```ini -NAME = ini -VERSION = v1 -IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s - -[package] -CLONE_URL = https://%(IMPORT_PATH)s - -[package.sub] -``` - -```go -cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 -``` - -#### Retrieve parent keys available to a child section - -```go -cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] -``` - -### Auto-increment Key Names - -If key name is `-` in data source, then it would be seen as special syntax for auto-increment key name start from 1, and every section is independent on counter. - -```ini -[features] --: Support read/write comments of keys and sections --: Support auto-increment of key names --: Support load multiple files to overwrite key values -``` - -```go -cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} -``` - -### Map To Struct - -Want more objective way to play with INI? Cool. - -```ini -Name = Unknwon -age = 21 -Male = true -Born = 1993-01-01T20:17:05Z - -[Note] -Content = Hi is a good man! -Cities = HangZhou, Boston -``` - -```go -type Note struct { - Content string - Cities []string -} - -type Person struct { - Name string - Age int `ini:"age"` - Male bool - Born time.Time - Note - Created time.Time `ini:"-"` -} - -func main() { - cfg, err := ini.Load("path/to/ini") - // ... - p := new(Person) - err = cfg.MapTo(p) - // ... - - // Things can be simpler. - err = ini.MapTo(p, "path/to/ini") - // ... - - // Just map a section? Fine. - n := new(Note) - err = cfg.Section("Note").MapTo(n) - // ... -} -``` - -Can I have default value for field? Absolutely. - -Assign it before you map to struct. It will keep the value as it is if the key is not presented or got wrong type. - -```go -// ... -p := &Person{ - Name: "Joe", -} -// ... -``` - -It's really cool, but what's the point if you can't give me my file back from struct? - -### Reflect From Struct - -Why not? - -```go -type Embeded struct { - Dates []time.Time `delim:"|"` - Places []string `ini:"places,omitempty"` - None []int `ini:",omitempty"` -} - -type Author struct { - Name string `ini:"NAME"` - Male bool - Age int - GPA float64 - NeverMind string `ini:"-"` - *Embeded -} - -func main() { - a := &Author{"Unknwon", true, 21, 2.8, "", - &Embeded{ - []time.Time{time.Now(), time.Now()}, - []string{"HangZhou", "Boston"}, - []int{}, - }} - cfg := ini.Empty() - err = ini.ReflectFrom(cfg, a) - // ... -} -``` - -So, what do I get? - -```ini -NAME = Unknwon -Male = true -Age = 21 -GPA = 2.8 - -[Embeded] -Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 -places = HangZhou,Boston -``` - -#### Name Mapper - -To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual section and key name. - -There are 2 built-in name mappers: - -- `AllCapsUnderscore`: it converts to format `ALL_CAPS_UNDERSCORE` then match section or key. -- `TitleUnderscore`: it converts to format `title_underscore` then match section or key. - -To use them: - -```go -type Info struct { - PackageName string -} - -func main() { - err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) - // ... - - cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) - // ... - info := new(Info) - cfg.NameMapper = ini.AllCapsUnderscore - err = cfg.MapTo(info) - // ... -} -``` - -Same rules of name mapper apply to `ini.ReflectFromWithMapper` function. - -#### Value Mapper - -To expand values (e.g. from environment variables), you can use the `ValueMapper` to transform values: - -```go -type Env struct { - Foo string `ini:"foo"` -} - -func main() { - cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") - cfg.ValueMapper = os.ExpandEnv - // ... - env := &Env{} - err = cfg.Section("env").MapTo(env) -} -``` - -This would set the value of `env.Foo` to the value of the environment variable `MY_VAR`. - -#### Other Notes On Map/Reflect - -Any embedded struct is treated as a section by default, and there is no automatic parent-child relations in map/reflect feature: - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child -} - -type Config struct { - City string - Parent -} -``` - -Example configuration: - -```ini -City = Boston - -[Parent] -Name = Unknwon - -[Child] -Age = 21 -``` - -What if, yes, I'm paranoid, I want embedded struct to be in the same section. Well, all roads lead to Rome. - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child `ini:"Parent"` -} - -type Config struct { - City string - Parent -} -``` - -Example configuration: - -```ini -City = Boston - -[Parent] -Name = Unknwon -Age = 21 -``` - -## Getting Help - -- [API Documentation](https://gowalker.org/gopkg.in/ini.v1) -- [File An Issue](https://github.com/go-ini/ini/issues/new) - -## FAQs - -### What does `BlockMode` field do? - -By default, library lets you read and write values so we need a locker to make sure your data is safe. But in cases that you are very sure about only reading data through the library, you can set `cfg.BlockMode = false` to speed up read operations about **50-70%** faster. - -### Why another INI library? - -Many people are using my another INI library [goconfig](https://github.com/Unknwon/goconfig), so the reason for this one is I would like to make more Go style code. Also when you set `cfg.BlockMode = false`, this one is about **10-30%** faster. - -To make those changes I have to confirm API broken, so it's safer to keep it in another place and start using `gopkg.in` to version my package at this time.(PS: shorter import path) - -## License - -This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. diff --git a/vendor/github.com/go-ini/ini/README_ZH.md b/vendor/github.com/go-ini/ini/README_ZH.md deleted file mode 100644 index 2178e47895d..00000000000 --- a/vendor/github.com/go-ini/ini/README_ZH.md +++ /dev/null @@ -1,690 +0,0 @@ -本包提供了 Go 语言中读写 INI 文件的功能。 - -## 功能特性 - -- 支持覆盖加载多个数据源(`[]byte` 或文件) -- 支持递归读取键值 -- 支持读取父子分区 -- 支持读取自增键名 -- 支持读取多行的键值 -- 支持大量辅助方法 -- 支持在读取时直接转换为 Go 语言类型 -- 支持读取和 **写入** 分区和键的注释 -- 轻松操作分区、键值和注释 -- 在保存文件时分区和键值会保持原有的顺序 - -## 下载安装 - -使用一个特定版本: - - go get gopkg.in/ini.v1 - -使用最新版: - - go get github.com/go-ini/ini - -如需更新请添加 `-u` 选项。 - -### 测试安装 - -如果您想要在自己的机器上运行测试,请使用 `-t` 标记: - - go get -t gopkg.in/ini.v1 - -如需更新请添加 `-u` 选项。 - -## 开始使用 - -### 从数据源加载 - -一个 **数据源** 可以是 `[]byte` 类型的原始数据,或 `string` 类型的文件路径。您可以加载 **任意多个** 数据源。如果您传递其它类型的数据源,则会直接返回错误。 - -```go -cfg, err := ini.Load([]byte("raw data"), "filename") -``` - -或者从一个空白的文件开始: - -```go -cfg := ini.Empty() -``` - -当您在一开始无法决定需要加载哪些数据源时,仍可以使用 **Append()** 在需要的时候加载它们。 - -```go -err := cfg.Append("other file", []byte("other raw data")) -``` - -当您想要加载一系列文件,但是不能够确定其中哪些文件是不存在的,可以通过调用函数 `LooseLoad` 来忽略它们(`Load` 会因为文件不存在而返回错误): - -```go -cfg, err := ini.LooseLoad("filename", "filename_404") -``` - -更牛逼的是,当那些之前不存在的文件在重新调用 `Reload` 方法的时候突然出现了,那么它们会被正常加载。 - -#### 忽略键名的大小写 - -有时候分区和键的名称大小写混合非常烦人,这个时候就可以通过 `InsensitiveLoad` 将所有分区和键名在读取里强制转换为小写: - -```go -cfg, err := ini.InsensitiveLoad("filename") -//... - -// sec1 和 sec2 指向同一个分区对象 -sec1, err := cfg.GetSection("Section") -sec2, err := cfg.GetSection("SecTIOn") - -// key1 和 key2 指向同一个键对象 -key1, err := cfg.GetKey("Key") -key2, err := cfg.GetKey("KeY") -``` - -#### 类似 MySQL 配置中的布尔值键 - -MySQL 的配置文件中会出现没有具体值的布尔类型的键: - -```ini -[mysqld] -... -skip-host-cache -skip-name-resolve -``` - -默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理: - -```go -cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf")) -``` - -这些键的值永远为 `true`,且在保存到文件时也只会输出键名。 - -### 操作分区(Section) - -获取指定分区: - -```go -section, err := cfg.GetSection("section name") -``` - -如果您想要获取默认分区,则可以用空字符串代替分区名: - -```go -section, err := cfg.GetSection("") -``` - -当您非常确定某个分区是存在的,可以使用以下简便方法: - -```go -section := cfg.Section("") -``` - -如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会自动创建并返回一个对应的分区对象给您。 - -创建一个分区: - -```go -err := cfg.NewSection("new section") -``` - -获取所有分区对象或名称: - -```go -sections := cfg.Sections() -names := cfg.SectionStrings() -``` - -### 操作键(Key) - -获取某个分区下的键: - -```go -key, err := cfg.Section("").GetKey("key name") -``` - -和分区一样,您也可以直接获取键而忽略错误处理: - -```go -key := cfg.Section("").Key("key name") -``` - -判断某个键是否存在: - -```go -yes := cfg.Section("").HasKey("key name") -``` - -创建一个新的键: - -```go -err := cfg.Section("").NewKey("name", "value") -``` - -获取分区下的所有键或键名: - -```go -keys := cfg.Section("").Keys() -names := cfg.Section("").KeyStrings() -``` - -获取分区下的所有键值对的克隆: - -```go -hash := cfg.Section("").KeysHash() -``` - -### 操作键值(Value) - -获取一个类型为字符串(string)的值: - -```go -val := cfg.Section("").Key("key name").String() -``` - -获取值的同时通过自定义函数进行处理验证: - -```go -val := cfg.Section("").Key("key name").Validate(func(in string) string { - if len(in) == 0 { - return "default" - } - return in -}) -``` - -如果您不需要任何对值的自动转变功能(例如递归读取),可以直接获取原值(这种方式性能最佳): - -```go -val := cfg.Section("").Key("key name").Value() -``` - -判断某个原值是否存在: - -```go -yes := cfg.Section("").HasValue("test value") -``` - -获取其它类型的值: - -```go -// 布尔值的规则: -// true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On -// false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off -v, err = cfg.Section("").Key("BOOL").Bool() -v, err = cfg.Section("").Key("FLOAT64").Float64() -v, err = cfg.Section("").Key("INT").Int() -v, err = cfg.Section("").Key("INT64").Int64() -v, err = cfg.Section("").Key("UINT").Uint() -v, err = cfg.Section("").Key("UINT64").Uint64() -v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) -v, err = cfg.Section("").Key("TIME").Time() // RFC3339 - -v = cfg.Section("").Key("BOOL").MustBool() -v = cfg.Section("").Key("FLOAT64").MustFloat64() -v = cfg.Section("").Key("INT").MustInt() -v = cfg.Section("").Key("INT64").MustInt64() -v = cfg.Section("").Key("UINT").MustUint() -v = cfg.Section("").Key("UINT64").MustUint64() -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) -v = cfg.Section("").Key("TIME").MustTime() // RFC3339 - -// 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值, -// 当键不存在或者转换失败时,则会直接返回该默认值。 -// 但是,MustString 方法必须传递一个默认值。 - -v = cfg.Seciont("").Key("String").MustString("default") -v = cfg.Section("").Key("BOOL").MustBool(true) -v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) -v = cfg.Section("").Key("INT").MustInt(10) -v = cfg.Section("").Key("INT64").MustInt64(99) -v = cfg.Section("").Key("UINT").MustUint(3) -v = cfg.Section("").Key("UINT64").MustUint64(6) -v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) -v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 -``` - -如果我的值有好多行怎么办? - -```ini -[advance] -ADDRESS = """404 road, -NotFound, State, 5000 -Earth""" -``` - -嗯哼?小 case! - -```go -cfg.Section("advance").Key("ADDRESS").String() - -/* --- start --- -404 road, -NotFound, State, 5000 -Earth ------- end --- */ -``` - -赞爆了!那要是我属于一行的内容写不下想要写到第二行怎么办? - -```ini -[advance] -two_lines = how about \ - continuation lines? -lots_of_lines = 1 \ - 2 \ - 3 \ - 4 -``` - -简直是小菜一碟! - -```go -cfg.Section("advance").Key("two_lines").String() // how about continuation lines? -cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 -``` - -可是我有时候觉得两行连在一起特别没劲,怎么才能不自动连接两行呢? - -```go -cfg, err := ini.LoadSources(ini.LoadOptions{ - IgnoreContinuation: true, -}, "filename") -``` - -哇靠给力啊! - -需要注意的是,值两侧的单引号会被自动剔除: - -```ini -foo = "some value" // foo: some value -bar = 'some value' // bar: some value -``` - -这就是全部了?哈哈,当然不是。 - -#### 操作键值的辅助方法 - -获取键值时设定候选值: - -```go -v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) -v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) -v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) -v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) -v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) -v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) -v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) -v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 -``` - -如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。 - -验证获取的值是否在指定范围内: - -```go -vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) -vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) -vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) -vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) -vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) -vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) -vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 -``` - -##### 自动分割键值到切片(slice) - -当存在无效输入时,使用零值代替: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] -vals = cfg.Section("").Key("STRINGS").Strings(",") -vals = cfg.Section("").Key("FLOAT64S").Float64s(",") -vals = cfg.Section("").Key("INTS").Ints(",") -vals = cfg.Section("").Key("INT64S").Int64s(",") -vals = cfg.Section("").Key("UINTS").Uints(",") -vals = cfg.Section("").Key("UINT64S").Uint64s(",") -vals = cfg.Section("").Key("TIMES").Times(",") -``` - -从结果切片中剔除无效输入: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> [2.2] -vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") -vals = cfg.Section("").Key("INTS").ValidInts(",") -vals = cfg.Section("").Key("INT64S").ValidInt64s(",") -vals = cfg.Section("").Key("UINTS").ValidUints(",") -vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") -vals = cfg.Section("").Key("TIMES").ValidTimes(",") -``` - -当存在无效输入时,直接返回错误: - -```go -// Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] -// Input: how, 2.2, are, you -> error -vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") -vals = cfg.Section("").Key("INTS").StrictInts(",") -vals = cfg.Section("").Key("INT64S").StrictInt64s(",") -vals = cfg.Section("").Key("UINTS").StrictUints(",") -vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") -vals = cfg.Section("").Key("TIMES").StrictTimes(",") -``` - -### 保存配置 - -终于到了这个时刻,是时候保存一下配置了。 - -比较原始的做法是输出配置到某个文件: - -```go -// ... -err = cfg.SaveTo("my.ini") -err = cfg.SaveToIndent("my.ini", "\t") -``` - -另一个比较高级的做法是写入到任何实现 `io.Writer` 接口的对象中: - -```go -// ... -cfg.WriteTo(writer) -cfg.WriteToIndent(writer, "\t") -``` - -### 高级用法 - -#### 递归读取键值 - -在获取所有键值的过程中,特殊语法 `%()s` 会被应用,其中 `` 可以是相同分区或者默认分区下的键名。字符串 `%()s` 会被相应的键值所替代,如果指定的键不存在,则会用空字符串替代。您可以最多使用 99 层的递归嵌套。 - -```ini -NAME = ini - -[author] -NAME = Unknwon -GITHUB = https://github.com/%(NAME)s - -[package] -FULL_NAME = github.com/go-ini/%(NAME)s -``` - -```go -cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon -cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini -``` - -#### 读取父子分区 - -您可以在分区名称中使用 `.` 来表示两个或多个分区之间的父子关系。如果某个键在子分区中不存在,则会去它的父分区中再次寻找,直到没有父分区为止。 - -```ini -NAME = ini -VERSION = v1 -IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s - -[package] -CLONE_URL = https://%(IMPORT_PATH)s - -[package.sub] -``` - -```go -cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 -``` - -#### 获取上级父分区下的所有键名 - -```go -cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] -``` - -#### 读取自增键名 - -如果数据源中的键名为 `-`,则认为该键使用了自增键名的特殊语法。计数器从 1 开始,并且分区之间是相互独立的。 - -```ini -[features] --: Support read/write comments of keys and sections --: Support auto-increment of key names --: Support load multiple files to overwrite key values -``` - -```go -cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} -``` - -### 映射到结构 - -想要使用更加面向对象的方式玩转 INI 吗?好主意。 - -```ini -Name = Unknwon -age = 21 -Male = true -Born = 1993-01-01T20:17:05Z - -[Note] -Content = Hi is a good man! -Cities = HangZhou, Boston -``` - -```go -type Note struct { - Content string - Cities []string -} - -type Person struct { - Name string - Age int `ini:"age"` - Male bool - Born time.Time - Note - Created time.Time `ini:"-"` -} - -func main() { - cfg, err := ini.Load("path/to/ini") - // ... - p := new(Person) - err = cfg.MapTo(p) - // ... - - // 一切竟可以如此的简单。 - err = ini.MapTo(p, "path/to/ini") - // ... - - // 嗯哼?只需要映射一个分区吗? - n := new(Note) - err = cfg.Section("Note").MapTo(n) - // ... -} -``` - -结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。 - -```go -// ... -p := &Person{ - Name: "Joe", -} -// ... -``` - -这样玩 INI 真的好酷啊!然而,如果不能还给我原来的配置文件,有什么卵用? - -### 从结构反射 - -可是,我有说不能吗? - -```go -type Embeded struct { - Dates []time.Time `delim:"|"` - Places []string `ini:"places,omitempty"` - None []int `ini:",omitempty"` -} - -type Author struct { - Name string `ini:"NAME"` - Male bool - Age int - GPA float64 - NeverMind string `ini:"-"` - *Embeded -} - -func main() { - a := &Author{"Unknwon", true, 21, 2.8, "", - &Embeded{ - []time.Time{time.Now(), time.Now()}, - []string{"HangZhou", "Boston"}, - []int{}, - }} - cfg := ini.Empty() - err = ini.ReflectFrom(cfg, a) - // ... -} -``` - -瞧瞧,奇迹发生了。 - -```ini -NAME = Unknwon -Male = true -Age = 21 -GPA = 2.8 - -[Embeded] -Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 -places = HangZhou,Boston -``` - -#### 名称映射器(Name Mapper) - -为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。 - -目前有 2 款内置的映射器: - -- `AllCapsUnderscore`:该映射器将字段名转换至格式 `ALL_CAPS_UNDERSCORE` 后再去匹配分区名和键名。 -- `TitleUnderscore`:该映射器将字段名转换至格式 `title_underscore` 后再去匹配分区名和键名。 - -使用方法: - -```go -type Info struct{ - PackageName string -} - -func main() { - err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) - // ... - - cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) - // ... - info := new(Info) - cfg.NameMapper = ini.AllCapsUnderscore - err = cfg.MapTo(info) - // ... -} -``` - -使用函数 `ini.ReflectFromWithMapper` 时也可应用相同的规则。 - -#### 值映射器(Value Mapper) - -值映射器允许使用一个自定义函数自动展开值的具体内容,例如:运行时获取环境变量: - -```go -type Env struct { - Foo string `ini:"foo"` -} - -func main() { - cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") - cfg.ValueMapper = os.ExpandEnv - // ... - env := &Env{} - err = cfg.Section("env").MapTo(env) -} -``` - -本例中,`env.Foo` 将会是运行时所获取到环境变量 `MY_VAR` 的值。 - -#### 映射/反射的其它说明 - -任何嵌入的结构都会被默认认作一个不同的分区,并且不会自动产生所谓的父子分区关联: - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child -} - -type Config struct { - City string - Parent -} -``` - -示例配置文件: - -```ini -City = Boston - -[Parent] -Name = Unknwon - -[Child] -Age = 21 -``` - -很好,但是,我就是要嵌入结构也在同一个分区。好吧,你爹是李刚! - -```go -type Child struct { - Age string -} - -type Parent struct { - Name string - Child `ini:"Parent"` -} - -type Config struct { - City string - Parent -} -``` - -示例配置文件: - -```ini -City = Boston - -[Parent] -Name = Unknwon -Age = 21 -``` - -## 获取帮助 - -- [API 文档](https://gowalker.org/gopkg.in/ini.v1) -- [创建工单](https://github.com/go-ini/ini/issues/new) - -## 常见问题 - -### 字段 `BlockMode` 是什么? - -默认情况下,本库会在您进行读写操作时采用锁机制来确保数据时间。但在某些情况下,您非常确定只进行读操作。此时,您可以通过设置 `cfg.BlockMode = false` 来将读操作提升大约 **50-70%** 的性能。 - -### 为什么要写另一个 INI 解析库? - -许多人都在使用我的 [goconfig](https://github.com/Unknwon/goconfig) 来完成对 INI 文件的操作,但我希望使用更加 Go 风格的代码。并且当您设置 `cfg.BlockMode = false` 时,会有大约 **10-30%** 的性能提升。 - -为了做出这些改变,我必须对 API 进行破坏,所以新开一个仓库是最安全的做法。除此之外,本库直接使用 `gopkg.in` 来进行版本化发布。(其实真相是导入路径更短了) diff --git a/vendor/github.com/go-ini/ini/file.go b/vendor/github.com/go-ini/ini/file.go new file mode 100644 index 00000000000..ce26c3b3157 --- /dev/null +++ b/vendor/github.com/go-ini/ini/file.go @@ -0,0 +1,398 @@ +// Copyright 2017 Unknwon +// +// 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 ini + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + "sync" +) + +// File represents a combination of a or more INI file(s) in memory. +type File struct { + options LoadOptions + dataSources []dataSource + + // Should make things safe, but sometimes doesn't matter. + BlockMode bool + lock sync.RWMutex + + // To keep data in order. + sectionList []string + // Actual data is stored here. + sections map[string]*Section + + NameMapper + ValueMapper +} + +// newFile initializes File object with given data sources. +func newFile(dataSources []dataSource, opts LoadOptions) *File { + return &File{ + BlockMode: true, + dataSources: dataSources, + sections: make(map[string]*Section), + sectionList: make([]string, 0, 10), + options: opts, + } +} + +// Empty returns an empty file object. +func Empty() *File { + // Ignore error here, we sure our data is good. + f, _ := Load([]byte("")) + return f +} + +// NewSection creates a new section. +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 { + name = strings.ToLower(name) + } + + if f.BlockMode { + f.lock.Lock() + defer f.lock.Unlock() + } + + if inSlice(name, f.sectionList) { + return f.sections[name], nil + } + + f.sectionList = append(f.sectionList, name) + f.sections[name] = newSection(f, name) + return f.sections[name], nil +} + +// NewRawSection creates a new section with an unparseable body. +func (f *File) NewRawSection(name, body string) (*Section, error) { + section, err := f.NewSection(name) + if err != nil { + return nil, err + } + + section.isRawSection = true + section.rawBody = body + return section, nil +} + +// NewSections creates a list of sections. +func (f *File) NewSections(names ...string) (err error) { + for _, name := range names { + if _, err = f.NewSection(name); err != nil { + return err + } + } + return nil +} + +// GetSection returns section by given name. +func (f *File) GetSection(name string) (*Section, error) { + if len(name) == 0 { + name = DEFAULT_SECTION + } + if f.options.Insensitive { + name = strings.ToLower(name) + } + + if f.BlockMode { + f.lock.RLock() + defer f.lock.RUnlock() + } + + sec := f.sections[name] + if sec == nil { + return nil, fmt.Errorf("section '%s' does not exist", name) + } + return sec, nil +} + +// Section assumes named section exists and returns a zero-value when not. +func (f *File) Section(name string) *Section { + sec, err := f.GetSection(name) + if err != nil { + // Note: It's OK here because the only possible error is empty section name, + // but if it's empty, this piece of code won't be executed. + sec, _ = f.NewSection(name) + return sec + } + return sec +} + +// Section returns list of Section. +func (f *File) Sections() []*Section { + sections := make([]*Section, len(f.sectionList)) + for i := range f.sectionList { + sections[i] = f.Section(f.sectionList[i]) + } + return sections +} + +// ChildSections returns a list of child sections of given section name. +func (f *File) ChildSections(name string) []*Section { + return f.Section(name).ChildSections() +} + +// SectionStrings returns list of section names. +func (f *File) SectionStrings() []string { + list := make([]string, len(f.sectionList)) + copy(list, f.sectionList) + return list +} + +// DeleteSection deletes a section. +func (f *File) DeleteSection(name string) { + if f.BlockMode { + f.lock.Lock() + defer f.lock.Unlock() + } + + if len(name) == 0 { + name = DEFAULT_SECTION + } + + for i, s := range f.sectionList { + if s == name { + f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) + delete(f.sections, name) + return + } + } +} + +func (f *File) reload(s dataSource) error { + r, err := s.ReadCloser() + if err != nil { + return err + } + defer r.Close() + + return f.parse(r) +} + +// Reload reloads and parses all data sources. +func (f *File) Reload() (err error) { + for _, s := range f.dataSources { + if err = f.reload(s); err != nil { + // In loose mode, we create an empty default section for nonexistent files. + if os.IsNotExist(err) && f.options.Loose { + f.parse(bytes.NewBuffer(nil)) + continue + } + return err + } + } + return nil +} + +// Append appends one or more data sources and reloads automatically. +func (f *File) Append(source interface{}, others ...interface{}) error { + ds, err := parseDataSource(source) + if err != nil { + return err + } + f.dataSources = append(f.dataSources, ds) + for _, s := range others { + ds, err = parseDataSource(s) + if err != nil { + return err + } + f.dataSources = append(f.dataSources, ds) + } + return f.Reload() +} + +func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { + equalSign := "=" + if PrettyFormat { + equalSign = " = " + } + + // Use buffer to make sure target is safe until finish encoding. + buf := bytes.NewBuffer(nil) + for i, sname := range f.sectionList { + sec := f.Section(sname) + if len(sec.Comment) > 0 { + if sec.Comment[0] != '#' && sec.Comment[0] != ';' { + sec.Comment = "; " + sec.Comment + } else { + sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:]) + } + if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil { + return nil, err + } + } + + if i > 0 || DefaultHeader { + if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil { + return nil, err + } + } else { + // Write nothing if default section is empty + if len(sec.keyList) == 0 { + continue + } + } + + if sec.isRawSection { + if _, err := buf.WriteString(sec.rawBody); err != nil { + return nil, err + } + + if PrettySection { + // Put a line between sections + if _, err := buf.WriteString(LineBreak); err != nil { + return nil, err + } + } + continue + } + + // Count and generate alignment length and buffer spaces using the + // longest key. Keys may be modifed if they contain certain characters so + // we need to take that into account in our calculation. + alignLength := 0 + if PrettyFormat { + for _, kname := range sec.keyList { + keyLength := len(kname) + // First case will surround key by ` and second by """ + if strings.ContainsAny(kname, "\"=:") { + keyLength += 2 + } else if strings.Contains(kname, "`") { + keyLength += 6 + } + + if keyLength > alignLength { + alignLength = keyLength + } + } + } + alignSpaces := bytes.Repeat([]byte(" "), alignLength) + + KEY_LIST: + for _, kname := range sec.keyList { + key := sec.Key(kname) + if len(key.Comment) > 0 { + if len(indent) > 0 && sname != DEFAULT_SECTION { + buf.WriteString(indent) + } + if key.Comment[0] != '#' && key.Comment[0] != ';' { + key.Comment = "; " + key.Comment + } else { + key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:]) + } + if _, err := buf.WriteString(key.Comment + LineBreak); err != nil { + return nil, err + } + } + + if len(indent) > 0 && sname != DEFAULT_SECTION { + buf.WriteString(indent) + } + + switch { + case key.isAutoIncrement: + kname = "-" + case strings.ContainsAny(kname, "\"=:"): + kname = "`" + kname + "`" + case strings.Contains(kname, "`"): + kname = `"""` + kname + `"""` + } + + for _, val := range key.ValueWithShadows() { + if _, err := buf.WriteString(kname); err != nil { + return nil, err + } + + if key.isBooleanType { + if kname != sec.keyList[len(sec.keyList)-1] { + buf.WriteString(LineBreak) + } + continue KEY_LIST + } + + // Write out alignment spaces before "=" sign + if PrettyFormat { + buf.Write(alignSpaces[:alignLength-len(kname)]) + } + + // In case key value contains "\n", "`", "\"", "#" or ";" + if strings.ContainsAny(val, "\n`") { + val = `"""` + val + `"""` + } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") { + val = "`" + val + "`" + } + if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil { + return nil, err + } + } + + for _, val := range key.nestedValues { + if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { + return nil, err + } + } + } + + if PrettySection { + // Put a line between sections + if _, err := buf.WriteString(LineBreak); err != nil { + return nil, err + } + } + } + + return buf, nil +} + +// WriteToIndent writes content into io.Writer with given indention. +// If PrettyFormat has been set to be true, +// it will align "=" sign with spaces under each section. +func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) { + buf, err := f.writeToBuffer(indent) + if err != nil { + return 0, err + } + return buf.WriteTo(w) +} + +// WriteTo writes file content into io.Writer. +func (f *File) WriteTo(w io.Writer) (int64, error) { + return f.WriteToIndent(w, "") +} + +// SaveToIndent writes content to file system with given value indention. +func (f *File) SaveToIndent(filename, indent string) error { + // Note: Because we are truncating with os.Create, + // so it's safer to save to a temporary file location and rename afte done. + buf, err := f.writeToBuffer(indent) + if err != nil { + return err + } + + return ioutil.WriteFile(filename, buf.Bytes(), 0666) +} + +// SaveTo writes content to file system. +func (f *File) SaveTo(filename string) error { + return f.SaveToIndent(filename, "") +} diff --git a/vendor/github.com/go-ini/ini/ini.go b/vendor/github.com/go-ini/ini/ini.go index cd065e7822b..535d3588a78 100644 --- a/vendor/github.com/go-ini/ini/ini.go +++ b/vendor/github.com/go-ini/ini/ini.go @@ -17,16 +17,12 @@ package ini import ( "bytes" - "errors" "fmt" "io" + "io/ioutil" "os" "regexp" "runtime" - "strconv" - "strings" - "sync" - "time" ) const ( @@ -36,7 +32,7 @@ const ( // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 - _VERSION = "1.21.1" + _VERSION = "1.32.0" ) // Version returns current package version literal. @@ -59,6 +55,9 @@ var ( // Explicitly write DEFAULT section header DefaultHeader = false + + // Indicate whether to put a line between sections + PrettySection = true ) func init() { @@ -90,57 +89,22 @@ func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { return os.Open(s.name) } -type bytesReadCloser struct { - reader io.Reader -} - -func (rc *bytesReadCloser) Read(p []byte) (n int, err error) { - return rc.reader.Read(p) -} - -func (rc *bytesReadCloser) Close() error { - return nil -} - // sourceData represents an object that contains content in memory. type sourceData struct { data []byte } func (s *sourceData) ReadCloser() (io.ReadCloser, error) { - return &bytesReadCloser{bytes.NewReader(s.data)}, nil + return ioutil.NopCloser(bytes.NewReader(s.data)), nil } -// File represents a combination of a or more INI file(s) in memory. -type File struct { - // Should make things safe, but sometimes doesn't matter. - BlockMode bool - // Make sure data is safe in multiple goroutines. - lock sync.RWMutex - - // Allow combination of multiple data sources. - dataSources []dataSource - // Actual data is stored here. - sections map[string]*Section - - // To keep data in order. - sectionList []string - - options LoadOptions - - NameMapper - ValueMapper +// sourceReadCloser represents an input stream with Close method. +type sourceReadCloser struct { + reader io.ReadCloser } -// newFile initializes File object with given data sources. -func newFile(dataSources []dataSource, opts LoadOptions) *File { - return &File{ - BlockMode: true, - dataSources: dataSources, - sections: make(map[string]*Section), - sectionList: make([]string, 0, 10), - options: opts, - } +func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { + return s.reader, nil } func parseDataSource(source interface{}) (dataSource, error) { @@ -149,6 +113,8 @@ func parseDataSource(source interface{}) (dataSource, error) { return sourceFile{s}, nil case []byte: return &sourceData{s}, nil + case io.ReadCloser: + return &sourceReadCloser{s}, nil default: return nil, fmt.Errorf("error parsing data source: unknown type '%s'", s) } @@ -161,9 +127,26 @@ type LoadOptions struct { Insensitive bool // IgnoreContinuation indicates whether to ignore continuation lines while parsing. IgnoreContinuation bool + // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. + IgnoreInlineComment bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool + // AllowShadows indicates whether to keep track of keys with same name under same section. + AllowShadows bool + // AllowNestedValues indicates whether to allow AWS-like nested values. + // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values + AllowNestedValues bool + // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format + // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" + UnescapeValueDoubleQuotes bool + // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format + // when value is NOT surrounded by any quotes. + // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. + UnescapeValueCommentSymbols bool + // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise + // conform to key/value pairs. Specify the names of those blocks here. + UnparseableSections []string } func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { @@ -204,298 +187,8 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } -// Empty returns an empty file object. -func Empty() *File { - // Ignore error here, we sure our data is good. - f, _ := Load([]byte("")) - return f -} - -// NewSection creates a new section. -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 { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() - } - - if inSlice(name, f.sectionList) { - return f.sections[name], nil - } - - f.sectionList = append(f.sectionList, name) - f.sections[name] = newSection(f, name) - return f.sections[name], nil -} - -// NewSections creates a list of sections. -func (f *File) NewSections(names ...string) (err error) { - for _, name := range names { - if _, err = f.NewSection(name); err != nil { - return err - } - } - return nil -} - -// GetSection returns section by given name. -func (f *File) GetSection(name string) (*Section, error) { - if len(name) == 0 { - name = DEFAULT_SECTION - } else if f.options.Insensitive { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.RLock() - defer f.lock.RUnlock() - } - - sec := f.sections[name] - if sec == nil { - return nil, fmt.Errorf("section '%s' does not exist", name) - } - return sec, nil -} - -// Section assumes named section exists and returns a zero-value when not. -func (f *File) Section(name string) *Section { - sec, err := f.GetSection(name) - if err != nil { - // Note: It's OK here because the only possible error is empty section name, - // but if it's empty, this piece of code won't be executed. - sec, _ = f.NewSection(name) - return sec - } - return sec -} - -// Section returns list of Section. -func (f *File) Sections() []*Section { - sections := make([]*Section, len(f.sectionList)) - for i := range f.sectionList { - sections[i] = f.Section(f.sectionList[i]) - } - return sections -} - -// SectionStrings returns list of section names. -func (f *File) SectionStrings() []string { - list := make([]string, len(f.sectionList)) - copy(list, f.sectionList) - return list -} - -// DeleteSection deletes a section. -func (f *File) DeleteSection(name string) { - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() - } - - if len(name) == 0 { - name = DEFAULT_SECTION - } - - for i, s := range f.sectionList { - if s == name { - f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) - delete(f.sections, name) - return - } - } -} - -func (f *File) reload(s dataSource) error { - r, err := s.ReadCloser() - if err != nil { - return err - } - defer r.Close() - - return f.parse(r) -} - -// Reload reloads and parses all data sources. -func (f *File) Reload() (err error) { - for _, s := range f.dataSources { - if err = f.reload(s); err != nil { - // In loose mode, we create an empty default section for nonexistent files. - if os.IsNotExist(err) && f.options.Loose { - f.parse(bytes.NewBuffer(nil)) - continue - } - return err - } - } - return nil -} - -// Append appends one or more data sources and reloads automatically. -func (f *File) Append(source interface{}, others ...interface{}) error { - ds, err := parseDataSource(source) - if err != nil { - return err - } - f.dataSources = append(f.dataSources, ds) - for _, s := range others { - ds, err = parseDataSource(s) - if err != nil { - return err - } - f.dataSources = append(f.dataSources, ds) - } - return f.Reload() -} - -// WriteToIndent writes content into io.Writer with given indention. -// If PrettyFormat has been set to be true, -// it will align "=" sign with spaces under each section. -func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { - equalSign := "=" - if PrettyFormat { - equalSign = " = " - } - - // Use buffer to make sure target is safe until finish encoding. - buf := bytes.NewBuffer(nil) - for i, sname := range f.sectionList { - sec := f.Section(sname) - if len(sec.Comment) > 0 { - if sec.Comment[0] != '#' && sec.Comment[0] != ';' { - sec.Comment = "; " + sec.Comment - } - if _, err = buf.WriteString(sec.Comment + LineBreak); err != nil { - return 0, err - } - } - - if i > 0 || DefaultHeader { - if _, err = buf.WriteString("[" + sname + "]" + LineBreak); err != nil { - return 0, err - } - } else { - // Write nothing if default section is empty - if len(sec.keyList) == 0 { - continue - } - } - - // Count and generate alignment length and buffer spaces using the - // longest key. Keys may be modifed if they contain certain characters so - // we need to take that into account in our calculation. - alignLength := 0 - if PrettyFormat { - for _, kname := range sec.keyList { - keyLength := len(kname) - // First case will surround key by ` and second by """ - if strings.ContainsAny(kname, "\"=:") { - keyLength += 2 - } else if strings.Contains(kname, "`") { - keyLength += 6 - } - - if keyLength > alignLength { - alignLength = keyLength - } - } - } - alignSpaces := bytes.Repeat([]byte(" "), alignLength) - - for _, kname := range sec.keyList { - key := sec.Key(kname) - if len(key.Comment) > 0 { - if len(indent) > 0 && sname != DEFAULT_SECTION { - buf.WriteString(indent) - } - if key.Comment[0] != '#' && key.Comment[0] != ';' { - key.Comment = "; " + key.Comment - } - if _, err = buf.WriteString(key.Comment + LineBreak); err != nil { - return 0, err - } - } - - if len(indent) > 0 && sname != DEFAULT_SECTION { - buf.WriteString(indent) - } - - switch { - case key.isAutoIncrement: - kname = "-" - case strings.ContainsAny(kname, "\"=:"): - kname = "`" + kname + "`" - case strings.Contains(kname, "`"): - kname = `"""` + kname + `"""` - } - if _, err = buf.WriteString(kname); err != nil { - return 0, err - } - - if key.isBooleanType { - continue - } - - // Write out alignment spaces before "=" sign - if PrettyFormat { - buf.Write(alignSpaces[:alignLength-len(kname)]) - } - - val := key.value - // In case key value contains "\n", "`", "\"", "#" or ";" - if strings.ContainsAny(val, "\n`") { - val = `"""` + val + `"""` - } else if strings.ContainsAny(val, "#;") { - val = "`" + val + "`" - } - if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil { - return 0, err - } - } - - // Put a line between sections - if _, err = buf.WriteString(LineBreak); err != nil { - return 0, err - } - } - - return buf.WriteTo(w) -} - -// WriteTo writes file content into io.Writer. -func (f *File) WriteTo(w io.Writer) (int64, error) { - return f.WriteToIndent(w, "") -} - -// SaveToIndent writes content to file system with given value indention. -func (f *File) SaveToIndent(filename, indent string) error { - // Note: Because we are truncating with os.Create, - // so it's safer to save to a temporary file location and rename afte done. - tmpPath := filename + "." + strconv.Itoa(time.Now().Nanosecond()) + ".tmp" - defer os.Remove(tmpPath) - - fw, err := os.Create(tmpPath) - if err != nil { - return err - } - - if _, err = f.WriteToIndent(fw, indent); err != nil { - fw.Close() - return err - } - fw.Close() - - // Remove old file and rename the new one. - os.Remove(filename) - return os.Rename(tmpPath, filename) -} - -// SaveTo writes content to file system. -func (f *File) SaveTo(filename string) error { - return f.SaveToIndent(filename, "") +// InsensitiveLoad has exactly same functionality as Load function +// except it allows have shadow keys. +func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{AllowShadows: true}, source, others...) } diff --git a/vendor/github.com/go-ini/ini/key.go b/vendor/github.com/go-ini/ini/key.go index 9738c55a21b..7c8566a1b4c 100644 --- a/vendor/github.com/go-ini/ini/key.go +++ b/vendor/github.com/go-ini/ini/key.go @@ -15,6 +15,8 @@ package ini import ( + "bytes" + "errors" "fmt" "strconv" "strings" @@ -24,12 +26,62 @@ import ( // Key represents a key under a section. type Key struct { s *Section + Comment string name string value string isAutoIncrement bool isBooleanType bool - Comment string + isShadow bool + shadows []*Key + + nestedValues []string +} + +// newKey simply return a key object with given values. +func newKey(s *Section, name, val string) *Key { + return &Key{ + s: s, + name: name, + value: val, + } +} + +func (k *Key) addShadow(val string) error { + if k.isShadow { + return errors.New("cannot add shadow to another shadow key") + } else if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add shadow to auto-increment or boolean key") + } + + shadow := newKey(k.s, k.name, val) + shadow.isShadow = true + k.shadows = append(k.shadows, shadow) + return nil +} + +// AddShadow adds a new shadow key to itself. +func (k *Key) AddShadow(val string) error { + if !k.s.f.options.AllowShadows { + return errors.New("shadow key is not allowed") + } + return k.addShadow(val) +} + +func (k *Key) addNestedValue(val string) error { + if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add nested value to auto-increment or boolean key") + } + + k.nestedValues = append(k.nestedValues, val) + return nil +} + +func (k *Key) AddNestedValue(val string) error { + if !k.s.f.options.AllowNestedValues { + return errors.New("nested value is not allowed") + } + return k.addNestedValue(val) } // ValueMapper represents a mapping function for values, e.g. os.ExpandEnv @@ -45,16 +97,35 @@ func (k *Key) Value() string { return k.value } -// String returns string representation of value. -func (k *Key) String() string { - val := k.value +// ValueWithShadows returns raw values of key and its shadows if any. +func (k *Key) ValueWithShadows() []string { + if len(k.shadows) == 0 { + return []string{k.value} + } + vals := make([]string, len(k.shadows)+1) + vals[0] = k.value + for i := range k.shadows { + vals[i+1] = k.shadows[i].value + } + return vals +} + +// NestedValues returns nested values stored in the key. +// It is possible returned value is nil if no nested values stored in the key. +func (k *Key) NestedValues() []string { + return k.nestedValues +} + +// transformValue takes a raw value and transforms to its final string. +func (k *Key) transformValue(val string) string { if k.s.f.ValueMapper != nil { val = k.s.f.ValueMapper(val) } - if strings.Index(val, "%") == -1 { + + // Fail-fast if no indicate char found for recursive value + if !strings.Contains(val, "%") { return val } - for i := 0; i < _DEPTH_VALUES; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { @@ -67,7 +138,7 @@ func (k *Key) String() string { // Search in the same section. nk, err := k.s.GetKey(noption) - if err != nil { + if err != nil || k == nk { // Search again in default section. nk, _ = k.s.f.Section("").GetKey(noption) } @@ -78,6 +149,11 @@ func (k *Key) String() string { return val } +// String returns string representation of value. +func (k *Key) String() string { + return k.transformValue(k.value) +} + // Validate accepts a validate function which can // return modifed result as key value. func (k *Key) Validate(fn func(string) string) string { @@ -392,47 +468,95 @@ func (k *Key) Strings(delim string) []string { return []string{} } - vals := strings.Split(str, delim) - for i := range vals { - vals[i] = strings.TrimSpace(vals[i]) + runes := []rune(str) + vals := make([]string, 0, 2) + var buf bytes.Buffer + escape := false + idx := 0 + for { + if escape { + escape = false + if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) { + buf.WriteRune('\\') + } + buf.WriteRune(runes[idx]) + } else { + if runes[idx] == '\\' { + escape = true + } else if strings.HasPrefix(string(runes[idx:]), delim) { + idx += len(delim) - 1 + vals = append(vals, strings.TrimSpace(buf.String())) + buf.Reset() + } else { + buf.WriteRune(runes[idx]) + } + } + idx += 1 + if idx == len(runes) { + break + } } + + if buf.Len() > 0 { + vals = append(vals, strings.TrimSpace(buf.String())) + } + return vals } +// StringsWithShadows returns list of string divided by given delimiter. +// Shadows will also be appended if any. +func (k *Key) StringsWithShadows(delim string) []string { + vals := k.ValueWithShadows() + results := make([]string, 0, len(vals)*2) + for i := range vals { + if len(vals) == 0 { + continue + } + + results = append(results, strings.Split(vals[i], delim)...) + } + + for i := range results { + results[i] = k.transformValue(strings.TrimSpace(results[i])) + } + return results +} + // Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Float64s(delim string) []float64 { - vals, _ := k.getFloat64s(delim, true, false) + vals, _ := k.parseFloat64s(k.Strings(delim), true, false) return vals } // Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Ints(delim string) []int { - vals, _ := k.getInts(delim, true, false) + vals, _ := k.parseInts(k.Strings(delim), true, false) return vals } // Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Int64s(delim string) []int64 { - vals, _ := k.getInt64s(delim, true, false) + vals, _ := k.parseInt64s(k.Strings(delim), true, false) return vals } // Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uints(delim string) []uint { - vals, _ := k.getUints(delim, true, false) + vals, _ := k.parseUints(k.Strings(delim), true, false) return vals } // Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uint64s(delim string) []uint64 { - vals, _ := k.getUint64s(delim, true, false) + vals, _ := k.parseUint64s(k.Strings(delim), true, false) return vals } // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) TimesFormat(format, delim string) []time.Time { - vals, _ := k.getTimesFormat(format, delim, true, false) + vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) return vals } @@ -445,41 +569,41 @@ func (k *Key) Times(delim string) []time.Time { // ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then // it will not be included to result list. func (k *Key) ValidFloat64s(delim string) []float64 { - vals, _ := k.getFloat64s(delim, false, false) + vals, _ := k.parseFloat64s(k.Strings(delim), false, false) return vals } // ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will // not be included to result list. func (k *Key) ValidInts(delim string) []int { - vals, _ := k.getInts(delim, false, false) + vals, _ := k.parseInts(k.Strings(delim), false, false) return vals } // ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, // then it will not be included to result list. func (k *Key) ValidInt64s(delim string) []int64 { - vals, _ := k.getInt64s(delim, false, false) + vals, _ := k.parseInt64s(k.Strings(delim), false, false) return vals } // ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, // then it will not be included to result list. func (k *Key) ValidUints(delim string) []uint { - vals, _ := k.getUints(delim, false, false) + vals, _ := k.parseUints(k.Strings(delim), false, false) return vals } // ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned // integer, then it will not be included to result list. func (k *Key) ValidUint64s(delim string) []uint64 { - vals, _ := k.getUint64s(delim, false, false) + vals, _ := k.parseUint64s(k.Strings(delim), false, false) return vals } // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimesFormat(format, delim string) []time.Time { - vals, _ := k.getTimesFormat(format, delim, false, false) + vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) return vals } @@ -490,33 +614,33 @@ func (k *Key) ValidTimes(delim string) []time.Time { // StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. func (k *Key) StrictFloat64s(delim string) ([]float64, error) { - return k.getFloat64s(delim, false, true) + return k.parseFloat64s(k.Strings(delim), false, true) } // StrictInts returns list of int divided by given delimiter or error on first invalid input. func (k *Key) StrictInts(delim string) ([]int, error) { - return k.getInts(delim, false, true) + return k.parseInts(k.Strings(delim), false, true) } // StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. func (k *Key) StrictInt64s(delim string) ([]int64, error) { - return k.getInt64s(delim, false, true) + return k.parseInt64s(k.Strings(delim), false, true) } // StrictUints returns list of uint divided by given delimiter or error on first invalid input. func (k *Key) StrictUints(delim string) ([]uint, error) { - return k.getUints(delim, false, true) + return k.parseUints(k.Strings(delim), false, true) } // StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. func (k *Key) StrictUint64s(delim string) ([]uint64, error) { - return k.getUint64s(delim, false, true) + return k.parseUint64s(k.Strings(delim), false, true) } // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { - return k.getTimesFormat(format, delim, false, true) + return k.parseTimesFormat(format, k.Strings(delim), false, true) } // StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter @@ -525,9 +649,8 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) { return k.StrictTimesFormat(time.RFC3339, delim) } -// getFloat64s returns list of float64 divided by given delimiter. -func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]float64, error) { - strs := k.Strings(delim) +// parseFloat64s transforms strings to float64s. +func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { vals := make([]float64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseFloat(str, 64) @@ -541,9 +664,8 @@ func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]flo return vals, nil } -// getInts returns list of int divided by given delimiter. -func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, error) { - strs := k.Strings(delim) +// parseInts transforms strings to ints. +func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { vals := make([]int, 0, len(strs)) for _, str := range strs { val, err := strconv.Atoi(str) @@ -557,9 +679,8 @@ func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, er return vals, nil } -// getInt64s returns list of int64 divided by given delimiter. -func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64, error) { - strs := k.Strings(delim) +// parseInt64s transforms strings to int64s. +func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { vals := make([]int64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseInt(str, 10, 64) @@ -573,9 +694,8 @@ func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64 return vals, nil } -// getUints returns list of uint divided by given delimiter. -func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, error) { - strs := k.Strings(delim) +// parseUints transforms strings to uints. +func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { vals := make([]uint, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 0) @@ -589,9 +709,8 @@ func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, return vals, nil } -// getUint64s returns list of uint64 divided by given delimiter. -func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint64, error) { - strs := k.Strings(delim) +// parseUint64s transforms strings to uint64s. +func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { vals := make([]uint64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 64) @@ -605,9 +724,8 @@ func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint return vals, nil } -// getTimesFormat parses with given format and returns list of time.Time divided by given delimiter. -func (k *Key) getTimesFormat(format, delim string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { - strs := k.Strings(delim) +// parseTimesFormat transforms strings to times in given format. +func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { vals := make([]time.Time, 0, len(strs)) for _, str := range strs { val, err := time.Parse(format, str) diff --git a/vendor/github.com/go-ini/ini/parser.go b/vendor/github.com/go-ini/ini/parser.go index dc6df87a6c3..db3af8f0044 100644 --- a/vendor/github.com/go-ini/ini/parser.go +++ b/vendor/github.com/go-ini/ini/parser.go @@ -48,16 +48,31 @@ func newParser(r io.Reader) *parser { } } -// BOM handles header of BOM-UTF8 format. +// BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format. // http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding func (p *parser) BOM() error { - mask, err := p.buf.Peek(3) + mask, err := p.buf.Peek(2) if err != nil && err != io.EOF { return err - } else if len(mask) < 3 { + } else if len(mask) < 2 { return nil - } else if mask[0] == 239 && mask[1] == 187 && mask[2] == 191 { + } + + switch { + case mask[0] == 254 && mask[1] == 255: + fallthrough + case mask[0] == 255 && mask[1] == 254: p.buf.Read(mask) + case mask[0] == 239 && mask[1] == 187: + mask, err := p.buf.Peek(3) + if err != nil && err != io.EOF { + return err + } else if len(mask) < 3 { + return nil + } + if mask[2] == 191 { + p.buf.Read(mask) + } } return nil } @@ -174,11 +189,13 @@ func (p *parser) readContinuationLines(val string) (string, error) { // are quotes \" or \'. // It returns false if any other parts also contain same kind of quotes. func hasSurroundedQuote(in string, quote byte) bool { - return len(in) > 2 && in[0] == quote && in[len(in)-1] == quote && + return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote && strings.IndexByte(in[1:], quote) == len(in)-2 } -func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { +func (p *parser) readValue(in []byte, + ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols bool) (string, error) { + line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { return "", nil @@ -189,6 +206,8 @@ func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { valQuote = `"""` } else if line[0] == '`' { valQuote = "`" + } else if unescapeValueDoubleQuotes && line[0] == '"' { + valQuote = `"` } if len(valQuote) > 0 { @@ -199,27 +218,40 @@ func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { return p.readMultilines(line, line[startIdx:], valQuote) } + if unescapeValueDoubleQuotes && valQuote == `"` { + return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil + } return line[startIdx : pos+startIdx], nil } - // Won't be able to reach here if value only contains whitespace. + // Won't be able to reach here if value only contains whitespace line = strings.TrimSpace(line) - // Check continuation lines when desired. + // Check continuation lines when desired if !ignoreContinuation && line[len(line)-1] == '\\' { return p.readContinuationLines(line[:len(line)-1]) } - i := strings.IndexAny(line, "#;") - if i > -1 { - p.comment.WriteString(line[i:]) - line = strings.TrimSpace(line[:i]) + // Check if ignore inline comment + if !ignoreInlineComment { + i := strings.IndexAny(line, "#;") + if i > -1 { + p.comment.WriteString(line[i:]) + line = strings.TrimSpace(line[:i]) + } } - // Trim single quotes + // Trim single and double quotes if hasSurroundedQuote(line, '\'') || hasSurroundedQuote(line, '"') { line = line[1 : len(line)-1] + } else if len(valQuote) == 0 && unescapeValueCommentSymbols { + if strings.Contains(line, `\;`) { + line = strings.Replace(line, `\;`, ";", -1) + } + if strings.Contains(line, `\#`) { + line = strings.Replace(line, `\#`, "#", -1) + } } return line, nil } @@ -232,15 +264,32 @@ func (f *File) parse(reader io.Reader) (err error) { } // Ignore error because default section name is never empty string. - section, _ := f.NewSection(DEFAULT_SECTION) + name := DEFAULT_SECTION + if f.options.Insensitive { + name = strings.ToLower(DEFAULT_SECTION) + } + section, _ := f.NewSection(name) + + // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key + var isLastValueEmpty bool + var lastRegularKey *Key var line []byte + var inUnparseableSection bool for !p.isEOF { line, err = p.readUntil('\n') if err != nil { return err } + if f.options.AllowNestedValues && + isLastValueEmpty && len(line) > 0 { + if line[0] == ' ' || line[0] == '\t' { + lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) + continue + } + } + line = bytes.TrimLeftFunc(line, unicode.IsSpace) if len(line) == 0 { continue @@ -280,6 +329,21 @@ func (f *File) parse(reader io.Reader) (err error) { // Reset aotu-counter and comments p.comment.Reset() p.count = 1 + + inUnparseableSection = false + for i := range f.options.UnparseableSections { + if f.options.UnparseableSections[i] == name || + (f.options.Insensitive && strings.ToLower(f.options.UnparseableSections[i]) == strings.ToLower(name)) { + inUnparseableSection = true + continue + } + } + continue + } + + if inUnparseableSection { + section.isRawSection = true + section.rawBody += string(line) continue } @@ -287,11 +351,18 @@ func (f *File) parse(reader io.Reader) (err error) { if err != nil { // Treat as boolean key when desired, and whole line is key name. if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { - key, err := section.NewKey(string(line), "true") + kname, err := p.readValue(line, + f.options.IgnoreContinuation, + f.options.IgnoreInlineComment, + f.options.UnescapeValueDoubleQuotes, + f.options.UnescapeValueCommentSymbols) + if err != nil { + return err + } + key, err := section.NewBooleanKey(kname) if err != nil { return err } - key.isBooleanType = true key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() continue @@ -307,19 +378,24 @@ func (f *File) parse(reader io.Reader) (err error) { p.count++ } - key, err := section.NewKey(kname, "") + value, err := p.readValue(line[offset:], + f.options.IgnoreContinuation, + f.options.IgnoreInlineComment, + f.options.UnescapeValueDoubleQuotes, + f.options.UnescapeValueCommentSymbols) + if err != nil { + return err + } + isLastValueEmpty = len(value) == 0 + + key, err := section.NewKey(kname, value) if err != nil { return err } key.isAutoIncrement = isAutoIncr - - value, err := p.readValue(line[offset:], f.options.IgnoreContinuation) - if err != nil { - return err - } - key.SetValue(value) key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() + lastRegularKey = key } return nil } diff --git a/vendor/github.com/go-ini/ini/section.go b/vendor/github.com/go-ini/ini/section.go index bbb73caf8cc..d8a40261920 100644 --- a/vendor/github.com/go-ini/ini/section.go +++ b/vendor/github.com/go-ini/ini/section.go @@ -28,10 +28,19 @@ type Section struct { keys map[string]*Key keyList []string keysHash map[string]string + + isRawSection bool + rawBody string } func newSection(f *File, name string) *Section { - return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string)} + return &Section{ + f: f, + name: name, + keys: make(map[string]*Key), + keyList: make([]string, 0, 10), + keysHash: make(map[string]string), + } } // Name returns name of Section. @@ -39,6 +48,20 @@ func (s *Section) Name() string { return s.name } +// Body returns rawBody of Section if the section was marked as unparseable. +// It still follows the other rules of the INI format surrounding leading/trailing whitespace. +func (s *Section) Body() string { + return strings.TrimSpace(s.rawBody) +} + +// SetBody updates body content only if section is raw. +func (s *Section) SetBody(body string) { + if !s.isRawSection { + return + } + s.rawBody = body +} + // NewKey creates a new key to given section. func (s *Section) NewKey(name, val string) (*Key, error) { if len(name) == 0 { @@ -53,20 +76,33 @@ func (s *Section) NewKey(name, val string) (*Key, error) { } if inSlice(name, s.keyList) { - s.keys[name].value = val + if s.f.options.AllowShadows { + if err := s.keys[name].addShadow(val); err != nil { + return nil, err + } + } else { + s.keys[name].value = val + } return s.keys[name], nil } s.keyList = append(s.keyList, name) - s.keys[name] = &Key{ - s: s, - name: name, - value: val, - } + s.keys[name] = newKey(s, name, val) s.keysHash[name] = val return s.keys[name], nil } +// NewBooleanKey creates a new boolean type key to given section. +func (s *Section) NewBooleanKey(name string) (*Key, error) { + key, err := s.NewKey(name, "true") + if err != nil { + return nil, err + } + + key.isBooleanType = true + return key, nil +} + // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { // FIXME: change to section level lock? @@ -108,6 +144,7 @@ func (s *Section) HasKey(name string) bool { } // Haskey is a backwards-compatible name for HasKey. +// TODO: delete me in v2 func (s *Section) Haskey(name string) bool { return s.HasKey(name) } @@ -204,3 +241,17 @@ func (s *Section) DeleteKey(name string) { } } } + +// ChildSections returns a list of child sections of current section. +// For example, "[parent.child1]" and "[parent.child12]" are child sections +// of section "[parent]". +func (s *Section) ChildSections() []*Section { + prefix := s.name + "." + children := make([]*Section, 0, 3) + for _, name := range s.f.sectionList { + if strings.HasPrefix(name, prefix) { + children = append(children, s.f.sections[name]) + } + } + return children +} diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go index d00fb4b8373..9719dc6985a 100644 --- a/vendor/github.com/go-ini/ini/struct.go +++ b/vendor/github.com/go-ini/ini/struct.go @@ -78,34 +78,44 @@ func parseDelim(actual string) string { var reflectTime = reflect.TypeOf(time.Now()).Kind() // setSliceWithProperType sets proper values to slice based on its type. -func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { - strs := key.Strings(delim) +func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { + var strs []string + if allowShadow { + strs = key.StringsWithShadows(delim) + } else { + strs = key.Strings(delim) + } + numVals := len(strs) if numVals == 0 { return nil } var vals interface{} + var err error sliceOf := field.Type().Elem().Kind() switch sliceOf { case reflect.String: vals = strs case reflect.Int: - vals = key.Ints(delim) + vals, err = key.parseInts(strs, true, false) case reflect.Int64: - vals = key.Int64s(delim) + vals, err = key.parseInt64s(strs, true, false) case reflect.Uint: - vals = key.Uints(delim) + vals, err = key.parseUints(strs, true, false) case reflect.Uint64: - vals = key.Uint64s(delim) + vals, err = key.parseUint64s(strs, true, false) case reflect.Float64: - vals = key.Float64s(delim) + vals, err = key.parseFloat64s(strs, true, false) case reflectTime: - vals = key.Times(delim) + vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } + if err != nil && isStrict { + return err + } slice := reflect.MakeSlice(field.Type(), numVals, numVals) for i := 0; i < numVals; i++ { @@ -130,10 +140,17 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { return nil } +func wrapStrictError(err error, isStrict bool) error { + if isStrict { + return err + } + return nil +} + // 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. -func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { +func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { switch t.Kind() { case reflect.String: if len(key.String()) == 0 { @@ -143,20 +160,20 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri case reflect.Bool: boolVal, err := key.Bool() if err != nil { - return nil + return wrapStrictError(err, isStrict) } field.SetBool(boolVal) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: durationVal, err := key.Duration() // Skip zero value - if err == nil && int(durationVal) > 0 { + if err == nil && int64(durationVal) > 0 { field.Set(reflect.ValueOf(durationVal)) return nil } intVal, err := key.Int64() - if err != nil || intVal == 0 { - return nil + if err != nil { + return wrapStrictError(err, isStrict) } field.SetInt(intVal) // byte is an alias for uint8, so supporting uint8 breaks support for byte @@ -170,31 +187,43 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri uintVal, err := key.Uint64() if err != nil { - return nil + return wrapStrictError(err, isStrict) } field.SetUint(uintVal) - case reflect.Float64: + case reflect.Float32, reflect.Float64: floatVal, err := key.Float64() if err != nil { - return nil + return wrapStrictError(err, isStrict) } field.SetFloat(floatVal) case reflectTime: timeVal, err := key.Time() if err != nil { - return nil + return wrapStrictError(err, isStrict) } field.Set(reflect.ValueOf(timeVal)) case reflect.Slice: - return setSliceWithProperType(key, field, delim) + return setSliceWithProperType(key, field, delim, allowShadow, isStrict) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } -func (s *Section) mapTo(val reflect.Value) error { +func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { + opts := strings.SplitN(tag, ",", 3) + rawName = opts[0] + if len(opts) > 1 { + omitEmpty = opts[1] == "omitempty" + } + if len(opts) > 2 { + allowShadow = opts[2] == "allowshadow" + } + return rawName, omitEmpty, allowShadow +} + +func (s *Section) mapTo(val reflect.Value, isStrict bool) error { if val.Kind() == reflect.Ptr { val = val.Elem() } @@ -209,8 +238,8 @@ func (s *Section) mapTo(val reflect.Value) error { continue } - opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty - fieldName := s.parseFieldName(tpField.Name, opts[0]) + rawName, _, allowShadow := parseTagOptions(tag) + fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue } @@ -223,7 +252,7 @@ func (s *Section) mapTo(val reflect.Value) error { if isAnonymous || isStruct { if sec, err := s.f.GetSection(fieldName); err == nil { - if err = sec.mapTo(field); err != nil { + if err = sec.mapTo(field, isStrict); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } continue @@ -231,7 +260,8 @@ func (s *Section) mapTo(val reflect.Value) error { } if key, err := s.GetKey(fieldName); err == nil { - if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { + delim := parseDelim(tpField.Tag.Get("delim")) + if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } } @@ -250,7 +280,22 @@ func (s *Section) MapTo(v interface{}) error { return errors.New("cannot map to non-pointer struct") } - return s.mapTo(val) + return s.mapTo(val, false) +} + +// MapTo 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) + val := reflect.ValueOf(v) + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + val = val.Elem() + } else { + return errors.New("cannot map to non-pointer struct") + } + + return s.mapTo(val, true) } // MapTo maps file to given struct. @@ -258,6 +303,12 @@ func (f *File) MapTo(v interface{}) error { return f.Section("").MapTo(v) } +// MapTo 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. func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { cfg, err := Load(source, others...) @@ -268,11 +319,28 @@ func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, other return cfg.MapTo(v) } +// StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode, +// which returns all possible error including value parsing error. +func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { + cfg, err := Load(source, others...) + if err != nil { + return err + } + cfg.NameMapper = mapper + return cfg.StrictMapTo(v) +} + // MapTo maps data sources to given struct. func MapTo(v, source interface{}, others ...interface{}) error { return MapToWithMapper(v, nil, source, others...) } +// StrictMapTo maps data sources to given struct in strict mode, +// which returns all possible error including value parsing error. +func StrictMapTo(v, source interface{}, others ...interface{}) error { + return StrictMapToWithMapper(v, nil, source, others...) +} + // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { slice := field.Slice(0, field.Len()) @@ -340,10 +408,11 @@ func isEmptyValue(v reflect.Value) bool { return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 - case reflectTime: - return v.Interface().(time.Time).IsZero() case reflect.Interface, reflect.Ptr: return v.IsNil() + case reflectTime: + t, ok := v.Interface().(time.Time) + return ok && t.IsZero() } return false } @@ -381,6 +450,12 @@ func (s *Section) reflectFrom(val reflect.Value) error { // Note: fieldName can never be empty here, ignore error. sec, _ = s.f.NewSection(fieldName) } + + // Add comment from comment tag + if len(sec.Comment) == 0 { + sec.Comment = tpField.Tag.Get("comment") + } + if err = sec.reflectFrom(field); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } @@ -392,6 +467,12 @@ func (s *Section) reflectFrom(val reflect.Value) error { if err != nil { key, _ = s.NewKey(fieldName, "") } + + // Add comment from comment tag + if len(key.Comment) == 0 { + key.Comment = tpField.Tag.Get("comment") + } + if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } diff --git a/vendor/github.com/go-ldap/ldap/.gitignore b/vendor/github.com/go-ldap/ldap/.gitignore deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vendor/github.com/go-ldap/ldap/.travis.yml b/vendor/github.com/go-ldap/ldap/.travis.yml deleted file mode 100644 index 3a5402596d0..00000000000 --- a/vendor/github.com/go-ldap/ldap/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go -go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - tip -go_import_path: gopkg.in/ldap.v2 -install: - - go get gopkg.in/asn1-ber.v1 - - go get gopkg.in/ldap.v2 - - go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover - - go build -v ./... -script: - - go test -v -cover ./... diff --git a/vendor/github.com/go-ldap/ldap/LICENSE b/vendor/github.com/go-ldap/ldap/LICENSE index 74487567632..6c0ed4b3872 100644 --- a/vendor/github.com/go-ldap/ldap/LICENSE +++ b/vendor/github.com/go-ldap/ldap/LICENSE @@ -1,27 +1,22 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. +The MIT License (MIT) -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com) +Portions copyright (c) 2015-2016 go-ldap Authors - * 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. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -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. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/go-ldap/ldap/README.md b/vendor/github.com/go-ldap/ldap/README.md deleted file mode 100644 index f49b4d6a1b3..00000000000 --- a/vendor/github.com/go-ldap/ldap/README.md +++ /dev/null @@ -1,55 +0,0 @@ -[![GoDoc](https://godoc.org/gopkg.in/ldap.v2?status.svg)](https://godoc.org/gopkg.in/ldap.v2) -[![Build Status](https://travis-ci.org/go-ldap/ldap.svg)](https://travis-ci.org/go-ldap/ldap) - -# Basic LDAP v3 functionality for the GO programming language. - -## Install - -For the latest version use: - - go get gopkg.in/ldap.v2 - -Import the latest version with: - - import "gopkg.in/ldap.v2" - - -## Required Libraries: - - - gopkg.in/asn1-ber.v1 - -## Working: - - - Connecting to LDAP server - - Binding to LDAP server - - Searching for entries - - Compiling string filters to LDAP filters - - Paging Search Results - - Modify Requests / Responses - - Add Requests / Responses - - Delete Requests / Responses - - Better Unicode support - -## Examples: - - - search - - modify - -## Tests Implemented: - - - Filter Compile / Decompile - -## TODO: - - - [x] Add Requests / Responses - - [x] Delete Requests / Responses - - [x] Modify DN Requests / Responses - - [ ] Compare Requests / Responses - - [ ] Implement Tests / Benchmarks - - - ---- -The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) -The design is licensed under the Creative Commons 3.0 Attributions license. -Read this article for more details: http://blog.golang.org/gopher diff --git a/vendor/github.com/go-ldap/ldap/add.go b/vendor/github.com/go-ldap/ldap/add.go index 643ce5ffe4c..0e5f6cdba11 100644 --- a/vendor/github.com/go-ldap/ldap/add.go +++ b/vendor/github.com/go-ldap/ldap/add.go @@ -16,71 +16,80 @@ import ( "gopkg.in/asn1-ber.v1" ) +// Attribute represents an LDAP attribute type Attribute struct { - attrType string - attrVals []string + // Type is the name of the LDAP attribute + Type string + // Vals are the LDAP attribute values + Vals []string } func (a *Attribute) encode() *ber.Packet { seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attribute") - seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.attrType, "Type")) + seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.Type, "Type")) set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") - for _, value := range a.attrVals { + for _, value := range a.Vals { set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) } seq.AppendChild(set) return seq } +// AddRequest represents an LDAP AddRequest operation type AddRequest struct { - dn string - attributes []Attribute + // DN identifies the entry being added + DN string + // Attributes list the attributes of the new entry + Attributes []Attribute } func (a AddRequest) encode() *ber.Packet { request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request") - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.dn, "DN")) + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.DN, "DN")) attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") - for _, attribute := range a.attributes { + for _, attribute := range a.Attributes { attributes.AppendChild(attribute.encode()) } request.AppendChild(attributes) return request } +// Attribute adds an attribute with the given type and values func (a *AddRequest) Attribute(attrType string, attrVals []string) { - a.attributes = append(a.attributes, Attribute{attrType: attrType, attrVals: attrVals}) + a.Attributes = append(a.Attributes, Attribute{Type: attrType, Vals: attrVals}) } +// NewAddRequest returns an AddRequest for the given DN, with no attributes func NewAddRequest(dn string) *AddRequest { return &AddRequest{ - dn: dn, + DN: dn, } } +// Add performs the given AddRequest func (l *Conn) Add(addRequest *AddRequest) error { - messageID := l.nextMessageID() packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) packet.AppendChild(addRequest.encode()) l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return err } - if channel == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) - if packet == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err } if l.Debug { @@ -99,6 +108,6 @@ func (l *Conn) Add(addRequest *AddRequest) error { log.Printf("Unexpected Response: %d", packet.Children[1].Tag) } - l.Debug.Printf("%d: returning", messageID) + l.Debug.Printf("%d: returning", msgCtx.id) return nil } diff --git a/vendor/github.com/go-ldap/ldap/atomic_value.go b/vendor/github.com/go-ldap/ldap/atomic_value.go new file mode 100644 index 00000000000..bccf7573e0e --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/atomic_value.go @@ -0,0 +1,13 @@ +// +build go1.4 + +package ldap + +import ( + "sync/atomic" +) + +// For compilers that support it, we just use the underlying sync/atomic.Value +// type. +type atomicValue struct { + atomic.Value +} diff --git a/vendor/github.com/go-ldap/ldap/atomic_value_go13.go b/vendor/github.com/go-ldap/ldap/atomic_value_go13.go new file mode 100644 index 00000000000..04920bb2600 --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/atomic_value_go13.go @@ -0,0 +1,28 @@ +// +build !go1.4 + +package ldap + +import ( + "sync" +) + +// This is a helper type that emulates the use of the "sync/atomic.Value" +// struct that's available in Go 1.4 and up. +type atomicValue struct { + value interface{} + lock sync.RWMutex +} + +func (av *atomicValue) Store(val interface{}) { + av.lock.Lock() + av.value = val + av.lock.Unlock() +} + +func (av *atomicValue) Load() interface{} { + av.lock.RLock() + ret := av.value + av.lock.RUnlock() + + return ret +} diff --git a/vendor/github.com/go-ldap/ldap/bind.go b/vendor/github.com/go-ldap/ldap/bind.go index 4ad4b896c26..26b3cc7270d 100644 --- a/vendor/github.com/go-ldap/ldap/bind.go +++ b/vendor/github.com/go-ldap/ldap/bind.go @@ -10,16 +10,22 @@ import ( "gopkg.in/asn1-ber.v1" ) +// SimpleBindRequest represents a username/password bind operation type SimpleBindRequest struct { + // Username is the name of the Directory object that the client wishes to bind as Username string + // Password is the credentials to bind with Password string + // Controls are optional controls to send with the bind request Controls []Control } +// SimpleBindResult contains the response from the server type SimpleBindResult struct { Controls []Control } +// NewSimpleBindRequest returns a bind request func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest { return &SimpleBindRequest{ Username: username, @@ -39,11 +45,10 @@ func (bindRequest *SimpleBindRequest) encode() *ber.Packet { return request } +// SimpleBind performs the simple bind operation defined in the given request func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) { - messageID := l.nextMessageID() - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) encodedBindRequest := simpleBindRequest.encode() packet.AppendChild(encodedBindRequest) @@ -51,18 +56,20 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu ber.PrintPacket(packet) } - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return nil, err } - if channel == nil { - return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - packet = <-channel - if packet == nil { - return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve response")) + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err } if l.Debug { @@ -90,11 +97,10 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu return result, nil } +// Bind performs a bind with the given username and password func (l *Conn) Bind(username, password string) error { - messageID := l.nextMessageID() - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name")) @@ -105,18 +111,20 @@ func (l *Conn) Bind(username, password string) error { ber.PrintPacket(packet) } - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return err } - if channel == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - packet = <-channel - if packet == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not retrieve response")) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err } if l.Debug { diff --git a/vendor/github.com/go-ldap/ldap/client.go b/vendor/github.com/go-ldap/ldap/client.go index d3401f9e61e..055b27b5fc4 100644 --- a/vendor/github.com/go-ldap/ldap/client.go +++ b/vendor/github.com/go-ldap/ldap/client.go @@ -1,12 +1,16 @@ package ldap -import "crypto/tls" +import ( + "crypto/tls" + "time" +) // Client knows how to interact with an LDAP server type Client interface { Start() StartTLS(config *tls.Config) error Close() + SetTimeout(time.Duration) Bind(username, password string) error SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) diff --git a/vendor/github.com/go-ldap/ldap/compare.go b/vendor/github.com/go-ldap/ldap/compare.go index 802e9cc932a..cc6d2af5e5d 100644 --- a/vendor/github.com/go-ldap/ldap/compare.go +++ b/vendor/github.com/go-ldap/ldap/compare.go @@ -33,9 +33,8 @@ import ( // Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise // false with any error that occurs if any. func (l *Conn) Compare(dn, attribute, value string) (bool, error) { - messageID := l.nextMessageID() packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, "Compare Request") request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, dn, "DN")) @@ -48,20 +47,21 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) { l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return false, err } - if channel == nil { - return false, NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) - if packet == nil { - return false, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return false, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return false, err } if l.Debug { diff --git a/vendor/github.com/go-ldap/ldap/conn.go b/vendor/github.com/go-ldap/ldap/conn.go index 2f16443f6e4..eb28eb4726a 100644 --- a/vendor/github.com/go-ldap/ldap/conn.go +++ b/vendor/github.com/go-ldap/ldap/conn.go @@ -11,23 +11,66 @@ import ( "log" "net" "sync" + "sync/atomic" "time" "gopkg.in/asn1-ber.v1" ) const ( - MessageQuit = 0 - MessageRequest = 1 + // MessageQuit causes the processMessages loop to exit + MessageQuit = 0 + // MessageRequest sends a request to the server + MessageRequest = 1 + // MessageResponse receives a response from the server MessageResponse = 2 - MessageFinish = 3 + // MessageFinish indicates the client considers a particular message ID to be finished + MessageFinish = 3 + // MessageTimeout indicates the client-specified timeout for a particular message ID has been reached + MessageTimeout = 4 ) +// PacketResponse contains the packet or error encountered reading a response +type PacketResponse struct { + // Packet is the packet read from the server + Packet *ber.Packet + // Error is an error encountered while reading + Error error +} + +// ReadPacket returns the packet or an error +func (pr *PacketResponse) ReadPacket() (*ber.Packet, error) { + if (pr == nil) || (pr.Packet == nil && pr.Error == nil) { + return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve response")) + } + return pr.Packet, pr.Error +} + +type messageContext struct { + id int64 + // close(done) should only be called from finishMessage() + done chan struct{} + // close(responses) should only be called from processMessages(), and only sent to from sendResponse() + responses chan *PacketResponse +} + +// sendResponse should only be called within the processMessages() loop which +// is also responsible for closing the responses channel. +func (msgCtx *messageContext) sendResponse(packet *PacketResponse) { + select { + case msgCtx.responses <- packet: + // Successfully sent packet to message handler. + case <-msgCtx.done: + // The request handler is done and will not receive more + // packets. + } +} + type messagePacket struct { Op int MessageID int64 Packet *ber.Packet - Channel chan *ber.Packet + Context *messageContext } type sendMessageFlags uint @@ -40,18 +83,18 @@ const ( type Conn struct { conn net.Conn isTLS bool - isClosing bool + closing uint32 + closeErr atomicValue isStartingTLS bool Debug debugging - chanConfirm chan bool - chanResults map[int64]chan *ber.Packet + chanConfirm chan struct{} + messageContexts map[int64]*messageContext chanMessage chan *messagePacket chanMessageID chan int64 - wgSender sync.WaitGroup wgClose sync.WaitGroup - once sync.Once outstandingRequests uint messageMutex sync.Mutex + requestTimeout int64 } var _ Client = &Conn{} @@ -97,27 +140,39 @@ func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { // NewConn returns a new Conn using conn for network I/O. func NewConn(conn net.Conn, isTLS bool) *Conn { return &Conn{ - conn: conn, - chanConfirm: make(chan bool), - chanMessageID: make(chan int64), - chanMessage: make(chan *messagePacket, 10), - chanResults: map[int64]chan *ber.Packet{}, - isTLS: isTLS, + conn: conn, + chanConfirm: make(chan struct{}), + chanMessageID: make(chan int64), + chanMessage: make(chan *messagePacket, 10), + messageContexts: map[int64]*messageContext{}, + requestTimeout: 0, + isTLS: isTLS, } } +// Start initializes goroutines to read responses and process messages func (l *Conn) Start() { go l.reader() go l.processMessages() l.wgClose.Add(1) } +// isClosing returns whether or not we're currently closing. +func (l *Conn) isClosing() bool { + return atomic.LoadUint32(&l.closing) == 1 +} + +// setClosing sets the closing value to true +func (l *Conn) setClosing() bool { + return atomic.CompareAndSwapUint32(&l.closing, 0, 1) +} + // Close closes the connection. func (l *Conn) Close() { - l.once.Do(func() { - l.isClosing = true - l.wgSender.Wait() + l.messageMutex.Lock() + defer l.messageMutex.Unlock() + if l.setClosing() { l.Debug.Printf("Sending quit message and waiting for confirmation") l.chanMessage <- &messagePacket{Op: MessageQuit} <-l.chanConfirm @@ -125,51 +180,59 @@ func (l *Conn) Close() { l.Debug.Printf("Closing network connection") if err := l.conn.Close(); err != nil { - log.Print(err) + log.Println(err) } l.wgClose.Done() - }) + } l.wgClose.Wait() } +// SetTimeout sets the time after a request is sent that a MessageTimeout triggers +func (l *Conn) SetTimeout(timeout time.Duration) { + if timeout > 0 { + atomic.StoreInt64(&l.requestTimeout, int64(timeout)) + } +} + // Returns the next available messageID func (l *Conn) nextMessageID() int64 { - if l.chanMessageID != nil { - if messageID, ok := <-l.chanMessageID; ok { - return messageID - } + if messageID, ok := <-l.chanMessageID; ok { + return messageID } return 0 } // StartTLS sends the command to start a TLS session and then creates a new TLS Client func (l *Conn) StartTLS(config *tls.Config) error { - messageID := l.nextMessageID() - if l.isTLS { return NewError(ErrorNetwork, errors.New("ldap: already encrypted")) } packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS") request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command")) packet.AppendChild(request) l.Debug.PrintPacket(packet) - channel, err := l.sendMessageWithFlags(packet, startTLS) + msgCtx, err := l.sendMessageWithFlags(packet, startTLS) if err != nil { return err } - if channel == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } + defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) - l.finishMessage(messageID) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err + } if l.Debug { if err := addLDAPDescriptions(packet); err != nil { @@ -197,45 +260,51 @@ func (l *Conn) StartTLS(config *tls.Config) error { return nil } -func (l *Conn) sendMessage(packet *ber.Packet) (chan *ber.Packet, error) { +func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) { return l.sendMessageWithFlags(packet, 0) } -func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (chan *ber.Packet, error) { - if l.isClosing { +func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) { + if l.isClosing() { return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed")) } l.messageMutex.Lock() l.Debug.Printf("flags&startTLS = %d", flags&startTLS) if l.isStartingTLS { l.messageMutex.Unlock() - return nil, NewError(ErrorNetwork, errors.New("ldap: connection is in startls phase.")) + return nil, NewError(ErrorNetwork, errors.New("ldap: connection is in startls phase")) } if flags&startTLS != 0 { if l.outstandingRequests != 0 { l.messageMutex.Unlock() return nil, NewError(ErrorNetwork, errors.New("ldap: cannot StartTLS with outstanding requests")) - } else { - l.isStartingTLS = true } + l.isStartingTLS = true } l.outstandingRequests++ l.messageMutex.Unlock() - out := make(chan *ber.Packet) + responses := make(chan *PacketResponse) + messageID := packet.Children[0].Value.(int64) message := &messagePacket{ Op: MessageRequest, - MessageID: packet.Children[0].Value.(int64), + MessageID: messageID, Packet: packet, - Channel: out, + Context: &messageContext{ + id: messageID, + done: make(chan struct{}), + responses: responses, + }, } l.sendProcessMessage(message) - return out, nil + return message.Context, nil } -func (l *Conn) finishMessage(messageID int64) { - if l.isClosing { +func (l *Conn) finishMessage(msgCtx *messageContext) { + close(msgCtx.done) + + if l.isClosing() { return } @@ -248,18 +317,18 @@ func (l *Conn) finishMessage(messageID int64) { message := &messagePacket{ Op: MessageFinish, - MessageID: messageID, + MessageID: msgCtx.id, } l.sendProcessMessage(message) } func (l *Conn) sendProcessMessage(message *messagePacket) bool { - if l.isClosing { + l.messageMutex.Lock() + defer l.messageMutex.Unlock() + if l.isClosing() { return false } - l.wgSender.Add(1) l.chanMessage <- message - l.wgSender.Done() return true } @@ -268,13 +337,17 @@ func (l *Conn) processMessages() { if err := recover(); err != nil { log.Printf("ldap: recovered panic in processMessages: %v", err) } - for messageID, channel := range l.chanResults { + for messageID, msgCtx := range l.messageContexts { + // If we are closing due to an error, inform anyone who + // is waiting about the error. + if l.isClosing() && l.closeErr.Load() != nil { + msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}) + } l.Debug.Printf("Closing channel for MessageID %d", messageID) - close(channel) - delete(l.chanResults, messageID) + close(msgCtx.responses) + delete(l.messageContexts, messageID) } close(l.chanMessageID) - l.chanConfirm <- true close(l.chanConfirm) }() @@ -283,40 +356,68 @@ func (l *Conn) processMessages() { select { case l.chanMessageID <- messageID: messageID++ - case messagePacket, ok := <-l.chanMessage: - if !ok { - l.Debug.Printf("Shutting down - message channel is closed") - return - } - switch messagePacket.Op { + case message := <-l.chanMessage: + switch message.Op { case MessageQuit: l.Debug.Printf("Shutting down - quit message received") return case MessageRequest: // Add to message list and write to network - l.Debug.Printf("Sending message %d", messagePacket.MessageID) - l.chanResults[messagePacket.MessageID] = messagePacket.Channel - // go routine - buf := messagePacket.Packet.Bytes() + l.Debug.Printf("Sending message %d", message.MessageID) + buf := message.Packet.Bytes() _, err := l.conn.Write(buf) if err != nil { l.Debug.Printf("Error Sending Message: %s", err.Error()) + message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}) + close(message.Context.responses) break } + + // Only add to messageContexts if we were able to + // successfully write the message. + l.messageContexts[message.MessageID] = message.Context + + // Add timeout if defined + requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout)) + if requestTimeout > 0 { + go func() { + defer func() { + if err := recover(); err != nil { + log.Printf("ldap: recovered panic in RequestTimeout: %v", err) + } + }() + time.Sleep(requestTimeout) + timeoutMessage := &messagePacket{ + Op: MessageTimeout, + MessageID: message.MessageID, + } + l.sendProcessMessage(timeoutMessage) + }() + } case MessageResponse: - l.Debug.Printf("Receiving message %d", messagePacket.MessageID) - if chanResult, ok := l.chanResults[messagePacket.MessageID]; ok { - chanResult <- messagePacket.Packet + l.Debug.Printf("Receiving message %d", message.MessageID) + if msgCtx, ok := l.messageContexts[message.MessageID]; ok { + msgCtx.sendResponse(&PacketResponse{message.Packet, nil}) } else { - log.Printf("Received unexpected message %d", messagePacket.MessageID) - ber.PrintPacket(messagePacket.Packet) + log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing()) + ber.PrintPacket(message.Packet) + } + case MessageTimeout: + // Handle the timeout by closing the channel + // All reads will return immediately + if msgCtx, ok := l.messageContexts[message.MessageID]; ok { + l.Debug.Printf("Receiving message timeout for %d", message.MessageID) + msgCtx.sendResponse(&PacketResponse{message.Packet, errors.New("ldap: connection timed out")}) + delete(l.messageContexts, message.MessageID) + close(msgCtx.responses) } case MessageFinish: - // Remove from message list - l.Debug.Printf("Finished message %d", messagePacket.MessageID) - close(l.chanResults[messagePacket.MessageID]) - delete(l.chanResults, messagePacket.MessageID) + l.Debug.Printf("Finished message %d", message.MessageID) + if msgCtx, ok := l.messageContexts[message.MessageID]; ok { + delete(l.messageContexts, message.MessageID) + close(msgCtx.responses) + } } } } @@ -341,7 +442,8 @@ func (l *Conn) reader() { packet, err := ber.ReadPacket(l.conn) if err != nil { // A read error is expected here if we are closing the connection... - if !l.isClosing { + if !l.isClosing() { + l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err)) l.Debug.Printf("reader error: %s", err.Error()) } return @@ -364,6 +466,5 @@ func (l *Conn) reader() { if !l.sendProcessMessage(message) { return } - } } diff --git a/vendor/github.com/go-ldap/ldap/control.go b/vendor/github.com/go-ldap/ldap/control.go index 4d82980933e..342f325ca61 100644 --- a/vendor/github.com/go-ldap/ldap/control.go +++ b/vendor/github.com/go-ldap/ldap/control.go @@ -12,35 +12,48 @@ import ( ) const ( - ControlTypePaging = "1.2.840.113556.1.4.319" - ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1" + // ControlTypePaging - https://www.ietf.org/rfc/rfc2696.txt + ControlTypePaging = "1.2.840.113556.1.4.319" + // ControlTypeBeheraPasswordPolicy - https://tools.ietf.org/html/draft-behera-ldap-password-policy-10 + ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1" + // ControlTypeVChuPasswordMustChange - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4" - ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5" - ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2" + // ControlTypeVChuPasswordWarning - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 + ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5" + // ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296 + ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2" ) +// ControlTypeMap maps controls to text descriptions var ControlTypeMap = map[string]string{ ControlTypePaging: "Paging", ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft", ControlTypeManageDsaIT: "Manage DSA IT", } +// Control defines an interface controls provide to encode and describe themselves type Control interface { + // GetControlType returns the OID GetControlType() string + // Encode returns the ber packet representation Encode() *ber.Packet + // String returns a human-readable description String() string } +// ControlString implements the Control interface for simple controls type ControlString struct { ControlType string Criticality bool ControlValue string } +// GetControlType returns the OID func (c *ControlString) GetControlType() string { return c.ControlType } +// Encode returns the ber packet representation func (c *ControlString) Encode() *ber.Packet { packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")")) @@ -51,26 +64,32 @@ func (c *ControlString) Encode() *ber.Packet { return packet } +// String returns a human-readable description func (c *ControlString) String() string { return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue) } +// ControlPaging implements the paging control described in https://www.ietf.org/rfc/rfc2696.txt type ControlPaging struct { + // PagingSize indicates the page size PagingSize uint32 - Cookie []byte + // Cookie is an opaque value returned by the server to track a paging cursor + Cookie []byte } +// GetControlType returns the OID func (c *ControlPaging) GetControlType() string { return ControlTypePaging } +// Encode returns the ber packet representation func (c *ControlPaging) Encode() *ber.Packet { packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")")) p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)") seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value") - seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(c.PagingSize), "Paging Size")) + seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.PagingSize), "Paging Size")) cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie") cookie.Value = c.Cookie cookie.Data.Write(c.Cookie) @@ -81,6 +100,7 @@ func (c *ControlPaging) Encode() *ber.Packet { return packet } +// String returns a human-readable description func (c *ControlPaging) String() string { return fmt.Sprintf( "Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q", @@ -91,21 +111,29 @@ func (c *ControlPaging) String() string { c.Cookie) } +// SetCookie stores the given cookie in the paging control func (c *ControlPaging) SetCookie(cookie []byte) { c.Cookie = cookie } +// ControlBeheraPasswordPolicy implements the control described in https://tools.ietf.org/html/draft-behera-ldap-password-policy-10 type ControlBeheraPasswordPolicy struct { - Expire int64 - Grace int64 - Error int8 + // Expire contains the number of seconds before a password will expire + Expire int64 + // Grace indicates the remaining number of times a user will be allowed to authenticate with an expired password + Grace int64 + // Error indicates the error code + Error int8 + // ErrorString is a human readable error ErrorString string } +// GetControlType returns the OID func (c *ControlBeheraPasswordPolicy) GetControlType() string { return ControlTypeBeheraPasswordPolicy } +// Encode returns the ber packet representation func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet { packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeBeheraPasswordPolicy, "Control Type ("+ControlTypeMap[ControlTypeBeheraPasswordPolicy]+")")) @@ -113,6 +141,7 @@ func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet { return packet } +// String returns a human-readable description func (c *ControlBeheraPasswordPolicy) String() string { return fmt.Sprintf( "Control Type: %s (%q) Criticality: %t Expire: %d Grace: %d Error: %d, ErrorString: %s", @@ -125,39 +154,49 @@ func (c *ControlBeheraPasswordPolicy) String() string { c.ErrorString) } +// ControlVChuPasswordMustChange implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 type ControlVChuPasswordMustChange struct { + // MustChange indicates if the password is required to be changed MustChange bool } +// GetControlType returns the OID func (c *ControlVChuPasswordMustChange) GetControlType() string { return ControlTypeVChuPasswordMustChange } +// Encode returns the ber packet representation func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet { return nil } +// String returns a human-readable description func (c *ControlVChuPasswordMustChange) String() string { return fmt.Sprintf( - "Control Type: %s (%q) Criticality: %t MustChange: %b", + "Control Type: %s (%q) Criticality: %t MustChange: %v", ControlTypeMap[ControlTypeVChuPasswordMustChange], ControlTypeVChuPasswordMustChange, false, c.MustChange) } +// ControlVChuPasswordWarning implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 type ControlVChuPasswordWarning struct { + // Expire indicates the time in seconds until the password expires Expire int64 } +// GetControlType returns the OID func (c *ControlVChuPasswordWarning) GetControlType() string { return ControlTypeVChuPasswordWarning } +// Encode returns the ber packet representation func (c *ControlVChuPasswordWarning) Encode() *ber.Packet { return nil } +// String returns a human-readable description func (c *ControlVChuPasswordWarning) String() string { return fmt.Sprintf( "Control Type: %s (%q) Criticality: %t Expire: %b", @@ -167,14 +206,18 @@ func (c *ControlVChuPasswordWarning) String() string { c.Expire) } +// ControlManageDsaIT implements the control described in https://tools.ietf.org/html/rfc3296 type ControlManageDsaIT struct { + // Criticality indicates if this control is required Criticality bool } +// GetControlType returns the OID func (c *ControlManageDsaIT) GetControlType() string { return ControlTypeManageDsaIT } +// Encode returns the ber packet representation func (c *ControlManageDsaIT) Encode() *ber.Packet { //FIXME packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") @@ -185,6 +228,7 @@ func (c *ControlManageDsaIT) Encode() *ber.Packet { return packet } +// String returns a human-readable description func (c *ControlManageDsaIT) String() string { return fmt.Sprintf( "Control Type: %s (%q) Criticality: %t", @@ -193,10 +237,12 @@ func (c *ControlManageDsaIT) String() string { c.Criticality) } +// NewControlManageDsaIT returns a ControlManageDsaIT control func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT { return &ControlManageDsaIT{Criticality: Criticality} } +// FindControl returns the first control of the given type in the list, or nil func FindControl(controls []Control, controlType string) Control { for _, c := range controls { if c.GetControlType() == controlType { @@ -206,20 +252,56 @@ func FindControl(controls []Control, controlType string) Control { return nil } +// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made func DecodeControl(packet *ber.Packet) Control { - ControlType := packet.Children[0].Value.(string) - Criticality := false + var ( + ControlType = "" + Criticality = false + value *ber.Packet + ) + + switch len(packet.Children) { + case 0: + // at least one child is required for control type + return nil + + case 1: + // just type, no criticality or value + packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" + ControlType = packet.Children[0].Value.(string) + + case 2: + packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" + ControlType = packet.Children[0].Value.(string) + + // Children[1] could be criticality or value (both are optional) + // duck-type on whether this is a boolean + if _, ok := packet.Children[1].Value.(bool); ok { + packet.Children[1].Description = "Criticality" + Criticality = packet.Children[1].Value.(bool) + } else { + packet.Children[1].Description = "Control Value" + value = packet.Children[1] + } + + case 3: + packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" + ControlType = packet.Children[0].Value.(string) - packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" - value := packet.Children[1] - if len(packet.Children) == 3 { - value = packet.Children[2] packet.Children[1].Description = "Criticality" Criticality = packet.Children[1].Value.(bool) + + packet.Children[2].Description = "Control Value" + value = packet.Children[2] + + default: + // more than 3 children is invalid + return nil } - value.Description = "Control Value" switch ControlType { + case ControlTypeManageDsaIT: + return NewControlManageDsaIT(Criticality) case ControlTypePaging: value.Description += " (Paging)" c := new(ControlPaging) @@ -252,18 +334,18 @@ func DecodeControl(packet *ber.Packet) Control { for _, child := range sequence.Children { if child.Tag == 0 { //Warning - child := child.Children[0] - packet := ber.DecodePacket(child.Data.Bytes()) + warningPacket := child.Children[0] + packet := ber.DecodePacket(warningPacket.Data.Bytes()) val, ok := packet.Value.(int64) if ok { - if child.Tag == 0 { + if warningPacket.Tag == 0 { //timeBeforeExpiration c.Expire = val - child.Value = c.Expire - } else if child.Tag == 1 { + warningPacket.Value = c.Expire + } else if warningPacket.Tag == 1 { //graceAuthNsRemaining c.Grace = val - child.Value = c.Grace + warningPacket.Value = c.Grace } } } else if child.Tag == 1 { @@ -294,15 +376,19 @@ func DecodeControl(packet *ber.Packet) Control { c.Expire = expire value.Value = c.Expire + return c + default: + c := new(ControlString) + c.ControlType = ControlType + c.Criticality = Criticality + if value != nil { + c.ControlValue = value.Value.(string) + } return c } - c := new(ControlString) - c.ControlType = ControlType - c.Criticality = Criticality - c.ControlValue = value.Value.(string) - return c } +// NewControlString returns a generic control func NewControlString(controlType string, criticality bool, controlValue string) *ControlString { return &ControlString{ ControlType: controlType, @@ -311,10 +397,12 @@ func NewControlString(controlType string, criticality bool, controlValue string) } } +// NewControlPaging returns a paging control func NewControlPaging(pagingSize uint32) *ControlPaging { return &ControlPaging{PagingSize: pagingSize} } +// NewControlBeheraPasswordPolicy returns a ControlBeheraPasswordPolicy func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy { return &ControlBeheraPasswordPolicy{ Expire: -1, diff --git a/vendor/github.com/go-ldap/ldap/debug.go b/vendor/github.com/go-ldap/ldap/debug.go index b8a7ecbff1f..7279fc25182 100644 --- a/vendor/github.com/go-ldap/ldap/debug.go +++ b/vendor/github.com/go-ldap/ldap/debug.go @@ -6,7 +6,7 @@ import ( "gopkg.in/asn1-ber.v1" ) -// debbuging type +// debugging type // - has a Printf method to write the debug output type debugging bool diff --git a/vendor/github.com/go-ldap/ldap/del.go b/vendor/github.com/go-ldap/ldap/del.go index 2f0eae1cd29..4fd63dc3f25 100644 --- a/vendor/github.com/go-ldap/ldap/del.go +++ b/vendor/github.com/go-ldap/ldap/del.go @@ -12,8 +12,11 @@ import ( "gopkg.in/asn1-ber.v1" ) +// DelRequest implements an LDAP deletion request type DelRequest struct { - DN string + // DN is the name of the directory entry to delete + DN string + // Controls hold optional controls to send with the request Controls []Control } @@ -23,6 +26,7 @@ func (d DelRequest) encode() *ber.Packet { return request } +// NewDelRequest creates a delete request for the given DN and controls func NewDelRequest(DN string, Controls []Control) *DelRequest { return &DelRequest{ @@ -31,10 +35,10 @@ func NewDelRequest(DN string, } } +// Del executes the given delete request func (l *Conn) Del(delRequest *DelRequest) error { - messageID := l.nextMessageID() packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) packet.AppendChild(delRequest.encode()) if delRequest.Controls != nil { packet.AppendChild(encodeControls(delRequest.Controls)) @@ -42,20 +46,21 @@ func (l *Conn) Del(delRequest *DelRequest) error { l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return err } - if channel == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) - if packet == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err } if l.Debug { @@ -74,6 +79,6 @@ func (l *Conn) Del(delRequest *DelRequest) error { log.Printf("Unexpected Response: %d", packet.Children[1].Tag) } - l.Debug.Printf("%d: returning", messageID) + l.Debug.Printf("%d: returning", msgCtx.id) return nil } diff --git a/vendor/github.com/go-ldap/ldap/dn.go b/vendor/github.com/go-ldap/ldap/dn.go index 5d83c5e9ab9..34e9023af93 100644 --- a/vendor/github.com/go-ldap/ldap/dn.go +++ b/vendor/github.com/go-ldap/ldap/dn.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // -// File contains DN parsing functionallity +// File contains DN parsing functionality // // https://tools.ietf.org/html/rfc4514 // @@ -52,22 +52,28 @@ import ( "fmt" "strings" - ber "gopkg.in/asn1-ber.v1" + "gopkg.in/asn1-ber.v1" ) +// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514 type AttributeTypeAndValue struct { - Type string + // Type is the attribute type + Type string + // Value is the attribute value Value string } +// RelativeDN represents a relativeDistinguishedName from https://tools.ietf.org/html/rfc4514 type RelativeDN struct { Attributes []*AttributeTypeAndValue } +// DN represents a distinguishedName from https://tools.ietf.org/html/rfc4514 type DN struct { RDNs []*RelativeDN } +// ParseDN returns a distinguishedName or an error func ParseDN(str string) (*DN, error) { dn := new(DN) dn.RDNs = make([]*RelativeDN, 0) @@ -77,9 +83,19 @@ func ParseDN(str string) (*DN, error) { attribute := new(AttributeTypeAndValue) escaping := false + unescapedTrailingSpaces := 0 + stringFromBuffer := func() string { + s := buffer.String() + s = s[0 : len(s)-unescapedTrailingSpaces] + buffer.Reset() + unescapedTrailingSpaces = 0 + return s + } + for i := 0; i < len(str); i++ { char := str[i] if escaping { + unescapedTrailingSpaces = 0 escaping = false switch char { case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\': @@ -94,19 +110,17 @@ func ParseDN(str string) (*DN, error) { dst := []byte{0} n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2])) if err != nil { - return nil, errors.New( - fmt.Sprintf("Failed to decode escaped character: %s", err)) + return nil, fmt.Errorf("Failed to decode escaped character: %s", err) } else if n != 1 { - return nil, errors.New( - fmt.Sprintf("Expected 1 byte when un-escaping, got %d", n)) + return nil, fmt.Errorf("Expected 1 byte when un-escaping, got %d", n) } buffer.WriteByte(dst[0]) i++ } else if char == '\\' { + unescapedTrailingSpaces = 0 escaping = true } else if char == '=' { - attribute.Type = buffer.String() - buffer.Reset() + attribute.Type = stringFromBuffer() // Special case: If the first character in the value is # the // following data is BER encoded so we can just fast forward // and decode. @@ -119,18 +133,20 @@ func ParseDN(str string) (*DN, error) { } else { data = str[i:] } - raw_ber, err := enchex.DecodeString(data) + rawBER, err := enchex.DecodeString(data) if err != nil { - return nil, errors.New( - fmt.Sprintf("Failed to decode BER encoding: %s", err)) + return nil, fmt.Errorf("Failed to decode BER encoding: %s", err) } - packet := ber.DecodePacket(raw_ber) + packet := ber.DecodePacket(rawBER) buffer.WriteString(packet.Data.String()) i += len(data) - 1 } } else if char == ',' || char == '+' { // We're done with this RDN or value, push it - attribute.Value = buffer.String() + if len(attribute.Type) == 0 { + return nil, errors.New("incomplete type, value pair") + } + attribute.Value = stringFromBuffer() rdn.Attributes = append(rdn.Attributes, attribute) attribute = new(AttributeTypeAndValue) if char == ',' { @@ -138,8 +154,17 @@ func ParseDN(str string) (*DN, error) { rdn = new(RelativeDN) rdn.Attributes = make([]*AttributeTypeAndValue, 0) } - buffer.Reset() + } else if char == ' ' && buffer.Len() == 0 { + // ignore unescaped leading spaces + continue } else { + if char == ' ' { + // Track unescaped spaces in case they are trailing and we need to remove them + unescapedTrailingSpaces++ + } else { + // Reset if we see a non-space char + unescapedTrailingSpaces = 0 + } buffer.WriteByte(char) } } @@ -147,9 +172,76 @@ func ParseDN(str string) (*DN, error) { if len(attribute.Type) == 0 { return nil, errors.New("DN ended with incomplete type, value pair") } - attribute.Value = buffer.String() + attribute.Value = stringFromBuffer() rdn.Attributes = append(rdn.Attributes, attribute) dn.RDNs = append(dn.RDNs, rdn) } return dn, nil } + +// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch). +// Returns true if they have the same number of relative distinguished names +// and corresponding relative distinguished names (by position) are the same. +func (d *DN) Equal(other *DN) bool { + if len(d.RDNs) != len(other.RDNs) { + return false + } + for i := range d.RDNs { + if !d.RDNs[i].Equal(other.RDNs[i]) { + return false + } + } + return true +} + +// AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN. +// "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com" +// "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com" +// "ou=widgets,o=acme.com" is not an ancestor of "ou=widgets,o=acme.com" +func (d *DN) AncestorOf(other *DN) bool { + if len(d.RDNs) >= len(other.RDNs) { + return false + } + // Take the last `len(d.RDNs)` RDNs from the other DN to compare against + otherRDNs := other.RDNs[len(other.RDNs)-len(d.RDNs):] + for i := range d.RDNs { + if !d.RDNs[i].Equal(otherRDNs[i]) { + return false + } + } + return true +} + +// Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch). +// Relative distinguished names are the same if and only if they have the same number of AttributeTypeAndValues +// and each attribute of the first RDN is the same as the attribute of the second RDN with the same attribute type. +// The order of attributes is not significant. +// Case of attribute types is not significant. +func (r *RelativeDN) Equal(other *RelativeDN) bool { + if len(r.Attributes) != len(other.Attributes) { + return false + } + return r.hasAllAttributes(other.Attributes) && other.hasAllAttributes(r.Attributes) +} + +func (r *RelativeDN) hasAllAttributes(attrs []*AttributeTypeAndValue) bool { + for _, attr := range attrs { + found := false + for _, myattr := range r.Attributes { + if myattr.Equal(attr) { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +// Equal returns true if the AttributeTypeAndValue is equivalent to the specified AttributeTypeAndValue +// Case of the attribute type is not significant +func (a *AttributeTypeAndValue) Equal(other *AttributeTypeAndValue) bool { + return strings.EqualFold(a.Type, other.Type) && a.Value == other.Value +} diff --git a/vendor/github.com/go-ldap/ldap/dn_test.go b/vendor/github.com/go-ldap/ldap/dn_test.go deleted file mode 100644 index 39817c42741..00000000000 --- a/vendor/github.com/go-ldap/ldap/dn_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package ldap_test - -import ( - "reflect" - "testing" - - "gopkg.in/ldap.v2" -) - -func TestSuccessfulDNParsing(t *testing.T) { - testcases := map[string]ldap.DN{ - "": ldap.DN{[]*ldap.RelativeDN{}}, - "cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": ldap.DN{[]*ldap.RelativeDN{ - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"cn", "Jim, \"Hasse Hö\" Hansson!"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "dummy"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "com"}}}}}, - "UID=jsmith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{ - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"UID", "jsmith"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}}, - "OU=Sales+CN=J. Smith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{ - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{ - &ldap.AttributeTypeAndValue{"OU", "Sales"}, - &ldap.AttributeTypeAndValue{"CN", "J. Smith"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}}, - "1.3.6.1.4.1.1466.0=#04024869": ldap.DN{[]*ldap.RelativeDN{ - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}}}}, - "1.3.6.1.4.1.1466.0=#04024869,DC=net": ldap.DN{[]*ldap.RelativeDN{ - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}}, - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}}, - "CN=Lu\\C4\\8Di\\C4\\87": ldap.DN{[]*ldap.RelativeDN{ - &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"CN", "Lučić"}}}}}, - } - - for test, answer := range testcases { - dn, err := ldap.ParseDN(test) - if err != nil { - t.Errorf(err.Error()) - continue - } - if !reflect.DeepEqual(dn, &answer) { - t.Errorf("Parsed DN %s is not equal to the expected structure", test) - for _, rdn := range dn.RDNs { - for _, attribs := range rdn.Attributes { - t.Logf("#%v\n", attribs) - } - } - } - } -} - -func TestErrorDNParsing(t *testing.T) { - testcases := map[string]string{ - "*": "DN ended with incomplete type, value pair", - "cn=Jim\\0Test": "Failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'", - "cn=Jim\\0": "Got corrupted escaped character", - "DC=example,=net": "DN ended with incomplete type, value pair", - "1=#0402486": "Failed to decode BER encoding: encoding/hex: odd length hex string", - } - - for test, answer := range testcases { - _, err := ldap.ParseDN(test) - if err == nil { - t.Errorf("Expected %s to fail parsing but succeeded\n", test) - } else if err.Error() != answer { - t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error()) - } - } -} diff --git a/vendor/github.com/go-ldap/ldap/error.go b/vendor/github.com/go-ldap/ldap/error.go index 2dbc30ac085..4cccb537fdd 100644 --- a/vendor/github.com/go-ldap/ldap/error.go +++ b/vendor/github.com/go-ldap/ldap/error.go @@ -56,6 +56,7 @@ const ( ErrorUnexpectedResponse = 205 ) +// LDAPResultCodeMap contains string descriptions for LDAP error codes var LDAPResultCodeMap = map[uint8]string{ LDAPResultSuccess: "Success", LDAPResultOperationsError: "Operations Error", @@ -96,11 +97,23 @@ var LDAPResultCodeMap = map[uint8]string{ LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited", LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs", LDAPResultOther: "Other", + + ErrorNetwork: "Network Error", + ErrorFilterCompile: "Filter Compile Error", + ErrorFilterDecompile: "Filter Decompile Error", + ErrorDebugging: "Debugging Error", + ErrorUnexpectedMessage: "Unexpected Message", + ErrorUnexpectedResponse: "Unexpected Response", } func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) { - if len(packet.Children) >= 2 { + if packet == nil { + return ErrorUnexpectedResponse, "Empty packet" + } else if len(packet.Children) >= 2 { response := packet.Children[1] + if response == nil { + return ErrorUnexpectedResponse, "Empty response in packet" + } if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 { // Children[1].Children[2] is the diagnosticMessage which is guaranteed to exist as seen here: https://tools.ietf.org/html/rfc4511#section-4.1.9 return uint8(response.Children[0].Value.(int64)), response.Children[2].Value.(string) @@ -110,8 +123,11 @@ func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) { return ErrorNetwork, "Invalid packet format" } +// Error holds LDAP error information type Error struct { - Err error + // Err is the underlying error + Err error + // ResultCode is the LDAP error code ResultCode uint8 } @@ -119,10 +135,12 @@ func (e *Error) Error() string { return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error()) } +// NewError creates an LDAP error with the given code and underlying error func NewError(resultCode uint8, err error) error { return &Error{ResultCode: resultCode, Err: err} } +// IsErrorWithCode returns true if the given error is an LDAP error with the given result code func IsErrorWithCode(err error, desiredResultCode uint8) bool { if err == nil { return false diff --git a/vendor/github.com/go-ldap/ldap/example_test.go b/vendor/github.com/go-ldap/ldap/example_test.go deleted file mode 100644 index b018a966489..00000000000 --- a/vendor/github.com/go-ldap/ldap/example_test.go +++ /dev/null @@ -1,305 +0,0 @@ -package ldap_test - -import ( - "crypto/tls" - "fmt" - "log" - - "gopkg.in/ldap.v2" -) - -// ExampleConn_Bind demonstrates how to bind a connection to an ldap user -// allowing access to restricted attrabutes that user has access to -func ExampleConn_Bind() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password") - if err != nil { - log.Fatal(err) - } -} - -// ExampleConn_Search demonstrates how to use the search interface -func ExampleConn_Search() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - searchRequest := ldap.NewSearchRequest( - "dc=example,dc=com", // The base dn to search - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - "(&(objectClass=organizationalPerson))", // The filter to apply - []string{"dn", "cn"}, // A list attributes to retrieve - nil, - ) - - sr, err := l.Search(searchRequest) - if err != nil { - log.Fatal(err) - } - - for _, entry := range sr.Entries { - fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn")) - } -} - -// ExampleStartTLS demonstrates how to start a TLS connection -func ExampleConn_StartTLS() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - // Reconnect with TLS - err = l.StartTLS(&tls.Config{InsecureSkipVerify: true}) - if err != nil { - log.Fatal(err) - } - - // Opertations via l are now encrypted -} - -// ExampleConn_Compare demonstrates how to comapre an attribute with a value -func ExampleConn_Compare() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - matched, err := l.Compare("cn=user,dc=example,dc=com", "uid", "someuserid") - if err != nil { - log.Fatal(err) - } - - fmt.Println(matched) -} - -func ExampleConn_PasswordModify_admin() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - err = l.Bind("cn=admin,dc=example,dc=com", "password") - if err != nil { - log.Fatal(err) - } - - passwordModifyRequest := ldap.NewPasswordModifyRequest("cn=user,dc=example,dc=com", "", "NewPassword") - _, err = l.PasswordModify(passwordModifyRequest) - - if err != nil { - log.Fatalf("Password could not be changed: %s", err.Error()) - } -} - -func ExampleConn_PasswordModify_generatedPassword() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - err = l.Bind("cn=user,dc=example,dc=com", "password") - if err != nil { - log.Fatal(err) - } - - passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "") - passwordModifyResponse, err := l.PasswordModify(passwordModifyRequest) - if err != nil { - log.Fatalf("Password could not be changed: %s", err.Error()) - } - - generatedPassword := passwordModifyResponse.GeneratedPassword - log.Printf("Generated password: %s\n", generatedPassword) -} - -func ExampleConn_PasswordModify_setNewPassword() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - err = l.Bind("cn=user,dc=example,dc=com", "password") - if err != nil { - log.Fatal(err) - } - - passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "NewPassword") - _, err = l.PasswordModify(passwordModifyRequest) - - if err != nil { - log.Fatalf("Password could not be changed: %s", err.Error()) - } -} - -func ExampleConn_Modify() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - // Add a description, and replace the mail attributes - modify := ldap.NewModifyRequest("cn=user,dc=example,dc=com") - modify.Add("description", []string{"An example user"}) - modify.Replace("mail", []string{"user@example.org"}) - - err = l.Modify(modify) - if err != nil { - log.Fatal(err) - } -} - -// Example User Authentication shows how a typical application can verify a login attempt -func Example_userAuthentication() { - // The username and password we want to check - username := "someuser" - password := "userpassword" - - bindusername := "readonly" - bindpassword := "password" - - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - // Reconnect with TLS - err = l.StartTLS(&tls.Config{InsecureSkipVerify: true}) - if err != nil { - log.Fatal(err) - } - - // First bind with a read only user - err = l.Bind(bindusername, bindpassword) - if err != nil { - log.Fatal(err) - } - - // Search for the given username - searchRequest := ldap.NewSearchRequest( - "dc=example,dc=com", - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectClass=organizationalPerson)&(uid=%s))", username), - []string{"dn"}, - nil, - ) - - sr, err := l.Search(searchRequest) - if err != nil { - log.Fatal(err) - } - - if len(sr.Entries) != 1 { - log.Fatal("User does not exist or too many entries returned") - } - - userdn := sr.Entries[0].DN - - // Bind as the user to verify their password - err = l.Bind(userdn, password) - if err != nil { - log.Fatal(err) - } - - // Rebind as the read only user for any futher queries - err = l.Bind(bindusername, bindpassword) - if err != nil { - log.Fatal(err) - } -} - -func Example_beherappolicy() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - - controls := []ldap.Control{} - controls = append(controls, ldap.NewControlBeheraPasswordPolicy()) - bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", controls) - - r, err := l.SimpleBind(bindRequest) - ppolicyControl := ldap.FindControl(r.Controls, ldap.ControlTypeBeheraPasswordPolicy) - - var ppolicy *ldap.ControlBeheraPasswordPolicy - if ppolicyControl != nil { - ppolicy = ppolicyControl.(*ldap.ControlBeheraPasswordPolicy) - } else { - log.Printf("ppolicyControl response not avaliable.\n") - } - if err != nil { - errStr := "ERROR: Cannot bind: " + err.Error() - if ppolicy != nil && ppolicy.Error >= 0 { - errStr += ":" + ppolicy.ErrorString - } - log.Print(errStr) - } else { - logStr := "Login Ok" - if ppolicy != nil { - if ppolicy.Expire >= 0 { - logStr += fmt.Sprintf(". Password expires in %d seconds\n", ppolicy.Expire) - } else if ppolicy.Grace >= 0 { - logStr += fmt.Sprintf(". Password expired, %d grace logins remain\n", ppolicy.Grace) - } - } - log.Print(logStr) - } -} - -func Example_vchuppolicy() { - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) - if err != nil { - log.Fatal(err) - } - defer l.Close() - l.Debug = true - - bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", nil) - - r, err := l.SimpleBind(bindRequest) - - passwordMustChangeControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordMustChange) - var passwordMustChange *ldap.ControlVChuPasswordMustChange - if passwordMustChangeControl != nil { - passwordMustChange = passwordMustChangeControl.(*ldap.ControlVChuPasswordMustChange) - } - - if passwordMustChange != nil && passwordMustChange.MustChange { - log.Printf("Password Must be changed.\n") - } - - passwordWarningControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordWarning) - - var passwordWarning *ldap.ControlVChuPasswordWarning - if passwordWarningControl != nil { - passwordWarning = passwordWarningControl.(*ldap.ControlVChuPasswordWarning) - } else { - log.Printf("ppolicyControl response not available.\n") - } - if err != nil { - log.Print("ERROR: Cannot bind: " + err.Error()) - } else { - logStr := "Login Ok" - if passwordWarning != nil { - if passwordWarning.Expire >= 0 { - logStr += fmt.Sprintf(". Password expires in %d seconds\n", passwordWarning.Expire) - } - } - log.Print(logStr) - } -} diff --git a/vendor/github.com/go-ldap/ldap/filter.go b/vendor/github.com/go-ldap/ldap/filter.go index 63bcec1e3ae..3858a2865c0 100644 --- a/vendor/github.com/go-ldap/ldap/filter.go +++ b/vendor/github.com/go-ldap/ldap/filter.go @@ -15,6 +15,7 @@ import ( "gopkg.in/asn1-ber.v1" ) +// Filter choices const ( FilterAnd = 0 FilterOr = 1 @@ -28,6 +29,7 @@ const ( FilterExtensibleMatch = 9 ) +// FilterMap contains human readable descriptions of Filter choices var FilterMap = map[uint64]string{ FilterAnd: "And", FilterOr: "Or", @@ -41,18 +43,21 @@ var FilterMap = map[uint64]string{ FilterExtensibleMatch: "Extensible Match", } +// SubstringFilter options const ( FilterSubstringsInitial = 0 FilterSubstringsAny = 1 FilterSubstringsFinal = 2 ) +// FilterSubstringsMap contains human readable descriptions of SubstringFilter choices var FilterSubstringsMap = map[uint64]string{ FilterSubstringsInitial: "Substrings Initial", FilterSubstringsAny: "Substrings Any", FilterSubstringsFinal: "Substrings Final", } +// MatchingRuleAssertion choices const ( MatchingRuleAssertionMatchingRule = 1 MatchingRuleAssertionType = 2 @@ -60,6 +65,7 @@ const ( MatchingRuleAssertionDNAttributes = 4 ) +// MatchingRuleAssertionMap contains human readable descriptions of MatchingRuleAssertion choices var MatchingRuleAssertionMap = map[uint64]string{ MatchingRuleAssertionMatchingRule: "Matching Rule Assertion Matching Rule", MatchingRuleAssertionType: "Matching Rule Assertion Type", @@ -67,6 +73,7 @@ var MatchingRuleAssertionMap = map[uint64]string{ MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes", } +// CompileFilter converts a string representation of a filter into a BER-encoded packet func CompileFilter(filter string) (*ber.Packet, error) { if len(filter) == 0 || filter[0] != '(' { return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('")) @@ -75,12 +82,16 @@ func CompileFilter(filter string) (*ber.Packet, error) { if err != nil { return nil, err } - if pos != len(filter) { + switch { + case pos > len(filter): + return nil, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) + case pos < len(filter): return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:]))) } return packet, nil } +// DecompileFilter converts a packet representation of a filter into a string representation func DecompileFilter(packet *ber.Packet) (ret string, err error) { defer func() { if r := recover(); r != nil { @@ -239,11 +250,13 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { packet.AppendChild(child) return packet, newPos, err default: - READING_ATTR := 0 - READING_EXTENSIBLE_MATCHING_RULE := 1 - READING_CONDITION := 2 + const ( + stateReadingAttr = 0 + stateReadingExtensibleMatchingRule = 1 + stateReadingCondition = 2 + ) - state := READING_ATTR + state := stateReadingAttr attribute := "" extensibleDNAttributes := false @@ -261,56 +274,56 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { } switch state { - case READING_ATTR: + case stateReadingAttr: switch { // Extensible rule, with only DN-matching case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:="): packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) extensibleDNAttributes = true - state = READING_CONDITION + state = stateReadingCondition newPos += 5 // Extensible rule, with DN-matching and a matching OID case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:"): packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) extensibleDNAttributes = true - state = READING_EXTENSIBLE_MATCHING_RULE + state = stateReadingExtensibleMatchingRule newPos += 4 // Extensible rule, with attr only case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="): packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) - state = READING_CONDITION + state = stateReadingCondition newPos += 2 // Extensible rule, with no DN attribute matching case currentRune == ':': packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) - state = READING_EXTENSIBLE_MATCHING_RULE - newPos += 1 + state = stateReadingExtensibleMatchingRule + newPos++ // Equality condition case currentRune == '=': packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch]) - state = READING_CONDITION - newPos += 1 + state = stateReadingCondition + newPos++ // Greater-than or equal case currentRune == '>' && strings.HasPrefix(remainingFilter, ">="): packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual]) - state = READING_CONDITION + state = stateReadingCondition newPos += 2 // Less-than or equal case currentRune == '<' && strings.HasPrefix(remainingFilter, "<="): packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual]) - state = READING_CONDITION + state = stateReadingCondition newPos += 2 // Approx case currentRune == '~' && strings.HasPrefix(remainingFilter, "~="): packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterApproxMatch]) - state = READING_CONDITION + state = stateReadingCondition newPos += 2 // Still reading the attribute name @@ -319,12 +332,12 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { newPos += currentWidth } - case READING_EXTENSIBLE_MATCHING_RULE: + case stateReadingExtensibleMatchingRule: switch { // Matching rule OID is done case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="): - state = READING_CONDITION + state = stateReadingCondition newPos += 2 // Still reading the matching rule oid @@ -333,7 +346,7 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { newPos += currentWidth } - case READING_CONDITION: + case stateReadingCondition: // append to the condition condition += fmt.Sprintf("%c", currentRune) newPos += currentWidth @@ -369,9 +382,9 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { } // Add the value (only required child) - encodedString, err := escapedStringToEncodedBytes(condition) - if err != nil { - return packet, newPos, err + encodedString, encodeErr := escapedStringToEncodedBytes(condition) + if encodeErr != nil { + return packet, newPos, encodeErr } packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchValue, encodedString, MatchingRuleAssertionMap[MatchingRuleAssertionMatchValue])) @@ -401,17 +414,17 @@ func compileFilter(filter string, pos int) (*ber.Packet, int, error) { default: tag = FilterSubstringsAny } - encodedString, err := escapedStringToEncodedBytes(part) - if err != nil { - return packet, newPos, err + encodedString, encodeErr := escapedStringToEncodedBytes(part) + if encodeErr != nil { + return packet, newPos, encodeErr } seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, tag, encodedString, FilterSubstringsMap[uint64(tag)])) } packet.AppendChild(seq) default: - encodedString, err := escapedStringToEncodedBytes(condition) - if err != nil { - return packet, newPos, err + encodedString, encodeErr := escapedStringToEncodedBytes(condition) + if encodeErr != nil { + return packet, newPos, encodeErr } packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, encodedString, "Condition")) @@ -440,12 +453,12 @@ func escapedStringToEncodedBytes(escapedString string) (string, error) { if i+2 > len(escapedString) { return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter")) } - if escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3]); decodeErr != nil { + escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3]) + if decodeErr != nil { return "", NewError(ErrorFilterCompile, errors.New("ldap: invalid characters for escape in filter")) - } else { - buffer.WriteByte(escByte[0]) - i += 2 // +1 from end of loop, so 3 total for \xx. } + buffer.WriteByte(escByte[0]) + i += 2 // +1 from end of loop, so 3 total for \xx. } else { buffer.WriteRune(currentRune) } diff --git a/vendor/github.com/go-ldap/ldap/filter_test.go b/vendor/github.com/go-ldap/ldap/filter_test.go deleted file mode 100644 index ae1b79b0c0d..00000000000 --- a/vendor/github.com/go-ldap/ldap/filter_test.go +++ /dev/null @@ -1,248 +0,0 @@ -package ldap_test - -import ( - "strings" - "testing" - - "gopkg.in/asn1-ber.v1" - "gopkg.in/ldap.v2" -) - -type compileTest struct { - filterStr string - - expectedFilter string - expectedType int - expectedErr string -} - -var testFilters = []compileTest{ - compileTest{ - filterStr: "(&(sn=Miller)(givenName=Bob))", - expectedFilter: "(&(sn=Miller)(givenName=Bob))", - expectedType: ldap.FilterAnd, - }, - compileTest{ - filterStr: "(|(sn=Miller)(givenName=Bob))", - expectedFilter: "(|(sn=Miller)(givenName=Bob))", - expectedType: ldap.FilterOr, - }, - compileTest{ - filterStr: "(!(sn=Miller))", - expectedFilter: "(!(sn=Miller))", - expectedType: ldap.FilterNot, - }, - compileTest{ - filterStr: "(sn=Miller)", - expectedFilter: "(sn=Miller)", - expectedType: ldap.FilterEqualityMatch, - }, - compileTest{ - filterStr: "(sn=Mill*)", - expectedFilter: "(sn=Mill*)", - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn=*Mill)", - expectedFilter: "(sn=*Mill)", - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn=*Mill*)", - expectedFilter: "(sn=*Mill*)", - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn=*i*le*)", - expectedFilter: "(sn=*i*le*)", - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn=Mi*l*r)", - expectedFilter: "(sn=Mi*l*r)", - expectedType: ldap.FilterSubstrings, - }, - // substring filters escape properly - compileTest{ - filterStr: `(sn=Mi*함*r)`, - expectedFilter: `(sn=Mi*\ed\95\a8*r)`, - expectedType: ldap.FilterSubstrings, - }, - // already escaped substring filters don't get double-escaped - compileTest{ - filterStr: `(sn=Mi*\ed\95\a8*r)`, - expectedFilter: `(sn=Mi*\ed\95\a8*r)`, - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn=Mi*le*)", - expectedFilter: "(sn=Mi*le*)", - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn=*i*ler)", - expectedFilter: "(sn=*i*ler)", - expectedType: ldap.FilterSubstrings, - }, - compileTest{ - filterStr: "(sn>=Miller)", - expectedFilter: "(sn>=Miller)", - expectedType: ldap.FilterGreaterOrEqual, - }, - compileTest{ - filterStr: "(sn<=Miller)", - expectedFilter: "(sn<=Miller)", - expectedType: ldap.FilterLessOrEqual, - }, - compileTest{ - filterStr: "(sn=*)", - expectedFilter: "(sn=*)", - expectedType: ldap.FilterPresent, - }, - compileTest{ - filterStr: "(sn~=Miller)", - expectedFilter: "(sn~=Miller)", - expectedType: ldap.FilterApproxMatch, - }, - compileTest{ - filterStr: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`, - expectedFilter: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`, - expectedType: ldap.FilterEqualityMatch, - }, - compileTest{ - filterStr: `(objectGUID=абвгдеёжзийклмнопрстуфхцчшщъыьэюя)`, - expectedFilter: `(objectGUID=\d0\b0\d0\b1\d0\b2\d0\b3\d0\b4\d0\b5\d1\91\d0\b6\d0\b7\d0\b8\d0\b9\d0\ba\d0\bb\d0\bc\d0\bd\d0\be\d0\bf\d1\80\d1\81\d1\82\d1\83\d1\84\d1\85\d1\86\d1\87\d1\88\d1\89\d1\8a\d1\8b\d1\8c\d1\8d\d1\8e\d1\8f)`, - expectedType: ldap.FilterEqualityMatch, - }, - compileTest{ - filterStr: `(objectGUID=함수목록)`, - expectedFilter: `(objectGUID=\ed\95\a8\ec\88\98\eb\aa\a9\eb\a1\9d)`, - expectedType: ldap.FilterEqualityMatch, - }, - compileTest{ - filterStr: `(objectGUID=`, - expectedFilter: ``, - expectedType: 0, - expectedErr: "unexpected end of filter", - }, - compileTest{ - filterStr: `(objectGUID=함수목록`, - expectedFilter: ``, - expectedType: 0, - expectedErr: "unexpected end of filter", - }, - compileTest{ - filterStr: `(&(objectclass=inetorgperson)(cn=中文))`, - expectedFilter: `(&(objectclass=inetorgperson)(cn=\e4\b8\ad\e6\96\87))`, - expectedType: 0, - }, - // attr extension - compileTest{ - filterStr: `(memberOf:=foo)`, - expectedFilter: `(memberOf:=foo)`, - expectedType: ldap.FilterExtensibleMatch, - }, - // attr+named matching rule extension - compileTest{ - filterStr: `(memberOf:test:=foo)`, - expectedFilter: `(memberOf:test:=foo)`, - expectedType: ldap.FilterExtensibleMatch, - }, - // attr+oid matching rule extension - compileTest{ - filterStr: `(cn:1.2.3.4.5:=Fred Flintstone)`, - expectedFilter: `(cn:1.2.3.4.5:=Fred Flintstone)`, - expectedType: ldap.FilterExtensibleMatch, - }, - // attr+dn+oid matching rule extension - compileTest{ - filterStr: `(sn:dn:2.4.6.8.10:=Barney Rubble)`, - expectedFilter: `(sn:dn:2.4.6.8.10:=Barney Rubble)`, - expectedType: ldap.FilterExtensibleMatch, - }, - // attr+dn extension - compileTest{ - filterStr: `(o:dn:=Ace Industry)`, - expectedFilter: `(o:dn:=Ace Industry)`, - expectedType: ldap.FilterExtensibleMatch, - }, - // dn extension - compileTest{ - filterStr: `(:dn:2.4.6.8.10:=Dino)`, - expectedFilter: `(:dn:2.4.6.8.10:=Dino)`, - expectedType: ldap.FilterExtensibleMatch, - }, - compileTest{ - filterStr: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`, - expectedFilter: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`, - expectedType: ldap.FilterExtensibleMatch, - }, - - // compileTest{ filterStr: "()", filterType: FilterExtensibleMatch }, -} - -var testInvalidFilters = []string{ - `(objectGUID=\zz)`, - `(objectGUID=\a)`, -} - -func TestFilter(t *testing.T) { - // Test Compiler and Decompiler - for _, i := range testFilters { - filter, err := ldap.CompileFilter(i.filterStr) - if err != nil { - if i.expectedErr == "" || !strings.Contains(err.Error(), i.expectedErr) { - t.Errorf("Problem compiling '%s' - '%v' (expected error to contain '%v')", i.filterStr, err, i.expectedErr) - } - } else if filter.Tag != ber.Tag(i.expectedType) { - t.Errorf("%q Expected %q got %q", i.filterStr, ldap.FilterMap[uint64(i.expectedType)], ldap.FilterMap[uint64(filter.Tag)]) - } else { - o, err := ldap.DecompileFilter(filter) - if err != nil { - t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error()) - } else if i.expectedFilter != o { - t.Errorf("%q expected, got %q", i.expectedFilter, o) - } - } - } -} - -func TestInvalidFilter(t *testing.T) { - for _, filterStr := range testInvalidFilters { - if _, err := ldap.CompileFilter(filterStr); err == nil { - t.Errorf("Problem compiling %s - expected err", filterStr) - } - } -} - -func BenchmarkFilterCompile(b *testing.B) { - b.StopTimer() - filters := make([]string, len(testFilters)) - - // Test Compiler and Decompiler - for idx, i := range testFilters { - filters[idx] = i.filterStr - } - - maxIdx := len(filters) - b.StartTimer() - for i := 0; i < b.N; i++ { - ldap.CompileFilter(filters[i%maxIdx]) - } -} - -func BenchmarkFilterDecompile(b *testing.B) { - b.StopTimer() - filters := make([]*ber.Packet, len(testFilters)) - - // Test Compiler and Decompiler - for idx, i := range testFilters { - filters[idx], _ = ldap.CompileFilter(i.filterStr) - } - - maxIdx := len(filters) - b.StartTimer() - for i := 0; i < b.N; i++ { - ldap.DecompileFilter(filters[i%maxIdx]) - } -} diff --git a/vendor/github.com/go-ldap/ldap/ldap.go b/vendor/github.com/go-ldap/ldap/ldap.go index 1620aaea6ee..49692475697 100644 --- a/vendor/github.com/go-ldap/ldap/ldap.go +++ b/vendor/github.com/go-ldap/ldap/ldap.go @@ -9,7 +9,7 @@ import ( "io/ioutil" "os" - ber "gopkg.in/asn1-ber.v1" + "gopkg.in/asn1-ber.v1" ) // LDAP Application Codes @@ -36,6 +36,7 @@ const ( ApplicationExtendedResponse = 24 ) +// ApplicationMap contains human readable descriptions of LDAP Application Codes var ApplicationMap = map[uint8]string{ ApplicationBindRequest: "Bind Request", ApplicationBindResponse: "Bind Response", @@ -72,6 +73,7 @@ const ( BeheraPasswordInHistory = 8 ) +// BeheraPasswordPolicyErrorMap contains human readable descriptions of Behera Password Policy error codes var BeheraPasswordPolicyErrorMap = map[int8]string{ BeheraPasswordExpired: "Password expired", BeheraAccountLocked: "Account locked", @@ -151,16 +153,47 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) { func addControlDescriptions(packet *ber.Packet) { packet.Description = "Controls" for _, child := range packet.Children { + var value *ber.Packet + controlType := "" child.Description = "Control" - child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")" - value := child.Children[1] - if len(child.Children) == 3 { - child.Children[1].Description = "Criticality" - value = child.Children[2] - } - value.Description = "Control Value" + switch len(child.Children) { + case 0: + // at least one child is required for control type + continue - switch child.Children[0].Value.(string) { + case 1: + // just type, no criticality or value + controlType = child.Children[0].Value.(string) + child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")" + + case 2: + controlType = child.Children[0].Value.(string) + child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")" + // Children[1] could be criticality or value (both are optional) + // duck-type on whether this is a boolean + if _, ok := child.Children[1].Value.(bool); ok { + child.Children[1].Description = "Criticality" + } else { + child.Children[1].Description = "Control Value" + value = child.Children[1] + } + + case 3: + // criticality and value present + controlType = child.Children[0].Value.(string) + child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")" + child.Children[1].Description = "Criticality" + child.Children[2].Description = "Control Value" + value = child.Children[2] + + default: + // more than 3 children is invalid + continue + } + if value == nil { + continue + } + switch controlType { case ControlTypePaging: value.Description += " (Paging)" if value.Value != nil { @@ -186,18 +219,18 @@ func addControlDescriptions(packet *ber.Packet) { for _, child := range sequence.Children { if child.Tag == 0 { //Warning - child := child.Children[0] - packet := ber.DecodePacket(child.Data.Bytes()) + warningPacket := child.Children[0] + packet := ber.DecodePacket(warningPacket.Data.Bytes()) val, ok := packet.Value.(int64) if ok { - if child.Tag == 0 { + if warningPacket.Tag == 0 { //timeBeforeExpiration value.Description += " (TimeBeforeExpiration)" - child.Value = val - } else if child.Tag == 1 { + warningPacket.Value = val + } else if warningPacket.Tag == 1 { //graceAuthNsRemaining value.Description += " (GraceAuthNsRemaining)" - child.Value = val + warningPacket.Value = val } } } else if child.Tag == 1 { @@ -237,6 +270,7 @@ func addDefaultLDAPResponseDescriptions(packet *ber.Packet) { } } +// DebugBinaryFile reads and prints packets from the given filename func DebugBinaryFile(fileName string) error { file, err := ioutil.ReadFile(fileName) if err != nil { diff --git a/vendor/github.com/go-ldap/ldap/ldap_test.go b/vendor/github.com/go-ldap/ldap/ldap_test.go deleted file mode 100644 index 9f430518001..00000000000 --- a/vendor/github.com/go-ldap/ldap/ldap_test.go +++ /dev/null @@ -1,275 +0,0 @@ -package ldap_test - -import ( - "crypto/tls" - "fmt" - "testing" - - "gopkg.in/ldap.v2" -) - -var ldapServer = "ldap.itd.umich.edu" -var ldapPort = uint16(389) -var ldapTLSPort = uint16(636) -var baseDN = "dc=umich,dc=edu" -var filter = []string{ - "(cn=cis-fac)", - "(&(owner=*)(cn=cis-fac))", - "(&(objectclass=rfc822mailgroup)(cn=*Computer*))", - "(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"} -var attributes = []string{ - "cn", - "description"} - -func TestDial(t *testing.T) { - fmt.Printf("TestDial: starting...\n") - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Errorf(err.Error()) - return - } - defer l.Close() - fmt.Printf("TestDial: finished...\n") -} - -func TestDialTLS(t *testing.T) { - fmt.Printf("TestDialTLS: starting...\n") - l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true}) - if err != nil { - t.Errorf(err.Error()) - return - } - defer l.Close() - fmt.Printf("TestDialTLS: finished...\n") -} - -func TestStartTLS(t *testing.T) { - fmt.Printf("TestStartTLS: starting...\n") - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Errorf(err.Error()) - return - } - err = l.StartTLS(&tls.Config{InsecureSkipVerify: true}) - if err != nil { - t.Errorf(err.Error()) - return - } - fmt.Printf("TestStartTLS: finished...\n") -} - -func TestSearch(t *testing.T) { - fmt.Printf("TestSearch: starting...\n") - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Errorf(err.Error()) - return - } - defer l.Close() - - searchRequest := ldap.NewSearchRequest( - baseDN, - ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false, - filter[0], - attributes, - nil) - - sr, err := l.Search(searchRequest) - if err != nil { - t.Errorf(err.Error()) - return - } - - fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) -} - -func TestSearchStartTLS(t *testing.T) { - fmt.Printf("TestSearchStartTLS: starting...\n") - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Errorf(err.Error()) - return - } - defer l.Close() - - searchRequest := ldap.NewSearchRequest( - baseDN, - ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false, - filter[0], - attributes, - nil) - - sr, err := l.Search(searchRequest) - if err != nil { - t.Errorf(err.Error()) - return - } - - fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) - - fmt.Printf("TestSearchStartTLS: upgrading with startTLS\n") - err = l.StartTLS(&tls.Config{InsecureSkipVerify: true}) - if err != nil { - t.Errorf(err.Error()) - return - } - - sr, err = l.Search(searchRequest) - if err != nil { - t.Errorf(err.Error()) - return - } - - fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) -} - -func TestSearchWithPaging(t *testing.T) { - fmt.Printf("TestSearchWithPaging: starting...\n") - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Errorf(err.Error()) - return - } - defer l.Close() - - err = l.Bind("", "") - if err != nil { - t.Errorf(err.Error()) - return - } - - searchRequest := ldap.NewSearchRequest( - baseDN, - ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false, - filter[2], - attributes, - nil) - sr, err := l.SearchWithPaging(searchRequest, 5) - if err != nil { - t.Errorf(err.Error()) - return - } - - fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) - - searchRequest = ldap.NewSearchRequest( - baseDN, - ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false, - filter[2], - attributes, - []ldap.Control{ldap.NewControlPaging(5)}) - sr, err = l.SearchWithPaging(searchRequest, 5) - if err != nil { - t.Errorf(err.Error()) - return - } - - fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries)) - - searchRequest = ldap.NewSearchRequest( - baseDN, - ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false, - filter[2], - attributes, - []ldap.Control{ldap.NewControlPaging(500)}) - sr, err = l.SearchWithPaging(searchRequest, 5) - if err == nil { - t.Errorf("expected an error when paging size in control in search request doesn't match size given in call, got none") - return - } -} - -func searchGoroutine(t *testing.T, l *ldap.Conn, results chan *ldap.SearchResult, i int) { - searchRequest := ldap.NewSearchRequest( - baseDN, - ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false, - filter[i], - attributes, - nil) - sr, err := l.Search(searchRequest) - if err != nil { - t.Errorf(err.Error()) - results <- nil - return - } - results <- sr -} - -func testMultiGoroutineSearch(t *testing.T, TLS bool, startTLS bool) { - fmt.Printf("TestMultiGoroutineSearch: starting...\n") - var l *ldap.Conn - var err error - if TLS { - l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true}) - if err != nil { - t.Errorf(err.Error()) - return - } - defer l.Close() - } else { - l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Errorf(err.Error()) - return - } - if startTLS { - fmt.Printf("TestMultiGoroutineSearch: using StartTLS...\n") - err := l.StartTLS(&tls.Config{InsecureSkipVerify: true}) - if err != nil { - t.Errorf(err.Error()) - return - } - - } - } - - results := make([]chan *ldap.SearchResult, len(filter)) - for i := range filter { - results[i] = make(chan *ldap.SearchResult) - go searchGoroutine(t, l, results[i], i) - } - for i := range filter { - sr := <-results[i] - if sr == nil { - t.Errorf("Did not receive results from goroutine for %q", filter[i]) - } else { - fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries)) - } - } -} - -func TestMultiGoroutineSearch(t *testing.T) { - testMultiGoroutineSearch(t, false, false) - testMultiGoroutineSearch(t, true, true) - testMultiGoroutineSearch(t, false, true) -} - -func TestEscapeFilter(t *testing.T) { - if got, want := ldap.EscapeFilter("a\x00b(c)d*e\\f"), `a\00b\28c\29d\2ae\5cf`; got != want { - t.Errorf("Got %s, expected %s", want, got) - } - if got, want := ldap.EscapeFilter("Lučić"), `Lu\c4\8di\c4\87`; got != want { - t.Errorf("Got %s, expected %s", want, got) - } -} - -func TestCompare(t *testing.T) { - fmt.Printf("TestCompare: starting...\n") - l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) - if err != nil { - t.Fatal(err.Error()) - } - defer l.Close() - - dn := "cn=math mich,ou=User Groups,ou=Groups,dc=umich,dc=edu" - attribute := "cn" - value := "math mich" - - sr, err := l.Compare(dn, attribute, value) - if err != nil { - t.Errorf(err.Error()) - return - } - - fmt.Printf("TestCompare: -> %v\n", sr) -} diff --git a/vendor/github.com/go-ldap/ldap/modify.go b/vendor/github.com/go-ldap/ldap/modify.go index 4372a19dceb..e4ab6cefc7e 100644 --- a/vendor/github.com/go-ldap/ldap/modify.go +++ b/vendor/github.com/go-ldap/ldap/modify.go @@ -36,64 +36,76 @@ import ( "gopkg.in/asn1-ber.v1" ) +// Change operation choices const ( AddAttribute = 0 DeleteAttribute = 1 ReplaceAttribute = 2 ) +// PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 type PartialAttribute struct { - attrType string - attrVals []string + // Type is the type of the partial attribute + Type string + // Vals are the values of the partial attribute + Vals []string } func (p *PartialAttribute) encode() *ber.Packet { seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute") - seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.attrType, "Type")) + seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.Type, "Type")) set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") - for _, value := range p.attrVals { + for _, value := range p.Vals { set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) } seq.AppendChild(set) return seq } +// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 type ModifyRequest struct { - dn string - addAttributes []PartialAttribute - deleteAttributes []PartialAttribute - replaceAttributes []PartialAttribute + // DN is the distinguishedName of the directory entry to modify + DN string + // AddAttributes contain the attributes to add + AddAttributes []PartialAttribute + // DeleteAttributes contain the attributes to delete + DeleteAttributes []PartialAttribute + // ReplaceAttributes contain the attributes to replace + ReplaceAttributes []PartialAttribute } +// Add inserts the given attribute to the list of attributes to add func (m *ModifyRequest) Add(attrType string, attrVals []string) { - m.addAttributes = append(m.addAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals}) + m.AddAttributes = append(m.AddAttributes, PartialAttribute{Type: attrType, Vals: attrVals}) } +// Delete inserts the given attribute to the list of attributes to delete func (m *ModifyRequest) Delete(attrType string, attrVals []string) { - m.deleteAttributes = append(m.deleteAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals}) + m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{Type: attrType, Vals: attrVals}) } +// Replace inserts the given attribute to the list of attributes to replace func (m *ModifyRequest) Replace(attrType string, attrVals []string) { - m.replaceAttributes = append(m.replaceAttributes, PartialAttribute{attrType: attrType, attrVals: attrVals}) + m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{Type: attrType, Vals: attrVals}) } func (m ModifyRequest) encode() *ber.Packet { request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request") - request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.dn, "DN")) + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN")) changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes") - for _, attribute := range m.addAttributes { + for _, attribute := range m.AddAttributes { change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation")) change.AppendChild(attribute.encode()) changes.AppendChild(change) } - for _, attribute := range m.deleteAttributes { + for _, attribute := range m.DeleteAttributes { change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation")) change.AppendChild(attribute.encode()) changes.AppendChild(change) } - for _, attribute := range m.replaceAttributes { + for _, attribute := range m.ReplaceAttributes { change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation")) change.AppendChild(attribute.encode()) @@ -103,36 +115,38 @@ func (m ModifyRequest) encode() *ber.Packet { return request } +// NewModifyRequest creates a modify request for the given DN func NewModifyRequest( dn string, ) *ModifyRequest { return &ModifyRequest{ - dn: dn, + DN: dn, } } +// Modify performs the ModifyRequest func (l *Conn) Modify(modifyRequest *ModifyRequest) error { - messageID := l.nextMessageID() packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) packet.AppendChild(modifyRequest.encode()) l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return err } - if channel == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) - if packet == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err } if l.Debug { @@ -151,6 +165,6 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error { log.Printf("Unexpected Response: %d", packet.Children[1].Tag) } - l.Debug.Printf("%d: returning", messageID) + l.Debug.Printf("%d: returning", msgCtx.id) return nil } diff --git a/vendor/github.com/go-ldap/ldap/passwdmodify.go b/vendor/github.com/go-ldap/ldap/passwdmodify.go index 508b11ed727..7d8246fd189 100644 --- a/vendor/github.com/go-ldap/ldap/passwdmodify.go +++ b/vendor/github.com/go-ldap/ldap/passwdmodify.go @@ -16,13 +16,21 @@ const ( passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1" ) +// PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt type PasswordModifyRequest struct { + // UserIdentity is an optional string representation of the user associated with the request. + // This string may or may not be an LDAPDN [RFC2253]. + // If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session UserIdentity string - OldPassword string - NewPassword string + // OldPassword, if present, contains the user's current password + OldPassword string + // NewPassword, if present, contains the desired password for this user + NewPassword string } +// PasswordModifyResult holds the server response to a PasswordModifyRequest type PasswordModifyResult struct { + // GeneratedPassword holds a password generated by the server, if present GeneratedPassword string } @@ -47,7 +55,7 @@ func (r *PasswordModifyRequest) encode() (*ber.Packet, error) { return request, nil } -// Create a new PasswordModifyRequest +// NewPasswordModifyRequest creates a new PasswordModifyRequest // // According to the RFC 3602: // userIdentity is a string representing the user associated with the request. @@ -72,11 +80,10 @@ func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPasswo } } +// PasswordModify performs the modification request func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) { - messageID := l.nextMessageID() - packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) encodedPasswordModifyRequest, err := passwordModifyRequest.encode() if err != nil { @@ -86,20 +93,24 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return nil, err } - if channel == nil { - return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) result := &PasswordModifyResult{} - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err + } if packet == nil { return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) @@ -124,10 +135,10 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa extendedResponse := packet.Children[1] for _, child := range extendedResponse.Children { if child.Tag == 11 { - passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes()) - if len(passwordModifyReponseValue.Children) == 1 { - if passwordModifyReponseValue.Children[0].Tag == 0 { - result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes()) + passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes()) + if len(passwordModifyResponseValue.Children) == 1 { + if passwordModifyResponseValue.Children[0].Tag == 0 { + result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes()) } } } diff --git a/vendor/github.com/go-ldap/ldap/search.go b/vendor/github.com/go-ldap/ldap/search.go index 23a2cf2b202..2a99894c94b 100644 --- a/vendor/github.com/go-ldap/ldap/search.go +++ b/vendor/github.com/go-ldap/ldap/search.go @@ -68,18 +68,21 @@ import ( "gopkg.in/asn1-ber.v1" ) +// scope choices const ( ScopeBaseObject = 0 ScopeSingleLevel = 1 ScopeWholeSubtree = 2 ) +// ScopeMap contains human readable descriptions of scope choices var ScopeMap = map[int]string{ ScopeBaseObject: "Base Object", ScopeSingleLevel: "Single Level", ScopeWholeSubtree: "Whole Subtree", } +// derefAliases const ( NeverDerefAliases = 0 DerefInSearching = 1 @@ -87,6 +90,7 @@ const ( DerefAlways = 3 ) +// DerefMap contains human readable descriptions of derefAliases choices var DerefMap = map[int]string{ NeverDerefAliases: "NeverDerefAliases", DerefInSearching: "DerefInSearching", @@ -114,11 +118,15 @@ func NewEntry(dn string, attributes map[string][]string) *Entry { } } +// Entry represents a single search result entry type Entry struct { - DN string + // DN is the distinguished name of the entry + DN string + // Attributes are the returned attributes for the entry Attributes []*EntryAttribute } +// GetAttributeValues returns the values for the named attribute, or an empty list func (e *Entry) GetAttributeValues(attribute string) []string { for _, attr := range e.Attributes { if attr.Name == attribute { @@ -128,6 +136,7 @@ func (e *Entry) GetAttributeValues(attribute string) []string { return []string{} } +// GetRawAttributeValues returns the byte values for the named attribute, or an empty list func (e *Entry) GetRawAttributeValues(attribute string) [][]byte { for _, attr := range e.Attributes { if attr.Name == attribute { @@ -137,6 +146,7 @@ func (e *Entry) GetRawAttributeValues(attribute string) [][]byte { return [][]byte{} } +// GetAttributeValue returns the first value for the named attribute, or "" func (e *Entry) GetAttributeValue(attribute string) string { values := e.GetAttributeValues(attribute) if len(values) == 0 { @@ -145,6 +155,7 @@ func (e *Entry) GetAttributeValue(attribute string) string { return values[0] } +// GetRawAttributeValue returns the first value for the named attribute, or an empty slice func (e *Entry) GetRawAttributeValue(attribute string) []byte { values := e.GetRawAttributeValues(attribute) if len(values) == 0 { @@ -153,6 +164,7 @@ func (e *Entry) GetRawAttributeValue(attribute string) []byte { return values[0] } +// Print outputs a human-readable description func (e *Entry) Print() { fmt.Printf("DN: %s\n", e.DN) for _, attr := range e.Attributes { @@ -160,6 +172,7 @@ func (e *Entry) Print() { } } +// PrettyPrint outputs a human-readable description indenting func (e *Entry) PrettyPrint(indent int) { fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN) for _, attr := range e.Attributes { @@ -180,38 +193,51 @@ func NewEntryAttribute(name string, values []string) *EntryAttribute { } } +// EntryAttribute holds a single attribute type EntryAttribute struct { - Name string - Values []string + // Name is the name of the attribute + Name string + // Values contain the string values of the attribute + Values []string + // ByteValues contain the raw values of the attribute ByteValues [][]byte } +// Print outputs a human-readable description func (e *EntryAttribute) Print() { fmt.Printf("%s: %s\n", e.Name, e.Values) } +// PrettyPrint outputs a human-readable description with indenting func (e *EntryAttribute) PrettyPrint(indent int) { fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values) } +// SearchResult holds the server's response to a search request type SearchResult struct { - Entries []*Entry + // Entries are the returned entries + Entries []*Entry + // Referrals are the returned referrals Referrals []string - Controls []Control + // Controls are the returned controls + Controls []Control } +// Print outputs a human-readable description func (s *SearchResult) Print() { for _, entry := range s.Entries { entry.Print() } } +// PrettyPrint outputs a human-readable description with indenting func (s *SearchResult) PrettyPrint(indent int) { for _, entry := range s.Entries { entry.PrettyPrint(indent) } } +// SearchRequest represents a search request to send to the server type SearchRequest struct { BaseDN string Scope int @@ -247,6 +273,7 @@ func (s *SearchRequest) encode() (*ber.Packet, error) { return request, nil } +// NewSearchRequest creates a new search request func NewSearchRequest( BaseDN string, Scope, DerefAliases, SizeLimit, TimeLimit int, @@ -341,10 +368,10 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) return searchResult, nil } +// Search performs the given search request func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { - messageID := l.nextMessageID() packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) // encode search request encodedSearchRequest, err := searchRequest.encode() if err != nil { @@ -358,14 +385,11 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return nil, err } - if channel == nil { - return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) result := &SearchResult{ Entries: make([]*Entry, 0), @@ -374,11 +398,15 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { foundSearchResultDone := false for !foundSearchResultDone { - l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel - l.Debug.Printf("%d: got response %p", messageID, packet) - if packet == nil { - return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err } if l.Debug { @@ -417,6 +445,6 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string)) } } - l.Debug.Printf("%d: returning", messageID) + l.Debug.Printf("%d: returning", msgCtx.id) return result, nil } diff --git a/vendor/github.com/go-ldap/ldap/search_test.go b/vendor/github.com/go-ldap/ldap/search_test.go deleted file mode 100644 index efb8147d1a5..00000000000 --- a/vendor/github.com/go-ldap/ldap/search_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package ldap - -import ( - "reflect" - "testing" -) - -// TestNewEntry tests that repeated calls to NewEntry return the same value with the same input -func TestNewEntry(t *testing.T) { - dn := "testDN" - attributes := map[string][]string{ - "alpha": {"value"}, - "beta": {"value"}, - "gamma": {"value"}, - "delta": {"value"}, - "epsilon": {"value"}, - } - exectedEntry := NewEntry(dn, attributes) - - iteration := 0 - for { - if iteration == 100 { - break - } - testEntry := NewEntry(dn, attributes) - if !reflect.DeepEqual(exectedEntry, testEntry) { - t.Fatalf("consequent calls to NewEntry did not yield the same result:\n\texpected:\n\t%s\n\tgot:\n\t%s\n", exectedEntry, testEntry) - } - iteration = iteration + 1 - } -} diff --git a/vendor/github.com/go-macaron/binding/README.md b/vendor/github.com/go-macaron/binding/README.md deleted file mode 100644 index a6748b57a1d..00000000000 --- a/vendor/github.com/go-macaron/binding/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# binding [![Build Status](https://travis-ci.org/go-macaron/binding.svg?branch=master)](https://travis-ci.org/go-macaron/binding) [![](http://gocover.io/_badge/github.com/go-macaron/binding)](http://gocover.io/github.com/go-macaron/binding) - -Middleware binding provides request data binding and validation for [Macaron](https://github.com/go-macaron/macaron). - -### Installation - - go get github.com/go-macaron/binding - -## Getting Help - -- [API Reference](https://gowalker.org/github.com/go-macaron/binding) -- [Documentation](http://go-macaron.com/docs/middlewares/binding) - -## Credits - -This package is a modified version of [martini-contrib/binding](https://github.com/martini-contrib/binding). - -## 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/binding/binding.go b/vendor/github.com/go-macaron/binding/binding.go index dbd7beb45f6..5d178b7e1a8 100644 --- a/vendor/github.com/go-macaron/binding/binding.go +++ b/vendor/github.com/go-macaron/binding/binding.go @@ -22,6 +22,7 @@ import ( "io" "mime/multipart" "net/http" + "net/url" "reflect" "regexp" "strconv" @@ -32,7 +33,7 @@ import ( "gopkg.in/macaron.v1" ) -const _VERSION = "0.3.2" +const _VERSION = "0.6.0" func Version() string { return _VERSION @@ -211,13 +212,35 @@ func Json(jsonStruct interface{}, ifacePtr ...interface{}) macaron.Handler { } } +// RawValidate is same as Validate but does not require a HTTP context, +// and can be used independently just for validation. +// This function does not support Validator interface. +func RawValidate(obj interface{}) Errors { + var errs Errors + v := reflect.ValueOf(obj) + k := v.Kind() + if k == reflect.Interface || k == reflect.Ptr { + v = v.Elem() + k = v.Kind() + } + if k == reflect.Slice || k == reflect.Array { + for i := 0; i < v.Len(); i++ { + e := v.Index(i).Interface() + errs = validateStruct(errs, e) + } + } else { + errs = validateStruct(errs, obj) + } + return errs +} + // Validate is middleware to enforce required fields. If the struct // passed in implements Validator, then the user-defined Validate method // is executed, and its errors are mapped to the context. This middleware // performs no error handling: it merely detects errors and maps them. func Validate(obj interface{}) macaron.Handler { return func(ctx *macaron.Context) { - var errors Errors + var errs Errors v := reflect.ValueOf(obj) k := v.Kind() if k == reflect.Interface || k == reflect.Ptr { @@ -227,18 +250,18 @@ func Validate(obj interface{}) macaron.Handler { if k == reflect.Slice || k == reflect.Array { for i := 0; i < v.Len(); i++ { e := v.Index(i).Interface() - errors = validateStruct(errors, e) + errs = validateStruct(errs, e) if validator, ok := e.(Validator); ok { - errors = validator.Validate(ctx, errors) + errs = validator.Validate(ctx, errs) } } } else { - errors = validateStruct(errors, obj) + errs = validateStruct(errs, obj) if validator, ok := obj.(Validator); ok { - errors = validator.Validate(ctx, errors) + errs = validator.Validate(ctx, errs) } } - ctx.Map(errors) + ctx.Map(errs) } } @@ -246,9 +269,42 @@ var ( AlphaDashPattern = regexp.MustCompile("[^\\d\\w-_]") AlphaDashDotPattern = regexp.MustCompile("[^\\d\\w-_\\.]") EmailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?") - URLPattern = regexp.MustCompile(`(http|https):\/\/(?:\\S+(?::\\S*)?@)?[\w\-_]+(\.[\w\-_]+)*([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`) ) +// Copied from github.com/asaskevich/govalidator. +const _MAX_URL_RUNE_COUNT = 2083 +const _MIN_URL_RUNE_COUNT = 3 + +var ( + urlSchemaRx = `((ftp|tcp|udp|wss?|https?):\/\/)` + urlUsernameRx = `(\S+(:\S*)?@)` + urlIPRx = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))` + ipRx = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` + urlSubdomainRx = `((www\.)|([a-zA-Z0-9]([-\.][-\._a-zA-Z0-9]+)*))` + urlPortRx = `(:(\d{1,5}))` + urlPathRx = `((\/|\?|#)[^\s]*)` + URLPattern = regexp.MustCompile(`^` + urlSchemaRx + `?` + urlUsernameRx + `?` + `((` + urlIPRx + `|(\[` + ipRx + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + urlSubdomainRx + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + urlPortRx + `?` + urlPathRx + `?$`) +) + +// IsURL check if the string is an URL. +func isURL(str string) bool { + if str == "" || utf8.RuneCountInString(str) >= _MAX_URL_RUNE_COUNT || len(str) <= _MIN_URL_RUNE_COUNT || strings.HasPrefix(str, ".") { + return false + } + u, err := url.Parse(str) + if err != nil { + return false + } + if strings.HasPrefix(u.Host, ".") { + return false + } + if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { + return false + } + return URLPattern.MatchString(str) + +} + type ( // Rule represents a validation rule. Rule struct { @@ -257,18 +313,34 @@ type ( // IsValid applies validation rule to condition. IsValid func(Errors, string, interface{}) (bool, Errors) } - // RuleMapper represents a validation rule mapper, + + // ParamRule does same thing as Rule but passes rule itself to IsValid method. + ParamRule struct { + // IsMatch checks if rule matches. + IsMatch func(string) bool + // IsValid applies validation rule to condition. + IsValid func(Errors, string, string, interface{}) (bool, Errors) + } + + // RuleMapper and ParamRuleMapper represent validation rule mappers, // it allwos users to add custom validation rules. - RuleMapper []*Rule + RuleMapper []*Rule + ParamRuleMapper []*ParamRule ) var ruleMapper RuleMapper +var paramRuleMapper ParamRuleMapper // AddRule adds new validation rule. func AddRule(r *Rule) { ruleMapper = append(ruleMapper, r) } +// AddParamRule adds new validation rule. +func AddParamRule(r *ParamRule) { + paramRuleMapper = append(paramRuleMapper, r) +} + func in(fieldValue interface{}, arr string) bool { val := fmt.Sprintf("%v", fieldValue) vals := strings.Split(arr, ",") @@ -356,6 +428,16 @@ VALIDATE_RULES: break VALIDATE_RULES } case rule == "Required": + v := reflect.ValueOf(fieldValue) + if v.Kind() == reflect.Slice { + if v.Len() == 0 { + errors.Add([]string{field.Name}, ERR_REQUIRED, "Required") + break VALIDATE_RULES + } + + continue + } + if reflect.DeepEqual(zero, fieldValue) { errors.Add([]string{field.Name}, ERR_REQUIRED, "Required") break VALIDATE_RULES @@ -422,7 +504,7 @@ VALIDATE_RULES: str := fmt.Sprintf("%v", fieldValue) if len(str) == 0 { continue - } else if !URLPattern.MatchString(str) { + } else if !isURL(str) { errors.Add([]string{field.Name}, ERR_URL, "Url") break VALIDATE_RULES } @@ -456,7 +538,7 @@ VALIDATE_RULES: } } default: - // Apply custom validation rules. + // Apply custom validation rules var isValid bool for i := range ruleMapper { if ruleMapper[i].IsMatch(rule) { @@ -466,6 +548,14 @@ VALIDATE_RULES: } } } + for i := range paramRuleMapper { + if paramRuleMapper[i].IsMatch(rule) { + isValid, errors = paramRuleMapper[i].IsValid(errors, rule, field.Name, fieldValue) + if !isValid { + break VALIDATE_RULES + } + } + } } } return errors diff --git a/vendor/github.com/go-macaron/gzip/README.md b/vendor/github.com/go-macaron/gzip/README.md deleted file mode 100644 index 0c438a72027..00000000000 --- a/vendor/github.com/go-macaron/gzip/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# gzip [![Build Status](https://travis-ci.org/go-macaron/gzip.svg?branch=master)](https://travis-ci.org/go-macaron/gzip) [![](http://gocover.io/_badge/github.com/go-macaron/gzip)](http://gocover.io/github.com/go-macaron/gzip) - -Middleware gzip provides compress to responses for [Macaron](https://github.com/go-macaron/macaron). - -### Installation - - go get github.com/go-macaron/gzip - -## Getting Help - -- [API Reference](https://gowalker.org/github.com/go-macaron/gzip) -- [Documentation](http://go-macaron.com/docs/middlewares/gzip) - -## Credits - -This package is a modified version of [martini-contrib/gzip](https://github.com/martini-contrib/gzip). - -## 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/inject/README.md b/vendor/github.com/go-macaron/inject/README.md deleted file mode 100644 index c65c76955dd..00000000000 --- a/vendor/github.com/go-macaron/inject/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# inject [![Build Status](https://travis-ci.org/go-macaron/inject.svg?branch=master)](https://travis-ci.org/go-macaron/inject) [![](http://gocover.io/_badge/github.com/go-macaron/inject)](http://gocover.io/github.com/go-macaron/inject) - -Package inject provides utilities for mapping and injecting dependencies in various ways. - -**This a modified version of [codegangsta/inject](https://github.com/codegangsta/inject) for special purpose of Macaron** - -**Please use the original version if you need dependency injection feature** - -## 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/README.md b/vendor/github.com/go-macaron/session/README.md deleted file mode 100644 index b11bd4a793d..00000000000 --- a/vendor/github.com/go-macaron/session/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# session [![Build Status](https://travis-ci.org/go-macaron/session.svg?branch=master)](https://travis-ci.org/go-macaron/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 - - go get github.com/go-macaron/session - -## Getting Help - -- [API Reference](https://gowalker.org/github.com/go-macaron/session) -- [Documentation](https://go-macaron.com/docs/middlewares/session) - -## Credits - -This package is a modified version of [beego/session](https://github.com/astaxie/beego/tree/master/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/github.com/go-macaron/session/couchbase/couchbase.go deleted file mode 100644 index 1a77a42b5f3..00000000000 --- a/vendor/github.com/go-macaron/session/couchbase/couchbase.go +++ /dev/null @@ -1,223 +0,0 @@ -// 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 ( - "strings" - "sync" - - "github.com/couchbaselabs/go-couchbase" - - "github.com/go-macaron/session" -) - -// CouchbaseSessionStore represents a couchbase session store implementation. -type CouchbaseSessionStore struct { - b *couchbase.Bucket - sid string - lock sync.RWMutex - data map[interface{}]interface{} - maxlifetime int64 -} - -// Set sets value to given key in session. -func (s *CouchbaseSessionStore) 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 *CouchbaseSessionStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *CouchbaseSessionStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *CouchbaseSessionStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *CouchbaseSessionStore) Release() error { - defer s.b.Close() - - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - return s.b.Set(s.sid, int(s.maxlifetime), data) -} - -// Flush deletes all session data. -func (s *CouchbaseSessionStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// CouchbaseProvider represents a couchbase session provider implementation. -type CouchbaseProvider struct { - maxlifetime int64 - connStr string - pool string - bucket string - b *couchbase.Bucket -} - -func (cp *CouchbaseProvider) getBucket() *couchbase.Bucket { - c, err := couchbase.Connect(cp.connStr) - if err != nil { - return nil - } - - pool, err := c.GetPool(cp.pool) - if err != nil { - return nil - } - - bucket, err := pool.GetBucket(cp.bucket) - if err != nil { - return nil - } - - return bucket -} - -// Init initializes memory session provider. -// connStr is couchbase server REST/JSON URL -// e.g. http://host:port/, Pool, Bucket -func (p *CouchbaseProvider) Init(maxlifetime int64, connStr string) error { - p.maxlifetime = maxlifetime - configs := strings.Split(connStr, ",") - if len(configs) > 0 { - p.connStr = configs[0] - } - if len(configs) > 1 { - p.pool = configs[1] - } - if len(configs) > 2 { - p.bucket = configs[2] - } - - return nil -} - -// Read returns raw session store by session ID. -func (p *CouchbaseProvider) Read(sid string) (session.RawStore, error) { - p.b = p.getBucket() - - var doc []byte - - err := p.b.Get(sid, &doc) - var kv map[interface{}]interface{} - if doc == nil { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(doc) - if err != nil { - return nil, err - } - } - - cs := &CouchbaseSessionStore{b: p.b, sid: sid, data: kv, maxlifetime: p.maxlifetime} - return cs, nil -} - -// Exist returns true if session with given ID exists. -func (p *CouchbaseProvider) Exist(sid string) bool { - p.b = p.getBucket() - defer p.b.Close() - - var doc []byte - - if err := p.b.Get(sid, &doc); err != nil || doc == nil { - return false - } else { - return true - } -} - -// Destory deletes a session by session ID. -func (p *CouchbaseProvider) Destory(sid string) error { - p.b = p.getBucket() - defer p.b.Close() - - p.b.Delete(sid) - return nil -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *CouchbaseProvider) Regenerate(oldsid, sid string) (session.RawStore, error) { - p.b = p.getBucket() - - var doc []byte - if err := p.b.Get(oldsid, &doc); err != nil || doc == nil { - p.b.Set(sid, int(p.maxlifetime), "") - } else { - err := p.b.Delete(oldsid) - if err != nil { - return nil, err - } - _, _ = p.b.Add(sid, int(p.maxlifetime), doc) - } - - err := p.b.Get(sid, &doc) - if err != nil { - return nil, err - } - var kv map[interface{}]interface{} - if doc == nil { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(doc) - if err != nil { - return nil, err - } - } - - cs := &CouchbaseSessionStore{b: p.b, sid: sid, data: kv, maxlifetime: p.maxlifetime} - return cs, nil -} - -// Count counts and returns number of sessions. -func (p *CouchbaseProvider) Count() int { - // FIXME - return 0 -} - -// GC calls GC to clean expired sessions. -func (p *CouchbaseProvider) GC() {} - -func init() { - session.Register("couchbase", &CouchbaseProvider{}) -} diff --git a/vendor/github.com/go-macaron/session/ledis/ledis.go b/vendor/github.com/go-macaron/session/ledis/ledis.go deleted file mode 100644 index 73e27f5f22a..00000000000 --- a/vendor/github.com/go-macaron/session/ledis/ledis.go +++ /dev/null @@ -1,222 +0,0 @@ -// 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" - "strings" - "sync" - - "github.com/Unknwon/com" - "github.com/siddontang/ledisdb/config" - "github.com/siddontang/ledisdb/ledis" - "gopkg.in/ini.v1" - - "github.com/go-macaron/session" -) - -// LedisStore represents a ledis session store implementation. -type LedisStore struct { - c *ledis.DB - sid string - expire int64 - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewLedisStore creates and returns a ledis session store. -func NewLedisStore(c *ledis.DB, sid string, expire int64, kv map[interface{}]interface{}) *LedisStore { - return &LedisStore{ - c: c, - expire: expire, - sid: sid, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *LedisStore) 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 *LedisStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *LedisStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *LedisStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *LedisStore) Release() error { - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - if err = s.c.Set([]byte(s.sid), data); err != nil { - return err - } - _, err = s.c.Expire([]byte(s.sid), s.expire) - return err -} - -// Flush deletes all session data. -func (s *LedisStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// LedisProvider represents a ledis session provider implementation. -type LedisProvider struct { - c *ledis.DB - expire int64 -} - -// Init initializes ledis session provider. -// configs: data_dir=./app.db,db=0 -func (p *LedisProvider) Init(expire int64, configs string) error { - p.expire = expire - - cfg, err := ini.Load([]byte(strings.Replace(configs, ",", "\n", -1))) - if err != nil { - return err - } - - db := 0 - opt := new(config.Config) - for k, v := range cfg.Section("").KeysHash() { - switch k { - case "data_dir": - opt.DataDir = v - case "db": - db = com.StrTo(v).MustInt() - default: - return fmt.Errorf("session/ledis: unsupported option '%s'", k) - } - } - - l, err := ledis.Open(opt) - if err != nil { - return fmt.Errorf("session/ledis: error opening db: %v", err) - } - p.c, err = l.Select(db) - return err -} - -// Read returns raw session store by session ID. -func (p *LedisProvider) Read(sid string) (session.RawStore, error) { - if !p.Exist(sid) { - if err := p.c.Set([]byte(sid), []byte("")); err != nil { - return nil, err - } - } - - var kv map[interface{}]interface{} - kvs, err := p.c.Get([]byte(sid)) - if err != nil { - return nil, err - } - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(kvs) - if err != nil { - return nil, err - } - } - - return NewLedisStore(p.c, sid, p.expire, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *LedisProvider) Exist(sid string) bool { - count, err := p.c.Exists([]byte(sid)) - return err == nil && count > 0 -} - -// Destory deletes a session by session ID. -func (p *LedisProvider) Destory(sid string) error { - _, err := p.c.Del([]byte(sid)) - return err -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *LedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } - - kvs := make([]byte, 0) - if p.Exist(oldsid) { - if kvs, err = p.c.Get([]byte(oldsid)); err != nil { - return nil, err - } else if _, err = p.c.Del([]byte(oldsid)); err != nil { - return nil, err - } - } - if err = p.c.SetEX([]byte(sid), p.expire, kvs); err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(kvs)) - if err != nil { - return nil, err - } - } - - return NewLedisStore(p.c, sid, p.expire, kv), nil -} - -// Count counts and returns number of sessions. -func (p *LedisProvider) Count() int { - // FIXME: how come this library does not have DbSize() method? - return -1 -} - -// GC calls GC to clean expired sessions. -func (p *LedisProvider) GC() { - // FIXME: wtf??? -} - -func init() { - session.Register("ledis", &LedisProvider{}) -} diff --git a/vendor/github.com/go-macaron/session/ledis/ledis.goconvey b/vendor/github.com/go-macaron/session/ledis/ledis.goconvey deleted file mode 100644 index 8485e986e45..00000000000 --- a/vendor/github.com/go-macaron/session/ledis/ledis.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/github.com/go-macaron/session/memcache/memcache.goconvey b/vendor/github.com/go-macaron/session/memcache/memcache.goconvey deleted file mode 100644 index 8485e986e45..00000000000 --- a/vendor/github.com/go-macaron/session/memcache/memcache.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/github.com/go-macaron/session/mysql/mysql.go b/vendor/github.com/go-macaron/session/mysql/mysql.go index 0d96fb8ec18..a16db779c63 100644 --- a/vendor/github.com/go-macaron/session/mysql/mysql.go +++ b/vendor/github.com/go-macaron/session/mysql/mysql.go @@ -185,7 +185,7 @@ func (p *MysqlProvider) Count() (total int) { // GC calls GC to clean expired sessions. func (p *MysqlProvider) GC() { - if _, err := p.c.Exec("DELETE FROM session WHERE UNIX_TIMESTAMP(NOW()) - expiry > ?", p.expire); err != nil { + if _, err := p.c.Exec("DELETE FROM session WHERE expiry + ? <= UNIX_TIMESTAMP(NOW())", p.expire); err != nil { log.Printf("session/mysql: error garbage collecting: %v", err) } } diff --git a/vendor/github.com/go-macaron/session/mysql/mysql.goconvey b/vendor/github.com/go-macaron/session/mysql/mysql.goconvey deleted file mode 100644 index 8485e986e45..00000000000 --- a/vendor/github.com/go-macaron/session/mysql/mysql.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/github.com/go-macaron/session/nodb/nodb.go b/vendor/github.com/go-macaron/session/nodb/nodb.go deleted file mode 100644 index c02f323f322..00000000000 --- a/vendor/github.com/go-macaron/session/nodb/nodb.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2015 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" - "sync" - - "github.com/lunny/nodb" - "github.com/lunny/nodb/config" - - "github.com/go-macaron/session" -) - -// NodbStore represents a nodb session store implementation. -type NodbStore struct { - c *nodb.DB - sid string - expire int64 - lock sync.RWMutex - data map[interface{}]interface{} -} - -// NewNodbStore creates and returns a ledis session store. -func NewNodbStore(c *nodb.DB, sid string, expire int64, kv map[interface{}]interface{}) *NodbStore { - return &NodbStore{ - c: c, - expire: expire, - sid: sid, - data: kv, - } -} - -// Set sets value to given key in session. -func (s *NodbStore) 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 *NodbStore) Get(key interface{}) interface{} { - s.lock.RLock() - defer s.lock.RUnlock() - - return s.data[key] -} - -// Delete delete a key from session. -func (s *NodbStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - - delete(s.data, key) - return nil -} - -// ID returns current session ID. -func (s *NodbStore) ID() string { - return s.sid -} - -// Release releases resource and save data to provider. -func (s *NodbStore) Release() error { - data, err := session.EncodeGob(s.data) - if err != nil { - return err - } - - if err = s.c.Set([]byte(s.sid), data); err != nil { - return err - } - _, err = s.c.Expire([]byte(s.sid), s.expire) - return err -} - -// Flush deletes all session data. -func (s *NodbStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - - s.data = make(map[interface{}]interface{}) - return nil -} - -// NodbProvider represents a ledis session provider implementation. -type NodbProvider struct { - c *nodb.DB - expire int64 -} - -// Init initializes nodb session provider. -func (p *NodbProvider) Init(expire int64, configs string) error { - p.expire = expire - - cfg := new(config.Config) - cfg.DataDir = configs - dbs, err := nodb.Open(cfg) - if err != nil { - return fmt.Errorf("session/nodb: error opening db: %v", err) - } - - p.c, err = dbs.Select(0) - return err -} - -// Read returns raw session store by session ID. -func (p *NodbProvider) Read(sid string) (session.RawStore, error) { - if !p.Exist(sid) { - if err := p.c.Set([]byte(sid), []byte("")); err != nil { - return nil, err - } - } - - var kv map[interface{}]interface{} - kvs, err := p.c.Get([]byte(sid)) - if err != nil { - return nil, err - } - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(kvs) - if err != nil { - return nil, err - } - } - - return NewNodbStore(p.c, sid, p.expire, kv), nil -} - -// Exist returns true if session with given ID exists. -func (p *NodbProvider) Exist(sid string) bool { - count, err := p.c.Exists([]byte(sid)) - return err == nil && count > 0 -} - -// Destory deletes a session by session ID. -func (p *NodbProvider) Destory(sid string) error { - _, err := p.c.Del([]byte(sid)) - return err -} - -// Regenerate regenerates a session store from old session ID to new one. -func (p *NodbProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - if p.Exist(sid) { - return nil, fmt.Errorf("new sid '%s' already exists", sid) - } - - kvs := make([]byte, 0) - if p.Exist(oldsid) { - if kvs, err = p.c.Get([]byte(oldsid)); err != nil { - return nil, err - } else if _, err = p.c.Del([]byte(oldsid)); err != nil { - return nil, err - } - } - - if err = p.c.Set([]byte(sid), kvs); err != nil { - return nil, err - } else if _, err = p.c.Expire([]byte(sid), p.expire); err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(kvs)) - if err != nil { - return nil, err - } - } - - return NewNodbStore(p.c, sid, p.expire, kv), nil -} - -// Count counts and returns number of sessions. -func (p *NodbProvider) Count() int { - // FIXME: how come this library does not have DbSize() method? - return -1 -} - -// GC calls GC to clean expired sessions. -func (p *NodbProvider) GC() {} - -func init() { - session.Register("nodb", &NodbProvider{}) -} diff --git a/vendor/github.com/go-macaron/session/nodb/nodb.goconvey b/vendor/github.com/go-macaron/session/nodb/nodb.goconvey deleted file mode 100644 index 8485e986e45..00000000000 --- a/vendor/github.com/go-macaron/session/nodb/nodb.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/github.com/go-macaron/session/postgres/postgres.goconvey b/vendor/github.com/go-macaron/session/postgres/postgres.goconvey deleted file mode 100644 index 8485e986e45..00000000000 --- a/vendor/github.com/go-macaron/session/postgres/postgres.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/github.com/go-macaron/session/redis/redis.goconvey b/vendor/github.com/go-macaron/session/redis/redis.goconvey deleted file mode 100644 index 8485e986e45..00000000000 --- a/vendor/github.com/go-macaron/session/redis/redis.goconvey +++ /dev/null @@ -1 +0,0 @@ -ignore \ No newline at end of file diff --git a/vendor/github.com/go-sql-driver/mysql/AUTHORS b/vendor/github.com/go-sql-driver/mysql/AUTHORS index e47e5425cba..861905d2388 100644 --- a/vendor/github.com/go-sql-driver/mysql/AUTHORS +++ b/vendor/github.com/go-sql-driver/mysql/AUTHORS @@ -12,38 +12,57 @@ # Individual Persons Aaron Hopkins +Achille Roussel Arne Hormann +Asta Xie +Bulat Gaifullin Carlos Nieto Chris Moos +Daniel Montoya Daniel Nichter Daniël van Eeden +Dave Protasowski DisposaBoy Egor Smolyakov +Evan Shaw Frederick Mayle Gustavo Kristic Hanno Braun Henri Yandell Hirotaka Yamamoto +ICHINOSE Shogo INADA Naoki Jacek Szwec James Harr +Jeff Hodges +Jeffrey Charles Jian Zhen Joshua Prunier Julien Lefevre Julien Schmidt +Justin Li +Justin Nuß Kamil Dziedzic Kevin Malachowski +Kieron Woodhouse Lennart Rudolph Leonardo YongUk Kim +Linh Tran Tuan +Lion Yang Luca Looz Lucas Liu Luke Scott +Maciej Zimnoch Michael Woolnough Nicola Peduzzi Olivier Mengué +oscarzhao Paul Bonser Peter Schultz +Rebecca Chin Runrioter Wung +Robert Russell +Shuode Li Soroush Pour Stan Putrya Stanley Gunawan @@ -55,5 +74,9 @@ Zhenye Xie # Organizations Barracuda Networks, Inc. +Counting Ltd. Google Inc. +InfoSum Ltd. +Keybase Inc. +Pivotal Inc. Stripe Inc. diff --git a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md deleted file mode 100644 index 6bcad7eaa17..00000000000 --- a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md +++ /dev/null @@ -1,119 +0,0 @@ -## Version 1.3 (2016-12-01) - -Changes: - - - Go 1.1 is no longer supported - - Use decimals fields in MySQL to format time types (#249) - - Buffer optimizations (#269) - - TLS ServerName defaults to the host (#283) - - Refactoring (#400, #410, #437) - - Adjusted documentation for second generation CloudSQL (#485) - - Documented DSN system var quoting rules (#502) - - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512) - -New Features: - - - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249) - - Support for returning table alias on Columns() (#289, #359, #382) - - Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490) - - Support for uint64 parameters with high bit set (#332, #345) - - Cleartext authentication plugin support (#327) - - Exported ParseDSN function and the Config struct (#403, #419, #429) - - Read / Write timeouts (#401) - - Support for JSON field type (#414) - - Support for multi-statements and multi-results (#411, #431) - - DSN parameter to set the driver-side max_allowed_packet value manually (#489) - - Native password authentication plugin support (#494, #524) - -Bugfixes: - - - Fixed handling of queries without columns and rows (#255) - - Fixed a panic when SetKeepAlive() failed (#298) - - Handle ERR packets while reading rows (#321) - - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349) - - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356) - - Actually zero out bytes in handshake response (#378) - - Fixed race condition in registering LOAD DATA INFILE handler (#383) - - Fixed tests with MySQL 5.7.9+ (#380) - - QueryUnescape TLS config names (#397) - - Fixed "broken pipe" error by writing to closed socket (#390) - - Fixed LOAD LOCAL DATA INFILE buffering (#424) - - Fixed parsing of floats into float64 when placeholders are used (#434) - - Fixed DSN tests with Go 1.7+ (#459) - - Handle ERR packets while waiting for EOF (#473) - - Invalidate connection on error while discarding additional results (#513) - - Allow terminating packets of length 0 (#516) - - -## Version 1.2 (2014-06-03) - -Changes: - - - We switched back to a "rolling release". `go get` installs the current master branch again - - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver - - Exported errors to allow easy checking from application code - - Enabled TCP Keepalives on TCP connections - - Optimized INFILE handling (better buffer size calculation, lazy init, ...) - - The DSN parser also checks for a missing separating slash - - Faster binary date / datetime to string formatting - - Also exported the MySQLWarning type - - mysqlConn.Close returns the first error encountered instead of ignoring all errors - - writePacket() automatically writes the packet size to the header - - readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets - -New Features: - - - `RegisterDial` allows the usage of a custom dial function to establish the network connection - - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter - - Logging of critical errors is configurable with `SetLogger` - - Google CloudSQL support - -Bugfixes: - - - Allow more than 32 parameters in prepared statements - - Various old_password fixes - - Fixed TestConcurrent test to pass Go's race detection - - Fixed appendLengthEncodedInteger for large numbers - - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo) - - -## Version 1.1 (2013-11-02) - -Changes: - - - Go-MySQL-Driver now requires Go 1.1 - - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore - - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors - - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")` - - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'. - - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries - - Optimized the buffer for reading - - stmt.Query now caches column metadata - - New Logo - - Changed the copyright header to include all contributors - - Improved the LOAD INFILE documentation - - The driver struct is now exported to make the driver directly accessible - - Refactored the driver tests - - Added more benchmarks and moved all to a separate file - - Other small refactoring - -New Features: - - - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure - - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs - - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used - -Bugfixes: - - - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification - - Convert to DB timezone when inserting `time.Time` - - Splitted packets (more than 16MB) are now merged correctly - - Fixed false positive `io.EOF` errors when the data was fully read - - Avoid panics on reuse of closed connections - - Fixed empty string producing false nil values - - Fixed sign byte for positive TIME fields - - -## Version 1.0 (2013-05-14) - -Initial Release diff --git a/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md b/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md deleted file mode 100644 index 8fe16bcb497..00000000000 --- a/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md +++ /dev/null @@ -1,23 +0,0 @@ -# Contributing Guidelines - -## Reporting Issues - -Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). - -## Contributing Code - -By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. -Don't forget to add yourself to the AUTHORS file. - -### Code Review - -Everyone is invited to review and comment on pull requests. -If it looks fine to you, comment with "LGTM" (Looks good to me). - -If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. - -Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". - -## Development Ideas - -If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. diff --git a/vendor/github.com/go-sql-driver/mysql/README.md b/vendor/github.com/go-sql-driver/mysql/README.md deleted file mode 100644 index a060e3cfd4b..00000000000 --- a/vendor/github.com/go-sql-driver/mysql/README.md +++ /dev/null @@ -1,449 +0,0 @@ -# Go-MySQL-Driver - -A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package - -![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") - ---------------------------------------- - * [Features](#features) - * [Requirements](#requirements) - * [Installation](#installation) - * [Usage](#usage) - * [DSN (Data Source Name)](#dsn-data-source-name) - * [Password](#password) - * [Protocol](#protocol) - * [Address](#address) - * [Parameters](#parameters) - * [Examples](#examples) - * [Connection pool and timeouts](#connection-pool-and-timeouts) - * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support) - * [time.Time support](#timetime-support) - * [Unicode support](#unicode-support) - * [Testing / Development](#testing--development) - * [License](#license) - ---------------------------------------- - -## Features - * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance") - * Native Go implementation. No C-bindings, just pure Go - * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc) - * Automatic handling of broken connections - * Automatic Connection Pooling *(by database/sql package)* - * Supports queries larger than 16MB - * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support. - * Intelligent `LONG DATA` handling in prepared statements - * Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support - * Optional `time.Time` parsing - * Optional placeholder interpolation - -## Requirements - * Go 1.2 or higher - * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) - ---------------------------------------- - -## Installation -Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: -```bash -$ go get github.com/go-sql-driver/mysql -``` -Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. - -## Usage -_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. - -Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: -```go -import "database/sql" -import _ "github.com/go-sql-driver/mysql" - -db, err := sql.Open("mysql", "user:password@/dbname") -``` - -[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples"). - - -### DSN (Data Source Name) - -The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets): -``` -[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] -``` - -A DSN in its fullest form: -``` -username:password@protocol(address)/dbname?param=value -``` - -Except for the databasename, all values are optional. So the minimal DSN is: -``` -/dbname -``` - -If you do not want to preselect a database, leave `dbname` empty: -``` -/ -``` -This has the same effect as an empty DSN string: -``` - -``` - -Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct. - -#### Password -Passwords can consist of any character. Escaping is **not** necessary. - -#### Protocol -See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. -In general you should use an Unix domain socket if available and TCP otherwise for best performance. - -#### Address -For TCP and UDP networks, addresses have the form `host:port`. -If `host` is a literal IPv6 address, it must be enclosed in square brackets. -The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. - -For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`. - -#### Parameters -*Parameters are case-sensitive!* - -Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`. - -##### `allowAllFiles` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files. -[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html) - -##### `allowCleartextPasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowCleartextPasswords=true` allows using the [cleartext client side plugin](http://dev.mysql.com/doc/en/cleartext-authentication-plugin.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network. - -##### `allowNativePasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` -`allowNativePasswords=true` allows the usage of the mysql native password method. - -##### `allowOldPasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` -`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords). - -##### `charset` - -``` -Type: string -Valid Values: -Default: none -``` - -Sets the charset used for client-server interaction (`"SET NAMES "`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`). - -Usage of the `charset` parameter is discouraged because it issues additional queries to the server. -Unless you need the fallback behavior, please use `collation` instead. - -##### `collation` - -``` -Type: string -Valid Values: -Default: utf8_general_ci -``` - -Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail. - -A list of valid charsets for a server is retrievable with `SHOW COLLATION`. - -##### `clientFoundRows` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed. - -##### `columnsWithAlias` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -When `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example: - -``` -SELECT u.id FROM users as u -``` - -will return `u.id` instead of just `id` if `columnsWithAlias=true`. - -##### `interpolateParams` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`. - -*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are blacklisted as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!* - -##### `loc` - -``` -Type: string -Valid Values: -Default: UTC -``` - -Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details. - -Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter. - -Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. - -##### `maxAllowedPacket` -``` -Type: decimal number -Default: 0 -``` - -Max packet size allowed in bytes. Use `maxAllowedPacket=0` to automatically fetch the `max_allowed_packet` variable from server. - -##### `multiStatements` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -Allow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded. - -When `multiStatements` is used, `?` parameters must only be used in the first statement. - -##### `parseTime` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string` - - -##### `readTimeout` - -``` -Type: duration -Default: 0 -``` - -I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - -##### `strict` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`strict=true` enables a driver-side strict mode in which MySQL warnings are treated as errors. This mode should not be used in production as it may lead to data corruption in certain situations. - -A server-side strict mode, which is safe for production use, can be set via the [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) system variable. - -By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes. - -##### `timeout` - -``` -Type: duration -Default: OS default -``` - -Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - -##### `tls` - -``` -Type: bool / string -Valid Values: true, false, skip-verify, -Default: false -``` - -`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). - -##### `writeTimeout` - -``` -Type: duration -Default: 0 -``` - -I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - - -##### System Variables - -Any other parameters are interpreted as system variables: - * `=`: `SET =` - * `=`: `SET =` - * `=%27%27`: `SET =''` - -Rules: -* The values for string variables must be quoted with ' -* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! - (which implies values of string variables must be wrapped with `%27`) - -Examples: - * `autocommit=1`: `SET autocommit=1` - * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` - * [`tx_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `SET tx_isolation='REPEATABLE-READ'` - - -#### Examples -``` -user@unix(/path/to/socket)/dbname -``` - -``` -root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local -``` - -``` -user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true -``` - -Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html): -``` -user:password@/dbname?sql_mode=TRADITIONAL -``` - -TCP via IPv6: -``` -user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci -``` - -TCP on a remote host, e.g. Amazon RDS: -``` -id:password@tcp(your-amazonaws-uri.com:3306)/dbname -``` - -Google Cloud SQL on App Engine (First Generation MySQL Server): -``` -user@cloudsql(project-id:instance-name)/dbname -``` - -Google Cloud SQL on App Engine (Second Generation MySQL Server): -``` -user@cloudsql(project-id:regionname:instance-name)/dbname -``` - -TCP using default port (3306) on localhost: -``` -user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped -``` - -Use the default protocol (tcp) and host (localhost:3306): -``` -user:password@/dbname -``` - -No Database preselected: -``` -user:password@/ -``` - - -### Connection pool and timeouts -The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. - - -### `LOAD DATA LOCAL INFILE` support -For this feature you need direct access to the package. Therefore you must change the import path (no `_`): -```go -import "github.com/go-sql-driver/mysql" -``` - -Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)). - -To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. - -See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. - - -### `time.Time` support -The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your programm. - -However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter. - -**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes). - -Alternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`. - - -### Unicode support -Since version 1.1 Go-MySQL-Driver automatically uses the collation `utf8_general_ci` by default. - -Other collations / charsets can be set using the [`collation`](#collation) DSN parameter. - -Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default. - -See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support. - - -## Testing / Development -To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. - -Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated. -If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls). - -See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/CONTRIBUTING.md) for details. - ---------------------------------------- - -## License -Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) - -Mozilla summarizes the license scope as follows: -> MPL: The copyleft applies to any files containing MPLed code. - - -That means: - * You can **use** the **unchanged** source code both in private and commercially - * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0) - * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged** - -Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license. - -You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) - -![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow") - diff --git a/vendor/github.com/go-sql-driver/mysql/appengine.go b/vendor/github.com/go-sql-driver/mysql/appengine.go index 565614eef7f..be41f2ee6d7 100644 --- a/vendor/github.com/go-sql-driver/mysql/appengine.go +++ b/vendor/github.com/go-sql-driver/mysql/appengine.go @@ -11,7 +11,7 @@ package mysql import ( - "appengine/cloudsql" + "google.golang.org/appengine/cloudsql" ) func init() { diff --git a/vendor/github.com/go-sql-driver/mysql/collations.go b/vendor/github.com/go-sql-driver/mysql/collations.go index 82079cfb93d..136c9e4d1e9 100644 --- a/vendor/github.com/go-sql-driver/mysql/collations.go +++ b/vendor/github.com/go-sql-driver/mysql/collations.go @@ -9,6 +9,7 @@ package mysql const defaultCollation = "utf8_general_ci" +const binaryCollation = "binary" // A list of available collations mapped to the internal ID. // To update this map use the following MySQL query: diff --git a/vendor/github.com/go-sql-driver/mysql/connection.go b/vendor/github.com/go-sql-driver/mysql/connection.go index 08e5fadeb25..e57061412bc 100644 --- a/vendor/github.com/go-sql-driver/mysql/connection.go +++ b/vendor/github.com/go-sql-driver/mysql/connection.go @@ -17,6 +17,16 @@ import ( "time" ) +// a copy of context.Context for Go 1.7 and earlier +type mysqlContext interface { + Done() <-chan struct{} + Err() error + + // defined in context.Context, but not used in this driver: + // Deadline() (deadline time.Time, ok bool) + // Value(key interface{}) interface{} +} + type mysqlConn struct { buf buffer netConn net.Conn @@ -30,7 +40,14 @@ type mysqlConn struct { status statusFlag sequence uint8 parseTime bool - strict bool + + // for context support (Go 1.8+) + watching bool + watcher chan<- mysqlContext + closech chan struct{} + finished chan<- struct{} + canceled atomicError // set non-nil if conn is canceled + closed atomicBool // set when conn is closed, before closech is closed } // Handles parameters set in DSN after the connection is established @@ -63,22 +80,41 @@ func (mc *mysqlConn) handleParams() (err error) { return } +func (mc *mysqlConn) markBadConn(err error) error { + if mc == nil { + return err + } + if err != errBadConnNoWrite { + return err + } + return driver.ErrBadConn +} + func (mc *mysqlConn) Begin() (driver.Tx, error) { - if mc.netConn == nil { + return mc.begin(false) +} + +func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } - err := mc.exec("START TRANSACTION") + var q string + if readOnly { + q = "START TRANSACTION READ ONLY" + } else { + q = "START TRANSACTION" + } + err := mc.exec(q) if err == nil { return &mysqlTx{mc}, err } - - return nil, err + return nil, mc.markBadConn(err) } func (mc *mysqlConn) Close() (err error) { // Makes Close idempotent - if mc.netConn != nil { + if !mc.closed.IsSet() { err = mc.writeCommandPacket(comQuit) } @@ -92,26 +128,39 @@ func (mc *mysqlConn) Close() (err error) { // is called before auth or on auth failure because MySQL will have already // closed the network connection. func (mc *mysqlConn) cleanup() { - // Makes cleanup idempotent - if mc.netConn != nil { - if err := mc.netConn.Close(); err != nil { - errLog.Print(err) - } - mc.netConn = nil + if !mc.closed.TrySet(true) { + return } - mc.cfg = nil - mc.buf.nc = nil + + // Makes cleanup idempotent + close(mc.closech) + if mc.netConn == nil { + return + } + if err := mc.netConn.Close(); err != nil { + errLog.Print(err) + } +} + +func (mc *mysqlConn) error() error { + if mc.closed.IsSet() { + if err := mc.canceled.Value(); err != nil { + return err + } + return ErrInvalidConn + } + return nil } func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { - if mc.netConn == nil { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := mc.writeCommandPacketStr(comStmtPrepare, query) if err != nil { - return nil, err + return nil, mc.markBadConn(err) } stmt := &mysqlStmt{ @@ -145,7 +194,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin if buf == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return "", driver.ErrBadConn + return "", ErrInvalidConn } buf = buf[:0] argPos := 0 @@ -258,7 +307,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin } func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { - if mc.netConn == nil { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } @@ -272,7 +321,6 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err return nil, err } query = prepared - args = nil } mc.affectedRows = 0 mc.insertId = 0 @@ -284,14 +332,14 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err insertId: int64(mc.insertId), }, err } - return nil, err + return nil, mc.markBadConn(err) } // Internal function to execute commands func (mc *mysqlConn) exec(query string) error { // Send command if err := mc.writeCommandPacketStr(comQuery, query); err != nil { - return err + return mc.markBadConn(err) } // Read Result @@ -316,7 +364,11 @@ func (mc *mysqlConn) exec(query string) error { } func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { - if mc.netConn == nil { + return mc.query(query, args) +} + +func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } @@ -330,7 +382,6 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro return nil, err } query = prepared - args = nil } // Send command err := mc.writeCommandPacketStr(comQuery, query) @@ -352,12 +403,13 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro return nil, err } } + // Columns rows.rs.columns, err = mc.readColumns(resLen) return rows, err } } - return nil, err + return nil, mc.markBadConn(err) } // Gets the value of the given MySQL System Variable @@ -389,3 +441,21 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { } return nil, err } + +// finish is called when the query has canceled. +func (mc *mysqlConn) cancel(err error) { + mc.canceled.Set(err) + mc.cleanup() +} + +// finish is called when the query has succeeded. +func (mc *mysqlConn) finish() { + if !mc.watching || mc.finished == nil { + return + } + select { + case mc.finished <- struct{}{}: + mc.watching = false + case <-mc.closech: + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/connection_go18.go b/vendor/github.com/go-sql-driver/mysql/connection_go18.go new file mode 100644 index 00000000000..1306b70b73c --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection_go18.go @@ -0,0 +1,202 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "context" + "database/sql" + "database/sql/driver" +) + +// Ping implements driver.Pinger interface +func (mc *mysqlConn) Ping(ctx context.Context) error { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return driver.ErrBadConn + } + + if err := mc.watchCancel(ctx); err != nil { + return err + } + defer mc.finish() + + if err := mc.writeCommandPacket(comPing); err != nil { + return err + } + if _, err := mc.readResultOK(); err != nil { + return err + } + + return nil +} + +// BeginTx implements driver.ConnBeginTx interface +func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { + level, err := mapIsolationLevel(opts.Isolation) + if err != nil { + return nil, err + } + err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) + if err != nil { + return nil, err + } + } + + return mc.begin(opts.ReadOnly) +} + +func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := mc.query(query, dargs) + if err != nil { + mc.finish() + return nil, err + } + rows.finish = mc.finish + return rows, err +} + +func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + return mc.Exec(query, dargs) +} + +func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + stmt, err := mc.Prepare(query) + mc.finish() + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + stmt.Close() + return nil, ctx.Err() + } + return stmt, nil +} + +func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := stmt.query(dargs) + if err != nil { + stmt.mc.finish() + return nil, err + } + rows.finish = stmt.mc.finish + return rows, err +} + +func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.mc.finish() + + return stmt.Exec(dargs) +} + +func (mc *mysqlConn) watchCancel(ctx context.Context) error { + if mc.watching { + // Reach here if canceled, + // so the connection is already invalid + mc.cleanup() + return nil + } + if ctx.Done() == nil { + return nil + } + + mc.watching = true + select { + default: + case <-ctx.Done(): + return ctx.Err() + } + if mc.watcher == nil { + return nil + } + + mc.watcher <- ctx + + return nil +} + +func (mc *mysqlConn) startWatcher() { + watcher := make(chan mysqlContext, 1) + mc.watcher = watcher + finished := make(chan struct{}) + mc.finished = finished + go func() { + for { + var ctx mysqlContext + select { + case ctx = <-watcher: + case <-mc.closech: + return + } + + select { + case <-ctx.Done(): + mc.cancel(ctx.Err()) + case <-finished: + case <-mc.closech: + return + } + } + }() +} + +func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { + nv.Value, err = converter{}.ConvertValue(nv.Value) + return +} diff --git a/vendor/github.com/go-sql-driver/mysql/const.go b/vendor/github.com/go-sql-driver/mysql/const.go index 88cfff3fd8b..4a19ca52350 100644 --- a/vendor/github.com/go-sql-driver/mysql/const.go +++ b/vendor/github.com/go-sql-driver/mysql/const.go @@ -9,7 +9,8 @@ package mysql const ( - minProtocolVersion byte = 10 + defaultMaxAllowedPacket = 4 << 20 // 4 MiB + minProtocolVersion = 10 maxPacketSize = 1<<24 - 1 timeFormat = "2006-01-02 15:04:05.999999" ) @@ -87,8 +88,10 @@ const ( ) // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType +type fieldType byte + const ( - fieldTypeDecimal byte = iota + fieldTypeDecimal fieldType = iota fieldTypeTiny fieldTypeShort fieldTypeLong @@ -107,7 +110,7 @@ const ( fieldTypeBit ) const ( - fieldTypeJSON byte = iota + 0xf5 + fieldTypeJSON fieldType = iota + 0xf5 fieldTypeNewDecimal fieldTypeEnum fieldTypeSet diff --git a/vendor/github.com/go-sql-driver/mysql/driver.go b/vendor/github.com/go-sql-driver/mysql/driver.go index 0022d1f1e50..d42ce7a3de4 100644 --- a/vendor/github.com/go-sql-driver/mysql/driver.go +++ b/vendor/github.com/go-sql-driver/mysql/driver.go @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. -// Package mysql provides a MySQL driver for Go's database/sql package +// Package mysql provides a MySQL driver for Go's database/sql package. // // The driver should be used via the database/sql package: // @@ -22,6 +22,11 @@ import ( "net" ) +// watcher interface is used for context support (From Go 1.8) +type watcher interface { + startWatcher() +} + // MySQLDriver is exported to make the driver directly accessible. // In general the driver is used via the database/sql package. type MySQLDriver struct{} @@ -52,13 +57,13 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { mc := &mysqlConn{ maxAllowedPacket: maxPacketSize, maxWriteSize: maxPacketSize - 1, + closech: make(chan struct{}), } mc.cfg, err = ParseDSN(dsn) if err != nil { return nil, err } mc.parseTime = mc.cfg.ParseTime - mc.strict = mc.cfg.Strict // Connect to Server if dial, ok := dials[mc.cfg.Net]; ok { @@ -81,6 +86,11 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { } } + // Call startWatcher for context support (From Go 1.8) + if s, ok := interface{}(mc).(watcher); ok { + s.startWatcher() + } + mc.buf = newBuffer(mc.netConn) // Set I/O timeouts diff --git a/vendor/github.com/go-sql-driver/mysql/dsn.go b/vendor/github.com/go-sql-driver/mysql/dsn.go index ac00dcedd51..47eab694574 100644 --- a/vendor/github.com/go-sql-driver/mysql/dsn.go +++ b/vendor/github.com/go-sql-driver/mysql/dsn.go @@ -15,6 +15,7 @@ import ( "fmt" "net" "net/url" + "sort" "strconv" "strings" "time" @@ -27,7 +28,9 @@ var ( errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") ) -// Config is a configuration parsed from a DSN string +// Config is a configuration parsed from a DSN string. +// If a new Config is created instead of being parsed from a DSN string, +// the NewConfig function should be used, which sets default values. type Config struct { User string // Username Passwd string // Password (requires User) @@ -53,7 +56,54 @@ type Config struct { InterpolateParams bool // Interpolate placeholders into query string MultiStatements bool // Allow multiple statements in one query ParseTime bool // Parse time values to time.Time - Strict bool // Return warnings as errors + RejectReadOnly bool // Reject read-only connections +} + +// NewConfig creates a new Config and sets default values. +func NewConfig() *Config { + return &Config{ + Collation: defaultCollation, + Loc: time.UTC, + MaxAllowedPacket: defaultMaxAllowedPacket, + AllowNativePasswords: true, + } +} + +func (cfg *Config) normalize() error { + if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { + return errInvalidDSNUnsafeCollation + } + + // Set default network if empty + if cfg.Net == "" { + cfg.Net = "tcp" + } + + // Set default address if empty + if cfg.Addr == "" { + switch cfg.Net { + case "tcp": + cfg.Addr = "127.0.0.1:3306" + case "unix": + cfg.Addr = "/tmp/mysql.sock" + default: + return errors.New("default addr for network '" + cfg.Net + "' unknown") + } + + } else if cfg.Net == "tcp" { + cfg.Addr = ensureHavePort(cfg.Addr) + } + + if cfg.tls != nil { + if cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify { + host, _, err := net.SplitHostPort(cfg.Addr) + if err == nil { + cfg.tls.ServerName = host + } + } + } + + return nil } // FormatDSN formats the given Config into a DSN string which can be passed to @@ -102,12 +152,12 @@ func (cfg *Config) FormatDSN() string { } } - if cfg.AllowNativePasswords { + if !cfg.AllowNativePasswords { if hasParam { - buf.WriteString("&allowNativePasswords=true") + buf.WriteString("&allowNativePasswords=false") } else { hasParam = true - buf.WriteString("?allowNativePasswords=true") + buf.WriteString("?allowNativePasswords=false") } } @@ -195,12 +245,12 @@ func (cfg *Config) FormatDSN() string { buf.WriteString(cfg.ReadTimeout.String()) } - if cfg.Strict { + if cfg.RejectReadOnly { if hasParam { - buf.WriteString("&strict=true") + buf.WriteString("&rejectReadOnly=true") } else { hasParam = true - buf.WriteString("?strict=true") + buf.WriteString("?rejectReadOnly=true") } } @@ -234,7 +284,7 @@ func (cfg *Config) FormatDSN() string { buf.WriteString(cfg.WriteTimeout.String()) } - if cfg.MaxAllowedPacket > 0 { + if cfg.MaxAllowedPacket != defaultMaxAllowedPacket { if hasParam { buf.WriteString("&maxAllowedPacket=") } else { @@ -247,7 +297,12 @@ func (cfg *Config) FormatDSN() string { // other params if cfg.Params != nil { - for param, value := range cfg.Params { + var params []string + for param := range cfg.Params { + params = append(params, param) + } + sort.Strings(params) + for _, param := range params { if hasParam { buf.WriteByte('&') } else { @@ -257,7 +312,7 @@ func (cfg *Config) FormatDSN() string { buf.WriteString(param) buf.WriteByte('=') - buf.WriteString(url.QueryEscape(value)) + buf.WriteString(url.QueryEscape(cfg.Params[param])) } } @@ -267,10 +322,7 @@ func (cfg *Config) FormatDSN() string { // ParseDSN parses the DSN string to a Config func ParseDSN(dsn string) (cfg *Config, err error) { // New config with some default values - cfg = &Config{ - Loc: time.UTC, - Collation: defaultCollation, - } + cfg = NewConfig() // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] // Find the last '/' (since the password or the net addr might contain a '/') @@ -338,28 +390,9 @@ func ParseDSN(dsn string) (cfg *Config, err error) { return nil, errInvalidDSNNoSlash } - if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { - return nil, errInvalidDSNUnsafeCollation + if err = cfg.normalize(); err != nil { + return nil, err } - - // Set default network if empty - if cfg.Net == "" { - cfg.Net = "tcp" - } - - // Set default address if empty - if cfg.Addr == "" { - switch cfg.Net { - case "tcp": - cfg.Addr = "127.0.0.1:3306" - case "unix": - cfg.Addr = "/tmp/mysql.sock" - default: - return nil, errors.New("default addr for network '" + cfg.Net + "' unknown") - } - - } - return } @@ -374,7 +407,6 @@ func parseDSNParams(cfg *Config, params string) (err error) { // cfg params switch value := param[1]; param[0] { - // Disable INFILE whitelist / enable all files case "allowAllFiles": var isBool bool @@ -472,14 +504,18 @@ func parseDSNParams(cfg *Config, params string) (err error) { return } - // Strict mode - case "strict": + // Reject read-only connections + case "rejectReadOnly": var isBool bool - cfg.Strict, isBool = readBool(value) + cfg.RejectReadOnly, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } + // Strict mode + case "strict": + panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode") + // Dial Timeout case "timeout": cfg.Timeout, err = time.ParseDuration(value) @@ -506,14 +542,7 @@ func parseDSNParams(cfg *Config, params string) (err error) { return fmt.Errorf("invalid value for TLS config name: %v", err) } - if tlsConfig, ok := tlsConfigRegister[name]; ok { - if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify { - host, _, err := net.SplitHostPort(cfg.Addr) - if err == nil { - tlsConfig.ServerName = host - } - } - + if tlsConfig := getTLSConfigClone(name); tlsConfig != nil { cfg.TLSConfig = name cfg.tls = tlsConfig } else { @@ -546,3 +575,10 @@ func parseDSNParams(cfg *Config, params string) (err error) { return } + +func ensureHavePort(addr string) string { + if _, _, err := net.SplitHostPort(addr); err != nil { + return net.JoinHostPort(addr, "3306") + } + return addr +} diff --git a/vendor/github.com/go-sql-driver/mysql/errors.go b/vendor/github.com/go-sql-driver/mysql/errors.go index 857854e1476..760782ff2fb 100644 --- a/vendor/github.com/go-sql-driver/mysql/errors.go +++ b/vendor/github.com/go-sql-driver/mysql/errors.go @@ -9,10 +9,8 @@ package mysql import ( - "database/sql/driver" "errors" "fmt" - "io" "log" "os" ) @@ -31,6 +29,12 @@ var ( ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server") ErrBusyBuffer = errors.New("busy buffer") + + // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. + // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn + // to trigger a resend. + // See https://github.com/go-sql-driver/mysql/pull/302 + errBadConnNoWrite = errors.New("bad connection") ) var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) @@ -59,74 +63,3 @@ type MySQLError struct { func (me *MySQLError) Error() string { return fmt.Sprintf("Error %d: %s", me.Number, me.Message) } - -// MySQLWarnings is an error type which represents a group of one or more MySQL -// warnings -type MySQLWarnings []MySQLWarning - -func (mws MySQLWarnings) Error() string { - var msg string - for i, warning := range mws { - if i > 0 { - msg += "\r\n" - } - msg += fmt.Sprintf( - "%s %s: %s", - warning.Level, - warning.Code, - warning.Message, - ) - } - return msg -} - -// MySQLWarning is an error type which represents a single MySQL warning. -// Warnings are returned in groups only. See MySQLWarnings -type MySQLWarning struct { - Level string - Code string - Message string -} - -func (mc *mysqlConn) getWarnings() (err error) { - rows, err := mc.Query("SHOW WARNINGS", nil) - if err != nil { - return - } - - var warnings = MySQLWarnings{} - var values = make([]driver.Value, 3) - - for { - err = rows.Next(values) - switch err { - case nil: - warning := MySQLWarning{} - - if raw, ok := values[0].([]byte); ok { - warning.Level = string(raw) - } else { - warning.Level = fmt.Sprintf("%s", values[0]) - } - if raw, ok := values[1].([]byte); ok { - warning.Code = string(raw) - } else { - warning.Code = fmt.Sprintf("%s", values[1]) - } - if raw, ok := values[2].([]byte); ok { - warning.Message = string(raw) - } else { - warning.Message = fmt.Sprintf("%s", values[0]) - } - - warnings = append(warnings, warning) - - case io.EOF: - return warnings - - default: - rows.Close() - return - } - } -} diff --git a/vendor/github.com/go-sql-driver/mysql/fields.go b/vendor/github.com/go-sql-driver/mysql/fields.go new file mode 100644 index 00000000000..e1e2ece4b16 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/fields.go @@ -0,0 +1,194 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql" + "reflect" +) + +func (mf *mysqlField) typeDatabaseName() string { + switch mf.fieldType { + case fieldTypeBit: + return "BIT" + case fieldTypeBLOB: + if mf.charSet != collations[binaryCollation] { + return "TEXT" + } + return "BLOB" + case fieldTypeDate: + return "DATE" + case fieldTypeDateTime: + return "DATETIME" + case fieldTypeDecimal: + return "DECIMAL" + case fieldTypeDouble: + return "DOUBLE" + case fieldTypeEnum: + return "ENUM" + case fieldTypeFloat: + return "FLOAT" + case fieldTypeGeometry: + return "GEOMETRY" + case fieldTypeInt24: + return "MEDIUMINT" + case fieldTypeJSON: + return "JSON" + case fieldTypeLong: + return "INT" + case fieldTypeLongBLOB: + if mf.charSet != collations[binaryCollation] { + return "LONGTEXT" + } + return "LONGBLOB" + case fieldTypeLongLong: + return "BIGINT" + case fieldTypeMediumBLOB: + if mf.charSet != collations[binaryCollation] { + return "MEDIUMTEXT" + } + return "MEDIUMBLOB" + case fieldTypeNewDate: + return "DATE" + case fieldTypeNewDecimal: + return "DECIMAL" + case fieldTypeNULL: + return "NULL" + case fieldTypeSet: + return "SET" + case fieldTypeShort: + return "SMALLINT" + case fieldTypeString: + if mf.charSet == collations[binaryCollation] { + return "BINARY" + } + return "CHAR" + case fieldTypeTime: + return "TIME" + case fieldTypeTimestamp: + return "TIMESTAMP" + case fieldTypeTiny: + return "TINYINT" + case fieldTypeTinyBLOB: + if mf.charSet != collations[binaryCollation] { + return "TINYTEXT" + } + return "TINYBLOB" + case fieldTypeVarChar: + if mf.charSet == collations[binaryCollation] { + return "VARBINARY" + } + return "VARCHAR" + case fieldTypeVarString: + if mf.charSet == collations[binaryCollation] { + return "VARBINARY" + } + return "VARCHAR" + case fieldTypeYear: + return "YEAR" + default: + return "" + } +} + +var ( + scanTypeFloat32 = reflect.TypeOf(float32(0)) + scanTypeFloat64 = reflect.TypeOf(float64(0)) + scanTypeInt8 = reflect.TypeOf(int8(0)) + scanTypeInt16 = reflect.TypeOf(int16(0)) + scanTypeInt32 = reflect.TypeOf(int32(0)) + scanTypeInt64 = reflect.TypeOf(int64(0)) + scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) + scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) + scanTypeNullTime = reflect.TypeOf(NullTime{}) + scanTypeUint8 = reflect.TypeOf(uint8(0)) + scanTypeUint16 = reflect.TypeOf(uint16(0)) + scanTypeUint32 = reflect.TypeOf(uint32(0)) + scanTypeUint64 = reflect.TypeOf(uint64(0)) + scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) + scanTypeUnknown = reflect.TypeOf(new(interface{})) +) + +type mysqlField struct { + tableName string + name string + length uint32 + flags fieldFlag + fieldType fieldType + decimals byte + charSet uint8 +} + +func (mf *mysqlField) scanType() reflect.Type { + switch mf.fieldType { + case fieldTypeTiny: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint8 + } + return scanTypeInt8 + } + return scanTypeNullInt + + case fieldTypeShort, fieldTypeYear: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint16 + } + return scanTypeInt16 + } + return scanTypeNullInt + + case fieldTypeInt24, fieldTypeLong: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint32 + } + return scanTypeInt32 + } + return scanTypeNullInt + + case fieldTypeLongLong: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint64 + } + return scanTypeInt64 + } + return scanTypeNullInt + + case fieldTypeFloat: + if mf.flags&flagNotNULL != 0 { + return scanTypeFloat32 + } + return scanTypeNullFloat + + case fieldTypeDouble: + if mf.flags&flagNotNULL != 0 { + return scanTypeFloat64 + } + return scanTypeNullFloat + + case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, + fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, + fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, + fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, + fieldTypeTime: + return scanTypeRawBytes + + case fieldTypeDate, fieldTypeNewDate, + fieldTypeTimestamp, fieldTypeDateTime: + // NullTime is always returned for more consistent behavior as it can + // handle both cases of parseTime regardless if the field is nullable. + return scanTypeNullTime + + default: + return scanTypeUnknown + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/infile.go b/vendor/github.com/go-sql-driver/mysql/infile.go index 547357cfa76..4020f9192e5 100644 --- a/vendor/github.com/go-sql-driver/mysql/infile.go +++ b/vendor/github.com/go-sql-driver/mysql/infile.go @@ -147,7 +147,8 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) { } // send content packets - if err == nil { + // if packetSize == 0, the Reader contains no data + if err == nil && packetSize > 0 { data := make([]byte, 4+packetSize) var n int for err == nil { diff --git a/vendor/github.com/go-sql-driver/mysql/packets.go b/vendor/github.com/go-sql-driver/mysql/packets.go index 41b4d3d5509..d5dfbbae426 100644 --- a/vendor/github.com/go-sql-driver/mysql/packets.go +++ b/vendor/github.com/go-sql-driver/mysql/packets.go @@ -30,9 +30,12 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { // read packet header data, err := mc.buf.readNext(4) if err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return nil, cerr + } errLog.Print(err) mc.Close() - return nil, driver.ErrBadConn + return nil, ErrInvalidConn } // packet length [24 bit] @@ -54,7 +57,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { if prevData == nil { errLog.Print(ErrMalformPkt) mc.Close() - return nil, driver.ErrBadConn + return nil, ErrInvalidConn } return prevData, nil @@ -63,9 +66,12 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { // read packet body [pktLen bytes] data, err = mc.buf.readNext(pktLen) if err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return nil, cerr + } errLog.Print(err) mc.Close() - return nil, driver.ErrBadConn + return nil, ErrInvalidConn } // return data if this was the last packet @@ -125,11 +131,20 @@ func (mc *mysqlConn) writePacket(data []byte) error { // Handle error if err == nil { // n != len(data) + mc.cleanup() errLog.Print(ErrMalformPkt) } else { + if cerr := mc.canceled.Value(); cerr != nil { + return cerr + } + if n == 0 && pktLen == len(data)-4 { + // only for the first loop iteration when nothing was written yet + return errBadConnNoWrite + } + mc.cleanup() errLog.Print(err) } - return driver.ErrBadConn + return ErrInvalidConn } } @@ -263,7 +278,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // ClientFlags [32 bit] @@ -341,7 +356,9 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error { // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error { // User password - scrambleBuff := scrambleOldPassword(cipher, []byte(mc.cfg.Passwd)) + // https://dev.mysql.com/doc/internals/en/old-password-authentication.html + // Old password authentication only need and will need 8-byte challenge. + scrambleBuff := scrambleOldPassword(cipher[:8], []byte(mc.cfg.Passwd)) // Calculate the packet length and add a tailing 0 pktLen := len(scrambleBuff) + 1 @@ -349,7 +366,7 @@ func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add the scrambled password [null terminated string] @@ -368,7 +385,7 @@ func (mc *mysqlConn) writeClearAuthPacket() error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add the clear password [null terminated string] @@ -381,7 +398,9 @@ func (mc *mysqlConn) writeClearAuthPacket() error { // Native password authentication method // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error { - scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd)) + // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html + // Native password authentication only need and will need 20-byte challenge. + scrambleBuff := scramblePassword(cipher[0:20], []byte(mc.cfg.Passwd)) // Calculate the packet length and add a tailing 0 pktLen := len(scrambleBuff) @@ -389,7 +408,7 @@ func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add the scramble @@ -410,7 +429,7 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add command byte @@ -429,7 +448,7 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add command byte @@ -450,7 +469,7 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add command byte @@ -484,25 +503,26 @@ func (mc *mysqlConn) readResultOK() ([]byte, error) { if len(data) > 1 { pluginEndIndex := bytes.IndexByte(data, 0x00) plugin := string(data[1:pluginEndIndex]) - cipher := data[pluginEndIndex+1 : len(data)-1] + cipher := data[pluginEndIndex+1:] - if plugin == "mysql_old_password" { + switch plugin { + case "mysql_old_password": // using old_passwords return cipher, ErrOldPassword - } else if plugin == "mysql_clear_password" { + case "mysql_clear_password": // using clear text password return cipher, ErrCleartextPassword - } else if plugin == "mysql_native_password" { + case "mysql_native_password": // using mysql default authentication method return cipher, ErrNativePassword - } else { + default: return cipher, ErrUnknownPlugin } - } else { - // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest - return nil, ErrOldPassword } + // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest + return nil, ErrOldPassword + default: // Error otherwise return nil, mc.handleErrorPacket(data) } @@ -550,6 +570,22 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error { // Error Number [16 bit uint] errno := binary.LittleEndian.Uint16(data[1:3]) + // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION + // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) + if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { + // Oops; we are connected to a read-only connection, and won't be able + // to issue any write statements. Since RejectReadOnly is configured, + // we throw away this connection hoping this one would have write + // permission. This is specifically for a possible race condition + // during failover (e.g. on AWS Aurora). See README.md for more. + // + // We explicitly close the connection before returning + // driver.ErrBadConn to ensure that `database/sql` purges this + // connection and initiates a new one for next statement next time. + mc.Close() + return driver.ErrBadConn + } + pos := 3 // SQL State [optional: # + 5bytes string] @@ -589,14 +625,7 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error { } // warning count [2 bytes] - if !mc.strict { - return nil - } - pos := 1 + n + m + 2 - if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 { - return mc.getWarnings() - } return nil } @@ -668,14 +697,21 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { if err != nil { return nil, err } + pos += n // Filler [uint8] + pos++ + // Charset [charset, collation uint8] + columns[i].charSet = data[pos] + pos += 2 + // Length [uint32] - pos += n + 1 + 2 + 4 + columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4]) + pos += 4 // Field type [uint8] - columns[i].fieldType = data[pos] + columns[i].fieldType = fieldType(data[pos]) pos++ // Flags [uint16] @@ -808,14 +844,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { // Reserved [8 bit] // Warning count [16 bit uint] - if !stmt.mc.strict { - return columnCount, nil - } - // Check for warnings count > 0, only available in MySQL > 4.1 - if len(data) >= 12 && binary.LittleEndian.Uint16(data[10:12]) > 0 { - return columnCount, stmt.mc.getWarnings() - } return columnCount, nil } return 0, err @@ -887,6 +916,12 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc + // Determine threshould dynamically to avoid packet size shortage. + longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) + if longDataSize < 64 { + longDataSize = 64 + } + // Reset packet-sequence mc.sequence = 0 @@ -900,7 +935,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // command [1 byte] @@ -959,7 +994,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // build NULL-bitmap if arg == nil { nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = fieldTypeNULL + paramTypes[i+i] = byte(fieldTypeNULL) paramTypes[i+i+1] = 0x00 continue } @@ -967,7 +1002,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // cache types and values switch v := arg.(type) { case int64: - paramTypes[i+i] = fieldTypeLongLong + paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x00 if cap(paramValues)-len(paramValues)-8 >= 0 { @@ -983,7 +1018,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { } case float64: - paramTypes[i+i] = fieldTypeDouble + paramTypes[i+i] = byte(fieldTypeDouble) paramTypes[i+i+1] = 0x00 if cap(paramValues)-len(paramValues)-8 >= 0 { @@ -999,7 +1034,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { } case bool: - paramTypes[i+i] = fieldTypeTiny + paramTypes[i+i] = byte(fieldTypeTiny) paramTypes[i+i+1] = 0x00 if v { @@ -1011,10 +1046,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { case []byte: // Common case (non-nil value) first if v != nil { - paramTypes[i+i] = fieldTypeString + paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { + if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) @@ -1029,14 +1064,14 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // Handle []byte(nil) as a NULL value nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = fieldTypeNULL + paramTypes[i+i] = byte(fieldTypeNULL) paramTypes[i+i+1] = 0x00 case string: - paramTypes[i+i] = fieldTypeString + paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { + if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) @@ -1048,20 +1083,22 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { } case time.Time: - paramTypes[i+i] = fieldTypeString + paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - var val []byte + var a [64]byte + var b = a[:0] + if v.IsZero() { - val = []byte("0000-00-00") + b = append(b, "0000-00-00"...) } else { - val = []byte(v.In(mc.cfg.Loc).Format(timeFormat)) + b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat) } paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(val)), + uint64(len(b)), ) - paramValues = append(paramValues, val...) + paramValues = append(paramValues, b...) default: return fmt.Errorf("can not convert type: %T", arg) @@ -1120,10 +1157,11 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { } return io.EOF } + mc := rows.mc rows.mc = nil // Error otherwise - return rows.mc.handleErrorPacket(data) + return mc.handleErrorPacket(data) } // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] @@ -1187,7 +1225,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { continue case fieldTypeFloat: - dest[i] = float32(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))) + dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])) pos += 4 continue diff --git a/vendor/github.com/go-sql-driver/mysql/row_columntypes.go b/vendor/github.com/go-sql-driver/mysql/row_columntypes.go deleted file mode 100644 index 1dbfe472e7b..00000000000 --- a/vendor/github.com/go-sql-driver/mysql/row_columntypes.go +++ /dev/null @@ -1,78 +0,0 @@ -package mysql - -const ( - // In case we get something unexpected - FieldTypeUnknown = "UNKNOWN" - - // Human-readable names for each distinct type byte - FieldTypeNameDecimal = "DECIMAL" - FieldTypeNameTiny = "TINY" - FieldTypeNameShort = "SHORT" - FieldTypeNameLong = "LONG" - FieldTypeNameFloat = "FLOAT" - FieldTypeNameDouble = "DOUBLE" - FieldTypeNameNULL = "NULL" - FieldTypeNameTimestamp = "TIMESTAMP" - FieldTypeNameLongLong = "LONGLONG" - FieldTypeNameInt24 = "INT24" - FieldTypeNameDate = "DATE" - FieldTypeNameTime = "TIME" - FieldTypeNameDateTime = "DATETIME" - FieldTypeNameYear = "YEAR" - FieldTypeNameNewDate = "NEWDATE" - FieldTypeNameVarChar = "VARCHAR" - FieldTypeNameBit = "BIT" - FieldTypeNameJSON = "JSON" - FieldTypeNameNewDecimal = "NEWDECIMAL" - FieldTypeNameEnum = "ENUM" - FieldTypeNameSet = "SET" - FieldTypeNameTinyBLOB = "TINYBLOB" - FieldTypeNameMediumBLOB = "MEDIUMBLOB" - FieldTypeNameLongBLOB = "LONGBLOB" - FieldTypeNameBLOB = "BLOB" - FieldTypeNameVarString = "VARSTRING" - FieldTypeNameString = "STRING" - FieldTypeNameGeometry = "GEOMETRY" -) - -// mapping from each type identifier to human readable string -var mysqlTypeMap = map[byte]string{ - fieldTypeDecimal: FieldTypeNameDecimal, - fieldTypeTiny: FieldTypeNameTiny, - fieldTypeShort: FieldTypeNameShort, - fieldTypeLong: FieldTypeNameLong, - fieldTypeFloat: FieldTypeNameFloat, - fieldTypeDouble: FieldTypeNameDouble, - fieldTypeNULL: FieldTypeNameNULL, - fieldTypeTimestamp: FieldTypeNameTimestamp, - fieldTypeLongLong: FieldTypeNameLongLong, - fieldTypeInt24: FieldTypeNameInt24, - fieldTypeDate: FieldTypeNameDate, - fieldTypeTime: FieldTypeNameTime, - fieldTypeDateTime: FieldTypeNameDateTime, - fieldTypeYear: FieldTypeNameYear, - fieldTypeNewDate: FieldTypeNameNewDate, - fieldTypeVarChar: FieldTypeNameVarChar, - fieldTypeBit: FieldTypeNameBit, - fieldTypeJSON: FieldTypeNameJSON, - fieldTypeNewDecimal: FieldTypeNameNewDecimal, - fieldTypeEnum: FieldTypeNameEnum, - fieldTypeSet: FieldTypeNameSet, - fieldTypeTinyBLOB: FieldTypeNameTinyBLOB, - fieldTypeMediumBLOB: FieldTypeNameMediumBLOB, - fieldTypeLongBLOB: FieldTypeNameLongBLOB, - fieldTypeBLOB: FieldTypeNameBLOB, - fieldTypeVarString: FieldTypeNameVarString, - fieldTypeString: FieldTypeNameString, - fieldTypeGeometry: FieldTypeNameGeometry, -} - -// Make Rows implement the optional RowsColumnTypeDatabaseTypeName interface. -// See https://github.com/golang/go/commit/2a85578b0ecd424e95b29d810b7a414a299fd6a7 -// - (go 1.8 required for this to have any effect) -func (rows *mysqlRows) ColumnTypeDatabaseTypeName(index int) string { - if typeName, ok := mysqlTypeMap[rows.rs.columns[index].fieldType]; ok { - return typeName - } - return FieldTypeUnknown -} diff --git a/vendor/github.com/go-sql-driver/mysql/rows.go b/vendor/github.com/go-sql-driver/mysql/rows.go index 900f548ae5f..d3b1e282217 100644 --- a/vendor/github.com/go-sql-driver/mysql/rows.go +++ b/vendor/github.com/go-sql-driver/mysql/rows.go @@ -11,34 +11,24 @@ package mysql import ( "database/sql/driver" "io" + "math" + "reflect" ) -type mysqlField struct { - tableName string - name string - flags fieldFlag - fieldType byte - decimals byte -} - type resultSet struct { - columns []mysqlField - done bool + columns []mysqlField + columnNames []string + done bool } type mysqlRows struct { - mc *mysqlConn - rs resultSet + mc *mysqlConn + rs resultSet + finish func() } type binaryRows struct { mysqlRows - // stmtCols is a pointer to the statement's cached columns for different - // result sets. - stmtCols *[][]mysqlField - // i is a number of the current result set. It is used to fetch proper - // columns from stmtCols. - i int } type textRows struct { @@ -46,6 +36,10 @@ type textRows struct { } func (rows *mysqlRows) Columns() []string { + if rows.rs.columnNames != nil { + return rows.rs.columnNames + } + columns := make([]string, len(rows.rs.columns)) if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { for i := range columns { @@ -60,16 +54,61 @@ func (rows *mysqlRows) Columns() []string { columns[i] = rows.rs.columns[i].name } } + + rows.rs.columnNames = columns return columns } +func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { + return rows.rs.columns[i].typeDatabaseName() +} + +// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { +// return int64(rows.rs.columns[i].length), true +// } + +func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { + return rows.rs.columns[i].flags&flagNotNULL == 0, true +} + +func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { + column := rows.rs.columns[i] + decimals := int64(column.decimals) + + switch column.fieldType { + case fieldTypeDecimal, fieldTypeNewDecimal: + if decimals > 0 { + return int64(column.length) - 2, decimals, true + } + return int64(column.length) - 1, decimals, true + case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: + return decimals, decimals, true + case fieldTypeFloat, fieldTypeDouble: + if decimals == 0x1f { + return math.MaxInt64, math.MaxInt64, true + } + return math.MaxInt64, decimals, true + } + + return 0, 0, false +} + +func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { + return rows.rs.columns[i].scanType() +} + func (rows *mysqlRows) Close() (err error) { + if f := rows.finish; f != nil { + f() + rows.finish = nil + } + mc := rows.mc if mc == nil { return nil } - if mc.netConn == nil { - return ErrInvalidConn + if err := mc.error(); err != nil { + return err } // Remove unread packets from stream @@ -97,8 +136,8 @@ func (rows *mysqlRows) nextResultSet() (int, error) { if rows.mc == nil { return 0, io.EOF } - if rows.mc.netConn == nil { - return 0, ErrInvalidConn + if err := rows.mc.error(); err != nil { + return 0, err } // Remove unread packets from stream @@ -132,31 +171,20 @@ func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { } } -func (rows *binaryRows) NextResultSet() (err error) { +func (rows *binaryRows) NextResultSet() error { resLen, err := rows.nextNotEmptyResultSet() if err != nil { return err } - // get columns, if not cached, read them and cache them. - if rows.i >= len(*rows.stmtCols) { - rows.rs.columns, err = rows.mc.readColumns(resLen) - *rows.stmtCols = append(*rows.stmtCols, rows.rs.columns) - } else { - rows.rs.columns = (*rows.stmtCols)[rows.i] - if err := rows.mc.readUntilEOF(); err != nil { - return err - } - } - - rows.i++ - return nil + rows.rs.columns, err = rows.mc.readColumns(resLen) + return err } func (rows *binaryRows) Next(dest []driver.Value) error { if mc := rows.mc; mc != nil { - if mc.netConn == nil { - return ErrInvalidConn + if err := mc.error(); err != nil { + return err } // Fetch next row from stream @@ -177,8 +205,8 @@ func (rows *textRows) NextResultSet() (err error) { func (rows *textRows) Next(dest []driver.Value) error { if mc := rows.mc; mc != nil { - if mc.netConn == nil { - return ErrInvalidConn + if err := mc.error(); err != nil { + return err } // Fetch next row from stream diff --git a/vendor/github.com/go-sql-driver/mysql/statement.go b/vendor/github.com/go-sql-driver/mysql/statement.go index b8877167476..98e57bcd8c1 100644 --- a/vendor/github.com/go-sql-driver/mysql/statement.go +++ b/vendor/github.com/go-sql-driver/mysql/statement.go @@ -20,11 +20,10 @@ type mysqlStmt struct { mc *mysqlConn id uint32 paramCount int - columns [][]mysqlField // cached from the first query } func (stmt *mysqlStmt) Close() error { - if stmt.mc == nil || stmt.mc.netConn == nil { + if stmt.mc == nil || stmt.mc.closed.IsSet() { // driver.Stmt.Close can be called more than once, thus this function // has to be idempotent. // See also Issue #450 and golang/go#16019. @@ -46,14 +45,14 @@ func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter { } func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { - if stmt.mc.netConn == nil { + if stmt.mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := stmt.writeExecutePacket(args) if err != nil { - return nil, err + return nil, stmt.mc.markBadConn(err) } mc := stmt.mc @@ -90,14 +89,18 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { } func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { - if stmt.mc.netConn == nil { + return stmt.query(args) +} + +func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { + if stmt.mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := stmt.writeExecutePacket(args) if err != nil { - return nil, err + return nil, stmt.mc.markBadConn(err) } mc := stmt.mc @@ -109,20 +112,10 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { } rows := new(binaryRows) - rows.stmtCols = &stmt.columns if resLen > 0 { rows.mc = mc - rows.i++ - // Columns - // If not cached, read them and cache them - if len(stmt.columns) == 0 { - rows.rs.columns, err = mc.readColumns(resLen) - stmt.columns = append(stmt.columns, rows.rs.columns) - } else { - rows.rs.columns = stmt.columns[0] - err = mc.readUntilEOF() - } + rows.rs.columns, err = mc.readColumns(resLen) } else { rows.rs.done = true @@ -144,6 +137,12 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) { return v, nil } + if v != nil { + if valuer, ok := v.(driver.Valuer); ok { + return valuer.Value() + } + } + rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Ptr: @@ -164,6 +163,16 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) { return int64(u64), nil case reflect.Float32, reflect.Float64: return rv.Float(), nil + case reflect.Bool: + return rv.Bool(), nil + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } + return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) + case reflect.String: + return rv.String(), nil } return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) } diff --git a/vendor/github.com/go-sql-driver/mysql/transaction.go b/vendor/github.com/go-sql-driver/mysql/transaction.go index 33c749b35c4..417d72793b1 100644 --- a/vendor/github.com/go-sql-driver/mysql/transaction.go +++ b/vendor/github.com/go-sql-driver/mysql/transaction.go @@ -13,7 +13,7 @@ type mysqlTx struct { } func (tx *mysqlTx) Commit() (err error) { - if tx.mc == nil || tx.mc.netConn == nil { + if tx.mc == nil || tx.mc.closed.IsSet() { return ErrInvalidConn } err = tx.mc.exec("COMMIT") @@ -22,7 +22,7 @@ func (tx *mysqlTx) Commit() (err error) { } func (tx *mysqlTx) Rollback() (err error) { - if tx.mc == nil || tx.mc.netConn == nil { + if tx.mc == nil || tx.mc.closed.IsSet() { return ErrInvalidConn } err = tx.mc.exec("ROLLBACK") diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go index d523b7ffdff..a92a4029b18 100644 --- a/vendor/github.com/go-sql-driver/mysql/utils.go +++ b/vendor/github.com/go-sql-driver/mysql/utils.go @@ -16,16 +16,21 @@ import ( "fmt" "io" "strings" + "sync" + "sync/atomic" "time" ) var ( + tlsConfigLock sync.RWMutex tlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs ) // RegisterTLSConfig registers a custom tls.Config to be used with sql.Open. // Use the key as a value in the DSN where tls=value. // +// Note: The tls.Config provided to needs to be exclusively owned by the driver after registering. +// // rootCertPool := x509.NewCertPool() // pem, err := ioutil.ReadFile("/path/ca-cert.pem") // if err != nil { @@ -51,19 +56,32 @@ func RegisterTLSConfig(key string, config *tls.Config) error { return fmt.Errorf("key '%s' is reserved", key) } + tlsConfigLock.Lock() if tlsConfigRegister == nil { tlsConfigRegister = make(map[string]*tls.Config) } tlsConfigRegister[key] = config + tlsConfigLock.Unlock() return nil } // DeregisterTLSConfig removes the tls.Config associated with key. func DeregisterTLSConfig(key string) { + tlsConfigLock.Lock() if tlsConfigRegister != nil { delete(tlsConfigRegister, key) } + tlsConfigLock.Unlock() +} + +func getTLSConfigClone(key string) (config *tls.Config) { + tlsConfigLock.RLock() + if v, ok := tlsConfigRegister[key]; ok { + config = cloneTLSConfig(v) + } + tlsConfigLock.RUnlock() + return } // Returns the bool value of the input. @@ -548,8 +566,8 @@ func readLengthEncodedInteger(b []byte) (uint64, bool, int) { if len(b) == 0 { return 0, true, 1 } - switch b[0] { + switch b[0] { // 251: NULL case 0xfb: return 0, true, 1 @@ -738,3 +756,67 @@ func escapeStringQuotes(buf []byte, v string) []byte { return buf[:pos] } + +/****************************************************************************** +* Sync utils * +******************************************************************************/ + +// noCopy may be embedded into structs which must not be copied +// after the first use. +// +// See https://github.com/golang/go/issues/8005#issuecomment-190753527 +// for details. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} + +// atomicBool is a wrapper around uint32 for usage as a boolean value with +// atomic access. +type atomicBool struct { + _noCopy noCopy + value uint32 +} + +// IsSet returns wether the current boolean value is true +func (ab *atomicBool) IsSet() bool { + return atomic.LoadUint32(&ab.value) > 0 +} + +// Set sets the value of the bool regardless of the previous value +func (ab *atomicBool) Set(value bool) { + if value { + atomic.StoreUint32(&ab.value, 1) + } else { + atomic.StoreUint32(&ab.value, 0) + } +} + +// TrySet sets the value of the bool and returns wether the value changed +func (ab *atomicBool) TrySet(value bool) bool { + if value { + return atomic.SwapUint32(&ab.value, 1) == 0 + } + return atomic.SwapUint32(&ab.value, 0) > 0 +} + +// atomicBool is a wrapper for atomically accessed error values +type atomicError struct { + _noCopy noCopy + value atomic.Value +} + +// Set sets the error value regardless of the previous value. +// The value must not be nil +func (ae *atomicError) Set(value error) { + ae.value.Store(value) +} + +// Value returns the current error value +func (ae *atomicError) Value() error { + if v := ae.value.Load(); v != nil { + // this will panic if the value doesn't implement the error interface + return v.(error) + } + return nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go17.go b/vendor/github.com/go-sql-driver/mysql/utils_go17.go new file mode 100644 index 00000000000..f5956345674 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go17.go @@ -0,0 +1,40 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.7 +// +build !go1.8 + +package mysql + +import "crypto/tls" + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return &tls.Config{ + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go18.go b/vendor/github.com/go-sql-driver/mysql/utils_go18.go new file mode 100644 index 00000000000..7d8c9b16ec8 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go18.go @@ -0,0 +1,49 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "crypto/tls" + "database/sql" + "database/sql/driver" + "errors" +) + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return c.Clone() +} + +func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { + dargs := make([]driver.Value, len(named)) + for n, param := range named { + if len(param.Name) > 0 { + // TODO: support the use of Named Parameters #561 + return nil, errors.New("mysql: driver does not support the use of Named Parameters") + } + dargs[n] = param.Value + } + return dargs, nil +} + +func mapIsolationLevel(level driver.IsolationLevel) (string, error) { + switch sql.IsolationLevel(level) { + case sql.LevelRepeatableRead: + return "REPEATABLE READ", nil + case sql.LevelReadCommitted: + return "READ COMMITTED", nil + case sql.LevelReadUncommitted: + return "READ UNCOMMITTED", nil + case sql.LevelSerializable: + return "SERIALIZABLE", nil + default: + return "", errors.New("mysql: unsupported isolation level: " + string(level)) + } +} diff --git a/vendor/github.com/go-stack/stack/.travis.yml b/vendor/github.com/go-stack/stack/.travis.yml deleted file mode 100644 index d5e5dd52da0..00000000000 --- a/vendor/github.com/go-stack/stack/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go -sudo: false -go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - tip - -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover - -script: - - goveralls -service=travis-ci diff --git a/vendor/github.com/go-stack/stack/LICENSE.md b/vendor/github.com/go-stack/stack/LICENSE.md index c8ca66c5ede..2abf98ea835 100644 --- a/vendor/github.com/go-stack/stack/LICENSE.md +++ b/vendor/github.com/go-stack/stack/LICENSE.md @@ -1,13 +1,21 @@ -Copyright 2014 Chris Hines +The MIT License (MIT) -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 +Copyright (c) 2014 Chris Hines - http://www.apache.org/licenses/LICENSE-2.0 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -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. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/go-stack/stack/README.md b/vendor/github.com/go-stack/stack/README.md deleted file mode 100644 index f11ccccaa43..00000000000 --- a/vendor/github.com/go-stack/stack/README.md +++ /dev/null @@ -1,38 +0,0 @@ -[![GoDoc](https://godoc.org/github.com/go-stack/stack?status.svg)](https://godoc.org/github.com/go-stack/stack) -[![Go Report Card](https://goreportcard.com/badge/go-stack/stack)](https://goreportcard.com/report/go-stack/stack) -[![TravisCI](https://travis-ci.org/go-stack/stack.svg?branch=master)](https://travis-ci.org/go-stack/stack) -[![Coverage Status](https://coveralls.io/repos/github/go-stack/stack/badge.svg?branch=master)](https://coveralls.io/github/go-stack/stack?branch=master) - -# stack - -Package stack implements utilities to capture, manipulate, and format call -stacks. It provides a simpler API than package runtime. - -The implementation takes care of the minutia and special cases of interpreting -the program counter (pc) values returned by runtime.Callers. - -## Versioning - -Package stack publishes releases via [semver](http://semver.org/) compatible Git -tags prefixed with a single 'v'. The master branch always contains the latest -release. The develop branch contains unreleased commits. - -## Formatting - -Package stack's types implement fmt.Formatter, which provides a simple and -flexible way to declaratively configure formatting when used with logging or -error tracking packages. - -```go -func DoTheThing() { - c := stack.Caller(0) - log.Print(c) // "source.go:10" - log.Printf("%+v", c) // "pkg/path/source.go:10" - log.Printf("%n", c) // "DoTheThing" - - s := stack.Trace().TrimRuntime() - log.Print(s) // "[source.go:15 caller.go:42 main.go:14]" -} -``` - -See the docs for all of the supported formatting options. diff --git a/vendor/github.com/go-stack/stack/stack.go b/vendor/github.com/go-stack/stack/stack.go index a614eeebf16..1bc6971d889 100644 --- a/vendor/github.com/go-stack/stack/stack.go +++ b/vendor/github.com/go-stack/stack/stack.go @@ -1,3 +1,5 @@ +// +build go1.7 + // Package stack implements utilities to capture, manipulate, and format call // stacks. It provides a simpler API than package runtime. // @@ -21,29 +23,31 @@ import ( // Call records a single function invocation from a goroutine stack. type Call struct { - fn *runtime.Func - pc uintptr + frame runtime.Frame } // Caller returns a Call from the stack of the current goroutine. The argument // skip is the number of stack frames to ascend, with 0 identifying the // calling function. func Caller(skip int) Call { - var pcs [2]uintptr + // As of Go 1.9 we need room for up to three PC entries. + // + // 0. An entry for the stack frame prior to the target to check for + // special handling needed if that prior entry is runtime.sigpanic. + // 1. A possible second entry to hold metadata about skipped inlined + // functions. If inline functions were not skipped the target frame + // PC will be here. + // 2. A third entry for the target frame PC when the second entry + // is used for skipped inline functions. + var pcs [3]uintptr n := runtime.Callers(skip+1, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + frame, _ := frames.Next() + frame, _ = frames.Next() - var c Call - - if n < 2 { - return c + return Call{ + frame: frame, } - - c.pc = pcs[1] - if runtime.FuncForPC(pcs[0]) != sigpanic { - c.pc-- - } - c.fn = runtime.FuncForPC(c.pc) - return c } // String implements fmt.Stinger. It is equivalent to fmt.Sprintf("%v", c). @@ -54,9 +58,10 @@ func (c Call) String() string { // MarshalText implements encoding.TextMarshaler. It formats the Call the same // as fmt.Sprintf("%v", c). func (c Call) MarshalText() ([]byte, error) { - if c.fn == nil { + if c.frame == (runtime.Frame{}) { return nil, ErrNoFunc } + buf := bytes.Buffer{} fmt.Fprint(&buf, c) return buf.Bytes(), nil @@ -71,6 +76,7 @@ var ErrNoFunc = errors.New("no call stack information") // %s source file // %d line number // %n function name +// %k last segment of the package path // %v equivalent to %s:%d // // It accepts the '+' and '#' flags for most of the verbs as follows. @@ -78,22 +84,23 @@ var ErrNoFunc = errors.New("no call stack information") // %+s path of source file relative to the compile time GOPATH // %#s full path of source file // %+n import path qualified function name +// %+k full package path // %+v equivalent to %+s:%d // %#v equivalent to %#s:%d func (c Call) Format(s fmt.State, verb rune) { - if c.fn == nil { + if c.frame == (runtime.Frame{}) { fmt.Fprintf(s, "%%!%c(NOFUNC)", verb) return } switch verb { case 's', 'v': - file, line := c.fn.FileLine(c.pc) + file := c.frame.File switch { case s.Flag('#'): // done case s.Flag('+'): - file = file[pkgIndex(file, c.fn.Name()):] + file = file[pkgIndex(file, c.frame.Function):] default: const sep = "/" if i := strings.LastIndex(file, sep); i != -1 { @@ -103,16 +110,31 @@ func (c Call) Format(s fmt.State, verb rune) { io.WriteString(s, file) if verb == 'v' { buf := [7]byte{':'} - s.Write(strconv.AppendInt(buf[:1], int64(line), 10)) + s.Write(strconv.AppendInt(buf[:1], int64(c.frame.Line), 10)) } case 'd': - _, line := c.fn.FileLine(c.pc) buf := [6]byte{} - s.Write(strconv.AppendInt(buf[:0], int64(line), 10)) + s.Write(strconv.AppendInt(buf[:0], int64(c.frame.Line), 10)) + + case 'k': + name := c.frame.Function + const pathSep = "/" + start, end := 0, len(name) + if i := strings.LastIndex(name, pathSep); i != -1 { + start = i + len(pathSep) + } + const pkgSep = "." + if i := strings.Index(name[start:], pkgSep); i != -1 { + end = start + i + } + if s.Flag('+') { + start = 0 + } + io.WriteString(s, name[start:end]) case 'n': - name := c.fn.Name() + name := c.frame.Function if !s.Flag('+') { const pathSep = "/" if i := strings.LastIndex(name, pathSep); i != -1 { @@ -127,35 +149,17 @@ func (c Call) Format(s fmt.State, verb rune) { } } +// Frame returns the call frame infomation for the Call. +func (c Call) Frame() runtime.Frame { + return c.frame +} + // PC returns the program counter for this call frame; multiple frames may // have the same PC value. +// +// Deprecated: Use Call.Frame instead. func (c Call) PC() uintptr { - return c.pc -} - -// name returns the import path qualified name of the function containing the -// call. -func (c Call) name() string { - if c.fn == nil { - return "???" - } - return c.fn.Name() -} - -func (c Call) file() string { - if c.fn == nil { - return "???" - } - file, _ := c.fn.FileLine(c.pc) - return file -} - -func (c Call) line() int { - if c.fn == nil { - return 0 - } - _, line := c.fn.FileLine(c.pc) - return line + return c.frame.PC } // CallStack records a sequence of function invocations from a goroutine @@ -179,9 +183,6 @@ func (cs CallStack) MarshalText() ([]byte, error) { buf := bytes.Buffer{} buf.Write(openBracketBytes) for i, pc := range cs { - if pc.fn == nil { - return nil, ErrNoFunc - } if i > 0 { buf.Write(spaceBytes) } @@ -205,49 +206,22 @@ func (cs CallStack) Format(s fmt.State, verb rune) { s.Write(closeBracketBytes) } -// findSigpanic intentionally executes faulting code to generate a stack trace -// containing an entry for runtime.sigpanic. -func findSigpanic() *runtime.Func { - var fn *runtime.Func - var p *int - func() int { - defer func() { - if p := recover(); p != nil { - var pcs [512]uintptr - n := runtime.Callers(2, pcs[:]) - for _, pc := range pcs[:n] { - f := runtime.FuncForPC(pc) - if f.Name() == "runtime.sigpanic" { - fn = f - break - } - } - } - }() - // intentional nil pointer dereference to trigger sigpanic - return *p - }() - return fn -} - -var sigpanic = findSigpanic() - // Trace returns a CallStack for the current goroutine with element 0 // identifying the calling function. func Trace() CallStack { var pcs [512]uintptr - n := runtime.Callers(2, pcs[:]) - cs := make([]Call, n) + n := runtime.Callers(1, pcs[:]) - for i, pc := range pcs[:n] { - pcFix := pc - if i > 0 && cs[i-1].fn != sigpanic { - pcFix-- - } - cs[i] = Call{ - fn: runtime.FuncForPC(pcFix), - pc: pcFix, - } + frames := runtime.CallersFrames(pcs[:n]) + cs := make(CallStack, 0, n) + + // Skip extra frame retrieved just to make sure the runtime.sigpanic + // special case is handled. + frame, more := frames.Next() + + for more { + frame, more = frames.Next() + cs = append(cs, Call{frame: frame}) } return cs @@ -256,7 +230,7 @@ func Trace() CallStack { // TrimBelow returns a slice of the CallStack with all entries below c // removed. func (cs CallStack) TrimBelow(c Call) CallStack { - for len(cs) > 0 && cs[0].pc != c.pc { + for len(cs) > 0 && cs[0] != c { cs = cs[1:] } return cs @@ -265,7 +239,7 @@ func (cs CallStack) TrimBelow(c Call) CallStack { // TrimAbove returns a slice of the CallStack with all entries above c // removed. func (cs CallStack) TrimAbove(c Call) CallStack { - for len(cs) > 0 && cs[len(cs)-1].pc != c.pc { + for len(cs) > 0 && cs[len(cs)-1] != c { cs = cs[:len(cs)-1] } return cs @@ -314,12 +288,13 @@ func pkgIndex(file, funcName string) int { var runtimePath string func init() { - var pcs [1]uintptr + var pcs [3]uintptr runtime.Callers(0, pcs[:]) - fn := runtime.FuncForPC(pcs[0]) - file, _ := fn.FileLine(pcs[0]) + frames := runtime.CallersFrames(pcs[:]) + frame, _ := frames.Next() + file := frame.File - idx := pkgIndex(file, fn.Name()) + idx := pkgIndex(frame.File, frame.Function) runtimePath = file[:idx] if runtime.GOOS == "windows" { @@ -328,7 +303,7 @@ func init() { } func inGoroot(c Call) bool { - file := c.file() + file := c.frame.File if len(file) == 0 || file[0] == '?' { return true } diff --git a/vendor/github.com/go-xorm/builder/README.md b/vendor/github.com/go-xorm/builder/README.md deleted file mode 100644 index 1628736374d..00000000000 --- a/vendor/github.com/go-xorm/builder/README.md +++ /dev/null @@ -1,175 +0,0 @@ -# SQL builder - -[![CircleCI](https://circleci.com/gh/go-xorm/builder/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/builder/tree/master) - -Package builder is a lightweight and fast SQL builder for Go and XORM. - -Make sure you have installed Go 1.1+ and then: - - go get github.com/go-xorm/builder - -# Insert - -```Go -sql, args, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL() -``` - -# Select - -```Go -sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL() - -sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})). - RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL() -``` - -# Update - -```Go -sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL() -``` - -# Delete - -```Go -sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL() -``` - -# Conditions - -* `Eq` is a redefine of a map, you can give one or more conditions to `Eq` - -```Go -import . "github.com/go-xorm/builder" - -sql, args, _ := ToSQL(Eq{"a":1}) -// a=? [1] -sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0})) -// b=? AND c=? ["c", 0] -sql, args, _ := ToSQL(Eq{"b":"c", "c":0}) -// b=? AND c=? ["c", 0] -sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"})) -// b=? OR b=? ["c", "d"] -sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}}) -// b IN (?,?) ["c", "d"] -sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}}) -// b=? AND c IN (?,?) [1, 2, 3] -``` - -* `Neq` is the same to `Eq` - -```Go -import . "github.com/go-xorm/builder" - -sql, args, _ := ToSQL(Neq{"a":1}) -// a<>? [1] -sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0})) -// b<>? AND c<>? ["c", 0] -sql, args, _ := ToSQL(Neq{"b":"c", "c":0}) -// b<>? AND c<>? ["c", 0] -sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"})) -// b<>? OR b<>? ["c", "d"] -sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}}) -// b NOT IN (?,?) ["c", "d"] -sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}}) -// b<>? AND c NOT IN (?,?) [1, 2, 3] -``` - -* `Gt`, `Gte`, `Lt`, `Lte` - -```Go -import . "github.com/go-xorm/builder" - -sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2})) -// a>? AND b>=? [1, 2] -sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2})) -// a? [1, %c%, 2] -``` - -* `Or(conds ...Cond)`, Or can connect one or more conditions via Or - -```Go -import . "github.com/go-xorm/builder" - -sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2})) -// a=? OR b LIKE ? OR d<>? [1, %c%, 2] -sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2}))) -// a=? OR (b LIKE ? AND d<>?) [1, %c%, 2] -``` - -* `Between` - -```Go -import . "github.com/go-xorm/builder" - -sql, args, _ := ToSQL(Between{"a", 1, 2}) -// a BETWEEN 1 AND 2 -``` - -* Define yourself conditions - -Since `Cond` is an interface. - -```Go -type Cond interface { - WriteTo(Writer) error - And(...Cond) Cond - Or(...Cond) Cond - IsValid() bool -} -``` - -You can define yourself conditions and compose with other `Cond`. \ No newline at end of file diff --git a/vendor/github.com/go-xorm/builder/builder_select.go b/vendor/github.com/go-xorm/builder/builder_select.go index 05f116e0052..3a3967cccc7 100644 --- a/vendor/github.com/go-xorm/builder/builder_select.go +++ b/vendor/github.com/go-xorm/builder/builder_select.go @@ -45,6 +45,10 @@ func (b *Builder) selectWriteTo(w Writer) error { } } + if !b.cond.IsValid() { + return nil + } + if _, err := fmt.Fprint(w, " WHERE "); err != nil { return err } diff --git a/vendor/github.com/go-xorm/builder/circle.yml b/vendor/github.com/go-xorm/builder/circle.yml deleted file mode 100644 index b2a8bfc9ef4..00000000000 --- a/vendor/github.com/go-xorm/builder/circle.yml +++ /dev/null @@ -1,12 +0,0 @@ -dependencies: - override: - # './...' is a relative pattern which means all subdirectories - - go get -t -d -v ./... - - go build -v - - go get -u github.com/golang/lint/golint - -test: - override: - # './...' is a relative pattern which means all subdirectories - - golint ./... - - go test -v -race \ No newline at end of file diff --git a/vendor/github.com/go-xorm/builder/cond_and.go b/vendor/github.com/go-xorm/builder/cond_and.go index 9c30e9c2e51..e30bd186cdf 100644 --- a/vendor/github.com/go-xorm/builder/cond_and.go +++ b/vendor/github.com/go-xorm/builder/cond_and.go @@ -25,7 +25,9 @@ func And(conds ...Cond) Cond { func (and condAnd) WriteTo(w Writer) error { for i, cond := range and { _, isOr := cond.(condOr) - if isOr { + _, isExpr := cond.(expr) + wrap := isOr || isExpr + if wrap { fmt.Fprint(w, "(") } @@ -34,7 +36,7 @@ func (and condAnd) WriteTo(w Writer) error { return err } - if isOr { + if wrap { fmt.Fprint(w, ")") } diff --git a/vendor/github.com/go-xorm/builder/cond_in.go b/vendor/github.com/go-xorm/builder/cond_in.go index 71093e4b491..f6366d35c2b 100644 --- a/vendor/github.com/go-xorm/builder/cond_in.go +++ b/vendor/github.com/go-xorm/builder/cond_in.go @@ -23,10 +23,8 @@ func In(col string, values ...interface{}) Cond { } func (condIn condIn) handleBlank(w Writer) error { - if _, err := fmt.Fprintf(w, "%s IN ()", condIn.col); err != nil { - return err - } - return nil + _, err := fmt.Fprint(w, "0=1") + return err } func (condIn condIn) WriteTo(w Writer) error { diff --git a/vendor/github.com/go-xorm/builder/cond_notin.go b/vendor/github.com/go-xorm/builder/cond_notin.go index 9be44cb2afe..dc3ac49a358 100644 --- a/vendor/github.com/go-xorm/builder/cond_notin.go +++ b/vendor/github.com/go-xorm/builder/cond_notin.go @@ -20,10 +20,8 @@ func NotIn(col string, values ...interface{}) Cond { } func (condNotIn condNotIn) handleBlank(w Writer) error { - if _, err := fmt.Fprintf(w, "%s NOT IN ()", condNotIn.col); err != nil { - return err - } - return nil + _, err := fmt.Fprint(w, "0=0") + return err } func (condNotIn condNotIn) WriteTo(w Writer) error { diff --git a/vendor/github.com/go-xorm/core/README.md b/vendor/github.com/go-xorm/core/README.md deleted file mode 100644 index 09b72c74b39..00000000000 --- a/vendor/github.com/go-xorm/core/README.md +++ /dev/null @@ -1,116 +0,0 @@ -Core is a lightweight wrapper of sql.DB. - -[![CircleCI](https://circleci.com/gh/go-xorm/core/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/core/tree/master) - -# Open -```Go -db, _ := core.Open(db, connstr) -``` - -# SetMapper -```Go -db.SetMapper(SameMapper()) -``` - -## Scan usage - -### Scan -```Go -rows, _ := db.Query() -for rows.Next() { - rows.Scan() -} -``` - -### ScanMap -```Go -rows, _ := db.Query() -for rows.Next() { - rows.ScanMap() -``` - -### ScanSlice - -You can use `[]string`, `[][]byte`, `[]interface{}`, `[]*string`, `[]sql.NullString` to ScanSclice. Notice, slice's length should be equal or less than select columns. - -```Go -rows, _ := db.Query() -cols, _ := rows.Columns() -for rows.Next() { - var s = make([]string, len(cols)) - rows.ScanSlice(&s) -} -``` - -```Go -rows, _ := db.Query() -cols, _ := rows.Columns() -for rows.Next() { - var s = make([]*string, len(cols)) - rows.ScanSlice(&s) -} -``` - -### ScanStruct -```Go -rows, _ := db.Query() -for rows.Next() { - rows.ScanStructByName() - rows.ScanStructByIndex() -} -``` - -## Query usage -```Go -rows, err := db.Query("select * from table where name = ?", name) - -user = User{ - Name:"lunny", -} -rows, err := db.QueryStruct("select * from table where name = ?Name", - &user) - -var user = map[string]interface{}{ - "name": "lunny", -} -rows, err = db.QueryMap("select * from table where name = ?name", - &user) -``` - -## QueryRow usage -```Go -row := db.QueryRow("select * from table where name = ?", name) - -user = User{ - Name:"lunny", -} -row := db.QueryRowStruct("select * from table where name = ?Name", - &user) - -var user = map[string]interface{}{ - "name": "lunny", -} -row = db.QueryRowMap("select * from table where name = ?name", - &user) -``` - -## Exec usage -```Go -db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)", name, title, age, alias...) - -user = User{ - Name:"lunny", - Title:"test", - Age: 18, -} -result, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) values (?Name,?Title,?Age,?Alias,?NickName,?Created)", - &user) - -var user = map[string]interface{}{ - "Name": "lunny", - "Title": "test", - "Age": 18, -} -result, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name,created) values (?Name,?Title,?Age,?Alias,?NickName,?Created)", - &user) -``` \ No newline at end of file diff --git a/vendor/github.com/go-xorm/core/benchmark.sh b/vendor/github.com/go-xorm/core/benchmark.sh deleted file mode 100755 index eab9e57e9fd..00000000000 --- a/vendor/github.com/go-xorm/core/benchmark.sh +++ /dev/null @@ -1 +0,0 @@ -go test -v -bench=. -run=XXX diff --git a/vendor/github.com/go-xorm/core/circle.yml b/vendor/github.com/go-xorm/core/circle.yml deleted file mode 100644 index 006e1230bcc..00000000000 --- a/vendor/github.com/go-xorm/core/circle.yml +++ /dev/null @@ -1,14 +0,0 @@ -dependencies: - override: - # './...' is a relative pattern which means all subdirectories - - go get -t -d -v ./... - - go build -v - -database: - override: - - mysql -u root -e "CREATE DATABASE core_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - -test: - override: - # './...' is a relative pattern which means all subdirectories - - go test -v -race \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/CONTRIBUTING.md b/vendor/github.com/go-xorm/xorm/CONTRIBUTING.md deleted file mode 100644 index e0f6cfcdf23..00000000000 --- a/vendor/github.com/go-xorm/xorm/CONTRIBUTING.md +++ /dev/null @@ -1,49 +0,0 @@ -## Contributing to xorm - -`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very -much welcome. You can help with patch review, submitting bug reports, -or adding new functionality. There is no formal style guide, but -please conform to the style of existing code and general Go formatting -conventions when submitting patches. - -* [fork a repo](https://help.github.com/articles/fork-a-repo) -* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request) - -### Language - -Since `xorm` is a world-wide open source project, please describe your issues or code changes in English as soon as possible. - -### Sign your codes with comments -``` -// !! your comments - -e.g., - -// !lunny! this is comments made by lunny -``` - -### Patch review - -Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or -proposed functionality. - -### Bug reports - -We appreciate any bug reports, but especially ones with self-contained -(doesn't depend on code outside of xorm), minimal (can't be simplified -further) test cases. It's especially helpful if you can submit a pull -request with just the failing test case (you'll probably want to -pattern it after the tests in -[base.go](https://github.com/go-xorm/tests/blob/master/base.go) AND -[benchmark.go](https://github.com/go-xorm/tests/blob/master/benchmark.go). - -If you implements a new database interface, you maybe need to add a _test.go file. -For example, [mysql_test.go](https://github.com/go-xorm/tests/blob/master/mysql/mysql_test.go) - -### New functionality - -There are a number of pending patches for new functionality, so -additional feature patches will take a while to merge. Still, patches -are generally reviewed based on usefulness and complexity in addition -to time-in-queue, so if you have a knockout idea, take a shot. Feel -free to open an issue discussion your proposed patch beforehand. diff --git a/vendor/github.com/go-xorm/xorm/README.md b/vendor/github.com/go-xorm/xorm/README.md deleted file mode 100644 index bdcbab68cfa..00000000000 --- a/vendor/github.com/go-xorm/xorm/README.md +++ /dev/null @@ -1,279 +0,0 @@ -[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md) - -Xorm is a simple and powerful ORM for Go. - -[![CircleCI](https://circleci.com/gh/go-xorm/xorm/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/xorm/tree/master) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -# Notice - -The last master version is not backwards compatible. You should use `engine.ShowSQL()` and `engine.Logger().SetLevel()` instead of `engine.ShowSQL = `, `engine.ShowInfo = ` and so on. - -# Features - -* Struct <-> Table Mapping Support - -* Chainable APIs - -* Transaction Support - -* Both ORM and raw SQL operation Support - -* Sync database schema Support - -* Query Cache speed up - -* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/cmd/blob/master/README.md) - -* Simple cascade loading support - -* Optimistic Locking support - -* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder) - -# Drivers Support - -Drivers for Go's sql package which currently support database/sql includes: - -* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - -* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) - -* Postgres: [github.com/lib/pq](https://github.com/lib/pq) - -* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb) - -* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - -* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) - -* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment) - -# Changelog - -* **v0.6.0** - * remove support for ql - * add query condition builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder), so `Where`, `And`, `Or` -methods can use `builder.Cond` as parameter - * add Sum, SumInt, SumInt64 and NotIn methods - * some bugs fixed - -* **v0.5.0** - * logging interface changed - * some bugs fixed - -* **v0.4.5** - * many bugs fixed - * extends support unlimited deepth - * Delete Limit support - -* **v0.4.4** - * ql database expriment support - * tidb database expriment support - * sql.NullString and etc. field support - * select ForUpdate support - * many bugs fixed - -[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16) - -# Installation - - go get github.com/go-xorm/xorm - -# Documents - -* [Manual](http://xorm.io/docs) - -* [GoDoc](http://godoc.org/github.com/go-xorm/xorm) - -* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm) - -# Quick Start - -* Create Engine - -```Go -engine, err := xorm.NewEngine(driverName, dataSourceName) -``` - -* Define a struct and Sync2 table struct to database - -```Go -type User struct { - Id int64 - Name string - Salt string - Age int - Passwd string `xorm:"varchar(200)"` - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -err := engine.Sync2(new(User)) -``` - -* Query a SQL string, the returned results is []map[string][]byte - -```Go -results, err := engine.Query("select * from user") -``` - -* Execute a SQL string, the returned results - -```Go -affected, err := engine.Exec("update user set age = ? where name = ?", age, name) -``` - -* Insert one or multiple records to database - -```Go -affected, err := engine.Insert(&user) -// INSERT INTO struct () values () -affected, err := engine.Insert(&user1, &user2) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values () -affected, err := engine.Insert(&users) -// INSERT INTO struct () values (),(),() -affected, err := engine.Insert(&user1, &users) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values (),(),() -``` - -* Query one record from database - -```Go -has, err := engine.Get(&user) -// SELECT * FROM user LIMIT 1 -has, err := engine.Where("name = ?", name).Desc("id").Get(&user) -// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 -``` - -* Query multiple records from database, also you can use join and extends - -```Go -var users []User -err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users) -// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10 - -type Detail struct { - Id int64 - UserId int64 `xorm:"index"` -} - -type UserDetail struct { - User `xorm:"extends"` - Detail `xorm:"extends"` -} - -var users []UserDetail -err := engine.Table("user").Select("user.*, detail.*") - Join("INNER", "detail", "detail.user_id = user.id"). - Where("user.name = ?", name).Limit(10, 0). - Find(&users) -// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10 -``` - -* Query multiple records and record by record handle, there are two methods Iterate and Rows - -```Go -err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error { - user := bean.(*User) - return nil -}) -// SELECT * FROM user - -rows, err := engine.Rows(&User{Name:name}) -// SELECT * FROM user -defer rows.Close() -bean := new(Struct) -for rows.Next() { - err = rows.Scan(bean) -} -``` - -* Update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on. - -```Go -affected, err := engine.Id(1).Update(&user) -// UPDATE user SET ... Where id = ? - -affected, err := engine.Update(&user, &User{Name:name}) -// UPDATE user SET ... Where name = ? - -var ids = []int64{1, 2, 3} -affected, err := engine.In("id", ids).Update(&user) -// UPDATE user SET ... Where id IN (?, ?, ?) - -// force update indicated columns by Cols -affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -// force NOT update indicated columns by Omit -affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -affected, err := engine.Id(1).AllCols().Update(&user) -// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? -``` - -* Delete one or more records, Delete MUST have condition - -```Go -affected, err := engine.Where(...).Delete(&user) -// DELETE FROM user Where ... -affected, err := engine.Id(2).Delete(&user) -``` - -* Count records - -```Go -counts, err := engine.Count(&user) -// SELECT count(*) AS total FROM user -``` - -* Query conditions builder - -```Go -err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users) -// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?) -``` - -# Cases - -* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader) - -* [Wego](http://github.com/go-tango/wego) - -* [Docker.cn](https://docker.cn/) - -* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) - -* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel) - -* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) - -* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) - -* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) - -* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) - -* [YouGam](http://www.yougam.com/) - -* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) - -* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/) - -* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog) - -# Discuss - -Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) - -# Contributing - -If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md) - -# LICENSE - - BSD License - [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) diff --git a/vendor/github.com/go-xorm/xorm/README_CN.md b/vendor/github.com/go-xorm/xorm/README_CN.md deleted file mode 100644 index fafef1a5d84..00000000000 --- a/vendor/github.com/go-xorm/xorm/README_CN.md +++ /dev/null @@ -1,280 +0,0 @@ -# xorm - -[English](https://github.com/go-xorm/xorm/blob/master/README.md) - -xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 - -[![CircleCI](https://circleci.com/gh/go-xorm/xorm/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/xorm/tree/master) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-xorm/xorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -# 注意 - -最新的版本有不兼容的更新,您必须使用 `engine.ShowSQL()` 和 `engine.Logger().SetLevel()` 来替代 `engine.ShowSQL = `, `engine.ShowInfo = ` 等等。 - -## 特性 - -* 支持Struct和数据库表之间的灵活映射,并支持自动同步 - -* 事务支持 - -* 同时支持原始SQL语句和ORM操作的混合执行 - -* 使用连写来简化调用 - -* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件 - -* 支持级联加载Struct - -* 支持缓存 - -* 支持根据数据库自动生成xorm的结构体 - -* 支持记录版本(即乐观锁) - -* 内置SQL Builder支持 - -## 驱动支持 - -目前支持的Go数据库驱动和对应的数据库如下: - -* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - -* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) - -* Postgres: [github.com/lib/pq](https://github.com/lib/pq) - -* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb) - -* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - -* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) - -* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc) - -* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持) - -## 更新日志 - -* **v0.6.0** - * 去除对 ql 的支持 - * 新增条件查询分析器 [github.com/go-xorm/builder](https://github.com/go-xorm/builder), 从因此 `Where, And, Or` 函数 -将可以用 `builder.Cond` 作为条件组合 - * 新增 Sum, SumInt, SumInt64 和 NotIn 函数 - * Bug修正 - -* **v0.5.0** - * logging接口进行不兼容改变 - * Bug修正 - -* **v0.4.5** - * bug修正 - * extends 支持无限级 - * Delete Limit 支持 - -* **v0.4.4** - * Tidb 数据库支持 - * QL 试验性支持 - * sql.NullString支持 - * ForUpdate 支持 - * bug修正 - -[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16) - -## 安装 - - go get github.com/go-xorm/xorm - -## 文档 - -* [操作指南](http://xorm.io/docs) - -* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm) - -* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm) - -# 快速开始 - -* 第一步创建引擎,driverName, dataSourceName和database/sql接口相同 - -```Go -engine, err := xorm.NewEngine(driverName, dataSourceName) -``` - -* 定义一个和表同步的结构体,并且自动同步结构体到数据库 - -```Go -type User struct { - Id int64 - Name string - Salt string - Age int - Passwd string `xorm:"varchar(200)"` - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -err := engine.Sync2(new(User)) -``` - -* 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte - -```Go -results, err := engine.Query("select * from user") -``` - -* 执行一个SQL语句 - -```Go -affected, err := engine.Exec("update user set age = ? where name = ?", age, name) -``` - -* 插入一条或者多条记录 - -```Go -affected, err := engine.Insert(&user) -// INSERT INTO struct () values () -affected, err := engine.Insert(&user1, &user2) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values () -affected, err := engine.Insert(&users) -// INSERT INTO struct () values (),(),() -affected, err := engine.Insert(&user1, &users) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values (),(),() -``` - -* 查询单条记录 - -```Go -has, err := engine.Get(&user) -// SELECT * FROM user LIMIT 1 -has, err := engine.Where("name = ?", name).Desc("id").Get(&user) -// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 -``` - -* 查询多条记录,当然可以使用Join和extends来组合使用 - -```Go -var users []User -err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users) -// SELECT * FROM user WHERE name = ? AND age > 10 limit 0 offset 10 - -type Detail struct { - Id int64 - UserId int64 `xorm:"index"` -} - -type UserDetail struct { - User `xorm:"extends"` - Detail `xorm:"extends"` -} - -var users []UserDetail -err := engine.Table("user").Select("user.*, detail.*") - Join("INNER", "detail", "detail.user_id = user.id"). - Where("user.name = ?", name).Limit(10, 0). - Find(&users) -// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 0 offset 10 -``` - -* 根据条件遍历数据库,可以有两种方式: Iterate and Rows - -```Go -err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error { - user := bean.(*User) - return nil -}) -// SELECT * FROM user - -rows, err := engine.Rows(&User{Name:name}) -// SELECT * FROM user -defer rows.Close() -bean := new(Struct) -for rows.Next() { - err = rows.Scan(bean) -} -``` - -* 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段 - -```Go -affected, err := engine.Id(1).Update(&user) -// UPDATE user SET ... Where id = ? - -affected, err := engine.Update(&user, &User{Name:name}) -// UPDATE user SET ... Where name = ? - -var ids = []int64{1, 2, 3} -affected, err := engine.In(ids).Update(&user) -// UPDATE user SET ... Where id IN (?, ?, ?) - -// force update indicated columns by Cols -affected, err := engine.Id(1).Cols("age").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -// force NOT update indicated columns by Omit -affected, err := engine.Id(1).Omit("name").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -affected, err := engine.Id(1).AllCols().Update(&user) -// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? -``` - -* 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable - -```Go -affected, err := engine.Where(...).Delete(&user) -// DELETE FROM user Where ... -``` - -* 获取记录条数 - -```Go -counts, err := engine.Count(&user) -// SELECT count(*) AS total FROM user -``` - -* 条件编辑器 - -```Go -err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users) -// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?) -``` - -# 案例 - -* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader) - -* [Wego](http://github.com/go-tango/wego) - -* [Docker.cn](https://docker.cn/) - -* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) - -* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) - -* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) - -* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) - -* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) - -* [YouGam](http://www.yougam.com/) - -* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) - -* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/) - -* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog) - -## 讨论 - -请加入QQ群:280360085 进行讨论。 - -## 贡献 - -如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md) - -## LICENSE - -BSD License -[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) diff --git a/vendor/github.com/go-xorm/xorm/VERSION b/vendor/github.com/go-xorm/xorm/VERSION deleted file mode 100644 index 22c1aa4d020..00000000000 --- a/vendor/github.com/go-xorm/xorm/VERSION +++ /dev/null @@ -1 +0,0 @@ -xorm v0.6.0.1022 \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/circle.yml b/vendor/github.com/go-xorm/xorm/circle.yml deleted file mode 100644 index 8faa627d102..00000000000 --- a/vendor/github.com/go-xorm/xorm/circle.yml +++ /dev/null @@ -1,25 +0,0 @@ -dependencies: - override: - # './...' is a relative pattern which means all subdirectories - - go get -t -d -v ./... - - go get -t -d -v github.com/go-xorm/tests - - go build -v - -database: - override: - - mysql -u root -e "CREATE DATABASE xorm_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - mysql -u root -e "CREATE DATABASE xorm_test1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - mysql -u root -e "CREATE DATABASE xorm_test2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - mysql -u root -e "CREATE DATABASE xorm_test3 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" - - createdb -p 5432 -e -U postgres xorm_test - - createdb -p 5432 -e -U postgres xorm_test1 - - createdb -p 5432 -e -U postgres xorm_test2 - - createdb -p 5432 -e -U postgres xorm_test3 - -test: - override: - # './...' is a relative pattern which means all subdirectories - - go test -v -race - - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh - - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh - - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/docs/README.md b/vendor/github.com/go-xorm/xorm/docs/README.md deleted file mode 100644 index 6befd969b7d..00000000000 --- a/vendor/github.com/go-xorm/xorm/docs/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Xorm Manuals - -Please visit [xorm.io/docs](http://xorm.io/docs) - -# Contributing - -If you have any suggestion about docs, please pull request. \ No newline at end of file diff --git a/vendor/github.com/go-xorm/xorm/docs/images/cache_design.graffle b/vendor/github.com/go-xorm/xorm/docs/images/cache_design.graffle deleted file mode 100644 index 5b7c487b7dd..00000000000 --- a/vendor/github.com/go-xorm/xorm/docs/images/cache_design.graffle +++ /dev/null @@ -1,2295 +0,0 @@ - - - - - ActiveLayerIndex - 0 - ApplicationVersion - - com.omnigroup.OmniGrafflePro - 139.16.0.171715 - - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {771, 554.18930041152259}} - Class - SolidGraphic - ID - 2 - Style - - fill - - Color - - b - 0.989303 - g - 0.907286 - r - 0.795377 - - FillType - 2 - GradientAngle - 78 - GradientColor - - b - 1 - g - 0.854588 - r - 0.623912 - - MiddleColor - - b - 1 - g - 0.856844 - r - 0.43695 - - TrippleBlend - YES - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - BaseZoom - 0 - CanvasOrigin - {0, 0} - CanvasSize - {771, 554.18930041152259} - ColumnAlign - 1 - ColumnSpacing - 36 - CreationDate - 2013-09-29 07:57:57 +0000 - Creator - Lunny Xiao - DisplayScale - 1.000 cm = 1.000 cm - FileType - flat - GraphDocumentVersion - 8 - GraphicsList - - - Bounds - {{409.89504441572683, 415.64570506990464}, {104.42639923095703, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 30 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 .\ -.\ -.\ -} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{276.44083898205287, 413.07252538018992}, {112.36092376708984, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 29 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 .\ -.\ -.} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{409.89504441572689, 337.17180246145824}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 28 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 user-2:User\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{274.32251833907753, 322.94787397618234}, {112.36092376708984, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 27 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 select id from tb3:[2,5]} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{406.08888702072045, 256.42244420026987}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 25 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 user-2:User\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{406.08888302813585, 187.47137690331695}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 24 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 table-1:Table\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{406.08887903555114, 118.52029512620169}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 23 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 user-1:User\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{556.54055354053583, 325.93280718390133}, {124.41892177446698, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 22 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Del(k, v)} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{556.54055354053583, 240.81081643580876}, {124.41892177446698, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 21 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Put(k, v)} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{556.54054526129187, 150.52220626433376}, {124.41893005371094, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 20 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Get(k, v)} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{276.44083898205287, 214.72973288487913}, {112.36092376708984, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 19 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 select id from tb2:[2,5]} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{274.32251963877655, 117.18245433711769}, {112.36092376708984, 68.777008056640625}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 18 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 select id from tb1:[1,2,3]} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{103.00000194954862, 30.108108889738791}, {80, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 14 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset134 STHeitiSC-Light;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{532.04631600645348, 25.096524339927051}, {166.93052673339844, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 13 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;\f1\fnil\fcharset134 STHeitiSC-Light;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Cache\ - -\f1 Store} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{298.9845516069733, 37.412179328792348}, {173.03089904785156, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 17 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 LRUCacher} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{99.822519035537013, 333.12161552787364}, {88, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - NSKern - 0.0 - Size - 15 - - ID - 12 - Magnets - - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - fill - - Color - - b - 0.806569 - g - 0.806569 - r - 0.806569 - - FillType - 2 - GradientAngle - 90 - GradientColor - - w - 0.653285 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.2 - g - 0.2 - r - 0.2 - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\fs30 \cf0 \expnd0\expndtw0\kerning0 -Delet\ -SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{97.118322659032714, 226.09466078541047}, {88, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0 - g - 0 - r - 0.501961 - - Font - Verdana - NSKern - 0.0 - Size - 15 - - ID - 15 - Magnets - - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - fill - - Color - - b - 0 - g - 0.389485 - r - 1 - - FillType - 3 - GradientCenter - {-0.34285700000000002, -0.114286} - GradientColor - - b - 0 - g - 0.495748 - r - 1 - - MiddleColor - - b - 0 - g - 0.887657 - r - 1 - - MiddleFraction - 0.6269841194152832 - TrippleBlend - YES - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.2 - g - 0.2 - r - 0.2 - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red128\green0\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\fs30 \cf2 \expnd0\expndtw0\kerning0 -Update\ -SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{103, 123.08108395608006}, {80, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.821332 - g - 0.672602 - r - 0.928374 - - Font - Verdana - Size - 18 - - ID - 16 - Shape - Rectangle - Style - - fill - - Color - - b - 0.436973 - g - 0.155566 - r - 0.758999 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.25098 - g - 0 - r - 0.501961 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset134 STHeitiSC-Light;\f1\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red237\green172\blue209;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 select -\f1 -\f0 SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - GridInfo - - GuidesLocked - NO - GuidesVisible - YES - HPages - 2 - ImageCounter - 3 - KeepToScale - - Layers - - - Lock - NO - Name - 图层 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - AutoLayout - 2 - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - neato - neatoLineLength - 0.92083334922790527 - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - LinksVisible - NO - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2013-09-29 08:24:57 +0000 - Modifier - Lunny Xiao - NotesVisible - NO - Orientation - 2 - OriginVisible - NO - OutlineStyle - Brainstorming/Clouds - PageBreaks - NO - PrintInfo - - NSBottomMargin - - float - 41 - - NSHorizonalPagination - - coded - BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG - - NSLeftMargin - - float - 18 - - NSPaperSize - - size - {595, 842} - - NSPrintReverseOrientation - - int - 0 - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - PrintOnePage - - ReadOnly - NO - RowAlign - 1 - RowSpacing - 36 - SheetTitle - 版面 1 - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UniqueID - 1 - UseEntirePage - - VPages - 1 - WindowInfo - - CurrentSheet - 0 - ExpandedCanvases - - FitInWindow - - Frame - {{138, 197}, {869, 617}} - ListView - - OutlineWidth - 142 - RightSidebar - - Sidebar - - SidebarWidth - 138 - VisibleRegion - {{1.0591603214876664, 1.0591603214876664}, {770.00955372153339, 553.94084813804955}} - Zoom - 0.94414412975311279 - ZoomValues - - - 版面 1 - 0.0 - 1 - - - - - diff --git a/vendor/github.com/go-xorm/xorm/docs/images/cache_design.png b/vendor/github.com/go-xorm/xorm/docs/images/cache_design.png deleted file mode 100644 index 78796b56833..00000000000 Binary files a/vendor/github.com/go-xorm/xorm/docs/images/cache_design.png and /dev/null differ diff --git a/vendor/github.com/go-xorm/xorm/examples/cache.go b/vendor/github.com/go-xorm/xorm/examples/cache.go deleted file mode 100644 index a86dfd2d1b9..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/cache.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -func main() { - f := "cache.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL = true - cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) - Orm.SetDefaultCacher(cacher) - - err = Orm.CreateTables(&User{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = Orm.Insert(&User{Name: "xlw"}) - if err != nil { - fmt.Println(err) - return - } - - users := make([]User, 0) - err = Orm.Find(&users) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("users:", users) - - users2 := make([]User, 0) - - err = Orm.Find(&users2) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("users2:", users2) - - users3 := make([]User, 0) - - err = Orm.Find(&users3) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("users3:", users3) - - user4 := new(User) - has, err := Orm.Id(1).Get(user4) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("user4:", has, user4) - - user4.Name = "xiaolunwen" - _, err = Orm.Id(1).Update(user4) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("user4:", user4) - - user5 := new(User) - has, err = Orm.Id(1).Get(user5) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("user5:", has, user5) - - _, err = Orm.Id(1).Delete(new(User)) - if err != nil { - fmt.Println(err) - return - } - - for { - user6 := new(User) - has, err = Orm.Id(1).Get(user6) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("user6:", has, user6) - } -} diff --git a/vendor/github.com/go-xorm/xorm/examples/cachegoroutine.go b/vendor/github.com/go-xorm/xorm/examples/cachegoroutine.go deleted file mode 100644 index 0e50f5adfa7..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/cachegoroutine.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "fmt" - "os" - "time" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -func sqliteEngine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./goroutine.db") -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -var u *User = &User{} - -func test(engine *xorm.Engine) { - err := engine.CreateTables(u) - if err != nil { - fmt.Println(err) - return - } - - size := 500 - queue := make(chan int, size) - - for i := 0; i < size; i++ { - go func(x int) { - //x := i - err := engine.Ping() - if err != nil { - fmt.Println(err) - } else { - for j := 0; j < 10; j++ { - if x+j < 2 { - _, err = engine.Get(u) - } else if x+j < 4 { - users := make([]User, 0) - err = engine.Find(&users) - } else if x+j < 8 { - _, err = engine.Count(u) - } else if x+j < 16 { - _, err = engine.Insert(&User{Name: "xlw"}) - } else if x+j < 32 { - //_, err = engine.Id(1).Delete(u) - _, err = engine.Delete(u) - } - if err != nil { - fmt.Println(err) - queue <- x - return - } - } - fmt.Printf("%v success!\n", x) - } - queue <- x - }(i) - } - - for i := 0; i < size; i++ { - <-queue - } - - //conns := atomic.LoadInt32(&xorm.ConnectionNum) - //fmt.Println("connection number:", conns) - fmt.Println("end") -} - -func main() { - fmt.Println("-----start sqlite go routines-----") - engine, err := sqliteEngine() - if err != nil { - fmt.Println(err) - return - } - engine.ShowSQL = true - cacher := xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) - engine.SetDefaultCacher(cacher) - fmt.Println(engine) - test(engine) - fmt.Println("test end") - engine.Close() - - fmt.Println("-----start mysql go routines-----") - engine, err = mysqlEngine() - engine.ShowSQL = true - cacher = xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) - engine.SetDefaultCacher(cacher) - if err != nil { - fmt.Println(err) - return - } - defer engine.Close() - test(engine) -} diff --git a/vendor/github.com/go-xorm/xorm/examples/conversion.go b/vendor/github.com/go-xorm/xorm/examples/conversion.go deleted file mode 100644 index 1a74dea8cd4..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/conversion.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type Status struct { - Name string - Color string -} - -var ( - Registed Status = Status{"Registed", "white"} - Approved Status = Status{"Approved", "green"} - Removed Status = Status{"Removed", "red"} - Statuses map[string]Status = map[string]Status{ - Registed.Name: Registed, - Approved.Name: Approved, - Removed.Name: Removed, - } -) - -func (s *Status) FromDB(bytes []byte) error { - if r, ok := Statuses[string(bytes)]; ok { - *s = r - return nil - } else { - return errors.New("no this data") - } -} - -func (s *Status) ToDB() ([]byte, error) { - return []byte(s.Name), nil -} - -type User struct { - Id int64 - Name string - Status Status `xorm:"varchar(40)"` -} - -func main() { - f := "conversion.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL = true - err = Orm.CreateTables(&User{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = Orm.Insert(&User{1, "xlw", Registed}) - if err != nil { - fmt.Println(err) - return - } - - users := make([]User, 0) - err = Orm.Find(&users) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(users) -} diff --git a/vendor/github.com/go-xorm/xorm/examples/derive.go b/vendor/github.com/go-xorm/xorm/examples/derive.go deleted file mode 100644 index 2a340060efb..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/derive.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -type LoginInfo struct { - Id int64 - IP string - UserId int64 -} - -type LoginInfo1 struct { - LoginInfo `xorm:"extends"` - UserName string -} - -func main() { - f := "derive.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - defer Orm.Close() - Orm.ShowSQL = true - err = Orm.CreateTables(&User{}, &LoginInfo{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = Orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1}) - if err != nil { - fmt.Println(err) - return - } - - info := LoginInfo{} - _, err = Orm.Id(1).Get(&info) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(info) - - infos := make([]LoginInfo1, 0) - err = Orm.Sql(`select *, (select name from user where id = login_info.user_id) as user_name from - login_info limit 10`).Find(&infos) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(infos) -} diff --git a/vendor/github.com/go-xorm/xorm/examples/goroutine.go b/vendor/github.com/go-xorm/xorm/examples/goroutine.go deleted file mode 100644 index f99c9fbe472..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/goroutine.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "fmt" - "os" - "runtime" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -func sqliteEngine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./goroutine.db") -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -var u *User = &User{} - -func test(engine *xorm.Engine) { - err := engine.CreateTables(u) - if err != nil { - fmt.Println(err) - return - } - - size := 100 - queue := make(chan int, size) - - for i := 0; i < size; i++ { - go func(x int) { - //x := i - err := engine.Ping() - if err != nil { - fmt.Println(err) - } else { - /*err = engine.(u) - if err != nil { - fmt.Println("Map user failed") - } else {*/ - for j := 0; j < 10; j++ { - if x+j < 2 { - _, err = engine.Get(u) - } else if x+j < 4 { - users := make([]User, 0) - err = engine.Find(&users) - } else if x+j < 8 { - _, err = engine.Count(u) - } else if x+j < 16 { - _, err = engine.Insert(&User{Name: "xlw"}) - } else if x+j < 32 { - _, err = engine.Id(1).Delete(u) - } - if err != nil { - fmt.Println(err) - queue <- x - return - } - } - fmt.Printf("%v success!\n", x) - //} - } - queue <- x - }(i) - } - - for i := 0; i < size; i++ { - <-queue - } - - //conns := atomic.LoadInt32(&xorm.ConnectionNum) - //fmt.Println("connection number:", conns) - fmt.Println("end") -} - -func main() { - runtime.GOMAXPROCS(2) - fmt.Println("-----start sqlite go routines-----") - engine, err := sqliteEngine() - if err != nil { - fmt.Println(err) - return - } - engine.ShowSQL = true - fmt.Println(engine) - test(engine) - fmt.Println("test end") - engine.Close() - - fmt.Println("-----start mysql go routines-----") - engine, err = mysqlEngine() - if err != nil { - fmt.Println(err) - return - } - defer engine.Close() - test(engine) -} diff --git a/vendor/github.com/go-xorm/xorm/examples/maxconnect.go b/vendor/github.com/go-xorm/xorm/examples/maxconnect.go deleted file mode 100644 index 5f239d1e529..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/maxconnect.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "fmt" - "os" - "runtime" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -func sqliteEngine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./goroutine.db") -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -var u *User = &User{} - -func test(engine *xorm.Engine) { - err := engine.CreateTables(u) - if err != nil { - fmt.Println(err) - return - } - - engine.ShowSQL = true - engine.SetMaxOpenConns(5) - - size := 1000 - queue := make(chan int, size) - - for i := 0; i < size; i++ { - go func(x int) { - //x := i - err := engine.Ping() - if err != nil { - fmt.Println(err) - } else { - /*err = engine.Map(u) - if err != nil { - fmt.Println("Map user failed") - } else {*/ - for j := 0; j < 10; j++ { - if x+j < 2 { - _, err = engine.Get(u) - } else if x+j < 4 { - users := make([]User, 0) - err = engine.Find(&users) - } else if x+j < 8 { - _, err = engine.Count(u) - } else if x+j < 16 { - _, err = engine.Insert(&User{Name: "xlw"}) - } else if x+j < 32 { - _, err = engine.Id(1).Delete(u) - } - if err != nil { - fmt.Println(err) - queue <- x - return - } - } - fmt.Printf("%v success!\n", x) - //} - } - queue <- x - }(i) - } - - for i := 0; i < size; i++ { - <-queue - } - - fmt.Println("end") -} - -func main() { - runtime.GOMAXPROCS(2) - fmt.Println("create engine") - engine, err := sqliteEngine() - if err != nil { - fmt.Println(err) - return - } - engine.ShowSQL = true - fmt.Println(engine) - test(engine) - fmt.Println("------------------------") - engine.Close() - - engine, err = mysqlEngine() - if err != nil { - fmt.Println(err) - return - } - defer engine.Close() - test(engine) -} diff --git a/vendor/github.com/go-xorm/xorm/examples/singlemapping.go b/vendor/github.com/go-xorm/xorm/examples/singlemapping.go deleted file mode 100644 index f2d675b801e..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/singlemapping.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -type User struct { - Id int64 - Name string -} - -type LoginInfo struct { - Id int64 - IP string - UserId int64 - // timestamp should be updated by database, so only allow get from db - TimeStamp string `xorm:"<-"` - // assume - Nonuse int `xorm:"->"` -} - -func main() { - f := "singleMapping.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL = true - err = Orm.CreateTables(&User{}, &LoginInfo{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = Orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1, "", 23}) - if err != nil { - fmt.Println(err) - return - } - - info := LoginInfo{} - _, err = Orm.Id(1).Get(&info) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(info) -} diff --git a/vendor/github.com/go-xorm/xorm/examples/sync.go b/vendor/github.com/go-xorm/xorm/examples/sync.go deleted file mode 100644 index d108e4558cf..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/sync.go +++ /dev/null @@ -1,104 +0,0 @@ -package main - -import ( - "fmt" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" -) - -type SyncUser2 struct { - Id int64 - Name string `xorm:"unique"` - Age int `xorm:"index"` - Title string - Address string - Genre string - Area string - Date int -} - -type SyncLoginInfo2 struct { - Id int64 - IP string `xorm:"index"` - UserId int64 - AddedCol int - // timestamp should be updated by database, so only allow get from db - TimeStamp string - // assume - Nonuse int `xorm:"unique"` - Newa string `xorm:"index"` -} - -func sync(engine *xorm.Engine) error { - return engine.Sync(&SyncLoginInfo2{}, &SyncUser2{}) -} - -func sqliteEngine() (*xorm.Engine, error) { - f := "sync.db" - //os.Remove(f) - - return xorm.NewEngine("sqlite3", f) -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -func postgresEngine() (*xorm.Engine, error) { - return xorm.NewEngine("postgres", "dbname=xorm_test sslmode=disable") -} - -type engineFunc func() (*xorm.Engine, error) - -func main() { - //engines := []engineFunc{sqliteEngine, mysqlEngine, postgresEngine} - //engines := []engineFunc{sqliteEngine} - //engines := []engineFunc{mysqlEngine} - engines := []engineFunc{postgresEngine} - for _, enginefunc := range engines { - Orm, err := enginefunc() - fmt.Println("--------", Orm.DriverName, "----------") - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL = true - err = sync(Orm) - if err != nil { - fmt.Println(err) - } - - _, err = Orm.Where("id > 0").Delete(&SyncUser2{}) - if err != nil { - fmt.Println(err) - } - - user := &SyncUser2{ - Name: "testsdf", - Age: 15, - Title: "newsfds", - Address: "fasfdsafdsaf", - Genre: "fsafd", - Area: "fafdsafd", - Date: 1000, - } - _, err = Orm.Insert(user) - if err != nil { - fmt.Println(err) - return - } - - isexist, err := Orm.IsTableExist("sync_user2") - if err != nil { - fmt.Println(err) - return - } - if !isexist { - fmt.Println("sync_user2 is not exist") - return - } - } -} diff --git a/vendor/github.com/go-xorm/xorm/examples/tables.go b/vendor/github.com/go-xorm/xorm/examples/tables.go deleted file mode 100644 index 97c842be36d..00000000000 --- a/vendor/github.com/go-xorm/xorm/examples/tables.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -func main() { - if len(os.Args) < 2 { - fmt.Println("need db path") - return - } - - orm, err := xorm.NewEngine("sqlite3", os.Args[1]) - if err != nil { - fmt.Println(err) - return - } - defer orm.Close() - orm.ShowSQL = true - - tables, err := orm.DBMetas() - if err != nil { - fmt.Println(err) - return - } - - for _, table := range tables { - fmt.Println(table.Name) - } -} diff --git a/vendor/github.com/go-xorm/xorm/gen_reserved.sh b/vendor/github.com/go-xorm/xorm/gen_reserved.sh deleted file mode 100755 index 434a1bfcb00..00000000000 --- a/vendor/github.com/go-xorm/xorm/gen_reserved.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [ -f $1 ];then - cat $1| awk '{printf("\""$1"\":true,\n")}' -else - echo "argument $1 if not a file!" -fi diff --git a/vendor/github.com/go-xorm/xorm/pg_reserved.txt b/vendor/github.com/go-xorm/xorm/pg_reserved.txt deleted file mode 100644 index 720ed377ba0..00000000000 --- a/vendor/github.com/go-xorm/xorm/pg_reserved.txt +++ /dev/null @@ -1,746 +0,0 @@ -A non-reserved non-reserved -ABORT non-reserved -ABS reserved reserved -ABSENT non-reserved non-reserved -ABSOLUTE non-reserved non-reserved non-reserved reserved -ACCESS non-reserved -ACCORDING non-reserved non-reserved -ACTION non-reserved non-reserved non-reserved reserved -ADA non-reserved non-reserved non-reserved -ADD non-reserved non-reserved non-reserved reserved -ADMIN non-reserved non-reserved non-reserved -AFTER non-reserved non-reserved non-reserved -AGGREGATE non-reserved -ALL reserved reserved reserved reserved -ALLOCATE reserved reserved reserved -ALSO non-reserved -ALTER non-reserved reserved reserved reserved -ALWAYS non-reserved non-reserved non-reserved -ANALYSE reserved -ANALYZE reserved -AND reserved reserved reserved reserved -ANY reserved reserved reserved reserved -ARE reserved reserved reserved -ARRAY reserved reserved reserved -ARRAY_AGG reserved reserved -ARRAY_MAX_CARDINALITY reserved -AS reserved reserved reserved reserved -ASC reserved non-reserved non-reserved reserved -ASENSITIVE reserved reserved -ASSERTION non-reserved non-reserved non-reserved reserved -ASSIGNMENT non-reserved non-reserved non-reserved -ASYMMETRIC reserved reserved reserved -AT non-reserved reserved reserved reserved -ATOMIC reserved reserved -ATTRIBUTE non-reserved non-reserved non-reserved -ATTRIBUTES non-reserved non-reserved -AUTHORIZATION reserved (can be function or type) reserved reserved reserved -AVG reserved reserved reserved -BACKWARD non-reserved -BASE64 non-reserved non-reserved -BEFORE non-reserved non-reserved non-reserved -BEGIN non-reserved reserved reserved reserved -BEGIN_FRAME reserved -BEGIN_PARTITION reserved -BERNOULLI non-reserved non-reserved -BETWEEN non-reserved (cannot be function or type) reserved reserved reserved -BIGINT non-reserved (cannot be function or type) reserved reserved -BINARY reserved (can be function or type) reserved reserved -BIT non-reserved (cannot be function or type) reserved -BIT_LENGTH reserved -BLOB reserved reserved -BLOCKED non-reserved non-reserved -BOM non-reserved non-reserved -BOOLEAN non-reserved (cannot be function or type) reserved reserved -BOTH reserved reserved reserved reserved -BREADTH non-reserved non-reserved -BY non-reserved reserved reserved reserved -C non-reserved non-reserved non-reserved -CACHE non-reserved -CALL reserved reserved -CALLED non-reserved reserved reserved -CARDINALITY reserved reserved -CASCADE non-reserved non-reserved non-reserved reserved -CASCADED non-reserved reserved reserved reserved -CASE reserved reserved reserved reserved -CAST reserved reserved reserved reserved -CATALOG non-reserved non-reserved non-reserved reserved -CATALOG_NAME non-reserved non-reserved non-reserved -CEIL reserved reserved -CEILING reserved reserved -CHAIN non-reserved non-reserved non-reserved -CHAR non-reserved (cannot be function or type) reserved reserved reserved -CHARACTER non-reserved (cannot be function or type) reserved reserved reserved -CHARACTERISTICS non-reserved non-reserved non-reserved -CHARACTERS non-reserved non-reserved -CHARACTER_LENGTH reserved reserved reserved -CHARACTER_SET_CATALOG non-reserved non-reserved non-reserved -CHARACTER_SET_NAME non-reserved non-reserved non-reserved -CHARACTER_SET_SCHEMA non-reserved non-reserved non-reserved -CHAR_LENGTH reserved reserved reserved -CHECK reserved reserved reserved reserved -CHECKPOINT non-reserved -CLASS non-reserved -CLASS_ORIGIN non-reserved non-reserved non-reserved -CLOB reserved reserved -CLOSE non-reserved reserved reserved reserved -CLUSTER non-reserved -COALESCE non-reserved (cannot be function or type) reserved reserved reserved -COBOL non-reserved non-reserved non-reserved -COLLATE reserved reserved reserved reserved -COLLATION reserved (can be function or type) non-reserved non-reserved reserved -COLLATION_CATALOG non-reserved non-reserved non-reserved -COLLATION_NAME non-reserved non-reserved non-reserved -COLLATION_SCHEMA non-reserved non-reserved non-reserved -COLLECT reserved reserved -COLUMN reserved reserved reserved reserved -COLUMNS non-reserved non-reserved -COLUMN_NAME non-reserved non-reserved non-reserved -COMMAND_FUNCTION non-reserved non-reserved non-reserved -COMMAND_FUNCTION_CODE non-reserved non-reserved -COMMENT non-reserved -COMMENTS non-reserved -COMMIT non-reserved reserved reserved reserved -COMMITTED non-reserved non-reserved non-reserved non-reserved -CONCURRENTLY reserved (can be function or type) -CONDITION reserved reserved -CONDITION_NUMBER non-reserved non-reserved non-reserved -CONFIGURATION non-reserved -CONNECT reserved reserved reserved -CONNECTION non-reserved non-reserved non-reserved reserved -CONNECTION_NAME non-reserved non-reserved non-reserved -CONSTRAINT reserved reserved reserved reserved -CONSTRAINTS non-reserved non-reserved non-reserved reserved -CONSTRAINT_CATALOG non-reserved non-reserved non-reserved -CONSTRAINT_NAME non-reserved non-reserved non-reserved -CONSTRAINT_SCHEMA non-reserved non-reserved non-reserved -CONSTRUCTOR non-reserved non-reserved -CONTAINS reserved non-reserved -CONTENT non-reserved non-reserved non-reserved -CONTINUE non-reserved non-reserved non-reserved reserved -CONTROL non-reserved non-reserved -CONVERSION non-reserved -CONVERT reserved reserved reserved -COPY non-reserved -CORR reserved reserved -CORRESPONDING reserved reserved reserved -COST non-reserved -COUNT reserved reserved reserved -COVAR_POP reserved reserved -COVAR_SAMP reserved reserved -CREATE reserved reserved reserved reserved -CROSS reserved (can be function or type) reserved reserved reserved -CSV non-reserved -CUBE reserved reserved -CUME_DIST reserved reserved -CURRENT non-reserved reserved reserved reserved -CURRENT_CATALOG reserved reserved reserved -CURRENT_DATE reserved reserved reserved reserved -CURRENT_DEFAULT_TRANSFORM_GROUP reserved reserved -CURRENT_PATH reserved reserved -CURRENT_ROLE reserved reserved reserved -CURRENT_ROW reserved -CURRENT_SCHEMA reserved (can be function or type) reserved reserved -CURRENT_TIME reserved reserved reserved reserved -CURRENT_TIMESTAMP reserved reserved reserved reserved -CURRENT_TRANSFORM_GROUP_FOR_TYPE reserved reserved -CURRENT_USER reserved reserved reserved reserved -CURSOR non-reserved reserved reserved reserved -CURSOR_NAME non-reserved non-reserved non-reserved -CYCLE non-reserved reserved reserved -DATA non-reserved non-reserved non-reserved non-reserved -DATABASE non-reserved -DATALINK reserved reserved -DATE reserved reserved reserved -DATETIME_INTERVAL_CODE non-reserved non-reserved non-reserved -DATETIME_INTERVAL_PRECISION non-reserved non-reserved non-reserved -DAY non-reserved reserved reserved reserved -DB non-reserved non-reserved -DEALLOCATE non-reserved reserved reserved reserved -DEC non-reserved (cannot be function or type) reserved reserved reserved -DECIMAL non-reserved (cannot be function or type) reserved reserved reserved -DECLARE non-reserved reserved reserved reserved -DEFAULT reserved reserved reserved reserved -DEFAULTS non-reserved non-reserved non-reserved -DEFERRABLE reserved non-reserved non-reserved reserved -DEFERRED non-reserved non-reserved non-reserved reserved -DEFINED non-reserved non-reserved -DEFINER non-reserved non-reserved non-reserved -DEGREE non-reserved non-reserved -DELETE non-reserved reserved reserved reserved -DELIMITER non-reserved -DELIMITERS non-reserved -DENSE_RANK reserved reserved -DEPTH non-reserved non-reserved -DEREF reserved reserved -DERIVED non-reserved non-reserved -DESC reserved non-reserved non-reserved reserved -DESCRIBE reserved reserved reserved -DESCRIPTOR non-reserved non-reserved reserved -DETERMINISTIC reserved reserved -DIAGNOSTICS non-reserved non-reserved reserved -DICTIONARY non-reserved -DISABLE non-reserved -DISCARD non-reserved -DISCONNECT reserved reserved reserved -DISPATCH non-reserved non-reserved -DISTINCT reserved reserved reserved reserved -DLNEWCOPY reserved reserved -DLPREVIOUSCOPY reserved reserved -DLURLCOMPLETE reserved reserved -DLURLCOMPLETEONLY reserved reserved -DLURLCOMPLETEWRITE reserved reserved -DLURLPATH reserved reserved -DLURLPATHONLY reserved reserved -DLURLPATHWRITE reserved reserved -DLURLSCHEME reserved reserved -DLURLSERVER reserved reserved -DLVALUE reserved reserved -DO reserved -DOCUMENT non-reserved non-reserved non-reserved -DOMAIN non-reserved non-reserved non-reserved reserved -DOUBLE non-reserved reserved reserved reserved -DROP non-reserved reserved reserved reserved -DYNAMIC reserved reserved -DYNAMIC_FUNCTION non-reserved non-reserved non-reserved -DYNAMIC_FUNCTION_CODE non-reserved non-reserved -EACH non-reserved reserved reserved -ELEMENT reserved reserved -ELSE reserved reserved reserved reserved -EMPTY non-reserved non-reserved -ENABLE non-reserved -ENCODING non-reserved non-reserved non-reserved -ENCRYPTED non-reserved -END reserved reserved reserved reserved -END-EXEC reserved reserved reserved -END_FRAME reserved -END_PARTITION reserved -ENFORCED non-reserved -ENUM non-reserved -EQUALS reserved non-reserved -ESCAPE non-reserved reserved reserved reserved -EVENT non-reserved -EVERY reserved reserved -EXCEPT reserved reserved reserved reserved -EXCEPTION reserved -EXCLUDE non-reserved non-reserved non-reserved -EXCLUDING non-reserved non-reserved non-reserved -EXCLUSIVE non-reserved -EXEC reserved reserved reserved -EXECUTE non-reserved reserved reserved reserved -EXISTS non-reserved (cannot be function or type) reserved reserved reserved -EXP reserved reserved -EXPLAIN non-reserved -EXPRESSION non-reserved -EXTENSION non-reserved -EXTERNAL non-reserved reserved reserved reserved -EXTRACT non-reserved (cannot be function or type) reserved reserved reserved -FALSE reserved reserved reserved reserved -FAMILY non-reserved -FETCH reserved reserved reserved reserved -FILE non-reserved non-reserved -FILTER reserved reserved -FINAL non-reserved non-reserved -FIRST non-reserved non-reserved non-reserved reserved -FIRST_VALUE reserved reserved -FLAG non-reserved non-reserved -FLOAT non-reserved (cannot be function or type) reserved reserved reserved -FLOOR reserved reserved -FOLLOWING non-reserved non-reserved non-reserved -FOR reserved reserved reserved reserved -FORCE non-reserved -FOREIGN reserved reserved reserved reserved -FORTRAN non-reserved non-reserved non-reserved -FORWARD non-reserved -FOUND non-reserved non-reserved reserved -FRAME_ROW reserved -FREE reserved reserved -FREEZE reserved (can be function or type) -FROM reserved reserved reserved reserved -FS non-reserved non-reserved -FULL reserved (can be function or type) reserved reserved reserved -FUNCTION non-reserved reserved reserved -FUNCTIONS non-reserved -FUSION reserved reserved -G non-reserved non-reserved -GENERAL non-reserved non-reserved -GENERATED non-reserved non-reserved -GET reserved reserved reserved -GLOBAL non-reserved reserved reserved reserved -GO non-reserved non-reserved reserved -GOTO non-reserved non-reserved reserved -GRANT reserved reserved reserved reserved -GRANTED non-reserved non-reserved non-reserved -GREATEST non-reserved (cannot be function or type) -GROUP reserved reserved reserved reserved -GROUPING reserved reserved -GROUPS reserved -HANDLER non-reserved -HAVING reserved reserved reserved reserved -HEADER non-reserved -HEX non-reserved non-reserved -HIERARCHY non-reserved non-reserved -HOLD non-reserved reserved reserved -HOUR non-reserved reserved reserved reserved -ID non-reserved non-reserved -IDENTITY non-reserved reserved reserved reserved -IF non-reserved -IGNORE non-reserved non-reserved -ILIKE reserved (can be function or type) -IMMEDIATE non-reserved non-reserved non-reserved reserved -IMMEDIATELY non-reserved -IMMUTABLE non-reserved -IMPLEMENTATION non-reserved non-reserved -IMPLICIT non-reserved -IMPORT reserved reserved -IN reserved reserved reserved reserved -INCLUDING non-reserved non-reserved non-reserved -INCREMENT non-reserved non-reserved non-reserved -INDENT non-reserved non-reserved -INDEX non-reserved -INDEXES non-reserved -INDICATOR reserved reserved reserved -INHERIT non-reserved -INHERITS non-reserved -INITIALLY reserved non-reserved non-reserved reserved -INLINE non-reserved -INNER reserved (can be function or type) reserved reserved reserved -INOUT non-reserved (cannot be function or type) reserved reserved -INPUT non-reserved non-reserved non-reserved reserved -INSENSITIVE non-reserved reserved reserved reserved -INSERT non-reserved reserved reserved reserved -INSTANCE non-reserved non-reserved -INSTANTIABLE non-reserved non-reserved -INSTEAD non-reserved non-reserved non-reserved -INT non-reserved (cannot be function or type) reserved reserved reserved -INTEGER non-reserved (cannot be function or type) reserved reserved reserved -INTEGRITY non-reserved non-reserved -INTERSECT reserved reserved reserved reserved -INTERSECTION reserved reserved -INTERVAL non-reserved (cannot be function or type) reserved reserved reserved -INTO reserved reserved reserved reserved -INVOKER non-reserved non-reserved non-reserved -IS reserved (can be function or type) reserved reserved reserved -ISNULL reserved (can be function or type) -ISOLATION non-reserved non-reserved non-reserved reserved -JOIN reserved (can be function or type) reserved reserved reserved -K non-reserved non-reserved -KEY non-reserved non-reserved non-reserved reserved -KEY_MEMBER non-reserved non-reserved -KEY_TYPE non-reserved non-reserved -LABEL non-reserved -LAG reserved reserved -LANGUAGE non-reserved reserved reserved reserved -LARGE non-reserved reserved reserved -LAST non-reserved non-reserved non-reserved reserved -LAST_VALUE reserved reserved -LATERAL reserved reserved reserved -LC_COLLATE non-reserved -LC_CTYPE non-reserved -LEAD reserved reserved -LEADING reserved reserved reserved reserved -LEAKPROOF non-reserved -LEAST non-reserved (cannot be function or type) -LEFT reserved (can be function or type) reserved reserved reserved -LENGTH non-reserved non-reserved non-reserved -LEVEL non-reserved non-reserved non-reserved reserved -LIBRARY non-reserved non-reserved -LIKE reserved (can be function or type) reserved reserved reserved -LIKE_REGEX reserved reserved -LIMIT reserved non-reserved non-reserved -LINK non-reserved non-reserved -LISTEN non-reserved -LN reserved reserved -LOAD non-reserved -LOCAL non-reserved reserved reserved reserved -LOCALTIME reserved reserved reserved -LOCALTIMESTAMP reserved reserved reserved -LOCATION non-reserved non-reserved non-reserved -LOCATOR non-reserved non-reserved -LOCK non-reserved -LOWER reserved reserved reserved -M non-reserved non-reserved -MAP non-reserved non-reserved -MAPPING non-reserved non-reserved non-reserved -MATCH non-reserved reserved reserved reserved -MATCHED non-reserved non-reserved -MATERIALIZED non-reserved -MAX reserved reserved reserved -MAXVALUE non-reserved non-reserved non-reserved -MAX_CARDINALITY reserved -MEMBER reserved reserved -MERGE reserved reserved -MESSAGE_LENGTH non-reserved non-reserved non-reserved -MESSAGE_OCTET_LENGTH non-reserved non-reserved non-reserved -MESSAGE_TEXT non-reserved non-reserved non-reserved -METHOD reserved reserved -MIN reserved reserved reserved -MINUTE non-reserved reserved reserved reserved -MINVALUE non-reserved non-reserved non-reserved -MOD reserved reserved -MODE non-reserved -MODIFIES reserved reserved -MODULE reserved reserved reserved -MONTH non-reserved reserved reserved reserved -MORE non-reserved non-reserved non-reserved -MOVE non-reserved -MULTISET reserved reserved -MUMPS non-reserved non-reserved non-reserved -NAME non-reserved non-reserved non-reserved non-reserved -NAMES non-reserved non-reserved non-reserved reserved -NAMESPACE non-reserved non-reserved -NATIONAL non-reserved (cannot be function or type) reserved reserved reserved -NATURAL reserved (can be function or type) reserved reserved reserved -NCHAR non-reserved (cannot be function or type) reserved reserved reserved -NCLOB reserved reserved -NESTING non-reserved non-reserved -NEW reserved reserved -NEXT non-reserved non-reserved non-reserved reserved -NFC non-reserved non-reserved -NFD non-reserved non-reserved -NFKC non-reserved non-reserved -NFKD non-reserved non-reserved -NIL non-reserved non-reserved -NO non-reserved reserved reserved reserved -NONE non-reserved (cannot be function or type) reserved reserved -NORMALIZE reserved reserved -NORMALIZED non-reserved non-reserved -NOT reserved reserved reserved reserved -NOTHING non-reserved -NOTIFY non-reserved -NOTNULL reserved (can be function or type) -NOWAIT non-reserved -NTH_VALUE reserved reserved -NTILE reserved reserved -NULL reserved reserved reserved reserved -NULLABLE non-reserved non-reserved non-reserved -NULLIF non-reserved (cannot be function or type) reserved reserved reserved -NULLS non-reserved non-reserved non-reserved -NUMBER non-reserved non-reserved non-reserved -NUMERIC non-reserved (cannot be function or type) reserved reserved reserved -OBJECT non-reserved non-reserved non-reserved -OCCURRENCES_REGEX reserved reserved -OCTETS non-reserved non-reserved -OCTET_LENGTH reserved reserved reserved -OF non-reserved reserved reserved reserved -OFF non-reserved non-reserved non-reserved -OFFSET reserved reserved reserved -OIDS non-reserved -OLD reserved reserved -ON reserved reserved reserved reserved -ONLY reserved reserved reserved reserved -OPEN reserved reserved reserved -OPERATOR non-reserved -OPTION non-reserved non-reserved non-reserved reserved -OPTIONS non-reserved non-reserved non-reserved -OR reserved reserved reserved reserved -ORDER reserved reserved reserved reserved -ORDERING non-reserved non-reserved -ORDINALITY non-reserved non-reserved -OTHERS non-reserved non-reserved -OUT non-reserved (cannot be function or type) reserved reserved -OUTER reserved (can be function or type) reserved reserved reserved -OUTPUT non-reserved non-reserved reserved -OVER reserved (can be function or type) reserved reserved -OVERLAPS reserved (can be function or type) reserved reserved reserved -OVERLAY non-reserved (cannot be function or type) reserved reserved -OVERRIDING non-reserved non-reserved -OWNED non-reserved -OWNER non-reserved -P non-reserved non-reserved -PAD non-reserved non-reserved reserved -PARAMETER reserved reserved -PARAMETER_MODE non-reserved non-reserved -PARAMETER_NAME non-reserved non-reserved -PARAMETER_ORDINAL_POSITION non-reserved non-reserved -PARAMETER_SPECIFIC_CATALOG non-reserved non-reserved -PARAMETER_SPECIFIC_NAME non-reserved non-reserved -PARAMETER_SPECIFIC_SCHEMA non-reserved non-reserved -PARSER non-reserved -PARTIAL non-reserved non-reserved non-reserved reserved -PARTITION non-reserved reserved reserved -PASCAL non-reserved non-reserved non-reserved -PASSING non-reserved non-reserved non-reserved -PASSTHROUGH non-reserved non-reserved -PASSWORD non-reserved -PATH non-reserved non-reserved -PERCENT reserved -PERCENTILE_CONT reserved reserved -PERCENTILE_DISC reserved reserved -PERCENT_RANK reserved reserved -PERIOD reserved -PERMISSION non-reserved non-reserved -PLACING reserved non-reserved non-reserved -PLANS non-reserved -PLI non-reserved non-reserved non-reserved -PORTION reserved -POSITION non-reserved (cannot be function or type) reserved reserved reserved -POSITION_REGEX reserved reserved -POWER reserved reserved -PRECEDES reserved -PRECEDING non-reserved non-reserved non-reserved -PRECISION non-reserved (cannot be function or type) reserved reserved reserved -PREPARE non-reserved reserved reserved reserved -PREPARED non-reserved -PRESERVE non-reserved non-reserved non-reserved reserved -PRIMARY reserved reserved reserved reserved -PRIOR non-reserved non-reserved non-reserved reserved -PRIVILEGES non-reserved non-reserved non-reserved reserved -PROCEDURAL non-reserved -PROCEDURE non-reserved reserved reserved reserved -PROGRAM non-reserved -PUBLIC non-reserved non-reserved reserved -QUOTE non-reserved -RANGE non-reserved reserved reserved -RANK reserved reserved -READ non-reserved non-reserved non-reserved reserved -READS reserved reserved -REAL non-reserved (cannot be function or type) reserved reserved reserved -REASSIGN non-reserved -RECHECK non-reserved -RECOVERY non-reserved non-reserved -RECURSIVE non-reserved reserved reserved -REF non-reserved reserved reserved -REFERENCES reserved reserved reserved reserved -REFERENCING reserved reserved -REFRESH non-reserved -REGR_AVGX reserved reserved -REGR_AVGY reserved reserved -REGR_COUNT reserved reserved -REGR_INTERCEPT reserved reserved -REGR_R2 reserved reserved -REGR_SLOPE reserved reserved -REGR_SXX reserved reserved -REGR_SXY reserved reserved -REGR_SYY reserved reserved -REINDEX non-reserved -RELATIVE non-reserved non-reserved non-reserved reserved -RELEASE non-reserved reserved reserved -RENAME non-reserved -REPEATABLE non-reserved non-reserved non-reserved non-reserved -REPLACE non-reserved -REPLICA non-reserved -REQUIRING non-reserved non-reserved -RESET non-reserved -RESPECT non-reserved non-reserved -RESTART non-reserved non-reserved non-reserved -RESTORE non-reserved non-reserved -RESTRICT non-reserved non-reserved non-reserved reserved -RESULT reserved reserved -RETURN reserved reserved -RETURNED_CARDINALITY non-reserved non-reserved -RETURNED_LENGTH non-reserved non-reserved non-reserved -RETURNED_OCTET_LENGTH non-reserved non-reserved non-reserved -RETURNED_SQLSTATE non-reserved non-reserved non-reserved -RETURNING reserved non-reserved non-reserved -RETURNS non-reserved reserved reserved -REVOKE non-reserved reserved reserved reserved -RIGHT reserved (can be function or type) reserved reserved reserved -ROLE non-reserved non-reserved non-reserved -ROLLBACK non-reserved reserved reserved reserved -ROLLUP reserved reserved -ROUTINE non-reserved non-reserved -ROUTINE_CATALOG non-reserved non-reserved -ROUTINE_NAME non-reserved non-reserved -ROUTINE_SCHEMA non-reserved non-reserved -ROW non-reserved (cannot be function or type) reserved reserved -ROWS non-reserved reserved reserved reserved -ROW_COUNT non-reserved non-reserved non-reserved -ROW_NUMBER reserved reserved -RULE non-reserved -SAVEPOINT non-reserved reserved reserved -SCALE non-reserved non-reserved non-reserved -SCHEMA non-reserved non-reserved non-reserved reserved -SCHEMA_NAME non-reserved non-reserved non-reserved -SCOPE reserved reserved -SCOPE_CATALOG non-reserved non-reserved -SCOPE_NAME non-reserved non-reserved -SCOPE_SCHEMA non-reserved non-reserved -SCROLL non-reserved reserved reserved reserved -SEARCH non-reserved reserved reserved -SECOND non-reserved reserved reserved reserved -SECTION non-reserved non-reserved reserved -SECURITY non-reserved non-reserved non-reserved -SELECT reserved reserved reserved reserved -SELECTIVE non-reserved non-reserved -SELF non-reserved non-reserved -SENSITIVE reserved reserved -SEQUENCE non-reserved non-reserved non-reserved -SEQUENCES non-reserved -SERIALIZABLE non-reserved non-reserved non-reserved non-reserved -SERVER non-reserved non-reserved non-reserved -SERVER_NAME non-reserved non-reserved non-reserved -SESSION non-reserved non-reserved non-reserved reserved -SESSION_USER reserved reserved reserved reserved -SET non-reserved reserved reserved reserved -SETOF non-reserved (cannot be function or type) -SETS non-reserved non-reserved -SHARE non-reserved -SHOW non-reserved -SIMILAR reserved (can be function or type) reserved reserved -SIMPLE non-reserved non-reserved non-reserved -SIZE non-reserved non-reserved reserved -SMALLINT non-reserved (cannot be function or type) reserved reserved reserved -SNAPSHOT non-reserved -SOME reserved reserved reserved reserved -SOURCE non-reserved non-reserved -SPACE non-reserved non-reserved reserved -SPECIFIC reserved reserved -SPECIFICTYPE reserved reserved -SPECIFIC_NAME non-reserved non-reserved -SQL reserved reserved reserved -SQLCODE reserved -SQLERROR reserved -SQLEXCEPTION reserved reserved -SQLSTATE reserved reserved reserved -SQLWARNING reserved reserved -SQRT reserved reserved -STABLE non-reserved -STANDALONE non-reserved non-reserved non-reserved -START non-reserved reserved reserved -STATE non-reserved non-reserved -STATEMENT non-reserved non-reserved non-reserved -STATIC reserved reserved -STATISTICS non-reserved -STDDEV_POP reserved reserved -STDDEV_SAMP reserved reserved -STDIN non-reserved -STDOUT non-reserved -STORAGE non-reserved -STRICT non-reserved -STRIP non-reserved non-reserved non-reserved -STRUCTURE non-reserved non-reserved -STYLE non-reserved non-reserved -SUBCLASS_ORIGIN non-reserved non-reserved non-reserved -SUBMULTISET reserved reserved -SUBSTRING non-reserved (cannot be function or type) reserved reserved reserved -SUBSTRING_REGEX reserved reserved -SUCCEEDS reserved -SUM reserved reserved reserved -SYMMETRIC reserved reserved reserved -SYSID non-reserved -SYSTEM non-reserved reserved reserved -SYSTEM_TIME reserved -SYSTEM_USER reserved reserved reserved -T non-reserved non-reserved -TABLE reserved reserved reserved reserved -TABLES non-reserved -TABLESAMPLE reserved reserved -TABLESPACE non-reserved -TABLE_NAME non-reserved non-reserved non-reserved -TEMP non-reserved -TEMPLATE non-reserved -TEMPORARY non-reserved non-reserved non-reserved reserved -TEXT non-reserved -THEN reserved reserved reserved reserved -TIES non-reserved non-reserved -TIME non-reserved (cannot be function or type) reserved reserved reserved -TIMESTAMP non-reserved (cannot be function or type) reserved reserved reserved -TIMEZONE_HOUR reserved reserved reserved -TIMEZONE_MINUTE reserved reserved reserved -TO reserved reserved reserved reserved -TOKEN non-reserved non-reserved -TOP_LEVEL_COUNT non-reserved non-reserved -TRAILING reserved reserved reserved reserved -TRANSACTION non-reserved non-reserved non-reserved reserved -TRANSACTIONS_COMMITTED non-reserved non-reserved -TRANSACTIONS_ROLLED_BACK non-reserved non-reserved -TRANSACTION_ACTIVE non-reserved non-reserved -TRANSFORM non-reserved non-reserved -TRANSFORMS non-reserved non-reserved -TRANSLATE reserved reserved reserved -TRANSLATE_REGEX reserved reserved -TRANSLATION reserved reserved reserved -TREAT non-reserved (cannot be function or type) reserved reserved -TRIGGER non-reserved reserved reserved -TRIGGER_CATALOG non-reserved non-reserved -TRIGGER_NAME non-reserved non-reserved -TRIGGER_SCHEMA non-reserved non-reserved -TRIM non-reserved (cannot be function or type) reserved reserved reserved -TRIM_ARRAY reserved reserved -TRUE reserved reserved reserved reserved -TRUNCATE non-reserved reserved reserved -TRUSTED non-reserved -TYPE non-reserved non-reserved non-reserved non-reserved -TYPES non-reserved -UESCAPE reserved reserved -UNBOUNDED non-reserved non-reserved non-reserved -UNCOMMITTED non-reserved non-reserved non-reserved non-reserved -UNDER non-reserved non-reserved -UNENCRYPTED non-reserved -UNION reserved reserved reserved reserved -UNIQUE reserved reserved reserved reserved -UNKNOWN non-reserved reserved reserved reserved -UNLINK non-reserved non-reserved -UNLISTEN non-reserved -UNLOGGED non-reserved -UNNAMED non-reserved non-reserved non-reserved -UNNEST reserved reserved -UNTIL non-reserved -UNTYPED non-reserved non-reserved -UPDATE non-reserved reserved reserved reserved -UPPER reserved reserved reserved -URI non-reserved non-reserved -USAGE non-reserved non-reserved reserved -USER reserved reserved reserved reserved -USER_DEFINED_TYPE_CATALOG non-reserved non-reserved -USER_DEFINED_TYPE_CODE non-reserved non-reserved -USER_DEFINED_TYPE_NAME non-reserved non-reserved -USER_DEFINED_TYPE_SCHEMA non-reserved non-reserved -USING reserved reserved reserved reserved -VACUUM non-reserved -VALID non-reserved non-reserved non-reserved -VALIDATE non-reserved -VALIDATOR non-reserved -VALUE non-reserved reserved reserved reserved -VALUES non-reserved (cannot be function or type) reserved reserved reserved -VALUE_OF reserved -VARBINARY reserved reserved -VARCHAR non-reserved (cannot be function or type) reserved reserved reserved -VARIADIC reserved -VARYING non-reserved reserved reserved reserved -VAR_POP reserved reserved -VAR_SAMP reserved reserved -VERBOSE reserved (can be function or type) -VERSION non-reserved non-reserved non-reserved -VERSIONING reserved -VIEW non-reserved non-reserved non-reserved reserved -VOLATILE non-reserved -WHEN reserved reserved reserved reserved -WHENEVER reserved reserved reserved -WHERE reserved reserved reserved reserved -WHITESPACE non-reserved non-reserved non-reserved -WIDTH_BUCKET reserved reserved -WINDOW reserved reserved reserved -WITH reserved reserved reserved reserved -WITHIN reserved reserved -WITHOUT non-reserved reserved reserved -WORK non-reserved non-reserved non-reserved reserved -WRAPPER non-reserved non-reserved non-reserved -WRITE non-reserved non-reserved non-reserved reserved -XML non-reserved reserved reserved -XMLAGG reserved reserved -XMLATTRIBUTES non-reserved (cannot be function or type) reserved reserved -XMLBINARY reserved reserved -XMLCAST reserved reserved -XMLCOMMENT reserved reserved -XMLCONCAT non-reserved (cannot be function or type) reserved reserved -XMLDECLARATION non-reserved non-reserved -XMLDOCUMENT reserved reserved -XMLELEMENT non-reserved (cannot be function or type) reserved reserved -XMLEXISTS non-reserved (cannot be function or type) reserved reserved -XMLFOREST non-reserved (cannot be function or type) reserved reserved -XMLITERATE reserved reserved -XMLNAMESPACES reserved reserved -XMLPARSE non-reserved (cannot be function or type) reserved reserved -XMLPI non-reserved (cannot be function or type) reserved reserved -XMLQUERY reserved reserved -XMLROOT non-reserved (cannot be function or type) -XMLSCHEMA non-reserved non-reserved -XMLSERIALIZE non-reserved (cannot be function or type) reserved reserved -XMLTABLE reserved reserved -XMLTEXT reserved reserved -XMLVALIDATE reserved reserved -YEAR non-reserved reserved reserved reserved -YES non-reserved non-reserved non-reserved -ZONE non-reserved non-reserved non-reserved reserved \ No newline at end of file diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS new file mode 100644 index 00000000000..15167cd746c --- /dev/null +++ b/vendor/github.com/golang/protobuf/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS new file mode 100644 index 00000000000..1c4577e9680 --- /dev/null +++ b/vendor/github.com/golang/protobuf/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile deleted file mode 100644 index e2e0651a934..00000000000 --- a/vendor/github.com/golang/protobuf/proto/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# 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. - -install: - go install - -test: install generate-test-pbs - go test - - -generate-test-pbs: - make install - make -C testdata - protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto - make diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go new file mode 100644 index 00000000000..b2af97f4a98 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any.go @@ -0,0 +1,139 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package ptypes + +// This file implements functions to marshal proto.Message to/from +// google.protobuf.Any message. + +import ( + "fmt" + "reflect" + "strings" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +const googleApis = "type.googleapis.com/" + +// AnyMessageName returns the name of the message contained in a google.protobuf.Any message. +// +// Note that regular type assertions should be done using the Is +// function. AnyMessageName is provided for less common use cases like filtering a +// sequence of Any messages based on a set of allowed message type names. +func AnyMessageName(any *any.Any) (string, error) { + if any == nil { + return "", fmt.Errorf("message is nil") + } + slash := strings.LastIndex(any.TypeUrl, "/") + if slash < 0 { + return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl) + } + return any.TypeUrl[slash+1:], nil +} + +// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any. +func MarshalAny(pb proto.Message) (*any.Any, error) { + value, err := proto.Marshal(pb) + if err != nil { + return nil, err + } + return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil +} + +// DynamicAny is a value that can be passed to UnmarshalAny to automatically +// allocate a proto.Message for the type specified in a google.protobuf.Any +// message. The allocated message is stored in the embedded proto.Message. +// +// Example: +// +// var x ptypes.DynamicAny +// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } +// fmt.Printf("unmarshaled message: %v", x.Message) +type DynamicAny struct { + proto.Message +} + +// Empty returns a new proto.Message of the type specified in a +// google.protobuf.Any message. It returns an error if corresponding message +// type isn't linked in. +func Empty(any *any.Any) (proto.Message, error) { + aname, err := AnyMessageName(any) + if err != nil { + return nil, err + } + + t := proto.MessageType(aname) + if t == nil { + return nil, fmt.Errorf("any: message type %q isn't linked in", aname) + } + return reflect.New(t.Elem()).Interface().(proto.Message), nil +} + +// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any +// message and places the decoded result in pb. It returns an error if type of +// contents of Any message does not match type of pb message. +// +// pb can be a proto.Message, or a *DynamicAny. +func UnmarshalAny(any *any.Any, pb proto.Message) error { + if d, ok := pb.(*DynamicAny); ok { + if d.Message == nil { + var err error + d.Message, err = Empty(any) + if err != nil { + return err + } + } + return UnmarshalAny(any, d.Message) + } + + aname, err := AnyMessageName(any) + if err != nil { + return err + } + + mname := proto.MessageName(pb) + if aname != mname { + return fmt.Errorf("mismatched message type: got %q want %q", aname, mname) + } + return proto.Unmarshal(any.Value, pb) +} + +// Is returns true if any value contains a given message type. +func Is(any *any.Any, pb proto.Message) bool { + aname, err := AnyMessageName(any) + if err != nil { + return false + } + + return aname == proto.MessageName(pb) +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go new file mode 100644 index 00000000000..f34601723de --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go @@ -0,0 +1,178 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/any.proto + +/* +Package any is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/any.proto + +It has these top-level messages: + Any +*/ +package any + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +type Any struct { + // A URL/resource name whose content describes the type of the + // serialized protocol buffer message. + // + // For URLs which use the scheme `http`, `https`, or no scheme, the + // following restrictions and interpretations apply: + // + // * If no scheme is provided, `https` is assumed. + // * The last segment of the URL's path must represent the fully + // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"` + // Must be a valid serialized protocol buffer of the above specified type. + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *Any) Reset() { *m = Any{} } +func (m *Any) String() string { return proto.CompactTextString(m) } +func (*Any) ProtoMessage() {} +func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*Any) XXX_WellKnownType() string { return "Any" } + +func (m *Any) GetTypeUrl() string { + if m != nil { + return m.TypeUrl + } + return "" +} + +func (m *Any) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +func init() { + proto.RegisterType((*Any)(nil), "google.protobuf.Any") +} + +func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 185 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, + 0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a, + 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, + 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, + 0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce, + 0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52, + 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, + 0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c, + 0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce, + 0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go new file mode 100644 index 00000000000..c0d595da7ab --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/doc.go @@ -0,0 +1,35 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +/* +Package ptypes contains code for interacting with well-known types. +*/ +package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go new file mode 100644 index 00000000000..65cb0f8eb5f --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration.go @@ -0,0 +1,102 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package ptypes + +// This file implements conversions between google.protobuf.Duration +// and time.Duration. + +import ( + "errors" + "fmt" + "time" + + durpb "github.com/golang/protobuf/ptypes/duration" +) + +const ( + // Range of a durpb.Duration in seconds, as specified in + // google/protobuf/duration.proto. This is about 10,000 years in seconds. + maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) + minSeconds = -maxSeconds +) + +// validateDuration determines whether the durpb.Duration is valid according to the +// definition in google/protobuf/duration.proto. A valid durpb.Duration +// may still be too large to fit into a time.Duration (the range of durpb.Duration +// is about 10,000 years, and the range of time.Duration is about 290). +func validateDuration(d *durpb.Duration) error { + if d == nil { + return errors.New("duration: nil Duration") + } + if d.Seconds < minSeconds || d.Seconds > maxSeconds { + return fmt.Errorf("duration: %v: seconds out of range", d) + } + if d.Nanos <= -1e9 || d.Nanos >= 1e9 { + return fmt.Errorf("duration: %v: nanos out of range", d) + } + // Seconds and Nanos must have the same sign, unless d.Nanos is zero. + if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { + return fmt.Errorf("duration: %v: seconds and nanos have different signs", d) + } + return nil +} + +// Duration converts a durpb.Duration to a time.Duration. Duration +// returns an error if the durpb.Duration is invalid or is too large to be +// represented in a time.Duration. +func Duration(p *durpb.Duration) (time.Duration, error) { + if err := validateDuration(p); err != nil { + return 0, err + } + d := time.Duration(p.Seconds) * time.Second + if int64(d/time.Second) != p.Seconds { + return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) + } + if p.Nanos != 0 { + d += time.Duration(p.Nanos) + if (d < 0) != (p.Nanos < 0) { + return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p) + } + } + return d, nil +} + +// DurationProto converts a time.Duration to a durpb.Duration. +func DurationProto(d time.Duration) *durpb.Duration { + nanos := d.Nanoseconds() + secs := nanos / 1e9 + nanos -= secs * 1e9 + return &durpb.Duration{ + Seconds: secs, + Nanos: int32(nanos), + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go new file mode 100644 index 00000000000..b2410a098eb --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go @@ -0,0 +1,144 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/duration.proto + +/* +Package duration is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/duration.proto + +It has these top-level messages: + Duration +*/ +package duration + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +type Duration struct { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` +} + +func (m *Duration) Reset() { *m = Duration{} } +func (m *Duration) String() string { return proto.CompactTextString(m) } +func (*Duration) ProtoMessage() {} +func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*Duration) XXX_WellKnownType() string { return "Duration" } + +func (m *Duration) GetSeconds() int64 { + if m != nil { + return m.Seconds + } + return 0 +} + +func (m *Duration) GetNanos() int32 { + if m != nil { + return m.Nanos + } + return 0 +} + +func init() { + proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") +} + +func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 190 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a, + 0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56, + 0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5, + 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e, + 0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c, + 0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56, + 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e, + 0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4, + 0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78, + 0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63, + 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go new file mode 100644 index 00000000000..47f10dbc2cc --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp.go @@ -0,0 +1,134 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package ptypes + +// This file implements operations on google.protobuf.Timestamp. + +import ( + "errors" + "fmt" + "time" + + tspb "github.com/golang/protobuf/ptypes/timestamp" +) + +const ( + // Seconds field of the earliest valid Timestamp. + // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + minValidSeconds = -62135596800 + // Seconds field just after the latest valid Timestamp. + // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + maxValidSeconds = 253402300800 +) + +// validateTimestamp determines whether a Timestamp is valid. +// A valid timestamp represents a time in the range +// [0001-01-01, 10000-01-01) and has a Nanos field +// in the range [0, 1e9). +// +// If the Timestamp is valid, validateTimestamp returns nil. +// Otherwise, it returns an error that describes +// the problem. +// +// Every valid Timestamp can be represented by a time.Time, but the converse is not true. +func validateTimestamp(ts *tspb.Timestamp) error { + if ts == nil { + return errors.New("timestamp: nil Timestamp") + } + if ts.Seconds < minValidSeconds { + return fmt.Errorf("timestamp: %v before 0001-01-01", ts) + } + if ts.Seconds >= maxValidSeconds { + return fmt.Errorf("timestamp: %v after 10000-01-01", ts) + } + if ts.Nanos < 0 || ts.Nanos >= 1e9 { + return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts) + } + return nil +} + +// Timestamp converts a google.protobuf.Timestamp proto to a time.Time. +// It returns an error if the argument is invalid. +// +// Unlike most Go functions, if Timestamp returns an error, the first return value +// is not the zero time.Time. Instead, it is the value obtained from the +// time.Unix function when passed the contents of the Timestamp, in the UTC +// locale. This may or may not be a meaningful time; many invalid Timestamps +// do map to valid time.Times. +// +// A nil Timestamp returns an error. The first return value in that case is +// undefined. +func Timestamp(ts *tspb.Timestamp) (time.Time, error) { + // Don't return the zero value on error, because corresponds to a valid + // timestamp. Instead return whatever time.Unix gives us. + var t time.Time + if ts == nil { + t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp + } else { + t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() + } + return t, validateTimestamp(ts) +} + +// TimestampNow returns a google.protobuf.Timestamp for the current time. +func TimestampNow() *tspb.Timestamp { + ts, err := TimestampProto(time.Now()) + if err != nil { + panic("ptypes: time.Now() out of Timestamp range") + } + return ts +} + +// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. +// It returns an error if the resulting Timestamp is invalid. +func TimestampProto(t time.Time) (*tspb.Timestamp, error) { + seconds := t.Unix() + nanos := int32(t.Sub(time.Unix(seconds, 0))) + ts := &tspb.Timestamp{ + Seconds: seconds, + Nanos: nanos, + } + if err := validateTimestamp(ts); err != nil { + return nil, err + } + return ts, nil +} + +// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid +// Timestamps, it returns an error message in parentheses. +func TimestampString(ts *tspb.Timestamp) string { + t, err := Timestamp(ts) + if err != nil { + return fmt.Sprintf("(%v)", err) + } + return t.Format(time.RFC3339Nano) +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go new file mode 100644 index 00000000000..e23e4a25daf --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go @@ -0,0 +1,160 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/timestamp.proto + +/* +Package timestamp is a generated protocol buffer package. + +It is generated from these files: + google/protobuf/timestamp.proto + +It has these top-level messages: + Timestamp +*/ +package timestamp + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required, though only UTC (as indicated by "Z") is presently supported. +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) +// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one +// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()) +// to obtain a formatter capable of generating timestamps in this format. +// +// +type Timestamp struct { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` +} + +func (m *Timestamp) Reset() { *m = Timestamp{} } +func (m *Timestamp) String() string { return proto.CompactTextString(m) } +func (*Timestamp) ProtoMessage() {} +func (*Timestamp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } + +func (m *Timestamp) GetSeconds() int64 { + if m != nil { + return m.Seconds + } + return 0 +} + +func (m *Timestamp) GetNanos() int32 { + if m != nil { + return m.Nanos + } + return 0 +} + +func init() { + proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") +} + +func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 191 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f, + 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d, + 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28, + 0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5, + 0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89, + 0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70, + 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51, + 0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89, + 0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71, + 0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a, + 0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43, + 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00, +} diff --git a/vendor/github.com/gopherjs/gopherjs/LICENSE b/vendor/github.com/gopherjs/gopherjs/LICENSE new file mode 100644 index 00000000000..d496fef1092 --- /dev/null +++ b/vendor/github.com/gopherjs/gopherjs/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2013 Richard Musiol. 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. + +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/github.com/gopherjs/gopherjs/js/js.go b/vendor/github.com/gopherjs/gopherjs/js/js.go new file mode 100644 index 00000000000..3fbf1d88c60 --- /dev/null +++ b/vendor/github.com/gopherjs/gopherjs/js/js.go @@ -0,0 +1,168 @@ +// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax. +// +// Use MakeWrapper to expose methods to JavaScript. When passing values directly, the following type conversions are performed: +// +// | Go type | JavaScript type | Conversions back to interface{} | +// | --------------------- | --------------------- | ------------------------------- | +// | bool | Boolean | bool | +// | integers and floats | Number | float64 | +// | string | String | string | +// | []int8 | Int8Array | []int8 | +// | []int16 | Int16Array | []int16 | +// | []int32, []int | Int32Array | []int | +// | []uint8 | Uint8Array | []uint8 | +// | []uint16 | Uint16Array | []uint16 | +// | []uint32, []uint | Uint32Array | []uint | +// | []float32 | Float32Array | []float32 | +// | []float64 | Float64Array | []float64 | +// | all other slices | Array | []interface{} | +// | arrays | see slice type | see slice type | +// | functions | Function | func(...interface{}) *js.Object | +// | time.Time | Date | time.Time | +// | - | instanceof Node | *js.Object | +// | maps, structs | instanceof Object | map[string]interface{} | +// +// Additionally, for a struct containing a *js.Object field, only the content of the field will be passed to JavaScript and vice versa. +package js + +// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. A nil pointer to Object is equal to JavaScript's "null". Object can not be used as a map key. +type Object struct{ object *Object } + +// Get returns the object's property with the given key. +func (o *Object) Get(key string) *Object { return o.object.Get(key) } + +// Set assigns the value to the object's property with the given key. +func (o *Object) Set(key string, value interface{}) { o.object.Set(key, value) } + +// Delete removes the object's property with the given key. +func (o *Object) Delete(key string) { o.object.Delete(key) } + +// Length returns the object's "length" property, converted to int. +func (o *Object) Length() int { return o.object.Length() } + +// Index returns the i'th element of an array. +func (o *Object) Index(i int) *Object { return o.object.Index(i) } + +// SetIndex sets the i'th element of an array. +func (o *Object) SetIndex(i int, value interface{}) { o.object.SetIndex(i, value) } + +// Call calls the object's method with the given name. +func (o *Object) Call(name string, args ...interface{}) *Object { return o.object.Call(name, args...) } + +// Invoke calls the object itself. This will fail if it is not a function. +func (o *Object) Invoke(args ...interface{}) *Object { return o.object.Invoke(args...) } + +// New creates a new instance of this type object. This will fail if it not a function (constructor). +func (o *Object) New(args ...interface{}) *Object { return o.object.New(args...) } + +// Bool returns the object converted to bool according to JavaScript type conversions. +func (o *Object) Bool() bool { return o.object.Bool() } + +// String returns the object converted to string according to JavaScript type conversions. +func (o *Object) String() string { return o.object.String() } + +// Int returns the object converted to int according to JavaScript type conversions (parseInt). +func (o *Object) Int() int { return o.object.Int() } + +// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt). +func (o *Object) Int64() int64 { return o.object.Int64() } + +// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt). +func (o *Object) Uint64() uint64 { return o.object.Uint64() } + +// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat). +func (o *Object) Float() float64 { return o.object.Float() } + +// Interface returns the object converted to interface{}. See table in package comment for details. +func (o *Object) Interface() interface{} { return o.object.Interface() } + +// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use. +func (o *Object) Unsafe() uintptr { return o.object.Unsafe() } + +// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be recovered, giving an *Error that holds the JavaScript error object. +type Error struct { + *Object +} + +// Error returns the message of the encapsulated JavaScript error object. +func (err *Error) Error() string { + return "JavaScript error: " + err.Get("message").String() +} + +// Stack returns the stack property of the encapsulated JavaScript error object. +func (err *Error) Stack() string { + return err.Get("stack").String() +} + +// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). +var Global *Object + +// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'. +var Module *Object + +// Undefined gives the JavaScript value "undefined". +var Undefined *Object + +// Debugger gets compiled to JavaScript's "debugger;" statement. +func Debugger() {} + +// InternalObject returns the internal JavaScript object that represents i. Not intended for public use. +func InternalObject(i interface{}) *Object { + return nil +} + +// MakeFunc wraps a function and gives access to the values of JavaScript's "this" and "arguments" keywords. +func MakeFunc(fn func(this *Object, arguments []*Object) interface{}) *Object { + return Global.Call("$makeFunc", InternalObject(fn)) +} + +// Keys returns the keys of the given JavaScript object. +func Keys(o *Object) []string { + if o == nil || o == Undefined { + return nil + } + a := Global.Get("Object").Call("keys", o) + s := make([]string, a.Length()) + for i := 0; i < a.Length(); i++ { + s[i] = a.Index(i).String() + } + return s +} + +// MakeWrapper creates a JavaScript object which has wrappers for the exported methods of i. Use explicit getter and setter methods to expose struct fields to JavaScript. +func MakeWrapper(i interface{}) *Object { + v := InternalObject(i) + o := Global.Get("Object").New() + o.Set("__internal_object__", v) + methods := v.Get("constructor").Get("methods") + for i := 0; i < methods.Length(); i++ { + m := methods.Index(i) + if m.Get("pkg").String() != "" { // not exported + continue + } + o.Set(m.Get("name").String(), func(args ...*Object) *Object { + return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true).Call("apply", v, args) + }) + } + return o +} + +// NewArrayBuffer creates a JavaScript ArrayBuffer from a byte slice. +func NewArrayBuffer(b []byte) *Object { + slice := InternalObject(b) + offset := slice.Get("$offset").Int() + length := slice.Get("$length").Int() + return slice.Get("$array").Get("buffer").Call("slice", offset, offset+length) +} + +// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion). +type M map[string]interface{} + +// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion). +type S []interface{} + +func init() { + // avoid dead code elimination + e := Error{} + _ = e +} diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md deleted file mode 100644 index 33c3d2be3e3..00000000000 --- a/vendor/github.com/gorilla/websocket/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Gorilla WebSocket - -Gorilla WebSocket is a [Go](http://golang.org/) implementation of the -[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. - -[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket) -[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) - -### Documentation - -* [API Reference](http://godoc.org/github.com/gorilla/websocket) -* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) -* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) -* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) -* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) - -### Status - -The Gorilla WebSocket package provides a complete and tested implementation of -the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The -package API is stable. - -### Installation - - go get github.com/gorilla/websocket - -### Protocol Compliance - -The Gorilla WebSocket package passes the server tests in the [Autobahn Test -Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn -subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). - -### Gorilla WebSocket compared with other packages - - - - - - - - - - - - - - - - - - -
      github.com/gorillagolang.org/x/net
      RFC 6455 Features
      Passes Autobahn Test SuiteYesNo
      Receive fragmented messageYesNo, see note 1
      Send close messageYesNo
      Send pings and receive pongsYesNo
      Get the type of a received data messageYesYes, see note 2
      Other Features
      Compression ExtensionsExperimentalNo
      Read message using io.ReaderYesNo, see note 3
      Write message using io.WriteCloserYesNo, see note 3
      - -Notes: - -1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html). -2. The application can get the type of a received data message by implementing - a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal) - function. -3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. - Read returns when the input buffer is full or a frame boundary is - encountered. Each call to Write sends a single frame message. The Gorilla - io.Reader and io.WriteCloser operate on a single WebSocket message. - diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go index 78d932877b5..43a87c753bf 100644 --- a/vendor/github.com/gorilla/websocket/client.go +++ b/vendor/github.com/gorilla/websocket/client.go @@ -66,8 +66,9 @@ type Dialer struct { // HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration - // Input and output buffer sizes. If the buffer size is zero, then a - // default value of 4096 is used. + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // size is zero, then a useful default size is used. The I/O buffer sizes + // do not limit the size of the messages that can be sent or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the client's requested subprotocols. @@ -368,7 +369,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re return nil, resp, ErrBadHandshake } - for _, ext := range parseExtensions(req.Header) { + for _, ext := range parseExtensions(resp.Header) { if ext[""] != "permessage-deflate" { continue } @@ -389,32 +390,3 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re netConn = nil // to avoid close in defer. return conn, resp, nil } - -// cloneTLSConfig clones all public fields except the fields -// SessionTicketsDisabled and SessionTicketKey. This avoids copying the -// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a -// config in active use. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - } -} diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go new file mode 100644 index 00000000000..4f0d943723a --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client_clone.go @@ -0,0 +1,16 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.8 + +package websocket + +import "crypto/tls" + +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return cfg.Clone() +} diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go new file mode 100644 index 00000000000..babb007fb41 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/client_clone_legacy.go @@ -0,0 +1,38 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.8 + +package websocket + +import "crypto/tls" + +// cloneTLSConfig clones all public fields except the fields +// SessionTicketsDisabled and SessionTicketKey. This avoids copying the +// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a +// config in active use. +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return &tls.Config{ + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + } +} diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go index 72c166b2a75..813ffb1e843 100644 --- a/vendor/github.com/gorilla/websocket/compression.go +++ b/vendor/github.com/gorilla/websocket/compression.go @@ -12,31 +12,45 @@ import ( "sync" ) -var ( - flateWriterPool = sync.Pool{} +const ( + minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6 + maxCompressionLevel = flate.BestCompression + defaultCompressionLevel = 1 ) -func decompressNoContextTakeover(r io.Reader) io.Reader { +var ( + flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool + flateReaderPool = sync.Pool{New: func() interface{} { + return flate.NewReader(nil) + }} +) + +func decompressNoContextTakeover(r io.Reader) io.ReadCloser { const tail = // Add four bytes as specified in RFC "\x00\x00\xff\xff" + // Add final block to squelch unexpected EOF error from flate reader. "\x01\x00\x00\xff\xff" - return flate.NewReader(io.MultiReader(r, strings.NewReader(tail))) + + fr, _ := flateReaderPool.Get().(io.ReadCloser) + fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) + return &flateReadWrapper{fr} } -func compressNoContextTakeover(w io.WriteCloser) (io.WriteCloser, error) { +func isValidCompressionLevel(level int) bool { + return minCompressionLevel <= level && level <= maxCompressionLevel +} + +func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser { + p := &flateWriterPools[level-minCompressionLevel] tw := &truncWriter{w: w} - i := flateWriterPool.Get() - var fw *flate.Writer - var err error - if i == nil { - fw, err = flate.NewWriter(tw, 3) + fw, _ := p.Get().(*flate.Writer) + if fw == nil { + fw, _ = flate.NewWriter(tw, level) } else { - fw = i.(*flate.Writer) fw.Reset(tw) } - return &flateWrapper{fw: fw, tw: tw}, err + return &flateWriteWrapper{fw: fw, tw: tw, p: p} } // truncWriter is an io.Writer that writes all but the last four bytes of the @@ -75,24 +89,25 @@ func (w *truncWriter) Write(p []byte) (int, error) { return n + nn, err } -type flateWrapper struct { +type flateWriteWrapper struct { fw *flate.Writer tw *truncWriter + p *sync.Pool } -func (w *flateWrapper) Write(p []byte) (int, error) { +func (w *flateWriteWrapper) Write(p []byte) (int, error) { if w.fw == nil { return 0, errWriteClosed } return w.fw.Write(p) } -func (w *flateWrapper) Close() error { +func (w *flateWriteWrapper) Close() error { if w.fw == nil { return errWriteClosed } err1 := w.fw.Flush() - flateWriterPool.Put(w.fw) + w.p.Put(w.fw) w.fw = nil if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { return errors.New("websocket: internal error, unexpected bytes at end of flate stream") @@ -103,3 +118,31 @@ func (w *flateWrapper) Close() error { } return err2 } + +type flateReadWrapper struct { + fr io.ReadCloser +} + +func (r *flateReadWrapper) Read(p []byte) (int, error) { + if r.fr == nil { + return 0, io.ErrClosedPipe + } + n, err := r.fr.Read(p) + if err == io.EOF { + // Preemptively place the reader back in the pool. This helps with + // scenarios where the application does not call NextReader() soon after + // this final read. + r.Close() + } + return n, err +} + +func (r *flateReadWrapper) Close() error { + if r.fr == nil { + return io.ErrClosedPipe + } + err := r.fr.Close() + flateReaderPool.Put(r.fr) + r.fr = nil + return err +} diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go index ce7f0a6159f..97e1dbacb12 100644 --- a/vendor/github.com/gorilla/websocket/conn.go +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -10,6 +10,7 @@ import ( "errors" "io" "io/ioutil" + "math/rand" "net" "strconv" "sync" @@ -180,6 +181,11 @@ var ( errInvalidControlFrame = errors.New("websocket: invalid control frame") ) +func newMaskKey() [4]byte { + n := rand.Uint32() + return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} +} + func hideTempErr(err error) error { if e, ok := err.(net.Error); ok && e.Temporary() { err = &netError{msg: e.Error(), timeout: e.Timeout()} @@ -235,9 +241,11 @@ type Conn struct { writeErr error enableWriteCompression bool - newCompressionWriter func(io.WriteCloser) (io.WriteCloser, error) + compressionLevel int + newCompressionWriter func(io.WriteCloser, int) io.WriteCloser // Read fields + reader io.ReadCloser // the current reader returned to the application readErr error br *bufio.Reader readRemaining int64 // bytes remaining in current frame. @@ -253,31 +261,76 @@ type Conn struct { messageReader *messageReader // the current low-level reader readDecompress bool // whether last read frame had RSV1 set - newDecompressionReader func(io.Reader) io.Reader + newDecompressionReader func(io.Reader) io.ReadCloser } func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn { + return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil) +} + +type writeHook struct { + p []byte +} + +func (wh *writeHook) Write(p []byte) (int, error) { + wh.p = p + return len(p), nil +} + +func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn { mu := make(chan bool, 1) mu <- true - if readBufferSize == 0 { - readBufferSize = defaultReadBufferSize + var br *bufio.Reader + if readBufferSize == 0 && brw != nil && brw.Reader != nil { + // Reuse the supplied bufio.Reader if the buffer has a useful size. + // This code assumes that peek on a reader returns + // bufio.Reader.buf[:0]. + brw.Reader.Reset(conn) + if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 { + br = brw.Reader + } } - if readBufferSize < maxControlFramePayloadSize { - readBufferSize = maxControlFramePayloadSize + if br == nil { + if readBufferSize == 0 { + readBufferSize = defaultReadBufferSize + } + if readBufferSize < maxControlFramePayloadSize { + readBufferSize = maxControlFramePayloadSize + } + br = bufio.NewReaderSize(conn, readBufferSize) } - if writeBufferSize == 0 { - writeBufferSize = defaultWriteBufferSize + + var writeBuf []byte + if writeBufferSize == 0 && brw != nil && brw.Writer != nil { + // Use the bufio.Writer's buffer if the buffer has a useful size. This + // code assumes that bufio.Writer.buf[:1] is passed to the + // bufio.Writer's underlying writer. + var wh writeHook + brw.Writer.Reset(&wh) + brw.Writer.WriteByte(0) + brw.Flush() + if cap(wh.p) >= maxFrameHeaderSize+256 { + writeBuf = wh.p[:cap(wh.p)] + } + } + + if writeBuf == nil { + if writeBufferSize == 0 { + writeBufferSize = defaultWriteBufferSize + } + writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize) } c := &Conn{ isServer: isServer, - br: bufio.NewReaderSize(conn, readBufferSize), + br: br, conn: conn, mu: mu, readFinal: true, - writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize), + writeBuf: writeBuf, enableWriteCompression: true, + compressionLevel: defaultCompressionLevel, } c.SetCloseHandler(nil) c.SetPingHandler(nil) @@ -443,11 +496,7 @@ func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { } c.writer = mw if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { - w, err := c.newCompressionWriter(c.writer) - if err != nil { - c.writer = nil - return nil, err - } + w := c.newCompressionWriter(c.writer, c.compressionLevel) mw.compress = true c.writer = w } @@ -654,12 +703,33 @@ func (w *messageWriter) Close() error { return nil } +// WritePreparedMessage writes prepared message into connection. +func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error { + frameType, frameData, err := pm.frame(prepareKey{ + isServer: c.isServer, + compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType), + compressionLevel: c.compressionLevel, + }) + if err != nil { + return err + } + if c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = true + err = c.write(frameType, c.writeDeadline, frameData, nil) + if !c.isWriting { + panic("concurrent write to websocket connection") + } + c.isWriting = false + return err +} + // WriteMessage is a helper method for getting a writer using NextWriter, // writing the message and closing the writer. func (c *Conn) WriteMessage(messageType int, data []byte) error { if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { - // Fast path with no allocations and single frame. if err := c.prepWrite(messageType); err != nil { @@ -855,6 +925,11 @@ func (c *Conn) handleProtocolError(message string) error { // permanent. Once this method returns a non-nil error, all subsequent calls to // this method return the same error. func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { + // Close previous reader, only relevant for decompression. + if c.reader != nil { + c.reader.Close() + c.reader = nil + } c.messageReader = nil c.readLength = 0 @@ -867,11 +942,11 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { } if frameType == TextMessage || frameType == BinaryMessage { c.messageReader = &messageReader{c} - var r io.Reader = c.messageReader + c.reader = c.messageReader if c.readDecompress { - r = c.newDecompressionReader(r) + c.reader = c.newDecompressionReader(c.reader) } - return frameType, r, nil + return frameType, c.reader, nil } } @@ -933,6 +1008,10 @@ func (r *messageReader) Read(b []byte) (int, error) { return 0, err } +func (r *messageReader) Close() error { + return nil +} + // ReadMessage is a helper method for getting a reader using NextReader and // reading from that reader to a buffer. func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { @@ -969,6 +1048,15 @@ func (c *Conn) CloseHandler() func(code int, text string) error { // The code argument to h is the received close code or CloseNoStatusReceived // if the close message is empty. The default close handler sends a close frame // back to the peer. +// +// The application must read the connection to process close messages as +// described in the section on Control Frames above. +// +// The connection read methods return a CloseError when a close frame is +// received. Most applications should handle close messages as part of their +// normal error handling. Applications should only set a close handler when the +// application must perform some action before sending a close frame back to +// the peer. func (c *Conn) SetCloseHandler(h func(code int, text string) error) { if h == nil { h = func(code int, text string) error { @@ -991,6 +1079,9 @@ func (c *Conn) PingHandler() func(appData string) error { // SetPingHandler sets the handler for ping messages received from the peer. // The appData argument to h is the PING frame application data. The default // ping handler sends a pong to the peer. +// +// The application must read the connection to process ping messages as +// described in the section on Control Frames above. func (c *Conn) SetPingHandler(h func(appData string) error) { if h == nil { h = func(message string) error { @@ -1014,6 +1105,9 @@ func (c *Conn) PongHandler() func(appData string) error { // SetPongHandler sets the handler for pong messages received from the peer. // The appData argument to h is the PONG frame application data. The default // pong handler does nothing. +// +// The application must read the connection to process ping messages as +// described in the section on Control Frames above. func (c *Conn) SetPongHandler(h func(appData string) error) { if h == nil { h = func(string) error { return nil } @@ -1034,6 +1128,18 @@ func (c *Conn) EnableWriteCompression(enable bool) { c.enableWriteCompression = enable } +// SetCompressionLevel sets the flate compression level for subsequent text and +// binary messages. This function is a noop if compression was not negotiated +// with the peer. See the compress/flate package for a description of +// compression levels. +func (c *Conn) SetCompressionLevel(level int) error { + if !isValidCompressionLevel(level) { + return errors.New("websocket: invalid compression level") + } + c.compressionLevel = level + return nil +} + // FormatCloseMessage formats closeCode and text as a WebSocket close message. func FormatCloseMessage(closeCode int, text string) []byte { buf := make([]byte, 2+len(text)) diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go index 610acf71289..e291a952c1e 100644 --- a/vendor/github.com/gorilla/websocket/doc.go +++ b/vendor/github.com/gorilla/websocket/doc.go @@ -118,9 +118,10 @@ // // Applications are responsible for ensuring that no more than one goroutine // calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, -// WriteJSON) concurrently and that no more than one goroutine calls the read -// methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, -// SetPingHandler) concurrently. +// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and +// that no more than one goroutine calls the read methods (NextReader, +// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) +// concurrently. // // The Close and WriteControl methods can be called concurrently with all other // methods. @@ -150,19 +151,25 @@ // application's responsibility to check the Origin header before calling // Upgrade. // -// Compression [Experimental] +// Compression EXPERIMENTAL // // Per message compression extensions (RFC 7692) are experimentally supported // by this package in a limited capacity. Setting the EnableCompression option // to true in Dialer or Upgrader will attempt to negotiate per message deflate -// support. If compression was successfully negotiated with the connection's -// peer, any message received in compressed form will be automatically -// decompressed. All Read methods will return uncompressed bytes. +// support. +// +// var upgrader = websocket.Upgrader{ +// EnableCompression: true, +// } +// +// If compression was successfully negotiated with the connection's peer, any +// message received in compressed form will be automatically decompressed. +// All Read methods will return uncompressed bytes. // // Per message compression of messages written to a connection can be enabled // or disabled by calling the corresponding Conn method: // -// conn.EnableWriteCompression(true) +// conn.EnableWriteCompression(false) // // Currently this package does not support compression with "context takeover". // This means that messages must be compressed and decompressed in isolation, diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go index 6758a2cb7a4..6a88bbc7434 100644 --- a/vendor/github.com/gorilla/websocket/mask.go +++ b/vendor/github.com/gorilla/websocket/mask.go @@ -2,20 +2,14 @@ // this source code is governed by a BSD-style license that can be found in the // LICENSE file. +// +build !appengine + package websocket -import ( - "math/rand" - "unsafe" -) +import "unsafe" const wordSize = int(unsafe.Sizeof(uintptr(0))) -func newMaskKey() [4]byte { - n := rand.Uint32() - return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} -} - func maskBytes(key [4]byte, pos int, b []byte) int { // Mask one byte at a time for small buffers. diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go new file mode 100644 index 00000000000..2aac060e52e --- /dev/null +++ b/vendor/github.com/gorilla/websocket/mask_safe.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of +// this source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +// +build appengine + +package websocket + +func maskBytes(key [4]byte, pos int, b []byte) int { + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + return pos & 3 +} diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go new file mode 100644 index 00000000000..1efffbd1ebe --- /dev/null +++ b/vendor/github.com/gorilla/websocket/prepared.go @@ -0,0 +1,103 @@ +// Copyright 2017 The Gorilla WebSocket 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 websocket + +import ( + "bytes" + "net" + "sync" + "time" +) + +// PreparedMessage caches on the wire representations of a message payload. +// Use PreparedMessage to efficiently send a message payload to multiple +// connections. PreparedMessage is especially useful when compression is used +// because the CPU and memory expensive compression operation can be executed +// once for a given set of compression options. +type PreparedMessage struct { + messageType int + data []byte + err error + mu sync.Mutex + frames map[prepareKey]*preparedFrame +} + +// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage. +type prepareKey struct { + isServer bool + compress bool + compressionLevel int +} + +// preparedFrame contains data in wire representation. +type preparedFrame struct { + once sync.Once + data []byte +} + +// NewPreparedMessage returns an initialized PreparedMessage. You can then send +// it to connection using WritePreparedMessage method. Valid wire +// representation will be calculated lazily only once for a set of current +// connection options. +func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) { + pm := &PreparedMessage{ + messageType: messageType, + frames: make(map[prepareKey]*preparedFrame), + data: data, + } + + // Prepare a plain server frame. + _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false}) + if err != nil { + return nil, err + } + + // To protect against caller modifying the data argument, remember the data + // copied to the plain server frame. + pm.data = frameData[len(frameData)-len(data):] + return pm, nil +} + +func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { + pm.mu.Lock() + frame, ok := pm.frames[key] + if !ok { + frame = &preparedFrame{} + pm.frames[key] = frame + } + pm.mu.Unlock() + + var err error + frame.once.Do(func() { + // Prepare a frame using a 'fake' connection. + // TODO: Refactor code in conn.go to allow more direct construction of + // the frame. + mu := make(chan bool, 1) + mu <- true + var nc prepareConn + c := &Conn{ + conn: &nc, + mu: mu, + isServer: key.isServer, + compressionLevel: key.compressionLevel, + enableWriteCompression: true, + writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize), + } + if key.compress { + c.newCompressionWriter = compressNoContextTakeover + } + err = c.WriteMessage(pm.messageType, pm.data) + frame.data = nc.buf.Bytes() + }) + return pm.messageType, frame.data, err +} + +type prepareConn struct { + buf bytes.Buffer + net.Conn +} + +func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) } +func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil } diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go index aaedebdbe10..3495e0f1abc 100644 --- a/vendor/github.com/gorilla/websocket/server.go +++ b/vendor/github.com/gorilla/websocket/server.go @@ -28,8 +28,9 @@ type Upgrader struct { HandshakeTimeout time.Duration // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer - // size is zero, then a default value of 4096 is used. The I/O buffer sizes - // do not limit the size of the messages that can be sent or received. + // size is zero, then buffers allocated by the HTTP server are used. The + // I/O buffer sizes do not limit the size of the messages that can be sent + // or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the server's supported protocols in order of @@ -104,23 +105,23 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header // response. func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { if r.Method != "GET" { - return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET") + return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET") } if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { - return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific Sec-Websocket-Extensions headers are unsupported") - } - - if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") + return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported") } if !tokenListContainsValue(r.Header, "Connection", "upgrade") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header") } if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header") + } + + if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { + return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") } checkOrigin := u.CheckOrigin @@ -128,12 +129,12 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade checkOrigin = checkSameOrigin } if !checkOrigin(r) { - return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") + return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed") } challengeKey := r.Header.Get("Sec-Websocket-Key") if challengeKey == "" { - return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank") } subprotocol := u.selectSubprotocol(r, responseHeader) @@ -152,7 +153,6 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade var ( netConn net.Conn - br *bufio.Reader err error ) @@ -160,19 +160,18 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade if !ok { return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") } - var rw *bufio.ReadWriter - netConn, rw, err = h.Hijack() + var brw *bufio.ReadWriter + netConn, brw, err = h.Hijack() if err != nil { return u.returnError(w, r, http.StatusInternalServerError, err.Error()) } - br = rw.Reader - if br.Buffered() > 0 { + if brw.Reader.Buffered() > 0 { netConn.Close() return nil, errors.New("websocket: client sent data before handshake is complete") } - c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize) + c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw) c.subprotocol = subprotocol if compress { diff --git a/vendor/github.com/gosimple/slug/.gitignore b/vendor/github.com/gosimple/slug/.gitignore deleted file mode 100644 index 02a8da53752..00000000000 --- a/vendor/github.com/gosimple/slug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -_* -cover*.out diff --git a/vendor/github.com/gosimple/slug/LICENSE b/vendor/github.com/gosimple/slug/LICENSE new file mode 100644 index 00000000000..a612ad9813b --- /dev/null +++ b/vendor/github.com/gosimple/slug/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/gosimple/slug/README.md b/vendor/github.com/gosimple/slug/README.md deleted file mode 100644 index a2649bdb170..00000000000 --- a/vendor/github.com/gosimple/slug/README.md +++ /dev/null @@ -1,54 +0,0 @@ -slug -==== - -Package `slug` generate slug from unicode string, URL-friendly slugify with -multiple languages support. - -[![GoDoc](https://godoc.org/github.com/gosimple/slug?status.png)](https://godoc.org/github.com/gosimple/slug) -[![Build Status](https://drone.io/github.com/gosimple/slug/status.png)](https://drone.io/github.com/gosimple/slug/latest) - -[Documentation online](http://godoc.org/github.com/gosimple/slug) - -## Example - - package main - - import( - "github.com/gosimple/slug" - "fmt" - ) - - func main () { - text := slug.Make("Hellö Wörld хелло ворлд") - fmt.Println(text) // Will print hello-world-khello-vorld - - someText := slug.Make("影師") - fmt.Println(someText) // Will print: ying-shi - - enText := slug.MakeLang("This & that", "en") - fmt.Println(enText) // Will print 'this-and-that' - - deText := slug.MakeLang("Diese & Dass", "de") - fmt.Println(deText) // Will print 'diese-und-dass' - - slug.CustomSub = map[string]string{ - "water": "sand", - } - textSub := slug.Make("water is hot") - fmt.Println(textSub) // Will print 'sand-is-hot' - } - -### Requests or bugs? - - -## Installation - - go get -u github.com/gosimple/slug - -## License - -The source files are distributed under the -[Mozilla Public License, version 2.0](http://mozilla.org/MPL/2.0/), -unless otherwise noted. -Please read the [FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html) -if you have further questions regarding the license. diff --git a/vendor/github.com/gosimple/slug/default_substitution.go b/vendor/github.com/gosimple/slug/default_substitution.go deleted file mode 100644 index 847c85d1fc8..00000000000 --- a/vendor/github.com/gosimple/slug/default_substitution.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 by Dobrosław Żybort. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package slug - -var defaultSub = map[rune]string{ - '"': "", - '\'': "", - '’': "", - '‒': "-", // figure dash - '–': "-", // en dash - '—': "-", // em dash - '―': "-", // horizontal bar -} diff --git a/vendor/github.com/gosimple/slug/languages_substitution.go b/vendor/github.com/gosimple/slug/languages_substitution.go index 49ebb48dbf4..ba8ad01815e 100644 --- a/vendor/github.com/gosimple/slug/languages_substitution.go +++ b/vendor/github.com/gosimple/slug/languages_substitution.go @@ -5,6 +5,25 @@ package slug +func init() { + // Merge language subs with the default one + for _, sub := range []*map[rune]string{&deSub, &enSub, &plSub, &esSub} { + for key, value := range defaultSub { + (*sub)[key] = value + } + } +} + +var defaultSub = map[rune]string{ + '"': "", + '\'': "", + '’': "", + '‒': "-", // figure dash + '–': "-", // en dash + '—': "-", // em dash + '―': "-", // horizontal bar +} + var deSub = map[rune]string{ '&': "und", '@': "an", @@ -24,3 +43,15 @@ var esSub = map[rune]string{ '&': "y", '@': "en", } + +var grSub = map[rune]string{ + '&': "kai", + 'η': "i", + 'ή': "i", + 'Η': "i", + 'ι': "i", + 'ί': "i", + 'Ι': "i", + 'χ': "x", + 'Χ': "x", +} diff --git a/vendor/github.com/gosimple/slug/slug.go b/vendor/github.com/gosimple/slug/slug.go index b2c7d62514e..bd3ec51aa23 100644 --- a/vendor/github.com/gosimple/slug/slug.go +++ b/vendor/github.com/gosimple/slug/slug.go @@ -6,24 +6,30 @@ package slug import ( + "bytes" "regexp" + "sort" "strings" "github.com/rainycape/unidecode" ) var ( - // Custom substitution map + // CustomSub stores custom substitution map CustomSub map[string]string - // Custom rune substitution map + // CustomRuneSub stores custom rune substitution map CustomRuneSub map[rune]string - // Maximum slug length. It's smart so it will cat slug after full word. + // MaxLength stores maximum slug length. + // It's smart so it will cat slug after full word. // By default slugs aren't shortened. // If MaxLength is smaller than length of the first word, then returned // slug will contain only substring from the first word truncated // after MaxLength. MaxLength int + + regexpNonAuthorizedChars = regexp.MustCompile("[^a-z0-9-_]") + regexpMultipleDashes = regexp.MustCompile("-+") ) //============================================================================= @@ -54,20 +60,20 @@ func MakeLang(s string, lang string) (slug string) { slug = SubstituteRune(slug, plSub) case "es": slug = SubstituteRune(slug, esSub) + case "gr": + slug = SubstituteRune(slug, grSub) default: // fallback to "en" if lang not found slug = SubstituteRune(slug, enSub) } - slug = SubstituteRune(slug, defaultSub) - // Process all non ASCII symbols slug = unidecode.Unidecode(slug) slug = strings.ToLower(slug) // Process all remaining symbols - slug = regexp.MustCompile("[^a-z0-9-_]").ReplaceAllString(slug, "-") - slug = regexp.MustCompile("-+").ReplaceAllString(slug, "-") + slug = regexpNonAuthorizedChars.ReplaceAllString(slug, "-") + slug = regexpMultipleDashes.ReplaceAllString(slug, "-") slug = strings.Trim(slug, "-") if MaxLength > 0 { @@ -78,26 +84,34 @@ func MakeLang(s string, lang string) (slug string) { } // Substitute returns string with superseded all substrings from -// provided substitution map. +// provided substitution map. Substitution map will be applied in alphabetic +// order. Many passes, on one substitution another one could apply. func Substitute(s string, sub map[string]string) (buf string) { buf = s - for key, val := range sub { - buf = strings.Replace(s, key, val, -1) + var keys []string + for k := range sub { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, key := range keys { + buf = strings.Replace(buf, key, sub[key], -1) } return } // SubstituteRune substitutes string chars with provided rune -// substitution map. -func SubstituteRune(s string, sub map[rune]string) (buf string) { +// substitution map. One pass. +func SubstituteRune(s string, sub map[rune]string) string { + var buf bytes.Buffer for _, c := range s { if d, ok := sub[c]; ok { - buf += d + buf.WriteString(d) } else { - buf += string(c) + buf.WriteRune(c) } } - return + return buf.String() } func smartTruncate(text string) string { @@ -121,3 +135,23 @@ func smartTruncate(text string) string { } return strings.Trim(truncated, "-") } + +// IsSlug returns True if provided text does not contain white characters, +// punctuation, all letters are lower case and only from ASCII range. +// It could contain `-` and `_` but not at the beginning or end of the text. +// It should be in range of the MaxLength var if specified. +// All output from slug.Make(text) should pass this test. +func IsSlug(text string) bool { + if text == "" || + (MaxLength > 0 && len(text) > MaxLength) || + text[0] == '-' || text[0] == '_' || + text[len(text)-1] == '-' || text[len(text)-1] == '_' { + return false + } + for _, c := range text { + if (c < 'a' || c > 'z') && c != '-' && c != '_' && (c < '0' || c > '9') { + return false + } + } + return true +} diff --git a/vendor/github.com/gosimple/slug/slug_test.go b/vendor/github.com/gosimple/slug/slug_test.go deleted file mode 100644 index b996c3686b8..00000000000 --- a/vendor/github.com/gosimple/slug/slug_test.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2013 by Dobrosław Żybort. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package slug - -import ( - "testing" -) - -//============================================================================= - -func TestSlugMake(t *testing.T) { - var testCases = []struct { - in string - want string - }{ - {"DOBROSLAWZYBORT", "dobroslawzybort"}, - {"Dobroslaw Zybort", "dobroslaw-zybort"}, - {" Dobroslaw Zybort ?", "dobroslaw-zybort"}, - {"Dobrosław Żybort", "dobroslaw-zybort"}, - {"Ala ma 6 kotów.", "ala-ma-6-kotow"}, - - {"áÁàÀãÃâÂäÄąĄą̊Ą̊", "aaaaaaaaaaaaaa"}, - {"ćĆĉĈçÇ", "cccccc"}, - {"éÉèÈẽẼêÊëËęĘ", "eeeeeeeeeeee"}, - {"íÍìÌĩĨîÎïÏįĮ", "iiiiiiiiiiii"}, - {"łŁ", "ll"}, - {"ńŃ", "nn"}, - {"óÓòÒõÕôÔöÖǫǪǭǬø", "ooooooooooooooo"}, - {"śŚ", "ss"}, - {"úÚùÙũŨûÛüÜųŲ", "uuuuuuuuuuuu"}, - {"y̨Y̨", "yy"}, - {"źŹżŹ", "zzzz"}, - {"·/,:;`˜'\"", ""}, - {"2000–2013", "2000-2013"}, - {"style—not", "style-not"}, - {"test_slug", "test_slug"}, - {"Æ", "ae"}, - {"Ich heiße", "ich-heisse"}, - - {"This & that", "this-and-that"}, - {"fácil €", "facil-eu"}, - {"smile ☺", "smile"}, - {"Hellö Wörld хелло ворлд", "hello-world-khello-vorld"}, - {"\"C'est déjà l’été.\"", "cest-deja-lete"}, - {"jaja---lol-méméméoo--a", "jaja-lol-mememeoo-a"}, - {"影師", "ying-shi"}, - } - - for index, st := range testCases { - got := Make(st.in) - if got != st.want { - t.Errorf( - "%d. Make(%#v) = %#v; want %#v", - index, st.in, got, st.want) - } - } -} - -func TestSlugMakeLang(t *testing.T) { - var testCases = []struct { - lang string - in string - want string - }{ - {"en", "This & that", "this-and-that"}, - {"de", "This & that", "this-und-that"}, - {"pl", "This & that", "this-i-that"}, - {"es", "This & that", "this-y-that"}, - {"test", "This & that", "this-and-that"}, // unknown lang, fallback to "en" - } - - for index, smlt := range testCases { - got := MakeLang(smlt.in, smlt.lang) - if got != smlt.want { - t.Errorf( - "%d. MakeLang(%#v, %#v) = %#v; want %#v", - index, smlt.in, smlt.lang, got, smlt.want) - } - } -} - -func TestSlugMakeUserSubstituteLang(t *testing.T) { - var testCases = []struct { - cSub map[string]string - lang string - in string - want string - }{ - {map[string]string{"'": " "}, "en", "That's great", "that-s-great"}, - {map[string]string{"&": "or"}, "en", "This & that", "this-or-that"}, // by default "&" => "and" - {map[string]string{"&": "or"}, "de", "This & that", "this-or-that"}, // by default "&" => "und" - } - - for index, smust := range testCases { - CustomSub = smust.cSub - got := MakeLang(smust.in, smust.lang) - if got != smust.want { - t.Errorf( - "%d. %#v; MakeLang(%#v, %#v) = %#v; want %#v", - index, smust.cSub, smust.in, smust.lang, - got, smust.want) - - } - } -} - -func TestSlugMakeSubstituteOrderLang(t *testing.T) { - // Always substitute runes first - var testCases = []struct { - rSub map[rune]string - sSub map[string]string - in string - want string - }{ - {map[rune]string{'o': "left"}, map[string]string{"o": "right"}, "o o", "left-left"}, - {map[rune]string{'&': "down"}, map[string]string{"&": "up"}, "&", "down"}, - } - - for index, smsot := range testCases { - CustomRuneSub = smsot.rSub - CustomSub = smsot.sSub - got := Make(smsot.in) - if got != smsot.want { - t.Errorf( - "%d. %#v; %#v; Make(%#v) = %#v; want %#v", - index, smsot.rSub, smsot.sSub, smsot.in, - got, smsot.want) - - } - } -} - -func TestSubstituteLang(t *testing.T) { - var testCases = []struct { - cSub map[string]string - in string - want string - }{ - {map[string]string{"o": "no"}, "o o o", "no no no"}, - {map[string]string{"'": " "}, "That's great", "That s great"}, - } - - for index, sst := range testCases { - got := Substitute(sst.in, sst.cSub) - if got != sst.want { - t.Errorf( - "%d. Substitute(%#v, %#v) = %#v; want %#v", - index, sst.in, sst.cSub, got, sst.want) - } - } -} - -func TestSubstituteRuneLang(t *testing.T) { - var testCases = []struct { - cSub map[rune]string - in string - want string - }{ - {map[rune]string{'o': "no"}, "o o o", "no no no"}, - {map[rune]string{'\'': " "}, "That's great", "That s great"}, - } - - for index, ssrt := range testCases { - got := SubstituteRune(ssrt.in, ssrt.cSub) - if got != ssrt.want { - t.Errorf( - "%d. SubstituteRune(%#v, %#v) = %#v; want %#v", - index, ssrt.in, ssrt.cSub, got, ssrt.want) - } - } -} - -func TestSlugMakeSmartTruncate(t *testing.T) { - var testCases = []struct { - in string - maxLength int - want string - }{ - {"DOBROSLAWZYBORT", 100, "dobroslawzybort"}, - {"Dobroslaw Zybort", 100, "dobroslaw-zybort"}, - {"Dobroslaw Zybort", 12, "dobroslaw"}, - {" Dobroslaw Zybort ?", 12, "dobroslaw"}, - {"Ala ma 6 kotów.", 10, "ala-ma-6"}, - {"Dobrosław Żybort", 5, "dobro"}, - } - - for index, smstt := range testCases { - MaxLength = smstt.maxLength - got := Make(smstt.in) - if got != smstt.want { - t.Errorf( - "%d. MaxLength = %v; Make(%#v) = %#v; want %#v", - index, smstt.maxLength, smstt.in, got, smstt.want) - } - } -} - -func BenchmarkMakeShortAscii(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - Make("Hello world") - } -} -func BenchmarkMakeShort(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - Make("хелло ворлд") - } -} - -func BenchmarkMakeShortSymbols(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - Make("·/,:;`˜'\" &€£¥") - } -} - -func BenchmarkMakeMediumAscii(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - Make("ABCDE FGHIJ KLMNO PQRST UWXYZ ABCDE FGHIJ KLMNO PQRST UWXYZ ABCDE") - } -} - -func BenchmarkMakeMedium(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - Make("ヲァィゥェ ォャュョッ ーアイウエ オカキクケ コサシスセ ソタチツテ トナニヌネ ノハヒフヘ ホマミムメ モヤユヨラ リルレロワ") - } -} - -func BenchmarkMakeLongAscii(b *testing.B) { - longStr := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi " + - "pulvinar sodales ultrices. Nulla facilisi. Sed at vestibulum erat. Ut " + - "sit amet urna posuere, sagittis eros ac, varius nisi. Morbi ullamcorper " + - "odio at nunc pulvinar mattis. Vestibulum rutrum, ante eu dictum mattis, " + - "elit risus finibus nunc, consectetur facilisis eros leo ut sapien. Sed " + - "pulvinar volutpat mi. Cras semper mi ac eros accumsan, at feugiat massa " + - "elementum. Morbi eget dolor sit amet purus condimentum egestas non ut " + - "sapien. Duis feugiat magna vitae nisi lobortis, quis finibus sem " + - "sollicitudin. Pellentesque eleifend blandit ipsum, ut porta arcu " + - "ultricies et. Fusce vel ipsum porta, placerat diam ac, consectetur " + - "magna. Nulla in porta sem. Suspendisse commodo, felis in molestie " + - "ultricies, arcu ipsum aliquet turpis, elementum dapibus ipsum lorem a " + - "nisl. Etiam varius imperdiet placerat. Aliquam euismod lacus arcu, " + - "ultrices hendrerit est pellentesque vel. Aliquam sit amet laoreet leo. " + - "Integer eros libero, mollis sed posuere." - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Make(longStr) - } -} - -func BenchmarkSubstituteRuneShort(b *testing.B) { - shortStr := "Hello/Hi world" - subs := map[rune]string{'o': "no", '/': "slash"} - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - SubstituteRune(shortStr, subs) - } -} - -func BenchmarkSubstituteRuneLong(b *testing.B) { - longStr := "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi " + - "pulvinar sodales ultrices. Nulla facilisi. Sed at vestibulum erat. Ut " + - "sit amet urna posuere, sagittis eros ac, varius nisi. Morbi ullamcorper " + - "odio at nunc pulvinar mattis. Vestibulum rutrum, ante eu dictum mattis, " + - "elit risus finibus nunc, consectetur facilisis eros leo ut sapien. Sed " + - "pulvinar volutpat mi. Cras semper mi ac eros accumsan, at feugiat massa " + - "elementum. Morbi eget dolor sit amet purus condimentum egestas non ut " + - "sapien. Duis feugiat magna vitae nisi lobortis, quis finibus sem " + - "sollicitudin. Pellentesque eleifend blandit ipsum, ut porta arcu " + - "ultricies et. Fusce vel ipsum porta, placerat diam ac, consectetur " + - "magna. Nulla in porta sem. Suspendisse commodo, felis in molestie " + - "ultricies, arcu ipsum aliquet turpis, elementum dapibus ipsum lorem a " + - "nisl. Etiam varius imperdiet placerat. Aliquam euismod lacus arcu, " + - "ultrices hendrerit est pellentesque vel. Aliquam sit amet laoreet leo. " + - "Integer eros libero, mollis sed posuere." - subs := map[rune]string{ - 'o': "no", - '/': "slash", - 'i': "done", - 'E': "es", - 'a': "ASD", - '1': "one", - 'l': "onetwo", - } - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - SubstituteRune(longStr, subs) - } -} - -func BenchmarkSmartTruncateShort(b *testing.B) { - shortStr := "Hello-world" - MaxLength = 8 - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - smartTruncate(shortStr) - } -} - -func BenchmarkSmartTruncateLong(b *testing.B) { - longStr := "Lorem-ipsum-dolor-sit-amet,-consectetur-adipiscing-elit.-Morbi-" + - "pulvinar-sodales-ultrices.-Nulla-facilisi.-Sed-at-vestibulum-erat.-Ut-" + - "sit-amet-urna-posuere,-sagittis-eros-ac,-varius-nisi.-Morbi-ullamcorper-" + - "odio-at-nunc-pulvinar-mattis.-Vestibulum-rutrum,-ante-eu-dictum-mattis,-" + - "elit-risus-finibus-nunc,-consectetur-facilisis-eros-leo-ut-sapien.-Sed-" + - "pulvinar-volutpat-mi.-Cras-semper-mi-ac-eros-accumsan,-at-feugiat-massa-" + - "elementum.-Morbi-eget-dolor-sit-amet-purus-condimentum-egestas-non-ut-" + - "sapien.-Duis-feugiat-magna-vitae-nisi-lobortis,-quis-finibus-sem-" + - "sollicitudin.-Pellentesque-eleifend-blandit-ipsum,-ut-porta-arcu-" + - "ultricies-et.-Fusce-vel-ipsum-porta,-placerat-diam-ac,-consectetur-" + - "magna.-Nulla-in-porta-sem.-Suspendisse-commodo,-felis-in-molestie-" + - "ultricies,-arcu-ipsum-aliquet-turpis,-elementum-dapibus-ipsum-lorem-a-" + - "nisl.-Etiam-varius-imperdiet-placerat.-Aliquam-euismod-lacus-arcu,-" + - "ultrices-hendrerit-est-pellentesque-vel.-Aliquam-sit-amet-laoreet-leo.-" + - "Integer-eros-libero,-mollis-sed-posuere." - MaxLength = 256 - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - smartTruncate(longStr) - } -} diff --git a/vendor/github.com/grafana/grafana_plugin_model/LICENSE b/vendor/github.com/grafana/grafana_plugin_model/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/grafana/grafana_plugin_model/LICENSE @@ -0,0 +1,201 @@ + 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. diff --git a/vendor/github.com/grafana/grafana_plugin_model/go/datasource/datasource.pb.go b/vendor/github.com/grafana/grafana_plugin_model/go/datasource/datasource.pb.go new file mode 100644 index 00000000000..35e1c4dee26 --- /dev/null +++ b/vendor/github.com/grafana/grafana_plugin_model/go/datasource/datasource.pb.go @@ -0,0 +1,638 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: datasource.proto + +/* +Package datasource is a generated protocol buffer package. + +It is generated from these files: + datasource.proto + +It has these top-level messages: + DatasourceRequest + Query + TimeRange + DatasourceResponse + QueryResult + Table + TableColumn + TableRow + RowValue + DatasourceInfo + TimeSeries + Point +*/ +package datasource + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type RowValue_Kind int32 + +const ( + // Field type null. + RowValue_TYPE_NULL RowValue_Kind = 0 + // Field type double. + RowValue_TYPE_DOUBLE RowValue_Kind = 1 + // Field type int64. + RowValue_TYPE_INT64 RowValue_Kind = 2 + // Field type bool. + RowValue_TYPE_BOOL RowValue_Kind = 3 + // Field type string. + RowValue_TYPE_STRING RowValue_Kind = 4 + // Field type bytes. + RowValue_TYPE_BYTES RowValue_Kind = 5 +) + +var RowValue_Kind_name = map[int32]string{ + 0: "TYPE_NULL", + 1: "TYPE_DOUBLE", + 2: "TYPE_INT64", + 3: "TYPE_BOOL", + 4: "TYPE_STRING", + 5: "TYPE_BYTES", +} +var RowValue_Kind_value = map[string]int32{ + "TYPE_NULL": 0, + "TYPE_DOUBLE": 1, + "TYPE_INT64": 2, + "TYPE_BOOL": 3, + "TYPE_STRING": 4, + "TYPE_BYTES": 5, +} + +func (x RowValue_Kind) String() string { + return proto.EnumName(RowValue_Kind_name, int32(x)) +} +func (RowValue_Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{8, 0} } + +type DatasourceRequest struct { + TimeRange *TimeRange `protobuf:"bytes,1,opt,name=timeRange" json:"timeRange,omitempty"` + Datasource *DatasourceInfo `protobuf:"bytes,2,opt,name=datasource" json:"datasource,omitempty"` + Queries []*Query `protobuf:"bytes,3,rep,name=queries" json:"queries,omitempty"` +} + +func (m *DatasourceRequest) Reset() { *m = DatasourceRequest{} } +func (m *DatasourceRequest) String() string { return proto.CompactTextString(m) } +func (*DatasourceRequest) ProtoMessage() {} +func (*DatasourceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *DatasourceRequest) GetTimeRange() *TimeRange { + if m != nil { + return m.TimeRange + } + return nil +} + +func (m *DatasourceRequest) GetDatasource() *DatasourceInfo { + if m != nil { + return m.Datasource + } + return nil +} + +func (m *DatasourceRequest) GetQueries() []*Query { + if m != nil { + return m.Queries + } + return nil +} + +type Query struct { + RefId string `protobuf:"bytes,1,opt,name=refId" json:"refId,omitempty"` + MaxDataPoints int64 `protobuf:"varint,2,opt,name=maxDataPoints" json:"maxDataPoints,omitempty"` + IntervalMs int64 `protobuf:"varint,3,opt,name=intervalMs" json:"intervalMs,omitempty"` + ModelJson string `protobuf:"bytes,4,opt,name=modelJson" json:"modelJson,omitempty"` +} + +func (m *Query) Reset() { *m = Query{} } +func (m *Query) String() string { return proto.CompactTextString(m) } +func (*Query) ProtoMessage() {} +func (*Query) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Query) GetRefId() string { + if m != nil { + return m.RefId + } + return "" +} + +func (m *Query) GetMaxDataPoints() int64 { + if m != nil { + return m.MaxDataPoints + } + return 0 +} + +func (m *Query) GetIntervalMs() int64 { + if m != nil { + return m.IntervalMs + } + return 0 +} + +func (m *Query) GetModelJson() string { + if m != nil { + return m.ModelJson + } + return "" +} + +type TimeRange struct { + FromRaw string `protobuf:"bytes,1,opt,name=fromRaw" json:"fromRaw,omitempty"` + ToRaw string `protobuf:"bytes,2,opt,name=toRaw" json:"toRaw,omitempty"` + FromEpochMs int64 `protobuf:"varint,3,opt,name=fromEpochMs" json:"fromEpochMs,omitempty"` + ToEpochMs int64 `protobuf:"varint,4,opt,name=toEpochMs" json:"toEpochMs,omitempty"` +} + +func (m *TimeRange) Reset() { *m = TimeRange{} } +func (m *TimeRange) String() string { return proto.CompactTextString(m) } +func (*TimeRange) ProtoMessage() {} +func (*TimeRange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *TimeRange) GetFromRaw() string { + if m != nil { + return m.FromRaw + } + return "" +} + +func (m *TimeRange) GetToRaw() string { + if m != nil { + return m.ToRaw + } + return "" +} + +func (m *TimeRange) GetFromEpochMs() int64 { + if m != nil { + return m.FromEpochMs + } + return 0 +} + +func (m *TimeRange) GetToEpochMs() int64 { + if m != nil { + return m.ToEpochMs + } + return 0 +} + +type DatasourceResponse struct { + Results []*QueryResult `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` +} + +func (m *DatasourceResponse) Reset() { *m = DatasourceResponse{} } +func (m *DatasourceResponse) String() string { return proto.CompactTextString(m) } +func (*DatasourceResponse) ProtoMessage() {} +func (*DatasourceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *DatasourceResponse) GetResults() []*QueryResult { + if m != nil { + return m.Results + } + return nil +} + +type QueryResult struct { + Error string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` + RefId string `protobuf:"bytes,2,opt,name=refId" json:"refId,omitempty"` + MetaJson string `protobuf:"bytes,3,opt,name=metaJson" json:"metaJson,omitempty"` + Series []*TimeSeries `protobuf:"bytes,4,rep,name=series" json:"series,omitempty"` + Tables []*Table `protobuf:"bytes,5,rep,name=tables" json:"tables,omitempty"` +} + +func (m *QueryResult) Reset() { *m = QueryResult{} } +func (m *QueryResult) String() string { return proto.CompactTextString(m) } +func (*QueryResult) ProtoMessage() {} +func (*QueryResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *QueryResult) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +func (m *QueryResult) GetRefId() string { + if m != nil { + return m.RefId + } + return "" +} + +func (m *QueryResult) GetMetaJson() string { + if m != nil { + return m.MetaJson + } + return "" +} + +func (m *QueryResult) GetSeries() []*TimeSeries { + if m != nil { + return m.Series + } + return nil +} + +func (m *QueryResult) GetTables() []*Table { + if m != nil { + return m.Tables + } + return nil +} + +type Table struct { + Columns []*TableColumn `protobuf:"bytes,1,rep,name=columns" json:"columns,omitempty"` + Rows []*TableRow `protobuf:"bytes,2,rep,name=rows" json:"rows,omitempty"` +} + +func (m *Table) Reset() { *m = Table{} } +func (m *Table) String() string { return proto.CompactTextString(m) } +func (*Table) ProtoMessage() {} +func (*Table) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *Table) GetColumns() []*TableColumn { + if m != nil { + return m.Columns + } + return nil +} + +func (m *Table) GetRows() []*TableRow { + if m != nil { + return m.Rows + } + return nil +} + +type TableColumn struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *TableColumn) Reset() { *m = TableColumn{} } +func (m *TableColumn) String() string { return proto.CompactTextString(m) } +func (*TableColumn) ProtoMessage() {} +func (*TableColumn) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *TableColumn) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type TableRow struct { + Values []*RowValue `protobuf:"bytes,1,rep,name=values" json:"values,omitempty"` +} + +func (m *TableRow) Reset() { *m = TableRow{} } +func (m *TableRow) String() string { return proto.CompactTextString(m) } +func (*TableRow) ProtoMessage() {} +func (*TableRow) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *TableRow) GetValues() []*RowValue { + if m != nil { + return m.Values + } + return nil +} + +type RowValue struct { + Kind RowValue_Kind `protobuf:"varint,1,opt,name=kind,enum=models.RowValue_Kind" json:"kind,omitempty"` + DoubleValue float64 `protobuf:"fixed64,2,opt,name=doubleValue" json:"doubleValue,omitempty"` + Int64Value int64 `protobuf:"varint,3,opt,name=int64Value" json:"int64Value,omitempty"` + BoolValue bool `protobuf:"varint,4,opt,name=boolValue" json:"boolValue,omitempty"` + StringValue string `protobuf:"bytes,5,opt,name=stringValue" json:"stringValue,omitempty"` + BytesValue []byte `protobuf:"bytes,6,opt,name=bytesValue,proto3" json:"bytesValue,omitempty"` +} + +func (m *RowValue) Reset() { *m = RowValue{} } +func (m *RowValue) String() string { return proto.CompactTextString(m) } +func (*RowValue) ProtoMessage() {} +func (*RowValue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *RowValue) GetKind() RowValue_Kind { + if m != nil { + return m.Kind + } + return RowValue_TYPE_NULL +} + +func (m *RowValue) GetDoubleValue() float64 { + if m != nil { + return m.DoubleValue + } + return 0 +} + +func (m *RowValue) GetInt64Value() int64 { + if m != nil { + return m.Int64Value + } + return 0 +} + +func (m *RowValue) GetBoolValue() bool { + if m != nil { + return m.BoolValue + } + return false +} + +func (m *RowValue) GetStringValue() string { + if m != nil { + return m.StringValue + } + return "" +} + +func (m *RowValue) GetBytesValue() []byte { + if m != nil { + return m.BytesValue + } + return nil +} + +type DatasourceInfo struct { + Id int64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + OrgId int64 `protobuf:"varint,2,opt,name=orgId" json:"orgId,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` + Type string `protobuf:"bytes,4,opt,name=type" json:"type,omitempty"` + Url string `protobuf:"bytes,5,opt,name=url" json:"url,omitempty"` + JsonData string `protobuf:"bytes,6,opt,name=jsonData" json:"jsonData,omitempty"` + DecryptedSecureJsonData map[string]string `protobuf:"bytes,7,rep,name=decryptedSecureJsonData" json:"decryptedSecureJsonData,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` +} + +func (m *DatasourceInfo) Reset() { *m = DatasourceInfo{} } +func (m *DatasourceInfo) String() string { return proto.CompactTextString(m) } +func (*DatasourceInfo) ProtoMessage() {} +func (*DatasourceInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *DatasourceInfo) GetId() int64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *DatasourceInfo) GetOrgId() int64 { + if m != nil { + return m.OrgId + } + return 0 +} + +func (m *DatasourceInfo) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *DatasourceInfo) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *DatasourceInfo) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *DatasourceInfo) GetJsonData() string { + if m != nil { + return m.JsonData + } + return "" +} + +func (m *DatasourceInfo) GetDecryptedSecureJsonData() map[string]string { + if m != nil { + return m.DecryptedSecureJsonData + } + return nil +} + +type TimeSeries struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Tags map[string]string `protobuf:"bytes,2,rep,name=tags" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Points []*Point `protobuf:"bytes,3,rep,name=points" json:"points,omitempty"` +} + +func (m *TimeSeries) Reset() { *m = TimeSeries{} } +func (m *TimeSeries) String() string { return proto.CompactTextString(m) } +func (*TimeSeries) ProtoMessage() {} +func (*TimeSeries) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *TimeSeries) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *TimeSeries) GetTags() map[string]string { + if m != nil { + return m.Tags + } + return nil +} + +func (m *TimeSeries) GetPoints() []*Point { + if m != nil { + return m.Points + } + return nil +} + +type Point struct { + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp" json:"timestamp,omitempty"` + Value float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` +} + +func (m *Point) Reset() { *m = Point{} } +func (m *Point) String() string { return proto.CompactTextString(m) } +func (*Point) ProtoMessage() {} +func (*Point) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *Point) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + +func (m *Point) GetValue() float64 { + if m != nil { + return m.Value + } + return 0 +} + +func init() { + proto.RegisterType((*DatasourceRequest)(nil), "models.DatasourceRequest") + proto.RegisterType((*Query)(nil), "models.Query") + proto.RegisterType((*TimeRange)(nil), "models.TimeRange") + proto.RegisterType((*DatasourceResponse)(nil), "models.DatasourceResponse") + proto.RegisterType((*QueryResult)(nil), "models.QueryResult") + proto.RegisterType((*Table)(nil), "models.Table") + proto.RegisterType((*TableColumn)(nil), "models.TableColumn") + proto.RegisterType((*TableRow)(nil), "models.TableRow") + proto.RegisterType((*RowValue)(nil), "models.RowValue") + proto.RegisterType((*DatasourceInfo)(nil), "models.DatasourceInfo") + proto.RegisterType((*TimeSeries)(nil), "models.TimeSeries") + proto.RegisterType((*Point)(nil), "models.Point") + proto.RegisterEnum("models.RowValue_Kind", RowValue_Kind_name, RowValue_Kind_value) +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for DatasourcePlugin service + +type DatasourcePluginClient interface { + Query(ctx context.Context, in *DatasourceRequest, opts ...grpc.CallOption) (*DatasourceResponse, error) +} + +type datasourcePluginClient struct { + cc *grpc.ClientConn +} + +func NewDatasourcePluginClient(cc *grpc.ClientConn) DatasourcePluginClient { + return &datasourcePluginClient{cc} +} + +func (c *datasourcePluginClient) Query(ctx context.Context, in *DatasourceRequest, opts ...grpc.CallOption) (*DatasourceResponse, error) { + out := new(DatasourceResponse) + err := grpc.Invoke(ctx, "/models.DatasourcePlugin/Query", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for DatasourcePlugin service + +type DatasourcePluginServer interface { + Query(context.Context, *DatasourceRequest) (*DatasourceResponse, error) +} + +func RegisterDatasourcePluginServer(s *grpc.Server, srv DatasourcePluginServer) { + s.RegisterService(&_DatasourcePlugin_serviceDesc, srv) +} + +func _DatasourcePlugin_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DatasourceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatasourcePluginServer).Query(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/models.DatasourcePlugin/Query", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatasourcePluginServer).Query(ctx, req.(*DatasourceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _DatasourcePlugin_serviceDesc = grpc.ServiceDesc{ + ServiceName: "models.DatasourcePlugin", + HandlerType: (*DatasourcePluginServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Query", + Handler: _DatasourcePlugin_Query_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "datasource.proto", +} + +func init() { proto.RegisterFile("datasource.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 841 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdb, 0x8e, 0x23, 0x35, + 0x10, 0xa5, 0x2f, 0xc9, 0xa4, 0x2b, 0x3b, 0xa1, 0xd7, 0xdc, 0x42, 0x34, 0x42, 0xa1, 0xb5, 0x88, + 0x80, 0x44, 0x40, 0xd9, 0xd1, 0x80, 0x40, 0xe2, 0x21, 0x3b, 0x11, 0xca, 0x10, 0x66, 0x06, 0x27, + 0x8b, 0xb4, 0x08, 0x09, 0x75, 0xd2, 0x4e, 0x68, 0xb6, 0xbb, 0x9d, 0xb5, 0xdd, 0x13, 0x22, 0x9e, + 0xf8, 0x18, 0x24, 0x9e, 0xf9, 0x01, 0x1e, 0xf9, 0x2d, 0xe4, 0xea, 0x6b, 0x76, 0x02, 0x12, 0x6f, + 0xae, 0x73, 0x4e, 0x95, 0xcb, 0x55, 0x65, 0x1b, 0xdc, 0xc0, 0x57, 0xbe, 0xe4, 0xa9, 0x58, 0xb1, + 0xe1, 0x56, 0x70, 0xc5, 0x49, 0x33, 0xe6, 0x01, 0x8b, 0xa4, 0xf7, 0xbb, 0x01, 0x0f, 0x2f, 0x4b, + 0x92, 0xb2, 0x17, 0x29, 0x93, 0x8a, 0x7c, 0x0c, 0x8e, 0x0a, 0x63, 0x46, 0xfd, 0x64, 0xc3, 0xba, + 0x46, 0xdf, 0x18, 0xb4, 0x47, 0x0f, 0x87, 0x99, 0xc7, 0x70, 0x51, 0x10, 0xb4, 0xd2, 0x90, 0x0b, + 0x80, 0x6a, 0x8b, 0xae, 0x89, 0x1e, 0x6f, 0x16, 0x1e, 0x55, 0xfc, 0x69, 0xb2, 0xe6, 0xb4, 0xa6, + 0x24, 0xef, 0xc3, 0xc9, 0x8b, 0x94, 0x89, 0x90, 0xc9, 0xae, 0xd5, 0xb7, 0x06, 0xed, 0xd1, 0x69, + 0xe1, 0xf4, 0x6d, 0xca, 0xc4, 0x9e, 0x16, 0xac, 0xf7, 0x9b, 0x01, 0x0d, 0x84, 0xc8, 0xeb, 0xd0, + 0x10, 0x6c, 0x3d, 0x0d, 0x30, 0x2f, 0x87, 0x66, 0x06, 0x79, 0x04, 0xa7, 0xb1, 0xff, 0x8b, 0xde, + 0xe9, 0x96, 0x87, 0x89, 0x92, 0x98, 0x83, 0x45, 0x0f, 0x41, 0xf2, 0x0e, 0x40, 0x98, 0x28, 0x26, + 0xee, 0xfc, 0xe8, 0x1b, 0xbd, 0xa3, 0x96, 0xd4, 0x10, 0x72, 0x06, 0x0e, 0x6e, 0x7f, 0x25, 0x79, + 0xd2, 0xb5, 0x31, 0x7e, 0x05, 0x78, 0xbf, 0x82, 0x53, 0x1e, 0x9e, 0x74, 0xe1, 0x64, 0x2d, 0x78, + 0x4c, 0xfd, 0x5d, 0x9e, 0x48, 0x61, 0xea, 0x04, 0x15, 0xd7, 0xb8, 0x99, 0x25, 0x88, 0x06, 0xe9, + 0x43, 0x5b, 0x0b, 0x26, 0x5b, 0xbe, 0xfa, 0xa9, 0xdc, 0xbb, 0x0e, 0xe9, 0xcd, 0x15, 0x2f, 0x78, + 0x1b, 0xf9, 0x0a, 0xf0, 0x9e, 0x00, 0xa9, 0xf7, 0x49, 0x6e, 0x79, 0x22, 0x19, 0xf9, 0x08, 0x4e, + 0x04, 0x93, 0x69, 0xa4, 0x64, 0xd7, 0xc0, 0xfa, 0xbd, 0x76, 0x58, 0x3f, 0xe4, 0x68, 0xa1, 0xf1, + 0xfe, 0x30, 0xa0, 0x5d, 0x23, 0x74, 0xaa, 0x4c, 0x08, 0x2e, 0x8a, 0x5a, 0xa2, 0x51, 0x55, 0xd8, + 0xac, 0x57, 0xb8, 0x07, 0xad, 0x98, 0x29, 0x1f, 0x4b, 0x63, 0x21, 0x51, 0xda, 0xe4, 0x43, 0x68, + 0xca, 0xac, 0x8b, 0x36, 0x66, 0x41, 0xea, 0xc3, 0x32, 0x47, 0x86, 0xe6, 0x0a, 0xf2, 0x1e, 0x34, + 0x95, 0xbf, 0x8c, 0x98, 0xec, 0x36, 0x0e, 0x3b, 0xbe, 0xd0, 0x28, 0xcd, 0x49, 0xef, 0x07, 0x68, + 0x20, 0xa0, 0x8f, 0xb8, 0xe2, 0x51, 0x1a, 0x27, 0xf7, 0x8e, 0x88, 0xfc, 0x13, 0xe4, 0x68, 0xa1, + 0x21, 0x8f, 0xc0, 0x16, 0x7c, 0xa7, 0xfb, 0xaf, 0xb5, 0xee, 0x61, 0x70, 0xbe, 0xa3, 0xc8, 0x7a, + 0xef, 0x42, 0xbb, 0xe6, 0x4d, 0x08, 0xd8, 0x89, 0x1f, 0xb3, 0xbc, 0x0c, 0xb8, 0xf6, 0xce, 0xa1, + 0x55, 0x38, 0x91, 0x01, 0x34, 0xef, 0xfc, 0x28, 0x65, 0x45, 0x0a, 0x65, 0x58, 0xca, 0x77, 0xdf, + 0x69, 0x82, 0xe6, 0xbc, 0xf7, 0x97, 0x09, 0xad, 0x02, 0x24, 0x1f, 0x80, 0xfd, 0x3c, 0x4c, 0xb2, + 0x49, 0xed, 0x8c, 0xde, 0x78, 0xd9, 0x69, 0xf8, 0x75, 0x98, 0x04, 0x14, 0x25, 0x7a, 0x3c, 0x02, + 0x9e, 0x2e, 0x23, 0x86, 0x0c, 0x56, 0xde, 0xa0, 0x75, 0x28, 0x9f, 0xdd, 0x8b, 0xf3, 0x4c, 0x50, + 0xcd, 0x6e, 0x8e, 0xe8, 0xf1, 0x59, 0x72, 0x1e, 0x65, 0xb4, 0x1e, 0x9f, 0x16, 0xad, 0x00, 0x1d, + 0x5f, 0x2a, 0x11, 0x26, 0x9b, 0x8c, 0x6f, 0xe0, 0x41, 0xeb, 0x90, 0x8e, 0xbf, 0xdc, 0x2b, 0x26, + 0x33, 0x41, 0xb3, 0x6f, 0x0c, 0x1e, 0xd0, 0x1a, 0xe2, 0xad, 0xc1, 0xd6, 0xf9, 0x92, 0x53, 0x70, + 0x16, 0xcf, 0x6e, 0x27, 0x3f, 0x5e, 0x3f, 0x9d, 0xcd, 0xdc, 0x57, 0xc8, 0xab, 0xd0, 0x46, 0xf3, + 0xf2, 0xe6, 0xe9, 0x78, 0x36, 0x71, 0x0d, 0xd2, 0x01, 0x40, 0x60, 0x7a, 0xbd, 0xb8, 0x38, 0x77, + 0xcd, 0x52, 0x3f, 0xbe, 0xb9, 0x99, 0xb9, 0x56, 0xa9, 0x9f, 0x2f, 0xe8, 0xf4, 0xfa, 0x2b, 0xd7, + 0x2e, 0xf5, 0xe3, 0x67, 0x8b, 0xc9, 0xdc, 0x6d, 0x78, 0x7f, 0x9b, 0xd0, 0x39, 0x7c, 0x31, 0x48, + 0x07, 0xcc, 0x30, 0xab, 0xa2, 0x45, 0xcd, 0x30, 0xd0, 0x03, 0xca, 0xc5, 0x26, 0x1f, 0x50, 0x8b, + 0x66, 0x46, 0xd9, 0x44, 0xab, 0x6a, 0xa2, 0xc6, 0xd4, 0x7e, 0xcb, 0xf2, 0xbb, 0x8c, 0x6b, 0xe2, + 0x82, 0x95, 0x8a, 0x28, 0x2f, 0x81, 0x5e, 0xea, 0xd1, 0xfe, 0x59, 0xf2, 0x44, 0xef, 0x8a, 0x07, + 0x77, 0x68, 0x69, 0x93, 0x18, 0xde, 0x0a, 0xd8, 0x4a, 0xec, 0xb7, 0x8a, 0x05, 0x73, 0xb6, 0x4a, + 0x05, 0xbb, 0x2a, 0xa4, 0x27, 0x38, 0x0b, 0x8f, 0x8f, 0x3f, 0x73, 0xc3, 0xcb, 0xe3, 0x5e, 0x93, + 0x44, 0x89, 0x3d, 0xfd, 0xb7, 0x98, 0xbd, 0x2b, 0x38, 0xfb, 0x2f, 0x47, 0x9d, 0xfc, 0x73, 0xb6, + 0xcf, 0x07, 0x55, 0x2f, 0x75, 0x31, 0xee, 0xca, 0x99, 0x71, 0x68, 0x66, 0x7c, 0x6e, 0x7e, 0x66, + 0x78, 0x7f, 0x1a, 0x00, 0xd5, 0x05, 0x3c, 0x36, 0xe4, 0xe4, 0x13, 0xb0, 0x95, 0xbf, 0x29, 0x6e, + 0xcb, 0xd9, 0xfd, 0x6b, 0x3b, 0x5c, 0xf8, 0x1b, 0x99, 0xe5, 0x8c, 0x4a, 0x7d, 0x7d, 0xb7, 0xd9, + 0x0b, 0xfb, 0xd2, 0x83, 0x8d, 0x4f, 0x2c, 0xcd, 0xc9, 0xde, 0xa7, 0xe0, 0x94, 0x9e, 0xff, 0x2b, + 0xe9, 0x2f, 0xa0, 0x81, 0x91, 0xf0, 0x39, 0x0c, 0x63, 0x26, 0x95, 0x1f, 0x6f, 0xf3, 0xde, 0x57, + 0xc0, 0x61, 0x00, 0x23, 0x0f, 0x30, 0xa2, 0xe0, 0x56, 0x5d, 0xb8, 0x8d, 0xd2, 0x4d, 0x98, 0x90, + 0x2f, 0x8b, 0x8f, 0xe3, 0xed, 0xfb, 0x8d, 0xca, 0xff, 0xbb, 0x5e, 0xef, 0x18, 0x95, 0x3d, 0xb1, + 0xe3, 0x07, 0xdf, 0xd7, 0x3e, 0xac, 0x65, 0x13, 0xbf, 0xcf, 0xc7, 0xff, 0x04, 0x00, 0x00, 0xff, + 0xff, 0xab, 0xf8, 0xda, 0x77, 0x52, 0x07, 0x00, 0x00, +} diff --git a/vendor/github.com/grafana/grafana_plugin_model/go/datasource/service.go b/vendor/github.com/grafana/grafana_plugin_model/go/datasource/service.go new file mode 100644 index 00000000000..ae62fc863b1 --- /dev/null +++ b/vendor/github.com/grafana/grafana_plugin_model/go/datasource/service.go @@ -0,0 +1,42 @@ +package datasource + +import ( + "context" + + plugin "github.com/hashicorp/go-plugin" + "google.golang.org/grpc" +) + +type DatasourcePlugin interface { + Query(ctx context.Context, req *DatasourceRequest) (*DatasourceResponse, error) +} + +type DatasourcePluginImpl struct { + plugin.NetRPCUnsupportedPlugin + Plugin DatasourcePlugin +} + +func (p *DatasourcePluginImpl) GRPCServer(s *grpc.Server) error { + RegisterDatasourcePluginServer(s, &GRPCServer{p.Plugin}) + return nil +} + +func (p *DatasourcePluginImpl) GRPCClient(c *grpc.ClientConn) (interface{}, error) { + return &GRPCClient{NewDatasourcePluginClient(c)}, nil +} + +type GRPCClient struct { + DatasourcePluginClient +} + +func (m *GRPCClient) Query(ctx context.Context, req *DatasourceRequest) (*DatasourceResponse, error) { + return m.DatasourcePluginClient.Query(ctx, req) +} + +type GRPCServer struct { + DatasourcePlugin +} + +func (m *GRPCServer) Query(ctx context.Context, req *DatasourceRequest) (*DatasourceResponse, error) { + return m.DatasourcePlugin.Query(ctx, req) +} diff --git a/vendor/github.com/kr/s3/License b/vendor/github.com/hashicorp/go-hclog/LICENSE similarity index 61% rename from vendor/github.com/kr/s3/License rename to vendor/github.com/hashicorp/go-hclog/LICENSE index 4abc7488905..abaf1e45f2a 100644 --- a/vendor/github.com/kr/s3/License +++ b/vendor/github.com/hashicorp/go-hclog/LICENSE @@ -1,11 +1,13 @@ -Copyright (c) 2012 Keith Rarick. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: +Copyright (c) 2017 HashiCorp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. diff --git a/vendor/github.com/hashicorp/go-hclog/global.go b/vendor/github.com/hashicorp/go-hclog/global.go new file mode 100644 index 00000000000..55ce4396034 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/global.go @@ -0,0 +1,34 @@ +package hclog + +import ( + "sync" +) + +var ( + protect sync.Once + def Logger + + // The options used to create the Default logger. These are + // read only when the Default logger is created, so set them + // as soon as the process starts. + DefaultOptions = &LoggerOptions{ + Level: DefaultLevel, + Output: DefaultOutput, + } +) + +// Return a logger that is held globally. This can be a good starting +// place, and then you can use .With() and .Name() to create sub-loggers +// to be used in more specific contexts. +func Default() Logger { + protect.Do(func() { + def = New(DefaultOptions) + }) + + return def +} + +// A short alias for Default() +func L() Logger { + return Default() +} diff --git a/vendor/github.com/hashicorp/go-hclog/int.go b/vendor/github.com/hashicorp/go-hclog/int.go new file mode 100644 index 00000000000..8b13493f831 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/int.go @@ -0,0 +1,410 @@ +package hclog + +import ( + "bufio" + "encoding" + "encoding/json" + "fmt" + "log" + "os" + "runtime" + "strconv" + "strings" + "sync" + "time" +) + +var ( + _levelToBracket = map[Level]string{ + Debug: "[DEBUG]", + Trace: "[TRACE]", + Info: "[INFO ]", + Warn: "[WARN ]", + Error: "[ERROR]", + } +) + +// Given the options (nil for defaults), create a new Logger +func New(opts *LoggerOptions) Logger { + if opts == nil { + opts = &LoggerOptions{} + } + + output := opts.Output + if output == nil { + output = os.Stderr + } + + level := opts.Level + if level == NoLevel { + level = DefaultLevel + } + + mtx := opts.Mutex + if mtx == nil { + mtx = new(sync.Mutex) + } + + ret := &intLogger{ + m: mtx, + json: opts.JSONFormat, + caller: opts.IncludeLocation, + name: opts.Name, + timeFormat: TimeFormat, + w: bufio.NewWriter(output), + level: level, + } + if opts.TimeFormat != "" { + ret.timeFormat = opts.TimeFormat + } + return ret +} + +// The internal logger implementation. Internal in that it is defined entirely +// by this package. +type intLogger struct { + json bool + caller bool + name string + timeFormat string + + // this is a pointer so that it's shared by any derived loggers, since + // those derived loggers share the bufio.Writer as well. + m *sync.Mutex + w *bufio.Writer + level Level + + implied []interface{} +} + +// Make sure that intLogger is a Logger +var _ Logger = &intLogger{} + +// The time format to use for logging. This is a version of RFC3339 that +// contains millisecond precision +const TimeFormat = "2006-01-02T15:04:05.000Z0700" + +// Log a message and a set of key/value pairs if the given level is at +// or more severe that the threshold configured in the Logger. +func (z *intLogger) Log(level Level, msg string, args ...interface{}) { + if level < z.level { + return + } + + t := time.Now() + + z.m.Lock() + defer z.m.Unlock() + + if z.json { + z.logJson(t, level, msg, args...) + } else { + z.log(t, level, msg, args...) + } + + z.w.Flush() +} + +// Cleanup a path by returning the last 2 segments of the path only. +func trimCallerPath(path string) string { + // lovely borrowed from zap + // nb. To make sure we trim the path correctly on Windows too, we + // counter-intuitively need to use '/' and *not* os.PathSeparator here, + // because the path given originates from Go stdlib, specifically + // runtime.Caller() which (as of Mar/17) returns forward slashes even on + // Windows. + // + // See https://github.com/golang/go/issues/3335 + // and https://github.com/golang/go/issues/18151 + // + // for discussion on the issue on Go side. + // + + // Find the last separator. + // + idx := strings.LastIndexByte(path, '/') + if idx == -1 { + return path + } + + // Find the penultimate separator. + idx = strings.LastIndexByte(path[:idx], '/') + if idx == -1 { + return path + } + + return path[idx+1:] +} + +// Non-JSON logging format function +func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) { + z.w.WriteString(t.Format(z.timeFormat)) + z.w.WriteByte(' ') + + s, ok := _levelToBracket[level] + if ok { + z.w.WriteString(s) + } else { + z.w.WriteString("[UNKN ]") + } + + if z.caller { + if _, file, line, ok := runtime.Caller(3); ok { + z.w.WriteByte(' ') + z.w.WriteString(trimCallerPath(file)) + z.w.WriteByte(':') + z.w.WriteString(strconv.Itoa(line)) + z.w.WriteByte(':') + } + } + + z.w.WriteByte(' ') + + if z.name != "" { + z.w.WriteString(z.name) + z.w.WriteString(": ") + } + + z.w.WriteString(msg) + + args = append(z.implied, args...) + + var stacktrace CapturedStacktrace + + if args != nil && len(args) > 0 { + if len(args)%2 != 0 { + cs, ok := args[len(args)-1].(CapturedStacktrace) + if ok { + args = args[:len(args)-1] + stacktrace = cs + } else { + args = append(args, "") + } + } + + z.w.WriteByte(':') + + FOR: + for i := 0; i < len(args); i = i + 2 { + var val string + + switch st := args[i+1].(type) { + case string: + val = st + case int: + val = strconv.FormatInt(int64(st), 10) + case int64: + val = strconv.FormatInt(int64(st), 10) + case int32: + val = strconv.FormatInt(int64(st), 10) + case int16: + val = strconv.FormatInt(int64(st), 10) + case int8: + val = strconv.FormatInt(int64(st), 10) + case uint: + val = strconv.FormatUint(uint64(st), 10) + case uint64: + val = strconv.FormatUint(uint64(st), 10) + case uint32: + val = strconv.FormatUint(uint64(st), 10) + case uint16: + val = strconv.FormatUint(uint64(st), 10) + case uint8: + val = strconv.FormatUint(uint64(st), 10) + case CapturedStacktrace: + stacktrace = st + continue FOR + default: + val = fmt.Sprintf("%v", st) + } + + z.w.WriteByte(' ') + z.w.WriteString(args[i].(string)) + z.w.WriteByte('=') + + if strings.ContainsAny(val, " \t\n\r") { + z.w.WriteByte('"') + z.w.WriteString(val) + z.w.WriteByte('"') + } else { + z.w.WriteString(val) + } + } + } + + z.w.WriteString("\n") + + if stacktrace != "" { + z.w.WriteString(string(stacktrace)) + } +} + +// JSON logging function +func (z *intLogger) logJson(t time.Time, level Level, msg string, args ...interface{}) { + vals := map[string]interface{}{ + "@message": msg, + "@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"), + } + + var levelStr string + switch level { + case Error: + levelStr = "error" + case Warn: + levelStr = "warn" + case Info: + levelStr = "info" + case Debug: + levelStr = "debug" + case Trace: + levelStr = "trace" + default: + levelStr = "all" + } + + vals["@level"] = levelStr + + if z.name != "" { + vals["@module"] = z.name + } + + if z.caller { + if _, file, line, ok := runtime.Caller(3); ok { + vals["@caller"] = fmt.Sprintf("%s:%d", file, line) + } + } + + if args != nil && len(args) > 0 { + if len(args)%2 != 0 { + cs, ok := args[len(args)-1].(CapturedStacktrace) + if ok { + args = args[:len(args)-1] + vals["stacktrace"] = cs + } else { + args = append(args, "") + } + } + + for i := 0; i < len(args); i = i + 2 { + if _, ok := args[i].(string); !ok { + // As this is the logging function not much we can do here + // without injecting into logs... + continue + } + val := args[i+1] + // Check if val is of type error. If error type doesn't + // implement json.Marshaler or encoding.TextMarshaler + // then set val to err.Error() so that it gets marshaled + if err, ok := val.(error); ok { + switch err.(type) { + case json.Marshaler, encoding.TextMarshaler: + default: + val = err.Error() + } + } + vals[args[i].(string)] = val + } + } + + err := json.NewEncoder(z.w).Encode(vals) + if err != nil { + panic(err) + } +} + +// Emit the message and args at DEBUG level +func (z *intLogger) Debug(msg string, args ...interface{}) { + z.Log(Debug, msg, args...) +} + +// Emit the message and args at TRACE level +func (z *intLogger) Trace(msg string, args ...interface{}) { + z.Log(Trace, msg, args...) +} + +// Emit the message and args at INFO level +func (z *intLogger) Info(msg string, args ...interface{}) { + z.Log(Info, msg, args...) +} + +// Emit the message and args at WARN level +func (z *intLogger) Warn(msg string, args ...interface{}) { + z.Log(Warn, msg, args...) +} + +// Emit the message and args at ERROR level +func (z *intLogger) Error(msg string, args ...interface{}) { + z.Log(Error, msg, args...) +} + +// Indicate that the logger would emit TRACE level logs +func (z *intLogger) IsTrace() bool { + return z.level == Trace +} + +// Indicate that the logger would emit DEBUG level logs +func (z *intLogger) IsDebug() bool { + return z.level <= Debug +} + +// Indicate that the logger would emit INFO level logs +func (z *intLogger) IsInfo() bool { + return z.level <= Info +} + +// Indicate that the logger would emit WARN level logs +func (z *intLogger) IsWarn() bool { + return z.level <= Warn +} + +// Indicate that the logger would emit ERROR level logs +func (z *intLogger) IsError() bool { + return z.level <= Error +} + +// Return a sub-Logger for which every emitted log message will contain +// the given key/value pairs. This is used to create a context specific +// Logger. +func (z *intLogger) With(args ...interface{}) Logger { + var nz intLogger = *z + + nz.implied = append(nz.implied, args...) + + return &nz +} + +// Create a new sub-Logger that a name decending from the current name. +// This is used to create a subsystem specific Logger. +func (z *intLogger) Named(name string) Logger { + var nz intLogger = *z + + if nz.name != "" { + nz.name = nz.name + "." + name + } else { + nz.name = name + } + + return &nz +} + +// Create a new sub-Logger with an explicit name. This ignores the current +// name. This is used to create a standalone logger that doesn't fall +// within the normal hierarchy. +func (z *intLogger) ResetNamed(name string) Logger { + var nz intLogger = *z + + nz.name = name + + return &nz +} + +// Create a *log.Logger that will send it's data through this Logger. This +// allows packages that expect to be using the standard library log to actually +// use this logger. +func (z *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger { + if opts == nil { + opts = &StandardLoggerOptions{} + } + + return log.New(&stdlogAdapter{z, opts.InferLevels}, "", 0) +} diff --git a/vendor/github.com/hashicorp/go-hclog/log.go b/vendor/github.com/hashicorp/go-hclog/log.go new file mode 100644 index 00000000000..6be9839e8e0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/log.go @@ -0,0 +1,145 @@ +package hclog + +import ( + "io" + "log" + "os" + "strings" + "sync" +) + +var ( + DefaultOutput = os.Stderr + DefaultLevel = Info +) + +type Level int + +const ( + // This is a special level used to indicate that no level has been + // set and allow for a default to be used. + NoLevel Level = 0 + + // The most verbose level. Intended to be used for the tracing of actions + // in code, such as function enters/exits, etc. + Trace Level = 1 + + // For programmer lowlevel analysis. + Debug Level = 2 + + // For information about steady state operations. + Info Level = 3 + + // For information about rare but handled events. + Warn Level = 4 + + // For information about unrecoverable events. + Error Level = 5 +) + +// LevelFromString returns a Level type for the named log level, or "NoLevel" if +// the level string is invalid. This facilitates setting the log level via +// config or environment variable by name in a predictable way. +func LevelFromString(levelStr string) Level { + // We don't care about case. Accept "INFO" or "info" + levelStr = strings.ToLower(strings.TrimSpace(levelStr)) + switch levelStr { + case "trace": + return Trace + case "debug": + return Debug + case "info": + return Info + case "warn": + return Warn + case "error": + return Error + default: + return NoLevel + } +} + +// The main Logger interface. All code should code against this interface only. +type Logger interface { + // Args are alternating key, val pairs + // keys must be strings + // vals can be any type, but display is implementation specific + // Emit a message and key/value pairs at the TRACE level + Trace(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the DEBUG level + Debug(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the INFO level + Info(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the WARN level + Warn(msg string, args ...interface{}) + + // Emit a message and key/value pairs at the ERROR level + Error(msg string, args ...interface{}) + + // Indicate if TRACE logs would be emitted. This and the other Is* guards + // are used to elide expensive logging code based on the current level. + IsTrace() bool + + // Indicate if DEBUG logs would be emitted. This and the other Is* guards + IsDebug() bool + + // Indicate if INFO logs would be emitted. This and the other Is* guards + IsInfo() bool + + // Indicate if WARN logs would be emitted. This and the other Is* guards + IsWarn() bool + + // Indicate if ERROR logs would be emitted. This and the other Is* guards + IsError() bool + + // Creates a sublogger that will always have the given key/value pairs + With(args ...interface{}) Logger + + // Create a logger that will prepend the name string on the front of all messages. + // If the logger already has a name, the new value will be appended to the current + // name. That way, a major subsystem can use this to decorate all it's own logs + // without losing context. + Named(name string) Logger + + // Create a logger that will prepend the name string on the front of all messages. + // This sets the name of the logger to the value directly, unlike Named which honor + // the current name as well. + ResetNamed(name string) Logger + + // Return a value that conforms to the stdlib log.Logger interface + StandardLogger(opts *StandardLoggerOptions) *log.Logger +} + +type StandardLoggerOptions struct { + // Indicate that some minimal parsing should be done on strings to try + // and detect their level and re-emit them. + // This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO], + // [DEBUG] and strip it off before reapplying it. + InferLevels bool +} + +type LoggerOptions struct { + // Name of the subsystem to prefix logs with + Name string + + // The threshold for the logger. Anything less severe is supressed + Level Level + + // Where to write the logs to. Defaults to os.Stdout if nil + Output io.Writer + + // An optional mutex pointer in case Output is shared + Mutex *sync.Mutex + + // Control if the output should be in JSON. + JSONFormat bool + + // Include file and line information in each log line + IncludeLocation bool + + // The time format to use instead of the default + TimeFormat string +} diff --git a/vendor/github.com/hashicorp/go-hclog/stacktrace.go b/vendor/github.com/hashicorp/go-hclog/stacktrace.go new file mode 100644 index 00000000000..8af1a3be4c0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/stacktrace.go @@ -0,0 +1,108 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package hclog + +import ( + "bytes" + "runtime" + "strconv" + "strings" + "sync" +) + +var ( + _stacktraceIgnorePrefixes = []string{ + "runtime.goexit", + "runtime.main", + } + _stacktracePool = sync.Pool{ + New: func() interface{} { + return newProgramCounters(64) + }, + } +) + +// A stacktrace gathered by a previous call to log.Stacktrace. If passed +// to a logging function, the stacktrace will be appended. +type CapturedStacktrace string + +// Gather a stacktrace of the current goroutine and return it to be passed +// to a logging function. +func Stacktrace() CapturedStacktrace { + return CapturedStacktrace(takeStacktrace()) +} + +func takeStacktrace() string { + programCounters := _stacktracePool.Get().(*programCounters) + defer _stacktracePool.Put(programCounters) + + var buffer bytes.Buffer + + for { + // Skip the call to runtime.Counters and takeStacktrace so that the + // program counters start at the caller of takeStacktrace. + n := runtime.Callers(2, programCounters.pcs) + if n < cap(programCounters.pcs) { + programCounters.pcs = programCounters.pcs[:n] + break + } + // Don't put the too-short counter slice back into the pool; this lets + // the pool adjust if we consistently take deep stacktraces. + programCounters = newProgramCounters(len(programCounters.pcs) * 2) + } + + i := 0 + frames := runtime.CallersFrames(programCounters.pcs) + for frame, more := frames.Next(); more; frame, more = frames.Next() { + if shouldIgnoreStacktraceFunction(frame.Function) { + continue + } + if i != 0 { + buffer.WriteByte('\n') + } + i++ + buffer.WriteString(frame.Function) + buffer.WriteByte('\n') + buffer.WriteByte('\t') + buffer.WriteString(frame.File) + buffer.WriteByte(':') + buffer.WriteString(strconv.Itoa(int(frame.Line))) + } + + return buffer.String() +} + +func shouldIgnoreStacktraceFunction(function string) bool { + for _, prefix := range _stacktraceIgnorePrefixes { + if strings.HasPrefix(function, prefix) { + return true + } + } + return false +} + +type programCounters struct { + pcs []uintptr +} + +func newProgramCounters(size int) *programCounters { + return &programCounters{make([]uintptr, size)} +} diff --git a/vendor/github.com/hashicorp/go-hclog/stdlog.go b/vendor/github.com/hashicorp/go-hclog/stdlog.go new file mode 100644 index 00000000000..2bb927fc90c --- /dev/null +++ b/vendor/github.com/hashicorp/go-hclog/stdlog.go @@ -0,0 +1,62 @@ +package hclog + +import ( + "bytes" + "strings" +) + +// Provides a io.Writer to shim the data out of *log.Logger +// and back into our Logger. This is basically the only way to +// build upon *log.Logger. +type stdlogAdapter struct { + hl Logger + inferLevels bool +} + +// Take the data, infer the levels if configured, and send it through +// a regular Logger +func (s *stdlogAdapter) Write(data []byte) (int, error) { + str := string(bytes.TrimRight(data, " \t\n")) + + if s.inferLevels { + level, str := s.pickLevel(str) + switch level { + case Trace: + s.hl.Trace(str) + case Debug: + s.hl.Debug(str) + case Info: + s.hl.Info(str) + case Warn: + s.hl.Warn(str) + case Error: + s.hl.Error(str) + default: + s.hl.Info(str) + } + } else { + s.hl.Info(str) + } + + return len(data), nil +} + +// Detect, based on conventions, what log level this is +func (s *stdlogAdapter) pickLevel(str string) (Level, string) { + switch { + case strings.HasPrefix(str, "[DEBUG]"): + return Debug, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[TRACE]"): + return Trace, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[INFO]"): + return Info, strings.TrimSpace(str[6:]) + case strings.HasPrefix(str, "[WARN]"): + return Warn, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[ERROR]"): + return Error, strings.TrimSpace(str[7:]) + case strings.HasPrefix(str, "[ERR]"): + return Error, strings.TrimSpace(str[5:]) + default: + return Info, str + } +} diff --git a/vendor/github.com/hashicorp/go-plugin/LICENSE b/vendor/github.com/hashicorp/go-plugin/LICENSE new file mode 100644 index 00000000000..82b4de97c7e --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/LICENSE @@ -0,0 +1,353 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-plugin/client.go b/vendor/github.com/hashicorp/go-plugin/client.go new file mode 100644 index 00000000000..b912826b200 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/client.go @@ -0,0 +1,772 @@ +package plugin + +import ( + "bufio" + "crypto/subtle" + "crypto/tls" + "errors" + "fmt" + "hash" + "io" + "io/ioutil" + "log" + "net" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unicode" + + hclog "github.com/hashicorp/go-hclog" +) + +// If this is 1, then we've called CleanupClients. This can be used +// by plugin RPC implementations to change error behavior since you +// can expected network connection errors at this point. This should be +// read by using sync/atomic. +var Killed uint32 = 0 + +// This is a slice of the "managed" clients which are cleaned up when +// calling Cleanup +var managedClients = make([]*Client, 0, 5) +var managedClientsLock sync.Mutex + +// Error types +var ( + // ErrProcessNotFound is returned when a client is instantiated to + // reattach to an existing process and it isn't found. + ErrProcessNotFound = errors.New("Reattachment process not found") + + // ErrChecksumsDoNotMatch is returned when binary's checksum doesn't match + // the one provided in the SecureConfig. + ErrChecksumsDoNotMatch = errors.New("checksums did not match") + + // ErrSecureNoChecksum is returned when an empty checksum is provided to the + // SecureConfig. + ErrSecureConfigNoChecksum = errors.New("no checksum provided") + + // ErrSecureNoHash is returned when a nil Hash object is provided to the + // SecureConfig. + ErrSecureConfigNoHash = errors.New("no hash implementation provided") + + // ErrSecureConfigAndReattach is returned when both Reattach and + // SecureConfig are set. + ErrSecureConfigAndReattach = errors.New("only one of Reattach or SecureConfig can be set") +) + +// Client handles the lifecycle of a plugin application. It launches +// plugins, connects to them, dispenses interface implementations, and handles +// killing the process. +// +// Plugin hosts should use one Client for each plugin executable. To +// dispense a plugin type, use the `Client.Client` function, and then +// cal `Dispense`. This awkward API is mostly historical but is used to split +// the client that deals with subprocess management and the client that +// does RPC management. +// +// See NewClient and ClientConfig for using a Client. +type Client struct { + config *ClientConfig + exited bool + doneLogging chan struct{} + l sync.Mutex + address net.Addr + process *os.Process + client ClientProtocol + protocol Protocol + logger hclog.Logger +} + +// ClientConfig is the configuration used to initialize a new +// plugin client. After being used to initialize a plugin client, +// that configuration must not be modified again. +type ClientConfig struct { + // HandshakeConfig is the configuration that must match servers. + HandshakeConfig + + // Plugins are the plugins that can be consumed. + Plugins map[string]Plugin + + // One of the following must be set, but not both. + // + // Cmd is the unstarted subprocess for starting the plugin. If this is + // set, then the Client starts the plugin process on its own and connects + // to it. + // + // Reattach is configuration for reattaching to an existing plugin process + // that is already running. This isn't common. + Cmd *exec.Cmd + Reattach *ReattachConfig + + // SecureConfig is configuration for verifying the integrity of the + // executable. It can not be used with Reattach. + SecureConfig *SecureConfig + + // TLSConfig is used to enable TLS on the RPC client. + TLSConfig *tls.Config + + // Managed represents if the client should be managed by the + // plugin package or not. If true, then by calling CleanupClients, + // it will automatically be cleaned up. Otherwise, the client + // user is fully responsible for making sure to Kill all plugin + // clients. By default the client is _not_ managed. + Managed bool + + // The minimum and maximum port to use for communicating with + // the subprocess. If not set, this defaults to 10,000 and 25,000 + // respectively. + MinPort, MaxPort uint + + // StartTimeout is the timeout to wait for the plugin to say it + // has started successfully. + StartTimeout time.Duration + + // If non-nil, then the stderr of the client will be written to here + // (as well as the log). This is the original os.Stderr of the subprocess. + // This isn't the output of synced stderr. + Stderr io.Writer + + // SyncStdout, SyncStderr can be set to override the + // respective os.Std* values in the plugin. Care should be taken to + // avoid races here. If these are nil, then this will automatically be + // hooked up to os.Stdin, Stdout, and Stderr, respectively. + // + // If the default values (nil) are used, then this package will not + // sync any of these streams. + SyncStdout io.Writer + SyncStderr io.Writer + + // AllowedProtocols is a list of allowed protocols. If this isn't set, + // then only netrpc is allowed. This is so that older go-plugin systems + // can show friendly errors if they see a plugin with an unknown + // protocol. + // + // By setting this, you can cause an error immediately on plugin start + // if an unsupported protocol is used with a good error message. + // + // If this isn't set at all (nil value), then only net/rpc is accepted. + // This is done for legacy reasons. You must explicitly opt-in to + // new protocols. + AllowedProtocols []Protocol + + // Logger is the logger that the client will used. If none is provided, + // it will default to hclog's default logger. + Logger hclog.Logger +} + +// ReattachConfig is used to configure a client to reattach to an +// already-running plugin process. You can retrieve this information by +// calling ReattachConfig on Client. +type ReattachConfig struct { + Protocol Protocol + Addr net.Addr + Pid int +} + +// SecureConfig is used to configure a client to verify the integrity of an +// executable before running. It does this by verifying the checksum is +// expected. Hash is used to specify the hashing method to use when checksumming +// the file. The configuration is verified by the client by calling the +// SecureConfig.Check() function. +// +// The host process should ensure the checksum was provided by a trusted and +// authoritative source. The binary should be installed in such a way that it +// can not be modified by an unauthorized user between the time of this check +// and the time of execution. +type SecureConfig struct { + Checksum []byte + Hash hash.Hash +} + +// Check takes the filepath to an executable and returns true if the checksum of +// the file matches the checksum provided in the SecureConfig. +func (s *SecureConfig) Check(filePath string) (bool, error) { + if len(s.Checksum) == 0 { + return false, ErrSecureConfigNoChecksum + } + + if s.Hash == nil { + return false, ErrSecureConfigNoHash + } + + file, err := os.Open(filePath) + if err != nil { + return false, err + } + defer file.Close() + + _, err = io.Copy(s.Hash, file) + if err != nil { + return false, err + } + + sum := s.Hash.Sum(nil) + + return subtle.ConstantTimeCompare(sum, s.Checksum) == 1, nil +} + +// This makes sure all the managed subprocesses are killed and properly +// logged. This should be called before the parent process running the +// plugins exits. +// +// This must only be called _once_. +func CleanupClients() { + // Set the killed to true so that we don't get unexpected panics + atomic.StoreUint32(&Killed, 1) + + // Kill all the managed clients in parallel and use a WaitGroup + // to wait for them all to finish up. + var wg sync.WaitGroup + managedClientsLock.Lock() + for _, client := range managedClients { + wg.Add(1) + + go func(client *Client) { + client.Kill() + wg.Done() + }(client) + } + managedClientsLock.Unlock() + + log.Println("[DEBUG] plugin: waiting for all plugin processes to complete...") + wg.Wait() +} + +// Creates a new plugin client which manages the lifecycle of an external +// plugin and gets the address for the RPC connection. +// +// The client must be cleaned up at some point by calling Kill(). If +// the client is a managed client (created with NewManagedClient) you +// can just call CleanupClients at the end of your program and they will +// be properly cleaned. +func NewClient(config *ClientConfig) (c *Client) { + if config.MinPort == 0 && config.MaxPort == 0 { + config.MinPort = 10000 + config.MaxPort = 25000 + } + + if config.StartTimeout == 0 { + config.StartTimeout = 1 * time.Minute + } + + if config.Stderr == nil { + config.Stderr = ioutil.Discard + } + + if config.SyncStdout == nil { + config.SyncStdout = ioutil.Discard + } + if config.SyncStderr == nil { + config.SyncStderr = ioutil.Discard + } + + if config.AllowedProtocols == nil { + config.AllowedProtocols = []Protocol{ProtocolNetRPC} + } + + if config.Logger == nil { + config.Logger = hclog.New(&hclog.LoggerOptions{ + Output: hclog.DefaultOutput, + Level: hclog.Trace, + Name: "plugin", + }) + } + + c = &Client{ + config: config, + logger: config.Logger, + } + if config.Managed { + managedClientsLock.Lock() + managedClients = append(managedClients, c) + managedClientsLock.Unlock() + } + + return +} + +// Client returns the protocol client for this connection. +// +// Subsequent calls to this will return the same client. +func (c *Client) Client() (ClientProtocol, error) { + _, err := c.Start() + if err != nil { + return nil, err + } + + c.l.Lock() + defer c.l.Unlock() + + if c.client != nil { + return c.client, nil + } + + switch c.protocol { + case ProtocolNetRPC: + c.client, err = newRPCClient(c) + + case ProtocolGRPC: + c.client, err = newGRPCClient(c) + + default: + return nil, fmt.Errorf("unknown server protocol: %s", c.protocol) + } + + if err != nil { + c.client = nil + return nil, err + } + + return c.client, nil +} + +// Tells whether or not the underlying process has exited. +func (c *Client) Exited() bool { + c.l.Lock() + defer c.l.Unlock() + return c.exited +} + +// End the executing subprocess (if it is running) and perform any cleanup +// tasks necessary such as capturing any remaining logs and so on. +// +// This method blocks until the process successfully exits. +// +// This method can safely be called multiple times. +func (c *Client) Kill() { + // Grab a lock to read some private fields. + c.l.Lock() + process := c.process + addr := c.address + doneCh := c.doneLogging + c.l.Unlock() + + // If there is no process, we never started anything. Nothing to kill. + if process == nil { + return + } + + // We need to check for address here. It is possible that the plugin + // started (process != nil) but has no address (addr == nil) if the + // plugin failed at startup. If we do have an address, we need to close + // the plugin net connections. + graceful := false + if addr != nil { + // Close the client to cleanly exit the process. + client, err := c.Client() + if err == nil { + err = client.Close() + + // If there is no error, then we attempt to wait for a graceful + // exit. If there was an error, we assume that graceful cleanup + // won't happen and just force kill. + graceful = err == nil + if err != nil { + // If there was an error just log it. We're going to force + // kill in a moment anyways. + c.logger.Warn("error closing client during Kill", "err", err) + } + } + } + + // If we're attempting a graceful exit, then we wait for a short period + // of time to allow that to happen. To wait for this we just wait on the + // doneCh which would be closed if the process exits. + if graceful { + select { + case <-doneCh: + return + case <-time.After(250 * time.Millisecond): + } + } + + // If graceful exiting failed, just kill it + process.Kill() + + // Wait for the client to finish logging so we have a complete log + <-doneCh +} + +// Starts the underlying subprocess, communicating with it to negotiate +// a port for RPC connections, and returning the address to connect via RPC. +// +// This method is safe to call multiple times. Subsequent calls have no effect. +// Once a client has been started once, it cannot be started again, even if +// it was killed. +func (c *Client) Start() (addr net.Addr, err error) { + c.l.Lock() + defer c.l.Unlock() + + if c.address != nil { + return c.address, nil + } + + // If one of cmd or reattach isn't set, then it is an error. We wrap + // this in a {} for scoping reasons, and hopeful that the escape + // analysis will pop the stock here. + { + cmdSet := c.config.Cmd != nil + attachSet := c.config.Reattach != nil + secureSet := c.config.SecureConfig != nil + if cmdSet == attachSet { + return nil, fmt.Errorf("Only one of Cmd or Reattach must be set") + } + + if secureSet && attachSet { + return nil, ErrSecureConfigAndReattach + } + } + + // Create the logging channel for when we kill + c.doneLogging = make(chan struct{}) + + if c.config.Reattach != nil { + // Verify the process still exists. If not, then it is an error + p, err := os.FindProcess(c.config.Reattach.Pid) + if err != nil { + return nil, err + } + + // Attempt to connect to the addr since on Unix systems FindProcess + // doesn't actually return an error if it can't find the process. + conn, err := net.Dial( + c.config.Reattach.Addr.Network(), + c.config.Reattach.Addr.String()) + if err != nil { + p.Kill() + return nil, ErrProcessNotFound + } + conn.Close() + + // Goroutine to mark exit status + go func(pid int) { + // Wait for the process to die + pidWait(pid) + + // Log so we can see it + c.logger.Debug("reattached plugin process exited") + + // Mark it + c.l.Lock() + defer c.l.Unlock() + c.exited = true + + // Close the logging channel since that doesn't work on reattach + close(c.doneLogging) + }(p.Pid) + + // Set the address and process + c.address = c.config.Reattach.Addr + c.process = p + c.protocol = c.config.Reattach.Protocol + if c.protocol == "" { + // Default the protocol to net/rpc for backwards compatibility + c.protocol = ProtocolNetRPC + } + + return c.address, nil + } + + env := []string{ + fmt.Sprintf("%s=%s", c.config.MagicCookieKey, c.config.MagicCookieValue), + fmt.Sprintf("PLUGIN_MIN_PORT=%d", c.config.MinPort), + fmt.Sprintf("PLUGIN_MAX_PORT=%d", c.config.MaxPort), + } + + stdout_r, stdout_w := io.Pipe() + stderr_r, stderr_w := io.Pipe() + + cmd := c.config.Cmd + cmd.Env = append(cmd.Env, os.Environ()...) + cmd.Env = append(cmd.Env, env...) + cmd.Stdin = os.Stdin + cmd.Stderr = stderr_w + cmd.Stdout = stdout_w + + if c.config.SecureConfig != nil { + if ok, err := c.config.SecureConfig.Check(cmd.Path); err != nil { + return nil, fmt.Errorf("error verifying checksum: %s", err) + } else if !ok { + return nil, ErrChecksumsDoNotMatch + } + } + + c.logger.Debug("starting plugin", "path", cmd.Path, "args", cmd.Args) + err = cmd.Start() + if err != nil { + return + } + + // Set the process + c.process = cmd.Process + + // Make sure the command is properly cleaned up if there is an error + defer func() { + r := recover() + + if err != nil || r != nil { + cmd.Process.Kill() + } + + if r != nil { + panic(r) + } + }() + + // Start goroutine to wait for process to exit + exitCh := make(chan struct{}) + go func() { + // Make sure we close the write end of our stderr/stdout so + // that the readers send EOF properly. + defer stderr_w.Close() + defer stdout_w.Close() + + // Wait for the command to end. + cmd.Wait() + + // Log and make sure to flush the logs write away + c.logger.Debug("plugin process exited", "path", cmd.Path) + os.Stderr.Sync() + + // Mark that we exited + close(exitCh) + + // Set that we exited, which takes a lock + c.l.Lock() + defer c.l.Unlock() + c.exited = true + }() + + // Start goroutine that logs the stderr + go c.logStderr(stderr_r) + + // Start a goroutine that is going to be reading the lines + // out of stdout + linesCh := make(chan []byte) + go func() { + defer close(linesCh) + + buf := bufio.NewReader(stdout_r) + for { + line, err := buf.ReadBytes('\n') + if line != nil { + linesCh <- line + } + + if err == io.EOF { + return + } + } + }() + + // Make sure after we exit we read the lines from stdout forever + // so they don't block since it is an io.Pipe + defer func() { + go func() { + for _ = range linesCh { + } + }() + }() + + // Some channels for the next step + timeout := time.After(c.config.StartTimeout) + + // Start looking for the address + c.logger.Debug("waiting for RPC address", "path", cmd.Path) + select { + case <-timeout: + err = errors.New("timeout while waiting for plugin to start") + case <-exitCh: + err = errors.New("plugin exited before we could connect") + case lineBytes := <-linesCh: + // Trim the line and split by "|" in order to get the parts of + // the output. + line := strings.TrimSpace(string(lineBytes)) + parts := strings.SplitN(line, "|", 6) + if len(parts) < 4 { + err = fmt.Errorf( + "Unrecognized remote plugin message: %s\n\n"+ + "This usually means that the plugin is either invalid or simply\n"+ + "needs to be recompiled to support the latest protocol.", line) + return + } + + // Check the core protocol. Wrapped in a {} for scoping. + { + var coreProtocol int64 + coreProtocol, err = strconv.ParseInt(parts[0], 10, 0) + if err != nil { + err = fmt.Errorf("Error parsing core protocol version: %s", err) + return + } + + if int(coreProtocol) != CoreProtocolVersion { + err = fmt.Errorf("Incompatible core API version with plugin. "+ + "Plugin version: %s, Ours: %d\n\n"+ + "To fix this, the plugin usually only needs to be recompiled.\n"+ + "Please report this to the plugin author.", parts[0], CoreProtocolVersion) + return + } + } + + // Parse the protocol version + var protocol int64 + protocol, err = strconv.ParseInt(parts[1], 10, 0) + if err != nil { + err = fmt.Errorf("Error parsing protocol version: %s", err) + return + } + + // Test the API version + if uint(protocol) != c.config.ProtocolVersion { + err = fmt.Errorf("Incompatible API version with plugin. "+ + "Plugin version: %s, Ours: %d", parts[1], c.config.ProtocolVersion) + return + } + + switch parts[2] { + case "tcp": + addr, err = net.ResolveTCPAddr("tcp", parts[3]) + case "unix": + addr, err = net.ResolveUnixAddr("unix", parts[3]) + default: + err = fmt.Errorf("Unknown address type: %s", parts[3]) + } + + // If we have a server type, then record that. We default to net/rpc + // for backwards compatibility. + c.protocol = ProtocolNetRPC + if len(parts) >= 5 { + c.protocol = Protocol(parts[4]) + } + + found := false + for _, p := range c.config.AllowedProtocols { + if p == c.protocol { + found = true + break + } + } + if !found { + err = fmt.Errorf("Unsupported plugin protocol %q. Supported: %v", + c.protocol, c.config.AllowedProtocols) + return + } + + } + + c.address = addr + return +} + +// ReattachConfig returns the information that must be provided to NewClient +// to reattach to the plugin process that this client started. This is +// useful for plugins that detach from their parent process. +// +// If this returns nil then the process hasn't been started yet. Please +// call Start or Client before calling this. +func (c *Client) ReattachConfig() *ReattachConfig { + c.l.Lock() + defer c.l.Unlock() + + if c.address == nil { + return nil + } + + if c.config.Cmd != nil && c.config.Cmd.Process == nil { + return nil + } + + // If we connected via reattach, just return the information as-is + if c.config.Reattach != nil { + return c.config.Reattach + } + + return &ReattachConfig{ + Protocol: c.protocol, + Addr: c.address, + Pid: c.config.Cmd.Process.Pid, + } +} + +// Protocol returns the protocol of server on the remote end. This will +// start the plugin process if it isn't already started. Errors from +// starting the plugin are surpressed and ProtocolInvalid is returned. It +// is recommended you call Start explicitly before calling Protocol to ensure +// no errors occur. +func (c *Client) Protocol() Protocol { + _, err := c.Start() + if err != nil { + return ProtocolInvalid + } + + return c.protocol +} + +// dialer is compatible with grpc.WithDialer and creates the connection +// to the plugin. +func (c *Client) dialer(_ string, timeout time.Duration) (net.Conn, error) { + // Connect to the client + conn, err := net.Dial(c.address.Network(), c.address.String()) + if err != nil { + return nil, err + } + if tcpConn, ok := conn.(*net.TCPConn); ok { + // Make sure to set keep alive so that the connection doesn't die + tcpConn.SetKeepAlive(true) + } + + // If we have a TLS config we wrap our connection. We only do this + // for net/rpc since gRPC uses its own mechanism for TLS. + if c.protocol == ProtocolNetRPC && c.config.TLSConfig != nil { + conn = tls.Client(conn, c.config.TLSConfig) + } + + return conn, nil +} + +func (c *Client) logStderr(r io.Reader) { + bufR := bufio.NewReader(r) + for { + line, err := bufR.ReadString('\n') + if line != "" { + c.config.Stderr.Write([]byte(line)) + line = strings.TrimRightFunc(line, unicode.IsSpace) + + l := c.logger.Named(filepath.Base(c.config.Cmd.Path)) + + entry, err := parseJSON(line) + // If output is not JSON format, print directly to Debug + if err != nil { + l.Debug(line) + } else { + out := flattenKVPairs(entry.KVPairs) + + l = l.With("timestamp", entry.Timestamp.Format(hclog.TimeFormat)) + switch hclog.LevelFromString(entry.Level) { + case hclog.Trace: + l.Trace(entry.Message, out...) + case hclog.Debug: + l.Debug(entry.Message, out...) + case hclog.Info: + l.Info(entry.Message, out...) + case hclog.Warn: + l.Warn(entry.Message, out...) + case hclog.Error: + l.Error(entry.Message, out...) + } + } + } + + if err == io.EOF { + break + } + } + + // Flag that we've completed logging for others + close(c.doneLogging) +} diff --git a/vendor/github.com/hashicorp/go-plugin/discover.go b/vendor/github.com/hashicorp/go-plugin/discover.go new file mode 100644 index 00000000000..d22c566ed50 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/discover.go @@ -0,0 +1,28 @@ +package plugin + +import ( + "path/filepath" +) + +// Discover discovers plugins that are in a given directory. +// +// The directory doesn't need to be absolute. For example, "." will work fine. +// +// This currently assumes any file matching the glob is a plugin. +// In the future this may be smarter about checking that a file is +// executable and so on. +// +// TODO: test +func Discover(glob, dir string) ([]string, error) { + var err error + + // Make the directory absolute if it isn't already + if !filepath.IsAbs(dir) { + dir, err = filepath.Abs(dir) + if err != nil { + return nil, err + } + } + + return filepath.Glob(filepath.Join(dir, glob)) +} diff --git a/vendor/github.com/hashicorp/go-plugin/error.go b/vendor/github.com/hashicorp/go-plugin/error.go new file mode 100644 index 00000000000..22a7baa6a0d --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/error.go @@ -0,0 +1,24 @@ +package plugin + +// This is a type that wraps error types so that they can be messaged +// across RPC channels. Since "error" is an interface, we can't always +// gob-encode the underlying structure. This is a valid error interface +// implementer that we will push across. +type BasicError struct { + Message string +} + +// NewBasicError is used to create a BasicError. +// +// err is allowed to be nil. +func NewBasicError(err error) *BasicError { + if err == nil { + return nil + } + + return &BasicError{err.Error()} +} + +func (e *BasicError) Error() string { + return e.Message +} diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_client.go b/vendor/github.com/hashicorp/go-plugin/grpc_client.go new file mode 100644 index 00000000000..3bcf95efc56 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_client.go @@ -0,0 +1,83 @@ +package plugin + +import ( + "fmt" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/health/grpc_health_v1" +) + +// newGRPCClient creates a new GRPCClient. The Client argument is expected +// to be successfully started already with a lock held. +func newGRPCClient(c *Client) (*GRPCClient, error) { + // Build dialing options. + opts := make([]grpc.DialOption, 0, 5) + + // We use a custom dialer so that we can connect over unix domain sockets + opts = append(opts, grpc.WithDialer(c.dialer)) + + // go-plugin expects to block the connection + opts = append(opts, grpc.WithBlock()) + + // Fail right away + opts = append(opts, grpc.FailOnNonTempDialError(true)) + + // If we have no TLS configuration set, we need to explicitly tell grpc + // that we're connecting with an insecure connection. + if c.config.TLSConfig == nil { + opts = append(opts, grpc.WithInsecure()) + } else { + opts = append(opts, grpc.WithTransportCredentials( + credentials.NewTLS(c.config.TLSConfig))) + } + + // Connect. Note the first parameter is unused because we use a custom + // dialer that has the state to see the address. + conn, err := grpc.Dial("unused", opts...) + if err != nil { + return nil, err + } + + return &GRPCClient{ + Conn: conn, + Plugins: c.config.Plugins, + }, nil +} + +// GRPCClient connects to a GRPCServer over gRPC to dispense plugin types. +type GRPCClient struct { + Conn *grpc.ClientConn + Plugins map[string]Plugin +} + +// ClientProtocol impl. +func (c *GRPCClient) Close() error { + return c.Conn.Close() +} + +// ClientProtocol impl. +func (c *GRPCClient) Dispense(name string) (interface{}, error) { + raw, ok := c.Plugins[name] + if !ok { + return nil, fmt.Errorf("unknown plugin type: %s", name) + } + + p, ok := raw.(GRPCPlugin) + if !ok { + return nil, fmt.Errorf("plugin %q doesn't support gRPC", name) + } + + return p.GRPCClient(c.Conn) +} + +// ClientProtocol impl. +func (c *GRPCClient) Ping() error { + client := grpc_health_v1.NewHealthClient(c.Conn) + _, err := client.Check(context.Background(), &grpc_health_v1.HealthCheckRequest{ + Service: GRPCServiceName, + }) + + return err +} diff --git a/vendor/github.com/hashicorp/go-plugin/grpc_server.go b/vendor/github.com/hashicorp/go-plugin/grpc_server.go new file mode 100644 index 00000000000..177a0cdd7dc --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/grpc_server.go @@ -0,0 +1,115 @@ +package plugin + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" +) + +// GRPCServiceName is the name of the service that the health check should +// return as passing. +const GRPCServiceName = "plugin" + +// DefaultGRPCServer can be used with the "GRPCServer" field for Server +// as a default factory method to create a gRPC server with no extra options. +func DefaultGRPCServer(opts []grpc.ServerOption) *grpc.Server { + return grpc.NewServer(opts...) +} + +// GRPCServer is a ServerType implementation that serves plugins over +// gRPC. This allows plugins to easily be written for other languages. +// +// The GRPCServer outputs a custom configuration as a base64-encoded +// JSON structure represented by the GRPCServerConfig config structure. +type GRPCServer struct { + // Plugins are the list of plugins to serve. + Plugins map[string]Plugin + + // Server is the actual server that will accept connections. This + // will be used for plugin registration as well. + Server func([]grpc.ServerOption) *grpc.Server + + // TLS should be the TLS configuration if available. If this is nil, + // the connection will not have transport security. + TLS *tls.Config + + // DoneCh is the channel that is closed when this server has exited. + DoneCh chan struct{} + + // Stdout/StderrLis are the readers for stdout/stderr that will be copied + // to the stdout/stderr connection that is output. + Stdout io.Reader + Stderr io.Reader + + config GRPCServerConfig + server *grpc.Server +} + +// ServerProtocol impl. +func (s *GRPCServer) Init() error { + // Create our server + var opts []grpc.ServerOption + if s.TLS != nil { + opts = append(opts, grpc.Creds(credentials.NewTLS(s.TLS))) + } + s.server = s.Server(opts) + + // Register the health service + healthCheck := health.NewServer() + healthCheck.SetServingStatus( + GRPCServiceName, grpc_health_v1.HealthCheckResponse_SERVING) + grpc_health_v1.RegisterHealthServer(s.server, healthCheck) + + // Register all our plugins onto the gRPC server. + for k, raw := range s.Plugins { + p, ok := raw.(GRPCPlugin) + if !ok { + return fmt.Errorf("%q is not a GRPC-compatibile plugin", k) + } + + if err := p.GRPCServer(s.server); err != nil { + return fmt.Errorf("error registring %q: %s", k, err) + } + } + + return nil +} + +// Config is the GRPCServerConfig encoded as JSON then base64. +func (s *GRPCServer) Config() string { + // Create a buffer that will contain our final contents + var buf bytes.Buffer + + // Wrap the base64 encoding with JSON encoding. + if err := json.NewEncoder(&buf).Encode(s.config); err != nil { + // We panic since ths shouldn't happen under any scenario. We + // carefully control the structure being encoded here and it should + // always be successful. + panic(err) + } + + return buf.String() +} + +func (s *GRPCServer) Serve(lis net.Listener) { + // Start serving in a goroutine + go s.server.Serve(lis) + + // Wait until graceful completion + <-s.DoneCh +} + +// GRPCServerConfig is the extra configuration passed along for consumers +// to facilitate using GRPC plugins. +type GRPCServerConfig struct { + StdoutAddr string `json:"stdout_addr"` + StderrAddr string `json:"stderr_addr"` +} diff --git a/vendor/github.com/hashicorp/go-plugin/log_entry.go b/vendor/github.com/hashicorp/go-plugin/log_entry.go new file mode 100644 index 00000000000..2996c14c3cb --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/log_entry.go @@ -0,0 +1,73 @@ +package plugin + +import ( + "encoding/json" + "time" +) + +// logEntry is the JSON payload that gets sent to Stderr from the plugin to the host +type logEntry struct { + Message string `json:"@message"` + Level string `json:"@level"` + Timestamp time.Time `json:"timestamp"` + KVPairs []*logEntryKV `json:"kv_pairs"` +} + +// logEntryKV is a key value pair within the Output payload +type logEntryKV struct { + Key string `json:"key"` + Value interface{} `json:"value"` +} + +// flattenKVPairs is used to flatten KVPair slice into []interface{} +// for hclog consumption. +func flattenKVPairs(kvs []*logEntryKV) []interface{} { + var result []interface{} + for _, kv := range kvs { + result = append(result, kv.Key) + result = append(result, kv.Value) + } + + return result +} + +// parseJSON handles parsing JSON output +func parseJSON(input string) (*logEntry, error) { + var raw map[string]interface{} + entry := &logEntry{} + + err := json.Unmarshal([]byte(input), &raw) + if err != nil { + return nil, err + } + + // Parse hclog-specific objects + if v, ok := raw["@message"]; ok { + entry.Message = v.(string) + delete(raw, "@message") + } + + if v, ok := raw["@level"]; ok { + entry.Level = v.(string) + delete(raw, "@level") + } + + if v, ok := raw["@timestamp"]; ok { + t, err := time.Parse("2006-01-02T15:04:05.000000Z07:00", v.(string)) + if err != nil { + return nil, err + } + entry.Timestamp = t + delete(raw, "@timestamp") + } + + // Parse dynamic KV args from the hclog payload. + for k, v := range raw { + entry.KVPairs = append(entry.KVPairs, &logEntryKV{ + Key: k, + Value: v, + }) + } + + return entry, nil +} diff --git a/vendor/github.com/hashicorp/go-plugin/mux_broker.go b/vendor/github.com/hashicorp/go-plugin/mux_broker.go new file mode 100644 index 00000000000..01c45ad7c68 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/mux_broker.go @@ -0,0 +1,204 @@ +package plugin + +import ( + "encoding/binary" + "fmt" + "log" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/hashicorp/yamux" +) + +// MuxBroker is responsible for brokering multiplexed connections by unique ID. +// +// It is used by plugins to multiplex multiple RPC connections and data +// streams on top of a single connection between the plugin process and the +// host process. +// +// This allows a plugin to request a channel with a specific ID to connect to +// or accept a connection from, and the broker handles the details of +// holding these channels open while they're being negotiated. +// +// The Plugin interface has access to these for both Server and Client. +// The broker can be used by either (optionally) to reserve and connect to +// new multiplexed streams. This is useful for complex args and return values, +// or anything else you might need a data stream for. +type MuxBroker struct { + nextId uint32 + session *yamux.Session + streams map[uint32]*muxBrokerPending + + sync.Mutex +} + +type muxBrokerPending struct { + ch chan net.Conn + doneCh chan struct{} +} + +func newMuxBroker(s *yamux.Session) *MuxBroker { + return &MuxBroker{ + session: s, + streams: make(map[uint32]*muxBrokerPending), + } +} + +// Accept accepts a connection by ID. +// +// This should not be called multiple times with the same ID at one time. +func (m *MuxBroker) Accept(id uint32) (net.Conn, error) { + var c net.Conn + p := m.getStream(id) + select { + case c = <-p.ch: + close(p.doneCh) + case <-time.After(5 * time.Second): + m.Lock() + defer m.Unlock() + delete(m.streams, id) + + return nil, fmt.Errorf("timeout waiting for accept") + } + + // Ack our connection + if err := binary.Write(c, binary.LittleEndian, id); err != nil { + c.Close() + return nil, err + } + + return c, nil +} + +// AcceptAndServe is used to accept a specific stream ID and immediately +// serve an RPC server on that stream ID. This is used to easily serve +// complex arguments. +// +// The served interface is always registered to the "Plugin" name. +func (m *MuxBroker) AcceptAndServe(id uint32, v interface{}) { + conn, err := m.Accept(id) + if err != nil { + log.Printf("[ERR] plugin: plugin acceptAndServe error: %s", err) + return + } + + serve(conn, "Plugin", v) +} + +// Close closes the connection and all sub-connections. +func (m *MuxBroker) Close() error { + return m.session.Close() +} + +// Dial opens a connection by ID. +func (m *MuxBroker) Dial(id uint32) (net.Conn, error) { + // Open the stream + stream, err := m.session.OpenStream() + if err != nil { + return nil, err + } + + // Write the stream ID onto the wire. + if err := binary.Write(stream, binary.LittleEndian, id); err != nil { + stream.Close() + return nil, err + } + + // Read the ack that we connected. Then we're off! + var ack uint32 + if err := binary.Read(stream, binary.LittleEndian, &ack); err != nil { + stream.Close() + return nil, err + } + if ack != id { + stream.Close() + return nil, fmt.Errorf("bad ack: %d (expected %d)", ack, id) + } + + return stream, nil +} + +// NextId returns a unique ID to use next. +// +// It is possible for very long-running plugin hosts to wrap this value, +// though it would require a very large amount of RPC calls. In practice +// we've never seen it happen. +func (m *MuxBroker) NextId() uint32 { + return atomic.AddUint32(&m.nextId, 1) +} + +// Run starts the brokering and should be executed in a goroutine, since it +// blocks forever, or until the session closes. +// +// Uses of MuxBroker never need to call this. It is called internally by +// the plugin host/client. +func (m *MuxBroker) Run() { + for { + stream, err := m.session.AcceptStream() + if err != nil { + // Once we receive an error, just exit + break + } + + // Read the stream ID from the stream + var id uint32 + if err := binary.Read(stream, binary.LittleEndian, &id); err != nil { + stream.Close() + continue + } + + // Initialize the waiter + p := m.getStream(id) + select { + case p.ch <- stream: + default: + } + + // Wait for a timeout + go m.timeoutWait(id, p) + } +} + +func (m *MuxBroker) getStream(id uint32) *muxBrokerPending { + m.Lock() + defer m.Unlock() + + p, ok := m.streams[id] + if ok { + return p + } + + m.streams[id] = &muxBrokerPending{ + ch: make(chan net.Conn, 1), + doneCh: make(chan struct{}), + } + return m.streams[id] +} + +func (m *MuxBroker) timeoutWait(id uint32, p *muxBrokerPending) { + // Wait for the stream to either be picked up and connected, or + // for a timeout. + timeout := false + select { + case <-p.doneCh: + case <-time.After(5 * time.Second): + timeout = true + } + + m.Lock() + defer m.Unlock() + + // Delete the stream so no one else can grab it + delete(m.streams, id) + + // If we timed out, then check if we have a channel in the buffer, + // and if so, close it. + if timeout { + select { + case s := <-p.ch: + s.Close() + } + } +} diff --git a/vendor/github.com/hashicorp/go-plugin/plugin.go b/vendor/github.com/hashicorp/go-plugin/plugin.go new file mode 100644 index 00000000000..6b7bdd1cfd0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/plugin.go @@ -0,0 +1,56 @@ +// The plugin package exposes functions and helpers for communicating to +// plugins which are implemented as standalone binary applications. +// +// plugin.Client fully manages the lifecycle of executing the application, +// connecting to it, and returning the RPC client for dispensing plugins. +// +// plugin.Serve fully manages listeners to expose an RPC server from a binary +// that plugin.Client can connect to. +package plugin + +import ( + "errors" + "net/rpc" + + "google.golang.org/grpc" +) + +// Plugin is the interface that is implemented to serve/connect to an +// inteface implementation. +type Plugin interface { + // Server should return the RPC server compatible struct to serve + // the methods that the Client calls over net/rpc. + Server(*MuxBroker) (interface{}, error) + + // Client returns an interface implementation for the plugin you're + // serving that communicates to the server end of the plugin. + Client(*MuxBroker, *rpc.Client) (interface{}, error) +} + +// GRPCPlugin is the interface that is implemented to serve/connect to +// a plugin over gRPC. +type GRPCPlugin interface { + // GRPCServer should register this plugin for serving with the + // given GRPCServer. Unlike Plugin.Server, this is only called once + // since gRPC plugins serve singletons. + GRPCServer(*grpc.Server) error + + // GRPCClient should return the interface implementation for the plugin + // you're serving via gRPC. + GRPCClient(*grpc.ClientConn) (interface{}, error) +} + +// NetRPCUnsupportedPlugin implements Plugin but returns errors for the +// Server and Client functions. This will effectively disable support for +// net/rpc based plugins. +// +// This struct can be embedded in your struct. +type NetRPCUnsupportedPlugin struct{} + +func (p NetRPCUnsupportedPlugin) Server(*MuxBroker) (interface{}, error) { + return nil, errors.New("net/rpc plugin protocol not supported") +} + +func (p NetRPCUnsupportedPlugin) Client(*MuxBroker, *rpc.Client) (interface{}, error) { + return nil, errors.New("net/rpc plugin protocol not supported") +} diff --git a/vendor/github.com/hashicorp/go-plugin/process.go b/vendor/github.com/hashicorp/go-plugin/process.go new file mode 100644 index 00000000000..88c999a580d --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/process.go @@ -0,0 +1,24 @@ +package plugin + +import ( + "time" +) + +// pidAlive checks whether a pid is alive. +func pidAlive(pid int) bool { + return _pidAlive(pid) +} + +// pidWait blocks for a process to exit. +func pidWait(pid int) error { + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for range ticker.C { + if !pidAlive(pid) { + break + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/go-plugin/process_posix.go b/vendor/github.com/hashicorp/go-plugin/process_posix.go new file mode 100644 index 00000000000..70ba546bf6d --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/process_posix.go @@ -0,0 +1,19 @@ +// +build !windows + +package plugin + +import ( + "os" + "syscall" +) + +// _pidAlive tests whether a process is alive or not by sending it Signal 0, +// since Go otherwise has no way to test this. +func _pidAlive(pid int) bool { + proc, err := os.FindProcess(pid) + if err == nil { + err = proc.Signal(syscall.Signal(0)) + } + + return err == nil +} diff --git a/vendor/github.com/hashicorp/go-plugin/process_windows.go b/vendor/github.com/hashicorp/go-plugin/process_windows.go new file mode 100644 index 00000000000..9f7b0180901 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/process_windows.go @@ -0,0 +1,29 @@ +package plugin + +import ( + "syscall" +) + +const ( + // Weird name but matches the MSDN docs + exit_STILL_ACTIVE = 259 + + processDesiredAccess = syscall.STANDARD_RIGHTS_READ | + syscall.PROCESS_QUERY_INFORMATION | + syscall.SYNCHRONIZE +) + +// _pidAlive tests whether a process is alive or not +func _pidAlive(pid int) bool { + h, err := syscall.OpenProcess(processDesiredAccess, false, uint32(pid)) + if err != nil { + return false + } + + var ec uint32 + if e := syscall.GetExitCodeProcess(h, &ec); e != nil { + return false + } + + return ec == exit_STILL_ACTIVE +} diff --git a/vendor/github.com/hashicorp/go-plugin/protocol.go b/vendor/github.com/hashicorp/go-plugin/protocol.go new file mode 100644 index 00000000000..0cfc19e52d6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/protocol.go @@ -0,0 +1,45 @@ +package plugin + +import ( + "io" + "net" +) + +// Protocol is an enum representing the types of protocols. +type Protocol string + +const ( + ProtocolInvalid Protocol = "" + ProtocolNetRPC Protocol = "netrpc" + ProtocolGRPC Protocol = "grpc" +) + +// ServerProtocol is an interface that must be implemented for new plugin +// protocols to be servers. +type ServerProtocol interface { + // Init is called once to configure and initialize the protocol, but + // not start listening. This is the point at which all validation should + // be done and errors returned. + Init() error + + // Config is extra configuration to be outputted to stdout. This will + // be automatically base64 encoded to ensure it can be parsed properly. + // This can be an empty string if additional configuration is not needed. + Config() string + + // Serve is called to serve connections on the given listener. This should + // continue until the listener is closed. + Serve(net.Listener) +} + +// ClientProtocol is an interface that must be implemented for new plugin +// protocols to be clients. +type ClientProtocol interface { + io.Closer + + // Dispense dispenses a new instance of the plugin with the given name. + Dispense(string) (interface{}, error) + + // Ping checks that the client connection is still healthy. + Ping() error +} diff --git a/vendor/github.com/hashicorp/go-plugin/rpc_client.go b/vendor/github.com/hashicorp/go-plugin/rpc_client.go new file mode 100644 index 00000000000..f30a4b1d387 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/rpc_client.go @@ -0,0 +1,170 @@ +package plugin + +import ( + "crypto/tls" + "fmt" + "io" + "net" + "net/rpc" + + "github.com/hashicorp/yamux" +) + +// RPCClient connects to an RPCServer over net/rpc to dispense plugin types. +type RPCClient struct { + broker *MuxBroker + control *rpc.Client + plugins map[string]Plugin + + // These are the streams used for the various stdout/err overrides + stdout, stderr net.Conn +} + +// newRPCClient creates a new RPCClient. The Client argument is expected +// to be successfully started already with a lock held. +func newRPCClient(c *Client) (*RPCClient, error) { + // Connect to the client + conn, err := net.Dial(c.address.Network(), c.address.String()) + if err != nil { + return nil, err + } + if tcpConn, ok := conn.(*net.TCPConn); ok { + // Make sure to set keep alive so that the connection doesn't die + tcpConn.SetKeepAlive(true) + } + + if c.config.TLSConfig != nil { + conn = tls.Client(conn, c.config.TLSConfig) + } + + // Create the actual RPC client + result, err := NewRPCClient(conn, c.config.Plugins) + if err != nil { + conn.Close() + return nil, err + } + + // Begin the stream syncing so that stdin, out, err work properly + err = result.SyncStreams( + c.config.SyncStdout, + c.config.SyncStderr) + if err != nil { + result.Close() + return nil, err + } + + return result, nil +} + +// NewRPCClient creates a client from an already-open connection-like value. +// Dial is typically used instead. +func NewRPCClient(conn io.ReadWriteCloser, plugins map[string]Plugin) (*RPCClient, error) { + // Create the yamux client so we can multiplex + mux, err := yamux.Client(conn, nil) + if err != nil { + conn.Close() + return nil, err + } + + // Connect to the control stream. + control, err := mux.Open() + if err != nil { + mux.Close() + return nil, err + } + + // Connect stdout, stderr streams + stdstream := make([]net.Conn, 2) + for i, _ := range stdstream { + stdstream[i], err = mux.Open() + if err != nil { + mux.Close() + return nil, err + } + } + + // Create the broker and start it up + broker := newMuxBroker(mux) + go broker.Run() + + // Build the client using our broker and control channel. + return &RPCClient{ + broker: broker, + control: rpc.NewClient(control), + plugins: plugins, + stdout: stdstream[0], + stderr: stdstream[1], + }, nil +} + +// SyncStreams should be called to enable syncing of stdout, +// stderr with the plugin. +// +// This will return immediately and the syncing will continue to happen +// in the background. You do not need to launch this in a goroutine itself. +// +// This should never be called multiple times. +func (c *RPCClient) SyncStreams(stdout io.Writer, stderr io.Writer) error { + go copyStream("stdout", stdout, c.stdout) + go copyStream("stderr", stderr, c.stderr) + return nil +} + +// Close closes the connection. The client is no longer usable after this +// is called. +func (c *RPCClient) Close() error { + // Call the control channel and ask it to gracefully exit. If this + // errors, then we save it so that we always return an error but we + // want to try to close the other channels anyways. + var empty struct{} + returnErr := c.control.Call("Control.Quit", true, &empty) + + // Close the other streams we have + if err := c.control.Close(); err != nil { + return err + } + if err := c.stdout.Close(); err != nil { + return err + } + if err := c.stderr.Close(); err != nil { + return err + } + if err := c.broker.Close(); err != nil { + return err + } + + // Return back the error we got from Control.Quit. This is very important + // since we MUST return non-nil error if this fails so that Client.Kill + // will properly try a process.Kill. + return returnErr +} + +func (c *RPCClient) Dispense(name string) (interface{}, error) { + p, ok := c.plugins[name] + if !ok { + return nil, fmt.Errorf("unknown plugin type: %s", name) + } + + var id uint32 + if err := c.control.Call( + "Dispenser.Dispense", name, &id); err != nil { + return nil, err + } + + conn, err := c.broker.Dial(id) + if err != nil { + return nil, err + } + + return p.Client(c.broker, rpc.NewClient(conn)) +} + +// Ping pings the connection to ensure it is still alive. +// +// The error from the RPC call is returned exactly if you want to inspect +// it for further error analysis. Any error returned from here would indicate +// that the connection to the plugin is not healthy. +func (c *RPCClient) Ping() error { + var empty struct{} + return c.control.Call("Control.Ping", true, &empty) +} diff --git a/vendor/github.com/hashicorp/go-plugin/rpc_server.go b/vendor/github.com/hashicorp/go-plugin/rpc_server.go new file mode 100644 index 00000000000..5bb18dd5db1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/rpc_server.go @@ -0,0 +1,197 @@ +package plugin + +import ( + "errors" + "fmt" + "io" + "log" + "net" + "net/rpc" + "sync" + + "github.com/hashicorp/yamux" +) + +// RPCServer listens for network connections and then dispenses interface +// implementations over net/rpc. +// +// After setting the fields below, they shouldn't be read again directly +// from the structure which may be reading/writing them concurrently. +type RPCServer struct { + Plugins map[string]Plugin + + // Stdout, Stderr are what this server will use instead of the + // normal stdin/out/err. This is because due to the multi-process nature + // of our plugin system, we can't use the normal process values so we + // make our own custom one we pipe across. + Stdout io.Reader + Stderr io.Reader + + // DoneCh should be set to a non-nil channel that will be closed + // when the control requests the RPC server to end. + DoneCh chan<- struct{} + + lock sync.Mutex +} + +// ServerProtocol impl. +func (s *RPCServer) Init() error { return nil } + +// ServerProtocol impl. +func (s *RPCServer) Config() string { return "" } + +// ServerProtocol impl. +func (s *RPCServer) Serve(lis net.Listener) { + for { + conn, err := lis.Accept() + if err != nil { + log.Printf("[ERR] plugin: plugin server: %s", err) + return + } + + go s.ServeConn(conn) + } +} + +// ServeConn runs a single connection. +// +// ServeConn blocks, serving the connection until the client hangs up. +func (s *RPCServer) ServeConn(conn io.ReadWriteCloser) { + // First create the yamux server to wrap this connection + mux, err := yamux.Server(conn, nil) + if err != nil { + conn.Close() + log.Printf("[ERR] plugin: error creating yamux server: %s", err) + return + } + + // Accept the control connection + control, err := mux.Accept() + if err != nil { + mux.Close() + if err != io.EOF { + log.Printf("[ERR] plugin: error accepting control connection: %s", err) + } + + return + } + + // Connect the stdstreams (in, out, err) + stdstream := make([]net.Conn, 2) + for i, _ := range stdstream { + stdstream[i], err = mux.Accept() + if err != nil { + mux.Close() + log.Printf("[ERR] plugin: accepting stream %d: %s", i, err) + return + } + } + + // Copy std streams out to the proper place + go copyStream("stdout", stdstream[0], s.Stdout) + go copyStream("stderr", stdstream[1], s.Stderr) + + // Create the broker and start it up + broker := newMuxBroker(mux) + go broker.Run() + + // Use the control connection to build the dispenser and serve the + // connection. + server := rpc.NewServer() + server.RegisterName("Control", &controlServer{ + server: s, + }) + server.RegisterName("Dispenser", &dispenseServer{ + broker: broker, + plugins: s.Plugins, + }) + server.ServeConn(control) +} + +// done is called internally by the control server to trigger the +// doneCh to close which is listened to by the main process to cleanly +// exit. +func (s *RPCServer) done() { + s.lock.Lock() + defer s.lock.Unlock() + + if s.DoneCh != nil { + close(s.DoneCh) + s.DoneCh = nil + } +} + +// dispenseServer dispenses variousinterface implementations for Terraform. +type controlServer struct { + server *RPCServer +} + +// Ping can be called to verify the connection (and likely the binary) +// is still alive to a plugin. +func (c *controlServer) Ping( + null bool, response *struct{}) error { + *response = struct{}{} + return nil +} + +func (c *controlServer) Quit( + null bool, response *struct{}) error { + // End the server + c.server.done() + + // Always return true + *response = struct{}{} + + return nil +} + +// dispenseServer dispenses variousinterface implementations for Terraform. +type dispenseServer struct { + broker *MuxBroker + plugins map[string]Plugin +} + +func (d *dispenseServer) Dispense( + name string, response *uint32) error { + // Find the function to create this implementation + p, ok := d.plugins[name] + if !ok { + return fmt.Errorf("unknown plugin type: %s", name) + } + + // Create the implementation first so we know if there is an error. + impl, err := p.Server(d.broker) + if err != nil { + // We turn the error into an errors error so that it works across RPC + return errors.New(err.Error()) + } + + // Reserve an ID for our implementation + id := d.broker.NextId() + *response = id + + // Run the rest in a goroutine since it can only happen once this RPC + // call returns. We wait for a connection for the plugin implementation + // and serve it. + go func() { + conn, err := d.broker.Accept(id) + if err != nil { + log.Printf("[ERR] go-plugin: plugin dispense error: %s: %s", name, err) + return + } + + serve(conn, "Plugin", impl) + }() + + return nil +} + +func serve(conn io.ReadWriteCloser, name string, v interface{}) { + server := rpc.NewServer() + if err := server.RegisterName(name, v); err != nil { + log.Printf("[ERR] go-plugin: plugin dispense error: %s", err) + return + } + + server.ServeConn(conn) +} diff --git a/vendor/github.com/hashicorp/go-plugin/server.go b/vendor/github.com/hashicorp/go-plugin/server.go new file mode 100644 index 00000000000..e1543214a52 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/server.go @@ -0,0 +1,310 @@ +package plugin + +import ( + "crypto/tls" + "encoding/base64" + "errors" + "fmt" + "io/ioutil" + "log" + "net" + "os" + "os/signal" + "runtime" + "strconv" + "sync/atomic" + + "github.com/hashicorp/go-hclog" + + "google.golang.org/grpc" +) + +// CoreProtocolVersion is the ProtocolVersion of the plugin system itself. +// We will increment this whenever we change any protocol behavior. This +// will invalidate any prior plugins but will at least allow us to iterate +// on the core in a safe way. We will do our best to do this very +// infrequently. +const CoreProtocolVersion = 1 + +// HandshakeConfig is the configuration used by client and servers to +// handshake before starting a plugin connection. This is embedded by +// both ServeConfig and ClientConfig. +// +// In practice, the plugin host creates a HandshakeConfig that is exported +// and plugins then can easily consume it. +type HandshakeConfig struct { + // ProtocolVersion is the version that clients must match on to + // agree they can communicate. This should match the ProtocolVersion + // set on ClientConfig when using a plugin. + ProtocolVersion uint + + // MagicCookieKey and value are used as a very basic verification + // that a plugin is intended to be launched. This is not a security + // measure, just a UX feature. If the magic cookie doesn't match, + // we show human-friendly output. + MagicCookieKey string + MagicCookieValue string +} + +// ServeConfig configures what sorts of plugins are served. +type ServeConfig struct { + // HandshakeConfig is the configuration that must match clients. + HandshakeConfig + + // TLSProvider is a function that returns a configured tls.Config. + TLSProvider func() (*tls.Config, error) + + // Plugins are the plugins that are served. + Plugins map[string]Plugin + + // GRPCServer should be non-nil to enable serving the plugins over + // gRPC. This is a function to create the server when needed with the + // given server options. The server options populated by go-plugin will + // be for TLS if set. You may modify the input slice. + // + // Note that the grpc.Server will automatically be registered with + // the gRPC health checking service. This is not optional since go-plugin + // relies on this to implement Ping(). + GRPCServer func([]grpc.ServerOption) *grpc.Server +} + +// Protocol returns the protocol that this server should speak. +func (c *ServeConfig) Protocol() Protocol { + result := ProtocolNetRPC + if c.GRPCServer != nil { + result = ProtocolGRPC + } + + return result +} + +// Serve serves the plugins given by ServeConfig. +// +// Serve doesn't return until the plugin is done being executed. Any +// errors will be outputted to os.Stderr. +// +// This is the method that plugins should call in their main() functions. +func Serve(opts *ServeConfig) { + // Validate the handshake config + if opts.MagicCookieKey == "" || opts.MagicCookieValue == "" { + fmt.Fprintf(os.Stderr, + "Misconfigured ServeConfig given to serve this plugin: no magic cookie\n"+ + "key or value was set. Please notify the plugin author and report\n"+ + "this as a bug.\n") + os.Exit(1) + } + + // First check the cookie + if os.Getenv(opts.MagicCookieKey) != opts.MagicCookieValue { + fmt.Fprintf(os.Stderr, + "This binary is a plugin. These are not meant to be executed directly.\n"+ + "Please execute the program that consumes these plugins, which will\n"+ + "load any plugins automatically\n") + os.Exit(1) + } + + // Logging goes to the original stderr + log.SetOutput(os.Stderr) + + // internal logger to os.Stderr + logger := hclog.New(&hclog.LoggerOptions{ + Level: hclog.Trace, + Output: os.Stderr, + JSONFormat: true, + }) + + // Create our new stdout, stderr files. These will override our built-in + // stdout/stderr so that it works across the stream boundary. + stdout_r, stdout_w, err := os.Pipe() + if err != nil { + fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err) + os.Exit(1) + } + stderr_r, stderr_w, err := os.Pipe() + if err != nil { + fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err) + os.Exit(1) + } + + // Register a listener so we can accept a connection + listener, err := serverListener() + if err != nil { + logger.Error("plugin init error", "error", err) + return + } + + // Close the listener on return. We wrap this in a func() on purpose + // because the "listener" reference may change to TLS. + defer func() { + listener.Close() + }() + + var tlsConfig *tls.Config + if opts.TLSProvider != nil { + tlsConfig, err = opts.TLSProvider() + if err != nil { + logger.Error("plugin tls init", "error", err) + return + } + } + + // Create the channel to tell us when we're done + doneCh := make(chan struct{}) + + // Build the server type + var server ServerProtocol + switch opts.Protocol() { + case ProtocolNetRPC: + // If we have a TLS configuration then we wrap the listener + // ourselves and do it at that level. + if tlsConfig != nil { + listener = tls.NewListener(listener, tlsConfig) + } + + // Create the RPC server to dispense + server = &RPCServer{ + Plugins: opts.Plugins, + Stdout: stdout_r, + Stderr: stderr_r, + DoneCh: doneCh, + } + + case ProtocolGRPC: + // Create the gRPC server + server = &GRPCServer{ + Plugins: opts.Plugins, + Server: opts.GRPCServer, + TLS: tlsConfig, + Stdout: stdout_r, + Stderr: stderr_r, + DoneCh: doneCh, + } + + default: + panic("unknown server protocol: " + opts.Protocol()) + } + + // Initialize the servers + if err := server.Init(); err != nil { + logger.Error("protocol init", "error", err) + return + } + + // Build the extra configuration + extra := "" + if v := server.Config(); v != "" { + extra = base64.StdEncoding.EncodeToString([]byte(v)) + } + if extra != "" { + extra = "|" + extra + } + + logger.Debug("plugin address", "network", listener.Addr().Network(), "address", listener.Addr().String()) + + // Output the address and service name to stdout so that core can bring it up. + fmt.Printf("%d|%d|%s|%s|%s%s\n", + CoreProtocolVersion, + opts.ProtocolVersion, + listener.Addr().Network(), + listener.Addr().String(), + opts.Protocol(), + extra) + os.Stdout.Sync() + + // Eat the interrupts + ch := make(chan os.Signal, 1) + signal.Notify(ch, os.Interrupt) + go func() { + var count int32 = 0 + for { + <-ch + newCount := atomic.AddInt32(&count, 1) + logger.Debug("plugin received interrupt signal, ignoring", "count", newCount) + } + }() + + // Set our new out, err + os.Stdout = stdout_w + os.Stderr = stderr_w + + // Accept connections and wait for completion + go server.Serve(listener) + <-doneCh +} + +func serverListener() (net.Listener, error) { + if runtime.GOOS == "windows" { + return serverListener_tcp() + } + + return serverListener_unix() +} + +func serverListener_tcp() (net.Listener, error) { + minPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MIN_PORT"), 10, 32) + if err != nil { + return nil, err + } + + maxPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MAX_PORT"), 10, 32) + if err != nil { + return nil, err + } + + for port := minPort; port <= maxPort; port++ { + address := fmt.Sprintf("127.0.0.1:%d", port) + listener, err := net.Listen("tcp", address) + if err == nil { + return listener, nil + } + } + + return nil, errors.New("Couldn't bind plugin TCP listener") +} + +func serverListener_unix() (net.Listener, error) { + tf, err := ioutil.TempFile("", "plugin") + if err != nil { + return nil, err + } + path := tf.Name() + + // Close the file and remove it because it has to not exist for + // the domain socket. + if err := tf.Close(); err != nil { + return nil, err + } + if err := os.Remove(path); err != nil { + return nil, err + } + + l, err := net.Listen("unix", path) + if err != nil { + return nil, err + } + + // Wrap the listener in rmListener so that the Unix domain socket file + // is removed on close. + return &rmListener{ + Listener: l, + Path: path, + }, nil +} + +// rmListener is an implementation of net.Listener that forwards most +// calls to the listener but also removes a file as part of the close. We +// use this to cleanup the unix domain socket on close. +type rmListener struct { + net.Listener + Path string +} + +func (l *rmListener) Close() error { + // Close the listener itself + if err := l.Listener.Close(); err != nil { + return err + } + + // Remove the file + return os.Remove(l.Path) +} diff --git a/vendor/github.com/hashicorp/go-plugin/server_mux.go b/vendor/github.com/hashicorp/go-plugin/server_mux.go new file mode 100644 index 00000000000..033079ea0fc --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/server_mux.go @@ -0,0 +1,31 @@ +package plugin + +import ( + "fmt" + "os" +) + +// ServeMuxMap is the type that is used to configure ServeMux +type ServeMuxMap map[string]*ServeConfig + +// ServeMux is like Serve, but serves multiple types of plugins determined +// by the argument given on the command-line. +// +// This command doesn't return until the plugin is done being executed. Any +// errors are logged or output to stderr. +func ServeMux(m ServeMuxMap) { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, + "Invoked improperly. This is an internal command that shouldn't\n"+ + "be manually invoked.\n") + os.Exit(1) + } + + opts, ok := m[os.Args[1]] + if !ok { + fmt.Fprintf(os.Stderr, "Unknown plugin: %s\n", os.Args[1]) + os.Exit(1) + } + + Serve(opts) +} diff --git a/vendor/github.com/hashicorp/go-plugin/stream.go b/vendor/github.com/hashicorp/go-plugin/stream.go new file mode 100644 index 00000000000..1d547aaaab3 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/stream.go @@ -0,0 +1,18 @@ +package plugin + +import ( + "io" + "log" +) + +func copyStream(name string, dst io.Writer, src io.Reader) { + if src == nil { + panic(name + ": src is nil") + } + if dst == nil { + panic(name + ": dst is nil") + } + if _, err := io.Copy(dst, src); err != nil && err != io.EOF { + log.Printf("[ERR] plugin: stream copy '%s' error: %s", name, err) + } +} diff --git a/vendor/github.com/hashicorp/go-plugin/testing.go b/vendor/github.com/hashicorp/go-plugin/testing.go new file mode 100644 index 00000000000..c6bf7c4ed32 --- /dev/null +++ b/vendor/github.com/hashicorp/go-plugin/testing.go @@ -0,0 +1,120 @@ +package plugin + +import ( + "bytes" + "net" + "net/rpc" + + "github.com/mitchellh/go-testing-interface" + "google.golang.org/grpc" +) + +// The testing file contains test helpers that you can use outside of +// this package for making it easier to test plugins themselves. + +// TestConn is a helper function for returning a client and server +// net.Conn connected to each other. +func TestConn(t testing.T) (net.Conn, net.Conn) { + // Listen to any local port. This listener will be closed + // after a single connection is established. + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %s", err) + } + + // Start a goroutine to accept our client connection + var serverConn net.Conn + doneCh := make(chan struct{}) + go func() { + defer close(doneCh) + defer l.Close() + var err error + serverConn, err = l.Accept() + if err != nil { + t.Fatalf("err: %s", err) + } + }() + + // Connect to the server + clientConn, err := net.Dial("tcp", l.Addr().String()) + if err != nil { + t.Fatalf("err: %s", err) + } + + // Wait for the server side to acknowledge it has connected + <-doneCh + + return clientConn, serverConn +} + +// TestRPCConn returns a rpc client and server connected to each other. +func TestRPCConn(t testing.T) (*rpc.Client, *rpc.Server) { + clientConn, serverConn := TestConn(t) + + server := rpc.NewServer() + go server.ServeConn(serverConn) + + client := rpc.NewClient(clientConn) + return client, server +} + +// TestPluginRPCConn returns a plugin RPC client and server that are connected +// together and configured. +func TestPluginRPCConn(t testing.T, ps map[string]Plugin) (*RPCClient, *RPCServer) { + // Create two net.Conns we can use to shuttle our control connection + clientConn, serverConn := TestConn(t) + + // Start up the server + server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)} + go server.ServeConn(serverConn) + + // Connect the client to the server + client, err := NewRPCClient(clientConn, ps) + if err != nil { + t.Fatalf("err: %s", err) + } + + return client, server +} + +// TestPluginGRPCConn returns a plugin gRPC client and server that are connected +// together and configured. This is used to test gRPC connections. +func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCServer) { + // Create a listener + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %s", err) + } + + // Start up the server + server := &GRPCServer{ + Plugins: ps, + Server: DefaultGRPCServer, + Stdout: new(bytes.Buffer), + Stderr: new(bytes.Buffer), + } + if err := server.Init(); err != nil { + t.Fatalf("err: %s", err) + } + go server.Serve(l) + + // Connect to the server + conn, err := grpc.Dial( + l.Addr().String(), + grpc.WithBlock(), + grpc.WithInsecure()) + if err != nil { + t.Fatalf("err: %s", err) + } + + // Connection successful, close the listener + l.Close() + + // Create the client + client := &GRPCClient{ + Conn: conn, + Plugins: ps, + } + + return client, server +} diff --git a/vendor/github.com/hashicorp/go-version/.travis.yml b/vendor/github.com/hashicorp/go-version/.travis.yml deleted file mode 100644 index 9f30eecd73f..00000000000 --- a/vendor/github.com/hashicorp/go-version/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - 1.0 - - 1.1 - - 1.2 - - 1.3 - - 1.4 - -script: - - go test diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md deleted file mode 100644 index 1d50070f131..00000000000 --- a/vendor/github.com/hashicorp/go-version/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Versioning Library for Go -[![Build Status](https://travis-ci.org/hashicorp/go-version.svg?branch=master)](https://travis-ci.org/hashicorp/go-version) - -go-version is a library for parsing versions and version constraints, -and verifying versions against a set of constraints. go-version -can sort a collection of versions properly, handles prerelease/beta -versions, can increment versions, etc. - -Versions used with go-version must follow [SemVer](http://semver.org/). - -## Installation and Usage - -Package documentation can be found on -[GoDoc](http://godoc.org/github.com/hashicorp/go-version). - -Installation can be done with a normal `go get`: - -``` -$ go get github.com/hashicorp/go-version -``` - -#### Version Parsing and Comparison - -```go -v1, err := version.NewVersion("1.2") -v2, err := version.NewVersion("1.5+metadata") - -// Comparison example. There is also GreaterThan, Equal, and just -// a simple Compare that returns an int allowing easy >=, <=, etc. -if v1.LessThan(v2) { - fmt.Printf("%s is less than %s", v1, v2) -} -``` - -#### Version Constraints - -```go -v1, err := version.NewVersion("1.2") - -// Constraints example. -constraints, err := version.NewConstraint(">= 1.0, < 1.4") -if constraints.Check(v1) { - fmt.Printf("%s satisfies constraints %s", v1, constraints) -} -``` - -#### Version Sorting - -```go -versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"} -versions := make([]*version.Version, len(versionsRaw)) -for i, raw := range versionsRaw { - v, _ := version.NewVersion(raw) - versions[i] = v -} - -// After this, the versions are properly sorted -sort.Sort(version.Collection(versions)) -``` - -## Issues and Contributing - -If you find an issue with this library, please report an issue. If you'd -like, we welcome any contributions. Fork this library and submit a pull -request. diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go index 091cfab389f..8c73df0602b 100644 --- a/vendor/github.com/hashicorp/go-version/constraint.go +++ b/vendor/github.com/hashicorp/go-version/constraint.go @@ -37,7 +37,7 @@ func init() { } ops := make([]string, 0, len(constraintOperators)) - for k, _ := range constraintOperators { + for k := range constraintOperators { ops = append(ops, regexp.QuoteMeta(k)) } @@ -142,15 +142,37 @@ func constraintLessThanEqual(v, c *Version) bool { } func constraintPessimistic(v, c *Version) bool { + // If the version being checked is naturally less than the constraint, then there + // is no way for the version to be valid against the constraint if v.LessThan(c) { return false } + // We'll use this more than once, so grab the length now so it's a little cleaner + // to write the later checks + cs := len(c.segments) + // If the version being checked has less specificity than the constraint, then there + // is no way for the version to be valid against the constraint + if cs > len(v.segments) { + return false + } + + // Check the segments in the constraint against those in the version. If the version + // being checked, at any point, does not have the same values in each index of the + // constraints segments, then it cannot be valid against the constraint. for i := 0; i < c.si-1; i++ { if v.segments[i] != c.segments[i] { return false } } + // Check the last part of the segment in the constraint. If the version segment at + // this index is less than the constraints segment at this index, then it cannot + // be valid against the constraint + if c.segments[cs-1] > v.segments[cs-1] { + return false + } + + // If nothing has rejected the version by now, it's valid return true } diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go index d0e0b0c8ff7..bee527eb258 100644 --- a/vendor/github.com/hashicorp/go-version/version.go +++ b/vendor/github.com/hashicorp/go-version/version.go @@ -14,16 +14,16 @@ var versionRegexp *regexp.Regexp // The raw regular expression string used for testing the validity // of a version. -const VersionRegexpRaw string = `([0-9]+(\.[0-9]+){0,2})` + - `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + - `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + +const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + + `(-?([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + + `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + `?` // Version represents a single version. type Version struct { metadata string pre string - segments []int + segments []int64 si int } @@ -38,20 +38,23 @@ func NewVersion(v string) (*Version, error) { if matches == nil { return nil, fmt.Errorf("Malformed version: %s", v) } - segmentsStr := strings.Split(matches[1], ".") - segments := make([]int, len(segmentsStr), 3) + segments := make([]int64, len(segmentsStr)) si := 0 for i, str := range segmentsStr { - val, err := strconv.ParseInt(str, 10, 32) + val, err := strconv.ParseInt(str, 10, 64) if err != nil { return nil, fmt.Errorf( "Error parsing version: %s", err) } - segments[i] = int(val) - si += 1 + segments[i] = int64(val) + si++ } + + // Even though we could support more than three segments, if we + // got less than three, pad it with 0s. This is to cover the basic + // default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum for i := len(segments); i < 3; i++ { segments = append(segments, 0) } @@ -86,8 +89,8 @@ func (v *Version) Compare(other *Version) int { return 0 } - segmentsSelf := v.Segments() - segmentsOther := other.Segments() + segmentsSelf := v.Segments64() + segmentsOther := other.Segments64() // If the segments are the same, we must compare on prerelease info if reflect.DeepEqual(segmentsSelf, segmentsOther) { @@ -106,21 +109,56 @@ func (v *Version) Compare(other *Version) int { return comparePrereleases(preSelf, preOther) } + // Get the highest specificity (hS), or if they're equal, just use segmentSelf length + lenSelf := len(segmentsSelf) + lenOther := len(segmentsOther) + hS := lenSelf + if lenSelf < lenOther { + hS = lenOther + } // Compare the segments - for i := 0; i < len(segmentsSelf); i++ { + // Because a constraint could have more/less specificity than the version it's + // checking, we need to account for a lopsided or jagged comparison + for i := 0; i < hS; i++ { + if i > lenSelf-1 { + // This means Self had the lower specificity + // Check to see if the remaining segments in Other are all zeros + if !allZero(segmentsOther[i:]) { + // if not, it means that Other has to be greater than Self + return -1 + } + break + } else if i > lenOther-1 { + // this means Other had the lower specificity + // Check to see if the remaining segments in Self are all zeros - + if !allZero(segmentsSelf[i:]) { + //if not, it means that Self has to be greater than Other + return 1 + } + break + } lhs := segmentsSelf[i] rhs := segmentsOther[i] - if lhs == rhs { continue } else if lhs < rhs { return -1 - } else { - return 1 } + // Otherwis, rhs was > lhs, they're not equal + return 1 } - panic("should not be reached") + // if we got this far, they're equal + return 0 +} + +func allZero(segs []int64) bool { + for _, s := range segs { + if s != 0 { + return false + } + } + return true } func comparePart(preSelf string, preOther string) int { @@ -128,24 +166,42 @@ func comparePart(preSelf string, preOther string) int { return 0 } + var selfInt int64 + selfNumeric := true + selfInt, err := strconv.ParseInt(preSelf, 10, 64) + if err != nil { + selfNumeric = false + } + + var otherInt int64 + otherNumeric := true + otherInt, err = strconv.ParseInt(preOther, 10, 64) + if err != nil { + otherNumeric = false + } + // if a part is empty, we use the other to decide if preSelf == "" { - _, notIsNumeric := strconv.ParseInt(preOther, 10, 64) - if notIsNumeric == nil { + if otherNumeric { return -1 } return 1 } if preOther == "" { - _, notIsNumeric := strconv.ParseInt(preSelf, 10, 64) - if notIsNumeric == nil { + if selfNumeric { return 1 } return -1 } - if preSelf > preOther { + if selfNumeric && !otherNumeric { + return -1 + } else if !selfNumeric && otherNumeric { + return 1 + } else if !selfNumeric && !otherNumeric && preSelf > preOther { + return 1 + } else if selfInt > otherInt { return 1 } @@ -226,12 +282,25 @@ func (v *Version) Prerelease() string { return v.pre } -// Segments returns the numeric segments of the version as a slice. +// Segments returns the numeric segments of the version as a slice of ints. // // This excludes any metadata or pre-release information. For example, // for a version "1.2.3-beta", segments will return a slice of // 1, 2, 3. func (v *Version) Segments() []int { + segmentSlice := make([]int, len(v.segments)) + for i, v := range v.segments { + segmentSlice[i] = int(v) + } + return segmentSlice +} + +// Segments64 returns the numeric segments of the version as a slice of int64s. +// +// This excludes any metadata or pre-release information. For example, +// for a version "1.2.3-beta", segments will return a slice of +// 1, 2, 3. +func (v *Version) Segments64() []int64 { return v.segments } @@ -239,7 +308,13 @@ func (v *Version) Segments() []int { // and metadata information. func (v *Version) String() string { var buf bytes.Buffer - fmt.Fprintf(&buf, "%d.%d.%d", v.segments[0], v.segments[1], v.segments[2]) + fmtParts := make([]string, len(v.segments)) + for i, s := range v.segments { + // We can ignore err here since we've pre-parsed the values in segments + str := strconv.FormatInt(s, 10) + fmtParts[i] = str + } + fmt.Fprintf(&buf, strings.Join(fmtParts, ".")) if v.pre != "" { fmt.Fprintf(&buf, "-%s", v.pre) } diff --git a/vendor/github.com/hashicorp/yamux/LICENSE b/vendor/github.com/hashicorp/yamux/LICENSE new file mode 100644 index 00000000000..f0e5c79e181 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/vendor/github.com/hashicorp/yamux/addr.go b/vendor/github.com/hashicorp/yamux/addr.go new file mode 100644 index 00000000000..be6ebca9c78 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/addr.go @@ -0,0 +1,60 @@ +package yamux + +import ( + "fmt" + "net" +) + +// hasAddr is used to get the address from the underlying connection +type hasAddr interface { + LocalAddr() net.Addr + RemoteAddr() net.Addr +} + +// yamuxAddr is used when we cannot get the underlying address +type yamuxAddr struct { + Addr string +} + +func (*yamuxAddr) Network() string { + return "yamux" +} + +func (y *yamuxAddr) String() string { + return fmt.Sprintf("yamux:%s", y.Addr) +} + +// Addr is used to get the address of the listener. +func (s *Session) Addr() net.Addr { + return s.LocalAddr() +} + +// LocalAddr is used to get the local address of the +// underlying connection. +func (s *Session) LocalAddr() net.Addr { + addr, ok := s.conn.(hasAddr) + if !ok { + return &yamuxAddr{"local"} + } + return addr.LocalAddr() +} + +// RemoteAddr is used to get the address of remote end +// of the underlying connection +func (s *Session) RemoteAddr() net.Addr { + addr, ok := s.conn.(hasAddr) + if !ok { + return &yamuxAddr{"remote"} + } + return addr.RemoteAddr() +} + +// LocalAddr returns the local address +func (s *Stream) LocalAddr() net.Addr { + return s.session.LocalAddr() +} + +// LocalAddr returns the remote address +func (s *Stream) RemoteAddr() net.Addr { + return s.session.RemoteAddr() +} diff --git a/vendor/github.com/hashicorp/yamux/const.go b/vendor/github.com/hashicorp/yamux/const.go new file mode 100644 index 00000000000..4f52938287f --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/const.go @@ -0,0 +1,157 @@ +package yamux + +import ( + "encoding/binary" + "fmt" +) + +var ( + // ErrInvalidVersion means we received a frame with an + // invalid version + ErrInvalidVersion = fmt.Errorf("invalid protocol version") + + // ErrInvalidMsgType means we received a frame with an + // invalid message type + ErrInvalidMsgType = fmt.Errorf("invalid msg type") + + // ErrSessionShutdown is used if there is a shutdown during + // an operation + ErrSessionShutdown = fmt.Errorf("session shutdown") + + // ErrStreamsExhausted is returned if we have no more + // stream ids to issue + ErrStreamsExhausted = fmt.Errorf("streams exhausted") + + // ErrDuplicateStream is used if a duplicate stream is + // opened inbound + ErrDuplicateStream = fmt.Errorf("duplicate stream initiated") + + // ErrReceiveWindowExceeded indicates the window was exceeded + ErrRecvWindowExceeded = fmt.Errorf("recv window exceeded") + + // ErrTimeout is used when we reach an IO deadline + ErrTimeout = fmt.Errorf("i/o deadline reached") + + // ErrStreamClosed is returned when using a closed stream + ErrStreamClosed = fmt.Errorf("stream closed") + + // ErrUnexpectedFlag is set when we get an unexpected flag + ErrUnexpectedFlag = fmt.Errorf("unexpected flag") + + // ErrRemoteGoAway is used when we get a go away from the other side + ErrRemoteGoAway = fmt.Errorf("remote end is not accepting connections") + + // ErrConnectionReset is sent if a stream is reset. This can happen + // if the backlog is exceeded, or if there was a remote GoAway. + ErrConnectionReset = fmt.Errorf("connection reset") + + // ErrConnectionWriteTimeout indicates that we hit the "safety valve" + // timeout writing to the underlying stream connection. + ErrConnectionWriteTimeout = fmt.Errorf("connection write timeout") + + // ErrKeepAliveTimeout is sent if a missed keepalive caused the stream close + ErrKeepAliveTimeout = fmt.Errorf("keepalive timeout") +) + +const ( + // protoVersion is the only version we support + protoVersion uint8 = 0 +) + +const ( + // Data is used for data frames. They are followed + // by length bytes worth of payload. + typeData uint8 = iota + + // WindowUpdate is used to change the window of + // a given stream. The length indicates the delta + // update to the window. + typeWindowUpdate + + // Ping is sent as a keep-alive or to measure + // the RTT. The StreamID and Length value are echoed + // back in the response. + typePing + + // GoAway is sent to terminate a session. The StreamID + // should be 0 and the length is an error code. + typeGoAway +) + +const ( + // SYN is sent to signal a new stream. May + // be sent with a data payload + flagSYN uint16 = 1 << iota + + // ACK is sent to acknowledge a new stream. May + // be sent with a data payload + flagACK + + // FIN is sent to half-close the given stream. + // May be sent with a data payload. + flagFIN + + // RST is used to hard close a given stream. + flagRST +) + +const ( + // initialStreamWindow is the initial stream window size + initialStreamWindow uint32 = 256 * 1024 +) + +const ( + // goAwayNormal is sent on a normal termination + goAwayNormal uint32 = iota + + // goAwayProtoErr sent on a protocol error + goAwayProtoErr + + // goAwayInternalErr sent on an internal error + goAwayInternalErr +) + +const ( + sizeOfVersion = 1 + sizeOfType = 1 + sizeOfFlags = 2 + sizeOfStreamID = 4 + sizeOfLength = 4 + headerSize = sizeOfVersion + sizeOfType + sizeOfFlags + + sizeOfStreamID + sizeOfLength +) + +type header []byte + +func (h header) Version() uint8 { + return h[0] +} + +func (h header) MsgType() uint8 { + return h[1] +} + +func (h header) Flags() uint16 { + return binary.BigEndian.Uint16(h[2:4]) +} + +func (h header) StreamID() uint32 { + return binary.BigEndian.Uint32(h[4:8]) +} + +func (h header) Length() uint32 { + return binary.BigEndian.Uint32(h[8:12]) +} + +func (h header) String() string { + return fmt.Sprintf("Vsn:%d Type:%d Flags:%d StreamID:%d Length:%d", + h.Version(), h.MsgType(), h.Flags(), h.StreamID(), h.Length()) +} + +func (h header) encode(msgType uint8, flags uint16, streamID uint32, length uint32) { + h[0] = protoVersion + h[1] = msgType + binary.BigEndian.PutUint16(h[2:4], flags) + binary.BigEndian.PutUint32(h[4:8], streamID) + binary.BigEndian.PutUint32(h[8:12], length) +} diff --git a/vendor/github.com/hashicorp/yamux/mux.go b/vendor/github.com/hashicorp/yamux/mux.go new file mode 100644 index 00000000000..7abc7c744ce --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/mux.go @@ -0,0 +1,87 @@ +package yamux + +import ( + "fmt" + "io" + "os" + "time" +) + +// Config is used to tune the Yamux session +type Config struct { + // AcceptBacklog is used to limit how many streams may be + // waiting an accept. + AcceptBacklog int + + // EnableKeepalive is used to do a period keep alive + // messages using a ping. + EnableKeepAlive bool + + // KeepAliveInterval is how often to perform the keep alive + KeepAliveInterval time.Duration + + // ConnectionWriteTimeout is meant to be a "safety valve" timeout after + // we which will suspect a problem with the underlying connection and + // close it. This is only applied to writes, where's there's generally + // an expectation that things will move along quickly. + ConnectionWriteTimeout time.Duration + + // MaxStreamWindowSize is used to control the maximum + // window size that we allow for a stream. + MaxStreamWindowSize uint32 + + // LogOutput is used to control the log destination + LogOutput io.Writer +} + +// DefaultConfig is used to return a default configuration +func DefaultConfig() *Config { + return &Config{ + AcceptBacklog: 256, + EnableKeepAlive: true, + KeepAliveInterval: 30 * time.Second, + ConnectionWriteTimeout: 10 * time.Second, + MaxStreamWindowSize: initialStreamWindow, + LogOutput: os.Stderr, + } +} + +// VerifyConfig is used to verify the sanity of configuration +func VerifyConfig(config *Config) error { + if config.AcceptBacklog <= 0 { + return fmt.Errorf("backlog must be positive") + } + if config.KeepAliveInterval == 0 { + return fmt.Errorf("keep-alive interval must be positive") + } + if config.MaxStreamWindowSize < initialStreamWindow { + return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow) + } + return nil +} + +// Server is used to initialize a new server-side connection. +// There must be at most one server-side connection. If a nil config is +// provided, the DefaultConfiguration will be used. +func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) { + if config == nil { + config = DefaultConfig() + } + if err := VerifyConfig(config); err != nil { + return nil, err + } + return newSession(config, conn, false), nil +} + +// Client is used to initialize a new client-side connection. +// There must be at most one client-side connection. +func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) { + if config == nil { + config = DefaultConfig() + } + + if err := VerifyConfig(config); err != nil { + return nil, err + } + return newSession(config, conn, true), nil +} diff --git a/vendor/github.com/hashicorp/yamux/session.go b/vendor/github.com/hashicorp/yamux/session.go new file mode 100644 index 00000000000..3f5f4ff2daf --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/session.go @@ -0,0 +1,629 @@ +package yamux + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "log" + "math" + "net" + "strings" + "sync" + "sync/atomic" + "time" +) + +// Session is used to wrap a reliable ordered connection and to +// multiplex it into multiple streams. +type Session struct { + // remoteGoAway indicates the remote side does + // not want futher connections. Must be first for alignment. + remoteGoAway int32 + + // localGoAway indicates that we should stop + // accepting futher connections. Must be first for alignment. + localGoAway int32 + + // nextStreamID is the next stream we should + // send. This depends if we are a client/server. + nextStreamID uint32 + + // config holds our configuration + config *Config + + // logger is used for our logs + logger *log.Logger + + // conn is the underlying connection + conn io.ReadWriteCloser + + // bufRead is a buffered reader + bufRead *bufio.Reader + + // pings is used to track inflight pings + pings map[uint32]chan struct{} + pingID uint32 + pingLock sync.Mutex + + // streams maps a stream id to a stream, and inflight has an entry + // for any outgoing stream that has not yet been established. Both are + // protected by streamLock. + streams map[uint32]*Stream + inflight map[uint32]struct{} + streamLock sync.Mutex + + // synCh acts like a semaphore. It is sized to the AcceptBacklog which + // is assumed to be symmetric between the client and server. This allows + // the client to avoid exceeding the backlog and instead blocks the open. + synCh chan struct{} + + // acceptCh is used to pass ready streams to the client + acceptCh chan *Stream + + // sendCh is used to mark a stream as ready to send, + // or to send a header out directly. + sendCh chan sendReady + + // recvDoneCh is closed when recv() exits to avoid a race + // between stream registration and stream shutdown + recvDoneCh chan struct{} + + // shutdown is used to safely close a session + shutdown bool + shutdownErr error + shutdownCh chan struct{} + shutdownLock sync.Mutex +} + +// sendReady is used to either mark a stream as ready +// or to directly send a header +type sendReady struct { + Hdr []byte + Body io.Reader + Err chan error +} + +// newSession is used to construct a new session +func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session { + s := &Session{ + config: config, + logger: log.New(config.LogOutput, "", log.LstdFlags), + conn: conn, + bufRead: bufio.NewReader(conn), + pings: make(map[uint32]chan struct{}), + streams: make(map[uint32]*Stream), + inflight: make(map[uint32]struct{}), + synCh: make(chan struct{}, config.AcceptBacklog), + acceptCh: make(chan *Stream, config.AcceptBacklog), + sendCh: make(chan sendReady, 64), + recvDoneCh: make(chan struct{}), + shutdownCh: make(chan struct{}), + } + if client { + s.nextStreamID = 1 + } else { + s.nextStreamID = 2 + } + go s.recv() + go s.send() + if config.EnableKeepAlive { + go s.keepalive() + } + return s +} + +// IsClosed does a safe check to see if we have shutdown +func (s *Session) IsClosed() bool { + select { + case <-s.shutdownCh: + return true + default: + return false + } +} + +// CloseChan returns a read-only channel which is closed as +// soon as the session is closed. +func (s *Session) CloseChan() <-chan struct{} { + return s.shutdownCh +} + +// NumStreams returns the number of currently open streams +func (s *Session) NumStreams() int { + s.streamLock.Lock() + num := len(s.streams) + s.streamLock.Unlock() + return num +} + +// Open is used to create a new stream as a net.Conn +func (s *Session) Open() (net.Conn, error) { + conn, err := s.OpenStream() + if err != nil { + return nil, err + } + return conn, nil +} + +// OpenStream is used to create a new stream +func (s *Session) OpenStream() (*Stream, error) { + if s.IsClosed() { + return nil, ErrSessionShutdown + } + if atomic.LoadInt32(&s.remoteGoAway) == 1 { + return nil, ErrRemoteGoAway + } + + // Block if we have too many inflight SYNs + select { + case s.synCh <- struct{}{}: + case <-s.shutdownCh: + return nil, ErrSessionShutdown + } + +GET_ID: + // Get an ID, and check for stream exhaustion + id := atomic.LoadUint32(&s.nextStreamID) + if id >= math.MaxUint32-1 { + return nil, ErrStreamsExhausted + } + if !atomic.CompareAndSwapUint32(&s.nextStreamID, id, id+2) { + goto GET_ID + } + + // Register the stream + stream := newStream(s, id, streamInit) + s.streamLock.Lock() + s.streams[id] = stream + s.inflight[id] = struct{}{} + s.streamLock.Unlock() + + // Send the window update to create + if err := stream.sendWindowUpdate(); err != nil { + select { + case <-s.synCh: + default: + s.logger.Printf("[ERR] yamux: aborted stream open without inflight syn semaphore") + } + return nil, err + } + return stream, nil +} + +// Accept is used to block until the next available stream +// is ready to be accepted. +func (s *Session) Accept() (net.Conn, error) { + conn, err := s.AcceptStream() + if err != nil { + return nil, err + } + return conn, err +} + +// AcceptStream is used to block until the next available stream +// is ready to be accepted. +func (s *Session) AcceptStream() (*Stream, error) { + select { + case stream := <-s.acceptCh: + if err := stream.sendWindowUpdate(); err != nil { + return nil, err + } + return stream, nil + case <-s.shutdownCh: + return nil, s.shutdownErr + } +} + +// Close is used to close the session and all streams. +// Attempts to send a GoAway before closing the connection. +func (s *Session) Close() error { + s.shutdownLock.Lock() + defer s.shutdownLock.Unlock() + + if s.shutdown { + return nil + } + s.shutdown = true + if s.shutdownErr == nil { + s.shutdownErr = ErrSessionShutdown + } + close(s.shutdownCh) + s.conn.Close() + <-s.recvDoneCh + + s.streamLock.Lock() + defer s.streamLock.Unlock() + for _, stream := range s.streams { + stream.forceClose() + } + return nil +} + +// exitErr is used to handle an error that is causing the +// session to terminate. +func (s *Session) exitErr(err error) { + s.shutdownLock.Lock() + if s.shutdownErr == nil { + s.shutdownErr = err + } + s.shutdownLock.Unlock() + s.Close() +} + +// GoAway can be used to prevent accepting further +// connections. It does not close the underlying conn. +func (s *Session) GoAway() error { + return s.waitForSend(s.goAway(goAwayNormal), nil) +} + +// goAway is used to send a goAway message +func (s *Session) goAway(reason uint32) header { + atomic.SwapInt32(&s.localGoAway, 1) + hdr := header(make([]byte, headerSize)) + hdr.encode(typeGoAway, 0, 0, reason) + return hdr +} + +// Ping is used to measure the RTT response time +func (s *Session) Ping() (time.Duration, error) { + // Get a channel for the ping + ch := make(chan struct{}) + + // Get a new ping id, mark as pending + s.pingLock.Lock() + id := s.pingID + s.pingID++ + s.pings[id] = ch + s.pingLock.Unlock() + + // Send the ping request + hdr := header(make([]byte, headerSize)) + hdr.encode(typePing, flagSYN, 0, id) + if err := s.waitForSend(hdr, nil); err != nil { + return 0, err + } + + // Wait for a response + start := time.Now() + select { + case <-ch: + case <-time.After(s.config.ConnectionWriteTimeout): + s.pingLock.Lock() + delete(s.pings, id) // Ignore it if a response comes later. + s.pingLock.Unlock() + return 0, ErrTimeout + case <-s.shutdownCh: + return 0, ErrSessionShutdown + } + + // Compute the RTT + return time.Now().Sub(start), nil +} + +// keepalive is a long running goroutine that periodically does +// a ping to keep the connection alive. +func (s *Session) keepalive() { + for { + select { + case <-time.After(s.config.KeepAliveInterval): + _, err := s.Ping() + if err != nil { + s.logger.Printf("[ERR] yamux: keepalive failed: %v", err) + s.exitErr(ErrKeepAliveTimeout) + return + } + case <-s.shutdownCh: + return + } + } +} + +// waitForSendErr waits to send a header, checking for a potential shutdown +func (s *Session) waitForSend(hdr header, body io.Reader) error { + errCh := make(chan error, 1) + return s.waitForSendErr(hdr, body, errCh) +} + +// waitForSendErr waits to send a header with optional data, checking for a +// potential shutdown. Since there's the expectation that sends can happen +// in a timely manner, we enforce the connection write timeout here. +func (s *Session) waitForSendErr(hdr header, body io.Reader, errCh chan error) error { + timer := time.NewTimer(s.config.ConnectionWriteTimeout) + defer timer.Stop() + + ready := sendReady{Hdr: hdr, Body: body, Err: errCh} + select { + case s.sendCh <- ready: + case <-s.shutdownCh: + return ErrSessionShutdown + case <-timer.C: + return ErrConnectionWriteTimeout + } + + select { + case err := <-errCh: + return err + case <-s.shutdownCh: + return ErrSessionShutdown + case <-timer.C: + return ErrConnectionWriteTimeout + } +} + +// sendNoWait does a send without waiting. Since there's the expectation that +// the send happens right here, we enforce the connection write timeout if we +// can't queue the header to be sent. +func (s *Session) sendNoWait(hdr header) error { + timer := time.NewTimer(s.config.ConnectionWriteTimeout) + defer timer.Stop() + + select { + case s.sendCh <- sendReady{Hdr: hdr}: + return nil + case <-s.shutdownCh: + return ErrSessionShutdown + case <-timer.C: + return ErrConnectionWriteTimeout + } +} + +// send is a long running goroutine that sends data +func (s *Session) send() { + for { + select { + case ready := <-s.sendCh: + // Send a header if ready + if ready.Hdr != nil { + sent := 0 + for sent < len(ready.Hdr) { + n, err := s.conn.Write(ready.Hdr[sent:]) + if err != nil { + s.logger.Printf("[ERR] yamux: Failed to write header: %v", err) + asyncSendErr(ready.Err, err) + s.exitErr(err) + return + } + sent += n + } + } + + // Send data from a body if given + if ready.Body != nil { + _, err := io.Copy(s.conn, ready.Body) + if err != nil { + s.logger.Printf("[ERR] yamux: Failed to write body: %v", err) + asyncSendErr(ready.Err, err) + s.exitErr(err) + return + } + } + + // No error, successful send + asyncSendErr(ready.Err, nil) + case <-s.shutdownCh: + return + } + } +} + +// recv is a long running goroutine that accepts new data +func (s *Session) recv() { + if err := s.recvLoop(); err != nil { + s.exitErr(err) + } +} + +// recvLoop continues to receive data until a fatal error is encountered +func (s *Session) recvLoop() error { + defer close(s.recvDoneCh) + hdr := header(make([]byte, headerSize)) + var handler func(header) error + for { + // Read the header + if _, err := io.ReadFull(s.bufRead, hdr); err != nil { + if err != io.EOF && !strings.Contains(err.Error(), "closed") && !strings.Contains(err.Error(), "reset by peer") { + s.logger.Printf("[ERR] yamux: Failed to read header: %v", err) + } + return err + } + + // Verify the version + if hdr.Version() != protoVersion { + s.logger.Printf("[ERR] yamux: Invalid protocol version: %d", hdr.Version()) + return ErrInvalidVersion + } + + // Switch on the type + switch hdr.MsgType() { + case typeData: + handler = s.handleStreamMessage + case typeWindowUpdate: + handler = s.handleStreamMessage + case typeGoAway: + handler = s.handleGoAway + case typePing: + handler = s.handlePing + default: + return ErrInvalidMsgType + } + + // Invoke the handler + if err := handler(hdr); err != nil { + return err + } + } +} + +// handleStreamMessage handles either a data or window update frame +func (s *Session) handleStreamMessage(hdr header) error { + // Check for a new stream creation + id := hdr.StreamID() + flags := hdr.Flags() + if flags&flagSYN == flagSYN { + if err := s.incomingStream(id); err != nil { + return err + } + } + + // Get the stream + s.streamLock.Lock() + stream := s.streams[id] + s.streamLock.Unlock() + + // If we do not have a stream, likely we sent a RST + if stream == nil { + // Drain any data on the wire + if hdr.MsgType() == typeData && hdr.Length() > 0 { + s.logger.Printf("[WARN] yamux: Discarding data for stream: %d", id) + if _, err := io.CopyN(ioutil.Discard, s.bufRead, int64(hdr.Length())); err != nil { + s.logger.Printf("[ERR] yamux: Failed to discard data: %v", err) + return nil + } + } else { + s.logger.Printf("[WARN] yamux: frame for missing stream: %v", hdr) + } + return nil + } + + // Check if this is a window update + if hdr.MsgType() == typeWindowUpdate { + if err := stream.incrSendWindow(hdr, flags); err != nil { + if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil { + s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr) + } + return err + } + return nil + } + + // Read the new data + if err := stream.readData(hdr, flags, s.bufRead); err != nil { + if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil { + s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr) + } + return err + } + return nil +} + +// handlePing is invokde for a typePing frame +func (s *Session) handlePing(hdr header) error { + flags := hdr.Flags() + pingID := hdr.Length() + + // Check if this is a query, respond back in a separate context so we + // don't interfere with the receiving thread blocking for the write. + if flags&flagSYN == flagSYN { + go func() { + hdr := header(make([]byte, headerSize)) + hdr.encode(typePing, flagACK, 0, pingID) + if err := s.sendNoWait(hdr); err != nil { + s.logger.Printf("[WARN] yamux: failed to send ping reply: %v", err) + } + }() + return nil + } + + // Handle a response + s.pingLock.Lock() + ch := s.pings[pingID] + if ch != nil { + delete(s.pings, pingID) + close(ch) + } + s.pingLock.Unlock() + return nil +} + +// handleGoAway is invokde for a typeGoAway frame +func (s *Session) handleGoAway(hdr header) error { + code := hdr.Length() + switch code { + case goAwayNormal: + atomic.SwapInt32(&s.remoteGoAway, 1) + case goAwayProtoErr: + s.logger.Printf("[ERR] yamux: received protocol error go away") + return fmt.Errorf("yamux protocol error") + case goAwayInternalErr: + s.logger.Printf("[ERR] yamux: received internal error go away") + return fmt.Errorf("remote yamux internal error") + default: + s.logger.Printf("[ERR] yamux: received unexpected go away") + return fmt.Errorf("unexpected go away received") + } + return nil +} + +// incomingStream is used to create a new incoming stream +func (s *Session) incomingStream(id uint32) error { + // Reject immediately if we are doing a go away + if atomic.LoadInt32(&s.localGoAway) == 1 { + hdr := header(make([]byte, headerSize)) + hdr.encode(typeWindowUpdate, flagRST, id, 0) + return s.sendNoWait(hdr) + } + + // Allocate a new stream + stream := newStream(s, id, streamSYNReceived) + + s.streamLock.Lock() + defer s.streamLock.Unlock() + + // Check if stream already exists + if _, ok := s.streams[id]; ok { + s.logger.Printf("[ERR] yamux: duplicate stream declared") + if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil { + s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr) + } + return ErrDuplicateStream + } + + // Register the stream + s.streams[id] = stream + + // Check if we've exceeded the backlog + select { + case s.acceptCh <- stream: + return nil + default: + // Backlog exceeded! RST the stream + s.logger.Printf("[WARN] yamux: backlog exceeded, forcing connection reset") + delete(s.streams, id) + stream.sendHdr.encode(typeWindowUpdate, flagRST, id, 0) + return s.sendNoWait(stream.sendHdr) + } +} + +// closeStream is used to close a stream once both sides have +// issued a close. If there was an in-flight SYN and the stream +// was not yet established, then this will give the credit back. +func (s *Session) closeStream(id uint32) { + s.streamLock.Lock() + if _, ok := s.inflight[id]; ok { + select { + case <-s.synCh: + default: + s.logger.Printf("[ERR] yamux: SYN tracking out of sync") + } + } + delete(s.streams, id) + s.streamLock.Unlock() +} + +// establishStream is used to mark a stream that was in the +// SYN Sent state as established. +func (s *Session) establishStream(id uint32) { + s.streamLock.Lock() + if _, ok := s.inflight[id]; ok { + delete(s.inflight, id) + } else { + s.logger.Printf("[ERR] yamux: established stream without inflight SYN (no tracking entry)") + } + select { + case <-s.synCh: + default: + s.logger.Printf("[ERR] yamux: established stream without inflight SYN (didn't have semaphore)") + } + s.streamLock.Unlock() +} diff --git a/vendor/github.com/hashicorp/yamux/stream.go b/vendor/github.com/hashicorp/yamux/stream.go new file mode 100644 index 00000000000..d135ff0fadd --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/stream.go @@ -0,0 +1,461 @@ +package yamux + +import ( + "bytes" + "io" + "sync" + "sync/atomic" + "time" +) + +type streamState int + +const ( + streamInit streamState = iota + streamSYNSent + streamSYNReceived + streamEstablished + streamLocalClose + streamRemoteClose + streamClosed + streamReset +) + +// Stream is used to represent a logical stream +// within a session. +type Stream struct { + recvWindow uint32 + sendWindow uint32 + + id uint32 + session *Session + + state streamState + stateLock sync.Mutex + + recvBuf *bytes.Buffer + recvLock sync.Mutex + + controlHdr header + controlErr chan error + controlHdrLock sync.Mutex + + sendHdr header + sendErr chan error + sendLock sync.Mutex + + recvNotifyCh chan struct{} + sendNotifyCh chan struct{} + + readDeadline atomic.Value // time.Time + writeDeadline atomic.Value // time.Time +} + +// newStream is used to construct a new stream within +// a given session for an ID +func newStream(session *Session, id uint32, state streamState) *Stream { + s := &Stream{ + id: id, + session: session, + state: state, + controlHdr: header(make([]byte, headerSize)), + controlErr: make(chan error, 1), + sendHdr: header(make([]byte, headerSize)), + sendErr: make(chan error, 1), + recvWindow: initialStreamWindow, + sendWindow: initialStreamWindow, + recvNotifyCh: make(chan struct{}, 1), + sendNotifyCh: make(chan struct{}, 1), + } + s.readDeadline.Store(time.Time{}) + s.writeDeadline.Store(time.Time{}) + return s +} + +// Session returns the associated stream session +func (s *Stream) Session() *Session { + return s.session +} + +// StreamID returns the ID of this stream +func (s *Stream) StreamID() uint32 { + return s.id +} + +// Read is used to read from the stream +func (s *Stream) Read(b []byte) (n int, err error) { + defer asyncNotify(s.recvNotifyCh) +START: + s.stateLock.Lock() + switch s.state { + case streamLocalClose: + fallthrough + case streamRemoteClose: + fallthrough + case streamClosed: + s.recvLock.Lock() + if s.recvBuf == nil || s.recvBuf.Len() == 0 { + s.recvLock.Unlock() + s.stateLock.Unlock() + return 0, io.EOF + } + s.recvLock.Unlock() + case streamReset: + s.stateLock.Unlock() + return 0, ErrConnectionReset + } + s.stateLock.Unlock() + + // If there is no data available, block + s.recvLock.Lock() + if s.recvBuf == nil || s.recvBuf.Len() == 0 { + s.recvLock.Unlock() + goto WAIT + } + + // Read any bytes + n, _ = s.recvBuf.Read(b) + s.recvLock.Unlock() + + // Send a window update potentially + err = s.sendWindowUpdate() + return n, err + +WAIT: + var timeout <-chan time.Time + var timer *time.Timer + readDeadline := s.readDeadline.Load().(time.Time) + if !readDeadline.IsZero() { + delay := readDeadline.Sub(time.Now()) + timer = time.NewTimer(delay) + timeout = timer.C + } + select { + case <-s.recvNotifyCh: + if timer != nil { + timer.Stop() + } + goto START + case <-timeout: + return 0, ErrTimeout + } +} + +// Write is used to write to the stream +func (s *Stream) Write(b []byte) (n int, err error) { + s.sendLock.Lock() + defer s.sendLock.Unlock() + total := 0 + for total < len(b) { + n, err := s.write(b[total:]) + total += n + if err != nil { + return total, err + } + } + return total, nil +} + +// write is used to write to the stream, may return on +// a short write. +func (s *Stream) write(b []byte) (n int, err error) { + var flags uint16 + var max uint32 + var body io.Reader +START: + s.stateLock.Lock() + switch s.state { + case streamLocalClose: + fallthrough + case streamClosed: + s.stateLock.Unlock() + return 0, ErrStreamClosed + case streamReset: + s.stateLock.Unlock() + return 0, ErrConnectionReset + } + s.stateLock.Unlock() + + // If there is no data available, block + window := atomic.LoadUint32(&s.sendWindow) + if window == 0 { + goto WAIT + } + + // Determine the flags if any + flags = s.sendFlags() + + // Send up to our send window + max = min(window, uint32(len(b))) + body = bytes.NewReader(b[:max]) + + // Send the header + s.sendHdr.encode(typeData, flags, s.id, max) + if err = s.session.waitForSendErr(s.sendHdr, body, s.sendErr); err != nil { + return 0, err + } + + // Reduce our send window + atomic.AddUint32(&s.sendWindow, ^uint32(max-1)) + + // Unlock + return int(max), err + +WAIT: + var timeout <-chan time.Time + writeDeadline := s.writeDeadline.Load().(time.Time) + if !writeDeadline.IsZero() { + delay := writeDeadline.Sub(time.Now()) + timeout = time.After(delay) + } + select { + case <-s.sendNotifyCh: + goto START + case <-timeout: + return 0, ErrTimeout + } + return 0, nil +} + +// sendFlags determines any flags that are appropriate +// based on the current stream state +func (s *Stream) sendFlags() uint16 { + s.stateLock.Lock() + defer s.stateLock.Unlock() + var flags uint16 + switch s.state { + case streamInit: + flags |= flagSYN + s.state = streamSYNSent + case streamSYNReceived: + flags |= flagACK + s.state = streamEstablished + } + return flags +} + +// sendWindowUpdate potentially sends a window update enabling +// further writes to take place. Must be invoked with the lock. +func (s *Stream) sendWindowUpdate() error { + s.controlHdrLock.Lock() + defer s.controlHdrLock.Unlock() + + // Determine the delta update + max := s.session.config.MaxStreamWindowSize + delta := max - atomic.LoadUint32(&s.recvWindow) + + // Determine the flags if any + flags := s.sendFlags() + + // Check if we can omit the update + if delta < (max/2) && flags == 0 { + return nil + } + + // Update our window + atomic.AddUint32(&s.recvWindow, delta) + + // Send the header + s.controlHdr.encode(typeWindowUpdate, flags, s.id, delta) + if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil { + return err + } + return nil +} + +// sendClose is used to send a FIN +func (s *Stream) sendClose() error { + s.controlHdrLock.Lock() + defer s.controlHdrLock.Unlock() + + flags := s.sendFlags() + flags |= flagFIN + s.controlHdr.encode(typeWindowUpdate, flags, s.id, 0) + if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil { + return err + } + return nil +} + +// Close is used to close the stream +func (s *Stream) Close() error { + closeStream := false + s.stateLock.Lock() + switch s.state { + // Opened means we need to signal a close + case streamSYNSent: + fallthrough + case streamSYNReceived: + fallthrough + case streamEstablished: + s.state = streamLocalClose + goto SEND_CLOSE + + case streamLocalClose: + case streamRemoteClose: + s.state = streamClosed + closeStream = true + goto SEND_CLOSE + + case streamClosed: + case streamReset: + default: + panic("unhandled state") + } + s.stateLock.Unlock() + return nil +SEND_CLOSE: + s.stateLock.Unlock() + s.sendClose() + s.notifyWaiting() + if closeStream { + s.session.closeStream(s.id) + } + return nil +} + +// forceClose is used for when the session is exiting +func (s *Stream) forceClose() { + s.stateLock.Lock() + s.state = streamClosed + s.stateLock.Unlock() + s.notifyWaiting() +} + +// processFlags is used to update the state of the stream +// based on set flags, if any. Lock must be held +func (s *Stream) processFlags(flags uint16) error { + // Close the stream without holding the state lock + closeStream := false + defer func() { + if closeStream { + s.session.closeStream(s.id) + } + }() + + s.stateLock.Lock() + defer s.stateLock.Unlock() + if flags&flagACK == flagACK { + if s.state == streamSYNSent { + s.state = streamEstablished + } + s.session.establishStream(s.id) + } + if flags&flagFIN == flagFIN { + switch s.state { + case streamSYNSent: + fallthrough + case streamSYNReceived: + fallthrough + case streamEstablished: + s.state = streamRemoteClose + s.notifyWaiting() + case streamLocalClose: + s.state = streamClosed + closeStream = true + s.notifyWaiting() + default: + s.session.logger.Printf("[ERR] yamux: unexpected FIN flag in state %d", s.state) + return ErrUnexpectedFlag + } + } + if flags&flagRST == flagRST { + s.state = streamReset + closeStream = true + s.notifyWaiting() + } + return nil +} + +// notifyWaiting notifies all the waiting channels +func (s *Stream) notifyWaiting() { + asyncNotify(s.recvNotifyCh) + asyncNotify(s.sendNotifyCh) +} + +// incrSendWindow updates the size of our send window +func (s *Stream) incrSendWindow(hdr header, flags uint16) error { + if err := s.processFlags(flags); err != nil { + return err + } + + // Increase window, unblock a sender + atomic.AddUint32(&s.sendWindow, hdr.Length()) + asyncNotify(s.sendNotifyCh) + return nil +} + +// readData is used to handle a data frame +func (s *Stream) readData(hdr header, flags uint16, conn io.Reader) error { + if err := s.processFlags(flags); err != nil { + return err + } + + // Check that our recv window is not exceeded + length := hdr.Length() + if length == 0 { + return nil + } + if remain := atomic.LoadUint32(&s.recvWindow); length > remain { + s.session.logger.Printf("[ERR] yamux: receive window exceeded (stream: %d, remain: %d, recv: %d)", s.id, remain, length) + return ErrRecvWindowExceeded + } + + // Wrap in a limited reader + conn = &io.LimitedReader{R: conn, N: int64(length)} + + // Copy into buffer + s.recvLock.Lock() + if s.recvBuf == nil { + // Allocate the receive buffer just-in-time to fit the full data frame. + // This way we can read in the whole packet without further allocations. + s.recvBuf = bytes.NewBuffer(make([]byte, 0, length)) + } + if _, err := io.Copy(s.recvBuf, conn); err != nil { + s.session.logger.Printf("[ERR] yamux: Failed to read stream data: %v", err) + s.recvLock.Unlock() + return err + } + + // Decrement the receive window + atomic.AddUint32(&s.recvWindow, ^uint32(length-1)) + s.recvLock.Unlock() + + // Unblock any readers + asyncNotify(s.recvNotifyCh) + return nil +} + +// SetDeadline sets the read and write deadlines +func (s *Stream) SetDeadline(t time.Time) error { + if err := s.SetReadDeadline(t); err != nil { + return err + } + if err := s.SetWriteDeadline(t); err != nil { + return err + } + return nil +} + +// SetReadDeadline sets the deadline for future Read calls. +func (s *Stream) SetReadDeadline(t time.Time) error { + s.readDeadline.Store(t) + return nil +} + +// SetWriteDeadline sets the deadline for future Write calls +func (s *Stream) SetWriteDeadline(t time.Time) error { + s.writeDeadline.Store(t) + return nil +} + +// Shrink is used to compact the amount of buffers utilized +// This is useful when using Yamux in a connection pool to reduce +// the idle memory utilization. +func (s *Stream) Shrink() { + s.recvLock.Lock() + if s.recvBuf != nil && s.recvBuf.Len() == 0 { + s.recvBuf = nil + } + s.recvLock.Unlock() +} diff --git a/vendor/github.com/hashicorp/yamux/util.go b/vendor/github.com/hashicorp/yamux/util.go new file mode 100644 index 00000000000..5fe45afcdf2 --- /dev/null +++ b/vendor/github.com/hashicorp/yamux/util.go @@ -0,0 +1,28 @@ +package yamux + +// asyncSendErr is used to try an async send of an error +func asyncSendErr(ch chan error, err error) { + if ch == nil { + return + } + select { + case ch <- err: + default: + } +} + +// asyncNotify is used to signal a waiting goroutine +func asyncNotify(ch chan struct{}) { + select { + case ch <- struct{}{}: + default: + } +} + +// min computes the minimum of two values +func min(a, b uint32) uint32 { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/inconshreveable/log15/README.md b/vendor/github.com/inconshreveable/log15/README.md deleted file mode 100644 index 1727b6c493c..00000000000 --- a/vendor/github.com/inconshreveable/log15/README.md +++ /dev/null @@ -1,84 +0,0 @@ -![obligatory xkcd](http://imgs.xkcd.com/comics/standards.png) - -# log15 [![godoc reference](https://godoc.org/github.com/inconshreveable/log15?status.png)](https://godoc.org/github.com/inconshreveable/log15) [![Build Status](https://travis-ci.org/inconshreveable/log15.svg?branch=master)](https://travis-ci.org/inconshreveable/log15) - -Package log15 provides an opinionated, simple toolkit for best-practice logging in Go (golang) that is both human and machine readable. It is modeled after the Go standard library's [`io`](http://golang.org/pkg/io/) and [`net/http`](http://golang.org/pkg/net/http/) packages and is an alternative to the standard library's [`log`](http://golang.org/pkg/log/) package. - -## Features -- A simple, easy-to-understand API -- Promotes structured logging by encouraging use of key/value pairs -- Child loggers which inherit and add their own private context -- Lazy evaluation of expensive operations -- Simple Handler interface allowing for construction of flexible, custom logging configurations with a tiny API. -- Color terminal support -- Built-in support for logging to files, streams, syslog, and the network -- Support for forking records to multiple handlers, buffering records for output, failing over from failed handler writes, + more - -## Versioning -The API of the master branch of log15 should always be considered unstable. If you want to rely on a stable API, -you must vendor the library. - -## Importing - -```go -import log "github.com/inconshreveable/log15" -``` - -## Examples - -```go -// all loggers can have key/value context -srvlog := log.New("module", "app/server") - -// all log messages can have key/value context -srvlog.Warn("abnormal conn rate", "rate", curRate, "low", lowRate, "high", highRate) - -// child loggers with inherited context -connlog := srvlog.New("raddr", c.RemoteAddr()) -connlog.Info("connection open") - -// lazy evaluation -connlog.Debug("ping remote", "latency", log.Lazy{pingRemote}) - -// flexible configuration -srvlog.SetHandler(log.MultiHandler( - log.StreamHandler(os.Stderr, log.LogfmtFormat()), - log.LvlFilterHandler( - log.LvlError, - log.Must.FileHandler("errors.json", log.JsonFormat())))) -``` - -Will result in output that looks like this: - -``` -WARN[06-17|21:58:10] abnormal conn rate module=app/server rate=0.500 low=0.100 high=0.800 -INFO[06-17|21:58:10] connection open module=app/server raddr=10.0.0.1 -``` - -## Breaking API Changes -The following commits broke API stability. This reference is intended to help you understand the consequences of updating to a newer version -of log15. - -- 57a084d014d4150152b19e4e531399a7145d1540 - Added a `Get()` method to the `Logger` interface to retrieve the current handler -- 93404652ee366648fa622b64d1e2b67d75a3094a - `Record` field `Call` changed to `stack.Call` with switch to `github.com/go-stack/stack` -- a5e7613673c73281f58e15a87d2cf0cf111e8152 - Restored `syslog.Priority` argument to the `SyslogXxx` handler constructors - -## FAQ - -### The varargs style is brittle and error prone! Can I have type safety please? -Yes. Use `log.Ctx`: - -```go -srvlog := log.New(log.Ctx{"module": "app/server"}) -srvlog.Warn("abnormal conn rate", log.Ctx{"rate": curRate, "low": lowRate, "high": highRate}) -``` - -### Regenerating the CONTRIBUTORS file - -``` -go get -u github.com/kevinburke/write_mailmap -write_mailmap > CONTRIBUTORS -``` - -## License -Apache diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_appengine.go b/vendor/github.com/inconshreveable/log15/term/terminal_appengine.go deleted file mode 100644 index c1b5d2a3b1a..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_appengine.go +++ /dev/null @@ -1,13 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 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. - -// +build appengine - -package term - -// IsTty always returns false on AppEngine. -func IsTty(fd uintptr) bool { - return false -} diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_darwin.go b/vendor/github.com/inconshreveable/log15/term/terminal_darwin.go deleted file mode 100644 index d8f351b1b1a..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_darwin.go +++ /dev/null @@ -1,13 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 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. -// +build !appengine - -package term - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_freebsd.go b/vendor/github.com/inconshreveable/log15/term/terminal_freebsd.go deleted file mode 100644 index cfaceab337a..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_freebsd.go +++ /dev/null @@ -1,18 +0,0 @@ -package term - -import ( - "syscall" -) - -const ioctlReadTermios = syscall.TIOCGETA - -// Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin. -type Termios struct { - Iflag uint32 - Oflag uint32 - Cflag uint32 - Lflag uint32 - Cc [20]uint8 - Ispeed uint32 - Ospeed uint32 -} diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_linux.go b/vendor/github.com/inconshreveable/log15/term/terminal_linux.go deleted file mode 100644 index 5290468d698..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_linux.go +++ /dev/null @@ -1,14 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 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. - -// +build !appengine - -package term - -import "syscall" - -const ioctlReadTermios = syscall.TCGETS - -type Termios syscall.Termios diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_netbsd.go b/vendor/github.com/inconshreveable/log15/term/terminal_netbsd.go deleted file mode 100644 index f9bb9e1c23b..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_netbsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package term - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_notwindows.go b/vendor/github.com/inconshreveable/log15/term/terminal_notwindows.go deleted file mode 100644 index c9af534f62f..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_notwindows.go +++ /dev/null @@ -1,20 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 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. - -// +build linux,!appengine darwin freebsd openbsd netbsd - -package term - -import ( - "syscall" - "unsafe" -) - -// IsTty returns true if the given file descriptor is a terminal. -func IsTty(fd uintptr) bool { - var termios Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 -} diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_openbsd.go b/vendor/github.com/inconshreveable/log15/term/terminal_openbsd.go deleted file mode 100644 index f9bb9e1c23b..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_openbsd.go +++ /dev/null @@ -1,7 +0,0 @@ -package term - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_solaris.go b/vendor/github.com/inconshreveable/log15/term/terminal_solaris.go deleted file mode 100644 index 033c163246e..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_solaris.go +++ /dev/null @@ -1,9 +0,0 @@ -package term - -import "golang.org/x/sys/unix" - -// IsTty returns true if the given file descriptor is a terminal. -func IsTty(fd uintptr) bool { - _, err := unix.IoctlGetTermios(int(fd), unix.TCGETA) - return err == nil -} diff --git a/vendor/github.com/inconshreveable/log15/term/terminal_windows.go b/vendor/github.com/inconshreveable/log15/term/terminal_windows.go deleted file mode 100644 index df3c30c1589..00000000000 --- a/vendor/github.com/inconshreveable/log15/term/terminal_windows.go +++ /dev/null @@ -1,26 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 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. - -// +build windows - -package term - -import ( - "syscall" - "unsafe" -) - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var ( - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") -) - -// IsTty returns true if the given file descriptor is a terminal. -func IsTty(fd uintptr) bool { - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 -} diff --git a/vendor/github.com/jmespath/go-jmespath/.gitignore b/vendor/github.com/jmespath/go-jmespath/.gitignore deleted file mode 100644 index 531fcc11c70..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -jpgo -jmespath-fuzz.zip -cpu.out -go-jmespath.test diff --git a/vendor/github.com/jmespath/go-jmespath/.travis.yml b/vendor/github.com/jmespath/go-jmespath/.travis.yml deleted file mode 100644 index 1f98077570d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -sudo: false - -go: - - 1.4 - -install: go get -v -t ./... -script: make test diff --git a/vendor/github.com/jmespath/go-jmespath/Makefile b/vendor/github.com/jmespath/go-jmespath/Makefile deleted file mode 100644 index ad17bf0012e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/Makefile +++ /dev/null @@ -1,44 +0,0 @@ - -CMD = jpgo - -help: - @echo "Please use \`make ' where is one of" - @echo " test to run all the tests" - @echo " build to build the library and jp executable" - @echo " generate to run codegen" - - -generate: - go generate ./... - -build: - rm -f $(CMD) - go build ./... - rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./... - mv cmd/$(CMD)/$(CMD) . - -test: - go test -v ./... - -check: - go vet ./... - @echo "golint ./..." - @lint=`golint ./...`; \ - lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \ - echo "$$lint"; \ - if [ "$$lint" != "" ]; then exit 1; fi - -htmlc: - go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov - -buildfuzz: - go-fuzz-build github.com/jmespath/go-jmespath/fuzz - -fuzz: buildfuzz - go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/corpus - -bench: - go test -bench . -cpuprofile cpu.out - -pprof-cpu: - go tool pprof ./go-jmespath.test ./cpu.out diff --git a/vendor/github.com/jmespath/go-jmespath/README.md b/vendor/github.com/jmespath/go-jmespath/README.md deleted file mode 100644 index 187ef676dc9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# go-jmespath - A JMESPath implementation in Go - -[![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) - - - -See http://jmespath.org for more info. diff --git a/vendor/github.com/jmespath/go-jmespath/api.go b/vendor/github.com/jmespath/go-jmespath/api.go index 67df3fc1c87..9cfa988bc5b 100644 --- a/vendor/github.com/jmespath/go-jmespath/api.go +++ b/vendor/github.com/jmespath/go-jmespath/api.go @@ -1,5 +1,42 @@ package jmespath +import "strconv" + +// JmesPath is the epresentation of a compiled JMES path query. A JmesPath is +// safe for concurrent use by multiple goroutines. +type JMESPath struct { + ast ASTNode + intr *treeInterpreter +} + +// Compile parses a JMESPath expression and returns, if successful, a JMESPath +// object that can be used to match against data. +func Compile(expression string) (*JMESPath, error) { + parser := NewParser() + ast, err := parser.Parse(expression) + if err != nil { + return nil, err + } + jmespath := &JMESPath{ast: ast, intr: newInterpreter()} + return jmespath, nil +} + +// MustCompile is like Compile but panics if the expression cannot be parsed. +// It simplifies safe initialization of global variables holding compiled +// JMESPaths. +func MustCompile(expression string) *JMESPath { + jmespath, err := Compile(expression) + if err != nil { + panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error()) + } + return jmespath +} + +// Search evaluates a JMESPath expression against input data and returns the result. +func (jp *JMESPath) Search(data interface{}) (interface{}, error) { + return jp.intr.Execute(jp.ast, data) +} + // Search evaluates a JMESPath expression against input data and returns the result. func Search(expression string, data interface{}) (interface{}, error) { intr := newInterpreter() diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/basic.json b/vendor/github.com/jmespath/go-jmespath/compliance/basic.json deleted file mode 100644 index d550e969547..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/basic.json +++ /dev/null @@ -1,96 +0,0 @@ -[{ - "given": - {"foo": {"bar": {"baz": "correct"}}}, - "cases": [ - { - "expression": "foo", - "result": {"bar": {"baz": "correct"}} - }, - { - "expression": "foo.bar", - "result": {"baz": "correct"} - }, - { - "expression": "foo.bar.baz", - "result": "correct" - }, - { - "expression": "foo\n.\nbar\n.baz", - "result": "correct" - }, - { - "expression": "foo.bar.baz.bad", - "result": null - }, - { - "expression": "foo.bar.bad", - "result": null - }, - { - "expression": "foo.bad", - "result": null - }, - { - "expression": "bad", - "result": null - }, - { - "expression": "bad.morebad.morebad", - "result": null - } - ] -}, -{ - "given": - {"foo": {"bar": ["one", "two", "three"]}}, - "cases": [ - { - "expression": "foo", - "result": {"bar": ["one", "two", "three"]} - }, - { - "expression": "foo.bar", - "result": ["one", "two", "three"] - } - ] -}, -{ - "given": ["one", "two", "three"], - "cases": [ - { - "expression": "one", - "result": null - }, - { - "expression": "two", - "result": null - }, - { - "expression": "three", - "result": null - }, - { - "expression": "one.two", - "result": null - } - ] -}, -{ - "given": - {"foo": {"1": ["one", "two", "three"], "-1": "bar"}}, - "cases": [ - { - "expression": "foo.\"1\"", - "result": ["one", "two", "three"] - }, - { - "expression": "foo.\"1\"[0]", - "result": "one" - }, - { - "expression": "foo.\"-1\"", - "result": "bar" - } - ] -} -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/boolean.json b/vendor/github.com/jmespath/go-jmespath/compliance/boolean.json deleted file mode 100644 index e3fa196b14f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/boolean.json +++ /dev/null @@ -1,257 +0,0 @@ -[ - { - "given": { - "outer": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - } - }, - "cases": [ - { - "expression": "outer.foo || outer.bar", - "result": "foo" - }, - { - "expression": "outer.foo||outer.bar", - "result": "foo" - }, - { - "expression": "outer.bar || outer.baz", - "result": "bar" - }, - { - "expression": "outer.bar||outer.baz", - "result": "bar" - }, - { - "expression": "outer.bad || outer.foo", - "result": "foo" - }, - { - "expression": "outer.bad||outer.foo", - "result": "foo" - }, - { - "expression": "outer.foo || outer.bad", - "result": "foo" - }, - { - "expression": "outer.foo||outer.bad", - "result": "foo" - }, - { - "expression": "outer.bad || outer.alsobad", - "result": null - }, - { - "expression": "outer.bad||outer.alsobad", - "result": null - } - ] - }, - { - "given": { - "outer": { - "foo": "foo", - "bool": false, - "empty_list": [], - "empty_string": "" - } - }, - "cases": [ - { - "expression": "outer.empty_string || outer.foo", - "result": "foo" - }, - { - "expression": "outer.nokey || outer.bool || outer.empty_list || outer.empty_string || outer.foo", - "result": "foo" - } - ] - }, - { - "given": { - "True": true, - "False": false, - "Number": 5, - "EmptyList": [], - "Zero": 0 - }, - "cases": [ - { - "expression": "True && False", - "result": false - }, - { - "expression": "False && True", - "result": false - }, - { - "expression": "True && True", - "result": true - }, - { - "expression": "False && False", - "result": false - }, - { - "expression": "True && Number", - "result": 5 - }, - { - "expression": "Number && True", - "result": true - }, - { - "expression": "Number && False", - "result": false - }, - { - "expression": "Number && EmptyList", - "result": [] - }, - { - "expression": "Number && True", - "result": true - }, - { - "expression": "EmptyList && True", - "result": [] - }, - { - "expression": "EmptyList && False", - "result": [] - }, - { - "expression": "True || False", - "result": true - }, - { - "expression": "True || True", - "result": true - }, - { - "expression": "False || True", - "result": true - }, - { - "expression": "False || False", - "result": false - }, - { - "expression": "Number || EmptyList", - "result": 5 - }, - { - "expression": "Number || True", - "result": 5 - }, - { - "expression": "Number || True && False", - "result": 5 - }, - { - "expression": "(Number || True) && False", - "result": false - }, - { - "expression": "Number || (True && False)", - "result": 5 - }, - { - "expression": "!True", - "result": false - }, - { - "expression": "!False", - "result": true - }, - { - "expression": "!Number", - "result": false - }, - { - "expression": "!EmptyList", - "result": true - }, - { - "expression": "True && !False", - "result": true - }, - { - "expression": "True && !EmptyList", - "result": true - }, - { - "expression": "!False && !EmptyList", - "result": true - }, - { - "expression": "!(True && False)", - "result": true - }, - { - "expression": "!Zero", - "result": false - }, - { - "expression": "!!Zero", - "result": true - } - ] - }, - { - "given": { - "one": 1, - "two": 2, - "three": 3 - }, - "cases": [ - { - "expression": "one < two", - "result": true - }, - { - "expression": "one <= two", - "result": true - }, - { - "expression": "one == one", - "result": true - }, - { - "expression": "one == two", - "result": false - }, - { - "expression": "one > two", - "result": false - }, - { - "expression": "one >= two", - "result": false - }, - { - "expression": "one != two", - "result": true - }, - { - "expression": "one < two && three > one", - "result": true - }, - { - "expression": "one < two || three > one", - "result": true - }, - { - "expression": "one < two || three < one", - "result": true - }, - { - "expression": "two < one || three < one", - "result": false - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/current.json b/vendor/github.com/jmespath/go-jmespath/compliance/current.json deleted file mode 100644 index 0c26248d079..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/current.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "given": { - "foo": [{"name": "a"}, {"name": "b"}], - "bar": {"baz": "qux"} - }, - "cases": [ - { - "expression": "@", - "result": { - "foo": [{"name": "a"}, {"name": "b"}], - "bar": {"baz": "qux"} - } - }, - { - "expression": "@.bar", - "result": {"baz": "qux"} - }, - { - "expression": "@.foo[0]", - "result": {"name": "a"} - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/escape.json b/vendor/github.com/jmespath/go-jmespath/compliance/escape.json deleted file mode 100644 index 4a62d951a65..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/escape.json +++ /dev/null @@ -1,46 +0,0 @@ -[{ - "given": { - "foo.bar": "dot", - "foo bar": "space", - "foo\nbar": "newline", - "foo\"bar": "doublequote", - "c:\\\\windows\\path": "windows", - "/unix/path": "unix", - "\"\"\"": "threequotes", - "bar": {"baz": "qux"} - }, - "cases": [ - { - "expression": "\"foo.bar\"", - "result": "dot" - }, - { - "expression": "\"foo bar\"", - "result": "space" - }, - { - "expression": "\"foo\\nbar\"", - "result": "newline" - }, - { - "expression": "\"foo\\\"bar\"", - "result": "doublequote" - }, - { - "expression": "\"c:\\\\\\\\windows\\\\path\"", - "result": "windows" - }, - { - "expression": "\"/unix/path\"", - "result": "unix" - }, - { - "expression": "\"\\\"\\\"\\\"\"", - "result": "threequotes" - }, - { - "expression": "\"bar\".\"baz\"", - "result": "qux" - } - ] -}] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/filters.json b/vendor/github.com/jmespath/go-jmespath/compliance/filters.json deleted file mode 100644 index 5b9f52b1159..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/filters.json +++ /dev/null @@ -1,468 +0,0 @@ -[ - { - "given": {"foo": [{"name": "a"}, {"name": "b"}]}, - "cases": [ - { - "comment": "Matching a literal", - "expression": "foo[?name == 'a']", - "result": [{"name": "a"}] - } - ] - }, - { - "given": {"foo": [0, 1], "bar": [2, 3]}, - "cases": [ - { - "comment": "Matching a literal", - "expression": "*[?[0] == `0`]", - "result": [[], []] - } - ] - }, - { - "given": {"foo": [{"first": "foo", "last": "bar"}, - {"first": "foo", "last": "foo"}, - {"first": "foo", "last": "baz"}]}, - "cases": [ - { - "comment": "Matching an expression", - "expression": "foo[?first == last]", - "result": [{"first": "foo", "last": "foo"}] - }, - { - "comment": "Verify projection created from filter", - "expression": "foo[?first == last].first", - "result": ["foo"] - } - ] - }, - { - "given": {"foo": [{"age": 20}, - {"age": 25}, - {"age": 30}]}, - "cases": [ - { - "comment": "Greater than with a number", - "expression": "foo[?age > `25`]", - "result": [{"age": 30}] - }, - { - "expression": "foo[?age >= `25`]", - "result": [{"age": 25}, {"age": 30}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age > `30`]", - "result": [] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age < `25`]", - "result": [{"age": 20}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age <= `25`]", - "result": [{"age": 20}, {"age": 25}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age < `20`]", - "result": [] - }, - { - "expression": "foo[?age == `20`]", - "result": [{"age": 20}] - }, - { - "expression": "foo[?age != `20`]", - "result": [{"age": 25}, {"age": 30}] - } - ] - }, - { - "given": {"foo": [{"top": {"name": "a"}}, - {"top": {"name": "b"}}]}, - "cases": [ - { - "comment": "Filter with subexpression", - "expression": "foo[?top.name == 'a']", - "result": [{"top": {"name": "a"}}] - } - ] - }, - { - "given": {"foo": [{"top": {"first": "foo", "last": "bar"}}, - {"top": {"first": "foo", "last": "foo"}}, - {"top": {"first": "foo", "last": "baz"}}]}, - "cases": [ - { - "comment": "Matching an expression", - "expression": "foo[?top.first == top.last]", - "result": [{"top": {"first": "foo", "last": "foo"}}] - }, - { - "comment": "Matching a JSON array", - "expression": "foo[?top == `{\"first\": \"foo\", \"last\": \"bar\"}`]", - "result": [{"top": {"first": "foo", "last": "bar"}}] - } - ] - }, - { - "given": {"foo": [ - {"key": true}, - {"key": false}, - {"key": 0}, - {"key": 1}, - {"key": [0]}, - {"key": {"bar": [0]}}, - {"key": null}, - {"key": [1]}, - {"key": {"a":2}} - ]}, - "cases": [ - { - "expression": "foo[?key == `true`]", - "result": [{"key": true}] - }, - { - "expression": "foo[?key == `false`]", - "result": [{"key": false}] - }, - { - "expression": "foo[?key == `0`]", - "result": [{"key": 0}] - }, - { - "expression": "foo[?key == `1`]", - "result": [{"key": 1}] - }, - { - "expression": "foo[?key == `[0]`]", - "result": [{"key": [0]}] - }, - { - "expression": "foo[?key == `{\"bar\": [0]}`]", - "result": [{"key": {"bar": [0]}}] - }, - { - "expression": "foo[?key == `null`]", - "result": [{"key": null}] - }, - { - "expression": "foo[?key == `[1]`]", - "result": [{"key": [1]}] - }, - { - "expression": "foo[?key == `{\"a\":2}`]", - "result": [{"key": {"a":2}}] - }, - { - "expression": "foo[?`true` == key]", - "result": [{"key": true}] - }, - { - "expression": "foo[?`false` == key]", - "result": [{"key": false}] - }, - { - "expression": "foo[?`0` == key]", - "result": [{"key": 0}] - }, - { - "expression": "foo[?`1` == key]", - "result": [{"key": 1}] - }, - { - "expression": "foo[?`[0]` == key]", - "result": [{"key": [0]}] - }, - { - "expression": "foo[?`{\"bar\": [0]}` == key]", - "result": [{"key": {"bar": [0]}}] - }, - { - "expression": "foo[?`null` == key]", - "result": [{"key": null}] - }, - { - "expression": "foo[?`[1]` == key]", - "result": [{"key": [1]}] - }, - { - "expression": "foo[?`{\"a\":2}` == key]", - "result": [{"key": {"a":2}}] - }, - { - "expression": "foo[?key != `true`]", - "result": [{"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `false`]", - "result": [{"key": true}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `0`]", - "result": [{"key": true}, {"key": false}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `1`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `null`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `[1]`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `{\"a\":2}`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}] - }, - { - "expression": "foo[?`true` != key]", - "result": [{"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`false` != key]", - "result": [{"key": true}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`0` != key]", - "result": [{"key": true}, {"key": false}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`1` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`null` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`[1]` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`{\"a\":2}` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}] - } - ] - }, - { - "given": {"reservations": [ - {"instances": [ - {"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, - {"foo": 1, "bar": 2}, {"foo": 2, "bar": 1}]}]}, - "cases": [ - { - "expression": "reservations[].instances[?bar==`1`]", - "result": [[{"foo": 2, "bar": 1}]] - }, - { - "expression": "reservations[*].instances[?bar==`1`]", - "result": [[{"foo": 2, "bar": 1}]] - }, - { - "expression": "reservations[].instances[?bar==`1`][]", - "result": [{"foo": 2, "bar": 1}] - } - ] - }, - { - "given": { - "baz": "other", - "foo": [ - {"bar": 1}, {"bar": 2}, {"bar": 3}, {"bar": 4}, {"bar": 1, "baz": 2} - ] - }, - "cases": [ - { - "expression": "foo[?bar==`1`].bar[0]", - "result": [] - } - ] - }, - { - "given": { - "foo": [ - {"a": 1, "b": {"c": "x"}}, - {"a": 1, "b": {"c": "y"}}, - {"a": 1, "b": {"c": "z"}}, - {"a": 2, "b": {"c": "z"}}, - {"a": 1, "baz": 2} - ] - }, - "cases": [ - { - "expression": "foo[?a==`1`].b.c", - "result": ["x", "y", "z"] - } - ] - }, - { - "given": {"foo": [{"name": "a"}, {"name": "b"}, {"name": "c"}]}, - "cases": [ - { - "comment": "Filter with or expression", - "expression": "foo[?name == 'a' || name == 'b']", - "result": [{"name": "a"}, {"name": "b"}] - }, - { - "expression": "foo[?name == 'a' || name == 'e']", - "result": [{"name": "a"}] - }, - { - "expression": "foo[?name == 'a' || name == 'b' || name == 'c']", - "result": [{"name": "a"}, {"name": "b"}, {"name": "c"}] - } - ] - }, - { - "given": {"foo": [{"a": 1, "b": 2}, {"a": 1, "b": 3}]}, - "cases": [ - { - "comment": "Filter with and expression", - "expression": "foo[?a == `1` && b == `2`]", - "result": [{"a": 1, "b": 2}] - }, - { - "expression": "foo[?a == `1` && b == `4`]", - "result": [] - } - ] - }, - { - "given": {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}, - "cases": [ - { - "comment": "Filter with Or and And expressions", - "expression": "foo[?c == `3` || a == `1` && b == `4`]", - "result": [{"a": 1, "b": 2, "c": 3}] - }, - { - "expression": "foo[?b == `2` || a == `3` && b == `4`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?a == `3` && b == `4` || b == `2`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?(a == `3` && b == `4`) || b == `2`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?((a == `3` && b == `4`)) || b == `2`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?a == `3` && (b == `4` || b == `2`)]", - "result": [{"a": 3, "b": 4}] - }, - { - "expression": "foo[?a == `3` && ((b == `4` || b == `2`))]", - "result": [{"a": 3, "b": 4}] - } - ] - }, - { - "given": {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}, - "cases": [ - { - "comment": "Verify precedence of or/and expressions", - "expression": "foo[?a == `1` || b ==`2` && c == `5`]", - "result": [{"a": 1, "b": 2, "c": 3}] - }, - { - "comment": "Parentheses can alter precedence", - "expression": "foo[?(a == `1` || b ==`2`) && c == `5`]", - "result": [] - }, - { - "comment": "Not expressions combined with and/or", - "expression": "foo[?!(a == `1` || b ==`2`)]", - "result": [{"a": 3, "b": 4}] - } - ] - }, - { - "given": { - "foo": [ - {"key": true}, - {"key": false}, - {"key": []}, - {"key": {}}, - {"key": [0]}, - {"key": {"a": "b"}}, - {"key": 0}, - {"key": 1}, - {"key": null}, - {"notkey": true} - ] - }, - "cases": [ - { - "comment": "Unary filter expression", - "expression": "foo[?key]", - "result": [ - {"key": true}, {"key": [0]}, {"key": {"a": "b"}}, - {"key": 0}, {"key": 1} - ] - }, - { - "comment": "Unary not filter expression", - "expression": "foo[?!key]", - "result": [ - {"key": false}, {"key": []}, {"key": {}}, - {"key": null}, {"notkey": true} - ] - }, - { - "comment": "Equality with null RHS", - "expression": "foo[?key == `null`]", - "result": [ - {"key": null}, {"notkey": true} - ] - } - ] - }, - { - "given": { - "foo": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - "cases": [ - { - "comment": "Using @ in a filter expression", - "expression": "foo[?@ < `5`]", - "result": [0, 1, 2, 3, 4] - }, - { - "comment": "Using @ in a filter expression", - "expression": "foo[?`5` > @]", - "result": [0, 1, 2, 3, 4] - }, - { - "comment": "Using @ in a filter expression", - "expression": "foo[?@ == @]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/functions.json b/vendor/github.com/jmespath/go-jmespath/compliance/functions.json deleted file mode 100644 index 8b8db363a2b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/functions.json +++ /dev/null @@ -1,825 +0,0 @@ -[{ - "given": - { - "foo": -1, - "zero": 0, - "numbers": [-1, 3, 4, 5], - "array": [-1, 3, 4, 5, "a", "100"], - "strings": ["a", "b", "c"], - "decimals": [1.01, 1.2, -1.5], - "str": "Str", - "false": false, - "empty_list": [], - "empty_hash": {}, - "objects": {"foo": "bar", "bar": "baz"}, - "null_key": null - }, - "cases": [ - { - "expression": "abs(foo)", - "result": 1 - }, - { - "expression": "abs(foo)", - "result": 1 - }, - { - "expression": "abs(str)", - "error": "invalid-type" - }, - { - "expression": "abs(array[1])", - "result": 3 - }, - { - "expression": "abs(array[1])", - "result": 3 - }, - { - "expression": "abs(`false`)", - "error": "invalid-type" - }, - { - "expression": "abs(`-24`)", - "result": 24 - }, - { - "expression": "abs(`-24`)", - "result": 24 - }, - { - "expression": "abs(`1`, `2`)", - "error": "invalid-arity" - }, - { - "expression": "abs()", - "error": "invalid-arity" - }, - { - "expression": "unknown_function(`1`, `2`)", - "error": "unknown-function" - }, - { - "expression": "avg(numbers)", - "result": 2.75 - }, - { - "expression": "avg(array)", - "error": "invalid-type" - }, - { - "expression": "avg('abc')", - "error": "invalid-type" - }, - { - "expression": "avg(foo)", - "error": "invalid-type" - }, - { - "expression": "avg(@)", - "error": "invalid-type" - }, - { - "expression": "avg(strings)", - "error": "invalid-type" - }, - { - "expression": "ceil(`1.2`)", - "result": 2 - }, - { - "expression": "ceil(decimals[0])", - "result": 2 - }, - { - "expression": "ceil(decimals[1])", - "result": 2 - }, - { - "expression": "ceil(decimals[2])", - "result": -1 - }, - { - "expression": "ceil('string')", - "error": "invalid-type" - }, - { - "expression": "contains('abc', 'a')", - "result": true - }, - { - "expression": "contains('abc', 'd')", - "result": false - }, - { - "expression": "contains(`false`, 'd')", - "error": "invalid-type" - }, - { - "expression": "contains(strings, 'a')", - "result": true - }, - { - "expression": "contains(decimals, `1.2`)", - "result": true - }, - { - "expression": "contains(decimals, `false`)", - "result": false - }, - { - "expression": "ends_with(str, 'r')", - "result": true - }, - { - "expression": "ends_with(str, 'tr')", - "result": true - }, - { - "expression": "ends_with(str, 'Str')", - "result": true - }, - { - "expression": "ends_with(str, 'SStr')", - "result": false - }, - { - "expression": "ends_with(str, 'foo')", - "result": false - }, - { - "expression": "ends_with(str, `0`)", - "error": "invalid-type" - }, - { - "expression": "floor(`1.2`)", - "result": 1 - }, - { - "expression": "floor('string')", - "error": "invalid-type" - }, - { - "expression": "floor(decimals[0])", - "result": 1 - }, - { - "expression": "floor(foo)", - "result": -1 - }, - { - "expression": "floor(str)", - "error": "invalid-type" - }, - { - "expression": "length('abc')", - "result": 3 - }, - { - "expression": "length('✓foo')", - "result": 4 - }, - { - "expression": "length('')", - "result": 0 - }, - { - "expression": "length(@)", - "result": 12 - }, - { - "expression": "length(strings[0])", - "result": 1 - }, - { - "expression": "length(str)", - "result": 3 - }, - { - "expression": "length(array)", - "result": 6 - }, - { - "expression": "length(objects)", - "result": 2 - }, - { - "expression": "length(`false`)", - "error": "invalid-type" - }, - { - "expression": "length(foo)", - "error": "invalid-type" - }, - { - "expression": "length(strings[0])", - "result": 1 - }, - { - "expression": "max(numbers)", - "result": 5 - }, - { - "expression": "max(decimals)", - "result": 1.2 - }, - { - "expression": "max(strings)", - "result": "c" - }, - { - "expression": "max(abc)", - "error": "invalid-type" - }, - { - "expression": "max(array)", - "error": "invalid-type" - }, - { - "expression": "max(decimals)", - "result": 1.2 - }, - { - "expression": "max(empty_list)", - "result": null - }, - { - "expression": "merge(`{}`)", - "result": {} - }, - { - "expression": "merge(`{}`, `{}`)", - "result": {} - }, - { - "expression": "merge(`{\"a\": 1}`, `{\"b\": 2}`)", - "result": {"a": 1, "b": 2} - }, - { - "expression": "merge(`{\"a\": 1}`, `{\"a\": 2}`)", - "result": {"a": 2} - }, - { - "expression": "merge(`{\"a\": 1, \"b\": 2}`, `{\"a\": 2, \"c\": 3}`, `{\"d\": 4}`)", - "result": {"a": 2, "b": 2, "c": 3, "d": 4} - }, - { - "expression": "min(numbers)", - "result": -1 - }, - { - "expression": "min(decimals)", - "result": -1.5 - }, - { - "expression": "min(abc)", - "error": "invalid-type" - }, - { - "expression": "min(array)", - "error": "invalid-type" - }, - { - "expression": "min(empty_list)", - "result": null - }, - { - "expression": "min(decimals)", - "result": -1.5 - }, - { - "expression": "min(strings)", - "result": "a" - }, - { - "expression": "type('abc')", - "result": "string" - }, - { - "expression": "type(`1.0`)", - "result": "number" - }, - { - "expression": "type(`2`)", - "result": "number" - }, - { - "expression": "type(`true`)", - "result": "boolean" - }, - { - "expression": "type(`false`)", - "result": "boolean" - }, - { - "expression": "type(`null`)", - "result": "null" - }, - { - "expression": "type(`[0]`)", - "result": "array" - }, - { - "expression": "type(`{\"a\": \"b\"}`)", - "result": "object" - }, - { - "expression": "type(@)", - "result": "object" - }, - { - "expression": "sort(keys(objects))", - "result": ["bar", "foo"] - }, - { - "expression": "keys(foo)", - "error": "invalid-type" - }, - { - "expression": "keys(strings)", - "error": "invalid-type" - }, - { - "expression": "keys(`false`)", - "error": "invalid-type" - }, - { - "expression": "sort(values(objects))", - "result": ["bar", "baz"] - }, - { - "expression": "keys(empty_hash)", - "result": [] - }, - { - "expression": "values(foo)", - "error": "invalid-type" - }, - { - "expression": "join(', ', strings)", - "result": "a, b, c" - }, - { - "expression": "join(', ', strings)", - "result": "a, b, c" - }, - { - "expression": "join(',', `[\"a\", \"b\"]`)", - "result": "a,b" - }, - { - "expression": "join(',', `[\"a\", 0]`)", - "error": "invalid-type" - }, - { - "expression": "join(', ', str)", - "error": "invalid-type" - }, - { - "expression": "join('|', strings)", - "result": "a|b|c" - }, - { - "expression": "join(`2`, strings)", - "error": "invalid-type" - }, - { - "expression": "join('|', decimals)", - "error": "invalid-type" - }, - { - "expression": "join('|', decimals[].to_string(@))", - "result": "1.01|1.2|-1.5" - }, - { - "expression": "join('|', empty_list)", - "result": "" - }, - { - "expression": "reverse(numbers)", - "result": [5, 4, 3, -1] - }, - { - "expression": "reverse(array)", - "result": ["100", "a", 5, 4, 3, -1] - }, - { - "expression": "reverse(`[]`)", - "result": [] - }, - { - "expression": "reverse('')", - "result": "" - }, - { - "expression": "reverse('hello world')", - "result": "dlrow olleh" - }, - { - "expression": "starts_with(str, 'S')", - "result": true - }, - { - "expression": "starts_with(str, 'St')", - "result": true - }, - { - "expression": "starts_with(str, 'Str')", - "result": true - }, - { - "expression": "starts_with(str, 'String')", - "result": false - }, - { - "expression": "starts_with(str, `0`)", - "error": "invalid-type" - }, - { - "expression": "sum(numbers)", - "result": 11 - }, - { - "expression": "sum(decimals)", - "result": 0.71 - }, - { - "expression": "sum(array)", - "error": "invalid-type" - }, - { - "expression": "sum(array[].to_number(@))", - "result": 111 - }, - { - "expression": "sum(`[]`)", - "result": 0 - }, - { - "expression": "to_array('foo')", - "result": ["foo"] - }, - { - "expression": "to_array(`0`)", - "result": [0] - }, - { - "expression": "to_array(objects)", - "result": [{"foo": "bar", "bar": "baz"}] - }, - { - "expression": "to_array(`[1, 2, 3]`)", - "result": [1, 2, 3] - }, - { - "expression": "to_array(false)", - "result": [false] - }, - { - "expression": "to_string('foo')", - "result": "foo" - }, - { - "expression": "to_string(`1.2`)", - "result": "1.2" - }, - { - "expression": "to_string(`[0, 1]`)", - "result": "[0,1]" - }, - { - "expression": "to_number('1.0')", - "result": 1.0 - }, - { - "expression": "to_number('1.1')", - "result": 1.1 - }, - { - "expression": "to_number('4')", - "result": 4 - }, - { - "expression": "to_number('notanumber')", - "result": null - }, - { - "expression": "to_number(`false`)", - "result": null - }, - { - "expression": "to_number(`null`)", - "result": null - }, - { - "expression": "to_number(`[0]`)", - "result": null - }, - { - "expression": "to_number(`{\"foo\": 0}`)", - "result": null - }, - { - "expression": "\"to_string\"(`1.0`)", - "error": "syntax" - }, - { - "expression": "sort(numbers)", - "result": [-1, 3, 4, 5] - }, - { - "expression": "sort(strings)", - "result": ["a", "b", "c"] - }, - { - "expression": "sort(decimals)", - "result": [-1.5, 1.01, 1.2] - }, - { - "expression": "sort(array)", - "error": "invalid-type" - }, - { - "expression": "sort(abc)", - "error": "invalid-type" - }, - { - "expression": "sort(empty_list)", - "result": [] - }, - { - "expression": "sort(@)", - "error": "invalid-type" - }, - { - "expression": "not_null(unknown_key, str)", - "result": "Str" - }, - { - "expression": "not_null(unknown_key, foo.bar, empty_list, str)", - "result": [] - }, - { - "expression": "not_null(unknown_key, null_key, empty_list, str)", - "result": [] - }, - { - "expression": "not_null(all, expressions, are_null)", - "result": null - }, - { - "expression": "not_null()", - "error": "invalid-arity" - }, - { - "description": "function projection on single arg function", - "expression": "numbers[].to_string(@)", - "result": ["-1", "3", "4", "5"] - }, - { - "description": "function projection on single arg function", - "expression": "array[].to_number(@)", - "result": [-1, 3, 4, 5, 100] - } - ] -}, { - "given": - { - "foo": [ - {"b": "b", "a": "a"}, - {"c": "c", "b": "b"}, - {"d": "d", "c": "c"}, - {"e": "e", "d": "d"}, - {"f": "f", "e": "e"} - ] - }, - "cases": [ - { - "description": "function projection on variadic function", - "expression": "foo[].not_null(f, e, d, c, b, a)", - "result": ["b", "c", "d", "e", "f"] - } - ] -}, { - "given": - { - "people": [ - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"}, - {"age": 10, "age_str": "10", "bool": true, "name": 3} - ] - }, - "cases": [ - { - "description": "sort by field expression", - "expression": "sort_by(people, &age)", - "result": [ - {"age": 10, "age_str": "10", "bool": true, "name": 3}, - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"} - ] - }, - { - "expression": "sort_by(people, &age_str)", - "result": [ - {"age": 10, "age_str": "10", "bool": true, "name": 3}, - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"} - ] - }, - { - "description": "sort by function expression", - "expression": "sort_by(people, &to_number(age_str))", - "result": [ - {"age": 10, "age_str": "10", "bool": true, "name": 3}, - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"} - ] - }, - { - "description": "function projection on sort_by function", - "expression": "sort_by(people, &age)[].name", - "result": [3, "a", "c", "b", "d"] - }, - { - "expression": "sort_by(people, &extra)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, &bool)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, &name)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, name)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, &age)[].extra", - "result": ["foo", "bar"] - }, - { - "expression": "sort_by(`[]`, &age)", - "result": [] - }, - { - "expression": "max_by(people, &age)", - "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} - }, - { - "expression": "max_by(people, &age_str)", - "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} - }, - { - "expression": "max_by(people, &bool)", - "error": "invalid-type" - }, - { - "expression": "max_by(people, &extra)", - "error": "invalid-type" - }, - { - "expression": "max_by(people, &to_number(age_str))", - "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} - }, - { - "expression": "min_by(people, &age)", - "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} - }, - { - "expression": "min_by(people, &age_str)", - "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} - }, - { - "expression": "min_by(people, &bool)", - "error": "invalid-type" - }, - { - "expression": "min_by(people, &extra)", - "error": "invalid-type" - }, - { - "expression": "min_by(people, &to_number(age_str))", - "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} - } - ] -}, { - "given": - { - "people": [ - {"age": 10, "order": "1"}, - {"age": 10, "order": "2"}, - {"age": 10, "order": "3"}, - {"age": 10, "order": "4"}, - {"age": 10, "order": "5"}, - {"age": 10, "order": "6"}, - {"age": 10, "order": "7"}, - {"age": 10, "order": "8"}, - {"age": 10, "order": "9"}, - {"age": 10, "order": "10"}, - {"age": 10, "order": "11"} - ] - }, - "cases": [ - { - "description": "stable sort order", - "expression": "sort_by(people, &age)", - "result": [ - {"age": 10, "order": "1"}, - {"age": 10, "order": "2"}, - {"age": 10, "order": "3"}, - {"age": 10, "order": "4"}, - {"age": 10, "order": "5"}, - {"age": 10, "order": "6"}, - {"age": 10, "order": "7"}, - {"age": 10, "order": "8"}, - {"age": 10, "order": "9"}, - {"age": 10, "order": "10"}, - {"age": 10, "order": "11"} - ] - } - ] -}, { - "given": - { - "people": [ - {"a": 10, "b": 1, "c": "z"}, - {"a": 10, "b": 2, "c": null}, - {"a": 10, "b": 3}, - {"a": 10, "b": 4, "c": "z"}, - {"a": 10, "b": 5, "c": null}, - {"a": 10, "b": 6}, - {"a": 10, "b": 7, "c": "z"}, - {"a": 10, "b": 8, "c": null}, - {"a": 10, "b": 9} - ], - "empty": [] - }, - "cases": [ - { - "expression": "map(&a, people)", - "result": [10, 10, 10, 10, 10, 10, 10, 10, 10] - }, - { - "expression": "map(&c, people)", - "result": ["z", null, null, "z", null, null, "z", null, null] - }, - { - "expression": "map(&a, badkey)", - "error": "invalid-type" - }, - { - "expression": "map(&foo, empty)", - "result": [] - } - ] -}, { - "given": { - "array": [ - { - "foo": {"bar": "yes1"} - }, - { - "foo": {"bar": "yes2"} - }, - { - "foo1": {"bar": "no"} - } - ]}, - "cases": [ - { - "expression": "map(&foo.bar, array)", - "result": ["yes1", "yes2", null] - }, - { - "expression": "map(&foo1.bar, array)", - "result": [null, null, "no"] - }, - { - "expression": "map(&foo.bar.baz, array)", - "result": [null, null, null] - } - ] -}, { - "given": { - "array": [[1, 2, 3, [4]], [5, 6, 7, [8, 9]]] - }, - "cases": [ - { - "expression": "map(&[], array)", - "result": [[1, 2, 3, 4], [5, 6, 7, 8, 9]] - } - ] -} -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/identifiers.json b/vendor/github.com/jmespath/go-jmespath/compliance/identifiers.json deleted file mode 100644 index 7998a41ac9d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/identifiers.json +++ /dev/null @@ -1,1377 +0,0 @@ -[ - { - "given": { - "__L": true - }, - "cases": [ - { - "expression": "__L", - "result": true - } - ] - }, - { - "given": { - "!\r": true - }, - "cases": [ - { - "expression": "\"!\\r\"", - "result": true - } - ] - }, - { - "given": { - "Y_1623": true - }, - "cases": [ - { - "expression": "Y_1623", - "result": true - } - ] - }, - { - "given": { - "x": true - }, - "cases": [ - { - "expression": "x", - "result": true - } - ] - }, - { - "given": { - "\tF\uCebb": true - }, - "cases": [ - { - "expression": "\"\\tF\\uCebb\"", - "result": true - } - ] - }, - { - "given": { - " \t": true - }, - "cases": [ - { - "expression": "\" \\t\"", - "result": true - } - ] - }, - { - "given": { - " ": true - }, - "cases": [ - { - "expression": "\" \"", - "result": true - } - ] - }, - { - "given": { - "v2": true - }, - "cases": [ - { - "expression": "v2", - "result": true - } - ] - }, - { - "given": { - "\t": true - }, - "cases": [ - { - "expression": "\"\\t\"", - "result": true - } - ] - }, - { - "given": { - "_X": true - }, - "cases": [ - { - "expression": "_X", - "result": true - } - ] - }, - { - "given": { - "\t4\ud9da\udd15": true - }, - "cases": [ - { - "expression": "\"\\t4\\ud9da\\udd15\"", - "result": true - } - ] - }, - { - "given": { - "v24_W": true - }, - "cases": [ - { - "expression": "v24_W", - "result": true - } - ] - }, - { - "given": { - "H": true - }, - "cases": [ - { - "expression": "\"H\"", - "result": true - } - ] - }, - { - "given": { - "\f": true - }, - "cases": [ - { - "expression": "\"\\f\"", - "result": true - } - ] - }, - { - "given": { - "E4": true - }, - "cases": [ - { - "expression": "\"E4\"", - "result": true - } - ] - }, - { - "given": { - "!": true - }, - "cases": [ - { - "expression": "\"!\"", - "result": true - } - ] - }, - { - "given": { - "tM": true - }, - "cases": [ - { - "expression": "tM", - "result": true - } - ] - }, - { - "given": { - " [": true - }, - "cases": [ - { - "expression": "\" [\"", - "result": true - } - ] - }, - { - "given": { - "R!": true - }, - "cases": [ - { - "expression": "\"R!\"", - "result": true - } - ] - }, - { - "given": { - "_6W": true - }, - "cases": [ - { - "expression": "_6W", - "result": true - } - ] - }, - { - "given": { - "\uaBA1\r": true - }, - "cases": [ - { - "expression": "\"\\uaBA1\\r\"", - "result": true - } - ] - }, - { - "given": { - "tL7": true - }, - "cases": [ - { - "expression": "tL7", - "result": true - } - ] - }, - { - "given": { - "<": true - }, - "cases": [ - { - "expression": "\">\"", - "result": true - } - ] - }, - { - "given": { - "hvu": true - }, - "cases": [ - { - "expression": "hvu", - "result": true - } - ] - }, - { - "given": { - "; !": true - }, - "cases": [ - { - "expression": "\"; !\"", - "result": true - } - ] - }, - { - "given": { - "hU": true - }, - "cases": [ - { - "expression": "hU", - "result": true - } - ] - }, - { - "given": { - "!I\n\/": true - }, - "cases": [ - { - "expression": "\"!I\\n\\/\"", - "result": true - } - ] - }, - { - "given": { - "\uEEbF": true - }, - "cases": [ - { - "expression": "\"\\uEEbF\"", - "result": true - } - ] - }, - { - "given": { - "U)\t": true - }, - "cases": [ - { - "expression": "\"U)\\t\"", - "result": true - } - ] - }, - { - "given": { - "fa0_9": true - }, - "cases": [ - { - "expression": "fa0_9", - "result": true - } - ] - }, - { - "given": { - "/": true - }, - "cases": [ - { - "expression": "\"/\"", - "result": true - } - ] - }, - { - "given": { - "Gy": true - }, - "cases": [ - { - "expression": "Gy", - "result": true - } - ] - }, - { - "given": { - "\b": true - }, - "cases": [ - { - "expression": "\"\\b\"", - "result": true - } - ] - }, - { - "given": { - "<": true - }, - "cases": [ - { - "expression": "\"<\"", - "result": true - } - ] - }, - { - "given": { - "\t": true - }, - "cases": [ - { - "expression": "\"\\t\"", - "result": true - } - ] - }, - { - "given": { - "\t&\\\r": true - }, - "cases": [ - { - "expression": "\"\\t&\\\\\\r\"", - "result": true - } - ] - }, - { - "given": { - "#": true - }, - "cases": [ - { - "expression": "\"#\"", - "result": true - } - ] - }, - { - "given": { - "B__": true - }, - "cases": [ - { - "expression": "B__", - "result": true - } - ] - }, - { - "given": { - "\nS \n": true - }, - "cases": [ - { - "expression": "\"\\nS \\n\"", - "result": true - } - ] - }, - { - "given": { - "Bp": true - }, - "cases": [ - { - "expression": "Bp", - "result": true - } - ] - }, - { - "given": { - ",\t;": true - }, - "cases": [ - { - "expression": "\",\\t;\"", - "result": true - } - ] - }, - { - "given": { - "B_q": true - }, - "cases": [ - { - "expression": "B_q", - "result": true - } - ] - }, - { - "given": { - "\/+\t\n\b!Z": true - }, - "cases": [ - { - "expression": "\"\\/+\\t\\n\\b!Z\"", - "result": true - } - ] - }, - { - "given": { - "\udadd\udfc7\\ueFAc": true - }, - "cases": [ - { - "expression": "\"\udadd\udfc7\\\\ueFAc\"", - "result": true - } - ] - }, - { - "given": { - ":\f": true - }, - "cases": [ - { - "expression": "\":\\f\"", - "result": true - } - ] - }, - { - "given": { - "\/": true - }, - "cases": [ - { - "expression": "\"\\/\"", - "result": true - } - ] - }, - { - "given": { - "_BW_6Hg_Gl": true - }, - "cases": [ - { - "expression": "_BW_6Hg_Gl", - "result": true - } - ] - }, - { - "given": { - "\udbcf\udc02": true - }, - "cases": [ - { - "expression": "\"\udbcf\udc02\"", - "result": true - } - ] - }, - { - "given": { - "zs1DC": true - }, - "cases": [ - { - "expression": "zs1DC", - "result": true - } - ] - }, - { - "given": { - "__434": true - }, - "cases": [ - { - "expression": "__434", - "result": true - } - ] - }, - { - "given": { - "\udb94\udd41": true - }, - "cases": [ - { - "expression": "\"\udb94\udd41\"", - "result": true - } - ] - }, - { - "given": { - "Z_5": true - }, - "cases": [ - { - "expression": "Z_5", - "result": true - } - ] - }, - { - "given": { - "z_M_": true - }, - "cases": [ - { - "expression": "z_M_", - "result": true - } - ] - }, - { - "given": { - "YU_2": true - }, - "cases": [ - { - "expression": "YU_2", - "result": true - } - ] - }, - { - "given": { - "_0": true - }, - "cases": [ - { - "expression": "_0", - "result": true - } - ] - }, - { - "given": { - "\b+": true - }, - "cases": [ - { - "expression": "\"\\b+\"", - "result": true - } - ] - }, - { - "given": { - "\"": true - }, - "cases": [ - { - "expression": "\"\\\"\"", - "result": true - } - ] - }, - { - "given": { - "D7": true - }, - "cases": [ - { - "expression": "D7", - "result": true - } - ] - }, - { - "given": { - "_62L": true - }, - "cases": [ - { - "expression": "_62L", - "result": true - } - ] - }, - { - "given": { - "\tK\t": true - }, - "cases": [ - { - "expression": "\"\\tK\\t\"", - "result": true - } - ] - }, - { - "given": { - "\n\\\f": true - }, - "cases": [ - { - "expression": "\"\\n\\\\\\f\"", - "result": true - } - ] - }, - { - "given": { - "I_": true - }, - "cases": [ - { - "expression": "I_", - "result": true - } - ] - }, - { - "given": { - "W_a0_": true - }, - "cases": [ - { - "expression": "W_a0_", - "result": true - } - ] - }, - { - "given": { - "BQ": true - }, - "cases": [ - { - "expression": "BQ", - "result": true - } - ] - }, - { - "given": { - "\tX$\uABBb": true - }, - "cases": [ - { - "expression": "\"\\tX$\\uABBb\"", - "result": true - } - ] - }, - { - "given": { - "Z9": true - }, - "cases": [ - { - "expression": "Z9", - "result": true - } - ] - }, - { - "given": { - "\b%\"\uda38\udd0f": true - }, - "cases": [ - { - "expression": "\"\\b%\\\"\uda38\udd0f\"", - "result": true - } - ] - }, - { - "given": { - "_F": true - }, - "cases": [ - { - "expression": "_F", - "result": true - } - ] - }, - { - "given": { - "!,": true - }, - "cases": [ - { - "expression": "\"!,\"", - "result": true - } - ] - }, - { - "given": { - "\"!": true - }, - "cases": [ - { - "expression": "\"\\\"!\"", - "result": true - } - ] - }, - { - "given": { - "Hh": true - }, - "cases": [ - { - "expression": "Hh", - "result": true - } - ] - }, - { - "given": { - "&": true - }, - "cases": [ - { - "expression": "\"&\"", - "result": true - } - ] - }, - { - "given": { - "9\r\\R": true - }, - "cases": [ - { - "expression": "\"9\\r\\\\R\"", - "result": true - } - ] - }, - { - "given": { - "M_k": true - }, - "cases": [ - { - "expression": "M_k", - "result": true - } - ] - }, - { - "given": { - "!\b\n\udb06\ude52\"\"": true - }, - "cases": [ - { - "expression": "\"!\\b\\n\udb06\ude52\\\"\\\"\"", - "result": true - } - ] - }, - { - "given": { - "6": true - }, - "cases": [ - { - "expression": "\"6\"", - "result": true - } - ] - }, - { - "given": { - "_7": true - }, - "cases": [ - { - "expression": "_7", - "result": true - } - ] - }, - { - "given": { - "0": true - }, - "cases": [ - { - "expression": "\"0\"", - "result": true - } - ] - }, - { - "given": { - "\\8\\": true - }, - "cases": [ - { - "expression": "\"\\\\8\\\\\"", - "result": true - } - ] - }, - { - "given": { - "b7eo": true - }, - "cases": [ - { - "expression": "b7eo", - "result": true - } - ] - }, - { - "given": { - "xIUo9": true - }, - "cases": [ - { - "expression": "xIUo9", - "result": true - } - ] - }, - { - "given": { - "5": true - }, - "cases": [ - { - "expression": "\"5\"", - "result": true - } - ] - }, - { - "given": { - "?": true - }, - "cases": [ - { - "expression": "\"?\"", - "result": true - } - ] - }, - { - "given": { - "sU": true - }, - "cases": [ - { - "expression": "sU", - "result": true - } - ] - }, - { - "given": { - "VH2&H\\\/": true - }, - "cases": [ - { - "expression": "\"VH2&H\\\\\\/\"", - "result": true - } - ] - }, - { - "given": { - "_C": true - }, - "cases": [ - { - "expression": "_C", - "result": true - } - ] - }, - { - "given": { - "_": true - }, - "cases": [ - { - "expression": "_", - "result": true - } - ] - }, - { - "given": { - "<\t": true - }, - "cases": [ - { - "expression": "\"<\\t\"", - "result": true - } - ] - }, - { - "given": { - "\uD834\uDD1E": true - }, - "cases": [ - { - "expression": "\"\\uD834\\uDD1E\"", - "result": true - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/indices.json b/vendor/github.com/jmespath/go-jmespath/compliance/indices.json deleted file mode 100644 index aa03b35dd7f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/indices.json +++ /dev/null @@ -1,346 +0,0 @@ -[{ - "given": - {"foo": {"bar": ["zero", "one", "two"]}}, - "cases": [ - { - "expression": "foo.bar[0]", - "result": "zero" - }, - { - "expression": "foo.bar[1]", - "result": "one" - }, - { - "expression": "foo.bar[2]", - "result": "two" - }, - { - "expression": "foo.bar[3]", - "result": null - }, - { - "expression": "foo.bar[-1]", - "result": "two" - }, - { - "expression": "foo.bar[-2]", - "result": "one" - }, - { - "expression": "foo.bar[-3]", - "result": "zero" - }, - { - "expression": "foo.bar[-4]", - "result": null - } - ] -}, -{ - "given": - {"foo": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}]}, - "cases": [ - { - "expression": "foo.bar", - "result": null - }, - { - "expression": "foo[0].bar", - "result": "one" - }, - { - "expression": "foo[1].bar", - "result": "two" - }, - { - "expression": "foo[2].bar", - "result": "three" - }, - { - "expression": "foo[3].notbar", - "result": "four" - }, - { - "expression": "foo[3].bar", - "result": null - }, - { - "expression": "foo[0]", - "result": {"bar": "one"} - }, - { - "expression": "foo[1]", - "result": {"bar": "two"} - }, - { - "expression": "foo[2]", - "result": {"bar": "three"} - }, - { - "expression": "foo[3]", - "result": {"notbar": "four"} - }, - { - "expression": "foo[4]", - "result": null - } - ] -}, -{ - "given": [ - "one", "two", "three" - ], - "cases": [ - { - "expression": "[0]", - "result": "one" - }, - { - "expression": "[1]", - "result": "two" - }, - { - "expression": "[2]", - "result": "three" - }, - { - "expression": "[-1]", - "result": "three" - }, - { - "expression": "[-2]", - "result": "two" - }, - { - "expression": "[-3]", - "result": "one" - } - ] -}, -{ - "given": {"reservations": [ - {"instances": [{"foo": 1}, {"foo": 2}]} - ]}, - "cases": [ - { - "expression": "reservations[].instances[].foo", - "result": [1, 2] - }, - { - "expression": "reservations[].instances[].bar", - "result": [] - }, - { - "expression": "reservations[].notinstances[].foo", - "result": [] - }, - { - "expression": "reservations[].notinstances[].foo", - "result": [] - } - ] -}, -{ - "given": {"reservations": [{ - "instances": [ - {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]}, - {"foo": [{"bar": 5}, {"bar": 6}, {"notbar": [7]}, {"bar": 8}]}, - {"foo": "bar"}, - {"notfoo": [{"bar": 20}, {"bar": 21}, {"notbar": [7]}, {"bar": 22}]}, - {"bar": [{"baz": [1]}, {"baz": [2]}, {"baz": [3]}, {"baz": [4]}]}, - {"baz": [{"baz": [1, 2]}, {"baz": []}, {"baz": []}, {"baz": [3, 4]}]}, - {"qux": [{"baz": []}, {"baz": [1, 2, 3]}, {"baz": [4]}, {"baz": []}]} - ], - "otherkey": {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]} - }, { - "instances": [ - {"a": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]}, - {"b": [{"bar": 5}, {"bar": 6}, {"notbar": [7]}, {"bar": 8}]}, - {"c": "bar"}, - {"notfoo": [{"bar": 23}, {"bar": 24}, {"notbar": [7]}, {"bar": 25}]}, - {"qux": [{"baz": []}, {"baz": [1, 2, 3]}, {"baz": [4]}, {"baz": []}]} - ], - "otherkey": {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]} - } - ]}, - "cases": [ - { - "expression": "reservations[].instances[].foo[].bar", - "result": [1, 2, 4, 5, 6, 8] - }, - { - "expression": "reservations[].instances[].foo[].baz", - "result": [] - }, - { - "expression": "reservations[].instances[].notfoo[].bar", - "result": [20, 21, 22, 23, 24, 25] - }, - { - "expression": "reservations[].instances[].notfoo[].notbar", - "result": [[7], [7]] - }, - { - "expression": "reservations[].notinstances[].foo", - "result": [] - }, - { - "expression": "reservations[].instances[].foo[].notbar", - "result": [3, [7]] - }, - { - "expression": "reservations[].instances[].bar[].baz", - "result": [[1], [2], [3], [4]] - }, - { - "expression": "reservations[].instances[].baz[].baz", - "result": [[1, 2], [], [], [3, 4]] - }, - { - "expression": "reservations[].instances[].qux[].baz", - "result": [[], [1, 2, 3], [4], [], [], [1, 2, 3], [4], []] - }, - { - "expression": "reservations[].instances[].qux[].baz[]", - "result": [1, 2, 3, 4, 1, 2, 3, 4] - } - ] -}, -{ - "given": { - "foo": [ - [["one", "two"], ["three", "four"]], - [["five", "six"], ["seven", "eight"]], - [["nine"], ["ten"]] - ] - }, - "cases": [ - { - "expression": "foo[]", - "result": [["one", "two"], ["three", "four"], ["five", "six"], - ["seven", "eight"], ["nine"], ["ten"]] - }, - { - "expression": "foo[][0]", - "result": ["one", "three", "five", "seven", "nine", "ten"] - }, - { - "expression": "foo[][1]", - "result": ["two", "four", "six", "eight"] - }, - { - "expression": "foo[][0][0]", - "result": [] - }, - { - "expression": "foo[][2][2]", - "result": [] - }, - { - "expression": "foo[][0][0][100]", - "result": [] - } - ] -}, -{ - "given": { - "foo": [{ - "bar": [ - { - "qux": 2, - "baz": 1 - }, - { - "qux": 4, - "baz": 3 - } - ] - }, - { - "bar": [ - { - "qux": 6, - "baz": 5 - }, - { - "qux": 8, - "baz": 7 - } - ] - } - ] - }, - "cases": [ - { - "expression": "foo", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[]", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[].bar", - "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], - [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] - }, - { - "expression": "foo[].bar[]", - "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, - {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] - }, - { - "expression": "foo[].bar[].baz", - "result": [1, 3, 5, 7] - } - ] -}, -{ - "given": { - "string": "string", - "hash": {"foo": "bar", "bar": "baz"}, - "number": 23, - "nullvalue": null - }, - "cases": [ - { - "expression": "string[]", - "result": null - }, - { - "expression": "hash[]", - "result": null - }, - { - "expression": "number[]", - "result": null - }, - { - "expression": "nullvalue[]", - "result": null - }, - { - "expression": "string[].foo", - "result": null - }, - { - "expression": "hash[].foo", - "result": null - }, - { - "expression": "number[].foo", - "result": null - }, - { - "expression": "nullvalue[].foo", - "result": null - }, - { - "expression": "nullvalue[].foo[].bar", - "result": null - } - ] -} -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/literal.json b/vendor/github.com/jmespath/go-jmespath/compliance/literal.json deleted file mode 100644 index c6706b97196..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/literal.json +++ /dev/null @@ -1,185 +0,0 @@ -[ - { - "given": { - "foo": [{"name": "a"}, {"name": "b"}], - "bar": {"baz": "qux"} - }, - "cases": [ - { - "expression": "`\"foo\"`", - "result": "foo" - }, - { - "comment": "Interpret escaped unicode.", - "expression": "`\"\\u03a6\"`", - "result": "Φ" - }, - { - "expression": "`\"✓\"`", - "result": "✓" - }, - { - "expression": "`[1, 2, 3]`", - "result": [1, 2, 3] - }, - { - "expression": "`{\"a\": \"b\"}`", - "result": {"a": "b"} - }, - { - "expression": "`true`", - "result": true - }, - { - "expression": "`false`", - "result": false - }, - { - "expression": "`null`", - "result": null - }, - { - "expression": "`0`", - "result": 0 - }, - { - "expression": "`1`", - "result": 1 - }, - { - "expression": "`2`", - "result": 2 - }, - { - "expression": "`3`", - "result": 3 - }, - { - "expression": "`4`", - "result": 4 - }, - { - "expression": "`5`", - "result": 5 - }, - { - "expression": "`6`", - "result": 6 - }, - { - "expression": "`7`", - "result": 7 - }, - { - "expression": "`8`", - "result": 8 - }, - { - "expression": "`9`", - "result": 9 - }, - { - "comment": "Escaping a backtick in quotes", - "expression": "`\"foo\\`bar\"`", - "result": "foo`bar" - }, - { - "comment": "Double quote in literal", - "expression": "`\"foo\\\"bar\"`", - "result": "foo\"bar" - }, - { - "expression": "`\"1\\`\"`", - "result": "1`" - }, - { - "comment": "Multiple literal expressions with escapes", - "expression": "`\"\\\\\"`.{a:`\"b\"`}", - "result": {"a": "b"} - }, - { - "comment": "literal . identifier", - "expression": "`{\"a\": \"b\"}`.a", - "result": "b" - }, - { - "comment": "literal . identifier . identifier", - "expression": "`{\"a\": {\"b\": \"c\"}}`.a.b", - "result": "c" - }, - { - "comment": "literal . identifier bracket-expr", - "expression": "`[0, 1, 2]`[1]", - "result": 1 - } - ] - }, - { - "comment": "Literals", - "given": {"type": "object"}, - "cases": [ - { - "comment": "Literal with leading whitespace", - "expression": "` {\"foo\": true}`", - "result": {"foo": true} - }, - { - "comment": "Literal with trailing whitespace", - "expression": "`{\"foo\": true} `", - "result": {"foo": true} - }, - { - "comment": "Literal on RHS of subexpr not allowed", - "expression": "foo.`\"bar\"`", - "error": "syntax" - } - ] - }, - { - "comment": "Raw String Literals", - "given": {}, - "cases": [ - { - "expression": "'foo'", - "result": "foo" - }, - { - "expression": "' foo '", - "result": " foo " - }, - { - "expression": "'0'", - "result": "0" - }, - { - "expression": "'newline\n'", - "result": "newline\n" - }, - { - "expression": "'\n'", - "result": "\n" - }, - { - "expression": "'✓'", - "result": "✓" - }, - { - "expression": "'𝄞'", - "result": "𝄞" - }, - { - "expression": "' [foo] '", - "result": " [foo] " - }, - { - "expression": "'[foo]'", - "result": "[foo]" - }, - { - "comment": "Do not interpret escaped unicode.", - "expression": "'\\u03a6'", - "result": "\\u03a6" - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/multiselect.json b/vendor/github.com/jmespath/go-jmespath/compliance/multiselect.json deleted file mode 100644 index 8f2a481ed7c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/multiselect.json +++ /dev/null @@ -1,393 +0,0 @@ -[{ - "given": { - "foo": { - "bar": "bar", - "baz": "baz", - "qux": "qux", - "nested": { - "one": { - "a": "first", - "b": "second", - "c": "third" - }, - "two": { - "a": "first", - "b": "second", - "c": "third" - }, - "three": { - "a": "first", - "b": "second", - "c": {"inner": "third"} - } - } - }, - "bar": 1, - "baz": 2, - "qux\"": 3 - }, - "cases": [ - { - "expression": "foo.{bar: bar}", - "result": {"bar": "bar"} - }, - { - "expression": "foo.{\"bar\": bar}", - "result": {"bar": "bar"} - }, - { - "expression": "foo.{\"foo.bar\": bar}", - "result": {"foo.bar": "bar"} - }, - { - "expression": "foo.{bar: bar, baz: baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "foo.{\"bar\": bar, \"baz\": baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "{\"baz\": baz, \"qux\\\"\": \"qux\\\"\"}", - "result": {"baz": 2, "qux\"": 3} - }, - { - "expression": "foo.{bar:bar,baz:baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "foo.{bar: bar,qux: qux}", - "result": {"bar": "bar", "qux": "qux"} - }, - { - "expression": "foo.{bar: bar, noexist: noexist}", - "result": {"bar": "bar", "noexist": null} - }, - { - "expression": "foo.{noexist: noexist, alsonoexist: alsonoexist}", - "result": {"noexist": null, "alsonoexist": null} - }, - { - "expression": "foo.badkey.{nokey: nokey, alsonokey: alsonokey}", - "result": null - }, - { - "expression": "foo.nested.*.{a: a,b: b}", - "result": [{"a": "first", "b": "second"}, - {"a": "first", "b": "second"}, - {"a": "first", "b": "second"}] - }, - { - "expression": "foo.nested.three.{a: a, cinner: c.inner}", - "result": {"a": "first", "cinner": "third"} - }, - { - "expression": "foo.nested.three.{a: a, c: c.inner.bad.key}", - "result": {"a": "first", "c": null} - }, - { - "expression": "foo.{a: nested.one.a, b: nested.two.b}", - "result": {"a": "first", "b": "second"} - }, - { - "expression": "{bar: bar, baz: baz}", - "result": {"bar": 1, "baz": 2} - }, - { - "expression": "{bar: bar}", - "result": {"bar": 1} - }, - { - "expression": "{otherkey: bar}", - "result": {"otherkey": 1} - }, - { - "expression": "{no: no, exist: exist}", - "result": {"no": null, "exist": null} - }, - { - "expression": "foo.[bar]", - "result": ["bar"] - }, - { - "expression": "foo.[bar,baz]", - "result": ["bar", "baz"] - }, - { - "expression": "foo.[bar,qux]", - "result": ["bar", "qux"] - }, - { - "expression": "foo.[bar,noexist]", - "result": ["bar", null] - }, - { - "expression": "foo.[noexist,alsonoexist]", - "result": [null, null] - } - ] -}, { - "given": { - "foo": {"bar": 1, "baz": [2, 3, 4]} - }, - "cases": [ - { - "expression": "foo.{bar:bar,baz:baz}", - "result": {"bar": 1, "baz": [2, 3, 4]} - }, - { - "expression": "foo.[bar,baz[0]]", - "result": [1, 2] - }, - { - "expression": "foo.[bar,baz[1]]", - "result": [1, 3] - }, - { - "expression": "foo.[bar,baz[2]]", - "result": [1, 4] - }, - { - "expression": "foo.[bar,baz[3]]", - "result": [1, null] - }, - { - "expression": "foo.[bar[0],baz[3]]", - "result": [null, null] - } - ] -}, { - "given": { - "foo": {"bar": 1, "baz": 2} - }, - "cases": [ - { - "expression": "foo.{bar: bar, baz: baz}", - "result": {"bar": 1, "baz": 2} - }, - { - "expression": "foo.[bar,baz]", - "result": [1, 2] - } - ] -}, { - "given": { - "foo": { - "bar": {"baz": [{"common": "first", "one": 1}, - {"common": "second", "two": 2}]}, - "ignoreme": 1, - "includeme": true - } - }, - "cases": [ - { - "expression": "foo.{bar: bar.baz[1],includeme: includeme}", - "result": {"bar": {"common": "second", "two": 2}, "includeme": true} - }, - { - "expression": "foo.{\"bar.baz.two\": bar.baz[1].two, includeme: includeme}", - "result": {"bar.baz.two": 2, "includeme": true} - }, - { - "expression": "foo.[includeme, bar.baz[*].common]", - "result": [true, ["first", "second"]] - }, - { - "expression": "foo.[includeme, bar.baz[*].none]", - "result": [true, []] - }, - { - "expression": "foo.[includeme, bar.baz[].common]", - "result": [true, ["first", "second"]] - } - ] -}, { - "given": { - "reservations": [{ - "instances": [ - {"id": "id1", - "name": "first"}, - {"id": "id2", - "name": "second"} - ]}, { - "instances": [ - {"id": "id3", - "name": "third"}, - {"id": "id4", - "name": "fourth"} - ]} - ]}, - "cases": [ - { - "expression": "reservations[*].instances[*].{id: id, name: name}", - "result": [[{"id": "id1", "name": "first"}, {"id": "id2", "name": "second"}], - [{"id": "id3", "name": "third"}, {"id": "id4", "name": "fourth"}]] - }, - { - "expression": "reservations[].instances[].{id: id, name: name}", - "result": [{"id": "id1", "name": "first"}, - {"id": "id2", "name": "second"}, - {"id": "id3", "name": "third"}, - {"id": "id4", "name": "fourth"}] - }, - { - "expression": "reservations[].instances[].[id, name]", - "result": [["id1", "first"], - ["id2", "second"], - ["id3", "third"], - ["id4", "fourth"]] - } - ] -}, -{ - "given": { - "foo": [{ - "bar": [ - { - "qux": 2, - "baz": 1 - }, - { - "qux": 4, - "baz": 3 - } - ] - }, - { - "bar": [ - { - "qux": 6, - "baz": 5 - }, - { - "qux": 8, - "baz": 7 - } - ] - } - ] - }, - "cases": [ - { - "expression": "foo", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[]", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[].bar", - "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], - [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] - }, - { - "expression": "foo[].bar[]", - "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, - {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] - }, - { - "expression": "foo[].bar[].[baz, qux]", - "result": [[1, 2], [3, 4], [5, 6], [7, 8]] - }, - { - "expression": "foo[].bar[].[baz]", - "result": [[1], [3], [5], [7]] - }, - { - "expression": "foo[].bar[].[baz, qux][]", - "result": [1, 2, 3, 4, 5, 6, 7, 8] - } - ] -}, -{ - "given": { - "foo": { - "baz": [ - { - "bar": "abc" - }, { - "bar": "def" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].bar, qux[0]]", - "result": [["abc", "def"], "zero"] - } - ] -}, -{ - "given": { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].[bar, boo], qux[0]]", - "result": [[["a", "c" ], ["d", "f" ]], "zero"] - } - ] -}, -{ - "given": { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].not_there || baz[*].bar, qux[0]]", - "result": [["a", "d"], "zero"] - } - ] -}, -{ - "given": {"type": "object"}, - "cases": [ - { - "comment": "Nested multiselect", - "expression": "[[*],*]", - "result": [null, ["object"]] - } - ] -}, -{ - "given": [], - "cases": [ - { - "comment": "Nested multiselect", - "expression": "[[*]]", - "result": [[]] - } - ] -} -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/ormatch.json b/vendor/github.com/jmespath/go-jmespath/compliance/ormatch.json deleted file mode 100644 index 2127cf441ba..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/ormatch.json +++ /dev/null @@ -1,59 +0,0 @@ -[{ - "given": - {"outer": {"foo": "foo", "bar": "bar", "baz": "baz"}}, - "cases": [ - { - "expression": "outer.foo || outer.bar", - "result": "foo" - }, - { - "expression": "outer.foo||outer.bar", - "result": "foo" - }, - { - "expression": "outer.bar || outer.baz", - "result": "bar" - }, - { - "expression": "outer.bar||outer.baz", - "result": "bar" - }, - { - "expression": "outer.bad || outer.foo", - "result": "foo" - }, - { - "expression": "outer.bad||outer.foo", - "result": "foo" - }, - { - "expression": "outer.foo || outer.bad", - "result": "foo" - }, - { - "expression": "outer.foo||outer.bad", - "result": "foo" - }, - { - "expression": "outer.bad || outer.alsobad", - "result": null - }, - { - "expression": "outer.bad||outer.alsobad", - "result": null - } - ] -}, { - "given": - {"outer": {"foo": "foo", "bool": false, "empty_list": [], "empty_string": ""}}, - "cases": [ - { - "expression": "outer.empty_string || outer.foo", - "result": "foo" - }, - { - "expression": "outer.nokey || outer.bool || outer.empty_list || outer.empty_string || outer.foo", - "result": "foo" - } - ] -}] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/pipe.json b/vendor/github.com/jmespath/go-jmespath/compliance/pipe.json deleted file mode 100644 index b10c0a496d6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/pipe.json +++ /dev/null @@ -1,131 +0,0 @@ -[{ - "given": { - "foo": { - "bar": { - "baz": "subkey" - }, - "other": { - "baz": "subkey" - }, - "other2": { - "baz": "subkey" - }, - "other3": { - "notbaz": ["a", "b", "c"] - }, - "other4": { - "notbaz": ["a", "b", "c"] - } - } - }, - "cases": [ - { - "expression": "foo.*.baz | [0]", - "result": "subkey" - }, - { - "expression": "foo.*.baz | [1]", - "result": "subkey" - }, - { - "expression": "foo.*.baz | [2]", - "result": "subkey" - }, - { - "expression": "foo.bar.* | [0]", - "result": "subkey" - }, - { - "expression": "foo.*.notbaz | [*]", - "result": [["a", "b", "c"], ["a", "b", "c"]] - }, - { - "expression": "{\"a\": foo.bar, \"b\": foo.other} | *.baz", - "result": ["subkey", "subkey"] - } - ] -}, { - "given": { - "foo": { - "bar": { - "baz": "one" - }, - "other": { - "baz": "two" - }, - "other2": { - "baz": "three" - }, - "other3": { - "notbaz": ["a", "b", "c"] - }, - "other4": { - "notbaz": ["d", "e", "f"] - } - } - }, - "cases": [ - { - "expression": "foo | bar", - "result": {"baz": "one"} - }, - { - "expression": "foo | bar | baz", - "result": "one" - }, - { - "expression": "foo|bar| baz", - "result": "one" - }, - { - "expression": "not_there | [0]", - "result": null - }, - { - "expression": "not_there | [0]", - "result": null - }, - { - "expression": "[foo.bar, foo.other] | [0]", - "result": {"baz": "one"} - }, - { - "expression": "{\"a\": foo.bar, \"b\": foo.other} | a", - "result": {"baz": "one"} - }, - { - "expression": "{\"a\": foo.bar, \"b\": foo.other} | b", - "result": {"baz": "two"} - }, - { - "expression": "foo.bam || foo.bar | baz", - "result": "one" - }, - { - "expression": "foo | not_there || bar", - "result": {"baz": "one"} - } - ] -}, { - "given": { - "foo": [{ - "bar": [{ - "baz": "one" - }, { - "baz": "two" - }] - }, { - "bar": [{ - "baz": "three" - }, { - "baz": "four" - }] - }] - }, - "cases": [ - { - "expression": "foo[*].bar[*] | [0][0]", - "result": {"baz": "one"} - } - ] -}] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/slice.json b/vendor/github.com/jmespath/go-jmespath/compliance/slice.json deleted file mode 100644 index 359477278c8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/slice.json +++ /dev/null @@ -1,187 +0,0 @@ -[{ - "given": { - "foo": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "bar": { - "baz": 1 - } - }, - "cases": [ - { - "expression": "bar[0:10]", - "result": null - }, - { - "expression": "foo[0:10:1]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[0:10]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[0:10:]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[0::1]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[0::]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[0:]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[:10:1]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[::1]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[:10:]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[::]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[:]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[1:9]", - "result": [1, 2, 3, 4, 5, 6, 7, 8] - }, - { - "expression": "foo[0:10:2]", - "result": [0, 2, 4, 6, 8] - }, - { - "expression": "foo[5:]", - "result": [5, 6, 7, 8, 9] - }, - { - "expression": "foo[5::2]", - "result": [5, 7, 9] - }, - { - "expression": "foo[::2]", - "result": [0, 2, 4, 6, 8] - }, - { - "expression": "foo[::-1]", - "result": [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - }, - { - "expression": "foo[1::2]", - "result": [1, 3, 5, 7, 9] - }, - { - "expression": "foo[10:0:-1]", - "result": [9, 8, 7, 6, 5, 4, 3, 2, 1] - }, - { - "expression": "foo[10:5:-1]", - "result": [9, 8, 7, 6] - }, - { - "expression": "foo[8:2:-2]", - "result": [8, 6, 4] - }, - { - "expression": "foo[0:20]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - { - "expression": "foo[10:-20:-1]", - "result": [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - }, - { - "expression": "foo[10:-20]", - "result": [] - }, - { - "expression": "foo[-4:-1]", - "result": [6, 7, 8] - }, - { - "expression": "foo[:-5:-1]", - "result": [9, 8, 7, 6] - }, - { - "expression": "foo[8:2:0]", - "error": "invalid-value" - }, - { - "expression": "foo[8:2:0:1]", - "error": "syntax" - }, - { - "expression": "foo[8:2&]", - "error": "syntax" - }, - { - "expression": "foo[2:a:3]", - "error": "syntax" - } - ] -}, { - "given": { - "foo": [{"a": 1}, {"a": 2}, {"a": 3}], - "bar": [{"a": {"b": 1}}, {"a": {"b": 2}}, - {"a": {"b": 3}}], - "baz": 50 - }, - "cases": [ - { - "expression": "foo[:2].a", - "result": [1, 2] - }, - { - "expression": "foo[:2].b", - "result": [] - }, - { - "expression": "foo[:2].a.b", - "result": [] - }, - { - "expression": "bar[::-1].a.b", - "result": [3, 2, 1] - }, - { - "expression": "bar[:2].a.b", - "result": [1, 2] - }, - { - "expression": "baz[:2].a", - "result": null - } - ] -}, { - "given": [{"a": 1}, {"a": 2}, {"a": 3}], - "cases": [ - { - "expression": "[:]", - "result": [{"a": 1}, {"a": 2}, {"a": 3}] - }, - { - "expression": "[:2].a", - "result": [1, 2] - }, - { - "expression": "[::-1].a", - "result": [3, 2, 1] - }, - { - "expression": "[:2].b", - "result": [] - } - ] -}] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/syntax.json b/vendor/github.com/jmespath/go-jmespath/compliance/syntax.json deleted file mode 100644 index 003c2945887..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/syntax.json +++ /dev/null @@ -1,616 +0,0 @@ -[{ - "comment": "Dot syntax", - "given": {"type": "object"}, - "cases": [ - { - "expression": "foo.bar", - "result": null - }, - { - "expression": "foo.1", - "error": "syntax" - }, - { - "expression": "foo.-11", - "error": "syntax" - }, - { - "expression": "foo", - "result": null - }, - { - "expression": "foo.", - "error": "syntax" - }, - { - "expression": "foo.", - "error": "syntax" - }, - { - "expression": ".foo", - "error": "syntax" - }, - { - "expression": "foo..bar", - "error": "syntax" - }, - { - "expression": "foo.bar.", - "error": "syntax" - }, - { - "expression": "foo[.]", - "error": "syntax" - } - ] -}, - { - "comment": "Simple token errors", - "given": {"type": "object"}, - "cases": [ - { - "expression": ".", - "error": "syntax" - }, - { - "expression": ":", - "error": "syntax" - }, - { - "expression": ",", - "error": "syntax" - }, - { - "expression": "]", - "error": "syntax" - }, - { - "expression": "[", - "error": "syntax" - }, - { - "expression": "}", - "error": "syntax" - }, - { - "expression": "{", - "error": "syntax" - }, - { - "expression": ")", - "error": "syntax" - }, - { - "expression": "(", - "error": "syntax" - }, - { - "expression": "((&", - "error": "syntax" - }, - { - "expression": "a[", - "error": "syntax" - }, - { - "expression": "a]", - "error": "syntax" - }, - { - "expression": "a][", - "error": "syntax" - }, - { - "expression": "!", - "error": "syntax" - } - ] - }, - { - "comment": "Boolean syntax errors", - "given": {"type": "object"}, - "cases": [ - { - "expression": "![!(!", - "error": "syntax" - } - ] - }, - { - "comment": "Wildcard syntax", - "given": {"type": "object"}, - "cases": [ - { - "expression": "*", - "result": ["object"] - }, - { - "expression": "*.*", - "result": [] - }, - { - "expression": "*.foo", - "result": [] - }, - { - "expression": "*[0]", - "result": [] - }, - { - "expression": ".*", - "error": "syntax" - }, - { - "expression": "*foo", - "error": "syntax" - }, - { - "expression": "*0", - "error": "syntax" - }, - { - "expression": "foo[*]bar", - "error": "syntax" - }, - { - "expression": "foo[*]*", - "error": "syntax" - } - ] - }, - { - "comment": "Flatten syntax", - "given": {"type": "object"}, - "cases": [ - { - "expression": "[]", - "result": null - } - ] - }, - { - "comment": "Simple bracket syntax", - "given": {"type": "object"}, - "cases": [ - { - "expression": "[0]", - "result": null - }, - { - "expression": "[*]", - "result": null - }, - { - "expression": "*.[0]", - "error": "syntax" - }, - { - "expression": "*.[\"0\"]", - "result": [[null]] - }, - { - "expression": "[*].bar", - "result": null - }, - { - "expression": "[*][0]", - "result": null - }, - { - "expression": "foo[#]", - "error": "syntax" - } - ] - }, - { - "comment": "Multi-select list syntax", - "given": {"type": "object"}, - "cases": [ - { - "expression": "foo[0]", - "result": null - }, - { - "comment": "Valid multi-select of a list", - "expression": "foo[0, 1]", - "error": "syntax" - }, - { - "expression": "foo.[0]", - "error": "syntax" - }, - { - "expression": "foo.[*]", - "result": null - }, - { - "comment": "Multi-select of a list with trailing comma", - "expression": "foo[0, ]", - "error": "syntax" - }, - { - "comment": "Multi-select of a list with trailing comma and no close", - "expression": "foo[0,", - "error": "syntax" - }, - { - "comment": "Multi-select of a list with trailing comma and no close", - "expression": "foo.[a", - "error": "syntax" - }, - { - "comment": "Multi-select of a list with extra comma", - "expression": "foo[0,, 1]", - "error": "syntax" - }, - { - "comment": "Multi-select of a list using an identifier index", - "expression": "foo[abc]", - "error": "syntax" - }, - { - "comment": "Multi-select of a list using identifier indices", - "expression": "foo[abc, def]", - "error": "syntax" - }, - { - "comment": "Multi-select of a list using an identifier index", - "expression": "foo[abc, 1]", - "error": "syntax" - }, - { - "comment": "Multi-select of a list using an identifier index with trailing comma", - "expression": "foo[abc, ]", - "error": "syntax" - }, - { - "comment": "Valid multi-select of a hash using an identifier index", - "expression": "foo.[abc]", - "result": null - }, - { - "comment": "Valid multi-select of a hash", - "expression": "foo.[abc, def]", - "result": null - }, - { - "comment": "Multi-select of a hash using a numeric index", - "expression": "foo.[abc, 1]", - "error": "syntax" - }, - { - "comment": "Multi-select of a hash with a trailing comma", - "expression": "foo.[abc, ]", - "error": "syntax" - }, - { - "comment": "Multi-select of a hash with extra commas", - "expression": "foo.[abc,, def]", - "error": "syntax" - }, - { - "comment": "Multi-select of a hash using number indices", - "expression": "foo.[0, 1]", - "error": "syntax" - } - ] - }, - { - "comment": "Multi-select hash syntax", - "given": {"type": "object"}, - "cases": [ - { - "comment": "No key or value", - "expression": "a{}", - "error": "syntax" - }, - { - "comment": "No closing token", - "expression": "a{", - "error": "syntax" - }, - { - "comment": "Not a key value pair", - "expression": "a{foo}", - "error": "syntax" - }, - { - "comment": "Missing value and closing character", - "expression": "a{foo:", - "error": "syntax" - }, - { - "comment": "Missing closing character", - "expression": "a{foo: 0", - "error": "syntax" - }, - { - "comment": "Missing value", - "expression": "a{foo:}", - "error": "syntax" - }, - { - "comment": "Trailing comma and no closing character", - "expression": "a{foo: 0, ", - "error": "syntax" - }, - { - "comment": "Missing value with trailing comma", - "expression": "a{foo: ,}", - "error": "syntax" - }, - { - "comment": "Accessing Array using an identifier", - "expression": "a{foo: bar}", - "error": "syntax" - }, - { - "expression": "a{foo: 0}", - "error": "syntax" - }, - { - "comment": "Missing key-value pair", - "expression": "a.{}", - "error": "syntax" - }, - { - "comment": "Not a key-value pair", - "expression": "a.{foo}", - "error": "syntax" - }, - { - "comment": "Missing value", - "expression": "a.{foo:}", - "error": "syntax" - }, - { - "comment": "Missing value with trailing comma", - "expression": "a.{foo: ,}", - "error": "syntax" - }, - { - "comment": "Valid multi-select hash extraction", - "expression": "a.{foo: bar}", - "result": null - }, - { - "comment": "Valid multi-select hash extraction", - "expression": "a.{foo: bar, baz: bam}", - "result": null - }, - { - "comment": "Trailing comma", - "expression": "a.{foo: bar, }", - "error": "syntax" - }, - { - "comment": "Missing key in second key-value pair", - "expression": "a.{foo: bar, baz}", - "error": "syntax" - }, - { - "comment": "Missing value in second key-value pair", - "expression": "a.{foo: bar, baz:}", - "error": "syntax" - }, - { - "comment": "Trailing comma", - "expression": "a.{foo: bar, baz: bam, }", - "error": "syntax" - }, - { - "comment": "Nested multi select", - "expression": "{\"\\\\\":{\" \":*}}", - "result": {"\\": {" ": ["object"]}} - } - ] - }, - { - "comment": "Or expressions", - "given": {"type": "object"}, - "cases": [ - { - "expression": "foo || bar", - "result": null - }, - { - "expression": "foo ||", - "error": "syntax" - }, - { - "expression": "foo.|| bar", - "error": "syntax" - }, - { - "expression": " || foo", - "error": "syntax" - }, - { - "expression": "foo || || foo", - "error": "syntax" - }, - { - "expression": "foo.[a || b]", - "result": null - }, - { - "expression": "foo.[a ||]", - "error": "syntax" - }, - { - "expression": "\"foo", - "error": "syntax" - } - ] - }, - { - "comment": "Filter expressions", - "given": {"type": "object"}, - "cases": [ - { - "expression": "foo[?bar==`\"baz\"`]", - "result": null - }, - { - "expression": "foo[? bar == `\"baz\"` ]", - "result": null - }, - { - "expression": "foo[ ?bar==`\"baz\"`]", - "error": "syntax" - }, - { - "expression": "foo[?bar==]", - "error": "syntax" - }, - { - "expression": "foo[?==]", - "error": "syntax" - }, - { - "expression": "foo[?==bar]", - "error": "syntax" - }, - { - "expression": "foo[?bar==baz?]", - "error": "syntax" - }, - { - "expression": "foo[?a.b.c==d.e.f]", - "result": null - }, - { - "expression": "foo[?bar==`[0, 1, 2]`]", - "result": null - }, - { - "expression": "foo[?bar==`[\"a\", \"b\", \"c\"]`]", - "result": null - }, - { - "comment": "Literal char not escaped", - "expression": "foo[?bar==`[\"foo`bar\"]`]", - "error": "syntax" - }, - { - "comment": "Literal char escaped", - "expression": "foo[?bar==`[\"foo\\`bar\"]`]", - "result": null - }, - { - "comment": "Unknown comparator", - "expression": "foo[?bar<>baz]", - "error": "syntax" - }, - { - "comment": "Unknown comparator", - "expression": "foo[?bar^baz]", - "error": "syntax" - }, - { - "expression": "foo[bar==baz]", - "error": "syntax" - }, - { - "comment": "Quoted identifier in filter expression no spaces", - "expression": "[?\"\\\\\">`\"foo\"`]", - "result": null - }, - { - "comment": "Quoted identifier in filter expression with spaces", - "expression": "[?\"\\\\\" > `\"foo\"`]", - "result": null - } - ] - }, - { - "comment": "Filter expression errors", - "given": {"type": "object"}, - "cases": [ - { - "expression": "bar.`\"anything\"`", - "error": "syntax" - }, - { - "expression": "bar.baz.noexists.`\"literal\"`", - "error": "syntax" - }, - { - "comment": "Literal wildcard projection", - "expression": "foo[*].`\"literal\"`", - "error": "syntax" - }, - { - "expression": "foo[*].name.`\"literal\"`", - "error": "syntax" - }, - { - "expression": "foo[].name.`\"literal\"`", - "error": "syntax" - }, - { - "expression": "foo[].name.`\"literal\"`.`\"subliteral\"`", - "error": "syntax" - }, - { - "comment": "Projecting a literal onto an empty list", - "expression": "foo[*].name.noexist.`\"literal\"`", - "error": "syntax" - }, - { - "expression": "foo[].name.noexist.`\"literal\"`", - "error": "syntax" - }, - { - "expression": "twolen[*].`\"foo\"`", - "error": "syntax" - }, - { - "comment": "Two level projection of a literal", - "expression": "twolen[*].threelen[*].`\"bar\"`", - "error": "syntax" - }, - { - "comment": "Two level flattened projection of a literal", - "expression": "twolen[].threelen[].`\"bar\"`", - "error": "syntax" - } - ] - }, - { - "comment": "Identifiers", - "given": {"type": "object"}, - "cases": [ - { - "expression": "foo", - "result": null - }, - { - "expression": "\"foo\"", - "result": null - }, - { - "expression": "\"\\\\\"", - "result": null - } - ] - }, - { - "comment": "Combined syntax", - "given": [], - "cases": [ - { - "expression": "*||*|*|*", - "result": null - }, - { - "expression": "*[]||[*]", - "result": [] - }, - { - "expression": "[*.*]", - "result": [null] - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/unicode.json b/vendor/github.com/jmespath/go-jmespath/compliance/unicode.json deleted file mode 100644 index 6b07b0b6dae..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/unicode.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "given": {"foo": [{"✓": "✓"}, {"✓": "✗"}]}, - "cases": [ - { - "expression": "foo[].\"✓\"", - "result": ["✓", "✗"] - } - ] - }, - { - "given": {"☯": true}, - "cases": [ - { - "expression": "\"☯\"", - "result": true - } - ] - }, - { - "given": {"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪": true}, - "cases": [ - { - "expression": "\"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪\"", - "result": true - } - ] - }, - { - "given": {"☃": true}, - "cases": [ - { - "expression": "\"☃\"", - "result": true - } - ] - } -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance/wildcard.json b/vendor/github.com/jmespath/go-jmespath/compliance/wildcard.json deleted file mode 100644 index 3bcec302815..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance/wildcard.json +++ /dev/null @@ -1,460 +0,0 @@ -[{ - "given": { - "foo": { - "bar": { - "baz": "val" - }, - "other": { - "baz": "val" - }, - "other2": { - "baz": "val" - }, - "other3": { - "notbaz": ["a", "b", "c"] - }, - "other4": { - "notbaz": ["a", "b", "c"] - }, - "other5": { - "other": { - "a": 1, - "b": 1, - "c": 1 - } - } - } - }, - "cases": [ - { - "expression": "foo.*.baz", - "result": ["val", "val", "val"] - }, - { - "expression": "foo.bar.*", - "result": ["val"] - }, - { - "expression": "foo.*.notbaz", - "result": [["a", "b", "c"], ["a", "b", "c"]] - }, - { - "expression": "foo.*.notbaz[0]", - "result": ["a", "a"] - }, - { - "expression": "foo.*.notbaz[-1]", - "result": ["c", "c"] - } - ] -}, { - "given": { - "foo": { - "first-1": { - "second-1": "val" - }, - "first-2": { - "second-1": "val" - }, - "first-3": { - "second-1": "val" - } - } - }, - "cases": [ - { - "expression": "foo.*", - "result": [{"second-1": "val"}, {"second-1": "val"}, - {"second-1": "val"}] - }, - { - "expression": "foo.*.*", - "result": [["val"], ["val"], ["val"]] - }, - { - "expression": "foo.*.*.*", - "result": [[], [], []] - }, - { - "expression": "foo.*.*.*.*", - "result": [[], [], []] - } - ] -}, { - "given": { - "foo": { - "bar": "one" - }, - "other": { - "bar": "one" - }, - "nomatch": { - "notbar": "three" - } - }, - "cases": [ - { - "expression": "*.bar", - "result": ["one", "one"] - } - ] -}, { - "given": { - "top1": { - "sub1": {"foo": "one"} - }, - "top2": { - "sub1": {"foo": "one"} - } - }, - "cases": [ - { - "expression": "*", - "result": [{"sub1": {"foo": "one"}}, - {"sub1": {"foo": "one"}}] - }, - { - "expression": "*.sub1", - "result": [{"foo": "one"}, - {"foo": "one"}] - }, - { - "expression": "*.*", - "result": [[{"foo": "one"}], - [{"foo": "one"}]] - }, - { - "expression": "*.*.foo[]", - "result": ["one", "one"] - }, - { - "expression": "*.sub1.foo", - "result": ["one", "one"] - } - ] -}, -{ - "given": - {"foo": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}]}, - "cases": [ - { - "expression": "foo[*].bar", - "result": ["one", "two", "three"] - }, - { - "expression": "foo[*].notbar", - "result": ["four"] - } - ] -}, -{ - "given": - [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}], - "cases": [ - { - "expression": "[*]", - "result": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}] - }, - { - "expression": "[*].bar", - "result": ["one", "two", "three"] - }, - { - "expression": "[*].notbar", - "result": ["four"] - } - ] -}, -{ - "given": { - "foo": { - "bar": [ - {"baz": ["one", "two", "three"]}, - {"baz": ["four", "five", "six"]}, - {"baz": ["seven", "eight", "nine"]} - ] - } - }, - "cases": [ - { - "expression": "foo.bar[*].baz", - "result": [["one", "two", "three"], ["four", "five", "six"], ["seven", "eight", "nine"]] - }, - { - "expression": "foo.bar[*].baz[0]", - "result": ["one", "four", "seven"] - }, - { - "expression": "foo.bar[*].baz[1]", - "result": ["two", "five", "eight"] - }, - { - "expression": "foo.bar[*].baz[2]", - "result": ["three", "six", "nine"] - }, - { - "expression": "foo.bar[*].baz[3]", - "result": [] - } - ] -}, -{ - "given": { - "foo": { - "bar": [["one", "two"], ["three", "four"]] - } - }, - "cases": [ - { - "expression": "foo.bar[*]", - "result": [["one", "two"], ["three", "four"]] - }, - { - "expression": "foo.bar[0]", - "result": ["one", "two"] - }, - { - "expression": "foo.bar[0][0]", - "result": "one" - }, - { - "expression": "foo.bar[0][0][0]", - "result": null - }, - { - "expression": "foo.bar[0][0][0][0]", - "result": null - }, - { - "expression": "foo[0][0]", - "result": null - } - ] -}, -{ - "given": { - "foo": [ - {"bar": [{"kind": "basic"}, {"kind": "intermediate"}]}, - {"bar": [{"kind": "advanced"}, {"kind": "expert"}]}, - {"bar": "string"} - ] - - }, - "cases": [ - { - "expression": "foo[*].bar[*].kind", - "result": [["basic", "intermediate"], ["advanced", "expert"]] - }, - { - "expression": "foo[*].bar[0].kind", - "result": ["basic", "advanced"] - } - ] -}, -{ - "given": { - "foo": [ - {"bar": {"kind": "basic"}}, - {"bar": {"kind": "intermediate"}}, - {"bar": {"kind": "advanced"}}, - {"bar": {"kind": "expert"}}, - {"bar": "string"} - ] - }, - "cases": [ - { - "expression": "foo[*].bar.kind", - "result": ["basic", "intermediate", "advanced", "expert"] - } - ] -}, -{ - "given": { - "foo": [{"bar": ["one", "two"]}, {"bar": ["three", "four"]}, {"bar": ["five"]}] - }, - "cases": [ - { - "expression": "foo[*].bar[0]", - "result": ["one", "three", "five"] - }, - { - "expression": "foo[*].bar[1]", - "result": ["two", "four"] - }, - { - "expression": "foo[*].bar[2]", - "result": [] - } - ] -}, -{ - "given": { - "foo": [{"bar": []}, {"bar": []}, {"bar": []}] - }, - "cases": [ - { - "expression": "foo[*].bar[0]", - "result": [] - } - ] -}, -{ - "given": { - "foo": [["one", "two"], ["three", "four"], ["five"]] - }, - "cases": [ - { - "expression": "foo[*][0]", - "result": ["one", "three", "five"] - }, - { - "expression": "foo[*][1]", - "result": ["two", "four"] - } - ] -}, -{ - "given": { - "foo": [ - [ - ["one", "two"], ["three", "four"] - ], [ - ["five", "six"], ["seven", "eight"] - ], [ - ["nine"], ["ten"] - ] - ] - }, - "cases": [ - { - "expression": "foo[*][0]", - "result": [["one", "two"], ["five", "six"], ["nine"]] - }, - { - "expression": "foo[*][1]", - "result": [["three", "four"], ["seven", "eight"], ["ten"]] - }, - { - "expression": "foo[*][0][0]", - "result": ["one", "five", "nine"] - }, - { - "expression": "foo[*][1][0]", - "result": ["three", "seven", "ten"] - }, - { - "expression": "foo[*][0][1]", - "result": ["two", "six"] - }, - { - "expression": "foo[*][1][1]", - "result": ["four", "eight"] - }, - { - "expression": "foo[*][2]", - "result": [] - }, - { - "expression": "foo[*][2][2]", - "result": [] - }, - { - "expression": "bar[*]", - "result": null - }, - { - "expression": "bar[*].baz[*]", - "result": null - } - ] -}, -{ - "given": { - "string": "string", - "hash": {"foo": "bar", "bar": "baz"}, - "number": 23, - "nullvalue": null - }, - "cases": [ - { - "expression": "string[*]", - "result": null - }, - { - "expression": "hash[*]", - "result": null - }, - { - "expression": "number[*]", - "result": null - }, - { - "expression": "nullvalue[*]", - "result": null - }, - { - "expression": "string[*].foo", - "result": null - }, - { - "expression": "hash[*].foo", - "result": null - }, - { - "expression": "number[*].foo", - "result": null - }, - { - "expression": "nullvalue[*].foo", - "result": null - }, - { - "expression": "nullvalue[*].foo[*].bar", - "result": null - } - ] -}, -{ - "given": { - "string": "string", - "hash": {"foo": "val", "bar": "val"}, - "number": 23, - "array": [1, 2, 3], - "nullvalue": null - }, - "cases": [ - { - "expression": "string.*", - "result": null - }, - { - "expression": "hash.*", - "result": ["val", "val"] - }, - { - "expression": "number.*", - "result": null - }, - { - "expression": "array.*", - "result": null - }, - { - "expression": "nullvalue.*", - "result": null - } - ] -}, -{ - "given": { - "a": [0, 1, 2], - "b": [0, 1, 2] - }, - "cases": [ - { - "expression": "*[0]", - "result": [0, 0] - } - ] -} -] diff --git a/vendor/github.com/jmespath/go-jmespath/compliance_test.go b/vendor/github.com/jmespath/go-jmespath/compliance_test.go deleted file mode 100644 index 4ee9c959dc6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/compliance_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package jmespath - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -type TestSuite struct { - Given interface{} - TestCases []TestCase `json:"cases"` - Comment string -} -type TestCase struct { - Comment string - Expression string - Result interface{} - Error string -} - -var whiteListed = []string{ - "compliance/basic.json", - "compliance/current.json", - "compliance/escape.json", - "compliance/filters.json", - "compliance/functions.json", - "compliance/identifiers.json", - "compliance/indices.json", - "compliance/literal.json", - "compliance/multiselect.json", - "compliance/ormatch.json", - "compliance/pipe.json", - "compliance/slice.json", - "compliance/syntax.json", - "compliance/unicode.json", - "compliance/wildcard.json", - "compliance/boolean.json", -} - -func allowed(path string) bool { - for _, el := range whiteListed { - if el == path { - return true - } - } - return false -} - -func TestCompliance(t *testing.T) { - assert := assert.New(t) - - var complianceFiles []string - err := filepath.Walk("compliance", func(path string, _ os.FileInfo, _ error) error { - //if strings.HasSuffix(path, ".json") { - if allowed(path) { - complianceFiles = append(complianceFiles, path) - } - return nil - }) - if assert.Nil(err) { - for _, filename := range complianceFiles { - runComplianceTest(assert, filename) - } - } -} - -func runComplianceTest(assert *assert.Assertions, filename string) { - var testSuites []TestSuite - data, err := ioutil.ReadFile(filename) - if assert.Nil(err) { - err := json.Unmarshal(data, &testSuites) - if assert.Nil(err) { - for _, testsuite := range testSuites { - runTestSuite(assert, testsuite, filename) - } - } - } -} - -func runTestSuite(assert *assert.Assertions, testsuite TestSuite, filename string) { - for _, testcase := range testsuite.TestCases { - if testcase.Error != "" { - // This is a test case that verifies we error out properly. - runSyntaxTestCase(assert, testsuite.Given, testcase, filename) - } else { - runTestCase(assert, testsuite.Given, testcase, filename) - } - } -} - -func runSyntaxTestCase(assert *assert.Assertions, given interface{}, testcase TestCase, filename string) { - // Anything with an .Error means that we expect that JMESPath should return - // an error when we try to evaluate the expression. - _, err := Search(testcase.Expression, given) - assert.NotNil(err, fmt.Sprintf("Expression: %s", testcase.Expression)) -} - -func runTestCase(assert *assert.Assertions, given interface{}, testcase TestCase, filename string) { - lexer := NewLexer() - var err error - _, err = lexer.tokenize(testcase.Expression) - if err != nil { - errMsg := fmt.Sprintf("(%s) Could not lex expression: %s -- %s", filename, testcase.Expression, err.Error()) - assert.Fail(errMsg) - return - } - parser := NewParser() - _, err = parser.Parse(testcase.Expression) - if err != nil { - errMsg := fmt.Sprintf("(%s) Could not parse expression: %s -- %s", filename, testcase.Expression, err.Error()) - assert.Fail(errMsg) - return - } - actual, err := Search(testcase.Expression, given) - if assert.Nil(err, fmt.Sprintf("Expression: %s", testcase.Expression)) { - assert.Equal(testcase.Result, actual, fmt.Sprintf("Expression: %s", testcase.Expression)) - } -} diff --git a/vendor/github.com/jmespath/go-jmespath/functions.go b/vendor/github.com/jmespath/go-jmespath/functions.go index 8a3f2ef0dce..9b7cd89b4bc 100644 --- a/vendor/github.com/jmespath/go-jmespath/functions.go +++ b/vendor/github.com/jmespath/go-jmespath/functions.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math" + "reflect" "sort" "strconv" "strings" @@ -124,197 +125,197 @@ type functionCaller struct { func newFunctionCaller() *functionCaller { caller := &functionCaller{} caller.functionTable = map[string]functionEntry{ - "length": functionEntry{ + "length": { name: "length", arguments: []argSpec{ - argSpec{types: []jpType{jpString, jpArray, jpObject}}, + {types: []jpType{jpString, jpArray, jpObject}}, }, handler: jpfLength, }, - "starts_with": functionEntry{ + "starts_with": { name: "starts_with", arguments: []argSpec{ - argSpec{types: []jpType{jpString}}, - argSpec{types: []jpType{jpString}}, + {types: []jpType{jpString}}, + {types: []jpType{jpString}}, }, handler: jpfStartsWith, }, - "abs": functionEntry{ + "abs": { name: "abs", arguments: []argSpec{ - argSpec{types: []jpType{jpNumber}}, + {types: []jpType{jpNumber}}, }, handler: jpfAbs, }, - "avg": functionEntry{ + "avg": { name: "avg", arguments: []argSpec{ - argSpec{types: []jpType{jpArrayNumber}}, + {types: []jpType{jpArrayNumber}}, }, handler: jpfAvg, }, - "ceil": functionEntry{ + "ceil": { name: "ceil", arguments: []argSpec{ - argSpec{types: []jpType{jpNumber}}, + {types: []jpType{jpNumber}}, }, handler: jpfCeil, }, - "contains": functionEntry{ + "contains": { name: "contains", arguments: []argSpec{ - argSpec{types: []jpType{jpArray, jpString}}, - argSpec{types: []jpType{jpAny}}, + {types: []jpType{jpArray, jpString}}, + {types: []jpType{jpAny}}, }, handler: jpfContains, }, - "ends_with": functionEntry{ + "ends_with": { name: "ends_with", arguments: []argSpec{ - argSpec{types: []jpType{jpString}}, - argSpec{types: []jpType{jpString}}, + {types: []jpType{jpString}}, + {types: []jpType{jpString}}, }, handler: jpfEndsWith, }, - "floor": functionEntry{ + "floor": { name: "floor", arguments: []argSpec{ - argSpec{types: []jpType{jpNumber}}, + {types: []jpType{jpNumber}}, }, handler: jpfFloor, }, - "map": functionEntry{ + "map": { name: "amp", arguments: []argSpec{ - argSpec{types: []jpType{jpExpref}}, - argSpec{types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, + {types: []jpType{jpArray}}, }, handler: jpfMap, hasExpRef: true, }, - "max": functionEntry{ + "max": { name: "max", arguments: []argSpec{ - argSpec{types: []jpType{jpArrayNumber, jpArrayString}}, + {types: []jpType{jpArrayNumber, jpArrayString}}, }, handler: jpfMax, }, - "merge": functionEntry{ + "merge": { name: "merge", arguments: []argSpec{ - argSpec{types: []jpType{jpObject}, variadic: true}, + {types: []jpType{jpObject}, variadic: true}, }, handler: jpfMerge, }, - "max_by": functionEntry{ + "max_by": { name: "max_by", arguments: []argSpec{ - argSpec{types: []jpType{jpArray}}, - argSpec{types: []jpType{jpExpref}}, + {types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, }, handler: jpfMaxBy, hasExpRef: true, }, - "sum": functionEntry{ + "sum": { name: "sum", arguments: []argSpec{ - argSpec{types: []jpType{jpArrayNumber}}, + {types: []jpType{jpArrayNumber}}, }, handler: jpfSum, }, - "min": functionEntry{ + "min": { name: "min", arguments: []argSpec{ - argSpec{types: []jpType{jpArrayNumber, jpArrayString}}, + {types: []jpType{jpArrayNumber, jpArrayString}}, }, handler: jpfMin, }, - "min_by": functionEntry{ + "min_by": { name: "min_by", arguments: []argSpec{ - argSpec{types: []jpType{jpArray}}, - argSpec{types: []jpType{jpExpref}}, + {types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, }, handler: jpfMinBy, hasExpRef: true, }, - "type": functionEntry{ + "type": { name: "type", arguments: []argSpec{ - argSpec{types: []jpType{jpAny}}, + {types: []jpType{jpAny}}, }, handler: jpfType, }, - "keys": functionEntry{ + "keys": { name: "keys", arguments: []argSpec{ - argSpec{types: []jpType{jpObject}}, + {types: []jpType{jpObject}}, }, handler: jpfKeys, }, - "values": functionEntry{ + "values": { name: "values", arguments: []argSpec{ - argSpec{types: []jpType{jpObject}}, + {types: []jpType{jpObject}}, }, handler: jpfValues, }, - "sort": functionEntry{ + "sort": { name: "sort", arguments: []argSpec{ - argSpec{types: []jpType{jpArrayString, jpArrayNumber}}, + {types: []jpType{jpArrayString, jpArrayNumber}}, }, handler: jpfSort, }, - "sort_by": functionEntry{ + "sort_by": { name: "sort_by", arguments: []argSpec{ - argSpec{types: []jpType{jpArray}}, - argSpec{types: []jpType{jpExpref}}, + {types: []jpType{jpArray}}, + {types: []jpType{jpExpref}}, }, handler: jpfSortBy, hasExpRef: true, }, - "join": functionEntry{ + "join": { name: "join", arguments: []argSpec{ - argSpec{types: []jpType{jpString}}, - argSpec{types: []jpType{jpArrayString}}, + {types: []jpType{jpString}}, + {types: []jpType{jpArrayString}}, }, handler: jpfJoin, }, - "reverse": functionEntry{ + "reverse": { name: "reverse", arguments: []argSpec{ - argSpec{types: []jpType{jpArray, jpString}}, + {types: []jpType{jpArray, jpString}}, }, handler: jpfReverse, }, - "to_array": functionEntry{ + "to_array": { name: "to_array", arguments: []argSpec{ - argSpec{types: []jpType{jpAny}}, + {types: []jpType{jpAny}}, }, handler: jpfToArray, }, - "to_string": functionEntry{ + "to_string": { name: "to_string", arguments: []argSpec{ - argSpec{types: []jpType{jpAny}}, + {types: []jpType{jpAny}}, }, handler: jpfToString, }, - "to_number": functionEntry{ + "to_number": { name: "to_number", arguments: []argSpec{ - argSpec{types: []jpType{jpAny}}, + {types: []jpType{jpAny}}, }, handler: jpfToNumber, }, - "not_null": functionEntry{ + "not_null": { name: "not_null", arguments: []argSpec{ - argSpec{types: []jpType{jpAny}, variadic: true}, + {types: []jpType{jpAny}, variadic: true}, }, handler: jpfNotNull, }, @@ -357,7 +358,7 @@ func (a *argSpec) typeCheck(arg interface{}) error { return nil } case jpArray: - if _, ok := arg.([]interface{}); ok { + if isSliceType(arg) { return nil } case jpObject: @@ -409,8 +410,9 @@ func jpfLength(arguments []interface{}) (interface{}, error) { arg := arguments[0] if c, ok := arg.(string); ok { return float64(utf8.RuneCountInString(c)), nil - } else if c, ok := arg.([]interface{}); ok { - return float64(len(c)), nil + } else if isSliceType(arg) { + v := reflect.ValueOf(arg) + return float64(v.Len()), nil } else if c, ok := arg.(map[string]interface{}); ok { return float64(len(c)), nil } diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-1 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-1 deleted file mode 100644 index 19102815663..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-1 +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-10 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-10 deleted file mode 100644 index 4d5f9756e55..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-10 +++ /dev/null @@ -1 +0,0 @@ -foo.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-100 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-100 deleted file mode 100644 index bc4f6a3f49c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-100 +++ /dev/null @@ -1 +0,0 @@ -ends_with(str, 'SStr') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-101 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-101 deleted file mode 100644 index 81bf07a7a1b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-101 +++ /dev/null @@ -1 +0,0 @@ -ends_with(str, 'foo') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-102 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-102 deleted file mode 100644 index 3225de91399..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-102 +++ /dev/null @@ -1 +0,0 @@ -floor(`1.2`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-103 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-103 deleted file mode 100644 index 8cac9595822..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-103 +++ /dev/null @@ -1 +0,0 @@ -floor(decimals[0]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-104 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-104 deleted file mode 100644 index bd76f47e216..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-104 +++ /dev/null @@ -1 +0,0 @@ -floor(foo) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-105 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-105 deleted file mode 100644 index c719add3deb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-105 +++ /dev/null @@ -1 +0,0 @@ -length('abc') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-106 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-106 deleted file mode 100644 index ff12f04f148..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-106 +++ /dev/null @@ -1 +0,0 @@ -length('') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-107 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-107 deleted file mode 100644 index 0eccba1d3a0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-107 +++ /dev/null @@ -1 +0,0 @@ -length(@) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-108 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-108 deleted file mode 100644 index ab14b0fa8e6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-108 +++ /dev/null @@ -1 +0,0 @@ -length(strings[0]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-109 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-109 deleted file mode 100644 index f1514bb7438..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-109 +++ /dev/null @@ -1 +0,0 @@ -length(str) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-110 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-110 deleted file mode 100644 index 09276059a23..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-110 +++ /dev/null @@ -1 +0,0 @@ -length(array) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-112 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-112 deleted file mode 100644 index ab14b0fa8e6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-112 +++ /dev/null @@ -1 +0,0 @@ -length(strings[0]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-115 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-115 deleted file mode 100644 index bfb41ae9875..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-115 +++ /dev/null @@ -1 +0,0 @@ -max(strings) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-118 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-118 deleted file mode 100644 index 915ec172ae7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-118 +++ /dev/null @@ -1 +0,0 @@ -merge(`{}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-119 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-119 deleted file mode 100644 index 5b74e9b593f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-119 +++ /dev/null @@ -1 +0,0 @@ -merge(`{}`, `{}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-12 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-12 deleted file mode 100644 index 64c5e5885a4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-12 +++ /dev/null @@ -1 +0,0 @@ -two \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-120 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-120 deleted file mode 100644 index f34dcd8fade..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-120 +++ /dev/null @@ -1 +0,0 @@ -merge(`{"a": 1}`, `{"b": 2}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-121 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-121 deleted file mode 100644 index e335dc96fea..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-121 +++ /dev/null @@ -1 +0,0 @@ -merge(`{"a": 1}`, `{"a": 2}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-122 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-122 deleted file mode 100644 index aac28fffeb3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-122 +++ /dev/null @@ -1 +0,0 @@ -merge(`{"a": 1, "b": 2}`, `{"a": 2, "c": 3}`, `{"d": 4}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-123 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-123 deleted file mode 100644 index 1c6fd67198e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-123 +++ /dev/null @@ -1 +0,0 @@ -min(numbers) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-126 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-126 deleted file mode 100644 index 93e68db7759..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-126 +++ /dev/null @@ -1 +0,0 @@ -min(decimals) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-128 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-128 deleted file mode 100644 index 554601ea427..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-128 +++ /dev/null @@ -1 +0,0 @@ -type('abc') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-129 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-129 deleted file mode 100644 index 1ab2d9834f8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-129 +++ /dev/null @@ -1 +0,0 @@ -type(`1.0`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-13 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-13 deleted file mode 100644 index 1d19714ffbc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-13 +++ /dev/null @@ -1 +0,0 @@ -three \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-130 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-130 deleted file mode 100644 index 3cee2f56f15..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-130 +++ /dev/null @@ -1 +0,0 @@ -type(`2`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-131 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-131 deleted file mode 100644 index 4821f9aefcf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-131 +++ /dev/null @@ -1 +0,0 @@ -type(`true`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-132 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-132 deleted file mode 100644 index 40b6913a6c0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-132 +++ /dev/null @@ -1 +0,0 @@ -type(`false`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-133 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-133 deleted file mode 100644 index c711252be28..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-133 +++ /dev/null @@ -1 +0,0 @@ -type(`null`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-134 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-134 deleted file mode 100644 index ec5d07e95cc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-134 +++ /dev/null @@ -1 +0,0 @@ -type(`[0]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-135 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-135 deleted file mode 100644 index 2080401e1ea..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-135 +++ /dev/null @@ -1 +0,0 @@ -type(`{"a": "b"}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-136 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-136 deleted file mode 100644 index c5ee2ba5cb8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-136 +++ /dev/null @@ -1 +0,0 @@ -type(@) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-137 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-137 deleted file mode 100644 index 1814ca17b87..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-137 +++ /dev/null @@ -1 +0,0 @@ -keys(objects) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-138 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-138 deleted file mode 100644 index e03cdb0d640..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-138 +++ /dev/null @@ -1 +0,0 @@ -values(objects) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-139 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-139 deleted file mode 100644 index 7fea8d2ce5c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-139 +++ /dev/null @@ -1 +0,0 @@ -keys(empty_hash) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-14 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-14 deleted file mode 100644 index a17c92f5974..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-14 +++ /dev/null @@ -1 +0,0 @@ -one.two \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-140 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-140 deleted file mode 100644 index 4f1d882a406..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-140 +++ /dev/null @@ -1 +0,0 @@ -join(', ', strings) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-141 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-141 deleted file mode 100644 index 4f1d882a406..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-141 +++ /dev/null @@ -1 +0,0 @@ -join(', ', strings) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-142 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-142 deleted file mode 100644 index 19ec1fe0900..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-142 +++ /dev/null @@ -1 +0,0 @@ -join(',', `["a", "b"]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-143 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-143 deleted file mode 100644 index 761c68a6b59..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-143 +++ /dev/null @@ -1 +0,0 @@ -join('|', strings) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-144 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-144 deleted file mode 100644 index a0dd68eaa90..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-144 +++ /dev/null @@ -1 +0,0 @@ -join('|', decimals[].to_string(@)) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-145 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-145 deleted file mode 100644 index a4190b2ba25..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-145 +++ /dev/null @@ -1 +0,0 @@ -join('|', empty_list) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-146 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-146 deleted file mode 100644 index f5033c30223..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-146 +++ /dev/null @@ -1 +0,0 @@ -reverse(numbers) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-147 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-147 deleted file mode 100644 index 822f054d50c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-147 +++ /dev/null @@ -1 +0,0 @@ -reverse(array) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-148 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-148 deleted file mode 100644 index a584adcc0c5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-148 +++ /dev/null @@ -1 +0,0 @@ -reverse(`[]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-149 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-149 deleted file mode 100644 index fb4cc5dc482..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-149 +++ /dev/null @@ -1 +0,0 @@ -reverse('') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-15 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-15 deleted file mode 100644 index 693f9549627..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-15 +++ /dev/null @@ -1 +0,0 @@ -foo."1" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-150 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-150 deleted file mode 100644 index aa260fabc17..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-150 +++ /dev/null @@ -1 +0,0 @@ -reverse('hello world') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-151 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-151 deleted file mode 100644 index d8c58826afd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-151 +++ /dev/null @@ -1 +0,0 @@ -starts_with(str, 'S') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-152 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-152 deleted file mode 100644 index 32e16b7bb00..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-152 +++ /dev/null @@ -1 +0,0 @@ -starts_with(str, 'St') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-153 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-153 deleted file mode 100644 index 5f575ae7fc4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-153 +++ /dev/null @@ -1 +0,0 @@ -starts_with(str, 'Str') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-155 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-155 deleted file mode 100644 index f31551c62fd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-155 +++ /dev/null @@ -1 +0,0 @@ -sum(numbers) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-156 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-156 deleted file mode 100644 index 18b90446cc9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-156 +++ /dev/null @@ -1 +0,0 @@ -sum(decimals) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-157 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-157 deleted file mode 100644 index def4d0bc19c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-157 +++ /dev/null @@ -1 +0,0 @@ -sum(array[].to_number(@)) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-158 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-158 deleted file mode 100644 index 48e4a7707c7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-158 +++ /dev/null @@ -1 +0,0 @@ -sum(`[]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-159 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-159 deleted file mode 100644 index 9fb939a0b1b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-159 +++ /dev/null @@ -1 +0,0 @@ -to_array('foo') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-16 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-16 deleted file mode 100644 index 86155ed7546..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-16 +++ /dev/null @@ -1 +0,0 @@ -foo."1"[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-160 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-160 deleted file mode 100644 index 74ba7cc67db..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-160 +++ /dev/null @@ -1 +0,0 @@ -to_array(`0`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-161 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-161 deleted file mode 100644 index 57f8b983f08..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-161 +++ /dev/null @@ -1 +0,0 @@ -to_array(objects) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-162 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-162 deleted file mode 100644 index d17c7345faf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-162 +++ /dev/null @@ -1 +0,0 @@ -to_array(`[1, 2, 3]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-163 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-163 deleted file mode 100644 index 15f70f78399..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-163 +++ /dev/null @@ -1 +0,0 @@ -to_array(false) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-164 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-164 deleted file mode 100644 index 9b227529b40..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-164 +++ /dev/null @@ -1 +0,0 @@ -to_string('foo') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-165 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-165 deleted file mode 100644 index 489a42935a6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-165 +++ /dev/null @@ -1 +0,0 @@ -to_string(`1.2`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-166 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-166 deleted file mode 100644 index d17106a00f5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-166 +++ /dev/null @@ -1 +0,0 @@ -to_string(`[0, 1]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-167 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-167 deleted file mode 100644 index 4f4ae9e6890..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-167 +++ /dev/null @@ -1 +0,0 @@ -to_number('1.0') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-168 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-168 deleted file mode 100644 index ce932e2e6ac..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-168 +++ /dev/null @@ -1 +0,0 @@ -to_number('1.1') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-169 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-169 deleted file mode 100644 index e246fa4dbcb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-169 +++ /dev/null @@ -1 +0,0 @@ -to_number('4') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-17 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-17 deleted file mode 100644 index de0b4c39d99..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-17 +++ /dev/null @@ -1 +0,0 @@ -foo."-1" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-170 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-170 deleted file mode 100644 index f8c264747e9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-170 +++ /dev/null @@ -1 +0,0 @@ -to_number('notanumber') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-171 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-171 deleted file mode 100644 index 7d423b1cd19..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-171 +++ /dev/null @@ -1 +0,0 @@ -to_number(`false`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-172 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-172 deleted file mode 100644 index 503716b687c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-172 +++ /dev/null @@ -1 +0,0 @@ -to_number(`null`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-173 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-173 deleted file mode 100644 index 7f61dfa157b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-173 +++ /dev/null @@ -1 +0,0 @@ -to_number(`[0]`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-174 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-174 deleted file mode 100644 index ee72a8c01ac..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-174 +++ /dev/null @@ -1 +0,0 @@ -to_number(`{"foo": 0}`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-175 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-175 deleted file mode 100644 index 8d8f1f75906..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-175 +++ /dev/null @@ -1 +0,0 @@ -sort(numbers) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-178 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-178 deleted file mode 100644 index 8cb54ba47b3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-178 +++ /dev/null @@ -1 +0,0 @@ -sort(empty_list) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-179 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-179 deleted file mode 100644 index cf2c9b1db2e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-179 +++ /dev/null @@ -1 +0,0 @@ -not_null(unknown_key, str) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-18 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-18 deleted file mode 100644 index b516b2c489f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-18 +++ /dev/null @@ -1 +0,0 @@ -@ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-180 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-180 deleted file mode 100644 index e047d486682..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-180 +++ /dev/null @@ -1 +0,0 @@ -not_null(unknown_key, foo.bar, empty_list, str) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-181 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-181 deleted file mode 100644 index c4cc87b9c12..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-181 +++ /dev/null @@ -1 +0,0 @@ -not_null(unknown_key, null_key, empty_list, str) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-182 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-182 deleted file mode 100644 index 2c7fa0a9c1e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-182 +++ /dev/null @@ -1 +0,0 @@ -not_null(all, expressions, are_null) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-183 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-183 deleted file mode 100644 index eb096e61cdd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-183 +++ /dev/null @@ -1 +0,0 @@ -numbers[].to_string(@) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-184 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-184 deleted file mode 100644 index 4958abaec45..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-184 +++ /dev/null @@ -1 +0,0 @@ -array[].to_number(@) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-185 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-185 deleted file mode 100644 index 1027084724d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-185 +++ /dev/null @@ -1 +0,0 @@ -foo[].not_null(f, e, d, c, b, a) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-186 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-186 deleted file mode 100644 index 83cb9161282..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-186 +++ /dev/null @@ -1 +0,0 @@ -sort_by(people, &age) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-187 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-187 deleted file mode 100644 index a494d6c4bf1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-187 +++ /dev/null @@ -1 +0,0 @@ -sort_by(people, &to_number(age_str)) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-188 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-188 deleted file mode 100644 index 2294fc54d12..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-188 +++ /dev/null @@ -1 +0,0 @@ -sort_by(people, &age)[].name \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-189 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-189 deleted file mode 100644 index bb8c2b46d1f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-189 +++ /dev/null @@ -1 +0,0 @@ -sort_by(people, &age)[].extra \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-19 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-19 deleted file mode 100644 index e3ed49ac653..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-19 +++ /dev/null @@ -1 +0,0 @@ -@.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-190 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-190 deleted file mode 100644 index 3ab0290340a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-190 +++ /dev/null @@ -1 +0,0 @@ -sort_by(`[]`, &age) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-191 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-191 deleted file mode 100644 index 97db56f7b67..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-191 +++ /dev/null @@ -1 +0,0 @@ -max_by(people, &age) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-192 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-192 deleted file mode 100644 index a7e648de963..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-192 +++ /dev/null @@ -1 +0,0 @@ -max_by(people, &age_str) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-193 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-193 deleted file mode 100644 index be4348d0c1e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-193 +++ /dev/null @@ -1 +0,0 @@ -max_by(people, &to_number(age_str)) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-194 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-194 deleted file mode 100644 index a707283d499..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-194 +++ /dev/null @@ -1 +0,0 @@ -min_by(people, &age) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-195 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-195 deleted file mode 100644 index 2cd6618d84b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-195 +++ /dev/null @@ -1 +0,0 @@ -min_by(people, &age_str) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-196 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-196 deleted file mode 100644 index 833e6837382..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-196 +++ /dev/null @@ -1 +0,0 @@ -min_by(people, &to_number(age_str)) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-198 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-198 deleted file mode 100644 index 706dbda89a8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-198 +++ /dev/null @@ -1 +0,0 @@ -__L \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-199 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-199 deleted file mode 100644 index ca593ca93c1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-199 +++ /dev/null @@ -1 +0,0 @@ -"!\r" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-2 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-2 deleted file mode 100644 index 4d5f9756e55..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-2 +++ /dev/null @@ -1 +0,0 @@ -foo.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-20 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-20 deleted file mode 100644 index f300ab91782..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-20 +++ /dev/null @@ -1 +0,0 @@ -@.foo[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-200 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-200 deleted file mode 100644 index 9c93843541d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-200 +++ /dev/null @@ -1 +0,0 @@ -Y_1623 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-201 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-201 deleted file mode 100644 index c1b0730e013..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-201 +++ /dev/null @@ -1 +0,0 @@ -x \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-202 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-202 deleted file mode 100644 index 1552ec63a6f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-202 +++ /dev/null @@ -1 +0,0 @@ -"\tF\uCebb" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-203 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-203 deleted file mode 100644 index 047041273f0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-203 +++ /dev/null @@ -1 +0,0 @@ -" \t" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-204 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-204 deleted file mode 100644 index efd782cc325..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-204 +++ /dev/null @@ -1 +0,0 @@ -" " \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-205 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-205 deleted file mode 100644 index 8494ac27064..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-205 +++ /dev/null @@ -1 +0,0 @@ -v2 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-206 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-206 deleted file mode 100644 index c61f7f7ebd8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-206 +++ /dev/null @@ -1 +0,0 @@ -"\t" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-207 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-207 deleted file mode 100644 index f6055f1898f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-207 +++ /dev/null @@ -1 +0,0 @@ -_X \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-208 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-208 deleted file mode 100644 index 4f58e0e7bd2..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-208 +++ /dev/null @@ -1 +0,0 @@ -"\t4\ud9da\udd15" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-209 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-209 deleted file mode 100644 index f536bfbf687..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-209 +++ /dev/null @@ -1 +0,0 @@ -v24_W \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-21 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-21 deleted file mode 100644 index ef47ff2c056..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-21 +++ /dev/null @@ -1 +0,0 @@ -"foo.bar" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-210 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-210 deleted file mode 100644 index 69759281cb4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-210 +++ /dev/null @@ -1 +0,0 @@ -"H" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-211 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-211 deleted file mode 100644 index c3e8b5927fb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-211 +++ /dev/null @@ -1 +0,0 @@ -"\f" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-212 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-212 deleted file mode 100644 index 24ecc222cbf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-212 +++ /dev/null @@ -1 +0,0 @@ -"E4" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-213 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-213 deleted file mode 100644 index 5693009d2e4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-213 +++ /dev/null @@ -1 +0,0 @@ -"!" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-214 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-214 deleted file mode 100644 index 62dd220e719..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-214 +++ /dev/null @@ -1 +0,0 @@ -tM \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-215 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-215 deleted file mode 100644 index 3c1e81f55ae..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-215 +++ /dev/null @@ -1 +0,0 @@ -" [" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-216 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-216 deleted file mode 100644 index 493daa673c4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-216 +++ /dev/null @@ -1 +0,0 @@ -"R!" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-217 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-217 deleted file mode 100644 index 116b50ab38b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-217 +++ /dev/null @@ -1 +0,0 @@ -_6W \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-218 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-218 deleted file mode 100644 index 0073fac4520..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-218 +++ /dev/null @@ -1 +0,0 @@ -"\uaBA1\r" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-219 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-219 deleted file mode 100644 index 00d8fa37eeb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-219 +++ /dev/null @@ -1 +0,0 @@ -tL7 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-22 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-22 deleted file mode 100644 index 661ebcfa337..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-22 +++ /dev/null @@ -1 +0,0 @@ -"foo bar" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-220 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-220 deleted file mode 100644 index c14f16e0264..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-220 +++ /dev/null @@ -1 +0,0 @@ -"<" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-257 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-257 deleted file mode 100644 index 8a2443e6e90..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-257 +++ /dev/null @@ -1 +0,0 @@ -hvu \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-258 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-258 deleted file mode 100644 index c9ddacbb61f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-258 +++ /dev/null @@ -1 +0,0 @@ -"; !" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-259 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-259 deleted file mode 100644 index d0209c6df0a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-259 +++ /dev/null @@ -1 +0,0 @@ -hU \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-26 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-26 deleted file mode 100644 index 82649bd24ee..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-26 +++ /dev/null @@ -1 +0,0 @@ -"/unix/path" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-260 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-260 deleted file mode 100644 index c07242aa44b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-260 +++ /dev/null @@ -1 +0,0 @@ -"!I\n\/" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-261 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-261 deleted file mode 100644 index 7aae4effc7c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-261 +++ /dev/null @@ -1 +0,0 @@ -"\uEEbF" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-262 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-262 deleted file mode 100644 index c1574f35ffa..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-262 +++ /dev/null @@ -1 +0,0 @@ -"U)\t" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-263 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-263 deleted file mode 100644 index 5197e3a2bf5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-263 +++ /dev/null @@ -1 +0,0 @@ -fa0_9 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-264 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-264 deleted file mode 100644 index 320558b0053..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-264 +++ /dev/null @@ -1 +0,0 @@ -"/" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-265 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-265 deleted file mode 100644 index 4a2cb086527..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-265 +++ /dev/null @@ -1 +0,0 @@ -Gy \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-266 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-266 deleted file mode 100644 index 9524c83813c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-266 +++ /dev/null @@ -1 +0,0 @@ -"\b" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-267 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-267 deleted file mode 100644 index 066b8d98b78..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-267 +++ /dev/null @@ -1 +0,0 @@ -"<" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-268 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-268 deleted file mode 100644 index c61f7f7ebd8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-268 +++ /dev/null @@ -1 +0,0 @@ -"\t" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-269 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-269 deleted file mode 100644 index a582f62d282..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-269 +++ /dev/null @@ -1 +0,0 @@ -"\t&\\\r" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-27 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-27 deleted file mode 100644 index a1d50731c78..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-27 +++ /dev/null @@ -1 +0,0 @@ -"\"\"\"" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-270 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-270 deleted file mode 100644 index e3c5eedeb59..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-270 +++ /dev/null @@ -1 +0,0 @@ -"#" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-271 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-271 deleted file mode 100644 index e75309a5241..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-271 +++ /dev/null @@ -1 +0,0 @@ -B__ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-272 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-272 deleted file mode 100644 index 027177272c5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-272 +++ /dev/null @@ -1 +0,0 @@ -"\nS \n" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-273 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-273 deleted file mode 100644 index 99432276ec4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-273 +++ /dev/null @@ -1 +0,0 @@ -Bp \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-274 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-274 deleted file mode 100644 index d4f8a788b80..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-274 +++ /dev/null @@ -1 +0,0 @@ -",\t;" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-275 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-275 deleted file mode 100644 index 56c384f7530..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-275 +++ /dev/null @@ -1 +0,0 @@ -B_q \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-276 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-276 deleted file mode 100644 index f093d2aa3bc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-276 +++ /dev/null @@ -1 +0,0 @@ -"\/+\t\n\b!Z" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-277 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-277 deleted file mode 100644 index 11e1229d9e3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-277 +++ /dev/null @@ -1 +0,0 @@ -"󇟇\\ueFAc" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-278 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-278 deleted file mode 100644 index 90dbfcfcd35..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-278 +++ /dev/null @@ -1 +0,0 @@ -":\f" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-279 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-279 deleted file mode 100644 index b06b8302524..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-279 +++ /dev/null @@ -1 +0,0 @@ -"\/" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-28 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-28 deleted file mode 100644 index 5f55d73af66..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-28 +++ /dev/null @@ -1 +0,0 @@ -"bar"."baz" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-280 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-280 deleted file mode 100644 index 0e4bf7c113b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-280 +++ /dev/null @@ -1 +0,0 @@ -_BW_6Hg_Gl \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-281 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-281 deleted file mode 100644 index 81bb45f8059..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-281 +++ /dev/null @@ -1 +0,0 @@ -"􃰂" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-282 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-282 deleted file mode 100644 index d0b4de14642..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-282 +++ /dev/null @@ -1 +0,0 @@ -zs1DC \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-283 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-283 deleted file mode 100644 index 68797580caa..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-283 +++ /dev/null @@ -1 +0,0 @@ -__434 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-284 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-284 deleted file mode 100644 index e61be91c4af..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-284 +++ /dev/null @@ -1 +0,0 @@ -"󵅁" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-285 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-285 deleted file mode 100644 index 026cb9cbb51..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-285 +++ /dev/null @@ -1 +0,0 @@ -Z_5 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-286 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-286 deleted file mode 100644 index ca9587d06c0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-286 +++ /dev/null @@ -1 +0,0 @@ -z_M_ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-287 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-287 deleted file mode 100644 index 67f6d9c42a3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-287 +++ /dev/null @@ -1 +0,0 @@ -YU_2 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-288 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-288 deleted file mode 100644 index 927ab653a73..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-288 +++ /dev/null @@ -1 +0,0 @@ -_0 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-289 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-289 deleted file mode 100644 index 39307ab938e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-289 +++ /dev/null @@ -1 +0,0 @@ -"\b+" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-29 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-29 deleted file mode 100644 index 8b0c5b41bd9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-29 +++ /dev/null @@ -1 +0,0 @@ -foo[?name == 'a'] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-290 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-290 deleted file mode 100644 index a3ec2ed7a12..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-290 +++ /dev/null @@ -1 +0,0 @@ -"\"" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-291 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-291 deleted file mode 100644 index 26bf7e122de..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-291 +++ /dev/null @@ -1 +0,0 @@ -D7 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-292 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-292 deleted file mode 100644 index d595c9f43a9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-292 +++ /dev/null @@ -1 +0,0 @@ -_62L \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-293 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-293 deleted file mode 100644 index f6869694967..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-293 +++ /dev/null @@ -1 +0,0 @@ -"\tK\t" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-294 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-294 deleted file mode 100644 index f3a9b7edb50..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-294 +++ /dev/null @@ -1 +0,0 @@ -"\n\\\f" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-295 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-295 deleted file mode 100644 index 455f00ffc29..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-295 +++ /dev/null @@ -1 +0,0 @@ -I_ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-296 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-296 deleted file mode 100644 index ccd5968f9c1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-296 +++ /dev/null @@ -1 +0,0 @@ -W_a0_ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-297 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-297 deleted file mode 100644 index ee55c16fc81..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-297 +++ /dev/null @@ -1 +0,0 @@ -BQ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-298 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-298 deleted file mode 100644 index 0d1a169a67a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-298 +++ /dev/null @@ -1 +0,0 @@ -"\tX$\uABBb" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-299 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-299 deleted file mode 100644 index 0573cfd73fd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-299 +++ /dev/null @@ -1 +0,0 @@ -Z9 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-3 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-3 deleted file mode 100644 index f0fcbd8eaf4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-3 +++ /dev/null @@ -1 +0,0 @@ -foo.bar.baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-30 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-30 deleted file mode 100644 index 4f8e6a17aab..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-30 +++ /dev/null @@ -1 +0,0 @@ -*[?[0] == `0`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-300 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-300 deleted file mode 100644 index a0db02bebf1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-300 +++ /dev/null @@ -1 +0,0 @@ -"\b%\"򞄏" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-301 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-301 deleted file mode 100644 index 56032f7a248..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-301 +++ /dev/null @@ -1 +0,0 @@ -_F \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-302 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-302 deleted file mode 100644 index 4a8a3cff369..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-302 +++ /dev/null @@ -1 +0,0 @@ -"!," \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-303 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-303 deleted file mode 100644 index 7c1efac0004..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-303 +++ /dev/null @@ -1 +0,0 @@ -"\"!" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-304 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-304 deleted file mode 100644 index a0f489d532f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-304 +++ /dev/null @@ -1 +0,0 @@ -Hh \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-305 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-305 deleted file mode 100644 index c64e8d5ac8b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-305 +++ /dev/null @@ -1 +0,0 @@ -"&" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-306 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-306 deleted file mode 100644 index 0567e992f14..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-306 +++ /dev/null @@ -1 +0,0 @@ -"9\r\\R" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-307 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-307 deleted file mode 100644 index ce8245c5b97..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-307 +++ /dev/null @@ -1 +0,0 @@ -M_k \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-308 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-308 deleted file mode 100644 index 8f16a5ac048..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-308 +++ /dev/null @@ -1 +0,0 @@ -"!\b\n󑩒\"\"" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-309 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-309 deleted file mode 100644 index 504ff5ae39f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-309 +++ /dev/null @@ -1 +0,0 @@ -"6" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-31 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-31 deleted file mode 100644 index 07fb57234b8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-31 +++ /dev/null @@ -1 +0,0 @@ -foo[?first == last] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-310 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-310 deleted file mode 100644 index 533dd8e5460..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-310 +++ /dev/null @@ -1 +0,0 @@ -_7 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-311 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-311 deleted file mode 100644 index 1e4a3a34155..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-311 +++ /dev/null @@ -1 +0,0 @@ -"0" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-312 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-312 deleted file mode 100644 index 37961f6ca42..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-312 +++ /dev/null @@ -1 +0,0 @@ -"\\8\\" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-313 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-313 deleted file mode 100644 index 23480cff14c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-313 +++ /dev/null @@ -1 +0,0 @@ -b7eo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-314 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-314 deleted file mode 100644 index e609f81a3b8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-314 +++ /dev/null @@ -1 +0,0 @@ -xIUo9 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-315 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-315 deleted file mode 100644 index d89a25f0b97..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-315 +++ /dev/null @@ -1 +0,0 @@ -"5" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-316 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-316 deleted file mode 100644 index 5adcf5e7dc5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-316 +++ /dev/null @@ -1 +0,0 @@ -"?" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-317 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-317 deleted file mode 100644 index ace4a897d33..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-317 +++ /dev/null @@ -1 +0,0 @@ -sU \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-318 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-318 deleted file mode 100644 index feffb7061b3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-318 +++ /dev/null @@ -1 +0,0 @@ -"VH2&H\\\/" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-319 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-319 deleted file mode 100644 index 8223f1e51e3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-319 +++ /dev/null @@ -1 +0,0 @@ -_C \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-32 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-32 deleted file mode 100644 index 7e85c4bdfe9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-32 +++ /dev/null @@ -1 +0,0 @@ -foo[?first == last].first \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-320 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-320 deleted file mode 100644 index c9cdc63b070..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-320 +++ /dev/null @@ -1 +0,0 @@ -_ \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-321 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-321 deleted file mode 100644 index c82f7982ee0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-321 +++ /dev/null @@ -1 +0,0 @@ -"<\t" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-322 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-322 deleted file mode 100644 index dae65c51554..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-322 +++ /dev/null @@ -1 +0,0 @@ -"\uD834\uDD1E" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-323 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-323 deleted file mode 100644 index b6b3695438a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-323 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-324 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-324 deleted file mode 100644 index bf06e678c15..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-324 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-325 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-325 deleted file mode 100644 index 5d48e0205ce..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-325 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-326 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-326 deleted file mode 100644 index de3af7230f9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-326 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[3] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-327 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-327 deleted file mode 100644 index a1c33350841..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-327 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-328 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-328 deleted file mode 100644 index ad0fef91cfa..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-328 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[-2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-329 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-329 deleted file mode 100644 index 3e83c6f7306..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-329 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[-3] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-33 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-33 deleted file mode 100644 index 72fc0a53e79..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-33 +++ /dev/null @@ -1 +0,0 @@ -foo[?age > `25`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-330 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-330 deleted file mode 100644 index 433a737d65e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-330 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[-4] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-331 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-331 deleted file mode 100644 index 4d5f9756e55..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-331 +++ /dev/null @@ -1 +0,0 @@ -foo.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-332 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-332 deleted file mode 100644 index 5e0d9b71772..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-332 +++ /dev/null @@ -1 +0,0 @@ -foo[0].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-333 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-333 deleted file mode 100644 index 3cd7e9460fe..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-333 +++ /dev/null @@ -1 +0,0 @@ -foo[1].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-334 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-334 deleted file mode 100644 index 74cb1765558..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-334 +++ /dev/null @@ -1 +0,0 @@ -foo[2].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-335 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-335 deleted file mode 100644 index 3cf2007f70d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-335 +++ /dev/null @@ -1 +0,0 @@ -foo[3].notbar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-336 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-336 deleted file mode 100644 index 9674d880375..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-336 +++ /dev/null @@ -1 +0,0 @@ -foo[3].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-337 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-337 deleted file mode 100644 index 9b0b2f8189b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-337 +++ /dev/null @@ -1 +0,0 @@ -foo[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-338 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-338 deleted file mode 100644 index 83c639a185b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-338 +++ /dev/null @@ -1 +0,0 @@ -foo[1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-339 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-339 deleted file mode 100644 index 3b76c9f64a4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-339 +++ /dev/null @@ -1 +0,0 @@ -foo[2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-34 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-34 deleted file mode 100644 index 9a2b0184edf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-34 +++ /dev/null @@ -1 +0,0 @@ -foo[?age >= `25`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-340 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-340 deleted file mode 100644 index ff99e045d2e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-340 +++ /dev/null @@ -1 +0,0 @@ -foo[3] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-341 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-341 deleted file mode 100644 index 040ecb240c8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-341 +++ /dev/null @@ -1 +0,0 @@ -foo[4] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-342 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-342 deleted file mode 100644 index 6e7ea636eec..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-342 +++ /dev/null @@ -1 +0,0 @@ -[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-343 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-343 deleted file mode 100644 index bace2a0be17..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-343 +++ /dev/null @@ -1 +0,0 @@ -[1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-344 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-344 deleted file mode 100644 index 5d50c80c068..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-344 +++ /dev/null @@ -1 +0,0 @@ -[2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-345 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-345 deleted file mode 100644 index 99d21a2a0f0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-345 +++ /dev/null @@ -1 +0,0 @@ -[-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-346 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-346 deleted file mode 100644 index 133a9c6272f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-346 +++ /dev/null @@ -1 +0,0 @@ -[-2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-347 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-347 deleted file mode 100644 index b7f78c5dc51..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-347 +++ /dev/null @@ -1 +0,0 @@ -[-3] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-348 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-348 deleted file mode 100644 index bd9de815f45..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-348 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-349 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-349 deleted file mode 100644 index 55e6257352f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-349 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-35 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-35 deleted file mode 100644 index fa83f1da3b7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-35 +++ /dev/null @@ -1 +0,0 @@ -foo[?age > `30`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-350 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-350 deleted file mode 100644 index 1661747c04d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-350 +++ /dev/null @@ -1 +0,0 @@ -reservations[].notinstances[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-351 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-351 deleted file mode 100644 index 1661747c04d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-351 +++ /dev/null @@ -1 +0,0 @@ -reservations[].notinstances[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-352 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-352 deleted file mode 100644 index 3debc70f895..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-352 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].foo[].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-353 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-353 deleted file mode 100644 index 75af2fda069..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-353 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].foo[].baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-354 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-354 deleted file mode 100644 index 4a70cd8a03c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-354 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].notfoo[].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-355 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-355 deleted file mode 100644 index 987985b002f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-355 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].notfoo[].notbar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-356 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-356 deleted file mode 100644 index 1661747c04d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-356 +++ /dev/null @@ -1 +0,0 @@ -reservations[].notinstances[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-357 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-357 deleted file mode 100644 index 634f937e555..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-357 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].foo[].notbar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-358 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-358 deleted file mode 100644 index 09cb7b8bb1b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-358 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].bar[].baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-359 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-359 deleted file mode 100644 index f5d9ac5b763..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-359 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].baz[].baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-36 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-36 deleted file mode 100644 index 463a2a542db..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-36 +++ /dev/null @@ -1 +0,0 @@ -foo[?age < `25`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-360 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-360 deleted file mode 100644 index d1016d6e75b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-360 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].qux[].baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-361 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-361 deleted file mode 100644 index ef54cf52d67..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-361 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].qux[].baz[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-362 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-362 deleted file mode 100644 index bea506ff235..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-362 +++ /dev/null @@ -1 +0,0 @@ -foo[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-363 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-363 deleted file mode 100644 index 20dd081e0e4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-363 +++ /dev/null @@ -1 +0,0 @@ -foo[][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-364 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-364 deleted file mode 100644 index 4803734b09e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-364 +++ /dev/null @@ -1 +0,0 @@ -foo[][1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-365 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-365 deleted file mode 100644 index 1be56598534..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-365 +++ /dev/null @@ -1 +0,0 @@ -foo[][0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-366 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-366 deleted file mode 100644 index d2cf6da59fe..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-366 +++ /dev/null @@ -1 +0,0 @@ -foo[][2][2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-367 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-367 deleted file mode 100644 index c609ca64b16..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-367 +++ /dev/null @@ -1 +0,0 @@ -foo[][0][0][100] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-368 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-368 deleted file mode 100644 index 19102815663..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-368 +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-369 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-369 deleted file mode 100644 index bea506ff235..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-369 +++ /dev/null @@ -1 +0,0 @@ -foo[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-37 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-37 deleted file mode 100644 index 10ed5d3f61f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-37 +++ /dev/null @@ -1 +0,0 @@ -foo[?age <= `25`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-370 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-370 deleted file mode 100644 index 13f2c4a0b4f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-370 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-371 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-371 deleted file mode 100644 index edf3d92775d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-371 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-372 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-372 deleted file mode 100644 index 2a3b993af24..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-372 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar[].baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-373 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-373 deleted file mode 100644 index d5ca878a13b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-373 +++ /dev/null @@ -1 +0,0 @@ -string[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-374 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-374 deleted file mode 100644 index fcd255f5d0c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-374 +++ /dev/null @@ -1 +0,0 @@ -hash[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-375 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-375 deleted file mode 100644 index 2d53bd7cdcd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-375 +++ /dev/null @@ -1 +0,0 @@ -number[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-376 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-376 deleted file mode 100644 index cb10d2497e1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-376 +++ /dev/null @@ -1 +0,0 @@ -nullvalue[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-377 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-377 deleted file mode 100644 index f6c79ca84ff..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-377 +++ /dev/null @@ -1 +0,0 @@ -string[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-378 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-378 deleted file mode 100644 index 09bf36e8a90..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-378 +++ /dev/null @@ -1 +0,0 @@ -hash[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-379 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-379 deleted file mode 100644 index 4c357818919..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-379 +++ /dev/null @@ -1 +0,0 @@ -number[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-38 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-38 deleted file mode 100644 index 16a4c36acbd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-38 +++ /dev/null @@ -1 +0,0 @@ -foo[?age < `20`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-380 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-380 deleted file mode 100644 index 2dd8ae21855..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-380 +++ /dev/null @@ -1 +0,0 @@ -nullvalue[].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-381 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-381 deleted file mode 100644 index dfed8160389..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-381 +++ /dev/null @@ -1 +0,0 @@ -nullvalue[].foo[].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-382 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-382 deleted file mode 100644 index d7628e646e1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-382 +++ /dev/null @@ -1 +0,0 @@ -`"foo"` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-383 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-383 deleted file mode 100644 index 49c5269b12e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-383 +++ /dev/null @@ -1 +0,0 @@ -`"\u03a6"` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-384 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-384 deleted file mode 100644 index d5db721d012..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-384 +++ /dev/null @@ -1 +0,0 @@ -`"✓"` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-385 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-385 deleted file mode 100644 index a2b6e4ec85d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-385 +++ /dev/null @@ -1 +0,0 @@ -`[1, 2, 3]` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-386 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-386 deleted file mode 100644 index f5801bdd680..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-386 +++ /dev/null @@ -1 +0,0 @@ -`{"a": "b"}` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-387 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-387 deleted file mode 100644 index f87db59a8b7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-387 +++ /dev/null @@ -1 +0,0 @@ -`true` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-388 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-388 deleted file mode 100644 index 3b20d905f33..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-388 +++ /dev/null @@ -1 +0,0 @@ -`false` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-389 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-389 deleted file mode 100644 index 70bcd29a7a8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-389 +++ /dev/null @@ -1 +0,0 @@ -`null` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-39 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-39 deleted file mode 100644 index 351054d3e61..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-39 +++ /dev/null @@ -1 +0,0 @@ -foo[?age == `20`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-390 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-390 deleted file mode 100644 index 0918d41559b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-390 +++ /dev/null @@ -1 +0,0 @@ -`0` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-391 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-391 deleted file mode 100644 index ef70c4c11e7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-391 +++ /dev/null @@ -1 +0,0 @@ -`1` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-392 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-392 deleted file mode 100644 index b39a922f403..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-392 +++ /dev/null @@ -1 +0,0 @@ -`2` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-393 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-393 deleted file mode 100644 index 7e65687dbfc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-393 +++ /dev/null @@ -1 +0,0 @@ -`3` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-394 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-394 deleted file mode 100644 index 770d1ece705..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-394 +++ /dev/null @@ -1 +0,0 @@ -`4` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-395 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-395 deleted file mode 100644 index a8b81985c76..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-395 +++ /dev/null @@ -1 +0,0 @@ -`5` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-396 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-396 deleted file mode 100644 index 7f0861065e7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-396 +++ /dev/null @@ -1 +0,0 @@ -`6` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-397 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-397 deleted file mode 100644 index 495114d919e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-397 +++ /dev/null @@ -1 +0,0 @@ -`7` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-398 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-398 deleted file mode 100644 index 94f355c46ca..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-398 +++ /dev/null @@ -1 +0,0 @@ -`8` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-399 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-399 deleted file mode 100644 index 600d2aa3f49..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-399 +++ /dev/null @@ -1 +0,0 @@ -`9` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-4 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-4 deleted file mode 100644 index 31485223580..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-4 +++ /dev/null @@ -1 +0,0 @@ -foo.bar.baz.bad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-40 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-40 deleted file mode 100644 index 99d9258a625..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-40 +++ /dev/null @@ -1 +0,0 @@ -foo[?age != `20`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-400 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-400 deleted file mode 100644 index 637015b5fde..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-400 +++ /dev/null @@ -1 +0,0 @@ -`"foo\`bar"` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-401 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-401 deleted file mode 100644 index 6fa7557b8d8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-401 +++ /dev/null @@ -1 +0,0 @@ -`"foo\"bar"` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-402 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-402 deleted file mode 100644 index 5aabeec3419..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-402 +++ /dev/null @@ -1 +0,0 @@ -`"1\`"` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-403 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-403 deleted file mode 100644 index 8302ea1984d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-403 +++ /dev/null @@ -1 +0,0 @@ -`"\\"`.{a:`"b"`} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-404 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-404 deleted file mode 100644 index d88d014a96c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-404 +++ /dev/null @@ -1 +0,0 @@ -`{"a": "b"}`.a \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-405 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-405 deleted file mode 100644 index 47152dddb73..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-405 +++ /dev/null @@ -1 +0,0 @@ -`{"a": {"b": "c"}}`.a.b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-406 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-406 deleted file mode 100644 index 895d4293878..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-406 +++ /dev/null @@ -1 +0,0 @@ -`[0, 1, 2]`[1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-407 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-407 deleted file mode 100644 index 42500a368cc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-407 +++ /dev/null @@ -1 +0,0 @@ -` {"foo": true}` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-408 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-408 deleted file mode 100644 index 08b944dad4a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-408 +++ /dev/null @@ -1 +0,0 @@ -`{"foo": true} ` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-409 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-409 deleted file mode 100644 index 6de163f80bc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-409 +++ /dev/null @@ -1 +0,0 @@ -'foo' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-41 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-41 deleted file mode 100644 index 5bc357d9fa6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-41 +++ /dev/null @@ -1 +0,0 @@ -foo[?top.name == 'a'] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-410 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-410 deleted file mode 100644 index b84bbdb29fb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-410 +++ /dev/null @@ -1 +0,0 @@ -' foo ' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-411 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-411 deleted file mode 100644 index bf6a07ace3d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-411 +++ /dev/null @@ -1 +0,0 @@ -'0' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-412 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-412 deleted file mode 100644 index c742f5b0c97..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-412 +++ /dev/null @@ -1,2 +0,0 @@ -'newline -' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-413 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-413 deleted file mode 100644 index 04e9b3ade60..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-413 +++ /dev/null @@ -1,2 +0,0 @@ -' -' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-414 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-414 deleted file mode 100644 index ebdaf120d7b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-414 +++ /dev/null @@ -1 +0,0 @@ -'✓' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-415 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-415 deleted file mode 100644 index d0ba5d7facb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-415 +++ /dev/null @@ -1 +0,0 @@ -'𝄞' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-416 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-416 deleted file mode 100644 index 19c2e2ef41c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-416 +++ /dev/null @@ -1 +0,0 @@ -' [foo] ' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-417 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-417 deleted file mode 100644 index 5faa483b197..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-417 +++ /dev/null @@ -1 +0,0 @@ -'[foo]' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-418 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-418 deleted file mode 100644 index e3c05c163a3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-418 +++ /dev/null @@ -1 +0,0 @@ -'\u03a6' \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-419 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-419 deleted file mode 100644 index 7c13861ac72..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-419 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar: bar} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-42 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-42 deleted file mode 100644 index d037a0a4ddf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-42 +++ /dev/null @@ -1 +0,0 @@ -foo[?top.first == top.last] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-420 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-420 deleted file mode 100644 index f795c255219..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-420 +++ /dev/null @@ -1 +0,0 @@ -foo.{"bar": bar} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-421 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-421 deleted file mode 100644 index 772c45639cc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-421 +++ /dev/null @@ -1 +0,0 @@ -foo.{"foo.bar": bar} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-422 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-422 deleted file mode 100644 index 8808e92bf31..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-422 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar: bar, baz: baz} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-423 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-423 deleted file mode 100644 index 3f13757a10c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-423 +++ /dev/null @@ -1 +0,0 @@ -foo.{"bar": bar, "baz": baz} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-424 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-424 deleted file mode 100644 index 23cd8903e73..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-424 +++ /dev/null @@ -1 +0,0 @@ -{"baz": baz, "qux\"": "qux\""} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-425 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-425 deleted file mode 100644 index fabb6da4fe8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-425 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar:bar,baz:baz} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-426 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-426 deleted file mode 100644 index 4c3f615b1cd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-426 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar: bar,qux: qux} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-427 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-427 deleted file mode 100644 index 8bc46535ac5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-427 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar: bar, noexist: noexist} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-428 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-428 deleted file mode 100644 index 2024b6f118d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-428 +++ /dev/null @@ -1 +0,0 @@ -foo.{noexist: noexist, alsonoexist: alsonoexist} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-429 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-429 deleted file mode 100644 index b52191d10a4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-429 +++ /dev/null @@ -1 +0,0 @@ -foo.badkey.{nokey: nokey, alsonokey: alsonokey} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-43 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-43 deleted file mode 100644 index 8534a5cae9f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-43 +++ /dev/null @@ -1 +0,0 @@ -foo[?top == `{"first": "foo", "last": "bar"}`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-430 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-430 deleted file mode 100644 index 5cd310b6d24..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-430 +++ /dev/null @@ -1 +0,0 @@ -foo.nested.*.{a: a,b: b} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-431 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-431 deleted file mode 100644 index 0b24ef53526..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-431 +++ /dev/null @@ -1 +0,0 @@ -foo.nested.three.{a: a, cinner: c.inner} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-432 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-432 deleted file mode 100644 index 473c1c351b4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-432 +++ /dev/null @@ -1 +0,0 @@ -foo.nested.three.{a: a, c: c.inner.bad.key} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-433 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-433 deleted file mode 100644 index 44ba735ab10..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-433 +++ /dev/null @@ -1 +0,0 @@ -foo.{a: nested.one.a, b: nested.two.b} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-434 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-434 deleted file mode 100644 index f5f89b12b5c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-434 +++ /dev/null @@ -1 +0,0 @@ -{bar: bar, baz: baz} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-435 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-435 deleted file mode 100644 index 697764cb306..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-435 +++ /dev/null @@ -1 +0,0 @@ -{bar: bar} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-436 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-436 deleted file mode 100644 index 20447fb1054..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-436 +++ /dev/null @@ -1 +0,0 @@ -{otherkey: bar} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-437 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-437 deleted file mode 100644 index 310b9b1dd27..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-437 +++ /dev/null @@ -1 +0,0 @@ -{no: no, exist: exist} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-438 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-438 deleted file mode 100644 index c79b2e24068..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-438 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-439 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-439 deleted file mode 100644 index ab498ef654c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-439 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,baz] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-44 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-44 deleted file mode 100644 index 71307c40947..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-44 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `true`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-440 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-440 deleted file mode 100644 index 4b8f39a468e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-440 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,qux] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-441 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-441 deleted file mode 100644 index b8f9020f8e7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-441 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,noexist] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-442 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-442 deleted file mode 100644 index b7c7b3f6556..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-442 +++ /dev/null @@ -1 +0,0 @@ -foo.[noexist,alsonoexist] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-443 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-443 deleted file mode 100644 index fabb6da4fe8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-443 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar:bar,baz:baz} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-444 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-444 deleted file mode 100644 index c15c39f82c1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-444 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,baz[0]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-445 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-445 deleted file mode 100644 index 9cebd89844f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-445 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,baz[1]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-446 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-446 deleted file mode 100644 index c5bbfbf848f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-446 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,baz[2]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-447 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-447 deleted file mode 100644 index d81cb2b9041..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-447 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,baz[3]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-448 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-448 deleted file mode 100644 index 3a65aa7d6f1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-448 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar[0],baz[3]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-449 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-449 deleted file mode 100644 index 8808e92bf31..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-449 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar: bar, baz: baz} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-45 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-45 deleted file mode 100644 index e142b22a25f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-45 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `false`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-450 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-450 deleted file mode 100644 index ab498ef654c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-450 +++ /dev/null @@ -1 +0,0 @@ -foo.[bar,baz] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-451 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-451 deleted file mode 100644 index 8e3d22dc53f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-451 +++ /dev/null @@ -1 +0,0 @@ -foo.{bar: bar.baz[1],includeme: includeme} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-452 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-452 deleted file mode 100644 index 398c7f8b06e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-452 +++ /dev/null @@ -1 +0,0 @@ -foo.{"bar.baz.two": bar.baz[1].two, includeme: includeme} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-453 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-453 deleted file mode 100644 index a1764448785..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-453 +++ /dev/null @@ -1 +0,0 @@ -foo.[includeme, bar.baz[*].common] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-454 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-454 deleted file mode 100644 index da5225ddccb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-454 +++ /dev/null @@ -1 +0,0 @@ -foo.[includeme, bar.baz[*].none] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-455 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-455 deleted file mode 100644 index a8870b22bcc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-455 +++ /dev/null @@ -1 +0,0 @@ -foo.[includeme, bar.baz[].common] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-456 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-456 deleted file mode 100644 index 420b1a57c45..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-456 +++ /dev/null @@ -1 +0,0 @@ -reservations[*].instances[*].{id: id, name: name} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-457 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-457 deleted file mode 100644 index 0761ee16dc0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-457 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].{id: id, name: name} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-458 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-458 deleted file mode 100644 index aa1191a48cd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-458 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[].[id, name] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-459 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-459 deleted file mode 100644 index 19102815663..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-459 +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-46 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-46 deleted file mode 100644 index 9a24a464eed..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-46 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `0`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-460 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-460 deleted file mode 100644 index bea506ff235..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-460 +++ /dev/null @@ -1 +0,0 @@ -foo[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-461 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-461 deleted file mode 100644 index 13f2c4a0b4f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-461 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-462 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-462 deleted file mode 100644 index edf3d92775d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-462 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-463 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-463 deleted file mode 100644 index d965466e91c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-463 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar[].[baz, qux] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-464 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-464 deleted file mode 100644 index f1822a1742b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-464 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar[].[baz] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-465 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-465 deleted file mode 100644 index c6f77b80c33..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-465 +++ /dev/null @@ -1 +0,0 @@ -foo[].bar[].[baz, qux][] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-466 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-466 deleted file mode 100644 index db56262a4ea..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-466 +++ /dev/null @@ -1 +0,0 @@ -foo.[baz[*].bar, qux[0]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-467 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-467 deleted file mode 100644 index b901067d271..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-467 +++ /dev/null @@ -1 +0,0 @@ -foo.[baz[*].[bar, boo], qux[0]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-468 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-468 deleted file mode 100644 index 738479fa69b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-468 +++ /dev/null @@ -1 +0,0 @@ -foo.[baz[*].not_there || baz[*].bar, qux[0]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-469 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-469 deleted file mode 100644 index 6926996a7b6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-469 +++ /dev/null @@ -1 +0,0 @@ -[[*],*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-47 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-47 deleted file mode 100644 index 6d33cc72c4e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-47 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `1`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-470 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-470 deleted file mode 100644 index 736be0a31f2..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-470 +++ /dev/null @@ -1 +0,0 @@ -[[*]] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-471 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-471 deleted file mode 100644 index 29e1fb20a55..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-471 +++ /dev/null @@ -1 +0,0 @@ -outer.foo || outer.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-472 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-472 deleted file mode 100644 index c0070ba783a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-472 +++ /dev/null @@ -1 +0,0 @@ -outer.foo||outer.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-473 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-473 deleted file mode 100644 index 661b0bec5e3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-473 +++ /dev/null @@ -1 +0,0 @@ -outer.bar || outer.baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-474 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-474 deleted file mode 100644 index 296d5aeee16..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-474 +++ /dev/null @@ -1 +0,0 @@ -outer.bar||outer.baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-475 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-475 deleted file mode 100644 index ca140f8aa33..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-475 +++ /dev/null @@ -1 +0,0 @@ -outer.bad || outer.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-476 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-476 deleted file mode 100644 index 15d30924274..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-476 +++ /dev/null @@ -1 +0,0 @@ -outer.bad||outer.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-477 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-477 deleted file mode 100644 index 56148d957b7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-477 +++ /dev/null @@ -1 +0,0 @@ -outer.foo || outer.bad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-478 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-478 deleted file mode 100644 index 6d3cf6d9069..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-478 +++ /dev/null @@ -1 +0,0 @@ -outer.foo||outer.bad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-479 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-479 deleted file mode 100644 index 100fa8339d5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-479 +++ /dev/null @@ -1 +0,0 @@ -outer.bad || outer.alsobad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-48 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-48 deleted file mode 100644 index de56fc042cb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-48 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `[0]`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-480 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-480 deleted file mode 100644 index 64490352bf0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-480 +++ /dev/null @@ -1 +0,0 @@ -outer.bad||outer.alsobad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-481 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-481 deleted file mode 100644 index af901bde17e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-481 +++ /dev/null @@ -1 +0,0 @@ -outer.empty_string || outer.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-482 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-482 deleted file mode 100644 index 36b63e462c4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-482 +++ /dev/null @@ -1 +0,0 @@ -outer.nokey || outer.bool || outer.empty_list || outer.empty_string || outer.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-483 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-483 deleted file mode 100644 index aba584f99ed..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-483 +++ /dev/null @@ -1 +0,0 @@ -foo.*.baz | [0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-484 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-484 deleted file mode 100644 index 4234ac01922..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-484 +++ /dev/null @@ -1 +0,0 @@ -foo.*.baz | [1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-485 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-485 deleted file mode 100644 index 12330d9902c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-485 +++ /dev/null @@ -1 +0,0 @@ -foo.*.baz | [2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-486 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-486 deleted file mode 100644 index 1b2d93e1952..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-486 +++ /dev/null @@ -1 +0,0 @@ -foo.bar.* | [0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-487 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-487 deleted file mode 100644 index c371fc6457a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-487 +++ /dev/null @@ -1 +0,0 @@ -foo.*.notbaz | [*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-488 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-488 deleted file mode 100644 index 3c835642eb2..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-488 +++ /dev/null @@ -1 +0,0 @@ -foo | bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-489 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-489 deleted file mode 100644 index decaa0421d6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-489 +++ /dev/null @@ -1 +0,0 @@ -foo | bar | baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-49 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-49 deleted file mode 100644 index 49d9c63a390..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-49 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `{"bar": [0]}`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-490 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-490 deleted file mode 100644 index b91068037b1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-490 +++ /dev/null @@ -1 +0,0 @@ -foo|bar| baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-491 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-491 deleted file mode 100644 index 11df74d8b46..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-491 +++ /dev/null @@ -1 +0,0 @@ -not_there | [0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-492 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-492 deleted file mode 100644 index 11df74d8b46..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-492 +++ /dev/null @@ -1 +0,0 @@ -not_there | [0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-493 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-493 deleted file mode 100644 index 37da9fc0b71..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-493 +++ /dev/null @@ -1 +0,0 @@ -[foo.bar, foo.other] | [0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-494 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-494 deleted file mode 100644 index 1f4fc943d70..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-494 +++ /dev/null @@ -1 +0,0 @@ -{"a": foo.bar, "b": foo.other} | a \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-495 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-495 deleted file mode 100644 index 67c7ea9cfe4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-495 +++ /dev/null @@ -1 +0,0 @@ -{"a": foo.bar, "b": foo.other} | b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-496 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-496 deleted file mode 100644 index d87f9bba4cd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-496 +++ /dev/null @@ -1 +0,0 @@ -{"a": foo.bar, "b": foo.other} | *.baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-497 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-497 deleted file mode 100644 index ebf8e271140..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-497 +++ /dev/null @@ -1 +0,0 @@ -foo.bam || foo.bar | baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-498 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-498 deleted file mode 100644 index f32bc6db510..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-498 +++ /dev/null @@ -1 +0,0 @@ -foo | not_there || bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-499 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-499 deleted file mode 100644 index d04459d9090..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-499 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[*] | [0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-5 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-5 deleted file mode 100644 index b537264a1d5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-5 +++ /dev/null @@ -1 +0,0 @@ -foo.bar.bad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-50 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-50 deleted file mode 100644 index c17c1df1706..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-50 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `null`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-500 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-500 deleted file mode 100644 index 3eb869f435b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-500 +++ /dev/null @@ -1 +0,0 @@ -bar[0:10] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-501 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-501 deleted file mode 100644 index aa5d6be52c7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-501 +++ /dev/null @@ -1 +0,0 @@ -foo[0:10:1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-502 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-502 deleted file mode 100644 index 1a4d1682da0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-502 +++ /dev/null @@ -1 +0,0 @@ -foo[0:10] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-503 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-503 deleted file mode 100644 index 5925a578b52..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-503 +++ /dev/null @@ -1 +0,0 @@ -foo[0:10:] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-504 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-504 deleted file mode 100644 index 081e93abd98..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-504 +++ /dev/null @@ -1 +0,0 @@ -foo[0::1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-505 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-505 deleted file mode 100644 index 92270014959..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-505 +++ /dev/null @@ -1 +0,0 @@ -foo[0::] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-506 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-506 deleted file mode 100644 index fd2294d6646..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-506 +++ /dev/null @@ -1 +0,0 @@ -foo[0:] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-507 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-507 deleted file mode 100644 index c6b551d5eae..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-507 +++ /dev/null @@ -1 +0,0 @@ -foo[:10:1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-508 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-508 deleted file mode 100644 index 503f58da6e3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-508 +++ /dev/null @@ -1 +0,0 @@ -foo[::1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-509 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-509 deleted file mode 100644 index f78bb770caa..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-509 +++ /dev/null @@ -1 +0,0 @@ -foo[:10:] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-51 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-51 deleted file mode 100644 index 589a214f453..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-51 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `[1]`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-510 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-510 deleted file mode 100644 index eb9d2ba881e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-510 +++ /dev/null @@ -1 +0,0 @@ -foo[::] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-511 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-511 deleted file mode 100644 index 1921a3d9865..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-511 +++ /dev/null @@ -1 +0,0 @@ -foo[:] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-512 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-512 deleted file mode 100644 index a87afcb1b32..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-512 +++ /dev/null @@ -1 +0,0 @@ -foo[1:9] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-513 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-513 deleted file mode 100644 index dbf51d8cde4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-513 +++ /dev/null @@ -1 +0,0 @@ -foo[0:10:2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-514 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-514 deleted file mode 100644 index f7288763a71..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-514 +++ /dev/null @@ -1 +0,0 @@ -foo[5:] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-515 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-515 deleted file mode 100644 index 64395761df6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-515 +++ /dev/null @@ -1 +0,0 @@ -foo[5::2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-516 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-516 deleted file mode 100644 index 706bb14dd7e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-516 +++ /dev/null @@ -1 +0,0 @@ -foo[::2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-517 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-517 deleted file mode 100644 index 8fcfaee95c6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-517 +++ /dev/null @@ -1 +0,0 @@ -foo[::-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-518 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-518 deleted file mode 100644 index f6a00bf9bbc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-518 +++ /dev/null @@ -1 +0,0 @@ -foo[1::2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-519 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-519 deleted file mode 100644 index ea068ee06fb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-519 +++ /dev/null @@ -1 +0,0 @@ -foo[10:0:-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-52 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-52 deleted file mode 100644 index 214917ac068..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-52 +++ /dev/null @@ -1 +0,0 @@ -foo[?key == `{"a":2}`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-520 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-520 deleted file mode 100644 index 1fe14258edc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-520 +++ /dev/null @@ -1 +0,0 @@ -foo[10:5:-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-521 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-521 deleted file mode 100644 index 4ba0e130228..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-521 +++ /dev/null @@ -1 +0,0 @@ -foo[8:2:-2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-522 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-522 deleted file mode 100644 index 25db439ff7d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-522 +++ /dev/null @@ -1 +0,0 @@ -foo[0:20] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-523 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-523 deleted file mode 100644 index 8a965920af5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-523 +++ /dev/null @@ -1 +0,0 @@ -foo[10:-20:-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-524 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-524 deleted file mode 100644 index b1e5ba3734f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-524 +++ /dev/null @@ -1 +0,0 @@ -foo[10:-20] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-525 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-525 deleted file mode 100644 index 06253112e4e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-525 +++ /dev/null @@ -1 +0,0 @@ -foo[-4:-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-526 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-526 deleted file mode 100644 index 1e14a6a4c5e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-526 +++ /dev/null @@ -1 +0,0 @@ -foo[:-5:-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-527 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-527 deleted file mode 100644 index aef5c2747d2..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-527 +++ /dev/null @@ -1 +0,0 @@ -foo[:2].a \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-528 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-528 deleted file mode 100644 index 93c95fcf689..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-528 +++ /dev/null @@ -1 +0,0 @@ -foo[:2].b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-529 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-529 deleted file mode 100644 index 7e0733e595e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-529 +++ /dev/null @@ -1 +0,0 @@ -foo[:2].a.b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-53 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-53 deleted file mode 100644 index 4c002ed80d6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-53 +++ /dev/null @@ -1 +0,0 @@ -foo[?`true` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-530 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-530 deleted file mode 100644 index 2438b25762d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-530 +++ /dev/null @@ -1 +0,0 @@ -bar[::-1].a.b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-531 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-531 deleted file mode 100644 index 549994b6bc4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-531 +++ /dev/null @@ -1 +0,0 @@ -bar[:2].a.b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-532 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-532 deleted file mode 100644 index ab98292b452..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-532 +++ /dev/null @@ -1 +0,0 @@ -baz[:2].a \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-533 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-533 deleted file mode 100644 index 65fca968764..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-533 +++ /dev/null @@ -1 +0,0 @@ -[:] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-534 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-534 deleted file mode 100644 index 18c5daf7bea..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-534 +++ /dev/null @@ -1 +0,0 @@ -[:2].a \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-535 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-535 deleted file mode 100644 index 1bb84f7d4bd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-535 +++ /dev/null @@ -1 +0,0 @@ -[::-1].a \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-536 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-536 deleted file mode 100644 index 7a0416f0566..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-536 +++ /dev/null @@ -1 +0,0 @@ -[:2].b \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-537 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-537 deleted file mode 100644 index 4d5f9756e55..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-537 +++ /dev/null @@ -1 +0,0 @@ -foo.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-538 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-538 deleted file mode 100644 index 19102815663..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-538 +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-539 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-539 deleted file mode 100644 index f59ec20aabf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-539 +++ /dev/null @@ -1 +0,0 @@ -* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-54 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-54 deleted file mode 100644 index 23d27073e97..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-54 +++ /dev/null @@ -1 +0,0 @@ -foo[?`false` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-540 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-540 deleted file mode 100644 index dee5695746e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-540 +++ /dev/null @@ -1 +0,0 @@ -*.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-541 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-541 deleted file mode 100644 index 1a16f7418d2..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-541 +++ /dev/null @@ -1 +0,0 @@ -*.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-542 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-542 deleted file mode 100644 index 7e8066d39f5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-542 +++ /dev/null @@ -1 +0,0 @@ -*[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-543 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-543 deleted file mode 100644 index 0637a088a01..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-543 +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-544 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-544 deleted file mode 100644 index 6e7ea636eec..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-544 +++ /dev/null @@ -1 +0,0 @@ -[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-545 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-545 deleted file mode 100644 index 5a5194647ad..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-545 +++ /dev/null @@ -1 +0,0 @@ -[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-546 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-546 deleted file mode 100644 index 416127425c2..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-546 +++ /dev/null @@ -1 +0,0 @@ -*.["0"] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-547 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-547 deleted file mode 100644 index cd9fb6ba778..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-547 +++ /dev/null @@ -1 +0,0 @@ -[*].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-548 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-548 deleted file mode 100644 index 9f3ada48077..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-548 +++ /dev/null @@ -1 +0,0 @@ -[*][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-549 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-549 deleted file mode 100644 index 9b0b2f8189b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-549 +++ /dev/null @@ -1 +0,0 @@ -foo[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-55 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-55 deleted file mode 100644 index 6d840ee568f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-55 +++ /dev/null @@ -1 +0,0 @@ -foo[?`0` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-550 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-550 deleted file mode 100644 index b23413b92af..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-550 +++ /dev/null @@ -1 +0,0 @@ -foo.[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-551 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-551 deleted file mode 100644 index 08ab2e1c420..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-551 +++ /dev/null @@ -1 +0,0 @@ -foo.[abc] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-552 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-552 deleted file mode 100644 index 78b05a5c64e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-552 +++ /dev/null @@ -1 +0,0 @@ -foo.[abc, def] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-553 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-553 deleted file mode 100644 index 1e7b886e79e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-553 +++ /dev/null @@ -1 +0,0 @@ -a.{foo: bar} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-554 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-554 deleted file mode 100644 index 91b4c9896e1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-554 +++ /dev/null @@ -1 +0,0 @@ -a.{foo: bar, baz: bam} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-555 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-555 deleted file mode 100644 index 8301ef981ef..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-555 +++ /dev/null @@ -1 +0,0 @@ -{"\\":{" ":*}} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-556 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-556 deleted file mode 100644 index 8f75cc91334..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-556 +++ /dev/null @@ -1 +0,0 @@ -foo || bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-557 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-557 deleted file mode 100644 index e5f122c5691..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-557 +++ /dev/null @@ -1 +0,0 @@ -foo.[a || b] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-558 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-558 deleted file mode 100644 index 39d1914328b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-558 +++ /dev/null @@ -1 +0,0 @@ -foo[?bar==`"baz"`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-559 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-559 deleted file mode 100644 index d08bbe2501e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-559 +++ /dev/null @@ -1 +0,0 @@ -foo[? bar == `"baz"` ] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-56 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-56 deleted file mode 100644 index addaf204c5b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-56 +++ /dev/null @@ -1 +0,0 @@ -foo[?`1` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-560 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-560 deleted file mode 100644 index a77f355812c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-560 +++ /dev/null @@ -1 +0,0 @@ -foo[?a.b.c==d.e.f] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-561 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-561 deleted file mode 100644 index c9697aa4870..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-561 +++ /dev/null @@ -1 +0,0 @@ -foo[?bar==`[0, 1, 2]`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-562 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-562 deleted file mode 100644 index fd7064a0868..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-562 +++ /dev/null @@ -1 +0,0 @@ -foo[?bar==`["a", "b", "c"]`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-563 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-563 deleted file mode 100644 index 61e5e1b8f71..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-563 +++ /dev/null @@ -1 +0,0 @@ -foo[?bar==`["foo\`bar"]`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-564 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-564 deleted file mode 100644 index bc9d8af1d92..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-564 +++ /dev/null @@ -1 +0,0 @@ -[?"\\">`"foo"`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-565 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-565 deleted file mode 100644 index 2dd54dc3904..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-565 +++ /dev/null @@ -1 +0,0 @@ -[?"\\" > `"foo"`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-566 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-566 deleted file mode 100644 index 19102815663..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-566 +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-567 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-567 deleted file mode 100644 index 7e9668e7834..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-567 +++ /dev/null @@ -1 +0,0 @@ -"foo" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-568 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-568 deleted file mode 100644 index d58ac16bf03..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-568 +++ /dev/null @@ -1 +0,0 @@ -"\\" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-569 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-569 deleted file mode 100644 index 33ac9fba6ff..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-569 +++ /dev/null @@ -1 +0,0 @@ -*||*|*|* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-57 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-57 deleted file mode 100644 index acf2435c7cb..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-57 +++ /dev/null @@ -1 +0,0 @@ -foo[?`[0]` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-570 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-570 deleted file mode 100644 index 99e19638ce4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-570 +++ /dev/null @@ -1 +0,0 @@ -*[]||[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-571 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-571 deleted file mode 100644 index be0845011c3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-571 +++ /dev/null @@ -1 +0,0 @@ -[*.*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-572 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-572 deleted file mode 100644 index a84b51e1cda..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-572 +++ /dev/null @@ -1 +0,0 @@ -foo[]."✓" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-573 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-573 deleted file mode 100644 index c2de55815f0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-573 +++ /dev/null @@ -1 +0,0 @@ -"☯" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-574 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-574 deleted file mode 100644 index dc2dda0bb68..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-574 +++ /dev/null @@ -1 +0,0 @@ -"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-575 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-575 deleted file mode 100644 index a2d3d5f6ae0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-575 +++ /dev/null @@ -1 +0,0 @@ -"☃" \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-576 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-576 deleted file mode 100644 index 0971c37eaf7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-576 +++ /dev/null @@ -1 +0,0 @@ -foo.*.baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-577 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-577 deleted file mode 100644 index 0e39dfd695d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-577 +++ /dev/null @@ -1 +0,0 @@ -foo.bar.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-578 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-578 deleted file mode 100644 index 89c1ce22dc7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-578 +++ /dev/null @@ -1 +0,0 @@ -foo.*.notbaz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-579 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-579 deleted file mode 100644 index 5199b9f95d4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-579 +++ /dev/null @@ -1 +0,0 @@ -foo.*.notbaz[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-58 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-58 deleted file mode 100644 index 99fe382c6c6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-58 +++ /dev/null @@ -1 +0,0 @@ -foo[?`{"bar": [0]}` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-580 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-580 deleted file mode 100644 index 5bb6d4ae783..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-580 +++ /dev/null @@ -1 +0,0 @@ -foo.*.notbaz[-1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-581 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-581 deleted file mode 100644 index edac73189d7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-581 +++ /dev/null @@ -1 +0,0 @@ -foo.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-582 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-582 deleted file mode 100644 index 458d0a6ddd0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-582 +++ /dev/null @@ -1 +0,0 @@ -foo.*.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-583 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-583 deleted file mode 100644 index f757fd53459..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-583 +++ /dev/null @@ -1 +0,0 @@ -foo.*.*.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-584 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-584 deleted file mode 100644 index 670049d96f7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-584 +++ /dev/null @@ -1 +0,0 @@ -foo.*.*.*.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-585 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-585 deleted file mode 100644 index 3c88caafe88..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-585 +++ /dev/null @@ -1 +0,0 @@ -*.bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-586 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-586 deleted file mode 100644 index f59ec20aabf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-586 +++ /dev/null @@ -1 +0,0 @@ -* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-587 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-587 deleted file mode 100644 index 0852fcc7895..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-587 +++ /dev/null @@ -1 +0,0 @@ -*.sub1 \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-588 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-588 deleted file mode 100644 index dee5695746e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-588 +++ /dev/null @@ -1 +0,0 @@ -*.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-589 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-589 deleted file mode 100644 index 66781bba40a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-589 +++ /dev/null @@ -1 +0,0 @@ -*.*.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-59 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-59 deleted file mode 100644 index 4aad20ae69e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-59 +++ /dev/null @@ -1 +0,0 @@ -foo[?`null` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-590 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-590 deleted file mode 100644 index 0db15d97e44..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-590 +++ /dev/null @@ -1 +0,0 @@ -*.sub1.foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-591 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-591 deleted file mode 100644 index b24be9d7d1c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-591 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-592 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-592 deleted file mode 100644 index e6efe133fcd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-592 +++ /dev/null @@ -1 +0,0 @@ -foo[*].notbar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-593 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-593 deleted file mode 100644 index 5a5194647ad..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-593 +++ /dev/null @@ -1 +0,0 @@ -[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-594 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-594 deleted file mode 100644 index cd9fb6ba778..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-594 +++ /dev/null @@ -1 +0,0 @@ -[*].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-595 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-595 deleted file mode 100644 index cbf1a5d596a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-595 +++ /dev/null @@ -1 +0,0 @@ -[*].notbar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-596 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-596 deleted file mode 100644 index 8bd13b7eb49..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-596 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[*].baz \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-597 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-597 deleted file mode 100644 index 7239f3e887e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-597 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[*].baz[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-598 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-598 deleted file mode 100644 index f5e431d9e3f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-598 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[*].baz[1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-599 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-599 deleted file mode 100644 index d0c25953968..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-599 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[*].baz[2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-6 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-6 deleted file mode 100644 index b9749b74897..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-6 +++ /dev/null @@ -1 +0,0 @@ -foo.bad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-60 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-60 deleted file mode 100644 index dac67509bb4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-60 +++ /dev/null @@ -1 +0,0 @@ -foo[?`[1]` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-600 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-600 deleted file mode 100644 index a6388271e41..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-600 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[*].baz[3] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-601 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-601 deleted file mode 100644 index 2a66ffe93b8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-601 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-602 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-602 deleted file mode 100644 index b6b3695438a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-602 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-603 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-603 deleted file mode 100644 index 7e57f9e74ce..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-603 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-604 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-604 deleted file mode 100644 index c5f8bef0bee..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-604 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[0][0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-605 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-605 deleted file mode 100644 index 3decf08030f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-605 +++ /dev/null @@ -1 +0,0 @@ -foo.bar[0][0][0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-606 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-606 deleted file mode 100644 index 655e2959bea..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-606 +++ /dev/null @@ -1 +0,0 @@ -foo[0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-607 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-607 deleted file mode 100644 index 2aa159718c8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-607 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[*].kind \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-608 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-608 deleted file mode 100644 index 556b380bab1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-608 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[0].kind \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-609 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-609 deleted file mode 100644 index 0de3229b83e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-609 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar.kind \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-61 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-61 deleted file mode 100644 index 130ed3b379e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-61 +++ /dev/null @@ -1 +0,0 @@ -foo[?`{"a":2}` == key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-610 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-610 deleted file mode 100644 index 3b511f13351..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-610 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-611 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-611 deleted file mode 100644 index c8dfa16e6bc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-611 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-612 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-612 deleted file mode 100644 index 69f04ee23ff..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-612 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-613 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-613 deleted file mode 100644 index 3b511f13351..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-613 +++ /dev/null @@ -1 +0,0 @@ -foo[*].bar[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-614 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-614 deleted file mode 100644 index 03e0c0cb93b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-614 +++ /dev/null @@ -1 +0,0 @@ -foo[*][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-615 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-615 deleted file mode 100644 index ac1c8966821..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-615 +++ /dev/null @@ -1 +0,0 @@ -foo[*][1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-616 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-616 deleted file mode 100644 index 03e0c0cb93b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-616 +++ /dev/null @@ -1 +0,0 @@ -foo[*][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-617 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-617 deleted file mode 100644 index ac1c8966821..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-617 +++ /dev/null @@ -1 +0,0 @@ -foo[*][1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-618 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-618 deleted file mode 100644 index 6494cf1c6a0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-618 +++ /dev/null @@ -1 +0,0 @@ -foo[*][0][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-619 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-619 deleted file mode 100644 index 1406be5721f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-619 +++ /dev/null @@ -1 +0,0 @@ -foo[*][1][0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-62 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-62 deleted file mode 100644 index 3d15fcc1697..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-62 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `true`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-620 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-620 deleted file mode 100644 index 72b5aa281a9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-620 +++ /dev/null @@ -1 +0,0 @@ -foo[*][0][1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-621 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-621 deleted file mode 100644 index 02a26491ae4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-621 +++ /dev/null @@ -1 +0,0 @@ -foo[*][1][1] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-622 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-622 deleted file mode 100644 index cb08037e209..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-622 +++ /dev/null @@ -1 +0,0 @@ -foo[*][2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-623 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-623 deleted file mode 100644 index 91d695995a4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-623 +++ /dev/null @@ -1 +0,0 @@ -foo[*][2][2] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-624 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-624 deleted file mode 100644 index f40f261ad17..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-624 +++ /dev/null @@ -1 +0,0 @@ -bar[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-625 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-625 deleted file mode 100644 index 03904b1dece..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-625 +++ /dev/null @@ -1 +0,0 @@ -bar[*].baz[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-626 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-626 deleted file mode 100644 index fd7c21c340c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-626 +++ /dev/null @@ -1 +0,0 @@ -string[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-627 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-627 deleted file mode 100644 index d7ca4719a99..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-627 +++ /dev/null @@ -1 +0,0 @@ -hash[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-628 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-628 deleted file mode 100644 index b3ddffe3cfe..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-628 +++ /dev/null @@ -1 +0,0 @@ -number[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-629 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-629 deleted file mode 100644 index c03cd39ebf5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-629 +++ /dev/null @@ -1 +0,0 @@ -nullvalue[*] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-63 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-63 deleted file mode 100644 index 08731af6908..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-63 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `false`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-630 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-630 deleted file mode 100644 index b3c40cd533f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-630 +++ /dev/null @@ -1 +0,0 @@ -string[*].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-631 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-631 deleted file mode 100644 index c5930d543f3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-631 +++ /dev/null @@ -1 +0,0 @@ -hash[*].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-632 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-632 deleted file mode 100644 index cc0b1a4896a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-632 +++ /dev/null @@ -1 +0,0 @@ -number[*].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-633 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-633 deleted file mode 100644 index d677b965852..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-633 +++ /dev/null @@ -1 +0,0 @@ -nullvalue[*].foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-634 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-634 deleted file mode 100644 index c1166640155..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-634 +++ /dev/null @@ -1 +0,0 @@ -nullvalue[*].foo[*].bar \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-635 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-635 deleted file mode 100644 index e3399771088..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-635 +++ /dev/null @@ -1 +0,0 @@ -string.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-636 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-636 deleted file mode 100644 index 76f53453a8a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-636 +++ /dev/null @@ -1 +0,0 @@ -hash.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-637 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-637 deleted file mode 100644 index dd485072f26..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-637 +++ /dev/null @@ -1 +0,0 @@ -number.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-638 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-638 deleted file mode 100644 index 16000c003cd..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-638 +++ /dev/null @@ -1 +0,0 @@ -array.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-639 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-639 deleted file mode 100644 index 1d0d03ed3b5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-639 +++ /dev/null @@ -1 +0,0 @@ -nullvalue.* \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-64 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-64 deleted file mode 100644 index b67aebe98ad..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-64 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `0`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-640 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-640 deleted file mode 100644 index 7e8066d39f5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-640 +++ /dev/null @@ -1 +0,0 @@ -*[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-641 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-641 deleted file mode 100644 index 41ebe5ba9d7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-641 +++ /dev/null @@ -1 +0,0 @@ -`foo` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-642 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-642 deleted file mode 100644 index fe0397993c5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-642 +++ /dev/null @@ -1 +0,0 @@ -`foo\"quote` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-643 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-643 deleted file mode 100644 index 1a27fd80c3c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-643 +++ /dev/null @@ -1 +0,0 @@ -`✓` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-644 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-644 deleted file mode 100644 index 559a13456be..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-644 +++ /dev/null @@ -1 +0,0 @@ -`foo\"bar` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-645 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-645 deleted file mode 100644 index e31621b438e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-645 +++ /dev/null @@ -1 +0,0 @@ -`1\`` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-646 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-646 deleted file mode 100644 index 6bf7a10362a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-646 +++ /dev/null @@ -1 +0,0 @@ -`\\`.{a:`b`} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-647 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-647 deleted file mode 100644 index 41ebe5ba9d7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-647 +++ /dev/null @@ -1 +0,0 @@ -`foo` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-648 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-648 deleted file mode 100644 index 28b9bcbbb52..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-648 +++ /dev/null @@ -1 +0,0 @@ -` foo` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-649 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-649 deleted file mode 100644 index 41ebe5ba9d7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-649 +++ /dev/null @@ -1 +0,0 @@ -`foo` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-65 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-65 deleted file mode 100644 index d3ac793bb6b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-65 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `1`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-650 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-650 deleted file mode 100644 index fe0397993c5..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-650 +++ /dev/null @@ -1 +0,0 @@ -`foo\"quote` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-651 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-651 deleted file mode 100644 index 1a27fd80c3c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-651 +++ /dev/null @@ -1 +0,0 @@ -`✓` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-652 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-652 deleted file mode 100644 index 559a13456be..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-652 +++ /dev/null @@ -1 +0,0 @@ -`foo\"bar` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-653 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-653 deleted file mode 100644 index e31621b438e..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-653 +++ /dev/null @@ -1 +0,0 @@ -`1\`` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-654 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-654 deleted file mode 100644 index 6bf7a10362a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-654 +++ /dev/null @@ -1 +0,0 @@ -`\\`.{a:`b`} \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-655 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-655 deleted file mode 100644 index 41ebe5ba9d7..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-655 +++ /dev/null @@ -1 +0,0 @@ -`foo` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-656 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-656 deleted file mode 100644 index 28b9bcbbb52..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-656 +++ /dev/null @@ -1 +0,0 @@ -` foo` \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-66 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-66 deleted file mode 100644 index 065295bc17a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-66 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `null`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-67 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-67 deleted file mode 100644 index 43d164927d4..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-67 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `[1]`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-68 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-68 deleted file mode 100644 index 6b884fa866f..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-68 +++ /dev/null @@ -1 +0,0 @@ -foo[?key != `{"a":2}`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-69 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-69 deleted file mode 100644 index d85c779d0a3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-69 +++ /dev/null @@ -1 +0,0 @@ -foo[?`true` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-7 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-7 deleted file mode 100644 index 44d6628cdc6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-7 +++ /dev/null @@ -1 +0,0 @@ -bad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-70 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-70 deleted file mode 100644 index 3e6dcf3045a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-70 +++ /dev/null @@ -1 +0,0 @@ -foo[?`false` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-71 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-71 deleted file mode 100644 index bdb820b30b3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-71 +++ /dev/null @@ -1 +0,0 @@ -foo[?`0` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-72 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-72 deleted file mode 100644 index 3f3048a004c..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-72 +++ /dev/null @@ -1 +0,0 @@ -foo[?`1` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-73 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-73 deleted file mode 100644 index dacc2572451..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-73 +++ /dev/null @@ -1 +0,0 @@ -foo[?`null` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-74 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-74 deleted file mode 100644 index 32ebae8800b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-74 +++ /dev/null @@ -1 +0,0 @@ -foo[?`[1]` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-75 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-75 deleted file mode 100644 index dcd023e0fbc..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-75 +++ /dev/null @@ -1 +0,0 @@ -foo[?`{"a":2}` != key] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-76 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-76 deleted file mode 100644 index e08cc13cbe3..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-76 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[?bar==`1`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-77 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-77 deleted file mode 100644 index 1ec43f45fce..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-77 +++ /dev/null @@ -1 +0,0 @@ -reservations[*].instances[?bar==`1`] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-78 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-78 deleted file mode 100644 index 30387116349..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-78 +++ /dev/null @@ -1 +0,0 @@ -reservations[].instances[?bar==`1`][] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-79 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-79 deleted file mode 100644 index e3875746b35..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-79 +++ /dev/null @@ -1 +0,0 @@ -foo[?bar==`1`].bar[0] \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-8 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-8 deleted file mode 100644 index da7bc1ccfd0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-8 +++ /dev/null @@ -1 +0,0 @@ -bad.morebad.morebad \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-80 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-80 deleted file mode 100644 index 5c3d683565d..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-80 +++ /dev/null @@ -1 +0,0 @@ -foo[?a==`1`].b.c \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-81 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-81 deleted file mode 100644 index 6232808f0ae..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-81 +++ /dev/null @@ -1 +0,0 @@ -abs(foo) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-82 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-82 deleted file mode 100644 index 6232808f0ae..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-82 +++ /dev/null @@ -1 +0,0 @@ -abs(foo) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-83 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-83 deleted file mode 100644 index 29497f4ff54..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-83 +++ /dev/null @@ -1 +0,0 @@ -abs(array[1]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-84 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-84 deleted file mode 100644 index 29497f4ff54..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-84 +++ /dev/null @@ -1 +0,0 @@ -abs(array[1]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-85 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-85 deleted file mode 100644 index 346696563f8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-85 +++ /dev/null @@ -1 +0,0 @@ -abs(`-24`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-86 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-86 deleted file mode 100644 index 346696563f8..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-86 +++ /dev/null @@ -1 +0,0 @@ -abs(`-24`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-87 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-87 deleted file mode 100644 index c6268f8473b..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-87 +++ /dev/null @@ -1 +0,0 @@ -avg(numbers) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-88 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-88 deleted file mode 100644 index 7ce703695ee..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-88 +++ /dev/null @@ -1 +0,0 @@ -ceil(`1.2`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-89 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-89 deleted file mode 100644 index 0561bc26d9a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-89 +++ /dev/null @@ -1 +0,0 @@ -ceil(decimals[0]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-9 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-9 deleted file mode 100644 index 19102815663..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-9 +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-90 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-90 deleted file mode 100644 index c78c1fc3002..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-90 +++ /dev/null @@ -1 +0,0 @@ -ceil(decimals[1]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-91 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-91 deleted file mode 100644 index ebcb4bbdbb9..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-91 +++ /dev/null @@ -1 +0,0 @@ -ceil(decimals[2]) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-92 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-92 deleted file mode 100644 index 6edbf1afe4a..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-92 +++ /dev/null @@ -1 +0,0 @@ -contains('abc', 'a') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-93 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-93 deleted file mode 100644 index d2b2f070dab..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-93 +++ /dev/null @@ -1 +0,0 @@ -contains('abc', 'd') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-94 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-94 deleted file mode 100644 index 3535da2eca6..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-94 +++ /dev/null @@ -1 +0,0 @@ -contains(strings, 'a') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-95 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-95 deleted file mode 100644 index ba839fe60d1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-95 +++ /dev/null @@ -1 +0,0 @@ -contains(decimals, `1.2`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-96 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-96 deleted file mode 100644 index f4358186979..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-96 +++ /dev/null @@ -1 +0,0 @@ -contains(decimals, `false`) \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-97 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-97 deleted file mode 100644 index adb65fc01f0..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-97 +++ /dev/null @@ -1 +0,0 @@ -ends_with(str, 'r') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-98 b/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-98 deleted file mode 100644 index 93d6901bead..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/corpus/expr-98 +++ /dev/null @@ -1 +0,0 @@ -ends_with(str, 'tr') \ No newline at end of file diff --git a/vendor/github.com/jmespath/go-jmespath/fuzz/jmespath.go b/vendor/github.com/jmespath/go-jmespath/fuzz/jmespath.go deleted file mode 100644 index c7df08782a1..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/fuzz/jmespath.go +++ /dev/null @@ -1,13 +0,0 @@ -package jmespath - -import "github.com/jmespath/go-jmespath" - -// Fuzz will fuzz test the JMESPath parser. -func Fuzz(data []byte) int { - p := jmespath.NewParser() - _, err := p.Parse(string(data)) - if err != nil { - return 1 - } - return 0 -} diff --git a/vendor/github.com/jmespath/go-jmespath/interpreter_test.go b/vendor/github.com/jmespath/go-jmespath/interpreter_test.go deleted file mode 100644 index 5b529c4f313..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/interpreter_test.go +++ /dev/null @@ -1,213 +0,0 @@ -package jmespath - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -type scalars struct { - Foo string - Bar string -} - -type sliceType struct { - A string - B []scalars - C []*scalars -} - -type benchmarkStruct struct { - Fooasdfasdfasdfasdf string -} - -type benchmarkNested struct { - Fooasdfasdfasdfasdf nestedA -} - -type nestedA struct { - Fooasdfasdfasdfasdf nestedB -} - -type nestedB struct { - Fooasdfasdfasdfasdf nestedC -} - -type nestedC struct { - Fooasdfasdfasdfasdf string -} - -type nestedSlice struct { - A []sliceType -} - -func TestCanSupportEmptyInterface(t *testing.T) { - assert := assert.New(t) - data := make(map[string]interface{}) - data["foo"] = "bar" - result, err := Search("foo", data) - assert.Nil(err) - assert.Equal("bar", result) -} - -func TestCanSupportUserDefinedStructsValue(t *testing.T) { - assert := assert.New(t) - s := scalars{Foo: "one", Bar: "bar"} - result, err := Search("Foo", s) - assert.Nil(err) - assert.Equal("one", result) -} - -func TestCanSupportUserDefinedStructsRef(t *testing.T) { - assert := assert.New(t) - s := scalars{Foo: "one", Bar: "bar"} - result, err := Search("Foo", &s) - assert.Nil(err) - assert.Equal("one", result) -} - -func TestCanSupportStructWithSliceAll(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", B: []scalars{scalars{"f1", "b1"}, scalars{"correct", "b2"}}} - result, err := Search("B[].Foo", data) - assert.Nil(err) - assert.Equal([]interface{}{"f1", "correct"}, result) -} - -func TestCanSupportStructWithSlicingExpression(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", B: []scalars{scalars{"f1", "b1"}, scalars{"correct", "b2"}}} - result, err := Search("B[:].Foo", data) - assert.Nil(err) - assert.Equal([]interface{}{"f1", "correct"}, result) -} - -func TestCanSupportStructWithFilterProjection(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", B: []scalars{scalars{"f1", "b1"}, scalars{"correct", "b2"}}} - result, err := Search("B[? `true` ].Foo", data) - assert.Nil(err) - assert.Equal([]interface{}{"f1", "correct"}, result) -} - -func TestCanSupportStructWithSlice(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", B: []scalars{scalars{"f1", "b1"}, scalars{"correct", "b2"}}} - result, err := Search("B[-1].Foo", data) - assert.Nil(err) - assert.Equal("correct", result) -} - -func TestCanSupportStructWithOrExpressions(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", C: nil} - result, err := Search("C || A", data) - assert.Nil(err) - assert.Equal("foo", result) -} - -func TestCanSupportStructWithSlicePointer(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", C: []*scalars{&scalars{"f1", "b1"}, &scalars{"correct", "b2"}}} - result, err := Search("C[-1].Foo", data) - assert.Nil(err) - assert.Equal("correct", result) -} - -func TestWillAutomaticallyCapitalizeFieldNames(t *testing.T) { - assert := assert.New(t) - s := scalars{Foo: "one", Bar: "bar"} - // Note that there's a lower cased "foo" instead of "Foo", - // but it should still correspond to the Foo field in the - // scalars struct - result, err := Search("foo", &s) - assert.Nil(err) - assert.Equal("one", result) -} - -func TestCanSupportStructWithSliceLowerCased(t *testing.T) { - assert := assert.New(t) - data := sliceType{A: "foo", B: []scalars{scalars{"f1", "b1"}, scalars{"correct", "b2"}}} - result, err := Search("b[-1].foo", data) - assert.Nil(err) - assert.Equal("correct", result) -} - -func TestCanSupportStructWithNestedPointers(t *testing.T) { - assert := assert.New(t) - data := struct{ A *struct{ B int } }{} - result, err := Search("A.B", data) - assert.Nil(err) - assert.Nil(result) -} - -func TestCanSupportFlattenNestedSlice(t *testing.T) { - assert := assert.New(t) - data := nestedSlice{A: []sliceType{ - {B: []scalars{{Foo: "f1a"}, {Foo: "f1b"}}}, - {B: []scalars{{Foo: "f2a"}, {Foo: "f2b"}}}, - }} - result, err := Search("A[].B[].Foo", data) - assert.Nil(err) - assert.Equal([]interface{}{"f1a", "f1b", "f2a", "f2b"}, result) -} - -func TestCanSupportFlattenNestedEmptySlice(t *testing.T) { - assert := assert.New(t) - data := nestedSlice{A: []sliceType{ - {}, {B: []scalars{{Foo: "a"}}}, - }} - result, err := Search("A[].B[].Foo", data) - assert.Nil(err) - assert.Equal([]interface{}{"a"}, result) -} - -func TestCanSupportProjectionsWithStructs(t *testing.T) { - assert := assert.New(t) - data := nestedSlice{A: []sliceType{ - {A: "first"}, {A: "second"}, {A: "third"}, - }} - result, err := Search("A[*].A", data) - assert.Nil(err) - assert.Equal([]interface{}{"first", "second", "third"}, result) -} - -func BenchmarkInterpretSingleFieldStruct(b *testing.B) { - intr := newInterpreter() - parser := NewParser() - ast, _ := parser.Parse("fooasdfasdfasdfasdf") - data := benchmarkStruct{"foobarbazqux"} - for i := 0; i < b.N; i++ { - intr.Execute(ast, &data) - } -} - -func BenchmarkInterpretNestedStruct(b *testing.B) { - intr := newInterpreter() - parser := NewParser() - ast, _ := parser.Parse("fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf") - data := benchmarkNested{ - nestedA{ - nestedB{ - nestedC{"foobarbazqux"}, - }, - }, - } - for i := 0; i < b.N; i++ { - intr.Execute(ast, &data) - } -} - -func BenchmarkInterpretNestedMaps(b *testing.B) { - jsonData := []byte(`{"fooasdfasdfasdfasdf": {"fooasdfasdfasdfasdf": {"fooasdfasdfasdfasdf": {"fooasdfasdfasdfasdf": "foobarbazqux"}}}}`) - var data interface{} - json.Unmarshal(jsonData, &data) - - intr := newInterpreter() - parser := NewParser() - ast, _ := parser.Parse("fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf") - for i := 0; i < b.N; i++ { - intr.Execute(ast, data) - } -} diff --git a/vendor/github.com/jmespath/go-jmespath/lexer_test.go b/vendor/github.com/jmespath/go-jmespath/lexer_test.go deleted file mode 100644 index 7a9a9ee24bf..00000000000 --- a/vendor/github.com/jmespath/go-jmespath/lexer_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package jmespath - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -var lexingTests = []struct { - expression string - expected []token -}{ - {"*", []token{token{tStar, "*", 0, 1}}}, - {".", []token{token{tDot, ".", 0, 1}}}, - {"[?", []token{token{tFilter, "[?", 0, 2}}}, - {"[]", []token{token{tFlatten, "[]", 0, 2}}}, - {"(", []token{token{tLparen, "(", 0, 1}}}, - {")", []token{token{tRparen, ")", 0, 1}}}, - {"[", []token{token{tLbracket, "[", 0, 1}}}, - {"]", []token{token{tRbracket, "]", 0, 1}}}, - {"{", []token{token{tLbrace, "{", 0, 1}}}, - {"}", []token{token{tRbrace, "}", 0, 1}}}, - {"||", []token{token{tOr, "||", 0, 2}}}, - {"|", []token{token{tPipe, "|", 0, 1}}}, - {"29", []token{token{tNumber, "29", 0, 2}}}, - {"2", []token{token{tNumber, "2", 0, 1}}}, - {"0", []token{token{tNumber, "0", 0, 1}}}, - {"-20", []token{token{tNumber, "-20", 0, 3}}}, - {"foo", []token{token{tUnquotedIdentifier, "foo", 0, 3}}}, - {`"bar"`, []token{token{tQuotedIdentifier, "bar", 0, 3}}}, - // Escaping the delimiter - {`"bar\"baz"`, []token{token{tQuotedIdentifier, `bar"baz`, 0, 7}}}, - {",", []token{token{tComma, ",", 0, 1}}}, - {":", []token{token{tColon, ":", 0, 1}}}, - {"<", []token{token{tLT, "<", 0, 1}}}, - {"<=", []token{token{tLTE, "<=", 0, 2}}}, - {">", []token{token{tGT, ">", 0, 1}}}, - {">=", []token{token{tGTE, ">=", 0, 2}}}, - {"==", []token{token{tEQ, "==", 0, 2}}}, - {"!=", []token{token{tNE, "!=", 0, 2}}}, - {"`[0, 1, 2]`", []token{token{tJSONLiteral, "[0, 1, 2]", 1, 9}}}, - {"'foo'", []token{token{tStringLiteral, "foo", 1, 3}}}, - {"'a'", []token{token{tStringLiteral, "a", 1, 1}}}, - {`'foo\'bar'`, []token{token{tStringLiteral, "foo'bar", 1, 7}}}, - {"@", []token{token{tCurrent, "@", 0, 1}}}, - {"&", []token{token{tExpref, "&", 0, 1}}}, - // Quoted identifier unicode escape sequences - {`"\u2713"`, []token{token{tQuotedIdentifier, "✓", 0, 3}}}, - {`"\\"`, []token{token{tQuotedIdentifier, `\`, 0, 1}}}, - {"`\"foo\"`", []token{token{tJSONLiteral, "\"foo\"", 1, 5}}}, - // Combinations of tokens. - {"foo.bar", []token{ - token{tUnquotedIdentifier, "foo", 0, 3}, - token{tDot, ".", 3, 1}, - token{tUnquotedIdentifier, "bar", 4, 3}, - }}, - {"foo[0]", []token{ - token{tUnquotedIdentifier, "foo", 0, 3}, - token{tLbracket, "[", 3, 1}, - token{tNumber, "0", 4, 1}, - token{tRbracket, "]", 5, 1}, - }}, - {"foo[?a We wouldn't even be having this discussion if thread local storage wasn't -> useful. But every feature comes at a cost, and in my opinion the cost of -> threadlocals far outweighs their benefits. They're just not a good fit for -> Go. - -So, yeah, that makes sense. That's a pretty good reason for why the language -won't support a specific and (relatively) unuseful feature that requires some -runtime changes, just for the sake of a little bit of log improvement. - -But does Go require runtime changes? - -### How it works ### - -Go has pretty fantastic introspective and reflective features, but one thing Go -doesn't give you is any kind of access to the stack pointer, or frame pointer, -or goroutine id, or anything contextual about your current stack. It gives you -access to your list of callers, but only along with program counters, which are -fixed at compile time. - -But it does give you the stack. - -So, we define 16 special functions and embed base-16 tags into the stack using -the call order of those 16 functions. Then, we can read our tags back out of -the stack looking at the callers list. - -We then use these tags as an index into a traditional map for implementing -this library. - -### What are people saying? ### - -"Wow, that's horrifying." - -"This is the most terrible thing I have seen in a very long time." - -"Where is it getting a context from? Is this serializing all the requests? What the heck is the client being bound to? What are these tags? Why does he need callers? Oh god no. No no no." - -### Docs ### - -Please see the docs at http://godoc.org/github.com/jtolds/gls diff --git a/vendor/github.com/jtolds/gls/context.go b/vendor/github.com/jtolds/gls/context.go index 94d7fbb7f2c..618a1710613 100644 --- a/vendor/github.com/jtolds/gls/context.go +++ b/vendor/github.com/jtolds/gls/context.go @@ -2,16 +2,10 @@ package gls import ( - "runtime" "sync" ) -const ( - maxCallers = 64 -) - var ( - stackTagPool = &idPool{} mgrRegistry = make(map[*ContextManager]bool) mgrRegistryMtx sync.RWMutex ) @@ -20,18 +14,13 @@ var ( // set multiple values at once. type Values map[interface{}]interface{} -func currentStack(skip int) []uintptr { - stack := make([]uintptr, maxCallers) - return stack[:runtime.Callers(2+skip, stack)] -} - // ContextManager is the main entrypoint for interacting with // Goroutine-local-storage. You can have multiple independent ContextManagers // at any given time. ContextManagers are usually declared globally for a given // class of context variables. You should use NewContextManager for // construction. type ContextManager struct { - mtx sync.RWMutex + mtx sync.Mutex values map[uint]Values } @@ -68,63 +57,77 @@ func (m *ContextManager) SetValues(new_values Values, context_call func()) { return } - tags := readStackTags(currentStack(1)) + mutated_keys := make([]interface{}, 0, len(new_values)) + mutated_vals := make(Values, len(new_values)) - m.mtx.Lock() - values := new_values - for _, tag := range tags { - if existing_values, ok := m.values[tag]; ok { - // oh, we found existing values, let's make a copy - values = make(Values, len(existing_values)+len(new_values)) - for key, val := range existing_values { - values[key] = val - } - for key, val := range new_values { - values[key] = val - } - break - } - } - new_tag := stackTagPool.Acquire() - m.values[new_tag] = values - m.mtx.Unlock() - defer func() { + EnsureGoroutineId(func(gid uint) { m.mtx.Lock() - delete(m.values, new_tag) + state, found := m.values[gid] + if !found { + state = make(Values, len(new_values)) + m.values[gid] = state + } m.mtx.Unlock() - stackTagPool.Release(new_tag) - }() - addStackTag(new_tag, context_call) + for key, new_val := range new_values { + mutated_keys = append(mutated_keys, key) + if old_val, ok := state[key]; ok { + mutated_vals[key] = old_val + } + state[key] = new_val + } + + defer func() { + if !found { + m.mtx.Lock() + delete(m.values, gid) + m.mtx.Unlock() + return + } + + for _, key := range mutated_keys { + if val, ok := mutated_vals[key]; ok { + state[key] = val + } else { + delete(state, key) + } + } + }() + + context_call() + }) } // GetValue will return a previously set value, provided that the value was set // by SetValues somewhere higher up the stack. If the value is not found, ok // will be false. -func (m *ContextManager) GetValue(key interface{}) (value interface{}, ok bool) { - - tags := readStackTags(currentStack(1)) - m.mtx.RLock() - defer m.mtx.RUnlock() - for _, tag := range tags { - if values, ok := m.values[tag]; ok { - value, ok := values[key] - return value, ok - } +func (m *ContextManager) GetValue(key interface{}) ( + value interface{}, ok bool) { + gid, ok := GetGoroutineId() + if !ok { + return nil, false } - return "", false + + m.mtx.Lock() + state, found := m.values[gid] + m.mtx.Unlock() + + if !found { + return nil, false + } + value, ok = state[key] + return value, ok } func (m *ContextManager) getValues() Values { - tags := readStackTags(currentStack(2)) - m.mtx.RLock() - defer m.mtx.RUnlock() - for _, tag := range tags { - if values, ok := m.values[tag]; ok { - return values - } + gid, ok := GetGoroutineId() + if !ok { + return nil } - return nil + m.mtx.Lock() + state, _ := m.values[gid] + m.mtx.Unlock() + return state } // Go preserves ContextManager values and Goroutine-local-storage across new @@ -137,12 +140,12 @@ func Go(cb func()) { mgrRegistryMtx.RLock() defer mgrRegistryMtx.RUnlock() - for mgr, _ := range mgrRegistry { + for mgr := range mgrRegistry { values := mgr.getValues() if len(values) > 0 { - mgr_copy := mgr - cb_copy := cb - cb = func() { mgr_copy.SetValues(values, cb_copy) } + cb = func(mgr *ContextManager, cb func()) func() { + return func() { mgr.SetValues(values, cb) } + }(mgr, cb) } } diff --git a/vendor/github.com/jtolds/gls/context_test.go b/vendor/github.com/jtolds/gls/context_test.go deleted file mode 100644 index ae5bde4aede..00000000000 --- a/vendor/github.com/jtolds/gls/context_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package gls - -import ( - "fmt" - "sync" - "testing" -) - -func TestContexts(t *testing.T) { - mgr1 := NewContextManager() - mgr2 := NewContextManager() - - CheckVal := func(mgr *ContextManager, key, exp_val string) { - val, ok := mgr.GetValue(key) - if len(exp_val) == 0 { - if ok { - t.Fatalf("expected no value for key %s, got %s", key, val) - } - return - } - if !ok { - t.Fatalf("expected value %s for key %s, got no value", - exp_val, key) - } - if exp_val != val { - t.Fatalf("expected value %s for key %s, got %s", exp_val, key, - val) - } - - } - - Check := func(exp_m1v1, exp_m1v2, exp_m2v1, exp_m2v2 string) { - CheckVal(mgr1, "key1", exp_m1v1) - CheckVal(mgr1, "key2", exp_m1v2) - CheckVal(mgr2, "key1", exp_m2v1) - CheckVal(mgr2, "key2", exp_m2v2) - } - - Check("", "", "", "") - mgr2.SetValues(Values{"key1": "val1c"}, func() { - Check("", "", "val1c", "") - mgr1.SetValues(Values{"key1": "val1a"}, func() { - Check("val1a", "", "val1c", "") - mgr1.SetValues(Values{"key2": "val1b"}, func() { - Check("val1a", "val1b", "val1c", "") - var wg sync.WaitGroup - wg.Add(2) - go func() { - defer wg.Done() - Check("", "", "", "") - }() - Go(func() { - defer wg.Done() - Check("val1a", "val1b", "val1c", "") - }) - wg.Wait() - }) - }) - }) -} - -func ExampleContextManager_SetValues() { - var ( - mgr = NewContextManager() - request_id_key = GenSym() - ) - - MyLog := func() { - if request_id, ok := mgr.GetValue(request_id_key); ok { - fmt.Println("My request id is:", request_id) - } else { - fmt.Println("No request id found") - } - } - - mgr.SetValues(Values{request_id_key: "12345"}, func() { - MyLog() - }) - MyLog() - - // Output: My request id is: 12345 - // No request id found -} - -func ExampleGo() { - var ( - mgr = NewContextManager() - request_id_key = GenSym() - ) - - MyLog := func() { - if request_id, ok := mgr.GetValue(request_id_key); ok { - fmt.Println("My request id is:", request_id) - } else { - fmt.Println("No request id found") - } - } - - mgr.SetValues(Values{request_id_key: "12345"}, func() { - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - MyLog() - }() - wg.Wait() - wg.Add(1) - Go(func() { - defer wg.Done() - MyLog() - }) - wg.Wait() - }) - - // Output: No request id found - // My request id is: 12345 -} - -func BenchmarkGetValue(b *testing.B) { - mgr := NewContextManager() - mgr.SetValues(Values{"test_key": "test_val"}, func() { - b.ResetTimer() - for i := 0; i < b.N; i++ { - val, ok := mgr.GetValue("test_key") - if !ok || val != "test_val" { - b.FailNow() - } - } - }) -} - -func BenchmarkSetValues(b *testing.B) { - mgr := NewContextManager() - for i := 0; i < b.N/2; i++ { - mgr.SetValues(Values{"test_key": "test_val"}, func() { - mgr.SetValues(Values{"test_key2": "test_val2"}, func() {}) - }) - } -} diff --git a/vendor/github.com/jtolds/gls/gen_sym.go b/vendor/github.com/jtolds/gls/gen_sym.go index 8d5fc24d4a4..7f615cce937 100644 --- a/vendor/github.com/jtolds/gls/gen_sym.go +++ b/vendor/github.com/jtolds/gls/gen_sym.go @@ -1,13 +1,21 @@ package gls +import ( + "sync" +) + var ( - symPool = &idPool{} + keyMtx sync.Mutex + keyCounter uint64 ) // ContextKey is a throwaway value you can use as a key to a ContextManager -type ContextKey struct{ id uint } +type ContextKey struct{ id uint64 } // GenSym will return a brand new, never-before-used ContextKey func GenSym() ContextKey { - return ContextKey{id: symPool.Acquire()} + keyMtx.Lock() + defer keyMtx.Unlock() + keyCounter += 1 + return ContextKey{id: keyCounter} } diff --git a/vendor/github.com/jtolds/gls/gid.go b/vendor/github.com/jtolds/gls/gid.go new file mode 100644 index 00000000000..c16bf3a554f --- /dev/null +++ b/vendor/github.com/jtolds/gls/gid.go @@ -0,0 +1,25 @@ +package gls + +var ( + stackTagPool = &idPool{} +) + +// Will return this goroutine's identifier if set. If you always need a +// goroutine identifier, you should use EnsureGoroutineId which will make one +// if there isn't one already. +func GetGoroutineId() (gid uint, ok bool) { + return readStackTag() +} + +// Will call cb with the current goroutine identifier. If one hasn't already +// been generated, one will be created and set first. The goroutine identifier +// might be invalid after cb returns. +func EnsureGoroutineId(cb func(gid uint)) { + if gid, ok := readStackTag(); ok { + cb(gid) + return + } + gid := stackTagPool.Acquire() + defer stackTagPool.Release(gid) + addStackTag(gid, func() { cb(gid) }) +} diff --git a/vendor/github.com/jtolds/gls/stack_tags.go b/vendor/github.com/jtolds/gls/stack_tags.go index 562a2fab799..cc95dcd8e77 100644 --- a/vendor/github.com/jtolds/gls/stack_tags.go +++ b/vendor/github.com/jtolds/gls/stack_tags.go @@ -2,68 +2,72 @@ package gls // so, basically, we're going to encode integer tags in base-16 on the stack -import ( - "reflect" - "runtime" +const ( + bitWidth = 4 + stackBatchSize = 16 ) -const ( - bitWidth = 4 +var ( + pc_lookup = make(map[uintptr]int8, 17) + mark_lookup [16]func(uint, func()) ) +func init() { + setEntries := func(f func(uint, func()), v int8) { + var ptr uintptr + f(0, func() { + ptr = findPtr() + }) + pc_lookup[ptr] = v + if v >= 0 { + mark_lookup[v] = f + } + } + setEntries(github_com_jtolds_gls_markS, -0x1) + setEntries(github_com_jtolds_gls_mark0, 0x0) + setEntries(github_com_jtolds_gls_mark1, 0x1) + setEntries(github_com_jtolds_gls_mark2, 0x2) + setEntries(github_com_jtolds_gls_mark3, 0x3) + setEntries(github_com_jtolds_gls_mark4, 0x4) + setEntries(github_com_jtolds_gls_mark5, 0x5) + setEntries(github_com_jtolds_gls_mark6, 0x6) + setEntries(github_com_jtolds_gls_mark7, 0x7) + setEntries(github_com_jtolds_gls_mark8, 0x8) + setEntries(github_com_jtolds_gls_mark9, 0x9) + setEntries(github_com_jtolds_gls_markA, 0xa) + setEntries(github_com_jtolds_gls_markB, 0xb) + setEntries(github_com_jtolds_gls_markC, 0xc) + setEntries(github_com_jtolds_gls_markD, 0xd) + setEntries(github_com_jtolds_gls_markE, 0xe) + setEntries(github_com_jtolds_gls_markF, 0xf) +} + func addStackTag(tag uint, context_call func()) { if context_call == nil { return } - markS(tag, context_call) + github_com_jtolds_gls_markS(tag, context_call) } -func markS(tag uint, cb func()) { _m(tag, cb) } -func mark0(tag uint, cb func()) { _m(tag, cb) } -func mark1(tag uint, cb func()) { _m(tag, cb) } -func mark2(tag uint, cb func()) { _m(tag, cb) } -func mark3(tag uint, cb func()) { _m(tag, cb) } -func mark4(tag uint, cb func()) { _m(tag, cb) } -func mark5(tag uint, cb func()) { _m(tag, cb) } -func mark6(tag uint, cb func()) { _m(tag, cb) } -func mark7(tag uint, cb func()) { _m(tag, cb) } -func mark8(tag uint, cb func()) { _m(tag, cb) } -func mark9(tag uint, cb func()) { _m(tag, cb) } -func markA(tag uint, cb func()) { _m(tag, cb) } -func markB(tag uint, cb func()) { _m(tag, cb) } -func markC(tag uint, cb func()) { _m(tag, cb) } -func markD(tag uint, cb func()) { _m(tag, cb) } -func markE(tag uint, cb func()) { _m(tag, cb) } -func markF(tag uint, cb func()) { _m(tag, cb) } - -var pc_lookup = make(map[uintptr]int8, 17) -var mark_lookup [16]func(uint, func()) - -func init() { - setEntries := func(f func(uint, func()), v int8) { - pc_lookup[reflect.ValueOf(f).Pointer()] = v - if v >= 0 { - mark_lookup[v] = f - } - } - setEntries(markS, -0x1) - setEntries(mark0, 0x0) - setEntries(mark1, 0x1) - setEntries(mark2, 0x2) - setEntries(mark3, 0x3) - setEntries(mark4, 0x4) - setEntries(mark5, 0x5) - setEntries(mark6, 0x6) - setEntries(mark7, 0x7) - setEntries(mark8, 0x8) - setEntries(mark9, 0x9) - setEntries(markA, 0xa) - setEntries(markB, 0xb) - setEntries(markC, 0xc) - setEntries(markD, 0xd) - setEntries(markE, 0xe) - setEntries(markF, 0xf) -} +// these private methods are named this horrendous name so gopherjs support +// is easier. it shouldn't add any runtime cost in non-js builds. +func github_com_jtolds_gls_markS(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark0(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark1(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark2(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark3(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark4(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark5(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark6(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark7(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark8(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_mark9(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_markA(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_markB(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_markC(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_markD(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_markE(tag uint, cb func()) { _m(tag, cb) } +func github_com_jtolds_gls_markF(tag uint, cb func()) { _m(tag, cb) } func _m(tag_remainder uint, cb func()) { if tag_remainder == 0 { @@ -73,21 +77,37 @@ func _m(tag_remainder uint, cb func()) { } } -func readStackTags(stack []uintptr) (tags []uint) { +func readStackTag() (tag uint, ok bool) { var current_tag uint - for _, pc := range stack { - pc = runtime.FuncForPC(pc).Entry() - val, ok := pc_lookup[pc] - if !ok { - continue + offset := 0 + for { + batch, next_offset := getStack(offset, stackBatchSize) + for _, pc := range batch { + val, ok := pc_lookup[pc] + if !ok { + continue + } + if val < 0 { + return current_tag, true + } + current_tag <<= bitWidth + current_tag += uint(val) } - if val < 0 { - tags = append(tags, current_tag) - current_tag = 0 - continue + if next_offset == 0 { + break } - current_tag <<= bitWidth - current_tag += uint(val) + offset = next_offset } - return + return 0, false +} + +func (m *ContextManager) preventInlining() { + // dunno if findPtr or getStack are likely to get inlined in a future release + // of go, but if they are inlined and their callers are inlined, that could + // hork some things. let's do our best to explain to the compiler that we + // really don't want those two functions inlined by saying they could change + // at any time. assumes preventInlining doesn't get compiled out. + // this whole thing is probably overkill. + findPtr = m.values[0][0].(func() uintptr) + getStack = m.values[0][1].(func(int, int) ([]uintptr, int)) } diff --git a/vendor/github.com/jtolds/gls/stack_tags_js.go b/vendor/github.com/jtolds/gls/stack_tags_js.go new file mode 100644 index 00000000000..c4e8b801d31 --- /dev/null +++ b/vendor/github.com/jtolds/gls/stack_tags_js.go @@ -0,0 +1,75 @@ +// +build js + +package gls + +// This file is used for GopherJS builds, which don't have normal runtime +// stack trace support + +import ( + "strconv" + "strings" + + "github.com/gopherjs/gopherjs/js" +) + +const ( + jsFuncNamePrefix = "github_com_jtolds_gls_mark" +) + +func jsMarkStack() (f []uintptr) { + lines := strings.Split( + js.Global.Get("Error").New().Get("stack").String(), "\n") + f = make([]uintptr, 0, len(lines)) + for i, line := range lines { + line = strings.TrimSpace(line) + if line == "" { + continue + } + if i == 0 { + if line != "Error" { + panic("didn't understand js stack trace") + } + continue + } + fields := strings.Fields(line) + if len(fields) < 2 || fields[0] != "at" { + panic("didn't understand js stack trace") + } + + pos := strings.Index(fields[1], jsFuncNamePrefix) + if pos < 0 { + continue + } + pos += len(jsFuncNamePrefix) + if pos >= len(fields[1]) { + panic("didn't understand js stack trace") + } + char := string(fields[1][pos]) + switch char { + case "S": + f = append(f, uintptr(0)) + default: + val, err := strconv.ParseUint(char, 16, 8) + if err != nil { + panic("didn't understand js stack trace") + } + f = append(f, uintptr(val)+1) + } + } + return f +} + +// variables to prevent inlining +var ( + findPtr = func() uintptr { + funcs := jsMarkStack() + if len(funcs) == 0 { + panic("failed to find function pointer") + } + return funcs[0] + } + + getStack = func(offset, amount int) (stack []uintptr, next_offset int) { + return jsMarkStack(), 0 + } +) diff --git a/vendor/github.com/jtolds/gls/stack_tags_main.go b/vendor/github.com/jtolds/gls/stack_tags_main.go new file mode 100644 index 00000000000..4da89e44f8e --- /dev/null +++ b/vendor/github.com/jtolds/gls/stack_tags_main.go @@ -0,0 +1,30 @@ +// +build !js + +package gls + +// This file is used for standard Go builds, which have the expected runtime +// support + +import ( + "runtime" +) + +var ( + findPtr = func() uintptr { + var pc [1]uintptr + n := runtime.Callers(4, pc[:]) + if n != 1 { + panic("failed to find function pointer") + } + return pc[0] + } + + getStack = func(offset, amount int) (stack []uintptr, next_offset int) { + stack = make([]uintptr, amount) + stack = stack[:runtime.Callers(offset, stack)] + if len(stack) < amount { + return stack, 0 + } + return stack, offset + len(stack) + } +) diff --git a/vendor/github.com/klauspost/compress/flate/crc32_amd64.go b/vendor/github.com/klauspost/compress/flate/crc32_amd64.go index 45d52f629c2..70a6095e60d 100644 --- a/vendor/github.com/klauspost/compress/flate/crc32_amd64.go +++ b/vendor/github.com/klauspost/compress/flate/crc32_amd64.go @@ -12,18 +12,20 @@ import ( // crc32sse returns a hash for the first 4 bytes of the slice // len(a) must be >= 4. //go:noescape -func crc32sse(a []byte) hash +func crc32sse(a []byte) uint32 // crc32sseAll calculates hashes for each 4-byte set in a. // dst must be east len(a) - 4 in size. // The size is not checked by the assembly. //go:noescape -func crc32sseAll(a []byte, dst []hash) +func crc32sseAll(a []byte, dst []uint32) // matchLenSSE4 returns the number of matching bytes in a and b // up to length 'max'. Both slices must be at least 'max' // bytes in size. -// It uses the PCMPESTRI SSE 4.2 instruction. +// +// TODO: drop the "SSE4" name, since it doesn't use any SSE instructions. +// //go:noescape func matchLenSSE4(a, b []byte, max int) int diff --git a/vendor/github.com/klauspost/compress/flate/crc32_amd64.s b/vendor/github.com/klauspost/compress/flate/crc32_amd64.s index f94969b7603..2fb2079b9d0 100644 --- a/vendor/github.com/klauspost/compress/flate/crc32_amd64.s +++ b/vendor/github.com/klauspost/compress/flate/crc32_amd64.s @@ -1,9 +1,10 @@ -//+build !noasm !appengine +//+build !noasm +//+build !appengine // Copyright 2015, Klaus Post, see LICENSE for details. -// func crc32sse(a []byte) hash -TEXT ·crc32sse(SB), 7, $0 +// func crc32sse(a []byte) uint32 +TEXT ·crc32sse(SB), 4, $0 MOVQ a+0(FP), R10 XORQ BX, BX @@ -14,8 +15,8 @@ TEXT ·crc32sse(SB), 7, $0 MOVL BX, ret+24(FP) RET -// func crc32sseAll(a []byte, dst []hash) -TEXT ·crc32sseAll(SB), 7, $0 +// func crc32sseAll(a []byte, dst []uint32) +TEXT ·crc32sseAll(SB), 4, $0 MOVQ a+0(FP), R8 // R8: src MOVQ a_len+8(FP), R10 // input length MOVQ dst+24(FP), R9 // R9: dst @@ -95,62 +96,62 @@ one_crc: JMP rem_loop // func matchLenSSE4(a, b []byte, max int) int -TEXT ·matchLenSSE4(SB), 7, $0 - MOVQ a+0(FP), R8 // R8: &a - MOVQ b+24(FP), R9 // R9: &b - MOVQ max+48(FP), R10 // R10: max - XORQ R11, R11 // match length +TEXT ·matchLenSSE4(SB), 4, $0 + MOVQ a_base+0(FP), SI + MOVQ b_base+24(FP), DI + MOVQ DI, DX + MOVQ max+48(FP), CX - MOVQ R10, R12 - SHRQ $4, R10 // max/16 - ANDQ $15, R12 // max & 15 - CMPQ R10, $0 - JEQ matchlen_verysmall +cmp8: + // As long as we are 8 or more bytes before the end of max, we can load and + // compare 8 bytes at a time. If those 8 bytes are equal, repeat. + CMPQ CX, $8 + JLT cmp1 + MOVQ (SI), AX + MOVQ (DI), BX + CMPQ AX, BX + JNE bsf + ADDQ $8, SI + ADDQ $8, DI + SUBQ $8, CX + JMP cmp8 -loopback_matchlen: - MOVOU (R8), X0 // a[x] - MOVOU (R9), X1 // b[x] +bsf: + // If those 8 bytes were not equal, XOR the two 8 byte values, and return + // the index of the first byte that differs. The BSF instruction finds the + // least significant 1 bit, the amd64 architecture is little-endian, and + // the shift by 3 converts a bit index to a byte index. + XORQ AX, BX + BSFQ BX, BX + SHRQ $3, BX + ADDQ BX, DI - // PCMPESTRI $0x18, X1, X0 - BYTE $0x66; BYTE $0x0f; BYTE $0x3a - BYTE $0x61; BYTE $0xc1; BYTE $0x18 - - JC match_ended - - ADDQ $16, R8 - ADDQ $16, R9 - ADDQ $16, R11 - - SUBQ $1, R10 - JNZ loopback_matchlen - -matchlen_verysmall: - CMPQ R12, $0 - JEQ done_matchlen - -loopback_matchlen_single: - // Naiive, but small use - MOVB (R8), R13 - MOVB (R9), R14 - CMPB R13, R14 - JNE done_matchlen - ADDQ $1, R8 - ADDQ $1, R9 - ADDQ $1, R11 - SUBQ $1, R12 - JNZ loopback_matchlen_single - MOVQ R11, ret+56(FP) + // Subtract off &b[0] to convert from &b[ret] to ret, and return. + SUBQ DX, DI + MOVQ DI, ret+56(FP) RET -match_ended: - ADDQ CX, R11 +cmp1: + // In the slices' tail, compare 1 byte at a time. + CMPQ CX, $0 + JEQ matchLenEnd + MOVB (SI), AX + MOVB (DI), BX + CMPB AX, BX + JNE matchLenEnd + ADDQ $1, SI + ADDQ $1, DI + SUBQ $1, CX + JMP cmp1 -done_matchlen: - MOVQ R11, ret+56(FP) +matchLenEnd: + // Subtract off &b[0] to convert from &b[ret] to ret, and return. + SUBQ DX, DI + MOVQ DI, ret+56(FP) RET // func histogram(b []byte, h []int32) -TEXT ·histogram(SB), 7, $0 +TEXT ·histogram(SB), 4, $0 MOVQ b+0(FP), SI // SI: &b MOVQ b_len+8(FP), R9 // R9: len(b) MOVQ h+24(FP), DI // DI: Histogram diff --git a/vendor/github.com/klauspost/compress/flate/crc32_noasm.go b/vendor/github.com/klauspost/compress/flate/crc32_noasm.go index 1c6d23eed63..bd98bd598ff 100644 --- a/vendor/github.com/klauspost/compress/flate/crc32_noasm.go +++ b/vendor/github.com/klauspost/compress/flate/crc32_noasm.go @@ -9,12 +9,12 @@ func init() { } // crc32sse should never be called. -func crc32sse(a []byte) hash { +func crc32sse(a []byte) uint32 { panic("no assembler") } // crc32sseAll should never be called. -func crc32sseAll(a []byte, dst []hash) { +func crc32sseAll(a []byte, dst []uint32) { panic("no assembler") } @@ -25,9 +25,10 @@ func matchLenSSE4(a, b []byte, max int) int { } // histogram accumulates a histogram of b in h. -// h must be at least 256 entries in length, -// and must be cleared before calling this function. +// +// len(h) must be >= 256, and h's elements must be all zeroes. func histogram(b []byte, h []int32) { + h = h[:256] for _, t := range b { h[t]++ } diff --git a/vendor/github.com/klauspost/compress/flate/deflate.go b/vendor/github.com/klauspost/compress/flate/deflate.go index a103c8f4ef5..9e6e7ff0cfe 100644 --- a/vendor/github.com/klauspost/compress/flate/deflate.go +++ b/vendor/github.com/klauspost/compress/flate/deflate.go @@ -12,19 +12,30 @@ import ( ) const ( - NoCompression = 0 - BestSpeed = 1 - fastCompression = 3 - BestCompression = 9 - DefaultCompression = -1 - ConstantCompression = -2 // Does only Huffman encoding - logWindowSize = 15 - windowSize = 1 << logWindowSize - windowMask = windowSize - 1 - logMaxOffsetSize = 15 // Standard DEFLATE - minMatchLength = 4 // The smallest match that the compressor looks for - maxMatchLength = 258 // The longest match for the compressor - minOffsetSize = 1 // The shortest offset that makes any sense + NoCompression = 0 + BestSpeed = 1 + BestCompression = 9 + DefaultCompression = -1 + + // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman + // entropy encoding. This mode is useful in compressing data that has + // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4) + // that lacks an entropy encoder. Compression gains are achieved when + // certain bytes in the input stream occur more frequently than others. + // + // Note that HuffmanOnly produces a compressed output that is + // RFC 1951 compliant. That is, any valid DEFLATE decompressor will + // continue to be able to decompress this output. + HuffmanOnly = -2 + ConstantCompression = HuffmanOnly // compatibility alias. + + logWindowSize = 15 + windowSize = 1 << logWindowSize + windowMask = windowSize - 1 + logMaxOffsetSize = 15 // Standard DEFLATE + minMatchLength = 4 // The smallest match that the compressor looks for + maxMatchLength = 258 // The longest match for the compressor + minOffsetSize = 1 // The shortest offset that makes any sense // The maximum number of tokens we put into a single flat block, just too // stop things from getting too large. @@ -45,29 +56,32 @@ type compressionLevel struct { good, lazy, nice, chain, fastSkipHashing, level int } +// Compression levels have been rebalanced from zlib deflate defaults +// to give a bigger spread in speed and compression. +// See https://blog.klauspost.com/rebalancing-deflate-compression-levels/ var levels = []compressionLevel{ {}, // 0 - // For levels 1-3 we don't bother trying with lazy matches - {4, 0, 8, 4, 4, 1}, - {4, 0, 16, 8, 5, 2}, - {4, 0, 32, 32, 6, 3}, - // Levels 4-9 use increasingly more lazy matching + // Level 1-4 uses specialized algorithm - values not used + {0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 2}, + {0, 0, 0, 0, 0, 3}, + {0, 0, 0, 0, 0, 4}, + // For levels 5-6 we don't bother trying with lazy matches. + // Lazy matching is at least 30% slower, with 1.5% increase. + {6, 0, 12, 8, 12, 5}, + {8, 0, 24, 16, 16, 6}, + // Levels 7-9 use increasingly more lazy matching // and increasingly stringent conditions for "good enough". - {4, 4, 16, 16, skipNever, 4}, - {8, 16, 32, 32, skipNever, 5}, - {8, 16, 128, 128, skipNever, 6}, - {8, 32, 128, 256, skipNever, 7}, - {32, 128, 258, 1024, skipNever, 8}, + {8, 8, 24, 16, skipNever, 7}, + {10, 16, 24, 64, skipNever, 8}, {32, 258, 258, 4096, skipNever, 9}, } -type hashid uint32 - type compressor struct { compressionLevel w *huffmanBitWriter - bulkHasher func([]byte, []hash) + bulkHasher func([]byte, []uint32) // compression algorithm fill func(*compressor, []byte) int // copy data to window @@ -80,8 +94,8 @@ type compressor struct { // hashPrev[hashHead[hashValue] & windowMask] contains the previous index // with the same hash value. chainHead int - hashHead []hashid - hashPrev []hashid + hashHead [hashSize]uint32 + hashPrev [windowSize]uint32 hashOffset int // input window: unprocessed data is window[index:windowEnd] @@ -97,20 +111,19 @@ type compressor struct { // deflate state length int offset int - hash hash + hash uint32 maxInsertIndex int err error ii uint16 // position of last match, intended to overflow to reset. - hashMatch [maxMatchLength + minMatchLength]hash + snap snappyEnc + hashMatch [maxMatchLength + minMatchLength]uint32 } -type hash int32 - func (d *compressor) fillDeflate(b []byte) int { if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) { // shift the window by windowSize - copy(d.window, d.window[windowSize:2*windowSize]) + copy(d.window[:], d.window[windowSize:2*windowSize]) d.index -= windowSize d.windowEnd -= windowSize if d.blockStart >= windowSize { @@ -123,16 +136,18 @@ func (d *compressor) fillDeflate(b []byte) int { delta := d.hashOffset - 1 d.hashOffset -= delta d.chainHead -= delta - for i, v := range d.hashPrev { + // Iterate over slices instead of arrays to avoid copying + // the entire table onto the stack (Issue #18625). + for i, v := range d.hashPrev[:] { if int(v) > delta { - d.hashPrev[i] = hashid(int(v) - delta) + d.hashPrev[i] = uint32(int(v) - delta) } else { d.hashPrev[i] = 0 } } - for i, v := range d.hashHead { + for i, v := range d.hashHead[:] { if int(v) > delta { - d.hashHead[i] = hashid(int(v) - delta) + d.hashHead[i] = uint32(int(v) - delta) } else { d.hashHead[i] = 0 } @@ -151,7 +166,31 @@ func (d *compressor) writeBlock(tok tokens, index int, eof bool) error { window = d.window[d.blockStart:index] } d.blockStart = index - d.w.writeBlock(tok, eof, window) + d.w.writeBlock(tok.tokens[:tok.n], eof, window) + return d.w.err + } + return nil +} + +// writeBlockSkip writes the current block and uses the number of tokens +// to determine if the block should be stored on no matches, or +// only huffman encoded. +func (d *compressor) writeBlockSkip(tok tokens, index int, eof bool) error { + if index > 0 || eof { + if d.blockStart <= index { + window := d.window[d.blockStart:index] + // If we removed less than a 64th of all literals + // we huffman compress the block. + if int(tok.n) > len(window)-int(tok.n>>6) { + d.w.writeBlockHuff(eof, window) + } else { + // Write a dynamic huffman block. + d.w.writeBlockDynamic(tok.tokens[:tok.n], eof, window) + } + } else { + d.w.writeBlock(tok.tokens[:tok.n], eof, nil) + } + d.blockStart = index return d.w.err } return nil @@ -164,7 +203,8 @@ func (d *compressor) writeBlock(tok tokens, index int, eof bool) error { func (d *compressor) fillWindow(b []byte) { // Do not fill window if we are in store-only mode, // use constant or Snappy compression. - if d.compressionLevel.level == 0 { + switch d.compressionLevel.level { + case 0, 1, 2: return } // If we are given too much, cut it. @@ -191,7 +231,7 @@ func (d *compressor) fillWindow(b []byte) { dst := d.hashMatch[:dstSize] d.bulkHasher(tocheck, dst) - var newH hash + var newH uint32 for i, val := range dst { di := i + startindex newH = val & hashMask @@ -199,7 +239,7 @@ func (d *compressor) fillWindow(b []byte) { // Our chain should point to the previous value. d.hashPrev[di&windowMask] = d.hashHead[newH] // Set the head of the hash chain to us. - d.hashHead[newH] = hashid(di + d.hashOffset) + d.hashHead[newH] = uint32(di + d.hashOffset) } d.hash = newH } @@ -326,25 +366,27 @@ func (d *compressor) writeStoredBlock(buf []byte) error { return d.w.err } -// oldHash is the hash function used when no native crc32 calculation -// or similar is present. -func oldHash(b []byte) hash { - return hash(b[0])<<(hashShift*3) + hash(b[1])<<(hashShift*2) + hash(b[2])<= 4. +func hash4(b []byte) uint32 { + return ((uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24) * hashmul) >> (32 - hashBits) } -// oldBulkHash will compute hashes using the same -// algorithm as oldHash -func oldBulkHash(b []byte, dst []hash) { +// bulkHash4 will compute hashes using the same +// algorithm as hash4 +func bulkHash4(b []byte, dst []uint32) { if len(b) < minMatchLength { return } - h := oldHash(b) - dst[0] = h - i := 1 + hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + dst[0] = (hb * hashmul) >> (32 - hashBits) end := len(b) - minMatchLength + 1 - for ; i < end; i++ { - h = (h << hashShift) + hash(b[i+3]) - dst[i] = h + for i := 1; i < end; i++ { + hb = (hb << 8) | uint32(b[i+3]) + dst[i] = (hb * hashmul) >> (32 - hashBits) } } @@ -353,6 +395,7 @@ func oldBulkHash(b []byte, dst []hash) { // bytes in size. func matchLen(a, b []byte, max int) int { a = a[:max] + b = b[:len(a)] for i, av := range a { if b[i] != av { return i @@ -362,25 +405,22 @@ func matchLen(a, b []byte, max int) int { } func (d *compressor) initDeflate() { - d.hashHead = make([]hashid, hashSize) - d.hashPrev = make([]hashid, windowSize) d.window = make([]byte, 2*windowSize) d.hashOffset = 1 - d.tokens.tokens = make([]token, maxFlateBlockTokens+1) d.length = minMatchLength - 1 d.offset = 0 d.byteAvailable = false d.index = 0 d.hash = 0 d.chainHead = -1 - d.bulkHasher = oldBulkHash + d.bulkHasher = bulkHash4 if useSSE42 { d.bulkHasher = crc32sseAll } } // Assumes that d.fastSkipHashing != skipNever, -// otherwise use deflateNoSkip +// otherwise use deflateLazy func (d *compressor) deflate() { // Sanity enables additional runtime tests. @@ -394,7 +434,7 @@ func (d *compressor) deflate() { d.maxInsertIndex = d.windowEnd - (minMatchLength - 1) if d.index < d.maxInsertIndex { - d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + d.hash = hash4(d.window[d.index : d.index+minMatchLength]) } for { @@ -411,7 +451,7 @@ func (d *compressor) deflate() { } if lookahead == 0 { if d.tokens.n > 0 { - if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { return } d.tokens.n = 0 @@ -421,11 +461,11 @@ func (d *compressor) deflate() { } if d.index < d.maxInsertIndex { // Update the hash - d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask - ch := d.hashHead[d.hash] + d.hash = hash4(d.window[d.index : d.index+minMatchLength]) + ch := d.hashHead[d.hash&hashMask] d.chainHead = int(ch) d.hashPrev[d.index&windowMask] = ch - d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + d.hashHead[d.hash&hashMask] = uint32(d.index + d.hashOffset) } d.length = minMatchLength - 1 d.offset = 0 @@ -468,8 +508,8 @@ func (d *compressor) deflate() { dstSize := len(tocheck) - minMatchLength + 1 if dstSize > 0 { dst := d.hashMatch[:dstSize] - oldBulkHash(tocheck, dst) - var newH hash + bulkHash4(tocheck, dst) + var newH uint32 for i, val := range dst { di := i + startindex newH = val & hashMask @@ -477,7 +517,7 @@ func (d *compressor) deflate() { // Our chain should point to the previous value. d.hashPrev[di&windowMask] = d.hashHead[newH] // Set the head of the hash chain to us. - d.hashHead[newH] = hashid(di + d.hashOffset) + d.hashHead[newH] = uint32(di + d.hashOffset) } d.hash = newH } @@ -487,12 +527,12 @@ func (d *compressor) deflate() { // item into the table. d.index += d.length if d.index < d.maxInsertIndex { - d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + d.hash = hash4(d.window[d.index : d.index+minMatchLength]) } } if d.tokens.n == maxFlateBlockTokens { // The block includes the current character - if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { return } d.tokens.n = 0 @@ -507,7 +547,7 @@ func (d *compressor) deflate() { d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[i])) d.tokens.n++ if d.tokens.n == maxFlateBlockTokens { - if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil { + if d.err = d.writeBlockSkip(d.tokens, i+1, false); d.err != nil { return } d.tokens.n = 0 @@ -532,7 +572,7 @@ func (d *compressor) deflateLazy() { d.maxInsertIndex = d.windowEnd - (minMatchLength - 1) if d.index < d.maxInsertIndex { - d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + d.hash = hash4(d.window[d.index : d.index+minMatchLength]) } for { @@ -566,11 +606,11 @@ func (d *compressor) deflateLazy() { } if d.index < d.maxInsertIndex { // Update the hash - d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask - ch := d.hashHead[d.hash] + d.hash = hash4(d.window[d.index : d.index+minMatchLength]) + ch := d.hashHead[d.hash&hashMask] d.chainHead = int(ch) d.hashPrev[d.index&windowMask] = ch - d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + d.hashHead[d.hash&hashMask] = uint32(d.index + d.hashOffset) } prevLength := d.length prevOffset := d.offset @@ -613,8 +653,8 @@ func (d *compressor) deflateLazy() { dstSize := len(tocheck) - minMatchLength + 1 if dstSize > 0 { dst := d.hashMatch[:dstSize] - oldBulkHash(tocheck, dst) - var newH hash + bulkHash4(tocheck, dst) + var newH uint32 for i, val := range dst { di := i + startindex newH = val & hashMask @@ -622,7 +662,7 @@ func (d *compressor) deflateLazy() { // Our chain should point to the previous value. d.hashPrev[di&windowMask] = d.hashHead[newH] // Set the head of the hash chain to us. - d.hashHead[newH] = hashid(di + d.hashOffset) + d.hashHead[newH] = uint32(di + d.hashOffset) } d.hash = newH } @@ -658,7 +698,7 @@ func (d *compressor) deflateLazy() { // If we have a long run of no matches, skip additional bytes // Resets when d.ii overflows after 64KB. if d.ii > 31 { - n := int(d.ii >> 6) + n := int(d.ii >> 5) for j := 0; j < n; j++ { if d.index >= d.windowEnd-1 { break @@ -695,7 +735,7 @@ func (d *compressor) deflateLazy() { } // Assumes that d.fastSkipHashing != skipNever, -// otherwise use deflateNoSkip +// otherwise use deflateLazySSE func (d *compressor) deflateSSE() { // Sanity enables additional runtime tests. @@ -709,7 +749,7 @@ func (d *compressor) deflateSSE() { d.maxInsertIndex = d.windowEnd - (minMatchLength - 1) if d.index < d.maxInsertIndex { - d.hash = oldHash(d.window[d.index:d.index+minMatchLength]) & hashMask + d.hash = crc32sse(d.window[d.index:d.index+minMatchLength]) & hashMask } for { @@ -726,7 +766,7 @@ func (d *compressor) deflateSSE() { } if lookahead == 0 { if d.tokens.n > 0 { - if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { return } d.tokens.n = 0 @@ -740,7 +780,7 @@ func (d *compressor) deflateSSE() { ch := d.hashHead[d.hash] d.chainHead = int(ch) d.hashPrev[d.index&windowMask] = ch - d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + d.hashHead[d.hash] = uint32(d.index + d.hashOffset) } d.length = minMatchLength - 1 d.offset = 0 @@ -785,7 +825,7 @@ func (d *compressor) deflateSSE() { dst := d.hashMatch[:dstSize] crc32sseAll(tocheck, dst) - var newH hash + var newH uint32 for i, val := range dst { di := i + startindex newH = val & hashMask @@ -793,7 +833,7 @@ func (d *compressor) deflateSSE() { // Our chain should point to the previous value. d.hashPrev[di&windowMask] = d.hashHead[newH] // Set the head of the hash chain to us. - d.hashHead[newH] = hashid(di + d.hashOffset) + d.hashHead[newH] = uint32(di + d.hashOffset) } d.hash = newH } @@ -808,14 +848,14 @@ func (d *compressor) deflateSSE() { } if d.tokens.n == maxFlateBlockTokens { // The block includes the current character - if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { + if d.err = d.writeBlockSkip(d.tokens, d.index, false); d.err != nil { return } d.tokens.n = 0 } } else { d.ii++ - end := d.index + int(d.ii>>uint(d.fastSkipHashing)) + 1 + end := d.index + int(d.ii>>5) + 1 if end > d.windowEnd { end = d.windowEnd } @@ -823,7 +863,7 @@ func (d *compressor) deflateSSE() { d.tokens.tokens[d.tokens.n] = literalToken(uint32(d.window[i])) d.tokens.n++ if d.tokens.n == maxFlateBlockTokens { - if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil { + if d.err = d.writeBlockSkip(d.tokens, i+1, false); d.err != nil { return } d.tokens.n = 0 @@ -886,7 +926,7 @@ func (d *compressor) deflateLazySSE() { ch := d.hashHead[d.hash] d.chainHead = int(ch) d.hashPrev[d.index&windowMask] = ch - d.hashHead[d.hash] = hashid(d.index + d.hashOffset) + d.hashHead[d.hash] = uint32(d.index + d.hashOffset) } prevLength := d.length prevOffset := d.offset @@ -930,7 +970,7 @@ func (d *compressor) deflateLazySSE() { if dstSize > 0 { dst := d.hashMatch[:dstSize] crc32sseAll(tocheck, dst) - var newH hash + var newH uint32 for i, val := range dst { di := i + startindex newH = val & hashMask @@ -938,7 +978,7 @@ func (d *compressor) deflateLazySSE() { // Our chain should point to the previous value. d.hashPrev[di&windowMask] = d.hashHead[newH] // Set the head of the hash chain to us. - d.hashHead[newH] = hashid(di + d.hashOffset) + d.hashHead[newH] = uint32(di + d.hashOffset) } d.hash = newH } @@ -1010,22 +1050,16 @@ func (d *compressor) deflateLazySSE() { } } -func (d *compressor) fillStore(b []byte) int { - n := copy(d.window[d.windowEnd:], b) - d.windowEnd += n - return n -} - func (d *compressor) store() { - if d.windowEnd > 0 { + if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) { d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + d.windowEnd = 0 } - d.windowEnd = 0 } -// fillHuff will fill the buffer with data for huffman-only compression. +// fillWindow will fill the buffer with data for huffman-only compression. // The number of bytes copied is returned. -func (d *compressor) fillHuff(b []byte) int { +func (d *compressor) fillBlock(b []byte) int { n := copy(d.window[d.windowEnd:], b) d.windowEnd += n return n @@ -1035,11 +1069,7 @@ func (d *compressor) fillHuff(b []byte) int { // if enough has been accumulated or we at the end of the stream. // Any error that occurred will be in d.err func (d *compressor) storeHuff() { - // We only compress if we have maxStoreBlockSize or we are at end-of-stream - if d.windowEnd < maxStoreBlockSize && !d.sync { - return - } - if d.windowEnd == 0 { + if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 { return } d.w.writeBlockHuff(false, d.window[:d.windowEnd]) @@ -1052,15 +1082,42 @@ func (d *compressor) storeHuff() { // Any error that occurred will be in d.err func (d *compressor) storeSnappy() { // We only compress if we have maxStoreBlockSize. - if d.windowEnd < maxStoreBlockSize && !d.sync { - return + if d.windowEnd < maxStoreBlockSize { + if !d.sync { + return + } + // Handle extremely small sizes. + if d.windowEnd < 128 { + if d.windowEnd == 0 { + return + } + if d.windowEnd <= 32 { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + d.tokens.n = 0 + d.windowEnd = 0 + } else { + d.w.writeBlockHuff(false, d.window[:d.windowEnd]) + d.err = d.w.err + } + d.tokens.n = 0 + d.windowEnd = 0 + d.snap.Reset() + return + } } - if d.windowEnd == 0 { - return + + d.snap.Encode(&d.tokens, d.window[:d.windowEnd]) + // If we made zero matches, store the block as is. + if int(d.tokens.n) == d.windowEnd { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + // If we removed less than 1/16th, huffman compress the block. + } else if int(d.tokens.n) > d.windowEnd-(d.windowEnd>>4) { + d.w.writeBlockHuff(false, d.window[:d.windowEnd]) + d.err = d.w.err + } else { + d.w.writeBlockDynamic(d.tokens.tokens[:d.tokens.n], false, d.window[:d.windowEnd]) + d.err = d.w.err } - snappyEncode(&d.tokens, d.window[:d.windowEnd]) - d.w.writeBlock(d.tokens, false, d.window[:d.windowEnd]) - d.err = d.w.err d.tokens.n = 0 d.windowEnd = 0 } @@ -1103,21 +1160,21 @@ func (d *compressor) init(w io.Writer, level int) (err error) { switch { case level == NoCompression: d.window = make([]byte, maxStoreBlockSize) - d.fill = (*compressor).fillStore + d.fill = (*compressor).fillBlock d.step = (*compressor).store case level == ConstantCompression: d.window = make([]byte, maxStoreBlockSize) - d.fill = (*compressor).fillHuff + d.fill = (*compressor).fillBlock d.step = (*compressor).storeHuff - case level == 1: + case level >= 1 && level <= 4: + d.snap = newSnappy(level) d.window = make([]byte, maxStoreBlockSize) - d.fill = (*compressor).fillHuff + d.fill = (*compressor).fillBlock d.step = (*compressor).storeSnappy - d.tokens.tokens = make([]token, maxStoreBlockSize+1) case level == DefaultCompression: - level = 6 + level = 5 fallthrough - case 2 <= level && level <= 9: + case 5 <= level && level <= 9: d.compressionLevel = levels[level] d.initDeflate() d.fill = (*compressor).fillDeflate @@ -1141,32 +1198,33 @@ func (d *compressor) init(w io.Writer, level int) (err error) { return nil } -// Used for zeroing the hash slice -var hzeroes [256]hashid - // reset the state of the compressor. func (d *compressor) reset(w io.Writer) { d.w.reset(w) d.sync = false d.err = nil + // We only need to reset a few things for Snappy. + if d.snap != nil { + d.snap.Reset() + d.windowEnd = 0 + d.tokens.n = 0 + return + } switch d.compressionLevel.chain { case 0: // level was NoCompression or ConstantCompresssion. d.windowEnd = 0 default: d.chainHead = -1 - for s := d.hashHead; len(s) > 0; { - n := copy(s, hzeroes[:]) - s = s[n:] + for i := range d.hashHead { + d.hashHead[i] = 0 } - for s := d.hashPrev; len(s) > 0; s = s[len(hzeroes):] { - copy(s, hzeroes[:]) + for i := range d.hashPrev { + d.hashPrev[i] = 0 } d.hashOffset = 1 - d.index, d.windowEnd = 0, 0 d.blockStart, d.byteAvailable = 0, false - d.tokens.n = 0 d.length = minMatchLength - 1 d.offset = 0 @@ -1194,10 +1252,10 @@ func (d *compressor) close() error { // NewWriter returns a new Writer compressing data at the given level. // Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression); -// higher levels typically run slower but compress more. Level 0 -// (NoCompression) does not attempt any compression; it only adds the -// necessary DEFLATE framing. Level -1 (DefaultCompression) uses the default -// compression level. +// higher levels typically run slower but compress more. +// Level 0 (NoCompression) does not attempt any compression; it only adds the +// necessary DEFLATE framing. +// Level -1 (DefaultCompression) uses the default compression level. // Level -2 (ConstantCompression) will use Huffman compression only, giving // a very fast compression for all types of input, but sacrificing considerable // compression efficiency. @@ -1250,10 +1308,12 @@ func (w *Writer) Write(data []byte) (n int, err error) { return w.d.write(data) } -// Flush flushes any pending compressed data to the underlying writer. +// Flush flushes any pending data to the underlying writer. // It is useful mainly in compressed network protocols, to ensure that // a remote reader has enough data to reconstruct a packet. // Flush does not return until the data has been written. +// Calling Flush when there is no pending data still causes the Writer +// to emit a sync marker of at least 4 bytes. // If the underlying writer returns an error, Flush returns that error. // // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. @@ -1272,7 +1332,7 @@ func (w *Writer) Close() error { // the result of NewWriter or NewWriterDict called with dst // and w's level and dictionary. func (w *Writer) Reset(dst io.Writer) { - if dw, ok := w.d.w.w.(*dictWriter); ok { + if dw, ok := w.d.w.writer.(*dictWriter); ok { // w was created with NewWriterDict dw.w = dst w.d.reset(dw) diff --git a/vendor/github.com/klauspost/compress/flate/dict_decoder.go b/vendor/github.com/klauspost/compress/flate/dict_decoder.go new file mode 100644 index 00000000000..71c75a065ea --- /dev/null +++ b/vendor/github.com/klauspost/compress/flate/dict_decoder.go @@ -0,0 +1,184 @@ +// Copyright 2016 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 flate + +// dictDecoder implements the LZ77 sliding dictionary as used in decompression. +// LZ77 decompresses data through sequences of two forms of commands: +// +// * Literal insertions: Runs of one or more symbols are inserted into the data +// stream as is. This is accomplished through the writeByte method for a +// single symbol, or combinations of writeSlice/writeMark for multiple symbols. +// Any valid stream must start with a literal insertion if no preset dictionary +// is used. +// +// * Backward copies: Runs of one or more symbols are copied from previously +// emitted data. Backward copies come as the tuple (dist, length) where dist +// determines how far back in the stream to copy from and length determines how +// many bytes to copy. Note that it is valid for the length to be greater than +// the distance. Since LZ77 uses forward copies, that situation is used to +// perform a form of run-length encoding on repeated runs of symbols. +// The writeCopy and tryWriteCopy are used to implement this command. +// +// For performance reasons, this implementation performs little to no sanity +// checks about the arguments. As such, the invariants documented for each +// method call must be respected. +type dictDecoder struct { + hist []byte // Sliding window history + + // Invariant: 0 <= rdPos <= wrPos <= len(hist) + wrPos int // Current output position in buffer + rdPos int // Have emitted hist[:rdPos] already + full bool // Has a full window length been written yet? +} + +// init initializes dictDecoder to have a sliding window dictionary of the given +// size. If a preset dict is provided, it will initialize the dictionary with +// the contents of dict. +func (dd *dictDecoder) init(size int, dict []byte) { + *dd = dictDecoder{hist: dd.hist} + + if cap(dd.hist) < size { + dd.hist = make([]byte, size) + } + dd.hist = dd.hist[:size] + + if len(dict) > len(dd.hist) { + dict = dict[len(dict)-len(dd.hist):] + } + dd.wrPos = copy(dd.hist, dict) + if dd.wrPos == len(dd.hist) { + dd.wrPos = 0 + dd.full = true + } + dd.rdPos = dd.wrPos +} + +// histSize reports the total amount of historical data in the dictionary. +func (dd *dictDecoder) histSize() int { + if dd.full { + return len(dd.hist) + } + return dd.wrPos +} + +// availRead reports the number of bytes that can be flushed by readFlush. +func (dd *dictDecoder) availRead() int { + return dd.wrPos - dd.rdPos +} + +// availWrite reports the available amount of output buffer space. +func (dd *dictDecoder) availWrite() int { + return len(dd.hist) - dd.wrPos +} + +// writeSlice returns a slice of the available buffer to write data to. +// +// This invariant will be kept: len(s) <= availWrite() +func (dd *dictDecoder) writeSlice() []byte { + return dd.hist[dd.wrPos:] +} + +// writeMark advances the writer pointer by cnt. +// +// This invariant must be kept: 0 <= cnt <= availWrite() +func (dd *dictDecoder) writeMark(cnt int) { + dd.wrPos += cnt +} + +// writeByte writes a single byte to the dictionary. +// +// This invariant must be kept: 0 < availWrite() +func (dd *dictDecoder) writeByte(c byte) { + dd.hist[dd.wrPos] = c + dd.wrPos++ +} + +// writeCopy copies a string at a given (dist, length) to the output. +// This returns the number of bytes copied and may be less than the requested +// length if the available space in the output buffer is too small. +// +// This invariant must be kept: 0 < dist <= histSize() +func (dd *dictDecoder) writeCopy(dist, length int) int { + dstBase := dd.wrPos + dstPos := dstBase + srcPos := dstPos - dist + endPos := dstPos + length + if endPos > len(dd.hist) { + endPos = len(dd.hist) + } + + // Copy non-overlapping section after destination position. + // + // This section is non-overlapping in that the copy length for this section + // is always less than or equal to the backwards distance. This can occur + // if a distance refers to data that wraps-around in the buffer. + // Thus, a backwards copy is performed here; that is, the exact bytes in + // the source prior to the copy is placed in the destination. + if srcPos < 0 { + srcPos += len(dd.hist) + dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:]) + srcPos = 0 + } + + // Copy possibly overlapping section before destination position. + // + // This section can overlap if the copy length for this section is larger + // than the backwards distance. This is allowed by LZ77 so that repeated + // strings can be succinctly represented using (dist, length) pairs. + // Thus, a forwards copy is performed here; that is, the bytes copied is + // possibly dependent on the resulting bytes in the destination as the copy + // progresses along. This is functionally equivalent to the following: + // + // for i := 0; i < endPos-dstPos; i++ { + // dd.hist[dstPos+i] = dd.hist[srcPos+i] + // } + // dstPos = endPos + // + for dstPos < endPos { + dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos]) + } + + dd.wrPos = dstPos + return dstPos - dstBase +} + +// tryWriteCopy tries to copy a string at a given (distance, length) to the +// output. This specialized version is optimized for short distances. +// +// This method is designed to be inlined for performance reasons. +// +// This invariant must be kept: 0 < dist <= histSize() +func (dd *dictDecoder) tryWriteCopy(dist, length int) int { + dstPos := dd.wrPos + endPos := dstPos + length + if dstPos < dist || endPos > len(dd.hist) { + return 0 + } + dstBase := dstPos + srcPos := dstPos - dist + + // Copy possibly overlapping section before destination position. +loop: + dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos]) + if dstPos < endPos { + goto loop // Avoid for-loop so that this function can be inlined + } + + dd.wrPos = dstPos + return dstPos - dstBase +} + +// readFlush returns a slice of the historical buffer that is ready to be +// emitted to the user. The data returned by readFlush must be fully consumed +// before calling any other dictDecoder methods. +func (dd *dictDecoder) readFlush() []byte { + toRead := dd.hist[dd.rdPos:dd.wrPos] + dd.rdPos = dd.wrPos + if dd.wrPos == len(dd.hist) { + dd.wrPos, dd.rdPos = 0, 0 + dd.full = true + } + return toRead +} diff --git a/vendor/github.com/klauspost/compress/flate/fixedhuff.go b/vendor/github.com/klauspost/compress/flate/fixedhuff.go deleted file mode 100644 index 7df8b9a293f..00000000000 --- a/vendor/github.com/klauspost/compress/flate/fixedhuff.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2013 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 flate - -// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT - -var fixedHuffmanDecoder = huffmanDecoder{ - 7, - [huffmanNumChunks]uint32{ - 0x1007, 0x0508, 0x0108, 0x1188, 0x1107, 0x0708, 0x0308, 0x0c09, - 0x1087, 0x0608, 0x0208, 0x0a09, 0x0008, 0x0808, 0x0408, 0x0e09, - 0x1047, 0x0588, 0x0188, 0x0909, 0x1147, 0x0788, 0x0388, 0x0d09, - 0x10c7, 0x0688, 0x0288, 0x0b09, 0x0088, 0x0888, 0x0488, 0x0f09, - 0x1027, 0x0548, 0x0148, 0x11c8, 0x1127, 0x0748, 0x0348, 0x0c89, - 0x10a7, 0x0648, 0x0248, 0x0a89, 0x0048, 0x0848, 0x0448, 0x0e89, - 0x1067, 0x05c8, 0x01c8, 0x0989, 0x1167, 0x07c8, 0x03c8, 0x0d89, - 0x10e7, 0x06c8, 0x02c8, 0x0b89, 0x00c8, 0x08c8, 0x04c8, 0x0f89, - 0x1017, 0x0528, 0x0128, 0x11a8, 0x1117, 0x0728, 0x0328, 0x0c49, - 0x1097, 0x0628, 0x0228, 0x0a49, 0x0028, 0x0828, 0x0428, 0x0e49, - 0x1057, 0x05a8, 0x01a8, 0x0949, 0x1157, 0x07a8, 0x03a8, 0x0d49, - 0x10d7, 0x06a8, 0x02a8, 0x0b49, 0x00a8, 0x08a8, 0x04a8, 0x0f49, - 0x1037, 0x0568, 0x0168, 0x11e8, 0x1137, 0x0768, 0x0368, 0x0cc9, - 0x10b7, 0x0668, 0x0268, 0x0ac9, 0x0068, 0x0868, 0x0468, 0x0ec9, - 0x1077, 0x05e8, 0x01e8, 0x09c9, 0x1177, 0x07e8, 0x03e8, 0x0dc9, - 0x10f7, 0x06e8, 0x02e8, 0x0bc9, 0x00e8, 0x08e8, 0x04e8, 0x0fc9, - 0x1007, 0x0518, 0x0118, 0x1198, 0x1107, 0x0718, 0x0318, 0x0c29, - 0x1087, 0x0618, 0x0218, 0x0a29, 0x0018, 0x0818, 0x0418, 0x0e29, - 0x1047, 0x0598, 0x0198, 0x0929, 0x1147, 0x0798, 0x0398, 0x0d29, - 0x10c7, 0x0698, 0x0298, 0x0b29, 0x0098, 0x0898, 0x0498, 0x0f29, - 0x1027, 0x0558, 0x0158, 0x11d8, 0x1127, 0x0758, 0x0358, 0x0ca9, - 0x10a7, 0x0658, 0x0258, 0x0aa9, 0x0058, 0x0858, 0x0458, 0x0ea9, - 0x1067, 0x05d8, 0x01d8, 0x09a9, 0x1167, 0x07d8, 0x03d8, 0x0da9, - 0x10e7, 0x06d8, 0x02d8, 0x0ba9, 0x00d8, 0x08d8, 0x04d8, 0x0fa9, - 0x1017, 0x0538, 0x0138, 0x11b8, 0x1117, 0x0738, 0x0338, 0x0c69, - 0x1097, 0x0638, 0x0238, 0x0a69, 0x0038, 0x0838, 0x0438, 0x0e69, - 0x1057, 0x05b8, 0x01b8, 0x0969, 0x1157, 0x07b8, 0x03b8, 0x0d69, - 0x10d7, 0x06b8, 0x02b8, 0x0b69, 0x00b8, 0x08b8, 0x04b8, 0x0f69, - 0x1037, 0x0578, 0x0178, 0x11f8, 0x1137, 0x0778, 0x0378, 0x0ce9, - 0x10b7, 0x0678, 0x0278, 0x0ae9, 0x0078, 0x0878, 0x0478, 0x0ee9, - 0x1077, 0x05f8, 0x01f8, 0x09e9, 0x1177, 0x07f8, 0x03f8, 0x0de9, - 0x10f7, 0x06f8, 0x02f8, 0x0be9, 0x00f8, 0x08f8, 0x04f8, 0x0fe9, - 0x1007, 0x0508, 0x0108, 0x1188, 0x1107, 0x0708, 0x0308, 0x0c19, - 0x1087, 0x0608, 0x0208, 0x0a19, 0x0008, 0x0808, 0x0408, 0x0e19, - 0x1047, 0x0588, 0x0188, 0x0919, 0x1147, 0x0788, 0x0388, 0x0d19, - 0x10c7, 0x0688, 0x0288, 0x0b19, 0x0088, 0x0888, 0x0488, 0x0f19, - 0x1027, 0x0548, 0x0148, 0x11c8, 0x1127, 0x0748, 0x0348, 0x0c99, - 0x10a7, 0x0648, 0x0248, 0x0a99, 0x0048, 0x0848, 0x0448, 0x0e99, - 0x1067, 0x05c8, 0x01c8, 0x0999, 0x1167, 0x07c8, 0x03c8, 0x0d99, - 0x10e7, 0x06c8, 0x02c8, 0x0b99, 0x00c8, 0x08c8, 0x04c8, 0x0f99, - 0x1017, 0x0528, 0x0128, 0x11a8, 0x1117, 0x0728, 0x0328, 0x0c59, - 0x1097, 0x0628, 0x0228, 0x0a59, 0x0028, 0x0828, 0x0428, 0x0e59, - 0x1057, 0x05a8, 0x01a8, 0x0959, 0x1157, 0x07a8, 0x03a8, 0x0d59, - 0x10d7, 0x06a8, 0x02a8, 0x0b59, 0x00a8, 0x08a8, 0x04a8, 0x0f59, - 0x1037, 0x0568, 0x0168, 0x11e8, 0x1137, 0x0768, 0x0368, 0x0cd9, - 0x10b7, 0x0668, 0x0268, 0x0ad9, 0x0068, 0x0868, 0x0468, 0x0ed9, - 0x1077, 0x05e8, 0x01e8, 0x09d9, 0x1177, 0x07e8, 0x03e8, 0x0dd9, - 0x10f7, 0x06e8, 0x02e8, 0x0bd9, 0x00e8, 0x08e8, 0x04e8, 0x0fd9, - 0x1007, 0x0518, 0x0118, 0x1198, 0x1107, 0x0718, 0x0318, 0x0c39, - 0x1087, 0x0618, 0x0218, 0x0a39, 0x0018, 0x0818, 0x0418, 0x0e39, - 0x1047, 0x0598, 0x0198, 0x0939, 0x1147, 0x0798, 0x0398, 0x0d39, - 0x10c7, 0x0698, 0x0298, 0x0b39, 0x0098, 0x0898, 0x0498, 0x0f39, - 0x1027, 0x0558, 0x0158, 0x11d8, 0x1127, 0x0758, 0x0358, 0x0cb9, - 0x10a7, 0x0658, 0x0258, 0x0ab9, 0x0058, 0x0858, 0x0458, 0x0eb9, - 0x1067, 0x05d8, 0x01d8, 0x09b9, 0x1167, 0x07d8, 0x03d8, 0x0db9, - 0x10e7, 0x06d8, 0x02d8, 0x0bb9, 0x00d8, 0x08d8, 0x04d8, 0x0fb9, - 0x1017, 0x0538, 0x0138, 0x11b8, 0x1117, 0x0738, 0x0338, 0x0c79, - 0x1097, 0x0638, 0x0238, 0x0a79, 0x0038, 0x0838, 0x0438, 0x0e79, - 0x1057, 0x05b8, 0x01b8, 0x0979, 0x1157, 0x07b8, 0x03b8, 0x0d79, - 0x10d7, 0x06b8, 0x02b8, 0x0b79, 0x00b8, 0x08b8, 0x04b8, 0x0f79, - 0x1037, 0x0578, 0x0178, 0x11f8, 0x1137, 0x0778, 0x0378, 0x0cf9, - 0x10b7, 0x0678, 0x0278, 0x0af9, 0x0078, 0x0878, 0x0478, 0x0ef9, - 0x1077, 0x05f8, 0x01f8, 0x09f9, 0x1177, 0x07f8, 0x03f8, 0x0df9, - 0x10f7, 0x06f8, 0x02f8, 0x0bf9, 0x00f8, 0x08f8, 0x04f8, 0x0ff9, - }, - nil, 0, -} diff --git a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go index 56985ef000b..f9b2a699a3d 100644 --- a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go +++ b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go @@ -6,7 +6,6 @@ package flate import ( "io" - "math" ) const ( @@ -23,9 +22,16 @@ const ( codegenCodeCount = 19 badCode = 255 - // Output byte buffer size - // Must be multiple of 6 (48 bits) + 8 - bufferSize = 240 + 8 + // bufferFlushSize indicates the buffer size + // after which bytes are flushed to the writer. + // Should preferably be a multiple of 6, since + // we accumulate 6 bytes between writes to the buffer. + bufferFlushSize = 240 + + // bufferSize is the actual output byte buffer size. + // It must have additional headroom for a flush + // which can contain up to 8 bytes. + bufferSize = bufferFlushSize + 8 ) // The number of extra bits needed by length code X - LENGTH_CODES_START. @@ -71,17 +77,21 @@ var offsetBase = []uint32{ var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} type huffmanBitWriter struct { - w io.Writer + // writer is the underlying writer. + // Do not use it directly; use the write method, which ensures + // that Write errors are sticky. + writer io.Writer + // Data waiting to be written is bytes[0:nbytes] // and then the low nbits of bits. bits uint64 nbits uint bytes [bufferSize]byte + codegenFreq [codegenCodeCount]int32 nbytes int literalFreq []int32 offsetFreq []int32 codegen []uint8 - codegenFreq []int32 literalEncoding *huffmanEncoder offsetEncoding *huffmanEncoder codegenEncoding *huffmanEncoder @@ -90,61 +100,22 @@ type huffmanBitWriter struct { func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { return &huffmanBitWriter{ - w: w, + writer: w, literalFreq: make([]int32, maxNumLit), offsetFreq: make([]int32, offsetCodeCount), codegen: make([]uint8, maxNumLit+offsetCodeCount+1), - codegenFreq: make([]int32, codegenCodeCount), literalEncoding: newHuffmanEncoder(maxNumLit), - offsetEncoding: newHuffmanEncoder(offsetCodeCount), codegenEncoding: newHuffmanEncoder(codegenCodeCount), + offsetEncoding: newHuffmanEncoder(offsetCodeCount), } } func (w *huffmanBitWriter) reset(writer io.Writer) { - w.w = writer + w.writer = writer w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil w.bytes = [bufferSize]byte{} - for i := range w.codegen { - w.codegen[i] = 0 - } - for _, s := range [...][]int32{w.literalFreq, w.offsetFreq, w.codegenFreq} { - for i := range s { - s[i] = 0 - } - } - encs := []*huffmanEncoder{w.literalEncoding, w.codegenEncoding} - // Don't reset, if we are huffman only mode - if w.offsetEncoding != huffOffset { - encs = append(encs, w.offsetEncoding) - } - for _, enc := range encs { - for i := range enc.codes { - enc.codes[i] = 0 - } - } } -/* Inlined in writeBits -func (w *huffmanBitWriter) flushBits() { - if w.err != nil { - w.nbits = 0 - return - } - bits := w.bits - w.bits >>= 16 - w.nbits -= 16 - n := w.nbytes - w.bytes[n] = byte(bits) - w.bytes[n+1] = byte(bits >> 8) - if n += 2; n >= len(w.bytes) { - _, w.err = w.w.Write(w.bytes[0:]) - n = 0 - } - w.nbytes = n -} -*/ - func (w *huffmanBitWriter) flush() { if w.err != nil { w.nbits = 0 @@ -162,11 +133,21 @@ func (w *huffmanBitWriter) flush() { n++ } w.bits = 0 - _, w.err = w.w.Write(w.bytes[0:n]) + w.write(w.bytes[:n]) w.nbytes = 0 } +func (w *huffmanBitWriter) write(b []byte) { + if w.err != nil { + return + } + _, w.err = w.writer.Write(b) +} + func (w *huffmanBitWriter) writeBits(b int32, nb uint) { + if w.err != nil { + return + } w.bits |= uint64(b) << w.nbits w.nbits += nb if w.nbits >= 48 { @@ -174,15 +155,16 @@ func (w *huffmanBitWriter) writeBits(b int32, nb uint) { w.bits >>= 48 w.nbits -= 48 n := w.nbytes - w.bytes[n] = byte(bits) - w.bytes[n+1] = byte(bits >> 8) - w.bytes[n+2] = byte(bits >> 16) - w.bytes[n+3] = byte(bits >> 24) - w.bytes[n+4] = byte(bits >> 32) - w.bytes[n+5] = byte(bits >> 40) + bytes := w.bytes[n : n+6] + bytes[0] = byte(bits) + bytes[1] = byte(bits >> 8) + bytes[2] = byte(bits >> 16) + bytes[3] = byte(bits >> 24) + bytes[4] = byte(bits >> 32) + bytes[5] = byte(bits >> 40) n += 6 - if n >= bufferSize-8 { - _, w.err = w.w.Write(w.bytes[:bufferSize-8]) + if n >= bufferFlushSize { + w.write(w.bytes[:n]) n = 0 } w.nbytes = n @@ -194,24 +176,21 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) { return } n := w.nbytes + if w.nbits&7 != 0 { + w.err = InternalError("writeBytes with unfinished bits") + return + } for w.nbits != 0 { w.bytes[n] = byte(w.bits) w.bits >>= 8 w.nbits -= 8 n++ } - if w.nbits != 0 { - w.err = InternalError("writeBytes with unfinished bits") - return - } if n != 0 { - _, w.err = w.w.Write(w.bytes[0:n]) - if w.err != nil { - return - } + w.write(w.bytes[:n]) } w.nbytes = 0 - _, w.err = w.w.Write(bytes) + w.write(bytes) } // RFC 1951 3.2.7 specifies a special run-length encoding for specifying @@ -221,11 +200,12 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) { // The result is written into the codegen array, and the frequencies // of each code is written into the codegenFreq array. // Codes 0-15 are single byte codes. Codes 16-18 are followed by additional -// information. Code badCode is an end marker +// information. Code badCode is an end marker // // numLiterals The number of literals in literalEncoding // numOffsets The number of offsets in offsetEncoding -func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { +// litenc, offenc The literal and offset encoder to use +func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) { for i := range w.codegenFreq { w.codegenFreq[i] = 0 } @@ -234,17 +214,15 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { // This is fine because the output is always shorter than the input used // so far. codegen := w.codegen // cache - // Copy the concatenated code sizes to codegen. Put a marker at the end. - //copy(codegen[0:numLiterals], w.literalEncoding.codeBits) - cgnl := codegen[0:numLiterals] + // Copy the concatenated code sizes to codegen. Put a marker at the end. + cgnl := codegen[:numLiterals] for i := range cgnl { - cgnl[i] = uint8(w.literalEncoding.codes[i].bits()) + cgnl[i] = uint8(litEnc.codes[i].len) } - //copy(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits) cgnl = codegen[numLiterals : numLiterals+numOffsets] for i := range cgnl { - cgnl[i] = uint8(w.offsetEncoding.codes[i].bits()) + cgnl[i] = uint8(offEnc.codes[i].len) } codegen[numLiterals+numOffsets] = badCode @@ -314,42 +292,71 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { codegen[outIndex] = badCode } -/* non-inlined: -func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) { - if w.err != nil { - return +// dynamicSize returns the size of dynamically encoded data in bits. +func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) { + numCodegens = len(w.codegenFreq) + for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { + numCodegens-- } - c := code.codes[literal] - w.writeBits(int32(c.code()), int32(c.bits())) -} -*/ + header := 3 + 5 + 5 + 4 + (3 * numCodegens) + + w.codegenEncoding.bitLength(w.codegenFreq[:]) + + int(w.codegenFreq[16])*2 + + int(w.codegenFreq[17])*3 + + int(w.codegenFreq[18])*7 + size = header + + litEnc.bitLength(w.literalFreq) + + offEnc.bitLength(w.offsetFreq) + + extraBits -func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) { + return size, numCodegens +} + +// fixedSize returns the size of dynamically encoded data in bits. +func (w *huffmanBitWriter) fixedSize(extraBits int) int { + return 3 + + fixedLiteralEncoding.bitLength(w.literalFreq) + + fixedOffsetEncoding.bitLength(w.offsetFreq) + + extraBits +} + +// storedSize calculates the stored size, including header. +// The function returns the size in bits and whether the block +// fits inside a single block. +func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) { + if in == nil { + return 0, false + } + if len(in) <= maxStoreBlockSize { + return (len(in) + 5) * 8, true + } + return 0, false +} + +func (w *huffmanBitWriter) writeCode(c hcode) { if w.err != nil { return } - c := code.codes[literal] - w.bits |= uint64(c.code()) << w.nbits - w.nbits += c.bits() + w.bits |= uint64(c.code) << w.nbits + w.nbits += uint(c.len) if w.nbits >= 48 { bits := w.bits w.bits >>= 48 w.nbits -= 48 n := w.nbytes - w.bytes[n] = byte(bits) - w.bytes[n+1] = byte(bits >> 8) - w.bytes[n+2] = byte(bits >> 16) - w.bytes[n+3] = byte(bits >> 24) - w.bytes[n+4] = byte(bits >> 32) - w.bytes[n+5] = byte(bits >> 40) + bytes := w.bytes[n : n+6] + bytes[0] = byte(bits) + bytes[1] = byte(bits >> 8) + bytes[2] = byte(bits >> 16) + bytes[3] = byte(bits >> 24) + bytes[4] = byte(bits >> 32) + bytes[5] = byte(bits >> 40) n += 6 - if n >= bufferSize-8 { - _, w.err = w.w.Write(w.bytes[:bufferSize-8]) + if n >= bufferFlushSize { + w.write(w.bytes[:n]) n = 0 } w.nbytes = n } - } // Write the header of a dynamic Huffman block to the output stream. @@ -371,8 +378,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n w.writeBits(int32(numCodegens-4), 4) for i := 0; i < numCodegens; i++ { - //value := w.codegenEncoding.codeBits[codegenOrder[i]] - value := w.codegenEncoding.codes[codegenOrder[i]].bits() + value := uint(w.codegenEncoding.codes[codegenOrder[i]].len) w.writeBits(int32(value), 3) } @@ -383,8 +389,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n if codeWord == badCode { break } - // The low byte contains the actual code to generate. - w.writeCode(w.codegenEncoding, uint32(codeWord)) + w.writeCode(w.codegenEncoding.codes[uint32(codeWord)]) switch codeWord { case 16: @@ -429,102 +434,50 @@ func (w *huffmanBitWriter) writeFixedHeader(isEof bool) { w.writeBits(value, 3) } -func (w *huffmanBitWriter) writeBlock(tok tokens, eof bool, input []byte) { +// writeBlock will write a block of tokens with the smallest encoding. +// The original input can be supplied, and if the huffman encoded data +// is larger than the original bytes, the data will be written as a +// stored block. +// If the input is nil, the tokens will always be Huffman encoded. +func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) { if w.err != nil { return } - copy(w.literalFreq, zeroLits[:]) - for i := range w.offsetFreq { - w.offsetFreq[i] = 0 - } + tokens = append(tokens, endBlockMarker) + numLiterals, numOffsets := w.indexTokens(tokens) - tok.tokens[tok.n] = endBlockMarker - tokens := tok.tokens[0 : tok.n+1] - - for _, t := range tokens { - switch t.typ() { - case literalType: - w.literalFreq[t.literal()]++ - case matchType: - length := t.length() - offset := t.offset() - w.literalFreq[lengthCodesStart+lengthCode(length)]++ - w.offsetFreq[offsetCode(offset)]++ - } - } - - // get the number of literals - numLiterals := len(w.literalFreq) - for w.literalFreq[numLiterals-1] == 0 { - numLiterals-- - } - // get the number of offsets - numOffsets := len(w.offsetFreq) - for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 { - numOffsets-- - } - if numOffsets == 0 { - // We haven't found a single match. If we want to go with the dynamic encoding, - // we should count at least one offset to be sure that the offset huffman tree could be encoded. - w.offsetFreq[0] = 1 - numOffsets = 1 - } - - w.literalEncoding.generate(w.literalFreq, 15) - w.offsetEncoding.generate(w.offsetFreq, 15) - - storedBytes := 0 - if input != nil { - storedBytes = len(input) - } - var extraBits int64 - var storedSize int64 = math.MaxInt64 - if storedBytes <= maxStoreBlockSize && input != nil { - storedSize = int64((storedBytes + 5) * 8) + var extraBits int + storedSize, storable := w.storedSize(input) + if storable { // We only bother calculating the costs of the extra bits required by // the length of offset fields (which will be the same for both fixed // and dynamic encoding), if we need to compare those two encodings // against stored encoding. for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ { // First eight length codes have extra size = 0. - extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart]) + extraBits += int(w.literalFreq[lengthCode]) * int(lengthExtraBits[lengthCode-lengthCodesStart]) } for offsetCode := 4; offsetCode < numOffsets; offsetCode++ { // First four offset codes have extra size = 0. - extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode]) + extraBits += int(w.offsetFreq[offsetCode]) * int(offsetExtraBits[offsetCode]) } } // Figure out smallest code. // Fixed Huffman baseline. - var size = int64(3) + - fixedLiteralEncoding.bitLength(w.literalFreq) + - fixedOffsetEncoding.bitLength(w.offsetFreq) + - extraBits var literalEncoding = fixedLiteralEncoding var offsetEncoding = fixedOffsetEncoding + var size = w.fixedSize(extraBits) // Dynamic Huffman? var numCodegens int // Generate codegen and codegenFrequencies, which indicates how to encode // the literalEncoding and the offsetEncoding. - w.generateCodegen(numLiterals, numOffsets) - w.codegenEncoding.generate(w.codegenFreq, 7) - numCodegens = len(w.codegenFreq) - for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { - numCodegens-- - } - dynamicHeader := int64(3+5+5+4+(3*numCodegens)) + - w.codegenEncoding.bitLength(w.codegenFreq) + - int64(extraBits) + - int64(w.codegenFreq[16]*2) + - int64(w.codegenFreq[17]*3) + - int64(w.codegenFreq[18]*7) - dynamicSize := dynamicHeader + - w.literalEncoding.bitLength(w.literalFreq) + - w.offsetEncoding.bitLength(w.offsetFreq) + w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding) + w.codegenEncoding.generate(w.codegenFreq[:], 7) + dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits) if dynamicSize < size { size = dynamicSize @@ -533,9 +486,9 @@ func (w *huffmanBitWriter) writeBlock(tok tokens, eof bool, input []byte) { } // Stored bytes? - if storedSize < size { - w.writeStoredHeader(storedBytes, eof) - w.writeBytes(input[0:storedBytes]) + if storable && storedSize < size { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) return } @@ -545,89 +498,153 @@ func (w *huffmanBitWriter) writeBlock(tok tokens, eof bool, input []byte) { } else { w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) } + + // Write the tokens. + w.writeTokens(tokens, literalEncoding.codes, offsetEncoding.codes) +} + +// writeBlockDynamic encodes a block using a dynamic Huffman table. +// This should be used if the symbols used have a disproportionate +// histogram distribution. +// If input is supplied and the compression savings are below 1/16th of the +// input size the block is stored. +func (w *huffmanBitWriter) writeBlockDynamic(tokens []token, eof bool, input []byte) { + if w.err != nil { + return + } + + tokens = append(tokens, endBlockMarker) + numLiterals, numOffsets := w.indexTokens(tokens) + + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding) + w.codegenEncoding.generate(w.codegenFreq[:], 7) + size, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, 0) + + // Store bytes, if we don't get a reasonable improvement. + if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) + return + } + + // Write Huffman table. + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + + // Write the tokens. + w.writeTokens(tokens, w.literalEncoding.codes, w.offsetEncoding.codes) +} + +// indexTokens indexes a slice of tokens, and updates +// literalFreq and offsetFreq, and generates literalEncoding +// and offsetEncoding. +// The number of literal and offset tokens is returned. +func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets int) { + for i := range w.literalFreq { + w.literalFreq[i] = 0 + } + for i := range w.offsetFreq { + w.offsetFreq[i] = 0 + } + for _, t := range tokens { - switch t.typ() { - case literalType: - w.writeCode(literalEncoding, t.literal()) - break - case matchType: - // Write the length - length := t.length() - lengthCode := lengthCode(length) - w.writeCode(literalEncoding, lengthCode+lengthCodesStart) - extraLengthBits := uint(lengthExtraBits[lengthCode]) - if extraLengthBits > 0 { - extraLength := int32(length - lengthBase[lengthCode]) - w.writeBits(extraLength, extraLengthBits) - } - // Write the offset - offset := t.offset() - offsetCode := offsetCode(offset) - w.writeCode(offsetEncoding, offsetCode) - extraOffsetBits := uint(offsetExtraBits[offsetCode]) - if extraOffsetBits > 0 { - extraOffset := int32(offset - offsetBase[offsetCode]) - w.writeBits(extraOffset, extraOffsetBits) - } - break - default: - panic("unknown token type: " + string(t)) + if t < matchType { + w.literalFreq[t.literal()]++ + continue + } + length := t.length() + offset := t.offset() + w.literalFreq[lengthCodesStart+lengthCode(length)]++ + w.offsetFreq[offsetCode(offset)]++ + } + + // get the number of literals + numLiterals = len(w.literalFreq) + for w.literalFreq[numLiterals-1] == 0 { + numLiterals-- + } + // get the number of offsets + numOffsets = len(w.offsetFreq) + for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 { + numOffsets-- + } + if numOffsets == 0 { + // We haven't found a single match. If we want to go with the dynamic encoding, + // we should count at least one offset to be sure that the offset huffman tree could be encoded. + w.offsetFreq[0] = 1 + numOffsets = 1 + } + w.literalEncoding.generate(w.literalFreq, 15) + w.offsetEncoding.generate(w.offsetFreq, 15) + return +} + +// writeTokens writes a slice of tokens to the output. +// codes for literal and offset encoding must be supplied. +func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) { + if w.err != nil { + return + } + for _, t := range tokens { + if t < matchType { + w.writeCode(leCodes[t.literal()]) + continue + } + // Write the length + length := t.length() + lengthCode := lengthCode(length) + w.writeCode(leCodes[lengthCode+lengthCodesStart]) + extraLengthBits := uint(lengthExtraBits[lengthCode]) + if extraLengthBits > 0 { + extraLength := int32(length - lengthBase[lengthCode]) + w.writeBits(extraLength, extraLengthBits) + } + // Write the offset + offset := t.offset() + offsetCode := offsetCode(offset) + w.writeCode(oeCodes[offsetCode]) + extraOffsetBits := uint(offsetExtraBits[offsetCode]) + if extraOffsetBits > 0 { + extraOffset := int32(offset - offsetBase[offsetCode]) + w.writeBits(extraOffset, extraOffsetBits) } } } +// huffOffset is a static offset encoder used for huffman only encoding. +// It can be reused since we will not be encoding offset values. var huffOffset *huffmanEncoder -var zeroLits [maxNumLit]int32 func init() { - var w = newHuffmanBitWriter(nil) + w := newHuffmanBitWriter(nil) w.offsetFreq[0] = 1 - w.offsetEncoding = newHuffmanEncoder(offsetCodeCount) - w.offsetEncoding.generate(w.offsetFreq, 15) - huffOffset = w.offsetEncoding + huffOffset = newHuffmanEncoder(offsetCodeCount) + huffOffset.generate(w.offsetFreq, 15) } -// writeBlockHuff will write a block of bytes as either -// Huffman encoded literals, or uncompressed bytes depending -// on what yields the smallest result. +// writeBlockHuff encodes a block of bytes as either +// Huffman encoded literals or uncompressed bytes if the +// results only gains very little from compression. func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) { if w.err != nil { return } + // Clear histogram - copy(w.literalFreq, zeroLits[:]) + for i := range w.literalFreq { + w.literalFreq[i] = 0 + } // Add everything as literals histogram(input, w.literalFreq) - w.literalFreq[endBlockMarker]++ + w.literalFreq[endBlockMarker] = 1 - // get the number of literals - numLiterals := len(w.literalFreq) - for w.literalFreq[numLiterals-1] == 0 { - numLiterals-- - } - - numOffsets := 1 + const numLiterals = endBlockMarker + 1 + const numOffsets = 1 w.literalEncoding.generate(w.literalFreq, 15) - w.offsetEncoding = huffOffset - - storedBytes := len(input) - - var extraBits int64 - var storedSize int64 = math.MaxInt64 - if storedBytes <= maxStoreBlockSize { - storedSize = int64((storedBytes + 5) * 8) - // We only bother calculating the costs of the extra bits required by - // the length of offset fields (which will be the same for both fixed - // and dynamic encoding), if we need to compare those two encodings - // against stored encoding. - for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ { - // First eight length codes have extra size = 0. - extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart]) - } - } // Figure out smallest code. // Always use dynamic Huffman or Store @@ -635,56 +652,50 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) { // Generate codegen and codegenFrequencies, which indicates how to encode // the literalEncoding and the offsetEncoding. - w.generateCodegen(numLiterals, numOffsets) - w.codegenEncoding.generate(w.codegenFreq, 7) - numCodegens = len(w.codegenFreq) - for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { - numCodegens-- - } - dynamicHeader := int64(3+5+5+4+(3*numCodegens)) + - w.codegenEncoding.bitLength(w.codegenFreq) + - int64(extraBits) + - int64(w.codegenFreq[16]*2) + - int64(w.codegenFreq[17]*3) + - int64(w.codegenFreq[18]*7) - size := dynamicHeader + - w.literalEncoding.bitLength(w.literalFreq) + - 1 /*w.offsetEncoding.bitLength(w.offsetFreq)*/ + w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, huffOffset) + w.codegenEncoding.generate(w.codegenFreq[:], 7) + size, numCodegens := w.dynamicSize(w.literalEncoding, huffOffset, 0) - // Stored bytes? - if storedSize < size { - w.writeStoredHeader(storedBytes, eof) - w.writeBytes(input[0:storedBytes]) + // Store bytes, if we don't get a reasonable improvement. + if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) return } // Huffman. w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + encoding := w.literalEncoding.codes[:257] + n := w.nbytes for _, t := range input { // Bitwriting inlined, ~30% speedup - c := w.literalEncoding.codes[t] - w.bits |= uint64(c.code()) << w.nbits - w.nbits += c.bits() - if w.nbits >= 48 { - bits := w.bits - w.bits >>= 48 - w.nbits -= 48 - n := w.nbytes - w.bytes[n] = byte(bits) - w.bytes[n+1] = byte(bits >> 8) - w.bytes[n+2] = byte(bits >> 16) - w.bytes[n+3] = byte(bits >> 24) - w.bytes[n+4] = byte(bits >> 32) - w.bytes[n+5] = byte(bits >> 40) - n += 6 - if n >= bufferSize-8 { - _, w.err = w.w.Write(w.bytes[:bufferSize-8]) - w.nbytes = 0 - } else { - w.nbytes = n - } + c := encoding[t] + w.bits |= uint64(c.code) << w.nbits + w.nbits += uint(c.len) + if w.nbits < 48 { + continue } + // Store 6 bytes + bits := w.bits + w.bits >>= 48 + w.nbits -= 48 + bytes := w.bytes[n : n+6] + bytes[0] = byte(bits) + bytes[1] = byte(bits >> 8) + bytes[2] = byte(bits >> 16) + bytes[3] = byte(bits >> 24) + bytes[4] = byte(bits >> 32) + bytes[5] = byte(bits >> 40) + n += 6 + if n < bufferFlushSize { + continue + } + w.write(w.bytes[:n]) + if w.err != nil { + return // Return early in the event of write failures + } + n = 0 } - // Write EOB - w.writeCode(w.literalEncoding, endBlockMarker) + w.nbytes = n + w.writeCode(encoding[endBlockMarker]) } diff --git a/vendor/github.com/klauspost/compress/flate/huffman_code.go b/vendor/github.com/klauspost/compress/flate/huffman_code.go index 9dba0faf339..bdcbd823b00 100644 --- a/vendor/github.com/klauspost/compress/flate/huffman_code.go +++ b/vendor/github.com/klauspost/compress/flate/huffman_code.go @@ -9,14 +9,17 @@ import ( "sort" ) -type hcode uint32 +// hcode is a huffman code with a bit code and bit length. +type hcode struct { + code, len uint16 +} type huffmanEncoder struct { codes []hcode freqcache []literalNode bitCount [17]int32 - lns literalNodeSorter - lfs literalFreqSorter + lns byLiteral // stored to avoid repeated allocation in generate + lfs byFreq // stored to avoid repeated allocation in generate } type literalNode struct { @@ -44,34 +47,16 @@ type levelInfo struct { needed int32 } -func (h hcode) codeBits() (code uint16, bits uint8) { - return uint16(h), uint8(h >> 16) -} - -func (h *hcode) set(code uint16, bits uint8) { - *h = hcode(code) | hcode(uint32(bits)<<16) -} - -func (h *hcode) setBits(bits uint8) { - *h = hcode(*h&0xffff) | hcode(uint32(bits)<<16) -} - -func toCode(code uint16, bits uint8) hcode { - return hcode(code) | hcode(uint32(bits)<<16) -} - -func (h hcode) code() (code uint16) { - return uint16(h) -} - -func (h hcode) bits() (bits uint) { - return uint(h >> 16) +// set sets the code and length of an hcode. +func (h *hcode) set(code uint16, length uint16) { + h.len = length + h.code = code } func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} } func newHuffmanEncoder(size int) *huffmanEncoder { - return &huffmanEncoder{codes: make([]hcode, size), freqcache: nil} + return &huffmanEncoder{codes: make([]hcode, size)} } // Generates a HuffmanCode corresponding to the fixed literal table @@ -81,7 +66,7 @@ func generateFixedLiteralEncoding() *huffmanEncoder { var ch uint16 for ch = 0; ch < maxNumLit; ch++ { var bits uint16 - var size uint8 + var size uint16 switch { case ch < 144: // size 8, 000110000 .. 10111111 @@ -103,7 +88,7 @@ func generateFixedLiteralEncoding() *huffmanEncoder { bits = ch + 192 - 280 size = 8 } - codes[ch] = toCode(reverseBits(bits, size), size) + codes[ch] = hcode{code: reverseBits(bits, byte(size)), len: size} } return h } @@ -111,8 +96,8 @@ func generateFixedLiteralEncoding() *huffmanEncoder { func generateFixedOffsetEncoding() *huffmanEncoder { h := newHuffmanEncoder(30) codes := h.codes - for ch := uint16(0); ch < 30; ch++ { - codes[ch] = toCode(reverseBits(ch, 5), 5) + for ch := range codes { + codes[ch] = hcode{code: reverseBits(uint16(ch), 5), len: 5} } return h } @@ -120,11 +105,11 @@ func generateFixedOffsetEncoding() *huffmanEncoder { var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding() var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding() -func (h *huffmanEncoder) bitLength(freq []int32) int64 { - var total int64 +func (h *huffmanEncoder) bitLength(freq []int32) int { + var total int for i, f := range freq { if f != 0 { - total += int64(f) * int64(h.codes[i].bits()) + total += int(f) * int(h.codes[i].len) } } return total @@ -138,7 +123,7 @@ const maxBitsLimit = 16 // The cases of 0, 1, and 2 literals are handled by special case code. // // list An array of the literals with non-zero frequencies -// and their associated frequencies. The array is in order of increasing +// and their associated frequencies. The array is in order of increasing // frequency, and has as its last element a special element with frequency // MaxInt32 // maxBits The maximum number of bits that should be used to encode any literal. @@ -153,7 +138,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 { list = list[0 : n+1] list[n] = maxNode() - // The tree can't have greater depth than n - 1, no matter what. This + // The tree can't have greater depth than n - 1, no matter what. This // saves a little bit of work in some small cases if maxBits > n-1 { maxBits = n - 1 @@ -222,7 +207,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 { if l.needed--; l.needed == 0 { // We've done everything we need to do for this level. - // Continue calculating one level up. Fill in nextPairFreq + // Continue calculating one level up. Fill in nextPairFreq // of that level with the sum of the two nodes we've just calculated on // this level. if l.level == maxBits { @@ -246,7 +231,6 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 { } bitCount := h.bitCount[:maxBits+1] - //make([]int32, maxBits+1) bits := 1 counts := &leafCounts[maxBits] for level := maxBits; level > 0; level-- { @@ -273,9 +257,9 @@ func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalN // assigned in literal order (not frequency order). chunk := list[len(list)-int(bits):] - h.lns.Sort(chunk) + h.lns.sort(chunk) for _, node := range chunk { - h.codes[node.literal] = toCode(reverseBits(code, uint8(n)), uint8(n)) + h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(n)} code++ } list = list[0 : len(list)-int(bits)] @@ -288,7 +272,10 @@ func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalN // maxBits The maximum number of bits to use for any literal. func (h *huffmanEncoder) generate(freq []int32, maxBits int32) { if h.freqcache == nil { - h.freqcache = make([]literalNode, 300) + // Allocate a reusable buffer with the longest possible frequency table. + // Possible lengths are codegenCodeCount, offsetCodeCount and maxNumLit. + // The largest of these is maxNumLit, so we allocate for that case. + h.freqcache = make([]literalNode, maxNumLit+1) } list := h.freqcache[:len(freq)+1] // Number of non-zero literals @@ -300,28 +287,22 @@ func (h *huffmanEncoder) generate(freq []int32, maxBits int32) { count++ } else { list[count] = literalNode{} - //h.codeBits[i] = 0 - h.codes[i].setBits(0) + h.codes[i].len = 0 } } list[len(freq)] = literalNode{} - // If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros - // FIXME: Doesn't do what it says on the tin (klauspost) - //h.codeBits = h.codeBits[0:len(freq)] - list = list[0:count] + list = list[:count] if count <= 2 { - // Handle the small cases here, because they are awkward for the general case code. With + // Handle the small cases here, because they are awkward for the general case code. With // two or fewer literals, everything has bit length 1. for i, node := range list { // "list" is in order of increasing literal value. h.codes[node.literal].set(uint16(i), 1) - //h.codeBits[node.literal] = 1 - //h.code[node.literal] = uint16(i) } return } - h.lfs.Sort(list) + h.lfs.sort(list) // Get the number of literals for each bit count bitCount := h.bitCounts(list, maxBits) @@ -329,35 +310,35 @@ func (h *huffmanEncoder) generate(freq []int32, maxBits int32) { h.assignEncodingAndSize(bitCount, list) } -type literalNodeSorter []literalNode +type byLiteral []literalNode -func (s *literalNodeSorter) Sort(a []literalNode) { - *s = literalNodeSorter(a) +func (s *byLiteral) sort(a []literalNode) { + *s = byLiteral(a) sort.Sort(s) } -func (s literalNodeSorter) Len() int { return len(s) } +func (s byLiteral) Len() int { return len(s) } -func (s literalNodeSorter) Less(i, j int) bool { +func (s byLiteral) Less(i, j int) bool { return s[i].literal < s[j].literal } -func (s literalNodeSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byLiteral) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -type literalFreqSorter []literalNode +type byFreq []literalNode -func (s *literalFreqSorter) Sort(a []literalNode) { - *s = literalFreqSorter(a) +func (s *byFreq) sort(a []literalNode) { + *s = byFreq(a) sort.Sort(s) } -func (s literalFreqSorter) Len() int { return len(s) } +func (s byFreq) Len() int { return len(s) } -func (s literalFreqSorter) Less(i, j int) bool { +func (s byFreq) Less(i, j int) bool { if s[i].freq == s[j].freq { return s[i].literal < s[j].literal } return s[i].freq < s[j].freq } -func (s literalFreqSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] } diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go index 91e27e7e280..53b63d9a0b3 100644 --- a/vendor/github.com/klauspost/compress/flate/inflate.go +++ b/vendor/github.com/klauspost/compress/flate/inflate.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate go run gen.go -output fixedhuff.go - // Package flate implements the DEFLATE compressed data format, described in // RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file // formats. @@ -13,11 +11,11 @@ import ( "bufio" "io" "strconv" + "sync" ) const ( - maxCodeLen = 16 // max length of Huffman code - maxHist = 32768 // max history required + maxCodeLen = 16 // max length of Huffman code // The next three numbers come from the RFC section 3.2.7, with the // additional proviso in section 3.2.5 which implies that distance codes // 30 and 31 should never occur in compressed data. @@ -26,6 +24,10 @@ const ( numCodes = 19 // number of codes in Huffman meta-code ) +// Initialize the fixedHuffmanDecoder only once upon first use. +var fixedOnce sync.Once +var fixedHuffmanDecoder huffmanDecoder + // A CorruptInputError reports the presence of corrupt input at a given offset. type CorruptInputError int64 @@ -39,6 +41,8 @@ type InternalError string func (e InternalError) Error() string { return "flate: internal error: " + string(e) } // A ReadError reports an error encountered while reading input. +// +// Deprecated: No longer returned. type ReadError struct { Offset int64 // byte offset where error occurred Err error // error returned by underlying Read @@ -49,6 +53,8 @@ func (e *ReadError) Error() string { } // A WriteError reports an error encountered while writing output. +// +// Deprecated: No longer returned. type WriteError struct { Offset int64 // byte offset where error occurred Err error // error returned by underlying Write @@ -67,10 +73,6 @@ type Resetter interface { Reset(r io.Reader, dict []byte) error } -// Note that much of the implementation of huffmanDecoder is also copied -// into gen.go (in package main) for the purpose of precomputing the -// fixed huffman tables so they can be included statically. - // The data structure for decoding Huffman tables is based on that of // zlib. There is a lookup table of a fixed bit width (huffmanChunkBits), // For codes smaller than the table width, there are multiple entries @@ -78,12 +80,15 @@ type Resetter interface { // larger than the table width, the table contains a link to an overflow // table. The width of each entry in the link table is the maximum code // size minus the chunk width. - +// // Note that you can do a lookup in the table even without all bits // filled. Since the extra bits are zero, and the DEFLATE Huffman codes // have the property that shorter codes come before longer ones, the // bit length estimate in the result is a lower bound on the actual // number of bits. +// +// See the following: +// http://www.gzip.org/algorithm.txt // chunk & 15 is number of bits // chunk >> 4 is value, including table link @@ -109,7 +114,7 @@ type huffmanDecoder struct { // trees are permitted. func (h *huffmanDecoder) init(bits []int) bool { // Sanity enables additional runtime tests during Huffman - // table construction. It's intended to be used during + // table construction. It's intended to be used during // development to supplement the currently ad-hoc unit tests. const sanity = false @@ -156,7 +161,7 @@ func (h *huffmanDecoder) init(bits []int) bool { // Check that the coding is complete (i.e., that we've // assigned all 2-to-the-max possible bit sequences). // Exception: To be compatible with zlib, we also need to - // accept degenerate single-code codings. See also + // accept degenerate single-code codings. See also // TestDegenerateHuffmanCoding. if code != 1< 0 { n := copy(b, f.toRead) f.toRead = f.toRead[n:] + if len(f.toRead) == 0 { + return n, f.err + } return n, nil } if f.err != nil { return 0, f.err } f.step(f) + if f.err != nil && len(f.toRead) == 0 { + f.toRead = f.dict.readFlush() // Flush what's left in case of error + } } } // Support the io.WriteTo interface for io.Copy and friends. func (f *decompressor) WriteTo(w io.Writer) (int64, error) { total := int64(0) + flushed := false for { - if f.err != nil { - if f.err == io.EOF { - return total, nil - } - return total, f.err - } if len(f.toRead) > 0 { - var n int - n, f.err = w.Write(f.toRead) - if f.err != nil { - return total, f.err + n, err := w.Write(f.toRead) + total += int64(n) + if err != nil { + f.err = err + return total, err } if n != len(f.toRead) { return total, io.ErrShortWrite } f.toRead = f.toRead[:0] - total += int64(n) } - f.step(f) + if f.err != nil && flushed { + if f.err == io.EOF { + return total, nil + } + return total, f.err + } + if f.err == nil { + f.step(f) + } + if len(f.toRead) == 0 && f.err != nil && !flushed { + f.toRead = f.dict.readFlush() // Flush what's left in case of error + flushed = true + } } } @@ -485,13 +492,12 @@ func (f *decompressor) readHuffman() error { return CorruptInputError(f.roffset) } - // In order to preserve the property that we never read any extra bytes - // after the end of the DEFLATE stream, huffSym conservatively reads min - // bits at a time until it decodes the symbol. However, since every block - // must end with an EOB marker, we can use that as the minimum number of - // bits to read and guarantee we never read past the end of the stream. - if f.bits[endBlockMarker] > 0 { - f.h1.min = f.bits[endBlockMarker] // Length of EOB marker + // As an optimization, we can initialize the min bits to read at a time + // for the HLIT tree to the length of the EOB marker since we know that + // every block must terminate with one. This preserves the property that + // we never read any extra bytes after the end of the DEFLATE stream. + if f.h1.min < f.bits[endBlockMarker] { + f.h1.min = f.bits[endBlockMarker] } return nil @@ -499,10 +505,24 @@ func (f *decompressor) readHuffman() error { // Decode a single Huffman block from f. // hl and hd are the Huffman states for the lit/length values -// and the distance values, respectively. If hd == nil, using the +// and the distance values, respectively. If hd == nil, using the // fixed distance encoding associated with fixed Huffman blocks. func (f *decompressor) huffmanBlock() { - for { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { v, err := f.huffSym(f.hl) if err != nil { f.err = err @@ -512,17 +532,16 @@ func (f *decompressor) huffmanBlock() { var length int switch { case v < 256: - f.hist[f.hp] = byte(v) - f.hp++ - if f.hp == len(f.hist) { - // After the flush, continue this loop. - f.flush((*decompressor).huffmanBlock) + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBlock + f.stepState = stateInit return } - continue + goto readLiteral case v == 256: - // Done with huffman block; read next block. - f.step = (*decompressor).nextBlock + f.finishBlock() return // otherwise, reference to older data case v < 265: @@ -602,63 +621,35 @@ func (f *decompressor) huffmanBlock() { return } - // Copy history[-dist:-dist+length] into output. - if dist > len(f.hist) { - f.err = InternalError("bad history distance") - return - } - // No check on length; encoding can be prescient. - if !f.hfull && dist > f.hp { + if dist > f.dict.histSize() { f.err = CorruptInputError(f.roffset) return } f.copyLen, f.copyDist = length, dist - if f.copyHist() { + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBlock // We need to continue this work + f.stepState = stateDict return } + goto readLiteral } } -// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself. -// It reports whether the f.hist buffer is full. -func (f *decompressor) copyHist() bool { - p := f.hp - f.copyDist - if p < 0 { - p += len(f.hist) - } - for f.copyLen > 0 { - n := f.copyLen - if x := len(f.hist) - f.hp; n > x { - n = x - } - if x := len(f.hist) - p; n > x { - n = x - } - forwardCopy(f.hist[:], f.hp, p, n) - p += n - f.hp += n - f.copyLen -= n - if f.hp == len(f.hist) { - // After flush continue copying out of history. - f.flush((*decompressor).copyHuff) - return true - } - if p == len(f.hist) { - p = 0 - } - } - return false -} - -func (f *decompressor) copyHuff() { - if f.copyHist() { - return - } - f.huffmanBlock() -} - // Copy a single uncompressed data block from input to output. func (f *decompressor) dataBlock() { // Uncompressed. @@ -670,7 +661,10 @@ func (f *decompressor) dataBlock() { nr, err := io.ReadFull(f.r, f.buf[0:4]) f.roffset += int64(nr) if err != nil { - f.err = &ReadError{f.roffset, err} + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + f.err = err return } n := int(f.buf[0]) | int(f.buf[1])<<8 @@ -681,8 +675,8 @@ func (f *decompressor) dataBlock() { } if n == 0 { - // 0-length block means sync - f.flush((*decompressor).nextBlock) + f.toRead = f.dict.readFlush() + f.finishBlock() return } @@ -693,41 +687,39 @@ func (f *decompressor) dataBlock() { // copyData copies f.copyLen bytes from the underlying reader into f.hist. // It pauses for reads when f.hist is full. func (f *decompressor) copyData() { - n := f.copyLen - for n > 0 { - m := len(f.hist) - f.hp - if m > n { - m = n - } - m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m]) - f.roffset += int64(m) - if err != nil { - f.err = &ReadError{f.roffset, err} - return - } - n -= m - f.hp += m - if f.hp == len(f.hist) { - f.copyLen = n - f.flush((*decompressor).copyData) - return - } + buf := f.dict.writeSlice() + if len(buf) > f.copyLen { + buf = buf[:f.copyLen] } - f.step = (*decompressor).nextBlock + + cnt, err := io.ReadFull(f.r, buf) + f.roffset += int64(cnt) + f.copyLen -= cnt + f.dict.writeMark(cnt) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + f.err = err + return + } + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).copyData + return + } + f.finishBlock() } -func (f *decompressor) setDict(dict []byte) { - if len(dict) > len(f.hist) { - // Will only remember the tail. - dict = dict[len(dict)-len(f.hist):] +func (f *decompressor) finishBlock() { + if f.final { + if f.dict.availRead() > 0 { + f.toRead = f.dict.readFlush() + } + f.err = io.EOF } - - f.hp = copy(f.hist[:], dict) - if f.hp == len(f.hist) { - f.hp = 0 - f.hfull = true - } - f.hw = f.hp + f.step = (*decompressor).nextBlock } func (f *decompressor) moreBits() error { @@ -775,19 +767,6 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) { } } -// Flush any buffered output to the underlying writer. -func (f *decompressor) flush(step func(*decompressor)) { - f.toRead = f.hist[f.hw:f.hp] - f.woffset += int64(f.hp - f.hw) - f.hw = f.hp - if f.hp == len(f.hist) { - f.hp = 0 - f.hw = 0 - f.hfull = true - } - f.step = step -} - func makeReader(r io.Reader) Reader { if rr, ok := r.(Reader); ok { return rr @@ -795,17 +774,35 @@ func makeReader(r io.Reader) Reader { return bufio.NewReader(r) } +func fixedHuffmanDecoderInit() { + fixedOnce.Do(func() { + // These come from the RFC section 3.2.6. + var bits [288]int + for i := 0; i < 144; i++ { + bits[i] = 8 + } + for i := 144; i < 256; i++ { + bits[i] = 9 + } + for i := 256; i < 280; i++ { + bits[i] = 7 + } + for i := 280; i < 288; i++ { + bits[i] = 8 + } + fixedHuffmanDecoder.init(bits[:]) + }) +} + func (f *decompressor) Reset(r io.Reader, dict []byte) error { *f = decompressor{ r: makeReader(r), bits: f.bits, codebits: f.codebits, - hist: f.hist, + dict: f.dict, step: (*decompressor).nextBlock, } - if dict != nil { - f.setDict(dict) - } + f.dict.init(maxMatchOffset, dict) return nil } @@ -818,29 +815,32 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error { // // The ReadCloser returned by NewReader also implements Resetter. func NewReader(r io.Reader) io.ReadCloser { + fixedHuffmanDecoderInit() + var f decompressor + f.r = makeReader(r) f.bits = new([maxNumLit + maxNumDist]int) f.codebits = new([numCodes]int) - f.r = makeReader(r) - f.hist = new([maxHist]byte) f.step = (*decompressor).nextBlock + f.dict.init(maxMatchOffset, nil) return &f } // NewReaderDict is like NewReader but initializes the reader -// with a preset dictionary. The returned Reader behaves as if +// with a preset dictionary. The returned Reader behaves as if // the uncompressed data stream started with the given dictionary, -// which has already been read. NewReaderDict is typically used +// which has already been read. NewReaderDict is typically used // to read data compressed by NewWriterDict. // // The ReadCloser returned by NewReader also implements Resetter. func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { + fixedHuffmanDecoderInit() + var f decompressor f.r = makeReader(r) - f.hist = new([maxHist]byte) f.bits = new([maxNumLit + maxNumDist]int) f.codebits = new([numCodes]int) f.step = (*decompressor).nextBlock - f.setDict(dict) + f.dict.init(maxMatchOffset, dict) return &f } diff --git a/vendor/github.com/klauspost/compress/flate/snappy.go b/vendor/github.com/klauspost/compress/flate/snappy.go index 78199380d18..d853320a758 100644 --- a/vendor/github.com/klauspost/compress/flate/snappy.go +++ b/vendor/github.com/klauspost/compress/flate/snappy.go @@ -5,16 +5,13 @@ package flate -// We limit how far copy back-references can go, the same as the C++ code. -const maxOffset = 1 << 15 - // emitLiteral writes a literal chunk and returns the number of bytes written. func emitLiteral(dst *tokens, lit []byte) { - ol := dst.n + ol := int(dst.n) for i, v := range lit { - dst.tokens[i+ol] = token(v) + dst.tokens[(i+ol)&maxStoreBlockSize] = token(v) } - dst.n += len(lit) + dst.n += uint16(len(lit)) } // emitCopy writes a copy chunk and returns the number of bytes written. @@ -23,75 +20,881 @@ func emitCopy(dst *tokens, offset, length int) { dst.n++ } -// snappyEncode uses Snappy-like compression, but stores as Huffman -// blocks. -func snappyEncode(dst *tokens, src []byte) { - // Return early if src is short. - if len(src) <= 4 { - if len(src) != 0 { - emitLiteral(dst, src) - } +type snappyEnc interface { + Encode(dst *tokens, src []byte) + Reset() +} + +func newSnappy(level int) snappyEnc { + switch level { + case 1: + return &snappyL1{} + case 2: + return &snappyL2{snappyGen: snappyGen{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)}} + case 3: + return &snappyL3{snappyGen: snappyGen{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)}} + case 4: + return &snappyL4{snappyL3{snappyGen: snappyGen{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)}}} + default: + panic("invalid level specified") + } +} + +const ( + tableBits = 14 // Bits used in the table + tableSize = 1 << tableBits // Size of the table + tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks. + tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32. + baseMatchOffset = 1 // The smallest match offset + baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5 + maxMatchOffset = 1 << 15 // The largest match offset +) + +func load32(b []byte, i int) uint32 { + b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load64(b []byte, i int) uint64 { + b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func hash(u uint32) uint32 { + return (u * 0x1e35a7bd) >> tableShift +} + +// snappyL1 encapsulates level 1 compression +type snappyL1 struct{} + +func (e *snappyL1) Reset() {} + +func (e *snappyL1) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 16 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) return } - // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. - const maxTableSize = 1 << 14 - shift, tableSize := uint(32-8), 1<<8 - for tableSize < maxTableSize && tableSize < len(src) { - shift-- - tableSize *= 2 - } - var table [maxTableSize]int - var misses int - // Iterate over the source bytes. - var ( - s int // The iterator position. - t int // The last position with the same hash as s. - lit int // The start position of any pending literal bytes. - ) - for s+3 < len(src) { - // Update the hash table. - b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3] - h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24 - p := &table[(h*0x1e35a7bd)>>shift] - // We need to to store values in [-1, inf) in table. To save - // some initialization time, (re)use the table's zero value - // and shift the values against this zero: add 1 on writes, - // subtract 1 on reads. - t, *p = *p-1, s+1 - // If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte. - if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] { - misses++ - // Skip 1 byte for 16 consecutive missed. - s += 1 + (misses >> 4) - continue - } - // Otherwise, we have a match. First, emit any pending literal bytes. - if lit != s { - emitLiteral(dst, src[lit:s]) - } - // Extend the match to be as long as possible. - s0 := s - s1 := s + maxMatchLength - if s1 > len(src) { - s1 = len(src) - } - s, t = s+4, t+4 - for s < s1 && src[s] == src[t] { - s++ - t++ - } - misses = 0 - // Emit the copied bytes. - // inlined: emitCopy(dst, s-t, s-s0) + // Initialize the hash table. + // + // The table element type is uint16, as s < sLimit and sLimit < len(src) + // and len(src) <= maxStoreBlockSize and maxStoreBlockSize == 65535. + var table [tableSize]uint16 - dst.tokens[dst.n] = matchToken(uint32(s-s0-3), uint32(s-t-minOffsetSize)) - dst.n++ - lit = s + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := len(src) - inputMargin + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := 0 + + // The encoded form must start with a literal, as there are no previous + // bytes to copy, so we start looking for hash matches at s == 1. + s := 1 + nextHash := hash(load32(src, s)) + + for { + // Copied from the C++ snappy implementation: + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned (or skipped), look at every third byte, etc.. When a match + // is found, immediately go back to looking at every byte. This is a + // small loss (~5% performance, ~0.1% density) for compressible data + // due to more bookkeeping, but for non-compressible data (such as + // JPEG) it's a huge win since the compressor quickly "realizes" the + // data is incompressible and doesn't bother looking for matches + // everywhere. + // + // The "skip" variable keeps track of how many bytes there are since + // the last match; dividing it by 32 (ie. right-shifting by five) gives + // the number of bytes to move ahead for each iteration. + skip := 32 + + nextS := s + candidate := 0 + for { + s = nextS + bytesBetweenHashLookups := skip >> 5 + nextS = s + bytesBetweenHashLookups + skip += bytesBetweenHashLookups + if nextS > sLimit { + goto emitRemainder + } + candidate = int(table[nextHash&tableMask]) + table[nextHash&tableMask] = uint16(s) + nextHash = hash(load32(src, nextS)) + if s-candidate <= maxMatchOffset && load32(src, s) == load32(src, candidate) { + break + } + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + emitLiteral(dst, src[nextEmit:s]) + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + base := s + + // Extend the 4-byte match as long as possible. + // + // This is an inlined version of Snappy's: + // s = extendMatch(src, candidate+4, s+4) + s += 4 + s1 := base + maxMatchLength + if s1 > len(src) { + s1 = len(src) + } + a := src[s:s1] + b := src[candidate+4:] + b = b[:len(a)] + l := len(a) + for i := range a { + if a[i] != b[i] { + l = i + break + } + } + s += l + + // matchToken is flate's equivalent of Snappy's emitCopy. + dst.tokens[dst.n] = matchToken(uint32(s-base-baseMatchLength), uint32(base-candidate-baseMatchOffset)) + dst.n++ + nextEmit = s + if s >= sLimit { + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load64(src, s-1) + prevHash := hash(uint32(x >> 0)) + table[prevHash&tableMask] = uint16(s - 1) + currHash := hash(uint32(x >> 8)) + candidate = int(table[currHash&tableMask]) + table[currHash&tableMask] = uint16(s) + if s-candidate > maxMatchOffset || uint32(x>>8) != load32(src, candidate) { + nextHash = hash(uint32(x >> 16)) + s++ + break + } + } } - // Emit any final pending literal bytes and return. - if lit != len(src) { - emitLiteral(dst, src[lit:]) +emitRemainder: + if nextEmit < len(src) { + emitLiteral(dst, src[nextEmit:]) } } + +type tableEntry struct { + val uint32 + offset int32 +} + +func load3232(b []byte, i int32) uint32 { + b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load6432(b []byte, i int32) uint64 { + b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +// snappyGen maintains the table for matches, +// and the previous byte block for level 2. +// This is the generic implementation. +type snappyGen struct { + prev []byte + cur int32 +} + +// snappyGen maintains the table for matches, +// and the previous byte block for level 2. +// This is the generic implementation. +type snappyL2 struct { + snappyGen + table [tableSize]tableEntry +} + +// EncodeL2 uses a similar algorithm to level 1, but is capable +// of matching across blocks giving better compression at a small slowdown. +func (e *snappyL2) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 8 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + // Protect against e.cur wraparound. + if e.cur > 1<<30 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + e.cur = maxStoreBlockSize + } + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + e.cur += maxStoreBlockSize + e.prev = e.prev[:0] + return + } + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := int32(0) + s := int32(0) + cv := load3232(src, s) + nextHash := hash(cv) + + for { + // Copied from the C++ snappy implementation: + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned (or skipped), look at every third byte, etc.. When a match + // is found, immediately go back to looking at every byte. This is a + // small loss (~5% performance, ~0.1% density) for compressible data + // due to more bookkeeping, but for non-compressible data (such as + // JPEG) it's a huge win since the compressor quickly "realizes" the + // data is incompressible and doesn't bother looking for matches + // everywhere. + // + // The "skip" variable keeps track of how many bytes there are since + // the last match; dividing it by 32 (ie. right-shifting by five) gives + // the number of bytes to move ahead for each iteration. + skip := int32(32) + + nextS := s + var candidate tableEntry + for { + s = nextS + bytesBetweenHashLookups := skip >> 5 + nextS = s + bytesBetweenHashLookups + skip += bytesBetweenHashLookups + if nextS > sLimit { + goto emitRemainder + } + candidate = e.table[nextHash&tableMask] + now := load3232(src, nextS) + e.table[nextHash&tableMask] = tableEntry{offset: s + e.cur, val: cv} + nextHash = hash(now) + + offset := s - (candidate.offset - e.cur) + if offset > maxMatchOffset || cv != candidate.val { + // Out of range or not matched. + cv = now + continue + } + break + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + emitLiteral(dst, src[nextEmit:s]) + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + // + s += 4 + t := candidate.offset - e.cur + 4 + l := e.matchlen(s, t, src) + + // matchToken is flate's equivalent of Snappy's emitCopy. (length,offset) + dst.tokens[dst.n] = matchToken(uint32(l+4-baseMatchLength), uint32(s-t-baseMatchOffset)) + dst.n++ + s += l + nextEmit = s + if s >= sLimit { + t += l + // Index first pair after match end. + if int(t+4) < len(src) && t > 0 { + cv := load3232(src, t) + e.table[hash(cv)&tableMask] = tableEntry{offset: t + e.cur, val: cv} + } + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load6432(src, s-1) + prevHash := hash(uint32(x)) + e.table[prevHash&tableMask] = tableEntry{offset: e.cur + s - 1, val: uint32(x)} + x >>= 8 + currHash := hash(uint32(x)) + candidate = e.table[currHash&tableMask] + e.table[currHash&tableMask] = tableEntry{offset: e.cur + s, val: uint32(x)} + + offset := s - (candidate.offset - e.cur) + if offset > maxMatchOffset || uint32(x) != candidate.val { + cv = uint32(x >> 8) + nextHash = hash(cv) + s++ + break + } + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + emitLiteral(dst, src[nextEmit:]) + } + e.cur += int32(len(src)) + e.prev = e.prev[:len(src)] + copy(e.prev, src) +} + +type tableEntryPrev struct { + Cur tableEntry + Prev tableEntry +} + +// snappyL3 +type snappyL3 struct { + snappyGen + table [tableSize]tableEntryPrev +} + +// Encode uses a similar algorithm to level 2, will check up to two candidates. +func (e *snappyL3) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 8 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + // Protect against e.cur wraparound. + if e.cur > 1<<30 { + for i := range e.table[:] { + e.table[i] = tableEntryPrev{} + } + e.snappyGen = snappyGen{cur: maxStoreBlockSize, prev: e.prev[:0]} + } + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + e.cur += maxStoreBlockSize + e.prev = e.prev[:0] + return + } + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := int32(0) + s := int32(0) + cv := load3232(src, s) + nextHash := hash(cv) + + for { + // Copied from the C++ snappy implementation: + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned (or skipped), look at every third byte, etc.. When a match + // is found, immediately go back to looking at every byte. This is a + // small loss (~5% performance, ~0.1% density) for compressible data + // due to more bookkeeping, but for non-compressible data (such as + // JPEG) it's a huge win since the compressor quickly "realizes" the + // data is incompressible and doesn't bother looking for matches + // everywhere. + // + // The "skip" variable keeps track of how many bytes there are since + // the last match; dividing it by 32 (ie. right-shifting by five) gives + // the number of bytes to move ahead for each iteration. + skip := int32(32) + + nextS := s + var candidate tableEntry + for { + s = nextS + bytesBetweenHashLookups := skip >> 5 + nextS = s + bytesBetweenHashLookups + skip += bytesBetweenHashLookups + if nextS > sLimit { + goto emitRemainder + } + candidates := e.table[nextHash&tableMask] + now := load3232(src, nextS) + e.table[nextHash&tableMask] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur, val: cv}} + nextHash = hash(now) + + // Check both candidates + candidate = candidates.Cur + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + break + } + } else { + // We only check if value mismatches. + // Offset will always be invalid in other cases. + candidate = candidates.Prev + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + break + } + } + } + cv = now + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + emitLiteral(dst, src[nextEmit:s]) + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + // + s += 4 + t := candidate.offset - e.cur + 4 + l := e.matchlen(s, t, src) + + // matchToken is flate's equivalent of Snappy's emitCopy. (length,offset) + dst.tokens[dst.n] = matchToken(uint32(l+4-baseMatchLength), uint32(s-t-baseMatchOffset)) + dst.n++ + s += l + nextEmit = s + if s >= sLimit { + t += l + // Index first pair after match end. + if int(t+4) < len(src) && t > 0 { + cv := load3232(src, t) + nextHash = hash(cv) + e.table[nextHash&tableMask] = tableEntryPrev{ + Prev: e.table[nextHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + t, val: cv}, + } + } + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-3 to s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load6432(src, s-3) + prevHash := hash(uint32(x)) + e.table[prevHash&tableMask] = tableEntryPrev{ + Prev: e.table[prevHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + s - 3, val: uint32(x)}, + } + x >>= 8 + prevHash = hash(uint32(x)) + + e.table[prevHash&tableMask] = tableEntryPrev{ + Prev: e.table[prevHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + s - 2, val: uint32(x)}, + } + x >>= 8 + prevHash = hash(uint32(x)) + + e.table[prevHash&tableMask] = tableEntryPrev{ + Prev: e.table[prevHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + s - 1, val: uint32(x)}, + } + x >>= 8 + currHash := hash(uint32(x)) + candidates := e.table[currHash&tableMask] + cv = uint32(x) + e.table[currHash&tableMask] = tableEntryPrev{ + Prev: candidates.Cur, + Cur: tableEntry{offset: s + e.cur, val: cv}, + } + + // Check both candidates + candidate = candidates.Cur + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + continue + } + } else { + // We only check if value mismatches. + // Offset will always be invalid in other cases. + candidate = candidates.Prev + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + continue + } + } + } + cv = uint32(x >> 8) + nextHash = hash(cv) + s++ + break + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + emitLiteral(dst, src[nextEmit:]) + } + e.cur += int32(len(src)) + e.prev = e.prev[:len(src)] + copy(e.prev, src) +} + +// snappyL4 +type snappyL4 struct { + snappyL3 +} + +// Encode uses a similar algorithm to level 3, +// but will check up to two candidates if first isn't long enough. +func (e *snappyL4) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 8 - 3 + minNonLiteralBlockSize = 1 + 1 + inputMargin + matchLenGood = 12 + ) + + // Protect against e.cur wraparound. + if e.cur > 1<<30 { + for i := range e.table[:] { + e.table[i] = tableEntryPrev{} + } + e.snappyGen = snappyGen{cur: maxStoreBlockSize, prev: e.prev[:0]} + } + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + e.cur += maxStoreBlockSize + e.prev = e.prev[:0] + return + } + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := int32(0) + s := int32(0) + cv := load3232(src, s) + nextHash := hash(cv) + + for { + // Copied from the C++ snappy implementation: + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned (or skipped), look at every third byte, etc.. When a match + // is found, immediately go back to looking at every byte. This is a + // small loss (~5% performance, ~0.1% density) for compressible data + // due to more bookkeeping, but for non-compressible data (such as + // JPEG) it's a huge win since the compressor quickly "realizes" the + // data is incompressible and doesn't bother looking for matches + // everywhere. + // + // The "skip" variable keeps track of how many bytes there are since + // the last match; dividing it by 32 (ie. right-shifting by five) gives + // the number of bytes to move ahead for each iteration. + skip := int32(32) + + nextS := s + var candidate tableEntry + var candidateAlt tableEntry + for { + s = nextS + bytesBetweenHashLookups := skip >> 5 + nextS = s + bytesBetweenHashLookups + skip += bytesBetweenHashLookups + if nextS > sLimit { + goto emitRemainder + } + candidates := e.table[nextHash&tableMask] + now := load3232(src, nextS) + e.table[nextHash&tableMask] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur, val: cv}} + nextHash = hash(now) + + // Check both candidates + candidate = candidates.Cur + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset < maxMatchOffset { + offset = s - (candidates.Prev.offset - e.cur) + if cv == candidates.Prev.val && offset < maxMatchOffset { + candidateAlt = candidates.Prev + } + break + } + } else { + // We only check if value mismatches. + // Offset will always be invalid in other cases. + candidate = candidates.Prev + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset < maxMatchOffset { + break + } + } + } + cv = now + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + emitLiteral(dst, src[nextEmit:s]) + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + // + s += 4 + t := candidate.offset - e.cur + 4 + l := e.matchlen(s, t, src) + // Try alternative candidate if match length < matchLenGood. + if l < matchLenGood-4 && candidateAlt.offset != 0 { + t2 := candidateAlt.offset - e.cur + 4 + l2 := e.matchlen(s, t2, src) + if l2 > l { + l = l2 + t = t2 + } + } + // matchToken is flate's equivalent of Snappy's emitCopy. (length,offset) + dst.tokens[dst.n] = matchToken(uint32(l+4-baseMatchLength), uint32(s-t-baseMatchOffset)) + dst.n++ + s += l + nextEmit = s + if s >= sLimit { + t += l + // Index first pair after match end. + if int(t+4) < len(src) && t > 0 { + cv := load3232(src, t) + nextHash = hash(cv) + e.table[nextHash&tableMask] = tableEntryPrev{ + Prev: e.table[nextHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + t, val: cv}, + } + } + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-3 to s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load6432(src, s-3) + prevHash := hash(uint32(x)) + e.table[prevHash&tableMask] = tableEntryPrev{ + Prev: e.table[prevHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + s - 3, val: uint32(x)}, + } + x >>= 8 + prevHash = hash(uint32(x)) + + e.table[prevHash&tableMask] = tableEntryPrev{ + Prev: e.table[prevHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + s - 2, val: uint32(x)}, + } + x >>= 8 + prevHash = hash(uint32(x)) + + e.table[prevHash&tableMask] = tableEntryPrev{ + Prev: e.table[prevHash&tableMask].Cur, + Cur: tableEntry{offset: e.cur + s - 1, val: uint32(x)}, + } + x >>= 8 + currHash := hash(uint32(x)) + candidates := e.table[currHash&tableMask] + cv = uint32(x) + e.table[currHash&tableMask] = tableEntryPrev{ + Prev: candidates.Cur, + Cur: tableEntry{offset: s + e.cur, val: cv}, + } + + // Check both candidates + candidate = candidates.Cur + candidateAlt = tableEntry{} + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + offset = s - (candidates.Prev.offset - e.cur) + if cv == candidates.Prev.val && offset <= maxMatchOffset { + candidateAlt = candidates.Prev + } + continue + } + } else { + // We only check if value mismatches. + // Offset will always be invalid in other cases. + candidate = candidates.Prev + if cv == candidate.val { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + continue + } + } + } + cv = uint32(x >> 8) + nextHash = hash(cv) + s++ + break + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + emitLiteral(dst, src[nextEmit:]) + } + e.cur += int32(len(src)) + e.prev = e.prev[:len(src)] + copy(e.prev, src) +} + +func (e *snappyGen) matchlen(s, t int32, src []byte) int32 { + s1 := int(s) + maxMatchLength - 4 + if s1 > len(src) { + s1 = len(src) + } + + // If we are inside the current block + if t >= 0 { + b := src[t:] + a := src[s:s1] + b = b[:len(a)] + // Extend the match to be as long as possible. + for i := range a { + if a[i] != b[i] { + return int32(i) + } + } + return int32(len(a)) + } + + // We found a match in the previous block. + tp := int32(len(e.prev)) + t + if tp < 0 { + return 0 + } + + // Extend the match to be as long as possible. + a := src[s:s1] + b := e.prev[tp:] + if len(b) > len(a) { + b = b[:len(a)] + } + a = a[:len(b)] + for i := range b { + if a[i] != b[i] { + return int32(i) + } + } + + // If we reached our limit, we matched everything we are + // allowed to in the previous block and we return. + n := int32(len(b)) + if int(s+n) == s1 { + return n + } + + // Continue looking for more matches in the current block. + a = src[s+n : s1] + b = src[:len(a)] + for i := range a { + if a[i] != b[i] { + return int32(i) + n + } + } + return int32(len(a)) + n +} + +// Reset the encoding table. +func (e *snappyGen) Reset() { + e.prev = e.prev[:0] + e.cur += maxMatchOffset +} diff --git a/vendor/github.com/klauspost/compress/flate/token.go b/vendor/github.com/klauspost/compress/flate/token.go index 94fa5eb93ab..4f275ea61df 100644 --- a/vendor/github.com/klauspost/compress/flate/token.go +++ b/vendor/github.com/klauspost/compress/flate/token.go @@ -4,6 +4,8 @@ package flate +import "fmt" + const ( // 2 bits: type 0 = literal 1=EOF 2=Match 3=Unused // 8 bits: xlength = length - MIN_MATCH_LENGTH @@ -68,8 +70,8 @@ var offsetCodes = [...]uint32{ type token uint32 type tokens struct { - tokens []token - n int + tokens [maxStoreBlockSize + 1]token + n uint16 // Must be able to contain maxStoreBlockSize } // Convert a literal into a literal token. @@ -80,6 +82,14 @@ func matchToken(xlength uint32, xoffset uint32) token { return token(matchType + xlength< maxMatchLength || xoffset > maxMatchOffset { + panic(fmt.Sprintf("Invalid match: len: %d, offset: %d\n", xlength, xoffset)) + return token(matchType) + } + return token(matchType + xlength<= len(z.buf) { return "", ErrHeader @@ -146,147 +151,142 @@ func (z *Reader) readString() (string, error) { return "", err } if z.buf[i] > 0x7f { - needconv = true + needConv = true } if z.buf[i] == 0 { - // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1). - if needconv { + // Digest covers the NUL terminator. + z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:i+1]) + + // Strings are ISO 8859-1, Latin-1 (RFC 1952, section 2.3.1). + if needConv { s := make([]rune, 0, i) - for _, v := range z.buf[0:i] { + for _, v := range z.buf[:i] { s = append(s, rune(v)) } return string(s), nil } - return string(z.buf[0:i]), nil + return string(z.buf[:i]), nil } } } -func (z *Reader) read2() (uint32, error) { - _, err := io.ReadFull(z.r, z.buf[0:2]) - if err != nil { - return 0, err - } - return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil -} - -func (z *Reader) readHeader(save bool) error { - _, err := io.ReadFull(z.r, z.buf[0:10]) - if err != nil { - return err +// readHeader reads the GZIP header according to section 2.3.1. +// This method does not set z.err. +func (z *Reader) readHeader() (hdr Header, err error) { + if _, err = io.ReadFull(z.r, z.buf[:10]); err != nil { + // RFC 1952, section 2.2, says the following: + // A gzip file consists of a series of "members" (compressed data sets). + // + // Other than this, the specification does not clarify whether a + // "series" is defined as "one or more" or "zero or more". To err on the + // side of caution, Go interprets this to mean "zero or more". + // Thus, it is okay to return io.EOF here. + return hdr, err } if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate { - return ErrHeader + return hdr, ErrHeader } - z.flg = z.buf[3] - if save { - z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0) - // z.buf[8] is xfl, ignored - z.OS = z.buf[9] - } - z.digest.Reset() - z.digest.Write(z.buf[0:10]) + flg := z.buf[3] + hdr.ModTime = time.Unix(int64(le.Uint32(z.buf[4:8])), 0) + // z.buf[8] is XFL and is currently ignored. + hdr.OS = z.buf[9] + z.digest = crc32.ChecksumIEEE(z.buf[:10]) - if z.flg&flagExtra != 0 { - n, err := z.read2() - if err != nil { - return err + if flg&flagExtra != 0 { + if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil { + return hdr, noEOF(err) } - data := make([]byte, n) + z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:2]) + data := make([]byte, le.Uint16(z.buf[:2])) if _, err = io.ReadFull(z.r, data); err != nil { - return err - } - if save { - z.Extra = data + return hdr, noEOF(err) } + z.digest = crc32.Update(z.digest, crc32.IEEETable, data) + hdr.Extra = data } var s string - if z.flg&flagName != 0 { + if flg&flagName != 0 { if s, err = z.readString(); err != nil { - return err - } - if save { - z.Name = s + return hdr, err } + hdr.Name = s } - if z.flg&flagComment != 0 { + if flg&flagComment != 0 { if s, err = z.readString(); err != nil { - return err + return hdr, err } - if save { - z.Comment = s + hdr.Comment = s + } + + if flg&flagHdrCrc != 0 { + if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil { + return hdr, noEOF(err) + } + digest := le.Uint16(z.buf[:2]) + if digest != uint16(z.digest) { + return hdr, ErrHeader } } - if z.flg&flagHdrCrc != 0 { - n, err := z.read2() - if err != nil { - return err - } - sum := z.digest.Sum32() & 0xFFFF - if n != sum { - return ErrHeader - } - } - - z.digest.Reset() + z.digest = 0 if z.decompressor == nil { z.decompressor = flate.NewReader(z.r) } else { z.decompressor.(flate.Resetter).Reset(z.r, nil) } - return nil + return hdr, nil } +// Read implements io.Reader, reading uncompressed bytes from its underlying Reader. func (z *Reader) Read(p []byte) (n int, err error) { if z.err != nil { return 0, z.err } - if len(p) == 0 { - return 0, nil - } - n, err = z.decompressor.Read(p) - z.digest.Write(p[0:n]) + n, z.err = z.decompressor.Read(p) + z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n]) z.size += uint32(n) - if n != 0 || err != io.EOF { - z.err = err - return + if z.err != io.EOF { + // In the normal case we return here. + return n, z.err } - // Finished file; check checksum + size. - if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil { - z.err = err - return 0, err + // Finished file; check checksum and size. + if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil { + z.err = noEOF(err) + return n, z.err } - crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8]) - sum := z.digest.Sum32() - if sum != crc32 || isize != z.size { + digest := le.Uint32(z.buf[:4]) + size := le.Uint32(z.buf[4:8]) + if digest != z.digest || size != z.size { z.err = ErrChecksum - return 0, z.err + return n, z.err } + z.digest, z.size = 0, 0 - // File is ok; is there another? + // File is ok; check if there is another. if !z.multistream { - return 0, io.EOF + return n, io.EOF + } + z.err = nil // Remove io.EOF + + if _, z.err = z.readHeader(); z.err != nil { + return n, z.err } - if err = z.readHeader(false); err != nil { - z.err = err - return + // Read from next file, if necessary. + if n > 0 { + return n, nil } - - // Yes. Reset and read from it. - z.digest.Reset() - z.size = 0 return z.Read(p) } // Support the io.WriteTo interface for io.Copy and friends. func (z *Reader) WriteTo(w io.Writer) (int64, error) { total := int64(0) + crcWriter := crc32.NewIEEE() for { if z.err != nil { if z.err == io.EOF { @@ -296,7 +296,7 @@ func (z *Reader) WriteTo(w io.Writer) (int64, error) { } // We write both to output and digest. - mw := io.MultiWriter(w, z.digest) + mw := io.MultiWriter(w, crcWriter) n, err := z.decompressor.(io.WriterTo).WriteTo(mw) total += n z.size += uint32(n) @@ -307,36 +307,38 @@ func (z *Reader) WriteTo(w io.Writer) (int64, error) { // Finished file; check checksum + size. if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil { - z.err = err - return 0, err - } - crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8]) - sum := z.digest.Sum32() - if sum != crc32 || isize != z.size { - z.err = ErrChecksum - return 0, z.err - } - - // File is ok; is there another? - if !z.multistream { - return total, nil - } - - err = z.readHeader(false) - // There was not more - if err == io.EOF { - return total, nil - } - if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } z.err = err return total, err } + z.digest = crcWriter.Sum32() + digest := le.Uint32(z.buf[:4]) + size := le.Uint32(z.buf[4:8]) + if digest != z.digest || size != z.size { + z.err = ErrChecksum + return total, z.err + } + z.digest, z.size = 0, 0 - // Yes. Reset and read from it. - z.digest.Reset() - z.size = 0 + // File is ok; check if there is another. + if !z.multistream { + return total, nil + } + crcWriter.Reset() + z.err = nil // Remove io.EOF + + if _, z.err = z.readHeader(); z.err != nil { + if z.err == io.EOF { + return total, nil + } + return total, z.err + } } } // Close closes the Reader. It does not close the underlying io.Reader. +// In order for the GZIP checksum to be verified, the reader must be +// fully consumed until the io.EOF. func (z *Reader) Close() error { return z.decompressor.Close() } diff --git a/vendor/github.com/klauspost/compress/gzip/gzip.go b/vendor/github.com/klauspost/compress/gzip/gzip.go index a590c883cd1..a0f3ed0fcf0 100644 --- a/vendor/github.com/klauspost/compress/gzip/gzip.go +++ b/vendor/github.com/klauspost/compress/gzip/gzip.go @@ -7,7 +7,6 @@ package gzip import ( "errors" "fmt" - "hash" "io" "github.com/klauspost/compress/flate" @@ -22,18 +21,19 @@ const ( BestCompression = flate.BestCompression DefaultCompression = flate.DefaultCompression ConstantCompression = flate.ConstantCompression + HuffmanOnly = flate.HuffmanOnly ) // A Writer is an io.WriteCloser. // Writes to a Writer are compressed and written to w. type Writer struct { - Header + Header // written at first call to Write, Flush, or Close w io.Writer level int wroteHeader bool compressor *flate.Writer - digest hash.Hash32 - size uint32 + digest uint32 // CRC-32, IEEE polynomial (section 8) + size uint32 // Uncompressed size (section 2.3.1) closed bool buf [10]byte err error @@ -46,10 +46,7 @@ type Writer struct { // Writes may be buffered and not flushed until Close. // // Callers that wish to set the fields in Writer.Header must do so before -// the first call to Write or Close. The Comment and Name header fields are -// UTF-8 strings in Go, but the underlying format requires NUL-terminated ISO -// 8859-1 (Latin-1). NUL or non-Latin-1 runes in those strings will lead to an -// error on Write. +// the first call to Write, Flush, or Close. func NewWriter(w io.Writer) *Writer { z, _ := NewWriterLevel(w, DefaultCompression) return z @@ -58,11 +55,11 @@ func NewWriter(w io.Writer) *Writer { // NewWriterLevel is like NewWriter but specifies the compression level instead // of assuming DefaultCompression. // -// The compression level can be ConstantCompression, DefaultCompression, -// NoCompression, or any integer value between BestSpeed and BestCompression -// inclusive. The error returned will be nil if the level is valid. +// The compression level can be DefaultCompression, NoCompression, or any +// integer value between BestSpeed and BestCompression inclusive. The error +// returned will be nil if the level is valid. func NewWriterLevel(w io.Writer, level int) (*Writer, error) { - if level < ConstantCompression || level > BestCompression { + if level < HuffmanOnly || level > BestCompression { return nil, fmt.Errorf("gzip: invalid compression level: %d", level) } z := new(Writer) @@ -71,12 +68,6 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) { } func (z *Writer) init(w io.Writer, level int) { - digest := z.digest - if digest != nil { - digest.Reset() - } else { - digest = crc32.NewIEEE() - } compressor := z.compressor if compressor != nil { compressor.Reset(w) @@ -87,7 +78,6 @@ func (z *Writer) init(w io.Writer, level int) { }, w: w, level: level, - digest: digest, compressor: compressor, } } @@ -100,26 +90,13 @@ func (z *Writer) Reset(w io.Writer) { z.init(w, z.level) } -// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). -func put2(p []byte, v uint16) { - p[0] = uint8(v >> 0) - p[1] = uint8(v >> 8) -} - -func put4(p []byte, v uint32) { - p[0] = uint8(v >> 0) - p[1] = uint8(v >> 8) - p[2] = uint8(v >> 16) - p[3] = uint8(v >> 24) -} - // writeBytes writes a length-prefixed byte slice to z.w. func (z *Writer) writeBytes(b []byte) error { if len(b) > 0xffff { return errors.New("gzip.Write: Extra data is too large") } - put2(z.buf[0:2], uint16(len(b))) - _, err := z.w.Write(z.buf[0:2]) + le.PutUint16(z.buf[:2], uint16(len(b))) + _, err := z.w.Write(z.buf[:2]) if err != nil { return err } @@ -154,7 +131,7 @@ func (z *Writer) writeString(s string) (err error) { } // GZIP strings are NUL-terminated. z.buf[0] = 0 - _, err = z.w.Write(z.buf[0:1]) + _, err = z.w.Write(z.buf[:1]) return err } @@ -181,7 +158,7 @@ func (z *Writer) Write(p []byte) (int, error) { if z.Comment != "" { z.buf[3] |= 0x10 } - put4(z.buf[4:8], uint32(z.ModTime.Unix())) + le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix())) if z.level == BestCompression { z.buf[8] = 2 } else if z.level == BestSpeed { @@ -190,7 +167,7 @@ func (z *Writer) Write(p []byte) (int, error) { z.buf[8] = 0 } z.buf[9] = z.OS - n, z.err = z.w.Write(z.buf[0:10]) + n, z.err = z.w.Write(z.buf[:10]) if z.err != nil { return n, z.err } @@ -217,7 +194,7 @@ func (z *Writer) Write(p []byte) (int, error) { } } z.size += uint32(len(p)) - z.digest.Write(p) + z.digest = crc32.Update(z.digest, crc32.IEEETable, p) n, z.err = z.compressor.Write(p) return n, z.err } @@ -267,8 +244,8 @@ func (z *Writer) Close() error { if z.err != nil { return z.err } - put4(z.buf[0:4], z.digest.Sum32()) - put4(z.buf[4:8], z.size) - _, z.err = z.w.Write(z.buf[0:8]) + le.PutUint32(z.buf[:4], z.digest) + le.PutUint32(z.buf[4:8], z.size) + _, z.err = z.w.Write(z.buf[:8]) return z.err } diff --git a/vendor/github.com/klauspost/compress/snappy/AUTHORS b/vendor/github.com/klauspost/compress/snappy/AUTHORS new file mode 100644 index 00000000000..fd1c6f67b36 --- /dev/null +++ b/vendor/github.com/klauspost/compress/snappy/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of Snappy-Go authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Damian Gryski +Google Inc. +Jan Mercl <0xjnml@gmail.com> +Rodolfo Carvalho +Sebastien Binet diff --git a/vendor/github.com/klauspost/compress/snappy/CONTRIBUTORS b/vendor/github.com/klauspost/compress/snappy/CONTRIBUTORS new file mode 100644 index 00000000000..a29b1339882 --- /dev/null +++ b/vendor/github.com/klauspost/compress/snappy/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This is the official list of people who can contribute +# (and typically have contributed) code to the Snappy-Go repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# The submission process automatically checks to make sure +# that people submitting code are listed in this file (by email address). +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# http://code.google.com/legal/individual-cla-v1.0.html +# http://code.google.com/legal/corporate-cla-v1.0.html +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. + +# Names should be added to this file like so: +# Name + +# Please keep the list sorted. + +Damian Gryski +Jan Mercl <0xjnml@gmail.com> +Kai Backman +Marc-Antoine Ruel +Nigel Tao +Rob Pike +Rodolfo Carvalho +Russ Cox +Sebastien Binet diff --git a/vendor/github.com/klauspost/compress/snappy/LICENSE b/vendor/github.com/klauspost/compress/snappy/LICENSE new file mode 100644 index 00000000000..7e69e1a2f61 --- /dev/null +++ b/vendor/github.com/klauspost/compress/snappy/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The Snappy-Go 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/github.com/klauspost/cpuid/.gitignore b/vendor/github.com/klauspost/cpuid/.gitignore deleted file mode 100644 index daf913b1b34..00000000000 --- a/vendor/github.com/klauspost/cpuid/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/klauspost/cpuid/.travis.yml b/vendor/github.com/klauspost/cpuid/.travis.yml deleted file mode 100644 index fb74de6b878..00000000000 --- a/vendor/github.com/klauspost/cpuid/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go - -go: - - 1.3 - - 1.4 - - 1.5 - - tip diff --git a/vendor/github.com/klauspost/cpuid/README.md b/vendor/github.com/klauspost/cpuid/README.md deleted file mode 100644 index b2b6bee879a..00000000000 --- a/vendor/github.com/klauspost/cpuid/README.md +++ /dev/null @@ -1,145 +0,0 @@ -# cpuid -Package cpuid provides information about the CPU running the current program. - -CPU features are detected on startup, and kept for fast access through the life of the application. -Currently x86 / x64 (AMD64) is supported, and no external C (cgo) code is used, which should make the library very easy to use. - -You can access the CPU information by accessing the shared CPU variable of the cpuid library. - -Package home: https://github.com/klauspost/cpuid - -[![GoDoc][1]][2] [![Build Status][3]][4] - -[1]: https://godoc.org/github.com/klauspost/cpuid?status.svg -[2]: https://godoc.org/github.com/klauspost/cpuid -[3]: https://travis-ci.org/klauspost/cpuid.svg -[4]: https://travis-ci.org/klauspost/cpuid - -# features -## CPU Instructions -* **CMOV** (i686 CMOV) -* **NX** (NX (No-Execute) bit) -* **AMD3DNOW** (AMD 3DNOW) -* **AMD3DNOWEXT** (AMD 3DNowExt) -* **MMX** (standard MMX) -* **MMXEXT** (SSE integer functions or AMD MMX ext) -* **SSE** (SSE functions) -* **SSE2** (P4 SSE functions) -* **SSE3** (Prescott SSE3 functions) -* **SSSE3** (Conroe SSSE3 functions) -* **SSE4** (Penryn SSE4.1 functions) -* **SSE4A** (AMD Barcelona microarchitecture SSE4a instructions) -* **SSE42** (Nehalem SSE4.2 functions) -* **AVX** (AVX functions) -* **AVX2** (AVX2 functions) -* **FMA3** (Intel FMA 3) -* **FMA4** (Bulldozer FMA4 functions) -* **XOP** (Bulldozer XOP functions) -* **F16C** (Half-precision floating-point conversion) -* **BMI1** (Bit Manipulation Instruction Set 1) -* **BMI2** (Bit Manipulation Instruction Set 2) -* **TBM** (AMD Trailing Bit Manipulation) -* **LZCNT** (LZCNT instruction) -* **POPCNT** (POPCNT instruction) -* **AESNI** (Advanced Encryption Standard New Instructions) -* **CLMUL** (Carry-less Multiplication) -* **HTT** (Hyperthreading (enabled)) -* **HLE** (Hardware Lock Elision) -* **RTM** (Restricted Transactional Memory) -* **RDRAND** (RDRAND instruction is available) -* **RDSEED** (RDSEED instruction is available) -* **ADX** (Intel ADX (Multi-Precision Add-Carry Instruction Extensions)) -* **SHA** (Intel SHA Extensions) -* **AVX512F** (AVX-512 Foundation) -* **AVX512DQ** (AVX-512 Doubleword and Quadword Instructions) -* **AVX512IFMA** (AVX-512 Integer Fused Multiply-Add Instructions) -* **AVX512PF** (AVX-512 Prefetch Instructions) -* **AVX512ER** (AVX-512 Exponential and Reciprocal Instructions) -* **AVX512CD** (AVX-512 Conflict Detection Instructions) -* **AVX512BW** (AVX-512 Byte and Word Instructions) -* **AVX512VL** (AVX-512 Vector Length Extensions) -* **AVX512VBMI** (AVX-512 Vector Bit Manipulation Instructions) -* **MPX** (Intel MPX (Memory Protection Extensions)) -* **ERMS** (Enhanced REP MOVSB/STOSB) -* **RDTSCP** (RDTSCP Instruction) -* **CX16** (CMPXCHG16B Instruction) -* **SGX** (Software Guard Extensions, with activation details) - -## Performance -* **RDTSCP()** Returns current cycle count. Can be used for benchmarking. -* **SSE2SLOW** (SSE2 is supported, but usually not faster) -* **SSE3SLOW** (SSE3 is supported, but usually not faster) -* **ATOM** (Atom processor, some SSSE3 instructions are slower) -* **Cache line** (Probable size of a cache line). -* **L1, L2, L3 Cache size** on newer Intel/AMD CPUs. - -## Cpu Vendor/VM -* **Intel** -* **AMD** -* **VIA** -* **Transmeta** -* **NSC** -* **KVM** (Kernel-based Virtual Machine) -* **MSVM** (Microsoft Hyper-V or Windows Virtual PC) -* **VMware** -* **XenHVM** - -# installing - -```go get github.com/klauspost/cpuid``` - -# example - -```Go -package main - -import ( - "fmt" - "github.com/klauspost/cpuid" -) - -func main() { - // Print basic CPU information: - fmt.Println("Name:", cpuid.CPU.BrandName) - fmt.Println("PhysicalCores:", cpuid.CPU.PhysicalCores) - fmt.Println("ThreadsPerCore:", cpuid.CPU.ThreadsPerCore) - fmt.Println("LogicalCores:", cpuid.CPU.LogicalCores) - fmt.Println("Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model) - fmt.Println("Features:", cpuid.CPU.Features) - fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine) - fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes") - fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1D, "bytes") - fmt.Println("L2 Cache:", cpuid.CPU.Cache.L2, "bytes") - fmt.Println("L3 Cache:", cpuid.CPU.Cache.L3, "bytes") - - // Test if we have a specific feature: - if cpuid.CPU.SSE() { - fmt.Println("We have Streaming SIMD Extensions") - } -} -``` - -Sample output: -``` ->go run main.go -Name: Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz -PhysicalCores: 2 -ThreadsPerCore: 2 -LogicalCores: 4 -Family 6 Model: 42 -Features: CMOV,MMX,MMXEXT,SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2,AVX,AESNI,CLMUL -Cacheline bytes: 64 -We have Streaming SIMD Extensions -``` - -# private package - -In the "private" folder you can find an autogenerated version of the library you can include in your own packages. - -For this purpose all exports are removed, and functions and constants are lowercased. - -This is not a recommended way of using the library, but provided for convenience, if it is difficult for you to use external packages. - -# license - -This code is published under an MIT license. See LICENSE file for more information. diff --git a/vendor/github.com/klauspost/cpuid/cpuid.go b/vendor/github.com/klauspost/cpuid/cpuid.go index 9230ca56282..44e50946f31 100644 --- a/vendor/github.com/klauspost/cpuid/cpuid.go +++ b/vendor/github.com/klauspost/cpuid/cpuid.go @@ -192,7 +192,7 @@ func Detect() { CPU.CacheLine = cacheLine() CPU.Family, CPU.Model = familyModel() CPU.Features = support() - CPU.SGX = sgx(CPU.Features&SGX != 0) + CPU.SGX = hasSGX(CPU.Features&SGX != 0) CPU.ThreadsPerCore = threadsPerCore() CPU.LogicalCores = logicalCores() CPU.PhysicalCores = physicalCores() @@ -437,14 +437,22 @@ func (c CPUInfo) ERMS() bool { return c.Features&ERMS != 0 } +// RDTSCP Instruction is available. func (c CPUInfo) RDTSCP() bool { return c.Features&RDTSCP != 0 } +// CX16 indicates if CMPXCHG16B instruction is available. func (c CPUInfo) CX16() bool { return c.Features&CX16 != 0 } +// TSX is split into HLE (Hardware Lock Elision) and RTM (Restricted Transactional Memory) detection. +// So TSX simply checks that. +func (c CPUInfo) TSX() bool { + return c.Features&(MPX|RTM) == MPX|RTM +} + // Atom indicates an Atom processor func (c CPUInfo) Atom() bool { return c.Features&ATOM != 0 @@ -757,7 +765,7 @@ type SGXSupport struct { MaxEnclaveSize64 int64 } -func sgx(available bool) (rval SGXSupport) { +func hasSGX(available bool) (rval SGXSupport) { rval.Available = available if !available { diff --git a/vendor/github.com/klauspost/cpuid/cpuid_386.s b/vendor/github.com/klauspost/cpuid/cpuid_386.s index 9947f7b6f6a..4d731711e48 100644 --- a/vendor/github.com/klauspost/cpuid/cpuid_386.s +++ b/vendor/github.com/klauspost/cpuid/cpuid_386.s @@ -1,5 +1,7 @@ // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. +// +build 386,!gccgo + // func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) TEXT ·asmCpuid(SB), 7, $0 XORL CX, CX diff --git a/vendor/github.com/klauspost/cpuid/cpuid_amd64.s b/vendor/github.com/klauspost/cpuid/cpuid_amd64.s index 68a7c9d8808..3c1d60e4221 100644 --- a/vendor/github.com/klauspost/cpuid/cpuid_amd64.s +++ b/vendor/github.com/klauspost/cpuid/cpuid_amd64.s @@ -1,5 +1,7 @@ // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. +//+build amd64,!gccgo + // func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) TEXT ·asmCpuid(SB), 7, $0 XORQ CX, CX diff --git a/vendor/github.com/klauspost/cpuid/detect_intel.go b/vendor/github.com/klauspost/cpuid/detect_intel.go index d5475ebfaa8..a5f04dd6d0a 100644 --- a/vendor/github.com/klauspost/cpuid/detect_intel.go +++ b/vendor/github.com/klauspost/cpuid/detect_intel.go @@ -1,6 +1,6 @@ // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. -// +build 386 amd64 +// +build 386,!gccgo amd64,!gccgo package cpuid diff --git a/vendor/github.com/klauspost/cpuid/detect_ref.go b/vendor/github.com/klauspost/cpuid/detect_ref.go index 6f9231b13bf..909c5d9a7ae 100644 --- a/vendor/github.com/klauspost/cpuid/detect_ref.go +++ b/vendor/github.com/klauspost/cpuid/detect_ref.go @@ -1,6 +1,6 @@ // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. -// +build !amd64,!386 +// +build !amd64,!386 gccgo package cpuid diff --git a/vendor/github.com/klauspost/cpuid/generate.go b/vendor/github.com/klauspost/cpuid/generate.go index c060b8165e8..90e7a98d278 100644 --- a/vendor/github.com/klauspost/cpuid/generate.go +++ b/vendor/github.com/klauspost/cpuid/generate.go @@ -1,3 +1,4 @@ package cpuid //go:generate go run private-gen.go +//go:generate gofmt -w ./private diff --git a/vendor/github.com/klauspost/cpuid/private/README.md b/vendor/github.com/klauspost/cpuid/private/README.md deleted file mode 100644 index 57a68f88274..00000000000 --- a/vendor/github.com/klauspost/cpuid/private/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# cpuid private - -This is a specially converted of the cpuid package, so it can be included in -a package without exporting anything. - -Package home: https://github.com/klauspost/cpuid diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid.go b/vendor/github.com/klauspost/cpuid/private/cpuid.go deleted file mode 100644 index be99cb0b70d..00000000000 --- a/vendor/github.com/klauspost/cpuid/private/cpuid.go +++ /dev/null @@ -1,987 +0,0 @@ -// Generated, DO NOT EDIT, -// but copy it to your own project and rename the package. -// See more at http://github.com/klauspost/cpuid - -package cpuid - -import ( - "strings" -) - -// Vendor is a representation of a CPU vendor. -type vendor int - -const ( - other vendor = iota - intel - amd - via - transmeta - nsc - kvm // Kernel-based Virtual Machine - msvm // Microsoft Hyper-V or Windows Virtual PC - vmware - xenhvm -) - -const ( - cmov = 1 << iota // i686 CMOV - nx // NX (No-Execute) bit - amd3dnow // AMD 3DNOW - amd3dnowext // AMD 3DNowExt - mmx // standard MMX - mmxext // SSE integer functions or AMD MMX ext - sse // SSE functions - sse2 // P4 SSE functions - sse3 // Prescott SSE3 functions - ssse3 // Conroe SSSE3 functions - sse4 // Penryn SSE4.1 functions - sse4a // AMD Barcelona microarchitecture SSE4a instructions - sse42 // Nehalem SSE4.2 functions - avx // AVX functions - avx2 // AVX2 functions - fma3 // Intel FMA 3 - fma4 // Bulldozer FMA4 functions - xop // Bulldozer XOP functions - f16c // Half-precision floating-point conversion - bmi1 // Bit Manipulation Instruction Set 1 - bmi2 // Bit Manipulation Instruction Set 2 - tbm // AMD Trailing Bit Manipulation - lzcnt // LZCNT instruction - popcnt // POPCNT instruction - aesni // Advanced Encryption Standard New Instructions - clmul // Carry-less Multiplication - htt // Hyperthreading (enabled) - hle // Hardware Lock Elision - rtm // Restricted Transactional Memory - rdrand // RDRAND instruction is available - rdseed // RDSEED instruction is available - adx // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) - sha // Intel SHA Extensions - avx512f // AVX-512 Foundation - avx512dq // AVX-512 Doubleword and Quadword Instructions - avx512ifma // AVX-512 Integer Fused Multiply-Add Instructions - avx512pf // AVX-512 Prefetch Instructions - avx512er // AVX-512 Exponential and Reciprocal Instructions - avx512cd // AVX-512 Conflict Detection Instructions - avx512bw // AVX-512 Byte and Word Instructions - avx512vl // AVX-512 Vector Length Extensions - avx512vbmi // AVX-512 Vector Bit Manipulation Instructions - mpx // Intel MPX (Memory Protection Extensions) - erms // Enhanced REP MOVSB/STOSB - rdtscp // RDTSCP Instruction - cx16 // CMPXCHG16B Instruction - - // Performance indicators - sse2slow // SSE2 is supported, but usually not faster - sse3slow // SSE3 is supported, but usually not faster - atom // Atom processor, some SSSE3 instructions are slower -) - -var flagNames = map[flags]string{ - cmov: "CMOV", // i686 CMOV - nx: "NX", // NX (No-Execute) bit - amd3dnow: "AMD3DNOW", // AMD 3DNOW - amd3dnowext: "AMD3DNOWEXT", // AMD 3DNowExt - mmx: "MMX", // Standard MMX - mmxext: "MMXEXT", // SSE integer functions or AMD MMX ext - sse: "SSE", // SSE functions - sse2: "SSE2", // P4 SSE2 functions - sse3: "SSE3", // Prescott SSE3 functions - ssse3: "SSSE3", // Conroe SSSE3 functions - sse4: "SSE4.1", // Penryn SSE4.1 functions - sse4a: "SSE4A", // AMD Barcelona microarchitecture SSE4a instructions - sse42: "SSE4.2", // Nehalem SSE4.2 functions - avx: "AVX", // AVX functions - avx2: "AVX2", // AVX functions - fma3: "FMA3", // Intel FMA 3 - fma4: "FMA4", // Bulldozer FMA4 functions - xop: "XOP", // Bulldozer XOP functions - f16c: "F16C", // Half-precision floating-point conversion - bmi1: "BMI1", // Bit Manipulation Instruction Set 1 - bmi2: "BMI2", // Bit Manipulation Instruction Set 2 - tbm: "TBM", // AMD Trailing Bit Manipulation - lzcnt: "LZCNT", // LZCNT instruction - popcnt: "POPCNT", // POPCNT instruction - aesni: "AESNI", // Advanced Encryption Standard New Instructions - clmul: "CLMUL", // Carry-less Multiplication - htt: "HTT", // Hyperthreading (enabled) - hle: "HLE", // Hardware Lock Elision - rtm: "RTM", // Restricted Transactional Memory - rdrand: "RDRAND", // RDRAND instruction is available - rdseed: "RDSEED", // RDSEED instruction is available - adx: "ADX", // Intel ADX (Multi-Precision Add-Carry Instruction Extensions) - sha: "SHA", // Intel SHA Extensions - avx512f: "AVX512F", // AVX-512 Foundation - avx512dq: "AVX512DQ", // AVX-512 Doubleword and Quadword Instructions - avx512ifma: "AVX512IFMA", // AVX-512 Integer Fused Multiply-Add Instructions - avx512pf: "AVX512PF", // AVX-512 Prefetch Instructions - avx512er: "AVX512ER", // AVX-512 Exponential and Reciprocal Instructions - avx512cd: "AVX512CD", // AVX-512 Conflict Detection Instructions - avx512bw: "AVX512BW", // AVX-512 Byte and Word Instructions - avx512vl: "AVX512VL", // AVX-512 Vector Length Extensions - avx512vbmi: "AVX512VBMI", // AVX-512 Vector Bit Manipulation Instructions - mpx: "MPX", // Intel MPX (Memory Protection Extensions) - erms: "ERMS", // Enhanced REP MOVSB/STOSB - rdtscp: "RDTSCP", // RDTSCP Instruction - cx16: "CX16", // CMPXCHG16B Instruction - - // Performance indicators - sse2slow: "SSE2SLOW", // SSE2 supported, but usually not faster - sse3slow: "SSE3SLOW", // SSE3 supported, but usually not faster - atom: "ATOM", // Atom processor, some SSSE3 instructions are slower - -} - -// CPUInfo contains information about the detected system CPU. -type cpuInfo struct { - brandname string // Brand name reported by the CPU - vendorid vendor // Comparable CPU vendor ID - features flags // Features of the CPU - physicalcores int // Number of physical processor cores in your CPU. Will be 0 if undetectable. - threadspercore int // Number of threads per physical core. Will be 1 if undetectable. - logicalcores int // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable. - family int // CPU family number - model int // CPU model number - cacheline int // Cache line size in bytes. Will be 0 if undetectable. - cache struct { - l1i int // L1 Instruction Cache (per core or shared). Will be -1 if undetected - l1d int // L1 Data Cache (per core or shared). Will be -1 if undetected - l2 int // L2 Cache (per core or shared). Will be -1 if undetected - l3 int // L3 Instruction Cache (per core or shared). Will be -1 if undetected - } - maxFunc uint32 - maxExFunc uint32 -} - -var cpuid func(op uint32) (eax, ebx, ecx, edx uint32) -var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32) -var xgetbv func(index uint32) (eax, edx uint32) -var rdtscpAsm func() (eax, ebx, ecx, edx uint32) - -// CPU contains information about the CPU as detected on startup, -// or when Detect last was called. -// -// Use this as the primary entry point to you data, -// this way queries are -var cpu cpuInfo - -func init() { - initCPU() - detect() -} - -// Detect will re-detect current CPU info. -// This will replace the content of the exported CPU variable. -// -// Unless you expect the CPU to change while you are running your program -// you should not need to call this function. -// If you call this, you must ensure that no other goroutine is accessing the -// exported CPU variable. -func detect() { - cpu.maxFunc = maxFunctionID() - cpu.maxExFunc = maxExtendedFunction() - cpu.brandname = brandName() - cpu.cacheline = cacheLine() - cpu.family, cpu.model = familyModel() - cpu.features = support() - cpu.threadspercore = threadsPerCore() - cpu.logicalcores = logicalCores() - cpu.physicalcores = physicalCores() - cpu.vendorid = vendorID() - cpu.cacheSize() -} - -// Generated here: http://play.golang.org/p/BxFH2Gdc0G - -// Cmov indicates support of CMOV instructions -func (c cpuInfo) cmov() bool { - return c.features&cmov != 0 -} - -// Amd3dnow indicates support of AMD 3DNOW! instructions -func (c cpuInfo) amd3dnow() bool { - return c.features&amd3dnow != 0 -} - -// Amd3dnowExt indicates support of AMD 3DNOW! Extended instructions -func (c cpuInfo) amd3dnowext() bool { - return c.features&amd3dnowext != 0 -} - -// MMX indicates support of MMX instructions -func (c cpuInfo) mmx() bool { - return c.features&mmx != 0 -} - -// MMXExt indicates support of MMXEXT instructions -// (SSE integer functions or AMD MMX ext) -func (c cpuInfo) mmxext() bool { - return c.features&mmxext != 0 -} - -// SSE indicates support of SSE instructions -func (c cpuInfo) sse() bool { - return c.features&sse != 0 -} - -// SSE2 indicates support of SSE 2 instructions -func (c cpuInfo) sse2() bool { - return c.features&sse2 != 0 -} - -// SSE3 indicates support of SSE 3 instructions -func (c cpuInfo) sse3() bool { - return c.features&sse3 != 0 -} - -// SSSE3 indicates support of SSSE 3 instructions -func (c cpuInfo) ssse3() bool { - return c.features&ssse3 != 0 -} - -// SSE4 indicates support of SSE 4 (also called SSE 4.1) instructions -func (c cpuInfo) sse4() bool { - return c.features&sse4 != 0 -} - -// SSE42 indicates support of SSE4.2 instructions -func (c cpuInfo) sse42() bool { - return c.features&sse42 != 0 -} - -// AVX indicates support of AVX instructions -// and operating system support of AVX instructions -func (c cpuInfo) avx() bool { - return c.features&avx != 0 -} - -// AVX2 indicates support of AVX2 instructions -func (c cpuInfo) avx2() bool { - return c.features&avx2 != 0 -} - -// FMA3 indicates support of FMA3 instructions -func (c cpuInfo) fma3() bool { - return c.features&fma3 != 0 -} - -// FMA4 indicates support of FMA4 instructions -func (c cpuInfo) fma4() bool { - return c.features&fma4 != 0 -} - -// XOP indicates support of XOP instructions -func (c cpuInfo) xop() bool { - return c.features&xop != 0 -} - -// F16C indicates support of F16C instructions -func (c cpuInfo) f16c() bool { - return c.features&f16c != 0 -} - -// BMI1 indicates support of BMI1 instructions -func (c cpuInfo) bmi1() bool { - return c.features&bmi1 != 0 -} - -// BMI2 indicates support of BMI2 instructions -func (c cpuInfo) bmi2() bool { - return c.features&bmi2 != 0 -} - -// TBM indicates support of TBM instructions -// (AMD Trailing Bit Manipulation) -func (c cpuInfo) tbm() bool { - return c.features&tbm != 0 -} - -// Lzcnt indicates support of LZCNT instruction -func (c cpuInfo) lzcnt() bool { - return c.features&lzcnt != 0 -} - -// Popcnt indicates support of POPCNT instruction -func (c cpuInfo) popcnt() bool { - return c.features&popcnt != 0 -} - -// HTT indicates the processor has Hyperthreading enabled -func (c cpuInfo) htt() bool { - return c.features&htt != 0 -} - -// SSE2Slow indicates that SSE2 may be slow on this processor -func (c cpuInfo) sse2slow() bool { - return c.features&sse2slow != 0 -} - -// SSE3Slow indicates that SSE3 may be slow on this processor -func (c cpuInfo) sse3slow() bool { - return c.features&sse3slow != 0 -} - -// AesNi indicates support of AES-NI instructions -// (Advanced Encryption Standard New Instructions) -func (c cpuInfo) aesni() bool { - return c.features&aesni != 0 -} - -// Clmul indicates support of CLMUL instructions -// (Carry-less Multiplication) -func (c cpuInfo) clmul() bool { - return c.features&clmul != 0 -} - -// NX indicates support of NX (No-Execute) bit -func (c cpuInfo) nx() bool { - return c.features&nx != 0 -} - -// SSE4A indicates support of AMD Barcelona microarchitecture SSE4a instructions -func (c cpuInfo) sse4a() bool { - return c.features&sse4a != 0 -} - -// HLE indicates support of Hardware Lock Elision -func (c cpuInfo) hle() bool { - return c.features&hle != 0 -} - -// RTM indicates support of Restricted Transactional Memory -func (c cpuInfo) rtm() bool { - return c.features&rtm != 0 -} - -// Rdrand indicates support of RDRAND instruction is available -func (c cpuInfo) rdrand() bool { - return c.features&rdrand != 0 -} - -// Rdseed indicates support of RDSEED instruction is available -func (c cpuInfo) rdseed() bool { - return c.features&rdseed != 0 -} - -// ADX indicates support of Intel ADX (Multi-Precision Add-Carry Instruction Extensions) -func (c cpuInfo) adx() bool { - return c.features&adx != 0 -} - -// SHA indicates support of Intel SHA Extensions -func (c cpuInfo) sha() bool { - return c.features&sha != 0 -} - -// AVX512F indicates support of AVX-512 Foundation -func (c cpuInfo) avx512f() bool { - return c.features&avx512f != 0 -} - -// AVX512DQ indicates support of AVX-512 Doubleword and Quadword Instructions -func (c cpuInfo) avx512dq() bool { - return c.features&avx512dq != 0 -} - -// AVX512IFMA indicates support of AVX-512 Integer Fused Multiply-Add Instructions -func (c cpuInfo) avx512ifma() bool { - return c.features&avx512ifma != 0 -} - -// AVX512PF indicates support of AVX-512 Prefetch Instructions -func (c cpuInfo) avx512pf() bool { - return c.features&avx512pf != 0 -} - -// AVX512ER indicates support of AVX-512 Exponential and Reciprocal Instructions -func (c cpuInfo) avx512er() bool { - return c.features&avx512er != 0 -} - -// AVX512CD indicates support of AVX-512 Conflict Detection Instructions -func (c cpuInfo) avx512cd() bool { - return c.features&avx512cd != 0 -} - -// AVX512BW indicates support of AVX-512 Byte and Word Instructions -func (c cpuInfo) avx512bw() bool { - return c.features&avx512bw != 0 -} - -// AVX512VL indicates support of AVX-512 Vector Length Extensions -func (c cpuInfo) avx512vl() bool { - return c.features&avx512vl != 0 -} - -// AVX512VBMI indicates support of AVX-512 Vector Bit Manipulation Instructions -func (c cpuInfo) avx512vbmi() bool { - return c.features&avx512vbmi != 0 -} - -// MPX indicates support of Intel MPX (Memory Protection Extensions) -func (c cpuInfo) mpx() bool { - return c.features&mpx != 0 -} - -// ERMS indicates support of Enhanced REP MOVSB/STOSB -func (c cpuInfo) erms() bool { - return c.features&erms != 0 -} - -func (c cpuInfo) rdtscp() bool { - return c.features&rdtscp != 0 -} - -func (c cpuInfo) cx16() bool { - return c.features&cx16 != 0 -} - -// Atom indicates an Atom processor -func (c cpuInfo) atom() bool { - return c.features&atom != 0 -} - -// Intel returns true if vendor is recognized as Intel -func (c cpuInfo) intel() bool { - return c.vendorid == intel -} - -// AMD returns true if vendor is recognized as AMD -func (c cpuInfo) amd() bool { - return c.vendorid == amd -} - -// Transmeta returns true if vendor is recognized as Transmeta -func (c cpuInfo) transmeta() bool { - return c.vendorid == transmeta -} - -// NSC returns true if vendor is recognized as National Semiconductor -func (c cpuInfo) nsc() bool { - return c.vendorid == nsc -} - -// VIA returns true if vendor is recognized as VIA -func (c cpuInfo) via() bool { - return c.vendorid == via -} - -// RTCounter returns the 64-bit time-stamp counter -// Uses the RDTSCP instruction. The value 0 is returned -// if the CPU does not support the instruction. -func (c cpuInfo) rtcounter() uint64 { - if !c.rdtscp() { - return 0 - } - a, _, _, d := rdtscpAsm() - return uint64(a) | (uint64(d) << 32) -} - -// Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP. -// This variable is OS dependent, but on Linux contains information -// about the current cpu/core the code is running on. -// If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned. -func (c cpuInfo) ia32tscaux() uint32 { - if !c.rdtscp() { - return 0 - } - _, _, ecx, _ := rdtscpAsm() - return ecx -} - -// LogicalCPU will return the Logical CPU the code is currently executing on. -// This is likely to change when the OS re-schedules the running thread -// to another CPU. -// If the current core cannot be detected, -1 will be returned. -func (c cpuInfo) logicalcpu() int { - if c.maxFunc < 1 { - return -1 - } - _, ebx, _, _ := cpuid(1) - return int(ebx >> 24) -} - -// VM Will return true if the cpu id indicates we are in -// a virtual machine. This is only a hint, and will very likely -// have many false negatives. -func (c cpuInfo) vm() bool { - switch c.vendorid { - case msvm, kvm, vmware, xenhvm: - return true - } - return false -} - -// Flags contains detected cpu features and caracteristics -type flags uint64 - -// String returns a string representation of the detected -// CPU features. -func (f flags) String() string { - return strings.Join(f.strings(), ",") -} - -// Strings returns and array of the detected features. -func (f flags) strings() []string { - s := support() - r := make([]string, 0, 20) - for i := uint(0); i < 64; i++ { - key := flags(1 << i) - val := flagNames[key] - if s&key != 0 { - r = append(r, val) - } - } - return r -} - -func maxExtendedFunction() uint32 { - eax, _, _, _ := cpuid(0x80000000) - return eax -} - -func maxFunctionID() uint32 { - a, _, _, _ := cpuid(0) - return a -} - -func brandName() string { - if maxExtendedFunction() >= 0x80000004 { - v := make([]uint32, 0, 48) - for i := uint32(0); i < 3; i++ { - a, b, c, d := cpuid(0x80000002 + i) - v = append(v, a, b, c, d) - } - return strings.Trim(string(valAsString(v...)), " ") - } - return "unknown" -} - -func threadsPerCore() int { - mfi := maxFunctionID() - if mfi < 0x4 || vendorID() != intel { - return 1 - } - - if mfi < 0xb { - _, b, _, d := cpuid(1) - if (d & (1 << 28)) != 0 { - // v will contain logical core count - v := (b >> 16) & 255 - if v > 1 { - a4, _, _, _ := cpuid(4) - // physical cores - v2 := (a4 >> 26) + 1 - if v2 > 0 { - return int(v) / int(v2) - } - } - } - return 1 - } - _, b, _, _ := cpuidex(0xb, 0) - if b&0xffff == 0 { - return 1 - } - return int(b & 0xffff) -} - -func logicalCores() int { - mfi := maxFunctionID() - switch vendorID() { - case intel: - // Use this on old Intel processors - if mfi < 0xb { - if mfi < 1 { - return 0 - } - // CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID) - // that can be assigned to logical processors in a physical package. - // The value may not be the same as the number of logical processors that are present in the hardware of a physical package. - _, ebx, _, _ := cpuid(1) - logical := (ebx >> 16) & 0xff - return int(logical) - } - _, b, _, _ := cpuidex(0xb, 1) - return int(b & 0xffff) - case amd: - _, b, _, _ := cpuid(1) - return int((b >> 16) & 0xff) - default: - return 0 - } -} - -func familyModel() (int, int) { - if maxFunctionID() < 0x1 { - return 0, 0 - } - eax, _, _, _ := cpuid(1) - family := ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff) - model := ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0) - return int(family), int(model) -} - -func physicalCores() int { - switch vendorID() { - case intel: - return logicalCores() / threadsPerCore() - case amd: - if maxExtendedFunction() >= 0x80000008 { - _, _, c, _ := cpuid(0x80000008) - return int(c&0xff) + 1 - } - } - return 0 -} - -// Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID -var vendorMapping = map[string]vendor{ - "AMDisbetter!": amd, - "AuthenticAMD": amd, - "CentaurHauls": via, - "GenuineIntel": intel, - "TransmetaCPU": transmeta, - "GenuineTMx86": transmeta, - "Geode by NSC": nsc, - "VIA VIA VIA ": via, - "KVMKVMKVMKVM": kvm, - "Microsoft Hv": msvm, - "VMwareVMware": vmware, - "XenVMMXenVMM": xenhvm, -} - -func vendorID() vendor { - _, b, c, d := cpuid(0) - v := valAsString(b, d, c) - vend, ok := vendorMapping[string(v)] - if !ok { - return other - } - return vend -} - -func cacheLine() int { - if maxFunctionID() < 0x1 { - return 0 - } - - _, ebx, _, _ := cpuid(1) - cache := (ebx & 0xff00) >> 5 // cflush size - if cache == 0 && maxExtendedFunction() >= 0x80000006 { - _, _, ecx, _ := cpuid(0x80000006) - cache = ecx & 0xff // cacheline size - } - // TODO: Read from Cache and TLB Information - return int(cache) -} - -func (c *cpuInfo) cacheSize() { - c.cache.l1d = -1 - c.cache.l1i = -1 - c.cache.l2 = -1 - c.cache.l3 = -1 - vendor := vendorID() - switch vendor { - case intel: - if maxFunctionID() < 4 { - return - } - for i := uint32(0); ; i++ { - eax, ebx, ecx, _ := cpuidex(4, i) - cacheType := eax & 15 - if cacheType == 0 { - break - } - cacheLevel := (eax >> 5) & 7 - coherency := int(ebx&0xfff) + 1 - partitions := int((ebx>>12)&0x3ff) + 1 - associativity := int((ebx>>22)&0x3ff) + 1 - sets := int(ecx) + 1 - size := associativity * partitions * coherency * sets - switch cacheLevel { - case 1: - if cacheType == 1 { - // 1 = Data Cache - c.cache.l1d = size - } else if cacheType == 2 { - // 2 = Instruction Cache - c.cache.l1i = size - } else { - if c.cache.l1d < 0 { - c.cache.l1i = size - } - if c.cache.l1i < 0 { - c.cache.l1i = size - } - } - case 2: - c.cache.l2 = size - case 3: - c.cache.l3 = size - } - } - case amd: - // Untested. - if maxExtendedFunction() < 0x80000005 { - return - } - _, _, ecx, edx := cpuid(0x80000005) - c.cache.l1d = int(((ecx >> 24) & 0xFF) * 1024) - c.cache.l1i = int(((edx >> 24) & 0xFF) * 1024) - - if maxExtendedFunction() < 0x80000006 { - return - } - _, _, ecx, _ = cpuid(0x80000006) - c.cache.l2 = int(((ecx >> 16) & 0xFFFF) * 1024) - } - - return -} - -func support() flags { - mfi := maxFunctionID() - vend := vendorID() - if mfi < 0x1 { - return 0 - } - rval := uint64(0) - _, _, c, d := cpuid(1) - if (d & (1 << 15)) != 0 { - rval |= cmov - } - if (d & (1 << 23)) != 0 { - rval |= mmx - } - if (d & (1 << 25)) != 0 { - rval |= mmxext - } - if (d & (1 << 25)) != 0 { - rval |= sse - } - if (d & (1 << 26)) != 0 { - rval |= sse2 - } - if (c & 1) != 0 { - rval |= sse3 - } - if (c & 0x00000200) != 0 { - rval |= ssse3 - } - if (c & 0x00080000) != 0 { - rval |= sse4 - } - if (c & 0x00100000) != 0 { - rval |= sse42 - } - if (c & (1 << 25)) != 0 { - rval |= aesni - } - if (c & (1 << 1)) != 0 { - rval |= clmul - } - if c&(1<<23) != 0 { - rval |= popcnt - } - if c&(1<<30) != 0 { - rval |= rdrand - } - if c&(1<<29) != 0 { - rval |= f16c - } - if c&(1<<13) != 0 { - rval |= cx16 - } - if vend == intel && (d&(1<<28)) != 0 && mfi >= 4 { - if threadsPerCore() > 1 { - rval |= htt - } - } - - // Check XGETBV, OXSAVE and AVX bits - if c&(1<<26) != 0 && c&(1<<27) != 0 && c&(1<<28) != 0 { - // Check for OS support - eax, _ := xgetbv(0) - if (eax & 0x6) == 0x6 { - rval |= avx - if (c & 0x00001000) != 0 { - rval |= fma3 - } - } - } - - // Check AVX2, AVX2 requires OS support, but BMI1/2 don't. - if mfi >= 7 { - _, ebx, ecx, _ := cpuidex(7, 0) - if (rval&avx) != 0 && (ebx&0x00000020) != 0 { - rval |= avx2 - } - if (ebx & 0x00000008) != 0 { - rval |= bmi1 - if (ebx & 0x00000100) != 0 { - rval |= bmi2 - } - } - if ebx&(1<<4) != 0 { - rval |= hle - } - if ebx&(1<<9) != 0 { - rval |= erms - } - if ebx&(1<<11) != 0 { - rval |= rtm - } - if ebx&(1<<14) != 0 { - rval |= mpx - } - if ebx&(1<<18) != 0 { - rval |= rdseed - } - if ebx&(1<<19) != 0 { - rval |= adx - } - if ebx&(1<<29) != 0 { - rval |= sha - } - - // Only detect AVX-512 features if XGETBV is supported - if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) { - // Check for OS support - eax, _ := xgetbv(0) - - // Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and - // ZMM16-ZMM31 state are enabled by OS) - /// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS). - if (eax>>5)&7 == 7 && (eax>>1)&3 == 3 { - if ebx&(1<<16) != 0 { - rval |= avx512f - } - if ebx&(1<<17) != 0 { - rval |= avx512dq - } - if ebx&(1<<21) != 0 { - rval |= avx512ifma - } - if ebx&(1<<26) != 0 { - rval |= avx512pf - } - if ebx&(1<<27) != 0 { - rval |= avx512er - } - if ebx&(1<<28) != 0 { - rval |= avx512cd - } - if ebx&(1<<30) != 0 { - rval |= avx512bw - } - if ebx&(1<<31) != 0 { - rval |= avx512vl - } - // ecx - if ecx&(1<<1) != 0 { - rval |= avx512vbmi - } - } - } - } - - if maxExtendedFunction() >= 0x80000001 { - _, _, c, d := cpuid(0x80000001) - if (c & (1 << 5)) != 0 { - rval |= lzcnt - rval |= popcnt - } - if (d & (1 << 31)) != 0 { - rval |= amd3dnow - } - if (d & (1 << 30)) != 0 { - rval |= amd3dnowext - } - if (d & (1 << 23)) != 0 { - rval |= mmx - } - if (d & (1 << 22)) != 0 { - rval |= mmxext - } - if (c & (1 << 6)) != 0 { - rval |= sse4a - } - if d&(1<<20) != 0 { - rval |= nx - } - if d&(1<<27) != 0 { - rval |= rdtscp - } - - /* Allow for selectively disabling SSE2 functions on AMD processors - with SSE2 support but not SSE4a. This includes Athlon64, some - Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster - than SSE2 often enough to utilize this special-case flag. - AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case - so that SSE2 is used unless explicitly disabled by checking - AV_CPU_FLAG_SSE2SLOW. */ - if vendorID() != intel && - rval&sse2 != 0 && (c&0x00000040) == 0 { - rval |= sse2slow - } - - /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be - * used unless the OS has AVX support. */ - if (rval & avx) != 0 { - if (c & 0x00000800) != 0 { - rval |= xop - } - if (c & 0x00010000) != 0 { - rval |= fma4 - } - } - - if vendorID() == intel { - family, model := familyModel() - if family == 6 && (model == 9 || model == 13 || model == 14) { - /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and - * 6/14 (core1 "yonah") theoretically support sse2, but it's - * usually slower than mmx. */ - if (rval & sse2) != 0 { - rval |= sse2slow - } - if (rval & sse3) != 0 { - rval |= sse3slow - } - } - /* The Atom processor has SSSE3 support, which is useful in many cases, - * but sometimes the SSSE3 version is slower than the SSE2 equivalent - * on the Atom, but is generally faster on other processors supporting - * SSSE3. This flag allows for selectively disabling certain SSSE3 - * functions on the Atom. */ - if family == 6 && model == 28 { - rval |= atom - } - } - } - return flags(rval) -} - -func valAsString(values ...uint32) []byte { - r := make([]byte, 4*len(values)) - for i, v := range values { - dst := r[i*4:] - dst[0] = byte(v & 0xff) - dst[1] = byte((v >> 8) & 0xff) - dst[2] = byte((v >> 16) & 0xff) - dst[3] = byte((v >> 24) & 0xff) - switch { - case dst[0] == 0: - return r[:i*4] - case dst[1] == 0: - return r[:i*4+1] - case dst[2] == 0: - return r[:i*4+2] - case dst[3] == 0: - return r[:i*4+3] - } - } - return r -} diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_386.s b/vendor/github.com/klauspost/cpuid/private/cpuid_386.s deleted file mode 100644 index 9947f7b6f6a..00000000000 --- a/vendor/github.com/klauspost/cpuid/private/cpuid_386.s +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) -TEXT ·asmCpuid(SB), 7, $0 - XORL CX, CX - MOVL op+0(FP), AX - CPUID - MOVL AX, eax+4(FP) - MOVL BX, ebx+8(FP) - MOVL CX, ecx+12(FP) - MOVL DX, edx+16(FP) - RET - -// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) -TEXT ·asmCpuidex(SB), 7, $0 - MOVL op+0(FP), AX - MOVL op2+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func xgetbv(index uint32) (eax, edx uint32) -TEXT ·asmXgetbv(SB), 7, $0 - MOVL index+0(FP), CX - BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV - MOVL AX, eax+4(FP) - MOVL DX, edx+8(FP) - RET - -// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) -TEXT ·asmRdtscpAsm(SB), 7, $0 - BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP - MOVL AX, eax+0(FP) - MOVL BX, ebx+4(FP) - MOVL CX, ecx+8(FP) - MOVL DX, edx+12(FP) - RET diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s b/vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s deleted file mode 100644 index 68a7c9d8808..00000000000 --- a/vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) -TEXT ·asmCpuid(SB), 7, $0 - XORQ CX, CX - MOVL op+0(FP), AX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) -TEXT ·asmCpuidex(SB), 7, $0 - MOVL op+0(FP), AX - MOVL op2+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func asmXgetbv(index uint32) (eax, edx uint32) -TEXT ·asmXgetbv(SB), 7, $0 - MOVL index+0(FP), CX - BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV - MOVL AX, eax+8(FP) - MOVL DX, edx+12(FP) - RET - -// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) -TEXT ·asmRdtscpAsm(SB), 7, $0 - BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP - MOVL AX, eax+0(FP) - MOVL BX, ebx+4(FP) - MOVL CX, ecx+8(FP) - MOVL DX, edx+12(FP) - RET diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go b/vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go deleted file mode 100644 index d5475ebfaa8..00000000000 --- a/vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// +build 386 amd64 - -package cpuid - -func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32) -func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) -func asmXgetbv(index uint32) (eax, edx uint32) -func asmRdtscpAsm() (eax, ebx, ecx, edx uint32) - -func initCPU() { - cpuid = asmCpuid - cpuidex = asmCpuidex - xgetbv = asmXgetbv - rdtscpAsm = asmRdtscpAsm -} diff --git a/vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go b/vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go deleted file mode 100644 index 6f9231b13bf..00000000000 --- a/vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// +build !amd64,!386 - -package cpuid - -func initCPU() { - cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) { - return 0, 0, 0, 0 - } - - cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) { - return 0, 0, 0, 0 - } - - xgetbv = func(index uint32) (eax, edx uint32) { - return 0, 0 - } - - rdtscpAsm = func() (eax, ebx, ecx, edx uint32) { - return 0, 0, 0, 0 - } -} diff --git a/vendor/github.com/klauspost/crc32/README.md b/vendor/github.com/klauspost/crc32/README.md deleted file mode 100644 index 029625d3609..00000000000 --- a/vendor/github.com/klauspost/crc32/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# crc32 -CRC32 hash with x64 optimizations - -This package is a drop-in replacement for the standard library `hash/crc32` package, that features SSE 4.2 optimizations on x64 platforms, for a 10x speedup. - -[![Build Status](https://travis-ci.org/klauspost/crc32.svg?branch=master)](https://travis-ci.org/klauspost/crc32) - -# usage - -Install using `go get github.com/klauspost/crc32`. This library is based on Go 1.5 code and requires Go 1.3 or newer. - -Replace `import "hash/crc32"` with `import "github.com/klauspost/crc32"` and you are good to go. - -# changes -* Oct 20, 2016: Changes have been merged to upstream Go. Package updated to match. -* Dec 4, 2015: Uses the "slice-by-8" trick more extensively, which gives a 1.5 to 2.5x speedup if assembler is unavailable. - - -# performance - -For *Go 1.7* performance is equivalent to the standard library. So if you use this package for Go 1.7 you can switch back. - - -For IEEE tables (the most common), there is approximately a factor 10 speedup with "CLMUL" (Carryless multiplication) instruction: -``` -benchmark old ns/op new ns/op delta -BenchmarkCrc32KB 99955 10258 -89.74% - -benchmark old MB/s new MB/s speedup -BenchmarkCrc32KB 327.83 3194.20 9.74x -``` - -For other tables and "CLMUL" capable machines the performance is the same as the standard library. - -Here are some detailed benchmarks, comparing to go 1.5 standard library with and without assembler enabled. - -``` -Std: Standard Go 1.5 library -Crc: Indicates IEEE type CRC. -40B: Size of each slice encoded. -NoAsm: Assembler was disabled (ie. not an AMD64 or SSE 4.2+ capable machine). -Castagnoli: Castagnoli CRC type. - -BenchmarkStdCrc40B-4 10000000 158 ns/op 252.88 MB/s -BenchmarkCrc40BNoAsm-4 20000000 105 ns/op 377.38 MB/s (slice8) -BenchmarkCrc40B-4 20000000 105 ns/op 378.77 MB/s (slice8) - -BenchmarkStdCrc1KB-4 500000 3604 ns/op 284.10 MB/s -BenchmarkCrc1KBNoAsm-4 1000000 1463 ns/op 699.79 MB/s (slice8) -BenchmarkCrc1KB-4 3000000 396 ns/op 2583.69 MB/s (asm) - -BenchmarkStdCrc8KB-4 200000 11417 ns/op 717.48 MB/s (slice8) -BenchmarkCrc8KBNoAsm-4 200000 11317 ns/op 723.85 MB/s (slice8) -BenchmarkCrc8KB-4 500000 2919 ns/op 2805.73 MB/s (asm) - -BenchmarkStdCrc32KB-4 30000 45749 ns/op 716.24 MB/s (slice8) -BenchmarkCrc32KBNoAsm-4 30000 45109 ns/op 726.42 MB/s (slice8) -BenchmarkCrc32KB-4 100000 11497 ns/op 2850.09 MB/s (asm) - -BenchmarkStdNoAsmCastagnol40B-4 10000000 161 ns/op 246.94 MB/s -BenchmarkStdCastagnoli40B-4 50000000 28.4 ns/op 1410.69 MB/s (asm) -BenchmarkCastagnoli40BNoAsm-4 20000000 100 ns/op 398.01 MB/s (slice8) -BenchmarkCastagnoli40B-4 50000000 28.2 ns/op 1419.54 MB/s (asm) - -BenchmarkStdNoAsmCastagnoli1KB-4 500000 3622 ns/op 282.67 MB/s -BenchmarkStdCastagnoli1KB-4 10000000 144 ns/op 7099.78 MB/s (asm) -BenchmarkCastagnoli1KBNoAsm-4 1000000 1475 ns/op 694.14 MB/s (slice8) -BenchmarkCastagnoli1KB-4 10000000 146 ns/op 6993.35 MB/s (asm) - -BenchmarkStdNoAsmCastagnoli8KB-4 50000 28781 ns/op 284.63 MB/s -BenchmarkStdCastagnoli8KB-4 1000000 1029 ns/op 7957.89 MB/s (asm) -BenchmarkCastagnoli8KBNoAsm-4 200000 11410 ns/op 717.94 MB/s (slice8) -BenchmarkCastagnoli8KB-4 1000000 1000 ns/op 8188.71 MB/s (asm) - -BenchmarkStdNoAsmCastagnoli32KB-4 10000 115426 ns/op 283.89 MB/s -BenchmarkStdCastagnoli32KB-4 300000 4065 ns/op 8059.13 MB/s (asm) -BenchmarkCastagnoli32KBNoAsm-4 30000 45171 ns/op 725.41 MB/s (slice8) -BenchmarkCastagnoli32KB-4 500000 4077 ns/op 8035.89 MB/s (asm) -``` - -The IEEE assembler optimizations has been submitted and will be part of the Go 1.6 standard library. - -However, the improved use of slice-by-8 has not, but will probably be submitted for Go 1.7. - -# license - -Standard Go license. Changes are Copyright (c) 2015 Klaus Post under same conditions. diff --git a/vendor/github.com/kr/pretty/.gitignore b/vendor/github.com/kr/pretty/.gitignore deleted file mode 100644 index 1f0a99f2f2b..00000000000 --- a/vendor/github.com/kr/pretty/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -[568].out -_go* -_test* -_obj diff --git a/vendor/github.com/kr/pretty/Readme b/vendor/github.com/kr/pretty/Readme deleted file mode 100644 index c589fc622b3..00000000000 --- a/vendor/github.com/kr/pretty/Readme +++ /dev/null @@ -1,9 +0,0 @@ -package pretty - - import "github.com/kr/pretty" - - Package pretty provides pretty-printing for Go values. - -Documentation - - http://godoc.org/github.com/kr/pretty diff --git a/vendor/github.com/kr/pretty/diff.go b/vendor/github.com/kr/pretty/diff.go index 8fe8e2405a0..6aa7f743a28 100644 --- a/vendor/github.com/kr/pretty/diff.go +++ b/vendor/github.com/kr/pretty/diff.go @@ -8,43 +8,81 @@ import ( type sbuf []string -func (s *sbuf) Write(b []byte) (int, error) { - *s = append(*s, string(b)) - return len(b), nil +func (p *sbuf) Printf(format string, a ...interface{}) { + s := fmt.Sprintf(format, a...) + *p = append(*p, s) } // Diff returns a slice where each element describes // a difference between a and b. func Diff(a, b interface{}) (desc []string) { - Fdiff((*sbuf)(&desc), a, b) + Pdiff((*sbuf)(&desc), a, b) return desc } +// wprintfer calls Fprintf on w for each Printf call +// with a trailing newline. +type wprintfer struct{ w io.Writer } + +func (p *wprintfer) Printf(format string, a ...interface{}) { + fmt.Fprintf(p.w, format+"\n", a...) +} + // Fdiff writes to w a description of the differences between a and b. func Fdiff(w io.Writer, a, b interface{}) { - diffWriter{w: w}.diff(reflect.ValueOf(a), reflect.ValueOf(b)) + Pdiff(&wprintfer{w}, a, b) } -type diffWriter struct { - w io.Writer +type Printfer interface { + Printf(format string, a ...interface{}) +} + +// Pdiff prints to p a description of the differences between a and b. +// It calls Printf once for each difference, with no trailing newline. +// The standard library log.Logger is a Printfer. +func Pdiff(p Printfer, a, b interface{}) { + diffPrinter{w: p}.diff(reflect.ValueOf(a), reflect.ValueOf(b)) +} + +type Logfer interface { + Logf(format string, a ...interface{}) +} + +// logprintfer calls Fprintf on w for each Printf call +// with a trailing newline. +type logprintfer struct{ l Logfer } + +func (p *logprintfer) Printf(format string, a ...interface{}) { + p.l.Logf(format, a...) +} + +// Ldiff prints to l a description of the differences between a and b. +// It calls Logf once for each difference, with no trailing newline. +// The standard library testing.T and testing.B are Logfers. +func Ldiff(l Logfer, a, b interface{}) { + Pdiff(&logprintfer{l}, a, b) +} + +type diffPrinter struct { + w Printfer l string // label } -func (w diffWriter) printf(f string, a ...interface{}) { +func (w diffPrinter) printf(f string, a ...interface{}) { var l string if w.l != "" { l = w.l + ": " } - fmt.Fprintf(w.w, l+f, a...) + w.w.Printf(l+f, a...) } -func (w diffWriter) diff(av, bv reflect.Value) { +func (w diffPrinter) diff(av, bv reflect.Value) { if !av.IsValid() && bv.IsValid() { - w.printf("nil != %#v", bv.Interface()) + w.printf("nil != %# v", formatter{v: bv, quote: true}) return } if av.IsValid() && !bv.IsValid() { - w.printf("%#v != nil", av.Interface()) + w.printf("%# v != nil", formatter{v: av, quote: true}) return } if !av.IsValid() && !bv.IsValid() { @@ -58,34 +96,61 @@ func (w diffWriter) diff(av, bv reflect.Value) { return } - // numeric types, including bool - if at.Kind() < reflect.Array { - a, b := av.Interface(), bv.Interface() - if a != b { - w.printf("%#v != %#v", a, b) + switch kind := at.Kind(); kind { + case reflect.Bool: + if a, b := av.Bool(), bv.Bool(); a != b { + w.printf("%v != %v", a, b) } - return - } - - switch at.Kind() { - case reflect.String: - a, b := av.Interface(), bv.Interface() - if a != b { - w.printf("%q != %q", a, b) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if a, b := av.Int(), bv.Int(); a != b { + w.printf("%d != %d", a, b) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + if a, b := av.Uint(), bv.Uint(); a != b { + w.printf("%d != %d", a, b) + } + case reflect.Float32, reflect.Float64: + if a, b := av.Float(), bv.Float(); a != b { + w.printf("%v != %v", a, b) + } + case reflect.Complex64, reflect.Complex128: + if a, b := av.Complex(), bv.Complex(); a != b { + w.printf("%v != %v", a, b) + } + case reflect.Array: + n := av.Len() + for i := 0; i < n; i++ { + w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) + } + case reflect.Chan, reflect.Func, reflect.UnsafePointer: + if a, b := av.Pointer(), bv.Pointer(); a != b { + w.printf("%#x != %#x", a, b) + } + case reflect.Interface: + w.diff(av.Elem(), bv.Elem()) + case reflect.Map: + ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys()) + for _, k := range ak { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.printf("%q != (missing)", av.MapIndex(k)) + } + for _, k := range both { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.diff(av.MapIndex(k), bv.MapIndex(k)) + } + for _, k := range bk { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.printf("(missing) != %q", bv.MapIndex(k)) } case reflect.Ptr: switch { case av.IsNil() && !bv.IsNil(): - w.printf("nil != %v", bv.Interface()) + w.printf("nil != %# v", formatter{v: bv, quote: true}) case !av.IsNil() && bv.IsNil(): - w.printf("%v != nil", av.Interface()) + w.printf("%# v != nil", formatter{v: av, quote: true}) case !av.IsNil() && !bv.IsNil(): w.diff(av.Elem(), bv.Elem()) } - case reflect.Struct: - for i := 0; i < av.NumField(); i++ { - w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i)) - } case reflect.Slice: lenA := av.Len() lenB := bv.Len() @@ -96,30 +161,20 @@ func (w diffWriter) diff(av, bv reflect.Value) { for i := 0; i < lenA; i++ { w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) } - case reflect.Map: - ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys()) - for _, k := range ak { - w := w.relabel(fmt.Sprintf("[%#v]", k.Interface())) - w.printf("%q != (missing)", av.MapIndex(k)) + case reflect.String: + if a, b := av.String(), bv.String(); a != b { + w.printf("%q != %q", a, b) } - for _, k := range both { - w := w.relabel(fmt.Sprintf("[%#v]", k.Interface())) - w.diff(av.MapIndex(k), bv.MapIndex(k)) + case reflect.Struct: + for i := 0; i < av.NumField(); i++ { + w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i)) } - for _, k := range bk { - w := w.relabel(fmt.Sprintf("[%#v]", k.Interface())) - w.printf("(missing) != %q", bv.MapIndex(k)) - } - case reflect.Interface: - w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface())) default: - if !reflect.DeepEqual(av.Interface(), bv.Interface()) { - w.printf("%# v != %# v", Formatter(av.Interface()), Formatter(bv.Interface())) - } + panic("unknown reflect Kind: " + kind.String()) } } -func (d diffWriter) relabel(name string) (d1 diffWriter) { +func (d diffPrinter) relabel(name string) (d1 diffPrinter) { d1 = d if d.l != "" && name[0] != '[' { d1.l += "." @@ -128,11 +183,63 @@ func (d diffWriter) relabel(name string) (d1 diffWriter) { return d1 } +// keyEqual compares a and b for equality. +// Both a and b must be valid map keys. +func keyEqual(av, bv reflect.Value) bool { + if !av.IsValid() && !bv.IsValid() { + return true + } + if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() { + return false + } + switch kind := av.Kind(); kind { + case reflect.Bool: + a, b := av.Bool(), bv.Bool() + return a == b + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + a, b := av.Int(), bv.Int() + return a == b + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + a, b := av.Uint(), bv.Uint() + return a == b + case reflect.Float32, reflect.Float64: + a, b := av.Float(), bv.Float() + return a == b + case reflect.Complex64, reflect.Complex128: + a, b := av.Complex(), bv.Complex() + return a == b + case reflect.Array: + for i := 0; i < av.Len(); i++ { + if !keyEqual(av.Index(i), bv.Index(i)) { + return false + } + } + return true + case reflect.Chan, reflect.UnsafePointer, reflect.Ptr: + a, b := av.Pointer(), bv.Pointer() + return a == b + case reflect.Interface: + return keyEqual(av.Elem(), bv.Elem()) + case reflect.String: + a, b := av.String(), bv.String() + return a == b + case reflect.Struct: + for i := 0; i < av.NumField(); i++ { + if !keyEqual(av.Field(i), bv.Field(i)) { + return false + } + } + return true + default: + panic("invalid map key type " + av.Type().String()) + } +} + func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) { for _, av := range a { inBoth := false for _, bv := range b { - if reflect.DeepEqual(av.Interface(), bv.Interface()) { + if keyEqual(av, bv) { inBoth = true both = append(both, av) break @@ -145,7 +252,7 @@ func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) { for _, bv := range b { inBoth := false for _, av := range a { - if reflect.DeepEqual(av.Interface(), bv.Interface()) { + if keyEqual(av, bv) { inBoth = true break } diff --git a/vendor/github.com/kr/pretty/diff_test.go b/vendor/github.com/kr/pretty/diff_test.go deleted file mode 100644 index 3c388f13ca7..00000000000 --- a/vendor/github.com/kr/pretty/diff_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package pretty - -import ( - "testing" -) - -type difftest struct { - a interface{} - b interface{} - exp []string -} - -type S struct { - A int - S *S - I interface{} - C []int -} - -var diffs = []difftest{ - {a: nil, b: nil}, - {a: S{A: 1}, b: S{A: 1}}, - - {0, "", []string{`int != string`}}, - {0, 1, []string{`0 != 1`}}, - {S{}, new(S), []string{`pretty.S != *pretty.S`}}, - {"a", "b", []string{`"a" != "b"`}}, - {S{}, S{A: 1}, []string{`A: 0 != 1`}}, - {new(S), &S{A: 1}, []string{`A: 0 != 1`}}, - {S{S: new(S)}, S{S: &S{A: 1}}, []string{`S.A: 0 != 1`}}, - {S{}, S{I: 0}, []string{`I: nil != 0`}}, - {S{I: 1}, S{I: "x"}, []string{`I: int != string`}}, - {S{}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}}, - {S{C: []int{}}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}}, - {S{C: []int{1, 2, 3}}, S{C: []int{1, 2, 4}}, []string{`C[2]: 3 != 4`}}, - {S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &{0 []}`}}, -} - -func TestDiff(t *testing.T) { - for _, tt := range diffs { - got := Diff(tt.a, tt.b) - eq := len(got) == len(tt.exp) - if eq { - for i := range got { - eq = eq && got[i] == tt.exp[i] - } - } - if !eq { - t.Errorf("diffing % #v", tt.a) - t.Errorf("with % #v", tt.b) - diffdiff(t, got, tt.exp) - continue - } - } -} - -func diffdiff(t *testing.T, got, exp []string) { - minus(t, "unexpected:", got, exp) - minus(t, "missing:", exp, got) -} - -func minus(t *testing.T, s string, a, b []string) { - var i, j int - for i = 0; i < len(a); i++ { - for j = 0; j < len(b); j++ { - if a[i] == b[j] { - break - } - } - if j == len(b) { - t.Error(s, a[i]) - } - } -} diff --git a/vendor/github.com/kr/pretty/example_test.go b/vendor/github.com/kr/pretty/example_test.go deleted file mode 100644 index ecf40f3fcc6..00000000000 --- a/vendor/github.com/kr/pretty/example_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package pretty_test - -import ( - "fmt" - "github.com/kr/pretty" -) - -func Example() { - type myType struct { - a, b int - } - var x = []myType{{1, 2}, {3, 4}, {5, 6}} - fmt.Printf("%# v", pretty.Formatter(x)) - // output: - // []pretty_test.myType{ - // {a:1, b:2}, - // {a:3, b:4}, - // {a:5, b:6}, - // } -} diff --git a/vendor/github.com/kr/pretty/formatter.go b/vendor/github.com/kr/pretty/formatter.go index 8dacda25fa8..a317d7b8ee8 100644 --- a/vendor/github.com/kr/pretty/formatter.go +++ b/vendor/github.com/kr/pretty/formatter.go @@ -10,12 +10,8 @@ import ( "github.com/kr/text" ) -const ( - limit = 50 -) - type formatter struct { - x interface{} + v reflect.Value force bool quote bool } @@ -30,11 +26,11 @@ type formatter struct { // format x according to the usual rules of package fmt. // In particular, if x satisfies fmt.Formatter, then x.Format will be called. func Formatter(x interface{}) (f fmt.Formatter) { - return formatter{x: x, quote: true} + return formatter{v: reflect.ValueOf(x), quote: true} } func (fo formatter) String() string { - return fmt.Sprint(fo.x) // unwrap it + return fmt.Sprint(fo.v.Interface()) // unwrap it } func (fo formatter) passThrough(f fmt.State, c rune) { @@ -51,14 +47,14 @@ func (fo formatter) passThrough(f fmt.State, c rune) { s += fmt.Sprintf(".%d", p) } s += string(c) - fmt.Fprintf(f, s, fo.x) + fmt.Fprintf(f, s, fo.v.Interface()) } func (fo formatter) Format(f fmt.State, c rune) { if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') { w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0) p := &printer{tw: w, Writer: w, visited: make(map[visit]int)} - p.printValue(reflect.ValueOf(fo.x), true, fo.quote) + p.printValue(fo.v, true, fo.quote) w.Flush() return } @@ -319,11 +315,6 @@ func (p *printer) fmtString(s string, quote bool) { io.WriteString(p, s) } -func tryDeepEqual(a, b interface{}) bool { - defer func() { recover() }() - return reflect.DeepEqual(a, b) -} - func writeByte(w io.Writer, b byte) { w.Write([]byte{b}) } diff --git a/vendor/github.com/kr/pretty/formatter_test.go b/vendor/github.com/kr/pretty/formatter_test.go deleted file mode 100644 index 5f3204e8e87..00000000000 --- a/vendor/github.com/kr/pretty/formatter_test.go +++ /dev/null @@ -1,261 +0,0 @@ -package pretty - -import ( - "fmt" - "io" - "strings" - "testing" - "unsafe" -) - -type test struct { - v interface{} - s string -} - -type LongStructTypeName struct { - longFieldName interface{} - otherLongFieldName interface{} -} - -type SA struct { - t *T - v T -} - -type T struct { - x, y int -} - -type F int - -func (f F) Format(s fmt.State, c rune) { - fmt.Fprintf(s, "F(%d)", int(f)) -} - -var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -var gosyntax = []test{ - {nil, `nil`}, - {"", `""`}, - {"a", `"a"`}, - {1, "int(1)"}, - {1.0, "float64(1)"}, - {[]int(nil), "[]int(nil)"}, - {[0]int{}, "[0]int{}"}, - {complex(1, 0), "(1+0i)"}, - //{make(chan int), "(chan int)(0x1234)"}, - {unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("unsafe.Pointer(0x%02x)", uintptr(unsafe.Pointer(&long)))}, - {func(int) {}, "func(int) {...}"}, - {map[int]int{1: 1}, "map[int]int{1:1}"}, - {int32(1), "int32(1)"}, - {io.EOF, `&errors.errorString{s:"EOF"}`}, - {[]string{"a"}, `[]string{"a"}`}, - { - []string{long}, - `[]string{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"}`, - }, - {F(5), "pretty.F(5)"}, - { - SA{&T{1, 2}, T{3, 4}}, - `pretty.SA{ - t: &pretty.T{x:1, y:2}, - v: pretty.T{x:3, y:4}, -}`, - }, - { - map[int][]byte{1: {}}, - `map[int][]uint8{ - 1: {}, -}`, - }, - { - map[int]T{1: {}}, - `map[int]pretty.T{ - 1: {}, -}`, - }, - { - long, - `"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"`, - }, - { - LongStructTypeName{ - longFieldName: LongStructTypeName{}, - otherLongFieldName: long, - }, - `pretty.LongStructTypeName{ - longFieldName: pretty.LongStructTypeName{}, - otherLongFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", -}`, - }, - { - &LongStructTypeName{ - longFieldName: &LongStructTypeName{}, - otherLongFieldName: (*LongStructTypeName)(nil), - }, - `&pretty.LongStructTypeName{ - longFieldName: &pretty.LongStructTypeName{}, - otherLongFieldName: (*pretty.LongStructTypeName)(nil), -}`, - }, - { - []LongStructTypeName{ - {nil, nil}, - {3, 3}, - {long, nil}, - }, - `[]pretty.LongStructTypeName{ - {}, - { - longFieldName: int(3), - otherLongFieldName: int(3), - }, - { - longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", - otherLongFieldName: nil, - }, -}`, - }, - { - []interface{}{ - LongStructTypeName{nil, nil}, - []byte{1, 2, 3}, - T{3, 4}, - LongStructTypeName{long, nil}, - }, - `[]interface {}{ - pretty.LongStructTypeName{}, - []uint8{0x1, 0x2, 0x3}, - pretty.T{x:3, y:4}, - pretty.LongStructTypeName{ - longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", - otherLongFieldName: nil, - }, -}`, - }, -} - -func TestGoSyntax(t *testing.T) { - for _, tt := range gosyntax { - s := fmt.Sprintf("%# v", Formatter(tt.v)) - if tt.s != s { - t.Errorf("expected %q", tt.s) - t.Errorf("got %q", s) - t.Errorf("expraw\n%s", tt.s) - t.Errorf("gotraw\n%s", s) - } - } -} - -type I struct { - i int - R interface{} -} - -func (i *I) I() *I { return i.R.(*I) } - -func TestCycle(t *testing.T) { - type A struct{ *A } - v := &A{} - v.A = v - - // panics from stack overflow without cycle detection - t.Logf("Example cycle:\n%# v", Formatter(v)) - - p := &A{} - s := fmt.Sprintf("%# v", Formatter([]*A{p, p})) - if strings.Contains(s, "CYCLIC") { - t.Errorf("Repeated address detected as cyclic reference:\n%s", s) - } - - type R struct { - i int - *R - } - r := &R{ - i: 1, - R: &R{ - i: 2, - R: &R{ - i: 3, - }, - }, - } - r.R.R.R = r - t.Logf("Example longer cycle:\n%# v", Formatter(r)) - - r = &R{ - i: 1, - R: &R{ - i: 2, - R: &R{ - i: 3, - R: &R{ - i: 4, - R: &R{ - i: 5, - R: &R{ - i: 6, - R: &R{ - i: 7, - R: &R{ - i: 8, - R: &R{ - i: 9, - R: &R{ - i: 10, - R: &R{ - i: 11, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - // here be pirates - r.R.R.R.R.R.R.R.R.R.R.R = r - t.Logf("Example very long cycle:\n%# v", Formatter(r)) - - i := &I{ - i: 1, - R: &I{ - i: 2, - R: &I{ - i: 3, - R: &I{ - i: 4, - R: &I{ - i: 5, - R: &I{ - i: 6, - R: &I{ - i: 7, - R: &I{ - i: 8, - R: &I{ - i: 9, - R: &I{ - i: 10, - R: &I{ - i: 11, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - iv := i.I().I().I().I().I().I().I().I().I().I() - *iv = *i - t.Logf("Example long interface cycle:\n%# v", Formatter(i)) -} diff --git a/vendor/github.com/kr/pretty/pretty.go b/vendor/github.com/kr/pretty/pretty.go index d3df8686ce8..49423ec7f54 100644 --- a/vendor/github.com/kr/pretty/pretty.go +++ b/vendor/github.com/kr/pretty/pretty.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "log" + "reflect" ) // Errorf is a convenience wrapper for fmt.Errorf. @@ -81,6 +82,15 @@ func Println(a ...interface{}) (n int, errno error) { return fmt.Println(wrap(a, true)...) } +// Sprint is a convenience wrapper for fmt.Sprintf. +// +// Calling Sprint(x, y) is equivalent to +// fmt.Sprint(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Sprint(a ...interface{}) string { + return fmt.Sprint(wrap(a, true)...) +} + // Sprintf is a convenience wrapper for fmt.Sprintf. // // Calling Sprintf(f, x, y) is equivalent to @@ -92,7 +102,7 @@ func Sprintf(format string, a ...interface{}) string { func wrap(a []interface{}, force bool) []interface{} { w := make([]interface{}, len(a)) for i, x := range a { - w[i] = formatter{x: x, force: force} + w[i] = formatter{v: reflect.ValueOf(x), force: force} } return w } diff --git a/vendor/github.com/kr/s3/Readme b/vendor/github.com/kr/s3/Readme deleted file mode 100644 index 93b53595271..00000000000 --- a/vendor/github.com/kr/s3/Readme +++ /dev/null @@ -1,4 +0,0 @@ -Package s3 signs HTTP requests for use with Amazon’s S3 API. - -Documentation: -http://godoc.org/github.com/kr/s3 diff --git a/vendor/github.com/kr/s3/s3util/Readme b/vendor/github.com/kr/s3/s3util/Readme deleted file mode 100644 index 97c4a9de3d3..00000000000 --- a/vendor/github.com/kr/s3/s3util/Readme +++ /dev/null @@ -1,4 +0,0 @@ -Package s3util provides streaming transfers to and from Amazon S3. - -Full documentation: -http://godoc.org/github.com/kr/s3/s3util diff --git a/vendor/github.com/kr/s3/s3util/config.go b/vendor/github.com/kr/s3/s3util/config.go deleted file mode 100644 index aeae14ac4e7..00000000000 --- a/vendor/github.com/kr/s3/s3util/config.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package s3util provides streaming transfers to and from Amazon S3. -// -// To use it, open or create an S3 object, read or write data, -// and close the object. -// -// You must assign valid credentials to DefaultConfig.Keys before using -// DefaultConfig. Be sure to close an io.WriteCloser returned by this package, -// to flush buffers and complete the multipart upload process. -package s3util - -// TODO(kr): parse error responses; return structured data - -import ( - "github.com/kr/s3" - "net/http" -) - -var DefaultConfig = &Config{ - Service: s3.DefaultService, - Keys: new(s3.Keys), -} - -type Config struct { - *s3.Service - *s3.Keys - *http.Client // if nil, uses http.DefaultClient -} diff --git a/vendor/github.com/kr/s3/s3util/error.go b/vendor/github.com/kr/s3/s3util/error.go deleted file mode 100644 index 8f512f46811..00000000000 --- a/vendor/github.com/kr/s3/s3util/error.go +++ /dev/null @@ -1,29 +0,0 @@ -package s3util - -import ( - "bytes" - "fmt" - "io" - "net/http" -) - -type respError struct { - r *http.Response - b bytes.Buffer -} - -func newRespError(r *http.Response) *respError { - e := new(respError) - e.r = r - io.Copy(&e.b, r.Body) - r.Body.Close() - return e -} - -func (e *respError) Error() string { - return fmt.Sprintf( - "unwanted http status %d: %q", - e.r.StatusCode, - e.b.String(), - ) -} diff --git a/vendor/github.com/kr/s3/s3util/open.go b/vendor/github.com/kr/s3/s3util/open.go deleted file mode 100644 index 3f6ae9c5d83..00000000000 --- a/vendor/github.com/kr/s3/s3util/open.go +++ /dev/null @@ -1,33 +0,0 @@ -package s3util - -import ( - "io" - "net/http" - "time" -) - -// Open requests the S3 object at url. An HTTP status other than 200 is -// considered an error. -// -// If c is nil, Open uses DefaultConfig. -func Open(url string, c *Config) (io.ReadCloser, error) { - if c == nil { - c = DefaultConfig - } - // TODO(kr): maybe parallel range fetching - r, _ := http.NewRequest("GET", url, nil) - r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - c.Sign(r, *c.Keys) - client := c.Client - if client == nil { - client = http.DefaultClient - } - resp, err := client.Do(r) - if err != nil { - return nil, err - } - if resp.StatusCode != 200 { - return nil, newRespError(resp) - } - return resp.Body, nil -} diff --git a/vendor/github.com/kr/s3/s3util/readdir.go b/vendor/github.com/kr/s3/s3util/readdir.go deleted file mode 100644 index d14d6002a34..00000000000 --- a/vendor/github.com/kr/s3/s3util/readdir.go +++ /dev/null @@ -1,208 +0,0 @@ -package s3util - -import ( - "bytes" - "encoding/xml" - "errors" - "io" - "net/http" - "net/url" - "os" - "strconv" - "strings" - "time" -) - -// File represents an S3 object or directory. -type File struct { - url string - prefix string - config *Config - result *listObjectsResult -} - -type fileInfo struct { - name string - size int64 - dir bool - modTime time.Time - sys *Stat -} - -// Stat contains information about an S3 object or directory. -// It is the "underlying data source" returned by method Sys -// for each FileInfo produced by this package. -// fi.Sys().(*s3util.Stat) -// For the meaning of these fields, see -// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html. -type Stat struct { - Key string - LastModified string - ETag string // ETag value, without double quotes. - Size string - StorageClass string - OwnerID string `xml:"Owner>ID"` - OwnerName string `xml:"Owner>DisplayName"` -} - -type listObjectsResult struct { - IsTruncated bool - Contents []Stat - Directories []string `xml:"CommonPrefixes>Prefix"` // Suffix "/" trimmed -} - -func (f *fileInfo) Name() string { return f.name } -func (f *fileInfo) Size() int64 { return f.size } -func (f *fileInfo) Mode() os.FileMode { - if f.dir { - return 0755 | os.ModeDir - } - return 0644 -} -func (f *fileInfo) ModTime() time.Time { - if f.modTime.IsZero() && f.sys != nil { - // we return the zero value if a parse error ever happens. - f.modTime, _ = time.Parse(time.RFC3339Nano, f.sys.LastModified) - } - return f.modTime -} -func (f *fileInfo) IsDir() bool { return f.dir } -func (f *fileInfo) Sys() interface{} { return f.sys } - -// NewFile returns a new File with the given URL and config. -// -// Set rawurl to a directory on S3, such as -// https://mybucket.s3.amazonaws.com/myfolder. -// The URL cannot have query parameters or a fragment. -// If c is nil, DefaultConfig will be used. -func NewFile(rawurl string, c *Config) (*File, error) { - u, err := url.Parse(rawurl) - if err != nil { - return nil, err - } - if u.RawQuery != "" { - return nil, errors.New("url cannot have raw query parameters.") - } - if u.Fragment != "" { - return nil, errors.New("url cannot have a fragment.") - } - - prefix := strings.TrimLeft(u.Path, "/") - if prefix != "" && !strings.HasSuffix(prefix, "/") { - prefix += "/" - } - u.Path = "" - return &File{u.String(), prefix, c, nil}, nil -} - -// Readdir requests a list of entries in the S3 directory -// represented by f and returns a slice of up to n FileInfo -// values, in alphabetical order. Subsequent calls -// on the same File will yield further FileInfos. -// Only direct children are returned, not deeper descendants. -func (f *File) Readdir(n int) ([]os.FileInfo, error) { - if f.result != nil && !f.result.IsTruncated { - return make([]os.FileInfo, 0), io.EOF - } - - reader, err := f.sendRequest(n) - if err != nil { - return nil, err - } - defer reader.Close() - - return f.parseResponse(reader) -} - -func (f *File) sendRequest(count int) (io.ReadCloser, error) { - c := f.config - if c == nil { - c = DefaultConfig - } - var buf bytes.Buffer - buf.WriteString(f.url) - buf.WriteString("?delimiter=%2F") - if f.prefix != "" { - buf.WriteString("&prefix=") - buf.WriteString(url.QueryEscape(f.prefix)) - } - if count > 0 { - buf.WriteString("&max-keys=") - buf.WriteString(strconv.Itoa(count)) - } - if f.result != nil && f.result.IsTruncated { - var lastDir, lastKey, marker string - if len(f.result.Directories) > 0 { - lastDir = f.result.Directories[len(f.result.Directories)-1] - } - if len(f.result.Contents) > 0 { - lastKey = f.result.Contents[len(f.result.Contents)-1].Key - } - - if lastKey > lastDir { - marker = lastKey - } else { - marker = lastDir - } - - if marker != "" { - buf.WriteString("&marker=") - buf.WriteString(url.QueryEscape(marker)) - } - } - u := buf.String() - r, _ := http.NewRequest("GET", u, nil) - r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - c.Sign(r, *c.Keys) - resp, err := http.DefaultClient.Do(r) - if err != nil { - return nil, err - } - if resp.StatusCode != 200 { - return nil, newRespError(resp) - } - return resp.Body, nil -} - -func (f *File) parseResponse(reader io.Reader) ([]os.FileInfo, error) { - decoder := xml.NewDecoder(reader) - result := listObjectsResult{} - var err error - err = decoder.Decode(&result) - if err != nil { - return nil, err - } - - infos := make([]os.FileInfo, len(result.Contents)+len(result.Directories)) - var size int64 - var name string - var is_dir bool - for i, content := range result.Contents { - c := content - c.ETag = strings.Trim(c.ETag, `"`) - size, _ = strconv.ParseInt(c.Size, 10, 0) - if size == 0 && strings.HasSuffix(c.Key, "/") { - name = strings.TrimRight(c.Key, "/") - is_dir = true - } else { - name = c.Key - is_dir = false - } - infos[i] = &fileInfo{ - name: name, - size: size, - dir: is_dir, - sys: &c, - } - } - for i, dir := range result.Directories { - infos[len(result.Contents)+i] = &fileInfo{ - name: strings.TrimRight(dir, "/"), - size: 0, - dir: true, - } - } - f.result = &result - - return infos, nil -} diff --git a/vendor/github.com/kr/s3/s3util/uploader.go b/vendor/github.com/kr/s3/s3util/uploader.go deleted file mode 100644 index 1a21511bd29..00000000000 --- a/vendor/github.com/kr/s3/s3util/uploader.go +++ /dev/null @@ -1,267 +0,0 @@ -package s3util - -import ( - "bytes" - "encoding/xml" - "github.com/kr/s3" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "sync" - "syscall" - "time" -) - -// defined by amazon -const ( - minPartSize = 5 * 1024 * 1024 - maxPartSize = 1<<31 - 1 // for 32-bit use; amz max is 5GiB - maxObjSize = 5 * 1024 * 1024 * 1024 * 1024 - maxNPart = 10000 -) - -const ( - concurrency = 5 - nTry = 2 -) - -type part struct { - r io.ReadSeeker - len int64 - - // read by xml encoder - PartNumber int - ETag string -} - -type uploader struct { - s3 s3.Service - keys s3.Keys - url string - client *http.Client - UploadId string // written by xml decoder - - bufsz int64 - buf []byte - off int - ch chan *part - part int - closed bool - err error - wg sync.WaitGroup - - xml struct { - XMLName string `xml:"CompleteMultipartUpload"` - Part []*part - } -} - -// Create creates an S3 object at url and sends multipart upload requests as -// data is written. -// -// If h is not nil, each of its entries is added to the HTTP request header. -// If c is nil, Create uses DefaultConfig. -func Create(url string, h http.Header, c *Config) (io.WriteCloser, error) { - if c == nil { - c = DefaultConfig - } - return newUploader(url, h, c) -} - -// Sends an S3 multipart upload initiation request. -// See http://docs.amazonwebservices.com/AmazonS3/latest/dev/mpuoverview.html. -// This initial request returns an UploadId that we use to identify -// subsequent PUT requests. -func newUploader(url string, h http.Header, c *Config) (u *uploader, err error) { - u = new(uploader) - u.s3 = *c.Service - u.url = url - u.keys = *c.Keys - u.client = c.Client - if u.client == nil { - u.client = http.DefaultClient - } - u.bufsz = minPartSize - r, err := http.NewRequest("POST", url+"?uploads", nil) - if err != nil { - return nil, err - } - r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - for k := range h { - for _, v := range h[k] { - r.Header.Add(k, v) - } - } - u.s3.Sign(r, u.keys) - resp, err := u.client.Do(r) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return nil, newRespError(resp) - } - err = xml.NewDecoder(resp.Body).Decode(u) - if err != nil { - return nil, err - } - u.ch = make(chan *part) - for i := 0; i < concurrency; i++ { - go u.worker() - } - return u, nil -} - -func (u *uploader) Write(p []byte) (n int, err error) { - if u.closed { - return 0, syscall.EINVAL - } - if u.err != nil { - return 0, u.err - } - for n < len(p) { - if cap(u.buf) == 0 { - u.buf = make([]byte, int(u.bufsz)) - // Increase part size (1.001x). - // This lets us reach the max object size (5TiB) while - // still doing minimal buffering for small objects. - u.bufsz = min(u.bufsz+u.bufsz/1000, maxPartSize) - } - r := copy(u.buf[u.off:], p[n:]) - u.off += r - n += r - if u.off == len(u.buf) { - u.flush() - } - } - return n, nil -} - -func (u *uploader) flush() { - u.wg.Add(1) - u.part++ - p := &part{bytes.NewReader(u.buf[:u.off]), int64(u.off), u.part, ""} - u.xml.Part = append(u.xml.Part, p) - u.ch <- p - u.buf, u.off = nil, 0 -} - -func (u *uploader) worker() { - for p := range u.ch { - u.retryUploadPart(p) - } -} - -// Calls putPart up to nTry times to recover from transient errors. -func (u *uploader) retryUploadPart(p *part) { - defer u.wg.Done() - defer func() { p.r = nil }() // free the large buffer - var err error - for i := 0; i < nTry; i++ { - p.r.Seek(0, 0) - err = u.putPart(p) - if err == nil { - return - } - } - u.err = err -} - -// Uploads part p, reading its contents from p.r. -// Stores the ETag in p.ETag. -func (u *uploader) putPart(p *part) error { - v := url.Values{} - v.Set("partNumber", strconv.Itoa(p.PartNumber)) - v.Set("uploadId", u.UploadId) - req, err := http.NewRequest("PUT", u.url+"?"+v.Encode(), p.r) - if err != nil { - return err - } - req.ContentLength = p.len - req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - u.s3.Sign(req, u.keys) - resp, err := u.client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return newRespError(resp) - } - s := resp.Header.Get("etag") // includes quote chars for some reason - if len(s) < 2 { - return fmt.Errorf("received invalid etag %q", s) - } - p.ETag = s[1 : len(s)-1] - return nil -} - -func (u *uploader) Close() error { - if u.closed { - return syscall.EINVAL - } - if cap(u.buf) > 0 { - u.flush() - } - u.wg.Wait() - close(u.ch) - u.closed = true - if u.err != nil { - u.abort() - return u.err - } - - body, err := xml.Marshal(u.xml) - if err != nil { - return err - } - b := bytes.NewBuffer(body) - v := url.Values{} - v.Set("uploadId", u.UploadId) - req, err := http.NewRequest("POST", u.url+"?"+v.Encode(), b) - if err != nil { - return err - } - req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - u.s3.Sign(req, u.keys) - resp, err := u.client.Do(req) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return newRespError(resp) - } - resp.Body.Close() - return nil -} - -func (u *uploader) abort() { - // TODO(kr): devise a reasonable way to report an error here in addition - // to the error that caused the abort. - v := url.Values{} - v.Set("uploadId", u.UploadId) - s := u.url + "?" + v.Encode() - req, err := http.NewRequest("DELETE", s, nil) - if err != nil { - return - } - req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) - u.s3.Sign(req, u.keys) - resp, err := u.client.Do(req) - if err != nil { - return - } - defer resp.Body.Close() - if resp.StatusCode != 200 { - return - } -} - -func min(a, b int64) int64 { - if a < b { - return a - } - return b -} diff --git a/vendor/github.com/kr/s3/sign.go b/vendor/github.com/kr/s3/sign.go deleted file mode 100644 index 0ff2d483bb4..00000000000 --- a/vendor/github.com/kr/s3/sign.go +++ /dev/null @@ -1,200 +0,0 @@ -// Package s3 signs HTTP requests for Amazon S3 and compatible services. -package s3 - -// See -// http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html. - -import ( - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "io" - "net/http" - "sort" - "strings" -) - -var signParams = map[string]bool{ - "acl": true, - "delete": true, - "lifecycle": true, - "location": true, - "logging": true, - "notification": true, - "partNumber": true, - "policy": true, - "requestPayment": true, - "response-cache-control": true, - "response-content-disposition": true, - "response-content-encoding": true, - "response-content-language": true, - "response-content-type": true, - "response-expires": true, - "restore": true, - "torrent": true, - "uploadId": true, - "uploads": true, - "versionId": true, - "versioning": true, - "versions": true, - "website": true, -} - -// Keys holds a set of Amazon Security Credentials. -type Keys struct { - AccessKey string - SecretKey string - - // SecurityToken is used for temporary security credentials. - // If set, it will be added to header field X-Amz-Security-Token - // before signing a request. - SecurityToken string - // See http://docs.aws.amazon.com/AmazonS3/latest/dev/MakingRequests.html#TypesofSecurityCredentials -} - -// IdentityBucket returns subdomain. -// It is designed to be used with S3-compatible services that -// treat the entire subdomain as the bucket name, for example -// storage.io. -func IdentityBucket(subdomain string) string { - return subdomain -} - -// AmazonBucket returns everything up to the last '.' in subdomain. -// It is designed to be used with the Amazon service. -// "johnsmith.s3" becomes "johnsmith" -// "johnsmith.s3-eu-west-1" becomes "johnsmith" -// "www.example.com.s3" becomes "www.example.com" -func AmazonBucket(subdomain string) string { - if i := strings.LastIndex(subdomain, "."); i != -1 { - return subdomain[:i] - } - return "" -} - -// DefaultService is the default Service used by Sign. -var DefaultService = &Service{Domain: "amazonaws.com"} - -// Sign signs an HTTP request with the given S3 keys. -// -// This function is a wrapper around DefaultService.Sign. -func Sign(r *http.Request, k Keys) { - DefaultService.Sign(r, k) -} - -// Service represents an S3-compatible service. -type Service struct { - // Domain is the service's root domain. It is used to extract - // the subdomain from an http.Request before passing the - // subdomain to Bucket. - Domain string - - // Bucket derives the bucket name from a subdomain. - // If nil, AmazonBucket is used. - Bucket func(subdomain string) string -} - -// Sign signs an HTTP request with the given S3 keys for use on service s. -func (s *Service) Sign(r *http.Request, k Keys) { - if k.SecurityToken != "" { - r.Header.Set("X-Amz-Security-Token", k.SecurityToken) - } - h := hmac.New(sha1.New, []byte(k.SecretKey)) - s.writeSigData(h, r) - sig := make([]byte, base64.StdEncoding.EncodedLen(h.Size())) - base64.StdEncoding.Encode(sig, h.Sum(nil)) - r.Header.Set("Authorization", "AWS "+k.AccessKey+":"+string(sig)) -} - -func (s *Service) writeSigData(w io.Writer, r *http.Request) { - w.Write([]byte(r.Method)) - w.Write([]byte{'\n'}) - w.Write([]byte(r.Header.Get("content-md5"))) - w.Write([]byte{'\n'}) - w.Write([]byte(r.Header.Get("content-type"))) - w.Write([]byte{'\n'}) - if _, ok := r.Header["X-Amz-Date"]; !ok { - w.Write([]byte(r.Header.Get("date"))) - } - w.Write([]byte{'\n'}) - writeAmzHeaders(w, r) - s.writeResource(w, r) -} - -func (s *Service) writeResource(w io.Writer, r *http.Request) { - s.writeVhostBucket(w, strings.ToLower(r.Host)) - path := r.URL.RequestURI() - if r.URL.RawQuery != "" { - path = path[:len(path)-len(r.URL.RawQuery)-1] - } - w.Write([]byte(path)) - s.writeSubResource(w, r) -} - -func (s *Service) writeVhostBucket(w io.Writer, host string) { - if i := strings.Index(host, ":"); i != -1 { - host = host[:i] - } - - if host == s.Domain { - // no vhost - do nothing - } else if strings.HasSuffix(host, "."+s.Domain) { - // vhost - bucket may be in prefix - b := s.Bucket - if b == nil { - b = AmazonBucket - } - bucket := b(host[:len(host)-len(s.Domain)-1]) - - if bucket != "" { - w.Write([]byte{'/'}) - w.Write([]byte(bucket)) - } - } else { - // cname - bucket is host - w.Write([]byte{'/'}) - w.Write([]byte(host)) - } -} - -func (s *Service) writeSubResource(w io.Writer, r *http.Request) { - var a []string - for k, vs := range r.URL.Query() { - if signParams[k] { - for _, v := range vs { - if v == "" { - a = append(a, k) - } else { - a = append(a, k+"="+v) - } - } - } - } - sort.Strings(a) - var p byte = '?' - for _, s := range a { - w.Write([]byte{p}) - w.Write([]byte(s)) - p = '&' - } -} - -func writeAmzHeaders(w io.Writer, r *http.Request) { - var keys []string - for k, _ := range r.Header { - if strings.HasPrefix(strings.ToLower(k), "x-amz-") { - keys = append(keys, k) - } - } - - sort.Strings(keys) - var a []string - for _, k := range keys { - v := r.Header[k] - a = append(a, strings.ToLower(k)+":"+strings.Join(v, ",")) - } - for _, h := range a { - w.Write([]byte(h)) - w.Write([]byte{'\n'}) - } -} diff --git a/vendor/github.com/kr/text/Readme b/vendor/github.com/kr/text/Readme deleted file mode 100644 index 7e6e7c0687b..00000000000 --- a/vendor/github.com/kr/text/Readme +++ /dev/null @@ -1,3 +0,0 @@ -This is a Go package for manipulating paragraphs of text. - -See http://go.pkgdoc.org/github.com/kr/text for full documentation. diff --git a/vendor/github.com/kr/text/colwriter/Readme b/vendor/github.com/kr/text/colwriter/Readme deleted file mode 100644 index 1c1f4e68393..00000000000 --- a/vendor/github.com/kr/text/colwriter/Readme +++ /dev/null @@ -1,5 +0,0 @@ -Package colwriter provides a write filter that formats -input lines in multiple columns. - -The package is a straightforward translation from -/src/cmd/draw/mc.c in Plan 9 from User Space. diff --git a/vendor/github.com/kr/text/colwriter/column.go b/vendor/github.com/kr/text/colwriter/column.go deleted file mode 100644 index 7302ce9f7a8..00000000000 --- a/vendor/github.com/kr/text/colwriter/column.go +++ /dev/null @@ -1,147 +0,0 @@ -// Package colwriter provides a write filter that formats -// input lines in multiple columns. -// -// The package is a straightforward translation from -// /src/cmd/draw/mc.c in Plan 9 from User Space. -package colwriter - -import ( - "bytes" - "io" - "unicode/utf8" -) - -const ( - tab = 4 -) - -const ( - // Print each input line ending in a colon ':' separately. - BreakOnColon uint = 1 << iota -) - -// A Writer is a filter that arranges input lines in as many columns as will -// fit in its width. Tab '\t' chars in the input are translated to sequences -// of spaces ending at multiples of 4 positions. -// -// If BreakOnColon is set, each input line ending in a colon ':' is written -// separately. -// -// The Writer assumes that all Unicode code points have the same width; this -// may not be true in some fonts. -type Writer struct { - w io.Writer - buf []byte - width int - flag uint -} - -// NewWriter allocates and initializes a new Writer writing to w. -// Parameter width controls the total number of characters on each line -// across all columns. -func NewWriter(w io.Writer, width int, flag uint) *Writer { - return &Writer{ - w: w, - width: width, - flag: flag, - } -} - -// Write writes p to the writer w. The only errors returned are ones -// encountered while writing to the underlying output stream. -func (w *Writer) Write(p []byte) (n int, err error) { - var linelen int - var lastWasColon bool - for i, c := range p { - w.buf = append(w.buf, c) - linelen++ - if c == '\t' { - w.buf[len(w.buf)-1] = ' ' - for linelen%tab != 0 { - w.buf = append(w.buf, ' ') - linelen++ - } - } - if w.flag&BreakOnColon != 0 && c == ':' { - lastWasColon = true - } else if lastWasColon { - if c == '\n' { - pos := bytes.LastIndex(w.buf[:len(w.buf)-1], []byte{'\n'}) - if pos < 0 { - pos = 0 - } - line := w.buf[pos:] - w.buf = w.buf[:pos] - if err = w.columnate(); err != nil { - if len(line) < i { - return i - len(line), err - } - return 0, err - } - if n, err := w.w.Write(line); err != nil { - if r := len(line) - n; r < i { - return i - r, err - } - return 0, err - } - } - lastWasColon = false - } - if c == '\n' { - linelen = 0 - } - } - return len(p), nil -} - -// Flush should be called after the last call to Write to ensure that any data -// buffered in the Writer is written to output. -func (w *Writer) Flush() error { - return w.columnate() -} - -func (w *Writer) columnate() error { - words := bytes.Split(w.buf, []byte{'\n'}) - w.buf = nil - if len(words[len(words)-1]) == 0 { - words = words[:len(words)-1] - } - maxwidth := 0 - for _, wd := range words { - if n := utf8.RuneCount(wd); n > maxwidth { - maxwidth = n - } - } - maxwidth++ // space char - wordsPerLine := w.width / maxwidth - if wordsPerLine <= 0 { - wordsPerLine = 1 - } - nlines := (len(words) + wordsPerLine - 1) / wordsPerLine - for i := 0; i < nlines; i++ { - col := 0 - endcol := 0 - for j := i; j < len(words); j += nlines { - endcol += maxwidth - _, err := w.w.Write(words[j]) - if err != nil { - return err - } - col += utf8.RuneCount(words[j]) - if j+nlines < len(words) { - for col < endcol { - _, err := w.w.Write([]byte{' '}) - if err != nil { - return err - } - col++ - } - } - } - _, err := w.w.Write([]byte{'\n'}) - if err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/kr/text/colwriter/column_test.go b/vendor/github.com/kr/text/colwriter/column_test.go deleted file mode 100644 index ce388f5a260..00000000000 --- a/vendor/github.com/kr/text/colwriter/column_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package colwriter - -import ( - "bytes" - "testing" -) - -var src = ` -.git -.gitignore -.godir -Procfile: -README.md -api.go -apps.go -auth.go -darwin.go -data.go -dyno.go: -env.go -git.go -help.go -hkdist -linux.go -ls.go -main.go -plugin.go -run.go -scale.go -ssh.go -tail.go -term -unix.go -update.go -version.go -windows.go -`[1:] - -var tests = []struct { - wid int - flag uint - src string - want string -}{ - {80, 0, "", ""}, - {80, 0, src, ` -.git README.md darwin.go git.go ls.go scale.go unix.go -.gitignore api.go data.go help.go main.go ssh.go update.go -.godir apps.go dyno.go: hkdist plugin.go tail.go version.go -Procfile: auth.go env.go linux.go run.go term windows.go -`[1:]}, - {80, BreakOnColon, src, ` -.git .gitignore .godir - -Procfile: -README.md api.go apps.go auth.go darwin.go data.go - -dyno.go: -env.go hkdist main.go scale.go term version.go -git.go linux.go plugin.go ssh.go unix.go windows.go -help.go ls.go run.go tail.go update.go -`[1:]}, - {20, 0, ` -Hello -Γειά σου -안녕 -今日は -`[1:], ` -Hello 안녕 -Γειά σου 今日は -`[1:]}, -} - -func TestWriter(t *testing.T) { - for _, test := range tests { - b := new(bytes.Buffer) - w := NewWriter(b, test.wid, test.flag) - if _, err := w.Write([]byte(test.src)); err != nil { - t.Error(err) - } - if err := w.Flush(); err != nil { - t.Error(err) - } - if g := b.String(); test.want != g { - t.Log("\n" + test.want) - t.Log("\n" + g) - t.Errorf("%q != %q", test.want, g) - } - } -} diff --git a/vendor/github.com/kr/text/indent_test.go b/vendor/github.com/kr/text/indent_test.go deleted file mode 100644 index 5c723eee855..00000000000 --- a/vendor/github.com/kr/text/indent_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package text - -import ( - "bytes" - "testing" -) - -type T struct { - inp, exp, pre string -} - -var tests = []T{ - { - "The quick brown fox\njumps over the lazy\ndog.\nBut not quickly.\n", - "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\nxxxBut not quickly.\n", - "xxx", - }, - { - "The quick brown fox\njumps over the lazy\ndog.\n\nBut not quickly.", - "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\n\nxxxBut not quickly.", - "xxx", - }, -} - -func TestIndent(t *testing.T) { - for _, test := range tests { - got := Indent(test.inp, test.pre) - if got != test.exp { - t.Errorf("mismatch %q != %q", got, test.exp) - } - } -} - -type IndentWriterTest struct { - inp, exp string - pre []string -} - -var ts = []IndentWriterTest{ - { - ` -The quick brown fox -jumps over the lazy -dog. -But not quickly. -`[1:], - ` -xxxThe quick brown fox -xxxjumps over the lazy -xxxdog. -xxxBut not quickly. -`[1:], - []string{"xxx"}, - }, - { - ` -The quick brown fox -jumps over the lazy -dog. -But not quickly. -`[1:], - ` -xxaThe quick brown fox -xxxjumps over the lazy -xxxdog. -xxxBut not quickly. -`[1:], - []string{"xxa", "xxx"}, - }, - { - ` -The quick brown fox -jumps over the lazy -dog. -But not quickly. -`[1:], - ` -xxaThe quick brown fox -xxbjumps over the lazy -xxcdog. -xxxBut not quickly. -`[1:], - []string{"xxa", "xxb", "xxc", "xxx"}, - }, - { - ` -The quick brown fox -jumps over the lazy -dog. - -But not quickly.`[1:], - ` -xxaThe quick brown fox -xxxjumps over the lazy -xxxdog. -xxx -xxxBut not quickly.`[1:], - []string{"xxa", "xxx"}, - }, -} - -func TestIndentWriter(t *testing.T) { - for _, test := range ts { - b := new(bytes.Buffer) - pre := make([][]byte, len(test.pre)) - for i := range test.pre { - pre[i] = []byte(test.pre[i]) - } - w := NewIndentWriter(b, pre...) - if _, err := w.Write([]byte(test.inp)); err != nil { - t.Error(err) - } - if got := b.String(); got != test.exp { - t.Errorf("mismatch %q != %q", got, test.exp) - t.Log(got) - t.Log(test.exp) - } - } -} diff --git a/vendor/github.com/kr/text/mc/Readme b/vendor/github.com/kr/text/mc/Readme deleted file mode 100644 index 519ddc00a13..00000000000 --- a/vendor/github.com/kr/text/mc/Readme +++ /dev/null @@ -1,9 +0,0 @@ -Command mc prints in multiple columns. - - Usage: mc [-] [-N] [file...] - -Mc splits the input into as many columns as will fit in N -print positions. If the output is a tty, the default N is -the number of characters in a terminal line; otherwise the -default N is 80. Under option - each input line ending in -a colon ':' is printed separately. diff --git a/vendor/github.com/kr/text/mc/mc.go b/vendor/github.com/kr/text/mc/mc.go deleted file mode 100644 index 00169a30f16..00000000000 --- a/vendor/github.com/kr/text/mc/mc.go +++ /dev/null @@ -1,62 +0,0 @@ -// Command mc prints in multiple columns. -// -// Usage: mc [-] [-N] [file...] -// -// Mc splits the input into as many columns as will fit in N -// print positions. If the output is a tty, the default N is -// the number of characters in a terminal line; otherwise the -// default N is 80. Under option - each input line ending in -// a colon ':' is printed separately. -package main - -import ( - "github.com/kr/pty" - "github.com/kr/text/colwriter" - "io" - "log" - "os" - "strconv" -) - -func main() { - var width int - var flag uint - args := os.Args[1:] - for len(args) > 0 && len(args[0]) > 0 && args[0][0] == '-' { - if len(args[0]) > 1 { - width, _ = strconv.Atoi(args[0][1:]) - } else { - flag |= colwriter.BreakOnColon - } - args = args[1:] - } - if width < 1 { - _, width, _ = pty.Getsize(os.Stdout) - } - if width < 1 { - width = 80 - } - - w := colwriter.NewWriter(os.Stdout, width, flag) - if len(args) > 0 { - for _, s := range args { - if f, err := os.Open(s); err == nil { - copyin(w, f) - f.Close() - } else { - log.Println(err) - } - } - } else { - copyin(w, os.Stdin) - } -} - -func copyin(w *colwriter.Writer, r io.Reader) { - if _, err := io.Copy(w, r); err != nil { - log.Println(err) - } - if err := w.Flush(); err != nil { - log.Println(err) - } -} diff --git a/vendor/github.com/kr/text/wrap_test.go b/vendor/github.com/kr/text/wrap_test.go deleted file mode 100644 index 634b6e8ebb9..00000000000 --- a/vendor/github.com/kr/text/wrap_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package text - -import ( - "bytes" - "testing" -) - -var text = "The quick brown fox jumps over the lazy dog." - -func TestWrap(t *testing.T) { - exp := [][]string{ - {"The", "quick", "brown", "fox"}, - {"jumps", "over", "the", "lazy", "dog."}, - } - words := bytes.Split([]byte(text), sp) - got := WrapWords(words, 1, 24, defaultPenalty) - if len(exp) != len(got) { - t.Fail() - } - for i := range exp { - if len(exp[i]) != len(got[i]) { - t.Fail() - } - for j := range exp[i] { - if exp[i][j] != string(got[i][j]) { - t.Fatal(i, exp[i][j], got[i][j]) - } - } - } -} - -func TestWrapNarrow(t *testing.T) { - exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog." - if Wrap(text, 5) != exp { - t.Fail() - } -} - -func TestWrapOneLine(t *testing.T) { - exp := "The quick brown fox jumps over the lazy dog." - if Wrap(text, 500) != exp { - t.Fail() - } -} - -func TestWrapBug1(t *testing.T) { - cases := []struct { - limit int - text string - want string - }{ - {4, "aaaaa", "aaaaa"}, - {4, "a aaaaa", "a\naaaaa"}, - } - - for _, test := range cases { - got := Wrap(test.text, test.limit) - if got != test.want { - t.Errorf("Wrap(%q, %d) = %q want %q", test.text, test.limit, got, test.want) - } - } -} diff --git a/vendor/github.com/lib/pq/CONTRIBUTING.md b/vendor/github.com/lib/pq/CONTRIBUTING.md deleted file mode 100644 index 84c937f1561..00000000000 --- a/vendor/github.com/lib/pq/CONTRIBUTING.md +++ /dev/null @@ -1,29 +0,0 @@ -## Contributing to pq - -`pq` has a backlog of pull requests, but contributions are still very -much welcome. You can help with patch review, submitting bug reports, -or adding new functionality. There is no formal style guide, but -please conform to the style of existing code and general Go formatting -conventions when submitting patches. - -### Patch review - -Help review existing open pull requests by commenting on the code or -proposed functionality. - -### Bug reports - -We appreciate any bug reports, but especially ones with self-contained -(doesn't depend on code outside of pq), minimal (can't be simplified -further) test cases. It's especially helpful if you can submit a pull -request with just the failing test case (you'll probably want to -pattern it after the tests in -[conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). - -### New functionality - -There are a number of pending patches for new functionality, so -additional feature patches will take a while to merge. Still, patches -are generally reviewed based on usefulness and complexity in addition -to time-in-queue, so if you have a knockout idea, take a shot. Feel -free to open an issue discussion your proposed patch beforehand. diff --git a/vendor/github.com/lib/pq/README.md b/vendor/github.com/lib/pq/README.md deleted file mode 100644 index 781c89eea69..00000000000 --- a/vendor/github.com/lib/pq/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# pq - A pure Go postgres driver for Go's database/sql package - -[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://godoc.org/github.com/lib/pq) -[![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq) - -## Install - - go get github.com/lib/pq - -## Docs - -For detailed documentation and basic usage examples, please see the package -documentation at . - -## Tests - -`go test` is used for testing. A running PostgreSQL server is -required, with the ability to log in. The default database to connect -to test with is "pqgotest," but it can be overridden using environment -variables. - -Example: - - PGHOST=/run/postgresql go test github.com/lib/pq - -Optionally, a benchmark suite can be run as part of the tests: - - PGHOST=/run/postgresql go test -bench . - -## Features - -* SSL -* Handles bad connections for `database/sql` -* Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) -* Scan binary blobs correctly (i.e. `bytea`) -* Package for `hstore` support -* COPY FROM support -* pq.ParseURL for converting urls to connection strings for sql.Open. -* Many libpq compatible environment variables -* Unix socket support -* Notifications: `LISTEN`/`NOTIFY` -* pgpass support - -## Future / Things you can help with - -* Better COPY FROM / COPY TO (see discussion in #181) - -## Thank you (alphabetical) - -Some of these contributors are from the original library `bmizerany/pq.go` whose -code still exists in here. - -* Andy Balholm (andybalholm) -* Ben Berkert (benburkert) -* Benjamin Heatwole (bheatwole) -* Bill Mill (llimllib) -* Bjørn Madsen (aeons) -* Blake Gentry (bgentry) -* Brad Fitzpatrick (bradfitz) -* Charlie Melbye (cmelbye) -* Chris Bandy (cbandy) -* Chris Gilling (cgilling) -* Chris Walsh (cwds) -* Dan Sosedoff (sosedoff) -* Daniel Farina (fdr) -* Eric Chlebek (echlebek) -* Eric Garrido (minusnine) -* Eric Urban (hydrogen18) -* Everyone at The Go Team -* Evan Shaw (edsrzf) -* Ewan Chou (coocood) -* Fazal Majid (fazalmajid) -* Federico Romero (federomero) -* Fumin (fumin) -* Gary Burd (garyburd) -* Heroku (heroku) -* James Pozdena (jpoz) -* Jason McVetta (jmcvetta) -* Jeremy Jay (pbnjay) -* Joakim Sernbrant (serbaut) -* John Gallagher (jgallagher) -* Jonathan Rudenberg (titanous) -* Joël Stemmer (jstemmer) -* Kamil Kisiel (kisielk) -* Kelly Dunn (kellydunn) -* Keith Rarick (kr) -* Kir Shatrov (kirs) -* Lann Martin (lann) -* Maciek Sakrejda (uhoh-itsmaciek) -* Marc Brinkmann (mbr) -* Marko Tiikkaja (johto) -* Matt Newberry (MattNewberry) -* Matt Robenolt (mattrobenolt) -* Martin Olsen (martinolsen) -* Mike Lewis (mikelikespie) -* Nicolas Patry (Narsil) -* Oliver Tonnhofer (olt) -* Patrick Hayes (phayes) -* Paul Hammond (paulhammond) -* Ryan Smith (ryandotsmith) -* Samuel Stauffer (samuel) -* Timothée Peignier (cyberdelia) -* Travis Cline (tmc) -* TruongSinh Tran-Nguyen (truongsinh) -* Yaismel Miranda (ympons) -* notedit (notedit) diff --git a/vendor/github.com/lib/pq/certs/README b/vendor/github.com/lib/pq/certs/README deleted file mode 100644 index 24ab7b25698..00000000000 --- a/vendor/github.com/lib/pq/certs/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains certificates and private keys for testing some -SSL-related functionality in Travis. Do NOT use these certificates for -anything other than testing. diff --git a/vendor/github.com/lib/pq/certs/postgresql.crt b/vendor/github.com/lib/pq/certs/postgresql.crt deleted file mode 100644 index 6e6b4284a1f..00000000000 --- a/vendor/github.com/lib/pq/certs/postgresql.crt +++ /dev/null @@ -1,69 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 2 (0x2) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA - Validity - Not Before: Oct 11 15:10:11 2014 GMT - Not After : Oct 8 15:10:11 2024 GMT - Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pqgosslcert - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:e3:8c:06:9a:70:54:51:d1:34:34:83:39:cd:a2: - 59:0f:05:ed:8d:d8:0e:34:d0:92:f4:09:4d:ee:8c: - 78:55:49:24:f8:3c:e0:34:58:02:b2:e7:94:58:c1: - e8:e5:bb:d1:af:f6:54:c1:40:b1:90:70:79:0d:35: - 54:9c:8f:16:e9:c2:f0:92:e6:64:49:38:c1:76:f8: - 47:66:c4:5b:4a:b6:a9:43:ce:c8:be:6c:4d:2b:94: - 97:3c:55:bc:d1:d0:6e:b7:53:ae:89:5c:4b:6b:86: - 40:be:c1:ae:1e:64:ce:9c:ae:87:0a:69:e5:c8:21: - 12:be:ae:1d:f6:45:df:16:a7 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 9B:25:31:63:A2:D8:06:FF:CB:E3:E9:96:FF:0D:BA:DC:12:7D:04:CF - X509v3 Authority Key Identifier: - keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72 - - X509v3 Basic Constraints: - CA:FALSE - X509v3 Key Usage: - Digital Signature, Non Repudiation, Key Encipherment - Signature Algorithm: sha256WithRSAEncryption - 3e:f5:f8:0b:4e:11:bd:00:86:1f:ce:dc:97:02:98:91:11:f5: - 65:f6:f2:8a:b2:3e:47:92:05:69:28:c9:e9:b4:f7:cf:93:d1: - 2d:81:5d:00:3c:23:be:da:70:ea:59:e1:2c:d3:25:49:ae:a6: - 95:54:c1:10:df:23:e3:fe:d6:e4:76:c7:6b:73:ad:1b:34:7c: - e2:56:cc:c0:37:ae:c5:7a:11:20:6c:3d:05:0e:99:cd:22:6c: - cf:59:a1:da:28:d4:65:ba:7d:2f:2b:3d:69:6d:a6:c1:ae:57: - bf:56:64:13:79:f8:48:46:65:eb:81:67:28:0b:7b:de:47:10: - b3:80:3c:31:d1:58:94:01:51:4a:c7:c8:1a:01:a8:af:c4:cd: - bb:84:a5:d9:8b:b4:b9:a1:64:3e:95:d9:90:1d:d5:3f:67:cc: - 3b:ba:f5:b4:d1:33:77:ee:c2:d2:3e:7e:c5:66:6e:b7:35:4c: - 60:57:b0:b8:be:36:c8:f3:d3:95:8c:28:4a:c9:f7:27:a4:0d: - e5:96:99:eb:f5:c8:bd:f3:84:6d:ef:02:f9:8a:36:7d:6b:5f: - 36:68:37:41:d9:74:ae:c6:78:2e:44:86:a1:ad:43:ca:fb:b5: - 3e:ba:10:23:09:02:ac:62:d1:d0:83:c8:95:b9:e3:5e:30:ff: - 5b:2b:38:fa ------BEGIN CERTIFICATE----- -MIIDEzCCAfugAwIBAgIBAjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP -MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp -dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTEwMTFa -Fw0yNDEwMDgxNTEwMTFaMGQxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx -EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx -FDASBgNVBAMTC3BxZ29zc2xjZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0WAKy55RYwejl -u9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+bE0rlJc8VbzR -0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQABo1owWDAdBgNV -HQ4EFgQUmyUxY6LYBv/L4+mW/w263BJ9BM8wHwYDVR0jBBgwFoAUUpPtHnYKn2VP -3hlmwdUiQDXLoHIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEL -BQADggEBAD71+AtOEb0Ahh/O3JcCmJER9WX28oqyPkeSBWkoyem098+T0S2BXQA8 -I77acOpZ4SzTJUmuppVUwRDfI+P+1uR2x2tzrRs0fOJWzMA3rsV6ESBsPQUOmc0i -bM9Zodoo1GW6fS8rPWltpsGuV79WZBN5+EhGZeuBZygLe95HELOAPDHRWJQBUUrH -yBoBqK/EzbuEpdmLtLmhZD6V2ZAd1T9nzDu69bTRM3fuwtI+fsVmbrc1TGBXsLi+ -Nsjz05WMKErJ9yekDeWWmev1yL3zhG3vAvmKNn1rXzZoN0HZdK7GeC5EhqGtQ8r7 -tT66ECMJAqxi0dCDyJW5414w/1srOPo= ------END CERTIFICATE----- diff --git a/vendor/github.com/lib/pq/certs/postgresql.key b/vendor/github.com/lib/pq/certs/postgresql.key deleted file mode 100644 index eb8b20be96d..00000000000 --- a/vendor/github.com/lib/pq/certs/postgresql.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0 -WAKy55RYwejlu9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+ -bE0rlJc8VbzR0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQAB -AoGAM5dM6/kp9P700i8qjOgRPym96Zoh5nGfz/rIE5z/r36NBkdvIg8OVZfR96nH -b0b9TOMR5lsPp0sI9yivTWvX6qyvLJRWy2vvx17hXK9NxXUNTAm0PYZUTvCtcPeX -RnJpzQKNZQPkFzF0uXBc4CtPK2Vz0+FGvAelrhYAxnw1dIkCQQD+9qaW5QhXjsjb -Nl85CmXgxPmGROcgLQCO+omfrjf9UXrituU9Dz6auym5lDGEdMFnkzfr+wpasEy9 -mf5ZZOhDAkEA5HjXfVGaCtpydOt6hDon/uZsyssCK2lQ7NSuE3vP+sUsYMzIpEoy -t3VWXqKbo+g9KNDTP4WEliqp1aiSIylzzQJANPeqzihQnlgEdD4MdD4rwhFJwVIp -Le8Lcais1KaN7StzOwxB/XhgSibd2TbnPpw+3bSg5n5lvUdo+e62/31OHwJAU1jS -I+F09KikQIr28u3UUWT2IzTT4cpVv1AHAQyV3sG3YsjSGT0IK20eyP9BEBZU2WL0 -7aNjrvR5aHxKc5FXsQJABsFtyGpgI5X4xufkJZVZ+Mklz2n7iXa+XPatMAHFxAtb -EEMt60rngwMjXAzBSC6OYuYogRRAY3UCacNC5VhLYQ== ------END RSA PRIVATE KEY----- diff --git a/vendor/github.com/lib/pq/certs/root.crt b/vendor/github.com/lib/pq/certs/root.crt deleted file mode 100644 index aecf8f6213b..00000000000 --- a/vendor/github.com/lib/pq/certs/root.crt +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEAzCCAuugAwIBAgIJANmheROCdW1NMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV -BAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGExEjAQBgNVBAcTCUxhcyBWZWdhczEaMBgG -A1UEChMRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMTBXBxIENBMB4XDTE0MTAx -MTE1MDQyOVoXDTI0MTAwODE1MDQyOVowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgT -Bk5ldmFkYTESMBAGA1UEBxMJTGFzIFZlZ2FzMRowGAYDVQQKExFnaXRodWIuY29t -L2xpYi9wcTEOMAwGA1UEAxMFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCV4PxP7ShzWBzUCThcKk3qZtOLtHmszQVtbqhvgTpm1kTRtKBdVMu0 -pLAHQ3JgJCnAYgH0iZxVGoMP16T3irdgsdC48+nNTFM2T0cCdkfDURGIhSFN47cb -Pgy306BcDUD2q7ucW33+dlFSRuGVewocoh4BWM/vMtMvvWzdi4Ag/L/jhb+5wZxZ -sWymsadOVSDePEMKOvlCa3EdVwVFV40TVyDb+iWBUivDAYsS2a3KajuJrO6MbZiE -Sp2RCIkZS2zFmzWxVRi9ZhzIZhh7EVF9JAaNC3T52jhGUdlRq3YpBTMnd89iOh74 -6jWXG7wSuPj3haFzyNhmJ0ZUh+2Ynoh1AgMBAAGjgcMwgcAwHQYDVR0OBBYEFFKT -7R52Cp9lT94ZZsHVIkA1y6ByMIGQBgNVHSMEgYgwgYWAFFKT7R52Cp9lT94ZZsHV -IkA1y6ByoWKkYDBeMQswCQYDVQQGEwJVUzEPMA0GA1UECBMGTmV2YWRhMRIwEAYD -VQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYD -VQQDEwVwcSBDQYIJANmheROCdW1NMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF -BQADggEBAAEhCLWkqJNMI8b4gkbmj5fqQ/4+oO83bZ3w2Oqf6eZ8I8BC4f2NOyE6 -tRUlq5+aU7eqC1cOAvGjO+YHN/bF/DFpwLlzvUSXt+JP/pYcUjL7v+pIvwqec9hD -ndvM4iIbkD/H/OYQ3L+N3W+G1x7AcFIX+bGCb3PzYVQAjxreV6//wgKBosMGFbZo -HPxT9RPMun61SViF04H5TNs0derVn1+5eiiYENeAhJzQNyZoOOUuX1X/Inx9bEPh -C5vFBtSMgIytPgieRJVWAiMLYsfpIAStrHztRAbBs2DU01LmMgRvHdxgFEKinC/d -UHZZQDP+6pT+zADrGhQGXe4eThaO6f0= ------END CERTIFICATE----- diff --git a/vendor/github.com/lib/pq/certs/server.crt b/vendor/github.com/lib/pq/certs/server.crt deleted file mode 100644 index ddc995a6d61..00000000000 --- a/vendor/github.com/lib/pq/certs/server.crt +++ /dev/null @@ -1,81 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA - Validity - Not Before: Oct 11 15:05:15 2014 GMT - Not After : Oct 8 15:05:15 2024 GMT - Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=postgres - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public Key: (2048 bit) - Modulus (2048 bit): - 00:d7:8a:4c:85:fb:17:a5:3c:8f:e0:72:11:29:ce: - 3f:b0:1f:3f:7d:c6:ee:7f:a7:fc:02:2b:35:47:08: - a6:3d:90:df:5c:56:14:94:00:c7:6d:d1:d2:e2:61: - 95:77:b8:e3:a6:66:31:f9:1f:21:7d:62:e1:27:da: - 94:37:61:4a:ea:63:53:a0:61:b8:9c:bb:a5:e2:e7: - b7:a6:d8:0f:05:04:c7:29:e2:ea:49:2b:7f:de:15: - 00:a6:18:70:50:c7:0c:de:9a:f9:5a:96:b0:e1:94: - 06:c6:6d:4a:21:3b:b4:0f:a5:6d:92:86:34:b2:4e: - d7:0e:a7:19:c0:77:0b:7b:87:c8:92:de:42:ff:86: - d2:b7:9a:a4:d4:15:23:ca:ad:a5:69:21:b8:ce:7e: - 66:cb:85:5d:b9:ed:8b:2d:09:8d:94:e4:04:1e:72: - ec:ef:d0:76:90:15:5a:a4:f7:91:4b:e9:ce:4e:9d: - 5d:9a:70:17:9c:d8:e9:73:83:ea:3d:61:99:a6:cd: - ac:91:40:5a:88:77:e5:4e:2a:8e:3d:13:f3:f9:38: - 6f:81:6b:8a:95:ca:0e:07:ab:6f:da:b4:8c:d9:ff: - aa:78:03:aa:c7:c2:cf:6f:64:92:d3:d8:83:d5:af: - f1:23:18:a7:2e:7b:17:0b:e7:7d:f1:fa:a8:41:a3: - 04:57 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - EE:F0:B3:46:DC:C7:09:EB:0E:B6:2F:E5:FE:62:60:45:44:9F:59:CC - X509v3 Authority Key Identifier: - keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72 - - X509v3 Basic Constraints: - CA:FALSE - X509v3 Key Usage: - Digital Signature, Non Repudiation, Key Encipherment - Signature Algorithm: sha256WithRSAEncryption - 7e:5a:6e:be:bf:d2:6c:c1:d6:fa:b6:fb:3f:06:53:36:08:87: - 9d:95:b1:39:af:9e:f6:47:38:17:39:da:25:7c:f2:ad:0c:e3: - ab:74:19:ca:fb:8c:a0:50:c0:1d:19:8a:9c:21:ed:0f:3a:d1: - 96:54:2e:10:09:4f:b8:70:f7:2b:99:43:d2:c6:15:bc:3f:24: - 7d:28:39:32:3f:8d:a4:4f:40:75:7f:3e:0d:1c:d1:69:f2:4e: - 98:83:47:97:d2:25:ac:c9:36:86:2f:04:a6:c4:86:c7:c4:00: - 5f:7f:b9:ad:fc:bf:e9:f5:78:d7:82:1a:51:0d:fc:ab:9e:92: - 1d:5f:0c:18:d1:82:e0:14:c9:ce:91:89:71:ff:49:49:ff:35: - bf:7b:44:78:42:c1:d0:66:65:bb:28:2e:60:ca:9b:20:12:a9: - 90:61:b1:96:ec:15:46:c9:37:f7:07:90:8a:89:45:2a:3f:37: - ec:dc:e3:e5:8f:c3:3a:57:80:a5:54:60:0c:e1:b2:26:99:2b: - 40:7e:36:d1:9a:70:02:ec:63:f4:3b:72:ae:81:fb:30:20:6d: - cb:48:46:c6:b5:8f:39:b1:84:05:25:55:8d:f5:62:f6:1b:46: - 2e:da:a3:4c:26:12:44:d7:56:b6:b8:a9:ca:d3:ab:71:45:7c: - 9f:48:6d:1e ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP -MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp -dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTA1MTVa -Fw0yNDEwMDgxNTA1MTVaMGExCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx -EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx -ETAPBgNVBAMTCHBvc3RncmVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYUlADHbdHS4mGV -d7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLqSSt/3hUAphhw -UMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C/4bSt5qk1BUj -yq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1dmnAXnNjpc4Pq -PWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOqx8LPb2SS09iD -1a/xIxinLnsXC+d98fqoQaMEVwIDAQABo1owWDAdBgNVHQ4EFgQU7vCzRtzHCesO -ti/l/mJgRUSfWcwwHwYDVR0jBBgwFoAUUpPtHnYKn2VP3hlmwdUiQDXLoHIwCQYD -VR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQELBQADggEBAH5abr6/0mzB -1vq2+z8GUzYIh52VsTmvnvZHOBc52iV88q0M46t0Gcr7jKBQwB0Zipwh7Q860ZZU -LhAJT7hw9yuZQ9LGFbw/JH0oOTI/jaRPQHV/Pg0c0WnyTpiDR5fSJazJNoYvBKbE -hsfEAF9/ua38v+n1eNeCGlEN/Kuekh1fDBjRguAUyc6RiXH/SUn/Nb97RHhCwdBm -ZbsoLmDKmyASqZBhsZbsFUbJN/cHkIqJRSo/N+zc4+WPwzpXgKVUYAzhsiaZK0B+ -NtGacALsY/Q7cq6B+zAgbctIRsa1jzmxhAUlVY31YvYbRi7ao0wmEkTXVra4qcrT -q3FFfJ9IbR4= ------END CERTIFICATE----- diff --git a/vendor/github.com/lib/pq/certs/server.key b/vendor/github.com/lib/pq/certs/server.key deleted file mode 100644 index bd7b019b655..00000000000 --- a/vendor/github.com/lib/pq/certs/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYU -lADHbdHS4mGVd7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLq -SSt/3hUAphhwUMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C -/4bSt5qk1BUjyq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1d -mnAXnNjpc4PqPWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOq -x8LPb2SS09iD1a/xIxinLnsXC+d98fqoQaMEVwIDAQABAoIBAF3ZoihUhJ82F4+r -Gz4QyDpv4L1reT2sb1aiabhcU8ZK5nbWJG+tRyjSS/i2dNaEcttpdCj9HR/zhgZM -bm0OuAgG58rVwgS80CZUruq++Qs+YVojq8/gWPTiQD4SNhV2Fmx3HkwLgUk3oxuT -SsvdqzGE3okGVrutCIcgy126eA147VPMoej1Bb3fO6npqK0pFPhZfAc0YoqJuM+k -obRm5pAnGUipyLCFXjA9HYPKwYZw2RtfdA3CiImHeanSdqS+ctrC9y8BV40Th7gZ -haXdKUNdjmIxV695QQ1mkGqpKLZFqhzKioGQ2/Ly2d1iaKN9fZltTusu8unepWJ2 -tlT9qMECgYEA9uHaF1t2CqE+AJvWTihHhPIIuLxoOQXYea1qvxfcH/UMtaLKzCNm -lQ5pqCGsPvp+10f36yttO1ZehIvlVNXuJsjt0zJmPtIolNuJY76yeussfQ9jHheB -5uPEzCFlHzxYbBUyqgWaF6W74okRGzEGJXjYSP0yHPPdU4ep2q3bGiUCgYEA34Af -wBSuQSK7uLxArWHvQhyuvi43ZGXls6oRGl+Ysj54s8BP6XGkq9hEJ6G4yxgyV+BR -DUOs5X8/TLT8POuIMYvKTQthQyCk0eLv2FLdESDuuKx0kBVY3s8lK3/z5HhrdOiN -VMNZU+xDKgKc3hN9ypkk8vcZe6EtH7Y14e0rVcsCgYBTgxi8F/M5K0wG9rAqphNz -VFBA9XKn/2M33cKjO5X5tXIEKzpAjaUQvNxexG04rJGljzG8+mar0M6ONahw5yD1 -O7i/XWgazgpuOEkkVYiYbd8RutfDgR4vFVMn3hAP3eDnRtBplRWH9Ec3HTiNIys6 -F8PKBOQjyRZQQC7jyzW3hQKBgACe5HeuFwXLSOYsb6mLmhR+6+VPT4wR1F95W27N -USk9jyxAnngxfpmTkiziABdgS9N+pfr5cyN4BP77ia/Jn6kzkC5Cl9SN5KdIkA3z -vPVtN/x/ThuQU5zaymmig1ThGLtMYggYOslG4LDfLPxY5YKIhle+Y+259twdr2yf -Mf2dAoGAaGv3tWMgnIdGRk6EQL/yb9PKHo7ShN+tKNlGaK7WwzBdKs+Fe8jkgcr7 -pz4Ne887CmxejdISzOCcdT+Zm9Bx6I/uZwWOtDvWpIgIxVX9a9URj/+D1MxTE/y4 -d6H+c89yDY62I2+drMpdjCd3EtCaTlxpTbRS+s1eAHMH7aEkcCE= ------END RSA PRIVATE KEY----- diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go index fadb88e5eac..de6e5c17ccd 100644 --- a/vendor/github.com/lib/pq/conn.go +++ b/vendor/github.com/lib/pq/conn.go @@ -339,6 +339,15 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { if err != nil { return nil, err } + + // cn.ssl and cn.startup panic on error. Make sure we don't leak cn.c. + panicking := true + defer func() { + if panicking { + cn.c.Close() + } + }() + cn.ssl(o) cn.buf = bufio.NewReader(cn.c) cn.startup(o) @@ -347,6 +356,7 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { err = cn.c.SetDeadline(time.Time{}) } + panicking = false return cn, err } diff --git a/vendor/github.com/lib/pq/doc.go b/vendor/github.com/lib/pq/doc.go index b2c3582c84a..a1b0297138d 100644 --- a/vendor/github.com/lib/pq/doc.go +++ b/vendor/github.com/lib/pq/doc.go @@ -239,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63 bytes by the PostgreSQL server. You can find a complete, working example of Listener usage at -http://godoc.org/github.com/lib/pq/examples/listen. +http://godoc.org/github.com/lib/pq/example/listen. */ package pq diff --git a/vendor/github.com/lib/pq/error.go b/vendor/github.com/lib/pq/error.go index b4bb44cee39..6928d96700e 100644 --- a/vendor/github.com/lib/pq/error.go +++ b/vendor/github.com/lib/pq/error.go @@ -153,6 +153,7 @@ var errorCodeNames = map[ErrorCode]string{ "22004": "null_value_not_allowed", "22002": "null_value_no_indicator_parameter", "22003": "numeric_value_out_of_range", + "2200H": "sequence_generator_limit_exceeded", "22026": "string_data_length_mismatch", "22001": "string_data_right_truncation", "22011": "substring_error", diff --git a/vendor/github.com/lib/pq/hstore/hstore.go b/vendor/github.com/lib/pq/hstore/hstore.go deleted file mode 100644 index 72d5abf51df..00000000000 --- a/vendor/github.com/lib/pq/hstore/hstore.go +++ /dev/null @@ -1,118 +0,0 @@ -package hstore - -import ( - "database/sql" - "database/sql/driver" - "strings" -) - -// A wrapper for transferring Hstore values back and forth easily. -type Hstore struct { - Map map[string]sql.NullString -} - -// escapes and quotes hstore keys/values -// s should be a sql.NullString or string -func hQuote(s interface{}) string { - var str string - switch v := s.(type) { - case sql.NullString: - if !v.Valid { - return "NULL" - } - str = v.String - case string: - str = v - default: - panic("not a string or sql.NullString") - } - - str = strings.Replace(str, "\\", "\\\\", -1) - return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"` -} - -// Scan implements the Scanner interface. -// -// Note h.Map is reallocated before the scan to clear existing values. If the -// hstore column's database value is NULL, then h.Map is set to nil instead. -func (h *Hstore) Scan(value interface{}) error { - if value == nil { - h.Map = nil - return nil - } - h.Map = make(map[string]sql.NullString) - var b byte - pair := [][]byte{{}, {}} - pi := 0 - inQuote := false - didQuote := false - sawSlash := false - bindex := 0 - for bindex, b = range value.([]byte) { - if sawSlash { - pair[pi] = append(pair[pi], b) - sawSlash = false - continue - } - - switch b { - case '\\': - sawSlash = true - continue - case '"': - inQuote = !inQuote - if !didQuote { - didQuote = true - } - continue - default: - if !inQuote { - switch b { - case ' ', '\t', '\n', '\r': - continue - case '=': - continue - case '>': - pi = 1 - didQuote = false - continue - case ',': - s := string(pair[1]) - if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { - h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} - } else { - h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} - } - pair[0] = []byte{} - pair[1] = []byte{} - pi = 0 - continue - } - } - } - pair[pi] = append(pair[pi], b) - } - if bindex > 0 { - s := string(pair[1]) - if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { - h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} - } else { - h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} - } - } - return nil -} - -// Value implements the driver Valuer interface. Note if h.Map is nil, the -// database column value will be set to NULL. -func (h Hstore) Value() (driver.Value, error) { - if h.Map == nil { - return nil, nil - } - parts := []string{} - for key, val := range h.Map { - thispart := hQuote(key) + "=>" + hQuote(val) - parts = append(parts, thispart) - } - return []byte(strings.Join(parts, ",")), nil -} diff --git a/vendor/github.com/lib/pq/listen_example/doc.go b/vendor/github.com/lib/pq/listen_example/doc.go deleted file mode 100644 index 80f0a9b9701..00000000000 --- a/vendor/github.com/lib/pq/listen_example/doc.go +++ /dev/null @@ -1,96 +0,0 @@ -/* - -Below you will find a self-contained Go program which uses the LISTEN / NOTIFY -mechanism to avoid polling the database while waiting for more work to arrive. - - // - // You can see the program in action by defining a function similar to - // the following: - // - // CREATE OR REPLACE FUNCTION public.get_work() - // RETURNS bigint - // LANGUAGE sql - // AS $$ - // SELECT CASE WHEN random() >= 0.2 THEN int8 '1' END - // $$ - // ; - - package main - - import ( - "database/sql" - "fmt" - "time" - - "github.com/lib/pq" - ) - - func doWork(db *sql.DB, work int64) { - // work here - } - - func getWork(db *sql.DB) { - for { - // get work from the database here - var work sql.NullInt64 - err := db.QueryRow("SELECT get_work()").Scan(&work) - if err != nil { - fmt.Println("call to get_work() failed: ", err) - time.Sleep(10 * time.Second) - continue - } - if !work.Valid { - // no more work to do - fmt.Println("ran out of work") - return - } - - fmt.Println("starting work on ", work.Int64) - go doWork(db, work.Int64) - } - } - - func waitForNotification(l *pq.Listener) { - select { - case <-l.Notify: - fmt.Println("received notification, new work available") - case <-time.After(90 * time.Second): - go l.Ping() - // Check if there's more work available, just in case it takes - // a while for the Listener to notice connection loss and - // reconnect. - fmt.Println("received no work for 90 seconds, checking for new work") - } - } - - func main() { - var conninfo string = "" - - db, err := sql.Open("postgres", conninfo) - if err != nil { - panic(err) - } - - reportProblem := func(ev pq.ListenerEventType, err error) { - if err != nil { - fmt.Println(err.Error()) - } - } - - listener := pq.NewListener(conninfo, 10 * time.Second, time.Minute, reportProblem) - err = listener.Listen("getwork") - if err != nil { - panic(err) - } - - fmt.Println("entering main loop") - for { - // process all available work before waiting for notifications - getWork(db) - waitForNotification(listener) - } - } - - -*/ -package listen_example diff --git a/vendor/github.com/lib/pq/oid/gen.go b/vendor/github.com/lib/pq/oid/gen.go new file mode 100644 index 00000000000..7c634cdc5cd --- /dev/null +++ b/vendor/github.com/lib/pq/oid/gen.go @@ -0,0 +1,93 @@ +// +build ignore + +// Generate the table of OID values +// Run with 'go run gen.go'. +package main + +import ( + "database/sql" + "fmt" + "log" + "os" + "os/exec" + "strings" + + _ "github.com/lib/pq" +) + +// OID represent a postgres Object Identifier Type. +type OID struct { + ID int + Type string +} + +// Name returns an upper case version of the oid type. +func (o OID) Name() string { + return strings.ToUpper(o.Type) +} + +func main() { + datname := os.Getenv("PGDATABASE") + sslmode := os.Getenv("PGSSLMODE") + + if datname == "" { + os.Setenv("PGDATABASE", "pqgotest") + } + + if sslmode == "" { + os.Setenv("PGSSLMODE", "disable") + } + + db, err := sql.Open("postgres", "") + if err != nil { + log.Fatal(err) + } + rows, err := db.Query(` + SELECT typname, oid + FROM pg_type WHERE oid < 10000 + ORDER BY oid; + `) + if err != nil { + log.Fatal(err) + } + oids := make([]*OID, 0) + for rows.Next() { + var oid OID + if err = rows.Scan(&oid.Type, &oid.ID); err != nil { + log.Fatal(err) + } + oids = append(oids, &oid) + } + if err = rows.Err(); err != nil { + log.Fatal(err) + } + cmd := exec.Command("gofmt") + cmd.Stderr = os.Stderr + w, err := cmd.StdinPipe() + if err != nil { + log.Fatal(err) + } + f, err := os.Create("types.go") + if err != nil { + log.Fatal(err) + } + cmd.Stdout = f + err = cmd.Start() + if err != nil { + log.Fatal(err) + } + fmt.Fprintln(w, "// Code generated by gen.go. DO NOT EDIT.") + fmt.Fprintln(w, "\npackage oid") + fmt.Fprintln(w, "const (") + for _, oid := range oids { + fmt.Fprintf(w, "T_%s Oid = %d\n", oid.Type, oid.ID) + } + fmt.Fprintln(w, ")") + fmt.Fprintln(w, "var TypeName = map[Oid]string{") + for _, oid := range oids { + fmt.Fprintf(w, "T_%s: \"%s\",\n", oid.Type, oid.Name()) + } + fmt.Fprintln(w, "}") + w.Close() + cmd.Wait() +} diff --git a/vendor/github.com/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md deleted file mode 100644 index e84226a7358..00000000000 --- a/vendor/github.com/mattn/go-colorable/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# go-colorable - -Colorable writer for windows. - -For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) -This package is possible to handle escape sequence for ansi color on windows. - -## Too Bad! - -![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) - - -## So Good! - -![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) - -## Usage - -```go -logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) -logrus.SetOutput(colorable.NewColorableStdout()) - -logrus.Info("succeeded") -logrus.Warn("not correct") -logrus.Error("something error") -logrus.Fatal("panic") -``` - -You can compile above code on non-windows OSs. - -## Installation - -``` -$ go get github.com/mattn/go-colorable -``` - -# License - -MIT - -# Author - -Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go new file mode 100644 index 00000000000..1f28d773d74 --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/colorable_appengine.go @@ -0,0 +1,29 @@ +// +build appengine + +package colorable + +import ( + "io" + "os" + + _ "github.com/mattn/go-isatty" +) + +// NewColorable return new instance of Writer which handle escape sequence. +func NewColorable(file *os.File) io.Writer { + if file == nil { + panic("nil passed instead of *os.File to NewColorable()") + } + + return file +} + +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. +func NewColorableStdout() io.Writer { + return os.Stdout +} + +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. +func NewColorableStderr() io.Writer { + return os.Stderr +} diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go index 52d6653b34b..887f203dc7f 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -1,12 +1,16 @@ // +build !windows +// +build !appengine package colorable import ( "io" "os" + + _ "github.com/mattn/go-isatty" ) +// NewColorable return new instance of Writer which handle escape sequence. func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") @@ -15,10 +19,12 @@ func NewColorable(file *os.File) io.Writer { return file } +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. func NewColorableStdout() io.Writer { return os.Stdout } +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. func NewColorableStderr() io.Writer { return os.Stderr } diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index c8f4e096344..e17a5474e98 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -1,8 +1,10 @@ +// +build windows +// +build !appengine + package colorable import ( "bytes" - "fmt" "io" "math" "os" @@ -52,6 +54,11 @@ type consoleScreenBufferInfo struct { maximumWindowSize coord } +type consoleCursorInfo struct { + size dword + visible int32 +} + var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") @@ -59,15 +66,20 @@ var ( procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") + procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") + procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") + procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW") ) +// Writer provide colorable Writer to the console type Writer struct { out io.Writer handle syscall.Handle - lastbuf bytes.Buffer oldattr word + oldpos coord } +// NewColorable return new instance of Writer which handle escape sequence from File. func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") @@ -77,16 +89,17 @@ func NewColorable(file *os.File) io.Writer { var csbi consoleScreenBufferInfo handle := syscall.Handle(file.Fd()) procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) - return &Writer{out: file, handle: handle, oldattr: csbi.attributes} - } else { - return file + return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}} } + return file } +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. func NewColorableStdout() io.Writer { return NewColorable(os.Stdout) } +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. func NewColorableStderr() io.Writer { return NewColorable(os.Stderr) } @@ -350,45 +363,83 @@ var color256 = map[int]int{ 255: 0xeeeeee, } +// `\033]0;TITLESTR\007` +func doTitleSequence(er *bytes.Reader) error { + var c byte + var err error + + c, err = er.ReadByte() + if err != nil { + return err + } + if c != '0' && c != '2' { + return nil + } + c, err = er.ReadByte() + if err != nil { + return err + } + if c != ';' { + return nil + } + title := make([]byte, 0, 80) + for { + c, err = er.ReadByte() + if err != nil { + return err + } + if c == 0x07 || c == '\n' { + break + } + title = append(title, c) + } + if len(title) > 0 { + title8, err := syscall.UTF16PtrFromString(string(title)) + if err == nil { + procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8))) + } + } + return nil +} + +// Write write data on console func (w *Writer) Write(data []byte) (n int, err error) { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - er := bytes.NewBuffer(data) + er := bytes.NewReader(data) + var bw [1]byte loop: for { - r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - if r1 == 0 { - break loop - } - - c1, _, err := er.ReadRune() + c1, err := er.ReadByte() if err != nil { break loop } if c1 != 0x1b { - fmt.Fprint(w.out, string(c1)) + bw[0] = c1 + w.out.Write(bw[:]) continue } - c2, _, err := er.ReadRune() + c2, err := er.ReadByte() if err != nil { - w.lastbuf.WriteRune(c1) break loop } + + if c2 == ']' { + if err := doTitleSequence(er); err != nil { + break loop + } + continue + } if c2 != 0x5b { - w.lastbuf.WriteRune(c1) - w.lastbuf.WriteRune(c2) continue } var buf bytes.Buffer - var m rune + var m byte for { - c, _, err := er.ReadRune() + c, err := er.ReadByte() if err != nil { - w.lastbuf.WriteRune(c1) - w.lastbuf.WriteRune(c2) - w.lastbuf.Write(buf.Bytes()) break loop } if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { @@ -398,7 +449,6 @@ loop: buf.Write([]byte(string(c))) } - var csbi consoleScreenBufferInfo switch m { case 'A': n, err = strconv.Atoi(buf.String()) @@ -422,19 +472,16 @@ loop: continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x -= short(n) + csbi.cursorPosition.x += short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'D': n, err = strconv.Atoi(buf.String()) if err != nil { continue } - if n, err = strconv.Atoi(buf.String()); err == nil { - var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'E': n, err = strconv.Atoi(buf.String()) if err != nil { @@ -459,61 +506,85 @@ loop: continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) - csbi.cursorPosition.x = short(n) + csbi.cursorPosition.x = short(n - 1) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) - case 'H': - token := strings.Split(buf.String(), ";") - if len(token) != 2 { - continue + case 'H', 'f': + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + if buf.Len() > 0 { + token := strings.Split(buf.String(), ";") + switch len(token) { + case 1: + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + csbi.cursorPosition.y = short(n1 - 1) + case 2: + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + n2, err := strconv.Atoi(token[1]) + if err != nil { + continue + } + csbi.cursorPosition.x = short(n2 - 1) + csbi.cursorPosition.y = short(n1 - 1) + } + } else { + csbi.cursorPosition.y = 0 } - n1, err := strconv.Atoi(token[0]) - if err != nil { - continue - } - n2, err := strconv.Atoi(token[1]) - if err != nil { - continue - } - csbi.cursorPosition.x = short(n2) - csbi.cursorPosition.x = short(n1) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'J': - n, err := strconv.Atoi(buf.String()) - if err != nil { - continue + n := 0 + if buf.Len() > 0 { + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } } + var count, written dword var cursor coord + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top} + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x) case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top} + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) } - var count, written dword - count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'K': - n, err := strconv.Atoi(buf.String()) - if err != nil { - continue + n := 0 + if buf.Len() > 0 { + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) var cursor coord + var count, written dword switch n { case 0: - cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x - 1) case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + count = dword(csbi.size.x - csbi.cursorPosition.x) case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + count = dword(csbi.size.x) } - var count, written dword - count = dword(csbi.size.x - csbi.cursorPosition.x) procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'm': + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) attr := csbi.attributes cs := buf.String() if cs == "" { @@ -521,7 +592,7 @@ loop: continue } token := strings.Split(cs, ";") - for i := 0; i < len(token); i += 1 { + for i := 0; i < len(token); i++ { ns := token[i] if n, err = strconv.Atoi(ns); err == nil { switch { @@ -531,12 +602,12 @@ loop: attr |= foregroundIntensity case n == 7: attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) - case 22 == n || n == 25 || n == 25: + case n == 22 || n == 25: attr |= foregroundIntensity case n == 27: attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) case 30 <= n && n <= 37: - attr = (attr & backgroundMask) + attr &= backgroundMask if (n-30)&1 != 0 { attr |= foregroundRed } @@ -563,7 +634,7 @@ loop: attr &= backgroundMask attr |= w.oldattr & foregroundMask case 40 <= n && n <= 47: - attr = (attr & foregroundMask) + attr &= foregroundMask if (n-40)&1 != 0 { attr |= backgroundRed } @@ -617,9 +688,39 @@ loop: procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) } } + case 'h': + var ci consoleCursorInfo + cs := buf.String() + if cs == "5>" { + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 0 + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?25" { + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 1 + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + } + case 'l': + var ci consoleCursorInfo + cs := buf.String() + if cs == "5>" { + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 1 + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + } else if cs == "?25" { + procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + ci.visible = 0 + procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) + } + case 's': + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + w.oldpos = csbi.cursorPosition + case 'u': + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) } } - return len(data) - w.lastbuf.Len(), nil + + return len(data), nil } type consoleColor struct { @@ -663,22 +764,22 @@ func (c consoleColor) backgroundAttr() (attr word) { } var color16 = []consoleColor{ - consoleColor{0x000000, false, false, false, false}, - consoleColor{0x000080, false, false, true, false}, - consoleColor{0x008000, false, true, false, false}, - consoleColor{0x008080, false, true, true, false}, - consoleColor{0x800000, true, false, false, false}, - consoleColor{0x800080, true, false, true, false}, - consoleColor{0x808000, true, true, false, false}, - consoleColor{0xc0c0c0, true, true, true, false}, - consoleColor{0x808080, false, false, false, true}, - consoleColor{0x0000ff, false, false, true, true}, - consoleColor{0x00ff00, false, true, false, true}, - consoleColor{0x00ffff, false, true, true, true}, - consoleColor{0xff0000, true, false, false, true}, - consoleColor{0xff00ff, true, false, true, true}, - consoleColor{0xffff00, true, true, false, true}, - consoleColor{0xffffff, true, true, true, true}, + {0x000000, false, false, false, false}, + {0x000080, false, false, true, false}, + {0x008000, false, true, false, false}, + {0x008080, false, true, true, false}, + {0x800000, true, false, false, false}, + {0x800080, true, false, true, false}, + {0x808000, true, true, false, false}, + {0xc0c0c0, true, true, true, false}, + {0x808080, false, false, false, true}, + {0x0000ff, false, false, true, true}, + {0x00ff00, false, true, false, true}, + {0x00ffff, false, true, true, true}, + {0xff0000, true, false, false, true}, + {0xff00ff, true, false, true, true}, + {0xffff00, true, true, false, true}, + {0xffffff, true, true, true, true}, } type hsv struct { diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go new file mode 100644 index 00000000000..9721e16f4bf --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -0,0 +1,55 @@ +package colorable + +import ( + "bytes" + "io" +) + +// NonColorable hold writer but remove escape sequence. +type NonColorable struct { + out io.Writer +} + +// NewNonColorable return new instance of Writer which remove escape sequence from Writer. +func NewNonColorable(w io.Writer) io.Writer { + return &NonColorable{out: w} +} + +// Write write data on console +func (w *NonColorable) Write(data []byte) (n int, err error) { + er := bytes.NewReader(data) + var bw [1]byte +loop: + for { + c1, err := er.ReadByte() + if err != nil { + break loop + } + if c1 != 0x1b { + bw[0] = c1 + w.out.Write(bw[:]) + continue + } + c2, err := er.ReadByte() + if err != nil { + break loop + } + if c2 != 0x5b { + continue + } + + var buf bytes.Buffer + for { + c, err := er.ReadByte() + if err != nil { + break loop + } + if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { + break + } + buf.Write([]byte(string(c))) + } + } + + return len(data), nil +} diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md deleted file mode 100644 index 1e69004bb03..00000000000 --- a/vendor/github.com/mattn/go-isatty/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# go-isatty - -[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty) -[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty) -[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master) -[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty) - -isatty for golang - -## Usage - -```go -package main - -import ( - "fmt" - "github.com/mattn/go-isatty" - "os" -) - -func main() { - if isatty.IsTerminal(os.Stdout.Fd()) { - fmt.Println("Is Terminal") - } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) { - fmt.Println("Is Cygwin/MSYS2 Terminal") - } else { - fmt.Println("Is Not Terminal") - } -} -``` - -## Installation - -``` -$ go get github.com/mattn/go-isatty -``` - -## License - -MIT - -## Author - -Yasuhiro Matsumoto (a.k.a mattn) - -## Thanks - -* k-takata: base idea for IsCygwinTerminal - - https://github.com/k-takata/go-iscygpty diff --git a/vendor/github.com/mattn/go-sqlite3/.gitignore b/vendor/github.com/mattn/go-sqlite3/.gitignore deleted file mode 100644 index bf90dfd898b..00000000000 --- a/vendor/github.com/mattn/go-sqlite3/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.db -*.exe -*.dll diff --git a/vendor/github.com/mattn/go-sqlite3/.travis.yml b/vendor/github.com/mattn/go-sqlite3/.travis.yml deleted file mode 100644 index e85e4738e14..00000000000 --- a/vendor/github.com/mattn/go-sqlite3/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: go -sudo: required -dist: trusty -go: - - 1.5 - - 1.6 - - tip -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx - - go test -v . -tags "libsqlite3" diff --git a/vendor/github.com/mattn/go-sqlite3/README.md b/vendor/github.com/mattn/go-sqlite3/README.md deleted file mode 100644 index c2e0d5a636e..00000000000 --- a/vendor/github.com/mattn/go-sqlite3/README.md +++ /dev/null @@ -1,81 +0,0 @@ -go-sqlite3 -========== - -[![Build Status](https://travis-ci.org/mattn/go-sqlite3.svg?branch=master)](https://travis-ci.org/mattn/go-sqlite3) -[![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.svg?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master) -[![GoDoc](https://godoc.org/github.com/mattn/go-sqlite3?status.svg)](http://godoc.org/github.com/mattn/go-sqlite3) - -Description ------------ - -sqlite3 driver conforming to the built-in database/sql interface - -Installation ------------- - -This package can be installed with the go get command: - - go get github.com/mattn/go-sqlite3 - -_go-sqlite3_ is *cgo* package. -If you want to build your app using go-sqlite3, you need gcc. -However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite3`, you don't need gcc to build your app anymore. - -Documentation -------------- - -API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3 - -Examples can be found under the `./_example` directory - -FAQ ---- - -* Want to build go-sqlite3 with libsqlite3 on my linux. - - Use `go build --tags "libsqlite3 linux"` - -* Want to build go-sqlite3 with libsqlite3 on OS X. - - Install sqlite3 from homebrew: `brew install sqlite3` - - Use `go build --tags "libsqlite3 darwin"` - -* Want to build go-sqlite3 with icu extension. - - Use `go build --tags "icu"` - -* Can't build go-sqlite3 on windows 64bit. - - > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. - > See: https://github.com/mattn/go-sqlite3/issues/27 - -* Getting insert error while query is opened. - - > You can pass some arguments into the connection string, for example, a URI. - > See: https://github.com/mattn/go-sqlite3/issues/39 - -* Do you want to cross compile? mingw on Linux or Mac? - - > See: https://github.com/mattn/go-sqlite3/issues/106 - > See also: http://www.limitlessfx.com/cross-compile-golang-app-for-windows-from-linux.html - -* Want to get time.Time with current locale - - Use `loc=auto` in SQLite3 filename schema like `file:foo.db?loc=auto`. - -License -------- - -MIT: http://mattn.mit-license.org/2012 - -sqlite3-binding.c, sqlite3-binding.h, sqlite3ext.h - -The -binding suffix was added to avoid build failures under gccgo. - -In this repository, those files are an amalgamation of code that was copied from SQLite3. The license of that code is the same as the license of SQLite3. - -Author ------- - -Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/mattn/go-sqlite3/backup.go b/vendor/github.com/mattn/go-sqlite3/backup.go index 4c1e38c878b..5ab3a54ded0 100644 --- a/vendor/github.com/mattn/go-sqlite3/backup.go +++ b/vendor/github.com/mattn/go-sqlite3/backup.go @@ -19,10 +19,12 @@ import ( "unsafe" ) +// SQLiteBackup implement interface of Backup. type SQLiteBackup struct { b *C.sqlite3_backup } +// Backup make backup from src to dest. func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteBackup, error) { destptr := C.CString(dest) defer C.free(unsafe.Pointer(destptr)) @@ -37,10 +39,10 @@ func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*SQLiteB return nil, c.lastError() } -// Backs up for one step. Calls the underlying `sqlite3_backup_step` function. -// This function returns a boolean indicating if the backup is done and -// an error signalling any other error. Done is returned if the underlying C -// function returns SQLITE_DONE (Code 101) +// Step to backs up for one step. Calls the underlying `sqlite3_backup_step` +// function. This function returns a boolean indicating if the backup is done +// and an error signalling any other error. Done is returned if the underlying +// C function returns SQLITE_DONE (Code 101) func (b *SQLiteBackup) Step(p int) (bool, error) { ret := C.sqlite3_backup_step(b.b, C.int(p)) if ret == C.SQLITE_DONE { @@ -51,24 +53,33 @@ func (b *SQLiteBackup) Step(p int) (bool, error) { return false, nil } +// Remaining return whether have the rest for backup. func (b *SQLiteBackup) Remaining() int { return int(C.sqlite3_backup_remaining(b.b)) } +// PageCount return count of pages. func (b *SQLiteBackup) PageCount() int { return int(C.sqlite3_backup_pagecount(b.b)) } +// Finish close backup. func (b *SQLiteBackup) Finish() error { return b.Close() } +// Close close backup. func (b *SQLiteBackup) Close() error { ret := C.sqlite3_backup_finish(b.b) + + // sqlite3_backup_finish() never fails, it just returns the + // error code from previous operations, so clean up before + // checking and returning an error + b.b = nil + runtime.SetFinalizer(b, nil) + if ret != 0 { return Error{Code: ErrNo(ret)} } - b.b = nil - runtime.SetFinalizer(b, nil) return nil } diff --git a/vendor/github.com/mattn/go-sqlite3/callback.go b/vendor/github.com/mattn/go-sqlite3/callback.go index e2bf3c6a217..29ece3d11d1 100644 --- a/vendor/github.com/mattn/go-sqlite3/callback.go +++ b/vendor/github.com/mattn/go-sqlite3/callback.go @@ -11,7 +11,11 @@ package sqlite3 // code for SQLite custom functions is in here. /* +#ifndef USE_LIBSQLITE3 #include +#else +#include +#endif #include void _sqlite3_result_text(sqlite3_context* ctx, const char* s); @@ -36,8 +40,8 @@ func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value } //export stepTrampoline -func stepTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) { - args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] +func stepTrampoline(ctx *C.sqlite3_context, argc C.int, argv **C.sqlite3_value) { + args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:int(argc):int(argc)] ai := lookupHandle(uintptr(C.sqlite3_user_data(ctx))).(*aggInfo) ai.Step(ctx, args) } @@ -49,6 +53,30 @@ func doneTrampoline(ctx *C.sqlite3_context) { ai.Done(ctx) } +//export compareTrampoline +func compareTrampoline(handlePtr uintptr, la C.int, a *C.char, lb C.int, b *C.char) C.int { + cmp := lookupHandle(handlePtr).(func(string, string) int) + return C.int(cmp(C.GoStringN(a, la), C.GoStringN(b, lb))) +} + +//export commitHookTrampoline +func commitHookTrampoline(handle uintptr) int { + callback := lookupHandle(handle).(func() int) + return callback() +} + +//export rollbackHookTrampoline +func rollbackHookTrampoline(handle uintptr) { + callback := lookupHandle(handle).(func()) + callback() +} + +//export updateHookTrampoline +func updateHookTrampoline(handle uintptr, op int, db *C.char, table *C.char, rowid int64) { + callback := lookupHandle(handle).(func(int, string, string, int64)) + callback(op, C.GoString(db), C.GoString(table), rowid) +} + // Use handles to avoid passing Go pointers to C. type handleVal struct { diff --git a/vendor/github.com/mattn/go-sqlite3/error.go b/vendor/github.com/mattn/go-sqlite3/error.go index b91010835c3..49ab8903667 100644 --- a/vendor/github.com/mattn/go-sqlite3/error.go +++ b/vendor/github.com/mattn/go-sqlite3/error.go @@ -7,12 +7,16 @@ package sqlite3 import "C" +// ErrNo inherit errno. type ErrNo int +// ErrNoMask is mask code. const ErrNoMask C.int = 0xff +// ErrNoExtended is extended errno. type ErrNoExtended int +// Error implement sqlite error code. type Error struct { Code ErrNo /* The error code returned by SQLite */ ExtendedCode ErrNoExtended /* The extended error code returned by SQLite */ @@ -52,14 +56,17 @@ var ( ErrWarning = ErrNo(28) /* Warnings from sqlite3_log() */ ) +// Error return error message from errno. func (err ErrNo) Error() string { return Error{Code: err}.Error() } +// Extend return extended errno. func (err ErrNo) Extend(by int) ErrNoExtended { return ErrNoExtended(int(err) | (by << 8)) } +// Error return error message that is extended code. func (err ErrNoExtended) Error() string { return Error{Code: ErrNo(C.int(err) & ErrNoMask), ExtendedCode: err}.Error() } @@ -121,7 +128,7 @@ var ( ErrConstraintTrigger = ErrConstraint.Extend(7) ErrConstraintUnique = ErrConstraint.Extend(8) ErrConstraintVTab = ErrConstraint.Extend(9) - ErrConstraintRowId = ErrConstraint.Extend(10) + ErrConstraintRowID = ErrConstraint.Extend(10) ErrNoticeRecoverWAL = ErrNotice.Extend(1) ErrNoticeRecoverRollback = ErrNotice.Extend(2) ErrWarningAutoIndex = ErrWarning.Extend(1) diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c index 614571c637f..b67d0a58997 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c @@ -1,8 +1,7 @@ -// +build !libsqlite3 - +#ifndef USE_LIBSQLITE3 /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.10.2. By combining all the individual C code files into this +** version 3.21.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 @@ -11,7 +10,7 @@ ** ** This file is all you need to compile SQLite. To use SQLite in other ** programs, you need this file and the "sqlite3.h" header file that defines -** the programming interface to the SQLite library. (If you do not have +** the programming interface to the SQLite library. (If you do not have ** the "sqlite3.h" header file at hand, you will find a copy embedded within ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed @@ -24,6 +23,761 @@ #ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif +/************** Begin file ctime.c *******************************************/ +/* +** 2010 February 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements routines used to report what compile-time options +** SQLite was built with. +*/ + +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + +/* +** Include the configuration header output by 'configure' if we're using the +** autoconf-based build +*/ +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) +#include "config.h" +#define SQLITECONFIG_H 1 +#endif + +/* These macros are provided to "stringify" the value of the define +** for those options in which the value is meaningful. */ +#define CTIMEOPT_VAL_(opt) #opt +#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) + +/* +** An array of names of all compile-time options. This array should +** be sorted A-Z. +** +** This array looks large, but in a typical installation actually uses +** only a handful of compile-time options, so most times this array is usually +** rather short and uses little memory space. +*/ +static const char * const sqlite3azCompileOpt[] = { + +/* +** BEGIN CODE GENERATED BY tool/mkctime.tcl +*/ +#if SQLITE_32BIT_ROWID + "32BIT_ROWID", +#endif +#if SQLITE_4_BYTE_ALIGNED_MALLOC + "4_BYTE_ALIGNED_MALLOC", +#endif +#if SQLITE_64BIT_STATS + "64BIT_STATS", +#endif +#if SQLITE_ALLOW_COVERING_INDEX_SCAN + "ALLOW_COVERING_INDEX_SCAN", +#endif +#if SQLITE_ALLOW_URI_AUTHORITY + "ALLOW_URI_AUTHORITY", +#endif +#ifdef SQLITE_BITMASK_TYPE + "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), +#endif +#if SQLITE_BUG_COMPATIBLE_20160819 + "BUG_COMPATIBLE_20160819", +#endif +#if SQLITE_CASE_SENSITIVE_LIKE + "CASE_SENSITIVE_LIKE", +#endif +#if SQLITE_CHECK_PAGES + "CHECK_PAGES", +#endif +#if defined(__clang__) && defined(__clang_major__) + "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." + CTIMEOPT_VAL(__clang_minor__) "." + CTIMEOPT_VAL(__clang_patchlevel__), +#elif defined(_MSC_VER) + "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), +#elif defined(__GNUC__) && defined(__VERSION__) + "COMPILER=gcc-" __VERSION__, +#endif +#if SQLITE_COVERAGE_TEST + "COVERAGE_TEST", +#endif +#if SQLITE_DEBUG + "DEBUG", +#endif +#if SQLITE_DEFAULT_AUTOMATIC_INDEX + "DEFAULT_AUTOMATIC_INDEX", +#endif +#if SQLITE_DEFAULT_AUTOVACUUM + "DEFAULT_AUTOVACUUM", +#endif +#ifdef SQLITE_DEFAULT_CACHE_SIZE + "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), +#endif +#if SQLITE_DEFAULT_CKPTFULLFSYNC + "DEFAULT_CKPTFULLFSYNC", +#endif +#ifdef SQLITE_DEFAULT_FILE_FORMAT + "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), +#endif +#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS + "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), +#endif +#if SQLITE_DEFAULT_FOREIGN_KEYS + "DEFAULT_FOREIGN_KEYS", +#endif +#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT + "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), +#endif +#ifdef SQLITE_DEFAULT_LOCKING_MODE + "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), +#endif +#ifdef SQLITE_DEFAULT_LOOKASIDE + "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE), +#endif +#if SQLITE_DEFAULT_MEMSTATUS + "DEFAULT_MEMSTATUS", +#endif +#ifdef SQLITE_DEFAULT_MMAP_SIZE + "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PAGE_SIZE + "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PCACHE_INITSZ + "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), +#endif +#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS + "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), +#endif +#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS + "DEFAULT_RECURSIVE_TRIGGERS", +#endif +#ifdef SQLITE_DEFAULT_ROWEST + "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), +#endif +#ifdef SQLITE_DEFAULT_SECTOR_SIZE + "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), +#endif +#ifdef SQLITE_DEFAULT_SYNCHRONOUS + "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT + "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), +#endif +#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS + "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WORKER_THREADS + "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), +#endif +#if SQLITE_DIRECT_OVERFLOW_READ + "DIRECT_OVERFLOW_READ", +#endif +#if SQLITE_DISABLE_DIRSYNC + "DISABLE_DIRSYNC", +#endif +#if SQLITE_DISABLE_FTS3_UNICODE + "DISABLE_FTS3_UNICODE", +#endif +#if SQLITE_DISABLE_FTS4_DEFERRED + "DISABLE_FTS4_DEFERRED", +#endif +#if SQLITE_DISABLE_INTRINSIC + "DISABLE_INTRINSIC", +#endif +#if SQLITE_DISABLE_LFS + "DISABLE_LFS", +#endif +#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS + "DISABLE_PAGECACHE_OVERFLOW_STATS", +#endif +#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT + "DISABLE_SKIPAHEAD_DISTINCT", +#endif +#ifdef SQLITE_ENABLE_8_3_NAMES + "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), +#endif +#if SQLITE_ENABLE_API_ARMOR + "ENABLE_API_ARMOR", +#endif +#if SQLITE_ENABLE_ATOMIC_WRITE + "ENABLE_ATOMIC_WRITE", +#endif +#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE + "ENABLE_BATCH_ATOMIC_WRITE", +#endif +#if SQLITE_ENABLE_CEROD + "ENABLE_CEROD", +#endif +#if SQLITE_ENABLE_COLUMN_METADATA + "ENABLE_COLUMN_METADATA", +#endif +#if SQLITE_ENABLE_COLUMN_USED_MASK + "ENABLE_COLUMN_USED_MASK", +#endif +#if SQLITE_ENABLE_COSTMULT + "ENABLE_COSTMULT", +#endif +#if SQLITE_ENABLE_CURSOR_HINTS + "ENABLE_CURSOR_HINTS", +#endif +#if SQLITE_ENABLE_DBSTAT_VTAB + "ENABLE_DBSTAT_VTAB", +#endif +#if SQLITE_ENABLE_EXPENSIVE_ASSERT + "ENABLE_EXPENSIVE_ASSERT", +#endif +#if SQLITE_ENABLE_FTS1 + "ENABLE_FTS1", +#endif +#if SQLITE_ENABLE_FTS2 + "ENABLE_FTS2", +#endif +#if SQLITE_ENABLE_FTS3 + "ENABLE_FTS3", +#endif +#if SQLITE_ENABLE_FTS3_PARENTHESIS + "ENABLE_FTS3_PARENTHESIS", +#endif +#if SQLITE_ENABLE_FTS3_TOKENIZER + "ENABLE_FTS3_TOKENIZER", +#endif +#if SQLITE_ENABLE_FTS4 + "ENABLE_FTS4", +#endif +#if SQLITE_ENABLE_FTS5 + "ENABLE_FTS5", +#endif +#if SQLITE_ENABLE_HIDDEN_COLUMNS + "ENABLE_HIDDEN_COLUMNS", +#endif +#if SQLITE_ENABLE_ICU + "ENABLE_ICU", +#endif +#if SQLITE_ENABLE_IOTRACE + "ENABLE_IOTRACE", +#endif +#if SQLITE_ENABLE_JSON1 + "ENABLE_JSON1", +#endif +#if SQLITE_ENABLE_LOAD_EXTENSION + "ENABLE_LOAD_EXTENSION", +#endif +#ifdef SQLITE_ENABLE_LOCKING_STYLE + "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), +#endif +#if SQLITE_ENABLE_MEMORY_MANAGEMENT + "ENABLE_MEMORY_MANAGEMENT", +#endif +#if SQLITE_ENABLE_MEMSYS3 + "ENABLE_MEMSYS3", +#endif +#if SQLITE_ENABLE_MEMSYS5 + "ENABLE_MEMSYS5", +#endif +#if SQLITE_ENABLE_MULTIPLEX + "ENABLE_MULTIPLEX", +#endif +#if SQLITE_ENABLE_NULL_TRIM + "ENABLE_NULL_TRIM", +#endif +#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK + "ENABLE_OVERSIZE_CELL_CHECK", +#endif +#if SQLITE_ENABLE_PREUPDATE_HOOK + "ENABLE_PREUPDATE_HOOK", +#endif +#if SQLITE_ENABLE_QPSG + "ENABLE_QPSG", +#endif +#if SQLITE_ENABLE_RBU + "ENABLE_RBU", +#endif +#if SQLITE_ENABLE_RTREE + "ENABLE_RTREE", +#endif +#if SQLITE_ENABLE_SELECTTRACE + "ENABLE_SELECTTRACE", +#endif +#if SQLITE_ENABLE_SESSION + "ENABLE_SESSION", +#endif +#if SQLITE_ENABLE_SNAPSHOT + "ENABLE_SNAPSHOT", +#endif +#if SQLITE_ENABLE_SQLLOG + "ENABLE_SQLLOG", +#endif +#if defined(SQLITE_ENABLE_STAT4) + "ENABLE_STAT4", +#elif defined(SQLITE_ENABLE_STAT3) + "ENABLE_STAT3", +#endif +#if SQLITE_ENABLE_STMTVTAB + "ENABLE_STMTVTAB", +#endif +#if SQLITE_ENABLE_STMT_SCANSTATUS + "ENABLE_STMT_SCANSTATUS", +#endif +#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + "ENABLE_UNKNOWN_SQL_FUNCTION", +#endif +#if SQLITE_ENABLE_UNLOCK_NOTIFY + "ENABLE_UNLOCK_NOTIFY", +#endif +#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT + "ENABLE_UPDATE_DELETE_LIMIT", +#endif +#if SQLITE_ENABLE_URI_00_ERROR + "ENABLE_URI_00_ERROR", +#endif +#if SQLITE_ENABLE_VFSTRACE + "ENABLE_VFSTRACE", +#endif +#if SQLITE_ENABLE_WHERETRACE + "ENABLE_WHERETRACE", +#endif +#if SQLITE_ENABLE_ZIPVFS + "ENABLE_ZIPVFS", +#endif +#if SQLITE_EXPLAIN_ESTIMATED_ROWS + "EXPLAIN_ESTIMATED_ROWS", +#endif +#if SQLITE_EXTRA_IFNULLROW + "EXTRA_IFNULLROW", +#endif +#ifdef SQLITE_EXTRA_INIT + "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), +#endif +#ifdef SQLITE_EXTRA_SHUTDOWN + "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), +#endif +#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH + "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), +#endif +#if SQLITE_FTS5_ENABLE_TEST_MI + "FTS5_ENABLE_TEST_MI", +#endif +#if SQLITE_FTS5_NO_WITHOUT_ROWID + "FTS5_NO_WITHOUT_ROWID", +#endif +#if SQLITE_HAS_CODEC + "HAS_CODEC", +#endif +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN + "HAVE_ISNAN", +#endif +#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX + "HOMEGROWN_RECURSIVE_MUTEX", +#endif +#if SQLITE_IGNORE_AFP_LOCK_ERRORS + "IGNORE_AFP_LOCK_ERRORS", +#endif +#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS + "IGNORE_FLOCK_LOCK_ERRORS", +#endif +#if SQLITE_INLINE_MEMCPY + "INLINE_MEMCPY", +#endif +#if SQLITE_INT64_TYPE + "INT64_TYPE", +#endif +#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX + "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), +#endif +#if SQLITE_LIKE_DOESNT_MATCH_BLOBS + "LIKE_DOESNT_MATCH_BLOBS", +#endif +#if SQLITE_LOCK_TRACE + "LOCK_TRACE", +#endif +#if SQLITE_LOG_CACHE_SPILL + "LOG_CACHE_SPILL", +#endif +#ifdef SQLITE_MALLOC_SOFT_LIMIT + "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), +#endif +#ifdef SQLITE_MAX_ATTACHED + "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), +#endif +#ifdef SQLITE_MAX_COLUMN + "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN), +#endif +#ifdef SQLITE_MAX_COMPOUND_SELECT + "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT), +#endif +#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE + "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_EXPR_DEPTH + "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH), +#endif +#ifdef SQLITE_MAX_FUNCTION_ARG + "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG), +#endif +#ifdef SQLITE_MAX_LENGTH + "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH), +#endif +#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH + "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH), +#endif +#ifdef SQLITE_MAX_MEMORY + "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE + "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE_ + "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_), +#endif +#ifdef SQLITE_MAX_PAGE_COUNT + "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT), +#endif +#ifdef SQLITE_MAX_PAGE_SIZE + "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_SCHEMA_RETRY + "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), +#endif +#ifdef SQLITE_MAX_SQL_LENGTH + "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH), +#endif +#ifdef SQLITE_MAX_TRIGGER_DEPTH + "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH), +#endif +#ifdef SQLITE_MAX_VARIABLE_NUMBER + "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER), +#endif +#ifdef SQLITE_MAX_VDBE_OP + "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), +#endif +#ifdef SQLITE_MAX_WORKER_THREADS + "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), +#endif +#if SQLITE_MEMDEBUG + "MEMDEBUG", +#endif +#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT + "MIXED_ENDIAN_64BIT_FLOAT", +#endif +#if SQLITE_MMAP_READWRITE + "MMAP_READWRITE", +#endif +#if SQLITE_MUTEX_NOOP + "MUTEX_NOOP", +#endif +#if SQLITE_MUTEX_NREF + "MUTEX_NREF", +#endif +#if SQLITE_MUTEX_OMIT + "MUTEX_OMIT", +#endif +#if SQLITE_MUTEX_PTHREADS + "MUTEX_PTHREADS", +#endif +#if SQLITE_MUTEX_W32 + "MUTEX_W32", +#endif +#if SQLITE_NEED_ERR_NAME + "NEED_ERR_NAME", +#endif +#if SQLITE_NOINLINE + "NOINLINE", +#endif +#if SQLITE_NO_SYNC + "NO_SYNC", +#endif +#if SQLITE_OMIT_ALTERTABLE + "OMIT_ALTERTABLE", +#endif +#if SQLITE_OMIT_ANALYZE + "OMIT_ANALYZE", +#endif +#if SQLITE_OMIT_ATTACH + "OMIT_ATTACH", +#endif +#if SQLITE_OMIT_AUTHORIZATION + "OMIT_AUTHORIZATION", +#endif +#if SQLITE_OMIT_AUTOINCREMENT + "OMIT_AUTOINCREMENT", +#endif +#if SQLITE_OMIT_AUTOINIT + "OMIT_AUTOINIT", +#endif +#if SQLITE_OMIT_AUTOMATIC_INDEX + "OMIT_AUTOMATIC_INDEX", +#endif +#if SQLITE_OMIT_AUTORESET + "OMIT_AUTORESET", +#endif +#if SQLITE_OMIT_AUTOVACUUM + "OMIT_AUTOVACUUM", +#endif +#if SQLITE_OMIT_BETWEEN_OPTIMIZATION + "OMIT_BETWEEN_OPTIMIZATION", +#endif +#if SQLITE_OMIT_BLOB_LITERAL + "OMIT_BLOB_LITERAL", +#endif +#if SQLITE_OMIT_BTREECOUNT + "OMIT_BTREECOUNT", +#endif +#if SQLITE_OMIT_CAST + "OMIT_CAST", +#endif +#if SQLITE_OMIT_CHECK + "OMIT_CHECK", +#endif +#if SQLITE_OMIT_COMPLETE + "OMIT_COMPLETE", +#endif +#if SQLITE_OMIT_COMPOUND_SELECT + "OMIT_COMPOUND_SELECT", +#endif +#if SQLITE_OMIT_CONFLICT_CLAUSE + "OMIT_CONFLICT_CLAUSE", +#endif +#if SQLITE_OMIT_CTE + "OMIT_CTE", +#endif +#if SQLITE_OMIT_DATETIME_FUNCS + "OMIT_DATETIME_FUNCS", +#endif +#if SQLITE_OMIT_DECLTYPE + "OMIT_DECLTYPE", +#endif +#if SQLITE_OMIT_DEPRECATED + "OMIT_DEPRECATED", +#endif +#if SQLITE_OMIT_DISKIO + "OMIT_DISKIO", +#endif +#if SQLITE_OMIT_EXPLAIN + "OMIT_EXPLAIN", +#endif +#if SQLITE_OMIT_FLAG_PRAGMAS + "OMIT_FLAG_PRAGMAS", +#endif +#if SQLITE_OMIT_FLOATING_POINT + "OMIT_FLOATING_POINT", +#endif +#if SQLITE_OMIT_FOREIGN_KEY + "OMIT_FOREIGN_KEY", +#endif +#if SQLITE_OMIT_GET_TABLE + "OMIT_GET_TABLE", +#endif +#if SQLITE_OMIT_HEX_INTEGER + "OMIT_HEX_INTEGER", +#endif +#if SQLITE_OMIT_INCRBLOB + "OMIT_INCRBLOB", +#endif +#if SQLITE_OMIT_INTEGRITY_CHECK + "OMIT_INTEGRITY_CHECK", +#endif +#if SQLITE_OMIT_LIKE_OPTIMIZATION + "OMIT_LIKE_OPTIMIZATION", +#endif +#if SQLITE_OMIT_LOAD_EXTENSION + "OMIT_LOAD_EXTENSION", +#endif +#if SQLITE_OMIT_LOCALTIME + "OMIT_LOCALTIME", +#endif +#if SQLITE_OMIT_LOOKASIDE + "OMIT_LOOKASIDE", +#endif +#if SQLITE_OMIT_MEMORYDB + "OMIT_MEMORYDB", +#endif +#if SQLITE_OMIT_OR_OPTIMIZATION + "OMIT_OR_OPTIMIZATION", +#endif +#if SQLITE_OMIT_PAGER_PRAGMAS + "OMIT_PAGER_PRAGMAS", +#endif +#if SQLITE_OMIT_PARSER_TRACE + "OMIT_PARSER_TRACE", +#endif +#if SQLITE_OMIT_POPEN + "OMIT_POPEN", +#endif +#if SQLITE_OMIT_PRAGMA + "OMIT_PRAGMA", +#endif +#if SQLITE_OMIT_PROGRESS_CALLBACK + "OMIT_PROGRESS_CALLBACK", +#endif +#if SQLITE_OMIT_QUICKBALANCE + "OMIT_QUICKBALANCE", +#endif +#if SQLITE_OMIT_REINDEX + "OMIT_REINDEX", +#endif +#if SQLITE_OMIT_SCHEMA_PRAGMAS + "OMIT_SCHEMA_PRAGMAS", +#endif +#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS + "OMIT_SCHEMA_VERSION_PRAGMAS", +#endif +#if SQLITE_OMIT_SHARED_CACHE + "OMIT_SHARED_CACHE", +#endif +#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES + "OMIT_SHUTDOWN_DIRECTORIES", +#endif +#if SQLITE_OMIT_SUBQUERY + "OMIT_SUBQUERY", +#endif +#if SQLITE_OMIT_TCL_VARIABLE + "OMIT_TCL_VARIABLE", +#endif +#if SQLITE_OMIT_TEMPDB + "OMIT_TEMPDB", +#endif +#if SQLITE_OMIT_TEST_CONTROL + "OMIT_TEST_CONTROL", +#endif +#if SQLITE_OMIT_TRACE + "OMIT_TRACE", +#endif +#if SQLITE_OMIT_TRIGGER + "OMIT_TRIGGER", +#endif +#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION + "OMIT_TRUNCATE_OPTIMIZATION", +#endif +#if SQLITE_OMIT_UTF16 + "OMIT_UTF16", +#endif +#if SQLITE_OMIT_VACUUM + "OMIT_VACUUM", +#endif +#if SQLITE_OMIT_VIEW + "OMIT_VIEW", +#endif +#if SQLITE_OMIT_VIRTUALTABLE + "OMIT_VIRTUALTABLE", +#endif +#if SQLITE_OMIT_WAL + "OMIT_WAL", +#endif +#if SQLITE_OMIT_WSD + "OMIT_WSD", +#endif +#if SQLITE_OMIT_XFER_OPT + "OMIT_XFER_OPT", +#endif +#if SQLITE_PCACHE_SEPARATE_HEADER + "PCACHE_SEPARATE_HEADER", +#endif +#if SQLITE_PERFORMANCE_TRACE + "PERFORMANCE_TRACE", +#endif +#if SQLITE_POWERSAFE_OVERWRITE + "POWERSAFE_OVERWRITE", +#endif +#if SQLITE_PREFER_PROXY_LOCKING + "PREFER_PROXY_LOCKING", +#endif +#if SQLITE_PROXY_DEBUG + "PROXY_DEBUG", +#endif +#if SQLITE_REVERSE_UNORDERED_SELECTS + "REVERSE_UNORDERED_SELECTS", +#endif +#if SQLITE_RTREE_INT_ONLY + "RTREE_INT_ONLY", +#endif +#if SQLITE_SECURE_DELETE + "SECURE_DELETE", +#endif +#if SQLITE_SMALL_STACK + "SMALL_STACK", +#endif +#ifdef SQLITE_SORTER_PMASZ + "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), +#endif +#if SQLITE_SOUNDEX + "SOUNDEX", +#endif +#ifdef SQLITE_STAT4_SAMPLES + "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), +#endif +#ifdef SQLITE_STMTJRNL_SPILL + "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), +#endif +#if SQLITE_SUBSTR_COMPATIBILITY + "SUBSTR_COMPATIBILITY", +#endif +#if SQLITE_SYSTEM_MALLOC + "SYSTEM_MALLOC", +#endif +#if SQLITE_TCL + "TCL", +#endif +#ifdef SQLITE_TEMP_STORE + "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), +#endif +#if SQLITE_TEST + "TEST", +#endif +#if defined(SQLITE_THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), +#elif defined(THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), +#else + "THREADSAFE=1", +#endif +#if SQLITE_UNLINK_AFTER_CLOSE + "UNLINK_AFTER_CLOSE", +#endif +#if SQLITE_UNTESTABLE + "UNTESTABLE", +#endif +#if SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif +#if SQLITE_USE_ALLOCA + "USE_ALLOCA", +#endif +#if SQLITE_USE_FCNTL_TRACE + "USE_FCNTL_TRACE", +#endif +#if SQLITE_USE_URI + "USE_URI", +#endif +#if SQLITE_VDBE_COVERAGE + "VDBE_COVERAGE", +#endif +#if SQLITE_WIN32_MALLOC + "WIN32_MALLOC", +#endif +#if SQLITE_ZERO_MALLOC + "ZERO_MALLOC", +#endif +/* +** END CODE GENERATED BY tool/mkctime.tcl +*/ +}; + +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ + *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); + return (const char**)sqlite3azCompileOpt; +} + +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +/************** End of ctime.c ***********************************************/ /************** Begin file sqliteInt.h ***************************************/ /* ** 2001 September 15 @@ -39,8 +793,43 @@ ** Internal interface definitions for SQLite. ** */ -#ifndef _SQLITEINT_H_ -#define _SQLITEINT_H_ +#ifndef SQLITEINT_H +#define SQLITEINT_H + +/* Special Comments: +** +** Some comments have special meaning to the tools that measure test +** coverage: +** +** NO_TEST - The branches on this line are not +** measured by branch coverage. This is +** used on lines of code that actually +** implement parts of coverage testing. +** +** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false +** and the correct answer is still obtained, +** though perhaps more slowly. +** +** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true +** and the correct answer is still obtained, +** though perhaps more slowly. +** +** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread +** that would be harmless and undetectable +** if it did occur. +** +** In all cases, the special comment must be enclosed in the usual +** slash-asterisk...asterisk-slash comment marks, with no spaces between the +** asterisks and the comment text. +*/ + +/* +** Make sure the Tcl calling convention macro is defined. This macro is +** only used by test code and Tcl integration code. +*/ +#ifndef SQLITE_TCLAPI +# define SQLITE_TCLAPI +#endif /* ** Include the header file used to customize the compiler options for MSVC. @@ -64,8 +853,8 @@ ** ** This file contains code that is specific to MSVC. */ -#ifndef _MSVC_H_ -#define _MSVC_H_ +#ifndef SQLITE_MSVC_H +#define SQLITE_MSVC_H #if defined(_MSC_VER) #pragma warning(disable : 4054) @@ -85,7 +874,7 @@ #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ -#endif /* _MSVC_H_ */ +#endif /* SQLITE_MSVC_H */ /************** End of msvc.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -123,6 +912,9 @@ #else /* This is not VxWorks. */ #define OS_VXWORKS 0 +#define HAVE_FCHOWN 1 +#define HAVE_READLINK 1 +#define HAVE_LSTAT 1 #endif /* defined(_WRS_KERNEL) */ /************** End of vxworks.h *********************************************/ @@ -160,12 +952,29 @@ # define _LARGEFILE_SOURCE 1 #endif -/* What version of GCC is being used. 0 means GCC is not being used */ -#ifdef __GNUC__ +/* The GCC_VERSION and MSVC_VERSION macros are used to +** conditionally include optimizations for each of these compilers. A +** value of 0 means that compiler is not being used. The +** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific +** optimizations, and hence set all compiler macros to 0 +** +** There was once also a CLANG_VERSION macro. However, we learn that the +** version numbers in clang are for "marketing" only and are inconsistent +** and unreliable. Fortunately, all versions of clang also recognize the +** gcc version numbers and have reasonable settings for gcc version numbers, +** so the GCC_VERSION macro will be set to a correct non-zero value even +** when compiling with clang. +*/ +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif /* Needed for various definitions... */ #if defined(__GNUC__) && !defined(_GNU_SOURCE) @@ -215,7 +1024,7 @@ /************** Include sqlite3.h in the middle of sqliteInt.h ***************/ /************** Begin file sqlite3.h *****************************************/ /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -246,8 +1055,8 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ -#ifndef _SQLITE3_H_ -#define _SQLITE3_H_ +#ifndef SQLITE3_H +#define SQLITE3_H #include /* Needed for the definition of va_list */ /* @@ -270,8 +1079,17 @@ extern "C" { #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif +#ifndef SQLITE_APICALL +# define SQLITE_APICALL +#endif #ifndef SQLITE_STDCALL -# define SQLITE_STDCALL +# define SQLITE_STDCALL SQLITE_APICALL +#endif +#ifndef SQLITE_CALLBACK +# define SQLITE_CALLBACK +#endif +#ifndef SQLITE_SYSAPI +# define SQLITE_SYSAPI #endif /* @@ -315,25 +1133,28 @@ extern "C" { ** be held constant and Z will be incremented or else Y will be incremented ** and Z will be reset to zero. ** -** Since version 3.6.18, SQLite source code has been stored in the +** Since [version 3.6.18] ([dateof:3.6.18]), +** SQLite source code has been stored in the ** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID -** string contains the date and time of the check-in (UTC) and an SHA1 -** hash of the entire source tree. +** string contains the date and time of the check-in (UTC) and a SHA1 +** or SHA3-256 hash of the entire source tree. If the source code has +** been edited in any way since it was last checked in, then the last +** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.10.2" -#define SQLITE_VERSION_NUMBER 3010002 -#define SQLITE_SOURCE_ID "2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9" +#define SQLITE_VERSION "3.21.0" +#define SQLITE_VERSION_NUMBER 3021000 +#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827" /* ** CAPI3REF: Run-Time Library Version Numbers -** KEYWORDS: sqlite3_version, sqlite3_sourceid +** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros @@ -345,7 +1166,7 @@ extern "C" { ** **
       ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
      -** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
      +** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
       ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
       ** 
      )^ ** @@ -355,16 +1176,18 @@ extern "C" { ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. +** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built +** using an edited copy of [the amalgamation], then the last four characters +** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; -SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void); -SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void); -SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void); +SQLITE_API const char *sqlite3_libversion(void); +SQLITE_API const char *sqlite3_sourceid(void); +SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics @@ -389,8 +1212,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void); ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS -SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName); -SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N); +SQLITE_API int sqlite3_compileoption_used(const char *zOptName); +SQLITE_API const char *sqlite3_compileoption_get(int N); #endif /* @@ -429,7 +1252,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N); ** ** See the [threading mode] documentation for additional information. */ -SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void); +SQLITE_API int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle @@ -465,7 +1288,11 @@ typedef struct sqlite3 sqlite3; */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; - typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +# ifdef SQLITE_UINT64_TYPE + typedef SQLITE_UINT64_TYPE sqlite_uint64; +# else + typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +# endif #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 sqlite_int64; typedef unsigned __int64 sqlite_uint64; @@ -526,8 +1353,8 @@ typedef sqlite_uint64 sqlite3_uint64; ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer ** argument is a harmless no-op. */ -SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*); -SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*); +SQLITE_API int sqlite3_close(sqlite3*); +SQLITE_API int sqlite3_close_v2(sqlite3*); /* ** The type for a callback function. @@ -563,7 +1390,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** from [sqlite3_malloc()] and passed back through the 5th parameter. ** To avoid memory leaks, the application should invoke [sqlite3_free()] ** on error message strings returned through the 5th parameter of -** of sqlite3_exec() after the error message string is no longer needed. +** sqlite3_exec() after the error message string is no longer needed. ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to ** NULL before returning. @@ -598,7 +1425,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. **
    */ -SQLITE_API int SQLITE_STDCALL sqlite3_exec( +SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ @@ -619,7 +1446,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ @@ -634,7 +1461,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -642,7 +1469,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ @@ -659,7 +1486,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( ** [result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to -** address this, newer versions of SQLite (version 3.3.8 and later) include +** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] +** and later) include ** support for additional result codes that provide more detailed information ** about errors. These [extended result codes] are enabled or disabled ** on a per database connection basis using the @@ -695,6 +1523,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) @@ -722,6 +1553,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations @@ -776,10 +1608,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN -** flag indicate that a file cannot be deleted when open. The +** flag indicates that a file cannot be deleted when open. The ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. +** +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying +** filesystem supports doing multiple write operations atomically when those +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -795,6 +1632,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -926,6 +1764,10 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_ATOMIC64K] **
  • [SQLITE_IOCAP_SAFE_APPEND] **
  • [SQLITE_IOCAP_SEQUENTIAL] +**
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] +**
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] +**
  • [SQLITE_IOCAP_IMMUTABLE] +**
  • [SQLITE_IOCAP_BATCH_ATOMIC] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1054,7 +1896,7 @@ struct sqlite3_io_methods { ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two -** integers where the first integer i the new retry count and the second +** integers where the first integer is the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be @@ -1182,6 +2024,12 @@ struct sqlite3_io_methods { ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** +**
  • [[SQLITE_FCNTL_WIN32_GET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the +** underlying native file handle associated with a file handle. This file +** control interprets its argument as a pointer to a native file handle and +** writes the resulting value there. +** **
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This ** opcode causes the xFileControl method to swap the file handle with the one @@ -1203,6 +2051,40 @@ struct sqlite3_io_methods { ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for ** this opcode. +** +**
  • [[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then +** the file descriptor is placed in "batch write mode", which +** means all subsequent write operations will be deferred and done +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems +** that do not support batch atomic writes will return SQLITE_NOTFOUND. +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make +** no VFS interface calls on the same [sqlite3_file] file descriptor +** except for calls to the xWrite method and the xFileControl method +** with [SQLITE_FCNTL_SIZE_HINT]. +** +**
  • [[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. +** This file control returns [SQLITE_OK] if and only if the writes were +** all performed successfully and have been committed to persistent storage. +** ^Regardless of whether or not it is successful, this file control takes +** the file descriptor out of batch write mode so that all subsequent +** write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +**
  • [[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. +** ^This file control takes the file descriptor out of batch write mode +** so that all subsequent write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1232,6 +2114,11 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_RBU 26 #define SQLITE_FCNTL_VFS_POINTER 27 #define SQLITE_FCNTL_JOURNAL_POINTER 28 +#define SQLITE_FCNTL_WIN32_GET_HANDLE 29 +#define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1251,6 +2138,16 @@ struct sqlite3_io_methods { */ typedef struct sqlite3_mutex sqlite3_mutex; +/* +** CAPI3REF: Loadable Extension Thunk +** +** A pointer to the opaque sqlite3_api_routines structure is passed as +** the third parameter to entry points of [loadable extensions]. This +** structure must be typedefed in order to work around compiler warnings +** on some platforms. +*/ +typedef struct sqlite3_api_routines sqlite3_api_routines; + /* ** CAPI3REF: OS Interface Object ** @@ -1444,7 +2341,7 @@ struct sqlite3_vfs { const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. - ** New fields may be appended in figure versions. The iVersion + ** New fields may be appended in future versions. The iVersion ** value will increment whenever this happens. */ }; @@ -1586,10 +2483,10 @@ struct sqlite3_vfs { ** must return [SQLITE_OK] on success and some other [error code] upon ** failure. */ -SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void); -SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void); -SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void); -SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void); +SQLITE_API int sqlite3_initialize(void); +SQLITE_API int sqlite3_shutdown(void); +SQLITE_API int sqlite3_os_init(void); +SQLITE_API int sqlite3_os_end(void); /* ** CAPI3REF: Configuring The SQLite Library @@ -1622,7 +2519,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void); ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. */ -SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...); +SQLITE_API int sqlite3_config(int, ...); /* ** CAPI3REF: Configure database connections @@ -1641,7 +2538,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...); ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if ** the call is considered successful. */ -SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...); +SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); /* ** CAPI3REF: Memory Allocation Routines @@ -1792,6 +2689,16 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example. ** +** [[SQLITE_CONFIG_SMALL_MALLOC]]
    SQLITE_CONFIG_SMALL_MALLOC
    +**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +** type int, interpreted as a boolean, which if true provides a hint to +** SQLite that it should avoid large memory allocations if possible. +** SQLite will run faster if it is free to make large memory allocations, +** but some application might prefer to run slower in exchange for +** guarantees about memory fragmentation that are possible if large +** allocations are avoided. This hint is normally off. +**
    +** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    **
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of @@ -1809,25 +2716,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_CONFIG_SCRATCH]]
    SQLITE_CONFIG_SCRATCH
    -**
    ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte -** aligned memory buffer from which the scratch allocations will be -** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ -** The first argument must be a pointer to an 8-byte aligned buffer -** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional -** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.

    -** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. +**

    The SQLITE_CONFIG_SCRATCH option is no longer used. **
    ** ** [[SQLITE_CONFIG_PAGECACHE]]
    SQLITE_CONFIG_PAGECACHE
    @@ -1863,8 +2752,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_CONFIG_HEAP]]
    SQLITE_CONFIG_HEAP
    **
    ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and -** [SQLITE_CONFIG_PAGECACHE]. +** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. @@ -2036,6 +2924,20 @@ struct sqlite3_mem_methods { ** is enabled (using the [PRAGMA threads] command) and the amount of content ** to be sorted exceeds the page size times the minimum of the ** [PRAGMA cache_size] setting and this value. +** +** [[SQLITE_CONFIG_STMTJRNL_SPILL]] +**
    SQLITE_CONFIG_STMTJRNL_SPILL +**
    ^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which +** becomes the [statement journal] spill-to-disk threshold. +** [Statement journals] are held in memory until their size (in bytes) +** exceeds this threshold, at which point they are written to disk. +** Or if the threshold is -1, statement journals are always held +** exclusively in memory. +** Since many statement journals never become large, setting the spill +** threshold to a value such as 64KiB can greatly reduce the amount of +** I/O required to support statement rollback. +** The default value for this setting is controlled by the +** [SQLITE_STMTJRNL_SPILL] compile-time option. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -2043,7 +2945,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ @@ -2063,6 +2965,8 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ +#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2120,11 +3024,78 @@ 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
    +**
    ^This option is used to enable or disable the two-argument +** version of 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 +** positive to enable fts3_tokenizer() 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 fts3_tokenizer is disabled or enabled +** 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
    +**
    ^This option is used to enable or disable the [sqlite3_load_extension()] +** interface independently of the [load_extension()] SQL function. +** The [sqlite3_enable_load_extension()] API enables or disables both the +** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. +** There should be two additional arguments. +** When the first argument to this interface is 1, then only the C-API is +** enabled and the SQL function remains disabled. If the first argument to +** this interface is 0, then both the C-API and the SQL function are disabled. +** If the first argument is -1, then no changes are made to state of either the +** C-API or the SQL function. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface +** is disabled or enabled following this call. The second parameter may +** be a NULL pointer, in which case the new setting is not reported back. +**
    +** +**
    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 +** does not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into this DBCONFIG option is unchanged +** until after the database connection closes. +**
    +** +**
    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 +** connections at all to the database. If so, it performs a checkpoint +** operation before closing the connection. This option may be used to +** override this behaviour. The first parameter passed to this operation +** is an integer - non-zero to disable checkpoints-on-close, or zero (the +** default) to enable them. The second parameter is a pointer to an integer +** into which is written 0 or 1 to indicate whether checkpoints-on-close +** have been disabled - 0 if they are not disabled, 1 if they are. +**
    +** +**
    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 +** of values of [bound parameters].)^ The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +**
    +** ** */ -#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ -#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ -#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ +#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ /* @@ -2135,7 +3106,7 @@ struct sqlite3_mem_methods { ** [extended result codes] feature of SQLite. ^The extended result ** codes are disabled by default for historical compatibility. */ -SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff); +SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid @@ -2149,20 +3120,30 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff) ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** -** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the -** most recent successful [INSERT] into a rowid table or [virtual table] -** on database connection D. -** ^Inserts into [WITHOUT ROWID] tables are not recorded. -** ^If no successful [INSERT]s into rowid tables -** have ever occurred on the database connection D, -** then sqlite3_last_insert_rowid(D) returns zero. +** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of +** the most recent successful [INSERT] into a rowid table or [virtual table] +** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not +** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred +** on the database connection D, then sqlite3_last_insert_rowid(D) returns +** zero. ** -** ^(If an [INSERT] occurs within a trigger or within a [virtual table] -** method, then this routine will return the [rowid] of the inserted -** row as long as the trigger or virtual table method is running. -** But once the trigger or virtual table method ends, the value returned -** by this routine reverts to what it was before the trigger or virtual -** table method began.)^ +** As well as being set automatically as rows are inserted into database +** tables, the value returned by this function may be set explicitly by +** [sqlite3_set_last_insert_rowid()] +** +** Some virtual table implementations may INSERT rows into rowid tables as +** part of committing a transaction (e.g. to flush data accumulated in memory +** to disk). In this case subsequent calls to this function return the rowid +** associated with these internal INSERT operations, which leads to +** unintuitive results. Virtual table implementations that do write to rowid +** tables in this way can avoid this problem by restoring the original +** rowid value using [sqlite3_set_last_insert_rowid()] before returning +** control to the user. +** +** ^(If an [INSERT] occurs within a trigger then this routine will +** return the [rowid] of the inserted row as long as the trigger is +** running. Once the trigger program ends, the value returned +** by this routine reverts to what it was before the trigger was fired.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this @@ -2187,7 +3168,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff) ** unpredictable and might not equal either the old or the new ** last insert [rowid]. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + +/* +** CAPI3REF: Set the Last Insert Rowid value. +** METHOD: sqlite3 +** +** The sqlite3_set_last_insert_rowid(D, R) method allows the application to +** set the value returned by calling sqlite3_last_insert_rowid(D) to R +** without inserting a row into the database. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified @@ -2240,7 +3231,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*); ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. */ -SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*); +SQLITE_API int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified @@ -2264,7 +3255,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*); ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. */ -SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*); +SQLITE_API int sqlite3_total_changes(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query @@ -2300,11 +3291,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*); ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. -** -** If the database connection closes while [sqlite3_interrupt()] -** is running then bad things will likely happen. */ -SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*); +SQLITE_API void sqlite3_interrupt(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete @@ -2339,8 +3327,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*); ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ -SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql); -SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql); +SQLITE_API int sqlite3_complete(const char *sql); +SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors @@ -2401,7 +3389,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql); ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); +SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); /* ** CAPI3REF: Set A Busy Timeout @@ -2424,7 +3412,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), ** ** See also: [PRAGMA busy_timeout] */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms); +SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries @@ -2499,7 +3487,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms); ** reflected in subsequent calls to [sqlite3_errcode()] or ** [sqlite3_errmsg()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_get_table( +SQLITE_API int sqlite3_get_table( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ char ***pazResult, /* Results of the query */ @@ -2507,7 +3495,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table( int *pnColumn, /* Number of result columns written here */ char **pzErrmsg /* Error msg written here */ ); -SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result); +SQLITE_API void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions @@ -2613,10 +3601,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result); ** addition that after the string has been read and copied into ** the result, [sqlite3_free()] is called on the input string.)^ */ -SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...); -SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list); -SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...); -SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list); +SQLITE_API char *sqlite3_mprintf(const char*,...); +SQLITE_API char *sqlite3_vmprintf(const char*, va_list); +SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); +SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* ** CAPI3REF: Memory Allocation Subsystem @@ -2706,12 +3694,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list ** a block of memory after it has been released using ** [sqlite3_free()] or [sqlite3_realloc()]. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int); -SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64); -SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int); -SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64); -SQLITE_API void SQLITE_STDCALL sqlite3_free(void*); -SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*); +SQLITE_API void *sqlite3_malloc(int); +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); +SQLITE_API void *sqlite3_realloc(void*, int); +SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); +SQLITE_API void sqlite3_free(void*); +SQLITE_API sqlite3_uint64 sqlite3_msize(void*); /* ** CAPI3REF: Memory Allocator Statistics @@ -2736,8 +3724,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*); ** by [sqlite3_memory_highwater(1)] is the high-water mark ** prior to the reset. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag); +SQLITE_API sqlite3_int64 sqlite3_memory_used(void); +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); /* ** CAPI3REF: Pseudo-Random Number Generator @@ -2760,17 +3748,19 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag); ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ -SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); +SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** METHOD: sqlite3 +** KEYWORDS: {authorizer callback} ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], +** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should @@ -2792,8 +3782,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters -** to the callback are zero-terminated strings that contain additional -** details about the action to be authorized. +** to the callback are either NULL pointers or zero-terminated strings +** that contain additional details about the action to be authorized. +** Applications must always be prepared to encounter a NULL pointer in any +** of the third through the sixth parameters of the authorization callback. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the @@ -2802,6 +3794,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. +** ^When a table is referenced by a [SELECT] but no column values are +** extracted from that table (for example in a query like +** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback +** is invoked once for that table with a column name that is an empty string. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. @@ -2843,7 +3839,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); ** as stated in the previous paragraph, sqlite3_step() invokes ** sqlite3_prepare_v2() to reprepare a statement after a schema change. */ -SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( +SQLITE_API int sqlite3_set_authorizer( sqlite3*, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pUserData @@ -2923,6 +3919,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 ** +** These routines are deprecated. Use the [sqlite3_trace_v2()] interface +** instead of the routines described here. +** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** @@ -2948,10 +3947,104 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); -SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*, +SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); +/* +** CAPI3REF: SQL Trace Event Codes +** KEYWORDS: SQLITE_TRACE +** +** These constants identify classes of events that can be monitored +** using the [sqlite3_trace_v2()] tracing logic. The third argument +** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** the following constants. ^The first argument to the trace callback +** is one of the following constants. +** +** New tracing constants may be added in future releases. +** +** ^A trace callback has four arguments: xCallback(T,C,P,X). +** ^The T argument is one of the integer type codes above. +** ^The C argument is a copy of the context pointer passed in as the +** fourth argument to [sqlite3_trace_v2()]. +** The P and X arguments are pointers whose meanings depend on T. +** +**
    +** [[SQLITE_TRACE_STMT]]
    SQLITE_TRACE_STMT
    +**
    ^An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. ^The P argument is a pointer to the +** [prepared statement]. ^The X argument is a pointer to a string which +** is the unexpanded SQL text of the prepared statement or an SQL comment +** that indicates the invocation of a trigger. ^The callback can compute +** the same text that would have been returned by the legacy [sqlite3_trace()] +** interface by using the X argument when X begins with "--" and invoking +** [sqlite3_expanded_sql(P)] otherwise. +** +** [[SQLITE_TRACE_PROFILE]]
    SQLITE_TRACE_PROFILE
    +**
    ^An SQLITE_TRACE_PROFILE callback provides approximately the same +** information as is provided by the [sqlite3_profile()] callback. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. +** +** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    +**
    ^An SQLITE_TRACE_ROW callback is invoked whenever a prepared +** statement generates a single row of result. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument is unused. +** +** [[SQLITE_TRACE_CLOSE]]
    SQLITE_TRACE_CLOSE
    +**
    ^An SQLITE_TRACE_CLOSE callback is invoked when a database +** connection closes. +** ^The P argument is a pointer to the [database connection] object +** and the X argument is unused. +**
    +*/ +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + +/* +** CAPI3REF: SQL Trace Hook +** METHOD: sqlite3 +** +** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback +** function X against [database connection] D, using property mask M +** and context pointer P. ^If the X callback is +** NULL or if the M mask is zero, then tracing is disabled. The +** M argument should be the bitwise OR-ed combination of +** zero or more [SQLITE_TRACE] constants. +** +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). +** +** ^The X callback is invoked whenever any of the events identified by +** mask M occur. ^The integer return value from the callback is currently +** ignored, though this may change in future releases. Callback +** implementations should return zero to ensure future compatibility. +** +** ^A trace callback is invoked with four arguments: callback(T,C,P,X). +** ^The T argument is one of the [SQLITE_TRACE] +** constants to indicate why the callback was invoked. +** ^The C argument is a copy of the context pointer. +** The P and X arguments are pointers whose meanings depend on T. +** +** The sqlite3_trace_v2() interface is intended to replace the legacy +** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which +** are deprecated. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); + /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 @@ -2984,7 +4077,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*, ** database connections for the meaning of "modify" in this paragraph. ** */ -SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); +SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection @@ -3074,10 +4167,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the fourth argument to sqlite3_open_v2(), or if it has +** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** As of SQLite version 3.7.7, URI filename interpretation is turned off +** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. @@ -3213,15 +4306,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo ** ** See also: [sqlite3_temp_directory] */ -SQLITE_API int SQLITE_STDCALL sqlite3_open( +SQLITE_API int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_open16( +SQLITE_API int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_open_v2( +SQLITE_API int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ @@ -3267,9 +4360,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2( ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam); -SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64); +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); +SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); /* @@ -3313,11 +4406,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha ** was invoked incorrectly by the application. In that case, the ** error code and message may or may not be set. */ -SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db); -SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db); -SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*); -SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int); +SQLITE_API int sqlite3_errcode(sqlite3 *db); +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); +SQLITE_API const char *sqlite3_errmsg(sqlite3*); +SQLITE_API const void *sqlite3_errmsg16(sqlite3*); +SQLITE_API const char *sqlite3_errstr(int); /* ** CAPI3REF: Prepared Statement Object @@ -3385,7 +4478,7 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** ** New run-time limit categories may be added in future releases. */ -SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); +SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories @@ -3416,9 +4509,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_VDBE_OP]] ^(
    SQLITE_LIMIT_VDBE_OP
    **
    The maximum number of instructions in a virtual machine program -** used to implement an SQL statement. This limit is not currently -** enforced, though that might be added in some future release of -** SQLite.
    )^ +** used to implement an SQL statement. If [sqlite3_prepare_v2()] or +** the equivalent tries to allocate space for more than this many opcodes +** in a single prepared statement, an SQLITE_NOMEM error is returned.)^ ** ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
    SQLITE_LIMIT_FUNCTION_ARG
    **
    The maximum number of arguments on a function.
    )^ @@ -3456,23 +4549,59 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +/* +** CAPI3REF: Prepare Flags +** +** These constants define various flags that can be passed into +** "prepFlags" parameter of the [sqlite3_prepare_v3()] and +** [sqlite3_prepare16_v3()] interfaces. +** +** New flags may be added in future releases of SQLite. +** +**
    +** [[SQLITE_PREPARE_PERSISTENT]] ^(
    SQLITE_PREPARE_PERSISTENT
    +**
    The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner +** that the prepared statement will be retained for a long time and +** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] +** and [sqlite3_prepare16_v3()] assume that the prepared statement will +** be used just once or at most a few times and then destroyed using +** [sqlite3_finalize()] relatively soon. The current implementation acts +** 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. +**
    +*/ +#define SQLITE_PREPARE_PERSISTENT 0x01 + /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** -** To execute an SQL query, it must first be compiled into a byte-code -** program using one of these routines. +** To execute an SQL statement, it must first be compiled into a byte-code +** program using one of these routines. Or, in other words, these routines +** are constructors for the [prepared statement] object. +** +** The preferred routine to use is [sqlite3_prepare_v2()]. The +** [sqlite3_prepare()] interface is legacy and should be avoided. +** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used +** for special purposes. +** +** The use of the UTF-8 interfaces is preferred, as SQLite currently +** does all parsing using UTF-8. The UTF-16 interfaces are provided +** as a convenience. The UTF-16 interfaces work by converting the +** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() -** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() -** use UTF-16. +** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), +** and sqlite3_prepare_v3() +** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the @@ -3499,10 +4628,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** -** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are -** recommended for all new programs. The two older interfaces are retained -** for backwards compatibility, but their use is discouraged. -** ^In the "v2" interfaces, the prepared statement +** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. +** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) +** are retained for backwards compatibility, but their use is discouraged. +** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: @@ -3535,46 +4665,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. **
  • +** +**

    ^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having +** the extra prepFlags parameter, which is a bit array consisting of zero or +** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The +** sqlite3_prepare_v2() interface works exactly the same as +** sqlite3_prepare_v3() with a zero prepFlags parameter. ** */ -SQLITE_API int SQLITE_STDCALL sqlite3_prepare( +SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2( +SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_prepare16( +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2( +SQLITE_API int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** -** ^This interface can be used to retrieve a saved copy of the original -** SQL text used to create a [prepared statement] if that statement was -** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], +** [sqlite3_prepare16_v2()], or [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. +** +** ^(For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL".)^ +** +** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory +** is available to hold the result, or if the result would exceed the +** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** +** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of +** 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 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 *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -3605,8 +4782,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt); ** sqlite3_stmt_readonly() to return true since, while those statements ** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. +** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since +** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and +** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so +** sqlite3_stmt_readonly() returns false for those commands. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset @@ -3627,7 +4808,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt); ** for example, in diagnostic routines to search for prepared ** statements that are holding a transaction open. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*); +SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); /* ** CAPI3REF: Dynamically Typed Value Object @@ -3663,12 +4844,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*); ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used with -** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** Unprotected sqlite3_value objects may only be used as arguments +** to [sqlite3_result_value()], [sqlite3_bind_value()], and +** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ -typedef struct Mem sqlite3_value; +typedef struct sqlite3_value sqlite3_value; /* ** CAPI3REF: SQL Function Context Object @@ -3770,6 +4952,15 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** +** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in +** [prepared statement] S to have an SQL value of NULL, but to also be +** associated with the pointer P of type T. ^D is either a NULL pointer or +** a pointer to a destructor function for P. ^SQLite will invoke the +** destructor D with a single argument of P when it is finished using +** P. The T parameter should be a static string, preferably a string +** literal. The sqlite3_bind_pointer() routine is part of the +** [pointer passing interface] added for SQLite 3.20.0. +** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], @@ -3791,20 +4982,21 @@ typedef struct sqlite3_context sqlite3_context; ** See also: [sqlite3_bind_parameter_count()], ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, +SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, +SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); +SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); +SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); +SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); +SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); +SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); /* ** CAPI3REF: Number Of SQL Parameters @@ -3825,7 +5017,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite ** [sqlite3_bind_parameter_name()], and ** [sqlite3_bind_parameter_index()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*); +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); /* ** CAPI3REF: Name Of A Host Parameter @@ -3846,14 +5038,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*); ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()] or -** [sqlite3_prepare16_v2()]. +** originally specified as UTF-16 in [sqlite3_prepare16()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_index()]. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int); +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); /* ** CAPI3REF: Index Of A Parameter With A Given Name @@ -3864,13 +5056,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or +** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_name()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /* ** CAPI3REF: Reset All Bindings On A Prepared Statement @@ -3880,19 +5073,23 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const ** the [sqlite3_bind_blob | bindings] on a [prepared statement]. ** ^Use this routine to reset all host parameters to NULL. */ -SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*); +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); /* ** CAPI3REF: Number Of Columns In A Result Set ** METHOD: sqlite3_stmt ** ** ^Return the number of columns in the result set returned by the -** [prepared statement]. ^This routine returns 0 if pStmt is an SQL -** statement that does not return data (for example an [UPDATE]). +** [prepared statement]. ^If this routine returns 0, that means the +** [prepared statement] returns no data (for example an [UPDATE]). +** ^However, just because this routine returns a positive number does not +** mean that one or more rows of data will be returned. ^A SELECT statement +** will always have a positive sqlite3_column_count() but depending on the +** WHERE clause constraints and the table content, it might return no rows. ** ** See also: [sqlite3_data_count()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Column Names In A Result Set @@ -3921,8 +5118,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt); ** then the name of the column is unspecified and may change from ** one release of SQLite to the next. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N); +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); /* ** CAPI3REF: Source Of Data In A Query Result @@ -3970,12 +5167,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N ** for the same [prepared statement] and result column ** at the same time then the results are undefined. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int); -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int); -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); /* ** CAPI3REF: Declared Datatype Of A Query Result @@ -4007,23 +5204,25 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt* ** is associated with individual values, not with the containers ** used to hold those values. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); /* ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** -** After a [prepared statement] has been prepared using either -** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** After a [prepared statement] has been prepared using any of +** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], +** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "v2" interface -** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy -** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "v2" interface is recommended for new applications but the legacy +** on whether the statement was prepared using the newer "vX" interfaces +** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], +** [sqlite3_prepare16_v2()] or the older legacy +** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], @@ -4069,7 +5268,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility ** break because any application that ever receives an SQLITE_MISUSE error @@ -4083,12 +5283,13 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements -** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] +** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "v2" interface is recommended. +** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ -SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*); +SQLITE_API int sqlite3_step(sqlite3_stmt*); /* ** CAPI3REF: Number of columns in a result set @@ -4109,7 +5310,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*); ** ** See also: [sqlite3_column_count()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Fundamental Datatypes @@ -4148,6 +5349,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** +** Summary: +**

    +**
    sqlite3_column_blob→BLOB result +**
    sqlite3_column_double→REAL result +**
    sqlite3_column_int→32-bit INTEGER result +**
    sqlite3_column_int64→64-bit INTEGER result +**
    sqlite3_column_text→UTF-8 TEXT result +**
    sqlite3_column_text16→UTF-16 TEXT result +**
    sqlite3_column_value→The result as an +** [sqlite3_value|unprotected sqlite3_value] object. +**
        +**
    sqlite3_column_bytes→Size of a BLOB +** or a UTF-8 TEXT result in bytes +**
    sqlite3_column_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_column_type→Default +** datatype of the result +**
    +** +** Details: +** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] @@ -4169,16 +5392,29 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** +** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) +** each return the value of a result column in a specific data format. If +** the result column is not initially in the requested format (for example, +** if the query returns an integer but the sqlite3_column_text() interface +** is used to extract the value) then an automatic type conversion is performed. +** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value -** returned by sqlite3_column_type() is only meaningful if no type -** conversions have occurred as described below. After a type conversion, -** the value returned by sqlite3_column_type() is undefined. Future +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. +** The return value of sqlite3_column_type() can be used to decide which +** of the first six interface should be used to extract the column value. +** The value returned by sqlite3_column_type() is only meaningful if no +** automatic type conversions have occurred for the value in question. +** After a type conversion, the result of calling sqlite3_column_type() +** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** +** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() +** or sqlite3_column_bytes16() interfaces can be used to determine the size +** of that BLOB or string. +** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts @@ -4215,9 +5451,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** Hence, the sqlite3_column_value() interface +** is normally only useful within the implementation of +** [application-defined SQL functions] or [virtual tables], not within +** top-level application code. ** -** These routines attempt to convert the value where appropriate. ^For -** example, if the internal representation is FLOAT and a text result +** The these routines may attempt to convert the datatype of the result. +** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: @@ -4289,7 +5529,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do not pass the pointers returned +** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** @@ -4299,16 +5539,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** pointer. Subsequent calls to [sqlite3_errcode()] will return ** [SQLITE_NOMEM].)^ */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol); -SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol); -SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol); -SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); +SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object @@ -4336,7 +5576,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int ** statement after it has been finalized can result in undefined and ** undesirable behavior such as segfaults and heap corruption. */ -SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); /* ** CAPI3REF: Reset A Prepared Statement Object @@ -4363,7 +5603,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt); ** ^The [sqlite3_reset(S)] interface does not change the values ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ -SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions @@ -4463,7 +5703,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt); ** close the database connection nor finalize or reset the prepared ** statement in which the function is running. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_function( +SQLITE_API int sqlite3_create_function( sqlite3 *db, const char *zFunctionName, int nArg, @@ -4473,7 +5713,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function( void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( +SQLITE_API int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, @@ -4483,7 +5723,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( +SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunctionName, int nArg, @@ -4529,12 +5769,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( ** these functions, we will not explain what they do. */ #ifndef SQLITE_OMIT_DEPRECATED -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void); -SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), +SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); +SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), void*,sqlite3_int64); #endif @@ -4542,21 +5782,40 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** -** The C-language implementation of SQL functions and aggregates uses -** this set of interface routines to access the parameter values on -** the function or aggregate. +** Summary: +**
    +**
    sqlite3_value_blob→BLOB value +**
    sqlite3_value_double→REAL value +**
    sqlite3_value_int→32-bit INTEGER value +**
    sqlite3_value_int64→64-bit INTEGER value +**
    sqlite3_value_pointer→Pointer value +**
    sqlite3_value_text→UTF-8 TEXT value +**
    sqlite3_value_text16→UTF-16 TEXT value in +** the native byteorder +**
    sqlite3_value_text16be→UTF-16be TEXT value +**
    sqlite3_value_text16le→UTF-16le TEXT value +**
        +**
    sqlite3_value_bytes→Size of a BLOB +** or a UTF-8 TEXT in bytes +**
    sqlite3_value_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_value_type→Default +** datatype of the value +**
    sqlite3_value_numeric_type   +** →  Best numeric datatype of the value +**
    ** -** The xFunc (for scalar functions) or xStep (for aggregates) parameters -** to [sqlite3_create_function()] and [sqlite3_create_function16()] -** define callbacks that implement the SQL functions and aggregates. -** The 3rd parameter to these callbacks is an array of pointers to -** [protected sqlite3_value] objects. There is one [sqlite3_value] object for -** each parameter to the SQL function. These routines are used to -** extract values from the [sqlite3_value] objects. +** Details: +** +** These routines extract type, size, and content information from +** [protected sqlite3_value] objects. Protected sqlite3_value objects +** are used to pass parameter information into implementation of +** [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] -** object results in undefined behavior. +** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object @@ -4567,6 +5826,24 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** +** ^If [sqlite3_value] object V was initialized +** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] +** and if X and Y are strings that compare equal according to strcmp(X,Y), +** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, +** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** +** ^(The sqlite3_value_type(V) interface returns the +** [SQLITE_INTEGER | datatype code] for the initial datatype of the +** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ +** Other interfaces might change the datatype for an sqlite3_value object. +** For example, if the datatype is initially SQLITE_INTEGER and +** sqlite3_value_text(V) is called to extract a text value for that +** integer, then subsequent calls to sqlite3_value_type(V) might return +** SQLITE_TEXT. Whether or not a persistent internal datatype conversion +** occurs is undefined and may change from one release of SQLite to the next. +** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If @@ -4584,18 +5861,19 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*); -SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*); -SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*); +SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); +SQLITE_API double sqlite3_value_double(sqlite3_value*); +SQLITE_API int sqlite3_value_int(sqlite3_value*); +SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +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*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -4606,12 +5884,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** SQLite makes no use of subtype itself. It merely passes the subtype -** from the result of one [application-defined SQL function] into the -** input of another. */ -SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*); +SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values @@ -4627,8 +5901,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*); ** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer ** then sqlite3_value_free(V) is a harmless no-op. */ -SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*); -SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*); +SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*); +SQLITE_API void sqlite3_value_free(sqlite3_value*); /* ** CAPI3REF: Obtain Aggregate Function Context @@ -4673,7 +5947,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*); ** This routine must be called from the same thread in which ** the aggregate SQL function is running. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes); +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /* ** CAPI3REF: User Data For Functions @@ -4688,7 +5962,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int ** This routine must be called from the same thread in which ** the application-defined function is running. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*); +SQLITE_API void *sqlite3_user_data(sqlite3_context*); /* ** CAPI3REF: Database Connection For Functions @@ -4700,7 +5974,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*); ** and [sqlite3_create_function16()] routines that originally ** registered the application defined function. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data @@ -4717,10 +5991,11 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata -** associated by the sqlite3_set_auxdata() function with the Nth argument -** value to the application-defined function. ^If there is no metadata -** associated with the function argument, this sqlite3_get_auxdata() interface +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument +** value to the application-defined function. ^N is zero for the left-most +** function argument. ^If there is no metadata +** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th @@ -4732,12 +6007,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including:
      -**
    • when the corresponding function parameter changes, or -**
    • when [sqlite3_reset()] or [sqlite3_finalize()] is called for the -** SQL statement, or -**
    • when sqlite3_set_auxdata() is invoked again on the same parameter, or -**
    • during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.
    )^ +**
  • ^(when the corresponding function parameter changes)^, or +**
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement)^, or +**
  • ^(when sqlite3_set_auxdata() is invoked again on the same +** parameter)^, or +**
  • ^(during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs.)^ ** ** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the @@ -4750,11 +6026,15 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** +** The value of the N parameter to these interfaces should be non-negative. +** Future enhancements may make use of negative N values to define new +** kinds of function caching behavior. +** ** These routines must be called from the same thread in which ** the SQL function is running. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N); -SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); +SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); /* @@ -4873,7 +6153,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained from +** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^The sqlite3_result_value() interface sets the result of @@ -4886,31 +6166,43 @@ typedef void (*sqlite3_destructor_type)(void*); ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** +** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an +** SQL NULL value, just like [sqlite3_result_null(C)], except that it +** also associates the host-language pointer P or type T with that +** NULL value such that the pointer can be retrieved within an +** [application-defined SQL function] using [sqlite3_value_pointer()]. +** ^If the D parameter is not NULL, then it is a pointer to a destructor +** for the P parameter. ^SQLite invokes D with P as its only argument +** when SQLite is finished with P. The T parameter should be a static +** string and preferably a string literal. The sqlite3_result_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*, +SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, sqlite3_uint64,void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64); -SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_double(sqlite3_context*, double); +SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); +SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); +SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); +SQLITE_API void sqlite3_result_null(sqlite3_context*); +SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, void(*)(void*), unsigned char encoding); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n); -SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); +SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); +SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); /* @@ -4925,7 +6217,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int); +SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences @@ -5007,14 +6299,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned ** ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_collation( +SQLITE_API int sqlite3_create_collation( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2( +SQLITE_API int sqlite3_create_collation_v2( sqlite3*, const char *zName, int eTextRep, @@ -5022,7 +6314,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2( int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16( +SQLITE_API int sqlite3_create_collation16( sqlite3*, const void *zName, int eTextRep, @@ -5057,12 +6349,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16( ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or ** [sqlite3_create_collation_v2()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed( +SQLITE_API int sqlite3_collation_needed( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16( +SQLITE_API int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) @@ -5076,11 +6368,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16( ** The code to implement this API is not available in the public release ** of SQLite. */ -SQLITE_API int SQLITE_STDCALL sqlite3_key( +SQLITE_API int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_key_v2( +SQLITE_API int sqlite3_key_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The key */ @@ -5094,11 +6386,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2( ** The code to implement this API is not available in the public release ** of SQLite. */ -SQLITE_API int SQLITE_STDCALL sqlite3_rekey( +SQLITE_API int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2( +SQLITE_API int sqlite3_rekey_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The new key */ @@ -5108,7 +6400,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2( ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ -SQLITE_API void SQLITE_STDCALL sqlite3_activate_see( +SQLITE_API void sqlite3_activate_see( const char *zPassPhrase /* Activation phrase */ ); #endif @@ -5118,7 +6410,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see( ** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ -SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod( +SQLITE_API void sqlite3_activate_cerod( const char *zPassPhrase /* Activation phrase */ ); #endif @@ -5140,7 +6432,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod( ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. */ -SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int); +SQLITE_API int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files @@ -5259,7 +6551,7 @@ SQLITE_API char *sqlite3_data_directory; ** connection while this routine is running, then the return value ** is undefined. */ -SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*); +SQLITE_API int sqlite3_get_autocommit(sqlite3*); /* ** CAPI3REF: Find The Database Handle Of A Prepared Statement @@ -5272,7 +6564,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*); ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to ** create the statement in the first place. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*); +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Return The Filename For A Database Connection @@ -5289,7 +6581,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*); ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName); +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only @@ -5299,7 +6591,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha ** of connection D is read-only, 0 if it is read/write, or -1 if N is not ** the name of a database on connection D. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement @@ -5315,7 +6607,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa ** [sqlite3_next_stmt(D,S)] must refer to an open database ** connection and in particular must not be a NULL pointer. */ -SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); /* ** CAPI3REF: Commit And Rollback Notification Callbacks @@ -5364,8 +6656,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_ ** ** See also the [sqlite3_update_hook()] interface. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); -SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); +SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks @@ -5374,7 +6666,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument ** to be invoked whenever a row is updated, inserted or deleted in -** a rowid table. +** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** @@ -5395,7 +6687,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook -** is not invoked when duplication rows are deleted because of an +** is not invoked when conflicting rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future @@ -5413,10 +6705,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), ** on the same [database connection] D, or NULL for ** the first call on D. ** -** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()] -** interfaces. +** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], +** and [sqlite3_preupdate_hook()] interfaces. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( +SQLITE_API void *sqlite3_update_hook( sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* @@ -5431,7 +6723,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. -** This is a change as of SQLite version 3.5.0. In prior versions of SQLite, +** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). +** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent @@ -5456,7 +6749,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( ** ** See Also: [SQLite Shared-Cache Mode] */ -SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int); +SQLITE_API int sqlite3_enable_shared_cache(int); /* ** CAPI3REF: Attempt To Free Heap Memory @@ -5472,7 +6765,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int); ** ** See also: [sqlite3_db_release_memory()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int); +SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection @@ -5486,7 +6779,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int); ** ** See also: [sqlite3_release_memory()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*); +SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size @@ -5525,7 +6818,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*); ** from the heap. ** )^ ** -** Beginning with SQLite version 3.7.3, the soft heap limit is enforced +** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), +** the soft heap limit is enforced ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] ** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], ** the soft heap limit is enforced on every memory allocation. Without @@ -5538,7 +6832,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*); ** The circumstances under which SQLite will enforce the soft heap limit may ** changes in future releases of SQLite. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N); +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface @@ -5549,7 +6843,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 ** only. All new applications should use the ** [sqlite3_soft_heap_limit64()] interface rather than this one. */ -SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N); +SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* @@ -5564,9 +6858,11 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N); ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a -** NULL pointer, then this routine simply checks for the existance of the +** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. +** does not. If the table name parameter T in a call to +** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is +** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -5619,7 +6915,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N); ** parsed, if that has not already been done, and returns an error if ** any errors are encountered while loading the schema. */ -SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata( +SQLITE_API int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ const char *zTableName, /* Table name */ @@ -5661,12 +6957,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata( ** should free this memory by calling [sqlite3_free()]. ** ** ^Extension loading must be enabled using -** [sqlite3_enable_load_extension()] prior to calling this API, +** [sqlite3_enable_load_extension()] or +** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) +** prior to calling this API, ** otherwise an error will be returned. ** +** Security warning: It is recommended that the +** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this +** interface. The use of the [sqlite3_enable_load_extension()] interface +** should be avoided. This will keep the SQL function [load_extension()] +** disabled and prevent SQL injections from giving attackers +** access to extension loading capabilities. +** ** See also the [load_extension() SQL function]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_load_extension( +SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Derived from zFile if 0 */ @@ -5686,8 +6991,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension( ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. +** +** ^This interface enables or disables both the C-API +** [sqlite3_load_extension()] and the SQL function [load_extension()]. +** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) +** to enable or disable only the C-API.)^ +** +** Security warning: It is recommended that extension loading +** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method +** rather than this interface, so the [load_extension()] SQL function +** remains disabled. This will prevent SQL injections from giving attackers +** access to extension loading capabilities. */ -SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff); +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* ** CAPI3REF: Automatically Load Statically Linked Extensions @@ -5699,7 +7015,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three -** arguments and expects and integer result as if the signature of the +** arguments and expects an integer result as if the signature of the ** entry point where as follows: ** **
    @@ -5725,7 +7041,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
     ** See also: [sqlite3_reset_auto_extension()]
     ** and [sqlite3_cancel_auto_extension()]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Cancel Automatic Extension Loading
    @@ -5737,7 +7053,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
     ** unregistered and it returns 0 if X was not on the list of initialization
     ** routines.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Reset Automatic Extension Loading
    @@ -5745,7 +7061,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
     ** ^This interface disables all automatic extensions previously
     ** registered using [sqlite3_auto_extension()].
     */
    -SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
    +SQLITE_API void sqlite3_reset_auto_extension(void);
     
     /*
     ** The interface to the virtual-table mechanism is currently considered
    @@ -5899,13 +7215,15 @@ struct sqlite3_module {
     ** the xUpdate method are automatically rolled back by SQLite.
     **
     ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
    -** structure for SQLite version 3.8.2. If a virtual table extension is
    +** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
    +** If a virtual table extension is
     ** used with an SQLite version earlier than 3.8.2, the results of attempting 
     ** to read or write the estimatedRows field are undefined (but are likely 
     ** to included crashing the application). The estimatedRows field should
     ** therefore only be used if [sqlite3_libversion_number()] returns a
     ** value greater than or equal to 3008002. Similarly, the idxFlags field
    -** was added for version 3.9.0. It may therefore only be used if
    +** was added for [version 3.9.0] ([dateof:3.9.0]). 
    +** It may therefore only be used if
     ** sqlite3_libversion_number() returns a value greater than or equal to
     ** 3009000.
     */
    @@ -5913,7 +7231,7 @@ struct sqlite3_index_info {
       /* Inputs */
       int nConstraint;           /* Number of entries in aConstraint */
       struct sqlite3_index_constraint {
    -     int iColumn;              /* Column on left-hand side of constraint */
    +     int iColumn;              /* Column constrained.  -1 for ROWID */
          unsigned char op;         /* Constraint operator */
          unsigned char usable;     /* True if this constraint is usable */
          int iTermOffset;          /* Used internally - xBestIndex should ignore */
    @@ -5954,15 +7272,20 @@ struct sqlite3_index_info {
     ** an operator that is part of a constraint term in the wHERE clause of
     ** a query that uses a [virtual table].
     */
    -#define SQLITE_INDEX_CONSTRAINT_EQ      2
    -#define SQLITE_INDEX_CONSTRAINT_GT      4
    -#define SQLITE_INDEX_CONSTRAINT_LE      8
    -#define SQLITE_INDEX_CONSTRAINT_LT     16
    -#define SQLITE_INDEX_CONSTRAINT_GE     32
    -#define SQLITE_INDEX_CONSTRAINT_MATCH  64
    -#define SQLITE_INDEX_CONSTRAINT_LIKE   65
    -#define SQLITE_INDEX_CONSTRAINT_GLOB   66
    -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
    +#define SQLITE_INDEX_CONSTRAINT_EQ         2
    +#define SQLITE_INDEX_CONSTRAINT_GT         4
    +#define SQLITE_INDEX_CONSTRAINT_LE         8
    +#define SQLITE_INDEX_CONSTRAINT_LT        16
    +#define SQLITE_INDEX_CONSTRAINT_GE        32
    +#define SQLITE_INDEX_CONSTRAINT_MATCH     64
    +#define SQLITE_INDEX_CONSTRAINT_LIKE      65
    +#define SQLITE_INDEX_CONSTRAINT_GLOB      66
    +#define SQLITE_INDEX_CONSTRAINT_REGEXP    67
    +#define SQLITE_INDEX_CONSTRAINT_NE        68
    +#define SQLITE_INDEX_CONSTRAINT_ISNOT     69
    +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
    +#define SQLITE_INDEX_CONSTRAINT_ISNULL    71
    +#define SQLITE_INDEX_CONSTRAINT_IS        72
     
     /*
     ** CAPI3REF: Register A Virtual Table Implementation
    @@ -5990,13 +7313,13 @@ struct sqlite3_index_info {
     ** interface is equivalent to sqlite3_create_module_v2() with a NULL
     ** destructor.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    +SQLITE_API int sqlite3_create_module(
       sqlite3 *db,               /* SQLite connection to register module with */
       const char *zName,         /* Name of the module */
       const sqlite3_module *p,   /* Methods for the module */
       void *pClientData          /* Client data for xCreate/xConnect */
     );
    -SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    +SQLITE_API int sqlite3_create_module_v2(
       sqlite3 *db,               /* SQLite connection to register module with */
       const char *zName,         /* Name of the module */
       const sqlite3_module *p,   /* Methods for the module */
    @@ -6059,7 +7382,7 @@ struct sqlite3_vtab_cursor {
     ** to declare the format (the names and datatypes of the columns) of
     ** the virtual tables they implement.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    +SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
     
     /*
     ** CAPI3REF: Overload A Function For A Virtual Table
    @@ -6078,7 +7401,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
     ** purpose is to be a placeholder function that can be overloaded
     ** by a [virtual table].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    +SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
     
     /*
     ** The interface to the virtual-table mechanism defined above (back up
    @@ -6153,6 +7476,12 @@ typedef struct sqlite3_blob sqlite3_blob;
     ** [database connection] error code and message accessible via 
     ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
     **
    +** A BLOB referenced by sqlite3_blob_open() may be read using the
    +** [sqlite3_blob_read()] interface and modified by using
    +** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
    +** different row of the same table using the [sqlite3_blob_reopen()]
    +** interface.  However, the column, table, or database of a [BLOB handle]
    +** cannot be changed after the [BLOB handle] is opened.
     **
     ** ^(If the row that a BLOB handle points to is modified by an
     ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
    @@ -6176,8 +7505,12 @@ typedef struct sqlite3_blob sqlite3_blob;
     **
     ** To avoid a resource leak, every open [BLOB handle] should eventually
     ** be released by a call to [sqlite3_blob_close()].
    +**
    +** See also: [sqlite3_blob_close()],
    +** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
    +** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    +SQLITE_API int sqlite3_blob_open(
       sqlite3*,
       const char *zDb,
       const char *zTable,
    @@ -6191,11 +7524,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
     ** CAPI3REF: Move a BLOB Handle to a New Row
     ** METHOD: sqlite3_blob
     **
    -** ^This function is used to move an existing blob handle so that it points
    +** ^This function is used to move an existing [BLOB handle] so that it points
     ** to a different row of the same database table. ^The new row is identified
     ** by the rowid value passed as the second argument. Only the row can be
     ** changed. ^The database, table and column on which the blob handle is open
    -** remain the same. Moving an existing blob handle to a new row can be
    +** remain the same. Moving an existing [BLOB handle] to a new row is
     ** faster than closing the existing handle and opening a new one.
     **
     ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
    @@ -6210,7 +7543,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
     **
     ** ^This function sets the database handle error code and message.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    +SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
     
     /*
     ** CAPI3REF: Close A BLOB Handle
    @@ -6233,7 +7566,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
     ** is passed a valid open blob handle, the values returned by the 
     ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    +SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
     
     /*
     ** CAPI3REF: Return The Size Of An Open BLOB
    @@ -6249,7 +7582,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
     ** been closed by [sqlite3_blob_close()].  Passing any other pointer in
     ** to this routine results in undefined and probably undesirable behavior.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
     
     /*
     ** CAPI3REF: Read Data From A BLOB Incrementally
    @@ -6278,7 +7611,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
     **
     ** See also: [sqlite3_blob_write()].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    +SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
     
     /*
     ** CAPI3REF: Write Data Into A BLOB Incrementally
    @@ -6320,7 +7653,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
     **
     ** See also: [sqlite3_blob_read()].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    +SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
     
     /*
     ** CAPI3REF: Virtual File System Objects
    @@ -6351,9 +7684,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
     ** ^(If the default VFS is unregistered, another VFS is chosen as
     ** the default.  The choice for the new VFS is arbitrary.)^
     */
    -SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
    -SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    -SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
    +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
     
     /*
     ** CAPI3REF: Mutexes
    @@ -6469,11 +7802,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
     **
     ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
     */
    -SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
    -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
    -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
    -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
    -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
    +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
    +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
    +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
    +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
    +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
     
     /*
     ** CAPI3REF: Mutex Methods Object
    @@ -6583,8 +7916,8 @@ struct sqlite3_mutex_methods {
     ** interface should also return 1 when given a NULL pointer.
     */
     #ifndef NDEBUG
    -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
    -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
    +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
     #endif
     
     /*
    @@ -6603,7 +7936,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
     #define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
     #define SQLITE_MUTEX_STATIC_MEM2      4  /* NOT USED */
     #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
    -#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
    +#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_randomness() */
     #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
     #define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
     #define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
    @@ -6624,7 +7957,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
     ** ^If the [threading mode] is Single-thread or Multi-thread then this
     ** routine returns a NULL pointer.
     */
    -SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
     
     /*
     ** CAPI3REF: Low-Level Control Of Database Files
    @@ -6659,7 +7992,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
     **
     ** See also: [SQLITE_FCNTL_LOCKSTATE]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    +SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
     
     /*
     ** CAPI3REF: Testing Interface
    @@ -6678,7 +8011,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
     ** Unlike most of the SQLite API, this function is not guaranteed to
     ** operate consistently from one release to the next.
     */
    -SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    +SQLITE_API int sqlite3_test_control(int op, ...);
     
     /*
     ** CAPI3REF: Testing Interface Operation Codes
    @@ -6704,9 +8037,10 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
     #define SQLITE_TESTCTRL_RESERVE                 14
     #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
     #define SQLITE_TESTCTRL_ISKEYWORD               16
    -#define SQLITE_TESTCTRL_SCRATCHMALLOC           17
    +#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
     #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
     #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
    +#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
     #define SQLITE_TESTCTRL_NEVER_CORRUPT           20
     #define SQLITE_TESTCTRL_VDBE_COVERAGE           21
     #define SQLITE_TESTCTRL_BYTEORDER               22
    @@ -6741,8 +8075,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
     **
     ** See also: [sqlite3_db_status()]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    -SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    +SQLITE_API int sqlite3_status64(
       int op,
       sqlite3_int64 *pCurrent,
       sqlite3_int64 *pHighwater,
    @@ -6762,8 +8096,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
     ** 
    This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application -** and internal memory usage by the SQLite library. Scratch memory -** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
    )^ @@ -6801,29 +8134,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.)^ ** -** [[SQLITE_STATUS_SCRATCH_USED]] ^(
    SQLITE_STATUS_SCRATCH_USED
    -**
    This parameter returns the number of allocations used out of the -** [scratch memory allocator] configured using -** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not -** in bytes. Since a single thread may only have one scratch allocation -** outstanding at time, this parameter also reports the number of threads -** using scratch memory at the same time.
    )^ +** [[SQLITE_STATUS_SCRATCH_USED]]
    SQLITE_STATUS_SCRATCH_USED
    +**
    No longer used.
    ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
    SQLITE_STATUS_SCRATCH_OVERFLOW
    -**
    This parameter returns the number of bytes of scratch memory -** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] -** buffer and where forced to overflow to [sqlite3_malloc()]. The values -** returned include overflows because the requested allocation was too -** larger (that is, because the requested allocation was larger than the -** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer -** slots were available. -**
    )^ +**
    No longer used.
    ** -** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
    SQLITE_STATUS_SCRATCH_SIZE
    -**
    This parameter records the largest memory allocation request -** handed to [scratch memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. -** The value written into the *pCurrent parameter is undefined.
    )^ +** [[SQLITE_STATUS_SCRATCH_SIZE]]
    SQLITE_STATUS_SCRATCH_SIZE
    +**
    No longer used.
    ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(
    SQLITE_STATUS_PARSER_STACK
    **
    The *pHighwater parameter records the deepest parser stack. @@ -6836,12 +8154,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* @@ -6867,7 +8185,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( ** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); +SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections @@ -6913,6 +8231,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** ^(
    SQLITE_DBSTATUS_CACHE_USED_SHARED
    +**
    This parameter is similar to DBSTATUS_CACHE_USED, except that if a +** pager cache is shared between two or more connections the bytes of heap +** memory used by that pager cache is divided evenly between the attached +** connections.)^ In other words, if none of the pager caches associated +** with the database connection are shared, this request returns the same +** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** shared, the value returned by this call will be smaller than that returned +** by DBSTATUS_CACHE_USED. ^The highwater mark associated with +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated @@ -6970,7 +8300,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 -#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ /* @@ -6997,7 +8328,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int ** ** See also: [sqlite3_status()] and [sqlite3_db_status()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements @@ -7033,6 +8364,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. +** +** [[SQLITE_STMTSTATUS_REPREPARE]]
    SQLITE_STMTSTATUS_REPREPARE
    +**
    ^This is the number of times that the prepare statement has been +** automatically regenerated due to schema changes or change to +** [bound parameters] that might affect the query plan. +** +** [[SQLITE_STMTSTATUS_RUN]]
    SQLITE_STMTSTATUS_RUN
    +**
    ^This is the number of times that the prepared statement has +** been run. A single "run" for the purposes of this counter is one +** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. +** The counter is incremented on the first [sqlite3_step()] call of each +** cycle. +** +** [[SQLITE_STMTSTATUS_MEMUSED]]
    SQLITE_STMTSTATUS_MEMUSED
    +**
    ^This is the approximate number of bytes of heap memory +** used to store the prepared statement. ^This value is not actually +** a counter, and so the resetFlg parameter to sqlite3_stmt_status() +** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. **
    ** */ @@ -7040,6 +8389,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object @@ -7324,7 +8676,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** -** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if +** ^A call to sqlite3_backup_init() will fail, returning NULL, if ** there is already a read or read-write transaction open on the ** destination database. ** @@ -7466,16 +8818,16 @@ typedef struct sqlite3_backup sqlite3_backup; ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. */ -SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init( +SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ const char *zDestName, /* Destination database name */ sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** CAPI3REF: Unlock Notification @@ -7592,7 +8944,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p); ** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED.)^ */ -SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify( +SQLITE_API int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ @@ -7607,8 +8959,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify( ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *); -SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int); +SQLITE_API int sqlite3_stricmp(const char *, const char *); +SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: String Globbing @@ -7625,7 +8977,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int); ** ** See also: [sqlite3_strlike()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr); +SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); /* ** CAPI3REF: String LIKE Matching @@ -7648,7 +9000,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt ** ** See also: [sqlite3_strglob()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); +SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); /* ** CAPI3REF: Error Logging Interface @@ -7671,7 +9023,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zSt ** a few hundred characters, it will be truncated to the length of the ** buffer. */ -SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...); +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); /* ** CAPI3REF: Write-Ahead Log Commit Hook @@ -7705,9 +9057,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...) ** previously registered write-ahead log callback. ^Note that the ** [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will -** those overwrite any prior [sqlite3_wal_hook()] settings. +** overwrite any prior [sqlite3_wal_hook()] settings. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook( +SQLITE_API void *sqlite3_wal_hook( sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* @@ -7742,7 +9094,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook( ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N); +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database @@ -7764,7 +9116,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** start a callback but which do not need the full power (and corresponding ** complication) of [sqlite3_wal_checkpoint_v2()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Checkpoint a database @@ -7858,7 +9210,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface ** from SQL. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( +SQLITE_API int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of attached database (or NULL) */ int eMode, /* SQLITE_CHECKPOINT_* value */ @@ -7894,7 +9246,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options ** may be added in the future. */ -SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...); +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options @@ -7947,7 +9299,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...); ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *); +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes @@ -8052,7 +9404,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *); ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus( +SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ @@ -8068,7 +9420,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus( ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ -SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); +SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction @@ -8100,11 +9452,125 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); ** ^This function does not set the database handle error code or message ** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*); +SQLITE_API int sqlite3_db_cacheflush(sqlite3*); + +/* +** CAPI3REF: The pre-update hook. +** +** ^These interfaces are only available if SQLite is compiled using the +** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. +** +** ^The [sqlite3_preupdate_hook()] interface registers a callback function +** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation +** on a database table. +** ^At most one preupdate hook may be registered at a time on a single +** [database connection]; each call to [sqlite3_preupdate_hook()] overrides +** the previous setting. +** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] +** with a NULL pointer as the second parameter. +** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as +** the first parameter to callbacks. +** +** ^The preupdate hook only fires for changes to real database tables; the +** preupdate hook is not invoked for changes to [virtual tables] or to +** system tables like sqlite_master or sqlite_stat1. +** +** ^The second parameter to the preupdate callback is a pointer to +** the [database connection] that registered the preupdate hook. +** ^The third parameter to the preupdate callback is one of the constants +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the +** kind of update operation that is about to occur. +** ^(The fourth parameter to the preupdate callback is the name of the +** database within the database connection that is being modified. This +** will be "main" for the main database or "temp" for TEMP tables or +** the name given after the AS keyword in the [ATTACH] statement for attached +** databases.)^ +** ^The fifth parameter to the preupdate callback is the name of the +** table that is being modified. +** +** For an UPDATE or DELETE operation on a [rowid table], the sixth +** parameter passed to the preupdate callback is the initial [rowid] of the +** row being modified or deleted. For an INSERT operation on a rowid table, +** or any operation on a WITHOUT ROWID table, the value of the sixth +** parameter is undefined. For an INSERT or UPDATE on a rowid table the +** seventh parameter is the final rowid value of the row being inserted +** or updated. The value of the seventh parameter passed to the callback +** function is not defined for operations on WITHOUT ROWID tables, or for +** INSERT operations on rowid tables. +** +** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], +** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces +** provide additional information about a preupdate event. These routines +** may only be called from within a preupdate callback. Invoking any of +** these routines from outside of a preupdate callback or with a +** [database connection] pointer that is different from the one supplied +** to the preupdate callback results in undefined and probably undesirable +** behavior. +** +** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns +** in the row that is being inserted, updated, or deleted. +** +** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row before it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE +** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row after it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE +** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate +** callback was invoked as a result of a direct insert, update, or delete +** operation; or 1 for inserts, updates, or deletes invoked by top-level +** triggers; or 2 for changes resulting from triggers called by top-level +** triggers; and so forth. +** +** See also: [sqlite3_update_hook()] +*/ +#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void* +); +SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_count(sqlite3 *); +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); +SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +#endif + +/* +** CAPI3REF: Low-level system error code +** +** ^Attempt to return the underlying operating system error code or error +** number that caused the most recent I/O error or failure to open a file. +** The return value is OS-dependent. For example, on unix systems, after +** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be +** called to get back the underlying "errno" that caused the problem, such +** as ENOSPC, EAUTH, EISDIR, and so forth. +*/ +SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot -** KEYWORDS: {snapshot} +** KEYWORDS: {snapshot} {sqlite3_snapshot} ** EXPERIMENTAL ** ** An instance of the snapshot object records the state of a [WAL mode] @@ -8128,7 +9594,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*); ** to an historical snapshot (if possible). The destructor for ** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. */ -typedef struct sqlite3_snapshot sqlite3_snapshot; +typedef struct sqlite3_snapshot { + unsigned char hidden[48]; +} sqlite3_snapshot; /* ** CAPI3REF: Record A Database Snapshot @@ -8139,9 +9607,32 @@ typedef struct sqlite3_snapshot sqlite3_snapshot; ** schema S in database connection D. ^On success, the ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. -** ^If schema S of [database connection] D is not a [WAL mode] database -** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)] -** leaves the *P value unchanged and returns an appropriate [error code]. +** If there is not already a read-transaction open on schema S when +** this function is called, one is opened automatically. +** +** The following must be true for this function to succeed. If any of +** the following statements are false when sqlite3_snapshot_get() is +** called, SQLITE_ERROR is returned. The final value of *P is undefined +** in this case. +** +**
      +**
    • The database handle must be in [autocommit mode]. +** +**
    • Schema S of [database connection] D must be a [WAL mode] database. +** +**
    • There must not be a write transaction open on schema S of database +** connection D. +** +**
    • One or more transactions must have been written to the current wal +** file since it was created on disk (by any connection). This means +** that a snapshot cannot be taken on a wal mode database with no wal +** file immediately after it is first opened. At least one transaction +** must be written to it first. +**
    +** +** This function may also return SQLITE_NOMEM. If it is called with the +** database handle in autocommit mode but fails for some other reason, +** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] @@ -8150,7 +9641,7 @@ typedef struct sqlite3_snapshot sqlite3_snapshot; ** The [sqlite3_snapshot_get()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get( +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot @@ -8160,22 +9651,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get( ** CAPI3REF: Start a read transaction on an historical snapshot ** EXPERIMENTAL ** -** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the -** read transaction that is currently open on schema S of -** [database connection] D so that it refers to historical [snapshot] P. +** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a +** read transaction for schema S of +** [database connection] D such that the read transaction +** refers to historical [snapshot] P, rather than the most +** recent change to the database. ** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success ** or an appropriate [error code] if it fails. ** ** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be -** the first operation, apart from other sqlite3_snapshot_open() calls, -** following the [BEGIN] that starts a new read transaction. -** ^A [snapshot] will fail to open if it has been overwritten by a -** [checkpoint]. +** the first operation following the [BEGIN] that takes the schema S +** out of [autocommit mode]. +** ^In other words, schema S must not currently be in +** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the +** database connection D must be out of [autocommit mode]. +** ^A [snapshot] will fail to open if it has been overwritten by a +** [checkpoint]. +** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the +** database connection D does not know that the database file for +** schema S is in [WAL mode]. A database connection might not know +** that the database file is in [WAL mode] if there has been no prior +** I/O on that database connection, or if the database entered [WAL mode] +** after the most recent I/O on the database connection.)^ +** (Hint: Run "[PRAGMA application_id]" against a newly opened +** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open( +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot @@ -8192,7 +9696,56 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open( ** The [sqlite3_snapshot_free()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*); +SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); + +/* +** CAPI3REF: Compare the ages of two snapshot handles. +** EXPERIMENTAL +** +** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages +** of two valid snapshot handles. +** +** If the two snapshot handles are not associated with the same database +** file, the result of the comparison is undefined. +** +** Additionally, the result of the comparison is only valid if both of the +** snapshot handles were obtained by calling sqlite3_snapshot_get() since the +** last time the wal file was deleted. The wal file is deleted when the +** database is changed back to rollback mode or when the number of database +** clients drops to zero. If either snapshot handle was obtained before the +** wal file was last deleted, the value returned by this function +** is undefined. +** +** Otherwise, this API returns a negative value if P1 refers to an older +** snapshot than P2, zero if the two handles refer to the same database +** snapshot, and a positive value if P1 is a newer snapshot than P2. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 +); + +/* +** CAPI3REF: Recover snapshots from a wal file +** EXPERIMENTAL +** +** If all connections disconnect from a database file but do not perform +** a checkpoint, the existing wal file is opened along with the database +** file the next time the database is opened. At this point it is only +** possible to successfully call sqlite3_snapshot_open() to open the most +** recent snapshot of the database (the one at the head of the wal file), +** even though the wal file may contain other valid snapshots for which +** clients have sqlite3_snapshot handles. +** +** This function attempts to scan the wal file associated with database zDb +** of database handle db and make all valid snapshots available to +** sqlite3_snapshot_open(). It is an error if there is already a read +** transaction open on the database, or if the database is not a wal mode +** database. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** Undo the hack that converts floating point types to integer for @@ -8205,8 +9758,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3 #if 0 } /* End of the 'extern "C"' block */ #endif -#endif /* _SQLITE3_H_ */ +#endif /* SQLITE3_H */ +/******** Begin file sqlite3rtree.h *********/ /* ** 2010 August 30 ** @@ -8246,7 +9800,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; ** ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback( +SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), @@ -8272,7 +9826,7 @@ struct sqlite3_rtree_geometry { ** ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) */ -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback( +SQLITE_API int sqlite3_rtree_query_callback( sqlite3 *db, const char *zQueryFunc, int (*xQueryFunc)(sqlite3_rtree_query_info*), @@ -8324,6 +9878,1298 @@ struct sqlite3_rtree_query_info { #endif /* ifndef _SQLITE3RTREE_H_ */ +/******** End of sqlite3rtree.h *********/ +/******** Begin file sqlite3session.h *********/ + +#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) +#define __SQLITESESSION_H_ 1 + +/* +** Make sure we can call this stuff from C++. +*/ +#if 0 +extern "C" { +#endif + + +/* +** CAPI3REF: Session Object Handle +*/ +typedef struct sqlite3_session sqlite3_session; + +/* +** CAPI3REF: Changeset Iterator Handle +*/ +typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; + +/* +** CAPI3REF: Create A New Session Object +** +** Create a new session object attached to database handle db. If successful, +** a pointer to the new object is written to *ppSession and SQLITE_OK is +** returned. If an error occurs, *ppSession is set to NULL and an SQLite +** error code (e.g. SQLITE_NOMEM) is returned. +** +** It is possible to create multiple session objects attached to a single +** database handle. +** +** Session objects created using this function should be deleted using the +** [sqlite3session_delete()] function before the database handle that they +** are attached to is itself closed. If the database handle is closed before +** the session object is deleted, then the results of calling any session +** module function, including [sqlite3session_delete()] on the session object +** are undefined. +** +** Because the session module uses the [sqlite3_preupdate_hook()] API, it +** is not possible for an application to register a pre-update hook on a +** database handle that has one or more session objects attached. Nor is +** it possible to create a session object attached to a database handle for +** which a pre-update hook is already defined. The results of attempting +** either of these things are undefined. +** +** The session object will be used to create changesets for tables in +** database zDb, where zDb is either "main", or "temp", or the name of an +** attached database. It is not an error if database zDb is not attached +** to the database when the session object is created. +*/ +SQLITE_API int sqlite3session_create( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (e.g. "main") */ + sqlite3_session **ppSession /* OUT: New session object */ +); + +/* +** CAPI3REF: Delete A Session Object +** +** Delete a session object previously allocated using +** [sqlite3session_create()]. Once a session object has been deleted, the +** results of attempting to use pSession with any other session module +** function are undefined. +** +** Session objects must be deleted before the database handle to which they +** are attached is closed. Refer to the documentation for +** [sqlite3session_create()] for details. +*/ +SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); + + +/* +** CAPI3REF: Enable Or Disable A Session Object +** +** Enable or disable the recording of changes by a session object. When +** enabled, a session object records changes made to the database. When +** disabled - it does not. A newly created session object is enabled. +** Refer to the documentation for [sqlite3session_changeset()] for further +** details regarding how enabling and disabling a session object affects +** the eventual changesets. +** +** Passing zero to this function disables the session. Passing a value +** greater than zero enables it. Passing a value less than zero is a +** no-op, and may be used to query the current state of the session. +** +** The return value indicates the final state of the session object: 0 if +** the session is disabled, or 1 if it is enabled. +*/ +SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); + +/* +** CAPI3REF: Set Or Clear the Indirect Change Flag +** +** Each change recorded by a session object is marked as either direct or +** indirect. A change is marked as indirect if either: +** +**
      +**
    • The session object "indirect" flag is set when the change is +** made, or +**
    • The change is made by an SQL trigger or foreign key action +** instead of directly as a result of a users SQL statement. +**
    +** +** If a single row is affected by more than one operation within a session, +** then the change is considered indirect if all operations meet the criteria +** for an indirect change above, or direct otherwise. +** +** This function is used to set, clear or query the session object indirect +** flag. If the second argument passed to this function is zero, then the +** indirect flag is cleared. If it is greater than zero, the indirect flag +** is set. Passing a value less than zero does not modify the current value +** of the indirect flag, and may be used to query the current state of the +** indirect flag for the specified session object. +** +** The return value indicates the final state of the indirect flag: 0 if +** it is clear, or 1 if it is set. +*/ +SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); + +/* +** CAPI3REF: Attach A Table To A Session Object +** +** If argument zTab is not NULL, then it is the name of a table to attach +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See +** documentation for [sqlite3session_changeset()] for further details. +** +** Or, if argument zTab is NULL, then changes are recorded for all tables +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for +** the new tables are also recorded. +** +** Changes can only be recorded for tables that have a PRIMARY KEY explicitly +** defined as part of their CREATE TABLE statement. It does not matter if the +** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY +** KEY may consist of a single column, or may be a composite key. +** +** It is not an error if the named table does not exist in the database. Nor +** is it an error if the named table does not have a PRIMARY KEY. However, +** no changes will be recorded in either of these scenarios. +** +** Changes are not recorded for individual rows that have NULL values stored +** in one or more of their PRIMARY KEY columns. +** +** SQLITE_OK is returned if the call completes without error. Or, if an error +** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. +*/ +SQLITE_API int sqlite3session_attach( + sqlite3_session *pSession, /* Session object */ + const char *zTab /* Table name */ +); + +/* +** CAPI3REF: Set a table filter on a Session Object. +** +** The second argument (xFilter) is the "filter callback". For changes to rows +** in tables that are not attached to the Session object, the filter is called +** to determine whether changes to the table's rows should be tracked or not. +** If xFilter returns 0, changes is not tracked. Note that once a table is +** attached, xFilter will not be called again. +*/ +SQLITE_API void sqlite3session_table_filter( + sqlite3_session *pSession, /* Session object */ + int(*xFilter)( + void *pCtx, /* Copy of third arg to _filter_table() */ + const char *zTab /* Table name */ + ), + void *pCtx /* First argument passed to xFilter */ +); + +/* +** CAPI3REF: Generate A Changeset From A Session Object +** +** Obtain a changeset containing changes to the tables attached to the +** session object passed as the first argument. If successful, +** set *ppChangeset to point to a buffer containing the changeset +** and *pnChangeset to the size of the changeset in bytes before returning +** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to +** zero and return an SQLite error code. +** +** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, +** each representing a change to a single row of an attached table. An INSERT +** change contains the values of each field of a new database row. A DELETE +** contains the original values of each field of a deleted database row. An +** UPDATE change contains the original values of each field of an updated +** database row along with the updated values for each updated non-primary-key +** column. It is not possible for an UPDATE change to represent a change that +** modifies the values of primary key columns. If such a change is made, it +** is represented in a changeset as a DELETE followed by an INSERT. +** +** Changes are not recorded for rows that have NULL values stored in one or +** more of their PRIMARY KEY columns. If such a row is inserted or deleted, +** no corresponding change is present in the changesets returned by this +** function. If an existing row with one or more NULL values stored in +** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, +** only an INSERT is appears in the changeset. Similarly, if an existing row +** with non-NULL PRIMARY KEY values is updated so that one or more of its +** PRIMARY KEY columns are set to NULL, the resulting changeset contains a +** DELETE change only. +** +** The contents of a changeset may be traversed using an iterator created +** using the [sqlite3changeset_start()] API. A changeset may be applied to +** a database with a compatible schema using the [sqlite3changeset_apply()] +** API. +** +** Within a changeset generated by this function, all changes related to a +** single table are grouped together. In other words, when iterating through +** a changeset or when applying a changeset to a database, all changes related +** to a single table are processed before moving on to the next table. Tables +** are sorted in the same order in which they were attached (or auto-attached) +** to the sqlite3_session object. The order in which the changes related to +** a single table are stored is undefined. +** +** Following a successful call to this function, it is the responsibility of +** the caller to eventually free the buffer that *ppChangeset points to using +** [sqlite3_free()]. +** +**

    Changeset Generation

    +** +** Once a table has been attached to a session object, the session object +** records the primary key values of all new rows inserted into the table. +** It also records the original primary key and other column values of any +** deleted or updated rows. For each unique primary key value, data is only +** recorded once - the first time a row with said primary key is inserted, +** updated or deleted in the lifetime of the session. +** +** There is one exception to the previous paragraph: when a row is inserted, +** updated or deleted, if one or more of its primary key columns contain a +** NULL value, no record of the change is made. +** +** The session object therefore accumulates two types of records - those +** that consist of primary key values only (created when the user inserts +** a new record) and those that consist of the primary key values and the +** original values of other table columns (created when the users deletes +** or updates a record). +** +** When this function is called, the requested changeset is created using +** both the accumulated records and the current contents of the database +** file. Specifically: +** +**
      +**
    • For each record generated by an insert, the database is queried +** for a row with a matching primary key. If one is found, an INSERT +** change is added to the changeset. If no such row is found, no change +** is added to the changeset. +** +**
    • For each record generated by an update or delete, the database is +** queried for a row with a matching primary key. If such a row is +** found and one or more of the non-primary key fields have been +** modified from their original values, an UPDATE change is added to +** the changeset. Or, if no such row is found in the table, a DELETE +** change is added to the changeset. If there is a row with a matching +** primary key in the database, but all fields contain their original +** values, no change is added to the changeset. +**
    +** +** This means, amongst other things, that if a row is inserted and then later +** deleted while a session object is active, neither the insert nor the delete +** will be present in the changeset. Or if a row is deleted and then later a +** row with the same primary key values inserted while a session object is +** active, the resulting changeset will contain an UPDATE change instead of +** a DELETE and an INSERT. +** +** When a session object is disabled (see the [sqlite3session_enable()] API), +** it does not accumulate records when rows are inserted, updated or deleted. +** This may appear to have some counter-intuitive effects if a single row +** is written to more than once during a session. For example, if a row +** is inserted while a session object is enabled, then later deleted while +** the same session object is disabled, no INSERT record will appear in the +** changeset, even though the delete took place while the session was disabled. +** Or, if one field of a row is updated while a session is disabled, and +** another field of the same row is updated while the session is enabled, the +** resulting changeset will contain an UPDATE change that updates both fields. +*/ +SQLITE_API int sqlite3session_changeset( + sqlite3_session *pSession, /* Session object */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ +); + +/* +** CAPI3REF: Load The Difference Between Tables Into A Session +** +** If it is not already attached to the session object passed as the first +** argument, this function attaches table zTbl in the same manner as the +** [sqlite3session_attach()] function. If zTbl does not exist, or if it +** does not have a primary key, this function is a no-op (but does not return +** an error). +** +** Argument zFromDb must be the name of a database ("main", "temp" etc.) +** attached to the same database handle as the session object that contains +** a table compatible with the table attached to the session by this function. +** A table is considered compatible if it: +** +**
      +**
    • Has the same name, +**
    • Has the same set of columns declared in the same order, and +**
    • Has the same PRIMARY KEY definition. +**
    +** +** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables +** are compatible but do not have any PRIMARY KEY columns, it is not an error +** but no changes are added to the session object. As with other session +** APIs, tables without PRIMARY KEYs are simply ignored. +** +** This function adds a set of changes to the session object that could be +** used to update the table in database zFrom (call this the "from-table") +** so that its content is the same as the table attached to the session +** object (call this the "to-table"). Specifically: +** +**
      +**
    • For each row (primary key) that exists in the to-table but not in +** the from-table, an INSERT record is added to the session object. +** +**
    • For each row (primary key) that exists in the to-table but not in +** the from-table, a DELETE record is added to the session object. +** +**
    • For each row (primary key) that exists in both tables, but features +** different non-PK values in each, an UPDATE record is added to the +** session. +**
    +** +** To clarify, if this function is called and then a changeset constructed +** using [sqlite3session_changeset()], then after applying that changeset to +** database zFrom the contents of the two compatible tables would be +** identical. +** +** It an error if database zFrom does not exist or does not contain the +** required compatible table. +** +** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite +** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to free this buffer using +** sqlite3_free(). +*/ +SQLITE_API int sqlite3session_diff( + sqlite3_session *pSession, + const char *zFromDb, + const char *zTbl, + char **pzErrMsg +); + + +/* +** CAPI3REF: Generate A Patchset From A Session Object +** +** The differences between a patchset and a changeset are that: +** +**
      +**
    • DELETE records consist of the primary key fields only. The +** original values of other fields are omitted. +**
    • The original values of any modified fields are omitted from +** UPDATE records. +**
    +** +** A patchset blob may be used with up to date versions of all +** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), +** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, +** attempting to use a patchset blob with old versions of the +** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. +** +** Because the non-primary key "old.*" fields are omitted, no +** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset +** is passed to the sqlite3changeset_apply() API. Other conflict types work +** in the same way as for changesets. +** +** Changes within a patchset are ordered in the same way as for changesets +** generated by the sqlite3session_changeset() function (i.e. all changes for +** a single table are grouped together, tables appear in the order in which +** they were attached to the session object). +*/ +SQLITE_API int sqlite3session_patchset( + sqlite3_session *pSession, /* Session object */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ +); + +/* +** CAPI3REF: Test if a changeset has recorded any changes. +** +** Return non-zero if no changes to attached tables have been recorded by +** the session object passed as the first argument. Otherwise, if one or +** more changes have been recorded, return zero. +** +** Even if this function returns zero, it is possible that calling +** [sqlite3session_changeset()] on the session handle may still return a +** changeset that contains no changes. This can happen when a row in +** an attached table is modified and then later on the original values +** are restored. However, if this function returns non-zero, then it is +** guaranteed that a call to sqlite3session_changeset() will return a +** changeset containing zero changes. +*/ +SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); + +/* +** CAPI3REF: Create An Iterator To Traverse A Changeset +** +** Create an iterator used to iterate through the contents of a changeset. +** If successful, *pp is set to point to the iterator handle and SQLITE_OK +** is returned. Otherwise, if an error occurs, *pp is set to zero and an +** SQLite error code is returned. +** +** The following functions can be used to advance and query a changeset +** iterator created by this function: +** +**
      +**
    • [sqlite3changeset_next()] +**
    • [sqlite3changeset_op()] +**
    • [sqlite3changeset_new()] +**
    • [sqlite3changeset_old()] +**
    +** +** It is the responsibility of the caller to eventually destroy the iterator +** by passing it to [sqlite3changeset_finalize()]. The buffer containing the +** changeset (pChangeset) must remain valid until after the iterator is +** destroyed. +** +** Assuming the changeset blob was created by one of the +** [sqlite3session_changeset()], [sqlite3changeset_concat()] or +** [sqlite3changeset_invert()] functions, all changes within the changeset +** that apply to a single table are grouped together. This means that when +** an application iterates through a changeset using an iterator created by +** this function, all changes that relate to a single table are visited +** 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. +*/ +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 */ +); + + +/* +** CAPI3REF: Advance A Changeset Iterator +** +** This function may only be used with iterators created by function +** [sqlite3changeset_start()]. If it is called on an iterator passed to +** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE +** is returned and the call has no effect. +** +** Immediately after an iterator is created by sqlite3changeset_start(), it +** does not point to any change in the changeset. Assuming the changeset +** is not empty, the first call to this function advances the iterator to +** point to the first change in the changeset. Each subsequent call advances +** the iterator to point to the next change in the changeset (if any). If +** no error occurs and the iterator points to a valid change after a call +** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. +** Otherwise, if all changes in the changeset have already been visited, +** SQLITE_DONE is returned. +** +** If an error occurs, an SQLite error code is returned. Possible error +** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or +** SQLITE_NOMEM. +*/ +SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Obtain The Current Operation From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this +** is not the case, this function returns [SQLITE_MISUSE]. +** +** If argument pzTab is not NULL, then *pzTab is set to point to a +** nul-terminated utf-8 encoded string containing the name of the table +** affected by the current change. The buffer remains valid until either +** 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 +** 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 +** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the +** type of change that the iterator currently points to. +** +** If no error occurs, SQLITE_OK is returned. If an error does occur, an +** SQLite error code is returned. The values of the output variables may not +** be trusted in this case. +*/ +SQLITE_API int sqlite3changeset_op( + sqlite3_changeset_iter *pIter, /* Iterator object */ + const char **pzTab, /* OUT: Pointer to table name */ + int *pnCol, /* OUT: Number of columns in table */ + int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int *pbIndirect /* OUT: True for an 'indirect' change */ +); + +/* +** CAPI3REF: Obtain The Primary Key Definition Of A Table +** +** For each modified table, a changeset includes the following: +** +**
      +**
    • The number of columns in the table, and +**
    • Which of those columns make up the tables PRIMARY KEY. +**
    +** +** This function is used to find which columns comprise the PRIMARY KEY of +** the table modified by the change that iterator pIter currently points to. +** If successful, *pabPK is set to point to an array of nCol entries, where +** nCol is the number of columns in the table. Elements of *pabPK are set to +** 0x01 if the corresponding column is part of the tables primary key, or +** 0x00 if it is not. +** +** If argument pnCol is not NULL, then *pnCol is set to the number of columns +** in the table. +** +** If this function is called when the iterator does not point to a valid +** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, +** SQLITE_OK is returned and the output variables populated as described +** above. +*/ +SQLITE_API int sqlite3changeset_pk( + sqlite3_changeset_iter *pIter, /* Iterator object */ + unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ + int *pnCol /* OUT: Number of entries in output array */ +); + +/* +** CAPI3REF: Obtain old.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** original row values stored as part of the UPDATE or DELETE change and +** returns SQLITE_OK. The name of the function comes from the fact that this +** is similar to the "old.*" columns available to update or delete triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_old( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain new.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** new row values stored as part of the UPDATE or INSERT change and +** returns SQLITE_OK. If the change is an UPDATE and does not include +** a new value for the requested column, *ppValue is set to NULL and +** SQLITE_OK returned. The name of the function comes from the fact that +** this is similar to the "new.*" columns available to update or delete +** triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_new( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator +** +** This function should only be used with iterator objects passed to a +** conflict-handler callback by [sqlite3changeset_apply()] with either +** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function +** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue +** is set to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the +** "conflicting row" associated with the current conflict-handler callback +** and returns SQLITE_OK. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_conflict( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Value from conflicting row */ +); + +/* +** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations +** +** This function may only be called with an iterator passed to an +** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case +** it sets the output variable to the total number of known foreign key +** violations in the destination database and returns SQLITE_OK. +** +** In all other cases this function returns SQLITE_MISUSE. +*/ +SQLITE_API int sqlite3changeset_fk_conflicts( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int *pnOut /* OUT: Number of FK violations */ +); + + +/* +** CAPI3REF: Finalize A Changeset Iterator +** +** This function is used to finalize an iterator allocated with +** [sqlite3changeset_start()]. +** +** This function should only be called on iterators created using the +** [sqlite3changeset_start()] function. If an application calls this +** function with an iterator passed to a conflict-handler by +** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the +** call has no effect. +** +** If an error was encountered within a call to an sqlite3changeset_xxx() +** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an +** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding +** to that error is returned by this function. Otherwise, SQLITE_OK is +** returned. This is to allow the following pattern (pseudo-code): +** +** sqlite3changeset_start(); +** while( SQLITE_ROW==sqlite3changeset_next() ){ +** // Do something with change. +** } +** rc = sqlite3changeset_finalize(); +** if( rc!=SQLITE_OK ){ +** // An error has occurred +** } +*/ +SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Invert A Changeset +** +** This function is used to "invert" a changeset object. Applying an inverted +** changeset to a database reverses the effects of applying the uninverted +** changeset. Specifically: +** +**
      +**
    • Each DELETE change is changed to an INSERT, and +**
    • Each INSERT change is changed to a DELETE, and +**
    • For each UPDATE change, the old.* and new.* values are exchanged. +**
    +** +** This function does not change the order in which changes appear within +** the changeset. It merely reverses the sense of each individual change. +** +** If successful, a pointer to a buffer containing the inverted changeset +** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and +** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are +** zeroed and an SQLite error code returned. +** +** It is the responsibility of the caller to eventually call sqlite3_free() +** on the *ppOut pointer to free the buffer allocation following a successful +** call to this function. +** +** WARNING/TODO: This function currently assumes that the input is a valid +** changeset. If it is not, the results are undefined. +*/ +SQLITE_API int sqlite3changeset_invert( + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ +); + +/* +** CAPI3REF: Concatenate Two Changeset Objects +** +** This function is used to concatenate two changesets, A and B, into a +** single changeset. The result is a changeset equivalent to applying +** changeset A followed by changeset B. +** +** This function combines the two input changesets using an +** sqlite3_changegroup object. Calling it produces similar results as the +** following code fragment: +** +** sqlite3_changegroup *pGrp; +** rc = sqlite3_changegroup_new(&pGrp); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB); +** if( rc==SQLITE_OK ){ +** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); +** }else{ +** *ppOut = 0; +** *pnOut = 0; +** } +** +** Refer to the sqlite3_changegroup documentation below for details. +*/ +SQLITE_API int sqlite3changeset_concat( + int nA, /* Number of bytes in buffer pA */ + void *pA, /* Pointer to buffer containing changeset A */ + int nB, /* Number of bytes in buffer pB */ + void *pB, /* Pointer to buffer containing changeset B */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: Buffer containing output changeset */ +); + + +/* +** CAPI3REF: Changegroup Handle +*/ +typedef struct sqlite3_changegroup sqlite3_changegroup; + +/* +** CAPI3REF: Create A New Changegroup Object +** +** An sqlite3_changegroup object is used to combine two or more changesets +** (or patchsets) into a single changeset (or patchset). A single changegroup +** object may combine changesets or patchsets, but not both. The output is +** always in the same format as the input. +** +** If successful, this function returns SQLITE_OK and populates (*pp) with +** a pointer to a new sqlite3_changegroup object before returning. The caller +** should eventually free the returned object using a call to +** sqlite3changegroup_delete(). If an error occurs, an SQLite error code +** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. +** +** The usual usage pattern for an sqlite3_changegroup object is as follows: +** +**
      +**
    • It is created using a call to sqlite3changegroup_new(). +** +**
    • Zero or more changesets (or patchsets) are added to the object +** by calling sqlite3changegroup_add(). +** +**
    • The result of combining all input changesets together is obtained +** by the application via a call to sqlite3changegroup_output(). +** +**
    • The object is deleted using a call to sqlite3changegroup_delete(). +**
    +** +** Any number of calls to add() and output() may be made between the calls to +** new() and delete(), and in any order. +** +** As well as the regular sqlite3changegroup_add() and +** sqlite3changegroup_output() functions, also available are the streaming +** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). +*/ +SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); + +/* +** CAPI3REF: Add A Changeset To A Changegroup +** +** Add all changes within the changeset (or patchset) in buffer pData (size +** nData bytes) to the changegroup. +** +** If the buffer contains a patchset, then all prior calls to this function +** on the same changegroup object must also have specified patchsets. Or, if +** the buffer contains a changeset, so must have the earlier calls to this +** function. Otherwise, SQLITE_ERROR is returned and no changes are added +** to the changegroup. +** +** Rows within the changeset and changegroup are identified by the values in +** their PRIMARY KEY columns. A change in the changeset is considered to +** apply to the same row as a change already present in the changegroup if +** the two rows have the same primary key. +** +** Changes to rows that do not already appear in the changegroup are +** simply copied into it. Or, if both the new changeset and the changegroup +** contain changes that apply to a single row, the final contents of the +** changegroup depends on the type of each change, as follows: +** +** +** +** +**
    Existing Change New Change Output Change +**
    INSERT INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    INSERT UPDATE +** The INSERT change remains in the changegroup. The values in the +** INSERT change are modified as if the row was inserted by the +** existing change and then updated according to the new change. +**
    INSERT DELETE +** The existing INSERT is removed from the changegroup. The DELETE is +** not added. +**
    UPDATE INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    UPDATE UPDATE +** The existing UPDATE remains within the changegroup. It is amended +** so that the accompanying values are as if the row was updated once +** by the existing change and then again by the new change. +**
    UPDATE DELETE +** The existing UPDATE is replaced by the new DELETE within the +** changegroup. +**
    DELETE INSERT +** If one or more of the column values in the row inserted by the +** new change differ from those in the row deleted by the existing +** change, the existing DELETE is replaced by an UPDATE within the +** changegroup. Otherwise, if the inserted row is exactly the same +** as the deleted row, the existing DELETE is simply discarded. +**
    DELETE UPDATE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    DELETE DELETE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    +** +** If the new changeset contains changes to a table that is already present +** in the changegroup, then the number of columns and the position of the +** primary key columns for the table must be consistent. If this is not the +** case, this function fails with SQLITE_SCHEMA. If the input changeset +** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is +** returned. Or, if an out-of-memory condition occurs during processing, this +** function returns SQLITE_NOMEM. In all cases, if an error occurs the +** final contents of the changegroup is undefined. +** +** If no error occurs, SQLITE_OK is returned. +*/ +SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); + +/* +** CAPI3REF: Obtain A Composite Changeset From A Changegroup +** +** Obtain a buffer containing a changeset (or patchset) representing the +** current contents of the changegroup. If the inputs to the changegroup +** were themselves changesets, the output is a changeset. Or, if the +** inputs were patchsets, the output is also a patchset. +** +** As with the output of the sqlite3session_changeset() and +** sqlite3session_patchset() functions, all changes related to a single +** table are grouped together in the output of this function. Tables appear +** in the same order as for the very first changeset added to the changegroup. +** If the second or subsequent changesets added to the changegroup contain +** changes for tables that do not appear in the first changeset, they are +** appended onto the end of the output changeset, again in the order in +** which they are first encountered. +** +** If an error occurs, an SQLite error code is returned and the output +** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK +** is returned and the output variables are set to the size of and a +** pointer to the output buffer, respectively. In this case it is the +** responsibility of the caller to eventually free the buffer using a +** call to sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_output( + sqlite3_changegroup*, + int *pnData, /* OUT: Size of output buffer in bytes */ + void **ppData /* OUT: Pointer to output buffer */ +); + +/* +** CAPI3REF: Delete A Changegroup Object +*/ +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); + +/* +** CAPI3REF: Apply A Changeset To A Database +** +** Apply a changeset to a database. This function attempts to update the +** "main" database attached to handle db with the changes found in the +** changeset passed via the second and third arguments. +** +** The fourth argument (xFilter) passed to this function is the "filter +** callback". If it is not NULL, then for each table affected by at least one +** change in the changeset, the filter callback is invoked with +** the table name as the second argument, and a copy of the context pointer +** passed as the sixth argument to this function as the first. If the "filter +** callback" returns zero, then no attempt is made to apply any changes to +** the table. Otherwise, if the return value is non-zero or the xFilter +** argument to this function is NULL, all changes related to the table are +** attempted. +** +** For each table that is not excluded by the filter callback, this function +** tests that the target database contains a compatible table. A table is +** considered compatible if all of the following are true: +** +**
      +**
    • The table has the same name as the name recorded in the +** changeset, and +**
    • The table has at least as many columns as recorded in the +** changeset, and +**
    • The table has primary key columns in the same position as +** recorded in the changeset. +**
    +** +** If there is no compatible table, it is not an error, but none of the +** changes associated with the table are applied. A warning message is issued +** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most +** one such warning is issued for each table in the changeset. +** +** For each change for which there is a compatible table, an attempt is made +** to modify the table contents according to the UPDATE, INSERT or DELETE +** change. If a change cannot be applied cleanly, the conflict handler +** function passed as the fifth argument to sqlite3changeset_apply() may be +** invoked. A description of exactly when the conflict handler is invoked for +** each type of change is below. +** +** Unlike the xFilter argument, xConflict may not be passed NULL. The results +** of passing anything other than a valid function pointer as the xConflict +** argument are undefined. +** +** Each time the conflict handler function is invoked, it must return one +** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or +** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned +** if the second argument passed to the conflict handler is either +** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler +** returns an illegal value, any changes already made are rolled back and +** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different +** actions are taken by sqlite3changeset_apply() depending on the value +** returned by each invocation of the conflict-handler function. Refer to +** the documentation for the three +** [SQLITE_CHANGESET_OMIT|available return values] for details. +** +**
    +**
    DELETE Changes
    +** For each DELETE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in +** the changeset the row is deleted from the target database. +** +** If a row with matching primary key values is found, but one or more of +** the non-primary key fields contains a value different from the original +** row value stored in the changeset, the conflict-handler function is +** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the +** database table has more columns than are recorded in the changeset, +** only the values of those non-primary key fields are compared against +** the current database contents - any trailing database table columns +** are ignored. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT +** (which can only happen if a foreign key constraint is violated), the +** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] +** passed as the second argument. This includes the case where the DELETE +** operation is attempted because an earlier call to the conflict handler +** function returned [SQLITE_CHANGESET_REPLACE]. +** +**
    INSERT Changes
    +** For each INSERT change, an attempt is made to insert the new row into +** the database. If the changeset row contains fewer fields than the +** database table, the trailing fields are populated with their default +** values. +** +** If the attempt to insert the row fails because the database already +** contains a row with the same primary key values, the conflict handler +** function is invoked with the second argument set to +** [SQLITE_CHANGESET_CONFLICT]. +** +** If the attempt to insert the row fails because of some other constraint +** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is +** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. +** This includes the case where the INSERT operation is re-attempted because +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +** +**
    UPDATE Changes
    +** For each UPDATE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all modified non-primary key columns also match the values +** stored in the changeset the row is updated within the target database. +** +** If a row with matching primary key values is found, but one or more of +** the modified non-primary key fields contains a value different from an +** original row value stored in the changeset, the conflict-handler function +** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since +** UPDATE changes only contain values for non-primary key fields that are +** to be modified, only those fields need to match the original values to +** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the UPDATE operation is attempted, but SQLite returns +** SQLITE_CONSTRAINT, the conflict-handler function is invoked with +** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. +** This includes the case where the UPDATE operation is attempted after +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +**
    +** +** It is safe to execute SQL statements, including those that write to the +** table that the callback related to, from within the xConflict callback. +** This can be used to further customize the applications conflict +** resolution strategy. +** +** All changes made by this function are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. +*/ +SQLITE_API int sqlite3changeset_apply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); + +/* +** CAPI3REF: Constants Passed To The Conflict Handler +** +** Values that may be passed as the second argument to a conflict-handler. +** +**
    +**
    SQLITE_CHANGESET_DATA
    +** The conflict handler is invoked with CHANGESET_DATA as the second argument +** when processing a DELETE or UPDATE change if a row with the required +** PRIMARY KEY fields is present in the database, but one or more other +** (non primary-key) fields modified by the update do not contain the +** expected "before" values. +** +** The conflicting row, in this case, is the database row with the matching +** primary key. +** +**
    SQLITE_CHANGESET_NOTFOUND
    +** The conflict handler is invoked with CHANGESET_NOTFOUND as the second +** argument when processing a DELETE or UPDATE change if a row with the +** required PRIMARY KEY fields is not present in the database. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
    SQLITE_CHANGESET_CONFLICT
    +** CHANGESET_CONFLICT is passed as the second argument to the conflict +** handler while processing an INSERT change if the operation would result +** in duplicate primary key values. +** +** The conflicting row in this case is the database row with the matching +** primary key. +** +**
    SQLITE_CHANGESET_FOREIGN_KEY
    +** If foreign key handling is enabled, and applying a changeset leaves the +** database in a state containing foreign key violations, the conflict +** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument +** exactly once before the changeset is committed. If the conflict handler +** returns CHANGESET_OMIT, the changes, including those that caused the +** foreign key constraint violation, are committed. Or, if it returns +** CHANGESET_ABORT, the changeset is rolled back. +** +** No current or conflicting row information is provided. The only function +** it is possible to call on the supplied sqlite3_changeset_iter handle +** is sqlite3changeset_fk_conflicts(). +** +**
    SQLITE_CHANGESET_CONSTRAINT
    +** If any other constraint violation occurs while applying a change (i.e. +** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is +** invoked with CHANGESET_CONSTRAINT as the second argument. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
    +*/ +#define SQLITE_CHANGESET_DATA 1 +#define SQLITE_CHANGESET_NOTFOUND 2 +#define SQLITE_CHANGESET_CONFLICT 3 +#define SQLITE_CHANGESET_CONSTRAINT 4 +#define SQLITE_CHANGESET_FOREIGN_KEY 5 + +/* +** CAPI3REF: Constants Returned By The Conflict Handler +** +** A conflict handler callback must return one of the following three values. +** +**
    +**
    SQLITE_CHANGESET_OMIT
    +** If a conflict handler returns this value no special action is taken. The +** change that caused the conflict is not applied. The session module +** continues to the next change in the changeset. +** +**
    SQLITE_CHANGESET_REPLACE
    +** This value may only be returned if the second argument to the conflict +** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this +** is not the case, any changes applied so far are rolled back and the +** call to sqlite3changeset_apply() returns SQLITE_MISUSE. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict +** handler, then the conflicting row is either updated or deleted, depending +** on the type of change. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict +** handler, then the conflicting row is removed from the database and a +** second attempt to apply the change is made. If this second attempt fails, +** the original row is restored to the database before continuing. +** +**
    SQLITE_CHANGESET_ABORT
    +** If this value is returned, any changes applied so far are rolled back +** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. +**
    +*/ +#define SQLITE_CHANGESET_OMIT 0 +#define SQLITE_CHANGESET_REPLACE 1 +#define SQLITE_CHANGESET_ABORT 2 + +/* +** CAPI3REF: Streaming Versions of API functions. +** +** The six streaming API xxx_strm() functions serve similar purposes to the +** corresponding non-streaming API functions: +** +** +** +**
    Streaming functionNon-streaming equivalent
    sqlite3changeset_apply_strm[sqlite3changeset_apply] +**
    sqlite3changeset_concat_strm[sqlite3changeset_concat] +**
    sqlite3changeset_invert_strm[sqlite3changeset_invert] +**
    sqlite3changeset_start_strm[sqlite3changeset_start] +**
    sqlite3session_changeset_strm[sqlite3session_changeset] +**
    sqlite3session_patchset_strm[sqlite3session_patchset] +**
    +** +** Non-streaming functions that accept changesets (or patchsets) as input +** require that the entire changeset be stored in a single buffer in memory. +** Similarly, those that return a changeset or patchset do so by returning +** a pointer to a single large buffer allocated using sqlite3_malloc(). +** Normally this is convenient. However, if an application running in a +** low-memory environment is required to handle very large changesets, the +** large contiguous memory allocations required can become onerous. +** +** In order to avoid this problem, instead of a single large buffer, input +** is passed to a streaming API functions by way of a callback function that +** the sessions module invokes to incrementally request input data as it is +** required. In all cases, a pair of API function parameters such as +** +**
    +**        int nChangeset,
    +**        void *pChangeset,
    +**  
    +** +** Is replaced by: +** +**
    +**        int (*xInput)(void *pIn, void *pData, int *pnData),
    +**        void *pIn,
    +**  
    +** +** Each time the xInput callback is invoked by the sessions module, the first +** argument passed is a copy of the supplied pIn context pointer. The second +** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no +** error occurs the xInput method should copy up to (*pnData) bytes of data +** into the buffer and set (*pnData) to the actual number of bytes copied +** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) +** should be set to zero to indicate this. Or, if an error occurs, an SQLite +** error code should be returned. In all cases, if an xInput callback returns +** an error, all processing is abandoned and the streaming API function +** returns a copy of the error code to the caller. +** +** In the case of sqlite3changeset_start_strm(), the xInput callback may be +** invoked by the sessions module at any point during the lifetime of the +** iterator. If such an xInput callback returns an error, the iterator enters +** an error state, whereby all subsequent calls to iterator functions +** immediately fail with the same error code as returned by xInput. +** +** Similarly, streaming API functions that return changesets (or patchsets) +** return them in chunks by way of a callback function instead of via a +** pointer to a single large buffer. In this case, a pair of parameters such +** as: +** +**
    +**        int *pnChangeset,
    +**        void **ppChangeset,
    +**  
    +** +** Is replaced by: +** +**
    +**        int (*xOutput)(void *pOut, const void *pData, int nData),
    +**        void *pOut
    +**  
    +** +** The xOutput callback is invoked zero or more times to return data to +** the application. The first parameter passed to each call is a copy of the +** pOut pointer supplied by the application. The second parameter, pData, +** points to a buffer nData bytes in size containing the chunk of output +** data being returned. If the xOutput callback successfully processes the +** supplied data, it should return SQLITE_OK to indicate success. Otherwise, +** it should return some other SQLite error code. In this case processing +** is immediately abandoned and the streaming API function returns a copy +** of the xOutput error code to the application. +** +** The sessions module never invokes an xOutput callback with the third +** parameter set to a value less than or equal to zero. Other than this, +** no guarantees are made as to the size of the chunks of data returned. +*/ +SQLITE_API int sqlite3changeset_apply_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); +SQLITE_API int sqlite3changeset_concat_strm( + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changeset_invert_strm( + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changeset_start_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +SQLITE_API int sqlite3session_changeset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3session_patchset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); + + +/* +** Make sure we can call this stuff from C++. +*/ +#if 0 +} +#endif + +#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ + +/******** End of sqlite3session.h *********/ +/******** Begin file fts5.h *********/ /* ** 2014 May 31 ** @@ -8409,6 +11255,9 @@ struct Fts5PhraseIter { ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** ** xColumnText: ** This function attempts to retrieve the text of column iCol of the ** current document. If successful, (*pz) is set to point to a buffer @@ -8429,15 +11278,29 @@ struct Fts5PhraseIter { ** the query within the current row. Return 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. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). ** +** 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. ** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** ** xRowid: ** Returns the rowid of the current row. ** @@ -8451,11 +11314,13 @@ struct Fts5PhraseIter { ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid ** ** with $p set to a phrase equivalent to the phrase iPhrase of the -** current query is executed. For each row visited, the callback function -** passed as the fourth argument is invoked. The context and API objects -** passed to the callback function may be used to access the properties of -** each matched row. Invoking Api.xUserData() returns a copy of the pointer -** passed as the third argument to pUserData. +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. @@ -8521,7 +11386,7 @@ struct Fts5PhraseIter { ** Fts5PhraseIter iter; ** int iCol, iOff; ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); -** iOff>=0; +** iCol>=0; ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) ** ){ ** // An instance of phrase iPhrase at offset iOff of column iCol @@ -8529,13 +11394,51 @@ struct Fts5PhraseIter { ** ** The Fts5PhraseIter structure is defined above. Applications should not ** modify this structure directly - it should only be used as shown above -** with the xPhraseFirst() and xPhraseNext() API methods. +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** ** xPhraseNext() ** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 1 */ + int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); @@ -8565,8 +11468,11 @@ struct Fts5ExtensionApi { int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); void *(*xGetAuxdata)(Fts5Context*, int bClear); - void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; /* @@ -8583,7 +11489,7 @@ struct Fts5ExtensionApi { ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: -** This function is used to allocate and inititalize a tokenizer instance. +** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) @@ -8843,7 +11749,7 @@ struct fts5_api { #endif /* _FTS5_H */ - +/******** End of fts5.h *********/ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -8852,8 +11758,9 @@ struct fts5_api { ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ -#ifdef _HAVE_SQLITE_CONFIG_H -#include "config.h" +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) +/* #include "config.h" */ +#define SQLITECONFIG_H 1 #endif /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ @@ -8947,7 +11854,7 @@ struct fts5_api { ** Not currently enforced. */ #ifndef SQLITE_MAX_VDBE_OP -# define SQLITE_MAX_VDBE_OP 25000 +# define SQLITE_MAX_VDBE_OP 250000000 #endif /* @@ -8961,13 +11868,13 @@ struct fts5_api { ** The suggested maximum number of in-memory pages to use for ** the main database table and for temporary tables. ** -** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size -** is 2000 pages. +** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000, +** which means the cache size is limited to 2048000 bytes of memory. ** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be ** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options. */ #ifndef SQLITE_DEFAULT_CACHE_SIZE -# define SQLITE_DEFAULT_CACHE_SIZE 2000 +# define SQLITE_DEFAULT_CACHE_SIZE -2000 #endif /* @@ -8980,8 +11887,9 @@ struct fts5_api { /* ** The maximum number of attached databases. This must be between 0 -** and 62. The upper bound on 62 is because a 64-bit integer bitmap -** is used internally to track attached databases. +** and 125. The upper bound of 125 is because the attached databases are +** counted using a signed 8-bit integer which has a maximum value of 127 +** and we have to allow 2 extra counts for the "main" and "temp" databases. */ #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 @@ -9016,7 +11924,7 @@ struct fts5_api { ** The default size of a database page. */ #ifndef SQLITE_DEFAULT_PAGE_SIZE -# define SQLITE_DEFAULT_PAGE_SIZE 1024 +# define SQLITE_DEFAULT_PAGE_SIZE 4096 #endif #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE # undef SQLITE_DEFAULT_PAGE_SIZE @@ -9097,7 +12005,7 @@ struct fts5_api { ** to the next, so we have developed the following set of #if statements ** to generate appropriate macros for a wide range of compilers. ** -** The correct "ANSI" way to do this is to use the intptr_t type. +** The correct "ANSI" way to do this is to use the intptr_t type. ** Unfortunately, that typedef is not available on all compilers, or ** if it is available, it requires an #include of specific headers ** that vary from one machine to the next. @@ -9121,21 +12029,6 @@ struct fts5_api { # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif -/* -** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to -** something between S (inclusive) and E (exclusive). -** -** In other words, S is a buffer and E is a pointer to the first byte after -** the end of buffer S. This macro returns true if P points to something -** contained within the buffer S. -*/ -#if defined(HAVE_STDINT_H) -# define SQLITE_WITHIN(P,S,E) \ - ((uintptr_t)(P)>=(uintptr_t)(S) && (uintptr_t)(P)<(uintptr_t)(E)) -#else -# define SQLITE_WITHIN(P,S,E) ((P)>=(S) && (P)<(E)) -#endif - /* ** A macro to hint to the compiler that a function should not be ** inlined. @@ -9154,11 +12047,12 @@ struct fts5_api { ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) -# if defined(_MSC_VER) && _MSC_VER>=1300 +# if defined(_MSC_VER) && _MSC_VER>=1400 # if !defined(_WIN32_WCE) # include # pragma intrinsic(_byteswap_ushort) # pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_byteswap_uint64) # pragma intrinsic(_ReadWriteBarrier) # else # include @@ -9176,6 +12070,11 @@ struct fts5_api { ** ** Older versions of SQLite used an optional THREADSAFE macro. ** We support that for legacy. +** +** To ensure that the correct value of "THREADSAFE" is reported when querying +** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this +** logic is partially replicated in ctime.c. If it is updated here, it should +** also be updated there. */ #if !defined(SQLITE_THREADSAFE) # if defined(THREADSAFE) @@ -9264,7 +12163,7 @@ struct fts5_api { ** is set. Thus NDEBUG becomes an opt-in rather than an opt-out ** feature. */ -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) @@ -9279,7 +12178,7 @@ struct fts5_api { #endif /* -** The testcase() macro is used to aid in coverage testing. When +** The testcase() macro is used to aid in coverage testing. When ** doing coverage testing, the condition inside the argument to ** testcase() must be evaluated both true and false in order to ** get full branch coverage. The testcase() macro is inserted @@ -9325,7 +12224,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int); #endif /* -** The ALWAYS and NEVER macros surround boolean expressions which +** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they ** are included in a few cases in order to enhance the resilience @@ -9339,7 +12238,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int); ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ -#if defined(SQLITE_COVERAGE_TEST) +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) @@ -9350,6 +12249,36 @@ SQLITE_PRIVATE void sqlite3Coverage(int); # define NEVER(X) (X) #endif +/* +** Some conditionals are optimizations only. In other words, if the +** conditionals are replaced with a constant 1 (true) or 0 (false) then +** the correct answer is still obtained, though perhaps not as quickly. +** +** The following macros mark these optimizations conditionals. +*/ +#if defined(SQLITE_MUTATION_TEST) +# define OK_IF_ALWAYS_TRUE(X) (1) +# define OK_IF_ALWAYS_FALSE(X) (0) +#else +# define OK_IF_ALWAYS_TRUE(X) (X) +# define OK_IF_ALWAYS_FALSE(X) (X) +#endif + +/* +** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is +** defined. We need to defend against those failures when testing with +** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches +** during a normal build. The following macro can be used to disable tests +** that are always false except when SQLITE_TEST_REALLOC_STRESS is set. +*/ +#if defined(SQLITE_TEST_REALLOC_STRESS) +# define ONLY_IF_REALLOC_STRESS(X) (X) +#elif !defined(NDEBUG) +# define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0) +#else +# define ONLY_IF_REALLOC_STRESS(X) (0) +#endif + /* ** Declarations used for tracing the operating system interfaces. */ @@ -9376,6 +12305,13 @@ SQLITE_PRIVATE void sqlite3Coverage(int); # undef SQLITE_NEED_ERR_NAME #endif +/* +** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN +*/ +#ifdef SQLITE_OMIT_EXPLAIN +# undef SQLITE_ENABLE_EXPLAIN_COMMENTS +#endif + /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() @@ -9409,8 +12345,8 @@ SQLITE_PRIVATE void sqlite3Coverage(int); ** This is the header file for the generic hash-table implementation ** used in SQLite. */ -#ifndef _SQLITE_HASH_H_ -#define _SQLITE_HASH_H_ +#ifndef SQLITE_HASH_H +#define SQLITE_HASH_H /* Forward declarations of structures. */ typedef struct Hash Hash; @@ -9490,7 +12426,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); */ /* #define sqliteHashCount(H) ((H)->count) // NOT USED */ -#endif /* _SQLITE_HASH_H_ */ +#endif /* SQLITE_HASH_H */ /************** End of hash.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -9522,76 +12458,76 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_AS 24 #define TK_WITHOUT 25 #define TK_COMMA 26 -#define TK_ID 27 -#define TK_INDEXED 28 -#define TK_ABORT 29 -#define TK_ACTION 30 -#define TK_AFTER 31 -#define TK_ANALYZE 32 -#define TK_ASC 33 -#define TK_ATTACH 34 -#define TK_BEFORE 35 -#define TK_BY 36 -#define TK_CASCADE 37 -#define TK_CAST 38 -#define TK_COLUMNKW 39 -#define TK_CONFLICT 40 -#define TK_DATABASE 41 -#define TK_DESC 42 -#define TK_DETACH 43 -#define TK_EACH 44 -#define TK_FAIL 45 -#define TK_FOR 46 -#define TK_IGNORE 47 -#define TK_INITIALLY 48 -#define TK_INSTEAD 49 -#define TK_LIKE_KW 50 -#define TK_MATCH 51 -#define TK_NO 52 -#define TK_KEY 53 -#define TK_OF 54 -#define TK_OFFSET 55 -#define TK_PRAGMA 56 -#define TK_RAISE 57 -#define TK_RECURSIVE 58 -#define TK_REPLACE 59 -#define TK_RESTRICT 60 -#define TK_ROW 61 -#define TK_TRIGGER 62 -#define TK_VACUUM 63 -#define TK_VIEW 64 -#define TK_VIRTUAL 65 -#define TK_WITH 66 -#define TK_REINDEX 67 -#define TK_RENAME 68 -#define TK_CTIME_KW 69 -#define TK_ANY 70 -#define TK_OR 71 -#define TK_AND 72 -#define TK_IS 73 -#define TK_BETWEEN 74 -#define TK_IN 75 -#define TK_ISNULL 76 -#define TK_NOTNULL 77 -#define TK_NE 78 -#define TK_EQ 79 -#define TK_GT 80 -#define TK_LE 81 -#define TK_LT 82 -#define TK_GE 83 -#define TK_ESCAPE 84 -#define TK_BITAND 85 -#define TK_BITOR 86 -#define TK_LSHIFT 87 -#define TK_RSHIFT 88 -#define TK_PLUS 89 -#define TK_MINUS 90 -#define TK_STAR 91 -#define TK_SLASH 92 -#define TK_REM 93 -#define TK_CONCAT 94 -#define TK_COLLATE 95 -#define TK_BITNOT 96 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_FAIL 42 +#define TK_OR 43 +#define TK_AND 44 +#define TK_IS 45 +#define TK_MATCH 46 +#define TK_LIKE_KW 47 +#define TK_BETWEEN 48 +#define TK_IN 49 +#define TK_ISNULL 50 +#define TK_NOTNULL 51 +#define TK_NE 52 +#define TK_EQ 53 +#define TK_GT 54 +#define TK_LE 55 +#define TK_LT 56 +#define TK_GE 57 +#define TK_ESCAPE 58 +#define TK_ID 59 +#define TK_COLUMNKW 60 +#define TK_FOR 61 +#define TK_IGNORE 62 +#define TK_INITIALLY 63 +#define TK_INSTEAD 64 +#define TK_NO 65 +#define TK_KEY 66 +#define TK_OF 67 +#define TK_OFFSET 68 +#define TK_PRAGMA 69 +#define TK_RAISE 70 +#define TK_RECURSIVE 71 +#define TK_REPLACE 72 +#define TK_RESTRICT 73 +#define TK_ROW 74 +#define TK_TRIGGER 75 +#define TK_VACUUM 76 +#define TK_VIEW 77 +#define TK_VIRTUAL 78 +#define TK_WITH 79 +#define TK_REINDEX 80 +#define TK_RENAME 81 +#define TK_CTIME_KW 82 +#define TK_ANY 83 +#define TK_BITAND 84 +#define TK_BITOR 85 +#define TK_LSHIFT 86 +#define TK_RSHIFT 87 +#define TK_PLUS 88 +#define TK_MINUS 89 +#define TK_STAR 90 +#define TK_SLASH 91 +#define TK_REM 92 +#define TK_CONCAT 93 +#define TK_COLLATE 94 +#define TK_BITNOT 95 +#define TK_INDEXED 96 #define TK_STRING 97 #define TK_JOIN_KW 98 #define TK_CONSTRAINT 99 @@ -9627,9 +12563,9 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_LIMIT 129 #define TK_WHERE 130 #define TK_INTO 131 -#define TK_INTEGER 132 -#define TK_FLOAT 133 -#define TK_BLOB 134 +#define TK_FLOAT 132 +#define TK_BLOB 133 +#define TK_INTEGER 134 #define TK_VARIABLE 135 #define TK_CASE 136 #define TK_WHEN 137 @@ -9638,24 +12574,23 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_INDEX 140 #define TK_ALTER 141 #define TK_ADD 142 -#define TK_TO_TEXT 143 -#define TK_TO_BLOB 144 -#define TK_TO_NUMERIC 145 -#define TK_TO_INT 146 -#define TK_TO_REAL 147 -#define TK_ISNOT 148 -#define TK_END_OF_FILE 149 -#define TK_UNCLOSED_STRING 150 -#define TK_FUNCTION 151 -#define TK_COLUMN 152 -#define TK_AGG_FUNCTION 153 -#define TK_AGG_COLUMN 154 -#define TK_UMINUS 155 -#define TK_UPLUS 156 -#define TK_REGISTER 157 -#define TK_ASTERISK 158 -#define TK_SPACE 159 -#define TK_ILLEGAL 160 +#define TK_ISNOT 143 +#define TK_FUNCTION 144 +#define TK_COLUMN 145 +#define TK_AGG_FUNCTION 146 +#define TK_AGG_COLUMN 147 +#define TK_UMINUS 148 +#define TK_UPLUS 149 +#define TK_REGISTER 150 +#define TK_VECTOR 151 +#define TK_SELECT_COLUMN 152 +#define TK_IF_NULL_ROW 153 +#define TK_ASTERISK 154 +#define TK_SPAN 155 +#define TK_END_OF_FILE 156 +#define TK_UNCLOSED_STRING 157 +#define TK_SPACE 158 +#define TK_ILLEGAL 159 /* The token codes above must all fit in 8 bits */ #define TKFLG_MASK 0xff @@ -9672,6 +12607,18 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #include #include +/* +** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY. +** This allows better measurements of where memcpy() is used when running +** cachegrind. But this macro version of memcpy() is very slow so it +** should not be used in production. This is a performance measurement +** hack only. +*/ +#ifdef SQLITE_INLINE_MEMCPY +# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\ + int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);} +#endif + /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point @@ -9694,7 +12641,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); /* ** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0 -** afterward. Having this macro allows us to cause the C compiler +** afterward. Having this macro allows us to cause the C compiler ** to omit code used by TEMP tables without messy #ifndef statements. */ #ifdef SQLITE_OMIT_TEMPDB @@ -9728,12 +12675,11 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 -# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif /* ** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if -** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it +** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it ** to zero. */ #if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0 @@ -9756,9 +12702,21 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); ** pagecaches for each database connection. A positive number is the ** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. +** +** The default value of "20" was choosen to minimize the run-time of the +** speedtest1 test program with options: --shrink-memory --reprepare */ #ifndef SQLITE_DEFAULT_PCACHE_INITSZ -# define SQLITE_DEFAULT_PCACHE_INITSZ 100 +# define SQLITE_DEFAULT_PCACHE_INITSZ 20 +#endif + +/* +** The compile-time options SQLITE_MMAP_READWRITE and +** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another. +** You must choose one or the other (or neither) but not both. +*/ +#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) +#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE #endif /* @@ -9772,8 +12730,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); /* ** Macros to compute minimum and maximum of two numbers. */ -#define MIN(A,B) ((A)<(B)?(A):(B)) -#define MAX(A,B) ((A)>(B)?(A):(B)) +#ifndef MIN +# define MIN(A,B) ((A)<(B)?(A):(B)) +#endif +#ifndef MAX +# define MAX(A,B) ((A)>(B)?(A):(B)) +#endif /* ** Swap two objects of type TYPE. @@ -9881,7 +12843,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */ ** 4 -> 20 1000 -> 99 1048576 -> 200 ** 10 -> 33 1024 -> 100 4294967296 -> 320 ** -** The LogEst can be negative to indicate fractional values. +** The LogEst can be negative to indicate fractional values. ** Examples: ** ** 0.5 -> -10 0.1 -> -33 0.0625 -> -40 @@ -9902,38 +12864,62 @@ typedef INT16_TYPE LogEst; # endif #endif +/* The uptr type is an unsigned integer large enough to hold a pointer +*/ +#if defined(HAVE_STDINT_H) + typedef uintptr_t uptr; +#elif SQLITE_PTRSIZE==4 + typedef u32 uptr; +#else + typedef u64 uptr; +#endif + +/* +** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to +** something between S (inclusive) and E (exclusive). +** +** In other words, S is a buffer and E is a pointer to the first byte after +** the end of buffer S. This macro returns true if P points to something +** contained within the buffer S. +*/ +#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E))) + + /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. ** ** For best performance, an attempt is made to guess at the byte-order ** using C-preprocessor macros. If that is unsuccessful, or if -** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. */ -#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \ +#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(SQLITE_RUNTIME_BYTEORDER) -# define SQLITE_BYTEORDER 1234 -# define SQLITE_BIGENDIAN 0 -# define SQLITE_LITTLEENDIAN 1 -# define SQLITE_UTF16NATIVE SQLITE_UTF16LE + defined(__arm__) +# define SQLITE_BYTEORDER 1234 +# elif defined(sparc) || defined(__ppc__) +# define SQLITE_BYTEORDER 4321 +# else +# define SQLITE_BYTEORDER 0 +# endif #endif -#if (defined(sparc) || defined(__ppc__)) \ - && !defined(SQLITE_RUNTIME_BYTEORDER) -# define SQLITE_BYTEORDER 4321 +#if SQLITE_BYTEORDER==4321 # define SQLITE_BIGENDIAN 1 # define SQLITE_LITTLEENDIAN 0 # define SQLITE_UTF16NATIVE SQLITE_UTF16BE -#endif -#if !defined(SQLITE_BYTEORDER) +#elif SQLITE_BYTEORDER==1234 +# define SQLITE_BIGENDIAN 0 +# define SQLITE_LITTLEENDIAN 1 +# define SQLITE_UTF16NATIVE SQLITE_UTF16LE +#else # ifdef SQLITE_AMALGAMATION const int sqlite3one = 1; # else extern const int sqlite3one; # endif -# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) @@ -9947,7 +12933,7 @@ typedef INT16_TYPE LogEst; #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) -/* +/* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. */ @@ -9986,10 +12972,6 @@ typedef INT16_TYPE LogEst; */ #ifdef __APPLE__ # include -# if TARGET_OS_IPHONE -# undef SQLITE_MAX_MMAP_SIZE -# define SQLITE_MAX_MMAP_SIZE 0 -# endif #endif #ifndef SQLITE_MAX_MMAP_SIZE # if defined(__linux__) \ @@ -10002,7 +12984,6 @@ typedef INT16_TYPE LogEst; # else # define SQLITE_MAX_MMAP_SIZE 0 # endif -# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ #endif /* @@ -10012,7 +12993,6 @@ typedef INT16_TYPE LogEst; */ #ifndef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE 0 -# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */ #endif #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE # undef SQLITE_DEFAULT_MMAP_SIZE @@ -10037,7 +13017,7 @@ typedef INT16_TYPE LogEst; ** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not ** the Select query generator tracing logic is turned on. */ -#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE) +#if defined(SQLITE_ENABLE_SELECTTRACE) # define SELECTTRACE_ENABLED 1 #else # define SELECTTRACE_ENABLED 0 @@ -10045,7 +13025,7 @@ typedef INT16_TYPE LogEst; /* ** An instance of the following structure is used to store the busy-handler -** callback for a given sqlite handle. +** callback for a given sqlite handle. ** ** The sqlite.busyHandler member of the sqlite struct contains the busy ** callback for the database handle. Each pager opened via the sqlite @@ -10090,9 +13070,9 @@ struct BusyHandler { /* ** The following value as a destructor means to use sqlite3DbFree(). -** The sqlite3DbFree() routine requires two parameters instead of the -** one parameter that destructors normally want. So we have to introduce -** this magic value that the code knows to handle differently. Any +** The sqlite3DbFree() routine requires two parameters instead of the +** one parameter that destructors normally want. So we have to introduce +** this magic value that the code knows to handle differently. Any ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ @@ -10116,19 +13096,19 @@ struct BusyHandler { #define SQLITE_WSD const #define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v))) #define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config) -SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J); -SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L); +SQLITE_API int sqlite3_wsd_init(int N, int J); +SQLITE_API void *sqlite3_wsd_find(void *K, int L); #else - #define SQLITE_WSD + #define SQLITE_WSD #define GLOBAL(t,v) v #define sqlite3GlobalConfig sqlite3Config #endif /* ** The following macros are used to suppress compiler warnings and to -** make it clear to human readers when a function parameter is deliberately +** make it clear to human readers when a function parameter is deliberately ** left unused within the body of a function. This usually happens when -** a function is called via a function pointer. For example the +** a function is called via a function pointer. For example the ** implementation of an SQL aggregate step callback may not use the ** parameter indicating the number of arguments passed to the aggregate, ** if it knows that this is enforced elsewhere. @@ -10171,6 +13151,7 @@ typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; +typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; @@ -10193,8 +13174,16 @@ typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; typedef struct With With; +/* A VList object records a mapping between parameters/variables/wildcards +** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer +** variable number associated with that parameter. See the format description +** on the sqlite3VListAdd() routine for more information. A VList is really +** just an array of integers. +*/ +typedef int VList; + /* -** Defer sourcing vdbe.h and btree.h until after the "u8" and +** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ @@ -10215,8 +13204,8 @@ typedef struct With With; ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. */ -#ifndef _BTREE_H_ -#define _BTREE_H_ +#ifndef SQLITE_BTREE_H +#define SQLITE_BTREE_H /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. @@ -10241,6 +13230,7 @@ typedef struct With With; typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; +typedef struct BtreePayload BtreePayload; SQLITE_PRIVATE int sqlite3BtreeOpen( @@ -10270,7 +13260,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); -SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); @@ -10292,7 +13281,9 @@ SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); +#ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); +#endif SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int); SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); @@ -10401,14 +13392,24 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); ** Flags passed as the third argument to sqlite3BtreeCursor(). ** ** For read-only cursors the wrFlag argument is always zero. For read-write -** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or -** (BTREE_WRCSR). If the BTREE_FORDELETE flag is set, then the cursor will +** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just +** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will ** only be used by SQLite for the following: ** -** * to seek to and delete specific entries, and/or +** * to seek to and then delete specific entries, and/or ** ** * to read values that will be used to create keys that other ** BTREE_FORDELETE cursors will seek to and delete. +** +** The BTREE_FORDELETE flag is an optimization hint. It is not used by +** by this, the native b-tree engine of SQLite, but it is available to +** alternative storage engines that might be substituted in place of this +** b-tree system. For alternative storage engines in which a delete of +** the main table row automatically deletes corresponding index rows, +** the FORDELETE flag hint allows those alternative storage engines to +** skip a lot of work. Namely: FORDELETE cursors may treat all SEEK +** and DELETE operations as no-ops, and any READ operation against a +** FORDELETE cursor may return a null row: 0x01 0x00. */ #define BTREE_WRCSR 0x00000004 /* read-write cursor */ #define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */ @@ -10420,6 +13421,7 @@ SQLITE_PRIVATE int sqlite3BtreeCursor( struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); @@ -10437,27 +13439,62 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( ); SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*); -SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, int); -SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, - const void *pData, int nData, - int nZero, int bias, int seekResult); +SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); + +/* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */ +#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ +#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ +#define BTREE_APPEND 0x08 /* Insert is likely an append */ + +/* An instance of the BtreePayload object describes the content of a single +** entry in either an index or table btree. +** +** Index btrees (used for indexes and also WITHOUT ROWID tables) contain +** an arbitrary key and no data. These btrees have pKey,nKey set to their +** key and pData,nData,nZero set to zero. +** +** Table btrees (used for rowid tables) contain an integer rowid used as +** the key and passed in the nKey field. The pKey field is zero. +** pData,nData hold the content of the new entry. nZero extra zero bytes +** are appended to the end of the content when constructing the entry. +** +** This object is used to pass information into sqlite3BtreeInsert(). The +** same information used to be passed as five separate parameters. But placing +** the information into this object helps to keep the interface more +** organized and understandable, and it also helps the resulting code to +** run a little faster by using fewer registers for parameter passing. +*/ +struct BtreePayload { + const void *pKey; /* Key content for indexes. NULL for tables */ + sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ + const void *pData; /* Data for tables. NULL for indexes */ + sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */ + u16 nMem; /* Number of aMem[] value. Might be zero */ + int nData; /* Size of pData. 0 if none. */ + int nZero; /* Extra zero data appended after pData,nData */ +}; + +SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, + int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); -SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); -SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); -SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt); -SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt); -SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); -SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags); +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(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 char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*); +#ifndef SQLITE_OMIT_INCRBLOB +SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *); +#endif SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); @@ -10467,6 +13504,7 @@ SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void); #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif +SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*); #ifndef SQLITE_OMIT_BTREECOUNT SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *); @@ -10489,15 +13527,19 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); +SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) +# define sqlite3BtreeSharable(X) 0 +# define sqlite3BtreeEnterCursor(X) +# define sqlite3BtreeConnectionCount(X) 1 #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE -SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); -SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG @@ -10508,9 +13550,7 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); #endif #else -# define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeLeave(X) -# define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) @@ -10520,7 +13560,7 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); #endif -#endif /* _BTREE_H_ */ +#endif /* SQLITE_BTREE_H */ /************** End of btree.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -10543,8 +13583,8 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ -#ifndef _SQLITE_VDBE_H_ -#define _SQLITE_VDBE_H_ +#ifndef SQLITE_VDBE_H +#define SQLITE_VDBE_H /* #include */ /* @@ -10558,7 +13598,7 @@ typedef struct Vdbe Vdbe; ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ -typedef struct Mem Mem; +typedef struct sqlite3_value Mem; typedef struct SubProgram SubProgram; /* @@ -10569,8 +13609,7 @@ typedef struct SubProgram SubProgram; struct VdbeOp { u8 opcode; /* What operation to perform */ signed char p4type; /* One of the P4_xxx constants for p4 */ - u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */ - u8 p5; /* Fifth parameter is an unsigned character */ + u16 p5; /* Fifth parameter is an unsigned 16-bit integer */ int p1; /* First operand */ int p2; /* Second parameter (often the jump destination) */ int p3; /* The third parameter */ @@ -10588,10 +13627,11 @@ struct VdbeOp { KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ + Table *pTab; /* Used when p4type is P4_TABLE */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif - int (*xAdvance)(BtCursor *, int *); + int (*xAdvance)(BtCursor *, int); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ @@ -10615,7 +13655,7 @@ struct SubProgram { int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ - int nOnce; /* Number of OP_Once instructions */ + u8 *aOnce; /* Array of OP_Once flags */ void *token; /* id that may be used to recursive triggers */ SubProgram *pNext; /* Next sub-program already visited */ }; @@ -10635,24 +13675,26 @@ typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ -#define P4_NOTUSED 0 /* The P4 parameter is not used */ -#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ -#define P4_STATIC (-2) /* Pointer to a static string */ -#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ -#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ -#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ -#define P4_EXPR (-7) /* P4 is a pointer to an Expr tree */ -#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ -#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ -#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ -#define P4_REAL (-12) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ -#define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ -#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ -#define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ -#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ -#define P4_FUNCCTX (-20) /* P4 is a pointer to an sqlite3_context object */ +#define P4_NOTUSED 0 /* The P4 parameter is not used */ +#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ +#define P4_STATIC (-1) /* Pointer to a static string */ +#define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ +#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ +#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ +#define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */ +#define P4_TABLE (-6) /* P4 is a pointer to a Table structure */ +/* Above do not own any resources. Must free those below */ +#define P4_FREE_IF_LE (-7) +#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ +#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ +#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ +#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -10695,205 +13737,226 @@ typedef struct VdbeOpList VdbeOpList; /************** Begin file opcodes.h *****************************************/ /* Automatically generated. Do not edit */ /* See the tool/mkopcodeh.tcl script for details */ -#define OP_Savepoint 1 -#define OP_AutoCommit 2 -#define OP_Transaction 3 -#define OP_SorterNext 4 -#define OP_PrevIfOpen 5 -#define OP_NextIfOpen 6 -#define OP_Prev 7 -#define OP_Next 8 -#define OP_Checkpoint 9 -#define OP_JournalMode 10 -#define OP_Vacuum 11 -#define OP_VFilter 12 /* synopsis: iplan=r[P3] zplan='P4' */ -#define OP_VUpdate 13 /* synopsis: data=r[P3@P2] */ -#define OP_Goto 14 -#define OP_Gosub 15 -#define OP_Return 16 -#define OP_InitCoroutine 17 -#define OP_EndCoroutine 18 +#define OP_Savepoint 0 +#define OP_AutoCommit 1 +#define OP_Transaction 2 +#define OP_SorterNext 3 /* jump */ +#define OP_PrevIfOpen 4 /* jump */ +#define OP_NextIfOpen 5 /* jump */ +#define OP_Prev 6 /* jump */ +#define OP_Next 7 /* jump */ +#define OP_Checkpoint 8 +#define OP_JournalMode 9 +#define OP_Vacuum 10 +#define OP_VFilter 11 /* jump, synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */ +#define OP_Goto 13 /* jump */ +#define OP_Gosub 14 /* jump */ +#define OP_InitCoroutine 15 /* jump */ +#define OP_Yield 16 /* jump */ +#define OP_MustBeInt 17 /* jump */ +#define OP_Jump 18 /* jump */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_Yield 20 -#define OP_HaltIfNull 21 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 22 -#define OP_Integer 23 /* synopsis: r[P2]=P1 */ -#define OP_Int64 24 /* synopsis: r[P2]=P4 */ -#define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 26 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 27 /* synopsis: r[P1]=NULL */ -#define OP_Blob 28 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 29 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 30 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 31 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 32 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 33 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 34 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 35 -#define OP_Function0 36 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Function 37 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_AddImm 38 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_MustBeInt 39 -#define OP_RealAffinity 40 -#define OP_Cast 41 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 42 -#define OP_Compare 43 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Jump 44 -#define OP_Once 45 -#define OP_If 46 -#define OP_IfNot 47 -#define OP_Column 48 /* synopsis: r[P3]=PX */ -#define OP_Affinity 49 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 50 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 51 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 52 -#define OP_SetCookie 53 -#define OP_ReopenIdx 54 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 55 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 56 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 57 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 58 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 59 -#define OP_SequenceTest 60 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_OpenPseudo 61 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 62 -#define OP_ColumnsUsed 63 -#define OP_SeekLT 64 /* synopsis: key=r[P3@P4] */ -#define OP_SeekLE 65 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGE 66 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGT 67 /* synopsis: key=r[P3@P4] */ -#define OP_Seek 68 /* synopsis: intkey=r[P2] */ -#define OP_NoConflict 69 /* synopsis: key=r[P3@P4] */ -#define OP_NotFound 70 /* synopsis: key=r[P3@P4] */ -#define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ -#define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_Found 73 /* synopsis: key=r[P3@P4] */ -#define OP_NotExists 74 /* synopsis: intkey=r[P3] */ -#define OP_Sequence 75 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ -#define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ -#define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */ -#define OP_Eq 79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */ -#define OP_Gt 80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */ -#define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */ -#define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]=r[P3] goto P2 */ -#define OP_NewRowid 84 /* synopsis: r[P2]=rowid */ -#define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ -#define OP_Add 89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_Insert 95 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ +#define OP_Once 20 /* jump */ +#define OP_If 21 /* jump */ +#define OP_IfNot 22 /* jump */ +#define OP_IfNullRow 23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ +#define OP_SeekLT 24 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekLE 25 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGE 26 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGT 27 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */ +#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */ +#define OP_Last 33 /* jump */ +#define OP_IfSmaller 34 /* jump */ +#define OP_SorterSort 35 /* jump */ +#define OP_Sort 36 /* jump */ +#define OP_Rewind 37 /* jump */ +#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */ +#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ +#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ +#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 46 /* jump */ +#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ +#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ +#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ +#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ +#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ +#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ +#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ +#define OP_ElseNotEq 58 /* jump, same as TK_ESCAPE */ +#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 60 /* jump */ +#define OP_VNext 61 /* jump */ +#define OP_Init 62 /* jump, synopsis: Start at P2 */ +#define OP_Return 63 +#define OP_EndCoroutine 64 +#define OP_HaltIfNull 65 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 66 +#define OP_Integer 67 /* synopsis: r[P2]=P1 */ +#define OP_Int64 68 /* synopsis: r[P2]=P4 */ +#define OP_String 69 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 70 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 71 /* synopsis: r[P1]=NULL */ +#define OP_Blob 72 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 73 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 74 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 75 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 76 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 77 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 78 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 79 +#define OP_AddImm 80 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 81 +#define OP_Cast 82 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 83 +#define OP_BitAnd 84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 88 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 89 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 90 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_Compare 94 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_BitNot 95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ +#define OP_Column 96 /* synopsis: r[P3]=PX */ #define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_InsertInt 98 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 99 -#define OP_ResetCount 100 -#define OP_SorterCompare 101 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 102 /* synopsis: r[P2]=data */ -#define OP_RowKey 103 /* synopsis: r[P2]=key */ -#define OP_RowData 104 /* synopsis: r[P2]=data */ -#define OP_Rowid 105 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 106 -#define OP_Last 107 -#define OP_SorterSort 108 -#define OP_Sort 109 -#define OP_Rewind 110 -#define OP_SorterInsert 111 -#define OP_IdxInsert 112 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 113 /* synopsis: key=r[P2@P3] */ -#define OP_IdxRowid 114 /* synopsis: r[P2]=rowid */ -#define OP_IdxLE 115 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGT 116 /* synopsis: key=r[P3@P4] */ -#define OP_IdxLT 117 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGE 118 /* synopsis: key=r[P3@P4] */ -#define OP_Destroy 119 -#define OP_Clear 120 -#define OP_ResetSorter 121 -#define OP_CreateIndex 122 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_CreateTable 123 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_ParseSchema 124 -#define OP_LoadAnalysis 125 -#define OP_DropTable 126 -#define OP_DropIndex 127 -#define OP_DropTrigger 128 -#define OP_IntegrityCk 129 -#define OP_RowSetAdd 130 /* synopsis: rowset(P1)=r[P2] */ -#define OP_RowSetRead 131 /* synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 132 /* synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_Program 134 -#define OP_Param 135 -#define OP_FkCounter 136 /* synopsis: fkctr[P1]+=P2 */ -#define OP_FkIfZero 137 /* synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_MemMax 138 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_IfPos 139 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_SetIfNotPos 140 /* synopsis: if r[P1]<=0 then r[P2]=P3 */ -#define OP_IfNotZero 141 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */ -#define OP_DecrJumpZero 142 /* synopsis: if (--r[P1])==0 goto P2 */ -#define OP_JumpZeroIncr 143 /* synopsis: if (r[P1]++)==0 ) goto P2 */ -#define OP_AggStep0 144 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 145 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 146 /* synopsis: accum=r[P1] N=P2 */ -#define OP_IncrVacuum 147 -#define OP_Expire 148 -#define OP_TableLock 149 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 150 -#define OP_VCreate 151 -#define OP_VDestroy 152 -#define OP_VOpen 153 -#define OP_VColumn 154 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VNext 155 -#define OP_VRename 156 -#define OP_Pagecount 157 -#define OP_MaxPgcnt 158 -#define OP_Init 159 /* synopsis: Start at P2 */ -#define OP_CursorHint 160 -#define OP_Noop 161 -#define OP_Explain 162 +#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 100 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 101 +#define OP_SetCookie 102 +#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenDup 106 +#define OP_OpenAutoindex 107 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 108 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 109 +#define OP_SequenceTest 110 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 111 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 112 +#define OP_ColumnsUsed 113 +#define OP_Sequence 114 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 115 /* synopsis: r[P2]=rowid */ +#define OP_Insert 116 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 117 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 118 +#define OP_ResetCount 119 +#define OP_SorterCompare 120 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 121 /* synopsis: r[P2]=data */ +#define OP_RowData 122 /* synopsis: r[P2]=data */ +#define OP_Rowid 123 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 124 +#define OP_SeekEnd 125 +#define OP_SorterInsert 126 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 127 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 128 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 129 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 130 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 131 +#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_Clear 133 +#define OP_ResetSorter 134 +#define OP_CreateBtree 135 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 136 +#define OP_ParseSchema 137 +#define OP_LoadAnalysis 138 +#define OP_DropTable 139 +#define OP_DropIndex 140 +#define OP_DropTrigger 141 +#define OP_IntegrityCk 142 +#define OP_RowSetAdd 143 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 144 +#define OP_FkCounter 145 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 146 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 147 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 148 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 149 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 150 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 151 +#define OP_TableLock 152 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 153 +#define OP_VCreate 154 +#define OP_VDestroy 155 +#define OP_VOpen 156 +#define OP_VColumn 157 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 158 +#define OP_Pagecount 159 +#define OP_MaxPgcnt 160 +#define OP_PureFunc0 161 +#define OP_Function0 162 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_PureFunc 163 +#define OP_Function 164 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_CursorHint 165 +#define OP_Noop 166 +#define OP_Explain 167 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ -#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */ -#define OPFLG_IN1 0x0002 /* in1: P1 is an input */ -#define OPFLG_IN2 0x0004 /* in2: P2 is an input */ -#define OPFLG_IN3 0x0008 /* in3: P3 is an input */ -#define OPFLG_OUT2 0x0010 /* out2: P2 is an output */ -#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */ +#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */ +#define OPFLG_IN1 0x02 /* in1: P1 is an input */ +#define OPFLG_IN2 0x04 /* in2: P2 is an input */ +#define OPFLG_IN3 0x08 /* in3: P3 is an input */ +#define OPFLG_OUT2 0x10 /* out2: P2 is an output */ +#define OPFLG_OUT3 0x20 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ -/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,\ -/* 8 */ 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01,\ -/* 16 */ 0x02, 0x01, 0x02, 0x12, 0x03, 0x08, 0x00, 0x10,\ -/* 24 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 32 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03,\ -/* 40 */ 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03,\ -/* 48 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x08, 0x00, 0x00,\ -/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 64 */ 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x26,\ -/* 72 */ 0x26, 0x09, 0x09, 0x10, 0x03, 0x03, 0x0b, 0x0b,\ -/* 80 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x10, 0x26, 0x26, 0x26,\ -/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\ -/* 96 */ 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 104 */ 0x00, 0x10, 0x00, 0x01, 0x01, 0x01, 0x01, 0x04,\ -/* 112 */ 0x04, 0x00, 0x10, 0x01, 0x01, 0x01, 0x01, 0x10,\ -/* 120 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 128 */ 0x00, 0x00, 0x06, 0x23, 0x0b, 0x10, 0x01, 0x10,\ -/* 136 */ 0x00, 0x01, 0x04, 0x03, 0x06, 0x03, 0x03, 0x03,\ -/* 144 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x01,\ -/* 160 */ 0x00, 0x00, 0x00,} +/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\ +/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\ +/* 24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\ +/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\ +/* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x02,\ +/* 64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\ +/* 72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 80 */ 0x02, 0x02, 0x02, 0x00, 0x26, 0x26, 0x26, 0x26,\ +/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\ +/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x04,\ +/* 128 */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10,\ +/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\ +/* 144 */ 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ +/* 160 */ 0x10, 0x00, 0x00, 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 +** JUMP opcode the better, so the mkopcodeh.tcl script that +** generated this include file strives to group all JUMP opcodes +** together near the beginning of the list. +*/ +#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ +/* +** Additional non-public SQLITE_PREPARE_* flags +*/ +#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ +#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ + /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. @@ -10909,22 +13972,32 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); -SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); +SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int); +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) +SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); +SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p); +#else +# define sqlite3VdbeVerifyNoMallocRequired(A,B) +# define sqlite3VdbeVerifyNoResultRow(A) +#endif +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); -SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); +SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); -SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); +SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); +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 void sqlite3VdbeRunOnlyOnce(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); @@ -10941,7 +14014,8 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); +SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8); SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); @@ -10954,7 +14028,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); -SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); +SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); @@ -10963,6 +14037,8 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif +SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); + /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on ** each VDBE opcode. ** @@ -11029,7 +14105,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif -#endif +#endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -11051,8 +14127,8 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch ** at a time and provides a journal for rollback. */ -#ifndef _PAGER_H_ -#define _PAGER_H_ +#ifndef SQLITE_PAGER_H +#define SQLITE_PAGER_H /* ** Default maximum size for persistent journal files. A negative @@ -11105,7 +14181,11 @@ typedef struct PgHdr DbPage; #define PAGER_LOCKINGMODE_EXCLUSIVE 1 /* -** Numeric constants that encode the journalmode. +** Numeric constants that encode the journalmode. +** +** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY) +** are exposed in the API via the "PRAGMA journal_mode" command and +** therefore cannot be changed without a compatibility break. */ #define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ @@ -11123,15 +14203,21 @@ typedef struct PgHdr DbPage; /* ** Flags for sqlite3PagerSetFlags() +** +** Value constraints (enforced via assert()): +** PAGER_FULLFSYNC == SQLITE_FullFSync +** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync +** PAGER_CACHE_SPILL == SQLITE_CacheSpill */ #define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */ #define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */ #define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */ -#define PAGER_SYNCHRONOUS_MASK 0x03 /* Mask for three values above */ -#define PAGER_FULLFSYNC 0x04 /* PRAGMA fullfsync=ON */ -#define PAGER_CKPT_FULLFSYNC 0x08 /* PRAGMA checkpoint_fullfsync=ON */ -#define PAGER_CACHESPILL 0x10 /* PRAGMA cache_spill=ON */ -#define PAGER_FLAGS_MASK 0x1c /* All above except SYNCHRONOUS */ +#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */ +#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */ +#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */ +#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */ +#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */ +#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */ /* ** The remainder of this file contains the declarations of the functions @@ -11149,7 +14235,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( int, void(*)(DbPage*) ); -SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*); SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ @@ -11178,6 +14264,7 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*); /* Operations on page references. */ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); @@ -11200,15 +14287,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); #ifndef SQLITE_OMIT_WAL -SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*); +SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); 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); +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); +SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); # endif +#else +# define sqlite3PagerUseWal(x,y) 0 #endif #ifdef SQLITE_ENABLE_ZIPVFS @@ -11227,11 +14320,10 @@ SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); -SQLITE_PRIVATE int sqlite3PagerNosync(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); -SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *); +SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ @@ -11258,7 +14350,7 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); # define enable_simulated_io_errors() #endif -#endif /* _PAGER_H_ */ +#endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -11292,7 +14384,8 @@ struct PgHdr { sqlite3_pcache_page *pPage; /* Pcache object page handle */ void *pData; /* Page data */ void *pExtra; /* Extra content */ - PgHdr *pDirty; /* Transient list of dirty pages */ + PCache *pCache; /* PRIVATE: Cache that owns this page */ + PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES @@ -11301,14 +14394,15 @@ struct PgHdr { u16 flags; /* PGHDR flags defined below */ /********************************************************************** - ** Elements above are public. All that follows is private to pcache.c - ** and should not be accessed by other modules. + ** Elements above, except pCache, are public. All that follow are + ** private to pcache.c and should not be accessed by other modules. + ** pCache is grouped with the public elements for efficiency. */ i16 nRef; /* Number of users of this page */ - PCache *pCache; /* Cache that owns this page */ - PgHdr *pDirtyNext; /* Next element in list of dirty pages */ PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ + /* NB: pDirtyNext and pDirtyPrev are undefined if the + ** PgHdr object is not dirty */ }; /* Bit values for PgHdr.flags */ @@ -11317,9 +14411,10 @@ struct PgHdr { #define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before ** writing this page to the database */ -#define PGHDR_NEED_READ 0x010 /* Content is unread */ -#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ -#define PGHDR_MMAP 0x040 /* This is an mmap page object */ +#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */ +#define PGHDR_MMAP 0x020 /* This is an mmap page object */ + +#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */ /* Initialize and shutdown the page cache subsystem */ SQLITE_PRIVATE int sqlite3PcacheInitialize(void); @@ -11363,6 +14458,7 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */ SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */ +SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*); /* Change a page number. Used by incr-vacuum. */ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno); @@ -11401,6 +14497,11 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*); SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #endif +#if defined(SQLITE_DEBUG) +/* Check invariants on a PgHdr object */ +SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*); +#endif + /* Set and get the suggested cache-size for the specified pager-cache. ** ** If no global maximum is configured, then the system attempts to limit @@ -11437,11 +14538,13 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void); SQLITE_PRIVATE int sqlite3HeaderSizePcache(void); SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); +/* Number of dirty pages as a percentage of the configured cache size */ +SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); + #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ - /************** Include os.h in the middle of sqliteInt.h ********************/ /************** Begin file os.h **********************************************/ /* @@ -11487,8 +14590,8 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); ** This file contains pre-processor directives related to operating system ** detection and/or setup. */ -#ifndef _OS_SETUP_H_ -#define _OS_SETUP_H_ +#ifndef SQLITE_OS_SETUP_H +#define SQLITE_OS_SETUP_H /* ** Figure out if we are dealing with Unix, Windows, or some other operating @@ -11528,7 +14631,7 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); # endif #endif -#endif /* _OS_SETUP_H_ */ +#endif /* SQLITE_OS_SETUP_H */ /************** End of os_setup.h ********************************************/ /************** Continuing where we left off in os.h *************************/ @@ -11667,7 +14770,7 @@ SQLITE_PRIVATE int sqlite3OsInit(void); /* ** Functions for accessing sqlite3_file methods */ -SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*); +SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*); SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size); @@ -11681,10 +14784,12 @@ SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); +#ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int); SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int); +#endif /* SQLITE_OMIT_WAL */ SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *); @@ -11704,6 +14809,7 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *); #endif /* SQLITE_OMIT_LOAD_EXTENSION */ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *); SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int); +SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*); SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); /* @@ -11711,7 +14817,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); ** sqlite3_malloc() to obtain space for the file-handle structure. */ SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); -SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *); +SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *); #endif /* _SQLITE_OS_H_ */ @@ -11793,6 +14899,36 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *); /************** End of mutex.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ +/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default +** synchronous setting to EXTRA. It is no longer supported. +*/ +#ifdef SQLITE_EXTRA_DURABLE +# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE +# define SQLITE_DEFAULT_SYNCHRONOUS 3 +#endif + +/* +** Default synchronous levels. +** +** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ +** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1. +** +** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS +** OFF 1 0 +** NORMAL 2 1 +** FULL 3 2 +** EXTRA 4 3 +** +** The "PRAGMA synchronous" statement also uses the zero-based numbers. +** In other words, the zero-based numbers are used for all external interfaces +** and the one-based values are used internally. +*/ +#ifndef SQLITE_DEFAULT_SYNCHRONOUS +# define SQLITE_DEFAULT_SYNCHRONOUS 2 +#endif +#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS +# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS +#endif /* ** Each database file to be accessed by the system is an instance @@ -11802,9 +14938,10 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *); ** databases may be attached. */ struct Db { - char *zName; /* Name of this database */ + char *zDbSName; /* Name of this database. (schema name, not filename) */ Btree *pBt; /* The B*Tree structure for this database file */ u8 safety_level; /* How aggressive at syncing data to disk */ + u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; @@ -11815,7 +14952,7 @@ struct Db { ** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing. ** In shared cache mode, a single Schema object can be shared by multiple ** Btrees that refer to the same underlying BtShared object. -** +** ** Schema objects are automatically deallocated when the last Btree that ** references them is destroyed. The TEMP Schema is manually freed by ** sqlite3_close(). @@ -11840,7 +14977,7 @@ struct Schema { }; /* -** These macros can be used to test, set, or clear bits in the +** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) @@ -11861,6 +14998,7 @@ struct Schema { #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ +#define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */ /* ** The number of different kinds of things that can be limited @@ -11889,12 +15027,12 @@ struct Schema { ** lookaside allocations are not used to construct the schema objects. */ struct Lookaside { + u32 bDisable; /* Only operate the lookaside when zero */ u16 sz; /* Size of each buffer in bytes */ - u8 bEnabled; /* False to disable new lookaside allocations */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ - int nOut; /* Number of buffers currently checked out */ - int mxOut; /* Highwater mark for nOut */ - int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ + u32 nSlot; /* Number of lookaside slots allocated */ + u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ + LookasideSlot *pInit; /* List of buffers not previously used */ LookasideSlot *pFree; /* List of available buffers */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ @@ -11904,13 +15042,15 @@ struct LookasideSlot { }; /* -** A hash table for function definitions. +** A hash table for built-in function definitions. (Application-defined +** 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.pHash chain. +** Collisions are on the FuncDef.u.pHash chain. */ +#define SQLITE_FUNC_HASH_SZ 23 struct FuncDefHash { - FuncDef *a[23]; /* Hash table for functions */ + FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; #ifdef SQLITE_USER_AUTHENTICATION @@ -11951,6 +15091,15 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); const char*); #endif +#ifndef SQLITE_OMIT_DEPRECATED +/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing +** in the style of sqlite3_trace() +*/ +#define SQLITE_TRACE_LEGACY 0x80 +#else +#define SQLITE_TRACE_LEGACY 0 +#endif /* SQLITE_OMIT_DEPRECATED */ + /* ** Each database connection is an instance of the following structure. @@ -11962,22 +15111,29 @@ struct sqlite3 { sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ - int flags; /* Miscellaneous flags. See below */ + u32 mDbFlags; /* flags recording internal state */ + u32 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 */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ + int iSysErrno; /* Errno value from last system error */ u16 dbOptFlags; /* Flags to enable/disable optimizations */ u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ + u8 bBenignMalloc; /* Do not require OOMs if true */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ + u8 mTrace; /* zero or more SQLITE_TRACE flags */ + u8 skipBtreeMutex; /* True if no shared-cache backends */ + u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ int nextPagesize; /* Pagesize after VACUUM if >0 */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ @@ -11998,16 +15154,23 @@ struct sqlite3 { int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ - void (*xTrace)(void*,const char*); /* Trace function */ + int (*xTrace)(u32,void*,void*,void*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ - void *pCommitArg; /* Argument to xCommitCallback() */ + void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ - void *pRollbackArg; /* Argument to xRollbackCallback() */ + void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ + void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ + void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64 + ); + PreUpdate *pPreUpdate; /* Context for active pre-update callback */ +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifndef SQLITE_OMIT_WAL int (*xWalCallback)(void *, sqlite3 *, const char *, int); void *pWalArg; @@ -12037,7 +15200,7 @@ struct sqlite3 { VTable **aVTrans; /* Virtual tables with open transactions */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif - FuncDefHash aFunc; /* Hash table of connection functions */ + Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ @@ -12049,8 +15212,8 @@ struct sqlite3 { i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY - /* The following variables are all protected by the STATIC_MASTER - ** mutex, not by sqlite3.mutex. They are used by code in notify.c. + /* The following variables are all protected by the STATIC_MASTER + ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to ** unlock so that it can proceed. @@ -12078,40 +15241,54 @@ struct sqlite3 { /* ** Possible values for the sqlite3.flags. +** +** Value constraints (enforced via assert()): +** SQLITE_FullFSync == PAGER_FULLFSYNC +** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC +** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ -#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ -#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ -#define SQLITE_FullFSync 0x00000004 /* Use full fsync on the backend */ -#define SQLITE_CkptFullFSync 0x00000008 /* Use full fsync for checkpoint */ -#define SQLITE_CacheSpill 0x00000010 /* OK to spill pager cache */ -#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */ +#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */ +#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */ +#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ +#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ +#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ +#define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */ #define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ #define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ -#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ -#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ -#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ -#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */ -#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ -#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */ -#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */ -#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */ -#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */ -#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */ -#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */ -#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */ -#define SQLITE_EnableTrigger 0x00800000 /* True to enable triggers */ -#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */ -#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */ -#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */ -#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */ -#define SQLITE_CellSizeCk 0x10000000 /* Check btree cell sizes on load */ +#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ +#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ +#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ +#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ +#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */ +#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */ +#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */ +#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */ +#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */ +#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */ +#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */ +#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */ +#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ +#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee */ +/* Flags used only if debugging */ +#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 */ +#endif +/* +** Allowed values for sqlite3.mDbFlags +*/ +#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 */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the @@ -12122,27 +15299,22 @@ struct sqlite3 { #define SQLITE_ColumnCache 0x0002 /* Column cache */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ -/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */ -#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ -#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ -#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ -#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ -#define SQLITE_Transitive 0x0200 /* Transitive constraints */ -#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ +#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ +#define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */ +#define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */ +#define SQLITE_Transitive 0x0080 /* Transitive constraints */ +#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */ +#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */ +#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ -#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */ + /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ -#ifndef SQLITE_OMIT_BUILTIN_TEST #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) -#else -#define OptimizationDisabled(db, mask) 0 -#define OptimizationEnabled(db, mask) 1 -#endif /* ** Return true if it OK to factor constant expressions into the initialization @@ -12164,28 +15336,33 @@ struct sqlite3 { /* ** Each SQL function is defined by an instance of the following -** structure. A pointer to this structure is stored in the sqlite.aFunc -** hash table. When multiple functions have the same name, the hash table -** points to a linked list of these structures. +** structure. For global built-in functions (ex: substr(), max(), count()) +** a pointer to this structure is held in the sqlite3BuiltinFunctions object. +** For per-connection application-defined functions, a pointer to this +** structure is held in the db->aHash hash table. +** +** The u.pHash field is used by the global built-ins. The u.pDestructor +** field is used by per-connection app-def functions. */ struct FuncDef { - i16 nArg; /* Number of arguments. -1 means unlimited */ + i8 nArg; /* Number of arguments. -1 means unlimited */ u16 funcFlags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ - void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */ - void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */ - char *zName; /* SQL name of the function. */ - FuncDef *pHash; /* Next with a different name but the same hash */ - FuncDestructor *pDestructor; /* Reference counted destructor function */ + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */ + void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ + const char *zName; /* SQL name of the function. */ + union { + FuncDef *pHash; /* Next with a different name but the same hash */ + FuncDestructor *pDestructor; /* Reference counted destructor function */ + } u; }; /* ** This structure encapsulates a user-function destructor callback (as ** configured using create_function_v2()) and a reference counter. When ** create_function_v2() is called to create a function with a destructor, -** a single object of this type is allocated. FuncDestructor.nRef is set to +** a single object of this type is allocated. FuncDestructor.nRef is set to ** the number of FuncDef objects created (either 1 or 3, depending on whether ** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor ** member of each of the new FuncDef objects is set to point to the allocated @@ -12206,6 +15383,13 @@ struct FuncDestructor { ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And ** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There ** are assert() statements in the code to verify this. +** +** Value constraints (enforced via assert()): +** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg +** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG +** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG +** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ #define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */ @@ -12221,16 +15405,17 @@ struct FuncDestructor { #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ +#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are ** used to create the initializers for the FuncDef structures. ** ** FUNCTION(zName, nArg, iArg, bNC, xFunc) -** Used to create a scalar function definition of a function zName +** Used to create a scalar function definition of a function zName ** implemented by C function xFunc that accepts nArg arguments. The ** value passed as iArg is cast to a (void*) and made available -** as the user-data (sqlite3_user_data()) for the function. If +** as the user-data (sqlite3_user_data()) for the function. If ** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set. ** ** VFUNCTION(zName, nArg, iArg, bNC, xFunc) @@ -12240,7 +15425,14 @@ struct FuncDestructor { ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions ** and functions like sqlite_version() that can change, but not during -** a single query. +** a single query. The iArg is ignored. The user-data is always set +** to a NULL pointer. The bNC parameter is not used. +** +** PURE_DATE(zName, nArg, iArg, bNC, xFunc) +** Used for "pure" date/time functions, this macro is like DFUNCTION +** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is +** ignored and the user-data for these functions is set to an +** arbitrary non-NULL pointer. The bNC parameter is not used. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by @@ -12249,8 +15441,8 @@ struct FuncDestructor { ** FUNCTION(). ** ** LIKEFUNC(zName, nArg, pArg, flags) -** Used to create a scalar function definition of a function zName -** that accepts nArg arguments and is implemented by a call to C +** Used to create a scalar function definition of a function zName +** that accepts nArg arguments and is implemented by a call to C ** function likeFunc. Argument pArg is cast to a (void *) and made ** available as the function user-data (sqlite3_user_data()). The ** FuncDef.flags variable is set to the value passed as the flags @@ -12258,28 +15450,31 @@ struct FuncDestructor { */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ + 0, 0, xFunc, 0, #zName, {0} } +#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + (void*)&sqlite3Config, 0, xFunc, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - pArg, 0, xFunc, 0, 0, #zName, 0, 0} + pArg, 0, xFunc, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ - (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0} + (void *)arg, 0, likeFunc, 0, #zName, {0} } #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ - SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} /* ** All current savepoints are stored in a linked list starting at @@ -12321,10 +15516,8 @@ struct Module { ** of this structure. */ struct Column { - char *zName; /* Name of this column */ + char *zName; /* Name of this column, \000, then the type */ Expr *pDflt; /* Default value of this column */ - char *zDflt; /* Original text of the default value */ - char *zType; /* Data type for this column */ char *zColl; /* Collating sequence. If NULL, use the default */ u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ char affinity; /* One of the SQLITE_AFF_... values */ @@ -12336,6 +15529,7 @@ struct Column { */ #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ +#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ /* ** A "Collating Sequence" is defined by an instance of the following @@ -12366,7 +15560,7 @@ struct CollSeq { ** ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve -** the speed a little by numbering the values consecutively. +** the speed a little by numbering the values consecutively. ** ** But rather than start with 0 or 1, we begin with 'A'. That way, ** when multiple affinity types are concatenated into a string and @@ -12385,7 +15579,7 @@ struct CollSeq { /* ** The SQLITE_AFF_MASK values masks off the significant bits of an -** affinity value. +** affinity value. */ #define SQLITE_AFF_MASK 0x47 @@ -12398,6 +15592,7 @@ struct CollSeq { ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ +#define SQLITE_KEEPNULL 0x08 /* Used by vector == or <> */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ #define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ @@ -12405,20 +15600,20 @@ struct CollSeq { /* ** An object of this type is created for each virtual table present in -** the database schema. +** the database schema. ** ** If the database schema is shared, then there is one instance of this ** structure for each database connection (sqlite3*) that uses the shared ** schema. This is because each database connection requires its own unique -** instance of the sqlite3_vtab* handle used to access the virtual table -** implementation. sqlite3_vtab* handles can not be shared between -** database connections, even when the rest of the in-memory database +** instance of the sqlite3_vtab* handle used to access the virtual table +** implementation. sqlite3_vtab* handles can not be shared between +** database connections, even when the rest of the in-memory database ** schema is shared, as the implementation often stores the database ** connection handle passed to it via the xConnect() or xCreate() method ** during initialization internally. This database connection handle may -** then be used by the virtual table implementation to access real tables -** within the database. So that they appear as part of the callers -** transaction, these accesses need to be made via the same database +** then be used by the virtual table implementation to access real tables +** within the database. So that they appear as part of the callers +** transaction, these accesses need to be made via the same database ** connection as that used to execute SQL operations on the virtual table. ** ** All VTable objects that correspond to a single table in a shared @@ -12430,19 +15625,19 @@ struct CollSeq { ** sqlite3_vtab* handle in the compiled query. ** ** When an in-memory Table object is deleted (for example when the -** schema is being reloaded for some reason), the VTable objects are not -** deleted and the sqlite3_vtab* handles are not xDisconnect()ed +** schema is being reloaded for some reason), the VTable objects are not +** deleted and the sqlite3_vtab* handles are not xDisconnect()ed ** immediately. Instead, they are moved from the Table.pVTable list to ** another linked list headed by the sqlite3.pDisconnect member of the -** corresponding sqlite3 structure. They are then deleted/xDisconnected +** corresponding sqlite3 structure. They are then deleted/xDisconnected ** next time a statement is prepared using said sqlite3*. This is done ** to avoid deadlock issues involving multiple sqlite3.mutex mutexes. ** Refer to comments above function sqlite3VtabUnlockList() for an ** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect ** list without holding the corresponding sqlite3.mutex mutex. ** -** The memory for objects of this type is always allocated by -** sqlite3DbMalloc(), using the connection handle stored in VTable.db as +** The memory for objects of this type is always allocated by +** sqlite3DbMalloc(), using the connection handle stored in VTable.db as ** the first argument. */ struct VTable { @@ -12469,15 +15664,15 @@ struct Table { ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */ int tnum; /* Root BTree page for this table */ + u32 nTabRef; /* Number of pointers to this Table */ + u32 tabFlags; /* Mask of TF_* values */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ - u16 nRef; /* Number of pointers to this Table */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ #endif - u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ @@ -12501,15 +15696,17 @@ struct Table { ** the TF_OOOHidden attribute would apply in this case. Such tables require ** special handling during INSERT processing. */ -#define TF_Readonly 0x01 /* Read-only system table */ -#define TF_Ephemeral 0x02 /* An ephemeral table */ -#define TF_HasPrimaryKey 0x04 /* Table has a primary key */ -#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ -#define TF_Virtual 0x10 /* Is a virtual table */ -#define TF_WithoutRowid 0x20 /* No rowid. PRIMARY KEY is the key */ -#define TF_NoVisibleRowid 0x40 /* No user-visible "rowid" column */ -#define TF_OOOHidden 0x80 /* Out-of-Order hidden columns */ - +#define TF_Readonly 0x0001 /* Read-only system table */ +#define TF_Ephemeral 0x0002 /* An ephemeral table */ +#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */ +#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */ +#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ +#define TF_WithoutRowid 0x0020 /* No rowid. PRIMARY KEY is the key */ +#define TF_NoVisibleRowid 0x0040 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x0080 /* Out-of-Order hidden columns */ +#define TF_StatsUsed 0x0100 /* Query planner decisions affected by + ** Index.aiRowLogEst[] values */ +#define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ /* ** Test to see whether or not a table is a virtual table. This is @@ -12517,7 +15714,7 @@ struct Table { ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE -# define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0) +# define IsVirtual(X) ((X)->nModuleArg) #else # define IsVirtual(X) 0 #endif @@ -12610,7 +15807,7 @@ struct FKey { ** key is set to NULL. CASCADE means that a DELETE or UPDATE of the ** referenced table row is propagated into the row that holds the ** foreign key. -** +** ** The following symbolic values are used to record which type ** of action to take. */ @@ -12631,7 +15828,7 @@ struct FKey { /* ** An instance of the following structure is passed as the first -** argument to sqlite3VdbeKeyCompare and is used to control the +** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. ** ** Note that aSortOrder[] and aColl[] have nField+1 slots. There @@ -12641,8 +15838,8 @@ struct FKey { struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ - u16 nField; /* Number of key columns in the index */ - u16 nXField; /* Number of columns beyond the key columns */ + u16 nKeyField; /* Number of key columns in the index */ + u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortOrder; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ @@ -12672,7 +15869,7 @@ struct KeyInfo { ** The key comparison functions actually return default_rc when they find ** an equals comparison. default_rc can be -1, 0, or +1. If there are ** multiple entries in the b-tree with the same key (when only looking -** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to +** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to ** cause the search to find the last match, or +1 to cause the search to ** find the first match. ** @@ -12689,8 +15886,8 @@ struct UnpackedRecord { u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ - i8 r1; /* Value to return if (lhs > rhs) */ - i8 r2; /* Value to return if (rhs < lhs) */ + i8 r1; /* Value to return if (lhs < rhs) */ + i8 r2; /* Value to return if (lhs > rhs) */ u8 eqSeen; /* True if an equality comparison has been seen */ }; @@ -12709,7 +15906,7 @@ struct UnpackedRecord { ** In the Table structure describing Ex1, nCol==3 because there are ** three columns in the table. In the Index structure describing ** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. -** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the +** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. @@ -12717,7 +15914,7 @@ struct UnpackedRecord { ** The Index.onError field determines whether or not the indexed columns ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index -** and the value of Index.onError indicate the which conflict resolution +** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. ** @@ -12752,6 +15949,7 @@ struct Index { unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ + unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ @@ -12782,7 +15980,7 @@ struct Index { #define XN_EXPR (-2) /* Indexed column is an expression */ /* -** Each sample stored in the sqlite_stat3 table is represented in memory +** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ @@ -12877,9 +16075,9 @@ typedef int ynVar; ** to represent the greater-than-or-equal-to operator in the expression ** tree. ** -** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, +** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, ** or TK_STRING), then Expr.token contains the text of the SQL literal. If -** the expression is a variable (TK_VARIABLE), then Expr.token contains the +** the expression is a variable (TK_VARIABLE), then Expr.token contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), ** then Expr.token contains the name of the function. ** @@ -12890,7 +16088,7 @@ typedef int ynVar; ** a CASE expression or an IN expression of the form " IN (, ...)". ** Expr.x.pSelect is used if the expression is a sub-select or an expression of ** the form " IN (SELECT ...)". If the EP_xIsSelect bit is set in the -** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is +** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is ** valid. ** ** An expression of the form ID or ID.ID refers to a column in a table. @@ -12901,8 +16099,8 @@ typedef int ynVar; ** value is also stored in the Expr.iAgg column in the aggregate so that ** it can be accessed after all aggregates are computed. ** -** If the expression is an unbound variable marker (a question mark -** character '?' in the original SQL) then the Expr.iTable holds the index +** If the expression is an unbound variable marker (a question mark +** character '?' in the original SQL) then the Expr.iTable holds the index ** number for that variable. ** ** If the expression is a subquery then Expr.iColumn holds an integer @@ -12941,7 +16139,7 @@ struct Expr { /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to - ** access them will result in a segfault or malfunction. + ** access them will result in a segfault or malfunction. *********************************************************************/ Expr *pLeft; /* Left subnode */ @@ -12962,16 +16160,19 @@ struct Expr { int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old - ** EP_Unlikely: 134217728 times likelihood */ + ** EP_Unlikely: 134217728 times likelihood + ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. - ** TK_VARIABLE: variable number (always >= 1). */ + ** TK_VARIABLE: variable number (always >= 1). + ** 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 ** 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. */ + Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL + ** for a column of an index on an expression */ }; /* @@ -12979,8 +16180,8 @@ struct Expr { */ #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ -#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ -#define EP_Error 0x000008 /* Expression contains one or more errors */ + /* 0x000004 // available for use */ + /* 0x000008 // available for use */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ @@ -13000,6 +16201,7 @@ struct Expr { #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #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 */ /* ** Combinations of two or more EP_* flags @@ -13007,7 +16209,7 @@ struct Expr { #define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */ /* -** These macros can be used to test, set, or clear bits in the +** These macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(P))!=0) @@ -13026,8 +16228,8 @@ struct Expr { #endif /* -** Macros to determine the number of bytes required by a normal Expr -** struct, an Expr struct with the EP_Reduced flag set in Expr.flags +** Macros to determine the number of bytes required by a normal Expr +** struct, an Expr struct with the EP_Reduced flag set in Expr.flags ** and an Expr struct with the EP_TokenOnly flag set. */ #define EXPR_FULLSIZE sizeof(Expr) /* Full size */ @@ -13035,7 +16237,7 @@ struct Expr { #define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */ /* -** Flags passed to the sqlite3ExprDup() function. See the header comment +** Flags passed to the sqlite3ExprDup() function. See the header comment ** above sqlite3ExprDup() for details. */ #define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */ @@ -13059,7 +16261,7 @@ struct Expr { struct ExprList { int nExpr; /* Number of expressions on the list */ struct ExprList_item { /* For each expression in the list */ - Expr *pExpr; /* The list of expressions */ + Expr *pExpr; /* The parse tree for this expression */ char *zName; /* Token associated with this expression */ char *zSpan; /* Original text of the expression */ u8 sortOrder; /* 1 for DESC or 0 for ASC */ @@ -13073,7 +16275,7 @@ struct ExprList { } x; int iConstExprReg; /* Register in which Expr value is cached */ } u; - } *a; /* Alloc a power of two greater or equal to nExpr */ + } a[1]; /* One slot for each expression in the list */ }; /* @@ -13117,7 +16319,11 @@ struct IdList { ** tables in a join to 32 instead of 64. But it also reduces the size ** of the library by 738 bytes on ix86. */ -typedef u64 Bitmask; +#ifdef SQLITE_BITMASK_TYPE + typedef SQLITE_BITMASK_TYPE Bitmask; +#else + typedef u64 Bitmask; +#endif /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". @@ -13129,6 +16335,7 @@ typedef u64 Bitmask; */ #define MASKBIT(n) (((Bitmask)1)<<(n)) #define MASKBIT32(n) (((unsigned int)1)<<(n)) +#define ALLBITS ((Bitmask)-1) /* ** The following structure describes the FROM clause of a SELECT statement. @@ -13163,7 +16370,7 @@ struct SrcList { int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { - u8 jointype; /* Type of join between this able and the previous */ + u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ @@ -13201,22 +16408,28 @@ struct SrcList { /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin() ** and the WhereInfo.wctrlFlags member. +** +** Value constraints (enforced via assert()): +** WHERE_USE_LIMIT == SF_FixedLimit */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ #define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ -#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */ -#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ -#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ -#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ -#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */ -#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ -#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ -#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ -#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ -#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ -#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */ +#define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */ +#define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ +#define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of + ** the OR optimization */ +#define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ +#define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ +#define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ +#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ +#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */ +#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ +#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */ + /* 0x2000 not currently used */ +#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ + /* 0x8000 not currently used */ /* Allowed return values from sqlite3WhereIsDistinct() */ @@ -13234,12 +16447,12 @@ struct SrcList { ** pEList corresponds to the result set of a SELECT and is NULL for ** other statements. ** -** NameContexts can be nested. When resolving names, the inner-most +** NameContexts can be nested. When resolving names, the inner-most ** context is searched first. If no match is found, the next outer ** context is checked. If there is still no match, the next context ** is checked. This process continues until either a match is found ** or all contexts are check. When a match is found, the nRef member of -** the context containing the match is incremented. +** the context containing the match is incremented. ** ** Each subquery gets a new NameContext. The pNext field points to the ** NameContext in the parent query. Thus the process of scanning the @@ -13260,16 +16473,18 @@ struct NameContext { /* ** Allowed values for the NameContext, ncFlags field. ** -** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and -** SQLITE_FUNC_MINMAX. -** +** Value constraints (all checked via assert()): +** NC_HasAgg == SF_HasAgg +** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ -#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */ +#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ -#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */ +#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ +#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ /* @@ -13295,13 +16510,13 @@ struct NameContext { struct Select { ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ - u16 selFlags; /* Various SF_* values */ + LogEst nSelectRow; /* Estimated number of result rows */ + u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ #if SELECTTRACE_ENABLED char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ #endif int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ - u64 nSelectRow; /* Estimated number of result rows */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ @@ -13317,23 +16532,30 @@ struct Select { /* ** Allowed values for Select.selFlags. The "SF" prefix stands for ** "Select Flag". +** +** Value constraints (all checked via assert()) +** SF_HasAgg == NC_HasAgg +** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX +** SF_FixedLimit == WHERE_USE_LIMIT */ -#define SF_Distinct 0x0001 /* Output should be DISTINCT */ -#define SF_All 0x0002 /* Includes the ALL keyword */ -#define SF_Resolved 0x0004 /* Identifiers have been resolved */ -#define SF_Aggregate 0x0008 /* Contains aggregate functions */ -#define SF_UsesEphemeral 0x0010 /* Uses the OpenEphemeral opcode */ -#define SF_Expanded 0x0020 /* sqlite3SelectExpand() called on this */ -#define SF_HasTypeInfo 0x0040 /* FROM subqueries have Table metadata */ -#define SF_Compound 0x0080 /* Part of a compound query */ -#define SF_Values 0x0100 /* Synthesized from VALUES clause */ -#define SF_MultiValue 0x0200 /* Single VALUES term with multiple rows */ -#define SF_NestedFrom 0x0400 /* Part of a parenthesized FROM clause */ -#define SF_MaybeConvert 0x0800 /* Need convertCompoundSelectToSubquery() */ -#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */ -#define SF_Recursive 0x2000 /* The recursive part of a recursive CTE */ -#define SF_Converted 0x4000 /* By convertCompoundSelectToSubquery() */ -#define SF_IncludeHidden 0x8000 /* Include hidden columns in output */ +#define SF_Distinct 0x00001 /* Output should be DISTINCT */ +#define SF_All 0x00002 /* Includes the ALL keyword */ +#define SF_Resolved 0x00004 /* Identifiers have been resolved */ +#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */ +#define SF_HasAgg 0x00010 /* Contains aggregate functions */ +#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */ +#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */ +#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */ +#define SF_Compound 0x00100 /* Part of a compound query */ +#define SF_Values 0x00200 /* Synthesized from VALUES clause */ +#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */ +#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ +#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ +#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ +#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ +#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ +#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ +#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ /* @@ -13341,7 +16563,7 @@ struct Select { ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** -** SRT_Union Store results as a key in a temporary index +** SRT_Union Store results as a key in a temporary index ** identified by pDest->iSDParm. ** ** SRT_Except Remove results from the temporary index pDest->iSDParm. @@ -13365,7 +16587,7 @@ struct Select { ** of the query. This destination implies "LIMIT 1". ** ** SRT_Set The result must be a single column. Store each -** row of result as the key in table pDest->iSDParm. +** row of result as the key in table pDest->iSDParm. ** Apply the affinity pDest->affSdst before storing ** results. Used to implement "IN (SELECT ...)". ** @@ -13425,19 +16647,19 @@ struct Select { */ struct SelectDest { u8 eDest; /* How to dispose of the results. On of SRT_* above. */ - char affSdst; /* Affinity used when eDest==SRT_Set */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ + char *zAffSdst; /* Affinity used when eDest==SRT_Set */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; /* -** During code generation of statements that do inserts into AUTOINCREMENT +** During code generation of statements that do inserts into AUTOINCREMENT ** tables, the following information is attached to the Table.u.autoInc.p ** pointer of each autoincrement table to record some side information that ** the code generator needs. We have to keep per-table autoincrement -** information in case inserts are down within triggers. Triggers do not +** information in case inserts are done within triggers. Triggers do not ** normally coordinate their activities, but we do need to coordinate the ** loading and saving of autoincrement information. */ @@ -13456,7 +16678,7 @@ struct AutoincInfo { #endif /* -** At least one instance of the following structure is created for each +** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE ** statement. All such objects are stored in the linked list headed at ** Parse.pTriggerPrg and deleted once statement compilation has been @@ -13469,7 +16691,7 @@ struct AutoincInfo { ** values for both pTrigger and orconf. ** ** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns -** accessed (or set to 0 for triggers fired as a result of INSERT +** accessed (or set to 0 for triggers fired as a result of INSERT ** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to ** a mask of new.* columns used by the program. */ @@ -13510,7 +16732,7 @@ struct TriggerPrg { ** is constant but the second part is reset at the beginning and end of ** each recursion. ** -** The nTableLock and aTableLock variables are only used if the shared-cache +** The nTableLock and aTableLock variables are only used if the shared-cache ** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are ** used to store the set of table-locks required by the statement being ** compiled. Function sqlite3TableLock() is used to add entries to the @@ -13529,36 +16751,25 @@ struct Parse { u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ - int aTempReg[8]; /* Holding area for temporary registers */ + u8 disableLookaside; /* Number of times lookaside has been disabled */ + u8 nColCache; /* Number of entries in aColCache[] */ 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 nSet; /* Number of sets used so far */ - int nOnce; /* Number of OP_Once instructions so far */ int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ - int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */ - int ckBase; /* Base register of data during check constraints */ - int iSelfTab; /* Table of an index whose exprs are being coded */ + int iSelfTab; /* Table for associated with an index on expr, or negative + ** of the base register during check-constraint eval */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ - struct yColCache { - int iTable; /* Table cursor number */ - i16 iColumn; /* Table column number */ - u8 tempReg; /* iReg is a temp register that needs to be freed */ - int iLevel; /* Nesting level */ - int iReg; /* Reg with value of this column. 0 means none. */ - int lru; /* Least recently used entry has the smallest value */ - } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ ExprList *pConstExpr;/* Constant expressions */ Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ - int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ @@ -13571,11 +16782,9 @@ struct Parse { TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ - - /* Information used while coding trigger programs. */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */ + 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 */ u32 newmask; /* Mask of new.* columns referenced */ @@ -13583,35 +16792,50 @@ struct Parse { u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ + /************************************************************************** + ** Fields above must be initialized to zero. The fields that follow, + ** down to the beginning of the recursive section, do not need to be + ** initialized as they will be set before being used. The boundary is + ** determined by offsetof(Parse,aColCache). + **************************************************************************/ + + struct yColCache { + int iTable; /* Table cursor number */ + i16 iColumn; /* Table column number */ + u8 tempReg; /* iReg is a temp register that needs to be freed */ + int iLevel; /* Nesting level */ + int iReg; /* Reg with value of this column. 0 means none. */ + int lru; /* Least recently used entry has the smallest value */ + } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ + int aTempReg[8]; /* Holding area for temporary registers */ + Token sNameToken; /* Token with unqualified schema object name */ + /************************************************************************ ** Above is constant between recursions. Below is reset before and after ** each recursion. The boundary between these two regions is determined - ** using offsetof(Parse,nVar) so the nVar field must be the first field - ** in the recursive region. + ** using offsetof(Parse,sLastToken) so the sLastToken field must be the + ** first field in the recursive region. ************************************************************************/ - int nVar; /* Number of '?' variables seen in the SQL so far */ - int nzVar; /* Number of available slots in azVar[] */ + Token sLastToken; /* The last token parsed */ + ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ #ifndef SQLITE_OMIT_VIRTUALTABLE u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ #endif - int nAlias; /* Number of aliased result set columns */ int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN int iSelectId; /* ID of current select for EXPLAIN output */ int iNextSelectId; /* Next available select ID for EXPLAIN output */ #endif - char **azVar; /* Pointers to names of parameters */ + VList *pVList; /* Mapping between variable names and numbers */ 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 */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ - Token sNameToken; /* Token with unqualified schema object name */ - Token sLastToken; /* The last token parsed */ #ifndef SQLITE_OMIT_VIRTUALTABLE Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ @@ -13622,6 +16846,14 @@ struct Parse { With *pWithToFree; /* Free this WITH object at the end of the parse */ }; +/* +** Sizes and pointers of various parts of the Parse object. +*/ +#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/ +#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ +#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ +#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ + /* ** Return true if currently inside an sqlite3_declare_vtab() call. */ @@ -13642,27 +16874,40 @@ struct AuthContext { /* ** Bitfield flags for P5 value in various opcodes. +** +** Value constraints (enforced via assert()): +** OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH +** OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF +** OPFLAG_BULKCSR == BTREE_BULKLOAD +** OPFLAG_SEEKEQ == BTREE_SEEK_EQ +** OPFLAG_FORDELETE == BTREE_FORDELETE +** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION +** OPFLAG_AUXDELETE == BTREE_AUXDELETE */ -#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ +#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ + /* Also used in P2 (not P5) of OP_Delete */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ -#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ +#define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ +#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ -#define OPFLAG_FORDELETE 0x08 /* OP_Open is opening for-delete csr */ +#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ #define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ +#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ +#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ /* * Each trigger present in the database schema is stored as an instance of - * struct Trigger. + * struct Trigger. * * Pointers to instances of struct Trigger are stored in two ways. - * 1. In the "trigHash" hash table (part of the sqlite3* that represents the + * 1. In the "trigHash" hash table (part of the sqlite3* that represents the * database). This allows Trigger structures to be retrieved by name. * 2. All triggers associated with a single table form a linked list, using the * pNext member of struct Trigger. A pointer to the first element of the @@ -13688,7 +16933,7 @@ struct Trigger { /* ** A trigger is either a BEFORE or an AFTER trigger. The following constants -** determine which. +** determine which. ** ** If there are multiple triggers, you might of some BEFORE and some AFTER. ** In that cases, the constants below can be ORed together. @@ -13698,15 +16943,15 @@ struct Trigger { /* * An instance of struct TriggerStep is used to store a single SQL statement - * that is a part of a trigger-program. + * that is a part of a trigger-program. * * Instances of struct TriggerStep are stored in a singly linked list (linked - * using the "pNext" member) referenced by the "step_list" member of the + * using the "pNext" member) referenced by the "step_list" member of the * associated struct Trigger instance. The first element of the linked list is * the first step of the trigger-program. - * + * * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or - * "SELECT" statement. The meanings of the other members is determined by the + * "SELECT" statement. The meanings of the other members is determined by the * value of "op" as follows: * * (op == TK_INSERT) @@ -13716,7 +16961,7 @@ struct Trigger { * zTarget -> Dequoted name of the table to insert into. * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then * this stores values to be inserted. Otherwise NULL. - * pIdList -> If this is an INSERT INTO ... () VALUES ... + * pIdList -> If this is an INSERT INTO ... () VALUES ... * statement, then this stores the column-names to be * inserted into. * @@ -13724,7 +16969,7 @@ struct Trigger { * zTarget -> Dequoted name of the table to delete from. * pWhere -> The WHERE clause of the DELETE statement if one is specified. * Otherwise NULL. - * + * * (op == TK_UPDATE) * zTarget -> Dequoted name of the table to update. * pWhere -> The WHERE clause of the UPDATE statement if one is specified. @@ -13732,7 +16977,7 @@ struct Trigger { * pExprList -> A list of the columns to update and the expressions to update * them to. See sqlite3Update() documentation of "pChanges" * argument. - * + * */ struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ @@ -13750,7 +16995,7 @@ struct TriggerStep { /* ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references -** explicit. +** explicit. */ typedef struct DbFixer DbFixer; struct DbFixer { @@ -13768,16 +17013,21 @@ struct DbFixer { */ struct StrAccum { sqlite3 *db; /* Optional database for lookaside. Can be NULL */ - char *zBase; /* A base allocation. Not from malloc. */ char *zText; /* The string collected so far */ - u32 nChar; /* Length of the string so far */ u32 nAlloc; /* Amount of space allocated in zText */ u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */ + u32 nChar; /* Length of the string so far */ u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */ - u8 bMalloced; /* zText points to allocated space */ + u8 printfFlags; /* SQLITE_PRINTF flags below */ }; #define STRACCUM_NOMEM 1 #define STRACCUM_TOOBIG 2 +#define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */ +#define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */ +#define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */ + +#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0) + /* ** A pointer to this structure is used to communicate information @@ -13801,10 +17051,12 @@ struct Sqlite3Config { int bFullMutex; /* True to enable full mutexing */ int bOpenUri; /* True to interpret filenames as URIs */ int bUseCis; /* Use covering indices for full-scans */ + int bSmallMalloc; /* Avoid large memory allocations if true */ int mxStrlen; /* Maximum string length */ int neverCorrupt; /* Database is always well-formed */ int szLookaside; /* Default lookaside buffer size */ int nLookaside; /* Default lookaside buffer count */ + int nStmtSpill; /* Stmt-journal spill-to-disk threshold */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */ @@ -13813,9 +17065,6 @@ struct Sqlite3Config { int mnReq, mxReq; /* Min and max heap requests sizes */ sqlite3_int64 szMmap; /* mmap() space per open file */ sqlite3_int64 mxMmap; /* Maximum value for szMmap */ - void *pScratch; /* Scratch memory */ - int szScratch; /* Size of each scratch buffer */ - int nScratch; /* Number of scratch buffers */ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ @@ -13844,10 +17093,11 @@ struct Sqlite3Config { void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ + int iOnceResetThreshold; /* When to reset OP_Once counters */ }; /* @@ -13872,19 +17122,24 @@ struct Sqlite3Config { ** Context pointer passed down through the tree-walk. */ struct Walker { + Parse *pParse; /* Parser context. */ int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ - Parse *pParse; /* Parser context. */ int walkerDepth; /* Number of subqueries */ u8 eCode; /* A small processing code */ union { /* Extra data for callback */ - NameContext *pNC; /* Naming context */ - int n; /* A counter */ - int iCur; /* A cursor number */ - SrcList *pSrcList; /* FROM clause */ - struct SrcCount *pSrcCount; /* Counting column references */ - struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ + NameContext *pNC; /* Naming context */ + int n; /* A counter */ + int iCur; /* A cursor number */ + SrcList *pSrcList; /* FROM clause */ + struct SrcCount *pSrcCount; /* Counting column references */ + struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ + int *aiCol; /* array of column indexes */ + struct IdxCover *pIdxCover; /* Check for index coverage */ + struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */ + ExprList *pGroupBy; /* GROUP BY clause */ + struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */ } u; }; @@ -13895,6 +17150,11 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*); SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*); +SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*); +SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*); +#endif /* ** Return code from the parse-tree walking primitives and their @@ -13953,7 +17213,26 @@ SQLITE_PRIVATE int sqlite3CantopenError(int); #define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NomemError(int); +SQLITE_PRIVATE int sqlite3IoerrnomemError(int); +SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); +# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__) +# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__) +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) +#else +# define SQLITE_NOMEM_BKPT SQLITE_NOMEM +# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) +#endif +/* +** FTS3 and FTS4 both require virtual table support +*/ +#if defined(SQLITE_OMIT_VIRTUALTABLE) +# undef SQLITE_ENABLE_FTS3 +# undef SQLITE_ENABLE_FTS4 +#endif /* ** FTS4 is really an extension for FTS3. It is enabled using the @@ -13986,6 +17265,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int); # define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04) # define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08) # define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)]) +# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80) #else # define sqlite3Toupper(x) toupper((unsigned char)(x)) # define sqlite3Isspace(x) isspace((unsigned char)(x)) @@ -13994,6 +17274,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int); # define sqlite3Isdigit(x) isdigit((unsigned char)(x)) # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) +# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') #endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_PRIVATE int sqlite3IsIdChar(u8); @@ -14002,8 +17283,9 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8); /* ** Internal function prototypes */ -#define sqlite3StrICmp sqlite3_stricmp +SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*); SQLITE_PRIVATE int sqlite3Strlen30(const char*); +SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*); #define sqlite3StrNICmp sqlite3_strnicmp SQLITE_PRIVATE int sqlite3MallocInit(void); @@ -14012,20 +17294,20 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64); SQLITE_PRIVATE void *sqlite3MallocZero(u64); SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64); SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64); +SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64); SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*); SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); +SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); SQLITE_PRIVATE int sqlite3MallocSize(void*); SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*); -SQLITE_PRIVATE void *sqlite3ScratchMalloc(int); -SQLITE_PRIVATE void sqlite3ScratchFree(void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void); -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); #endif SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); @@ -14041,18 +17323,22 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); #ifdef SQLITE_USE_ALLOCA # define sqlite3StackAllocRaw(D,N) alloca(N) # define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N) -# define sqlite3StackFree(D,P) +# define sqlite3StackFree(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) #endif -#ifdef SQLITE_ENABLE_MEMSYS3 -SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); -#endif +/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they +** are, disable MEMSYS3 +*/ #ifdef SQLITE_ENABLE_MEMSYS5 SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); +#undef SQLITE_ENABLE_MEMSYS3 +#endif +#ifdef SQLITE_ENABLE_MEMSYS3 +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); #endif @@ -14073,6 +17359,7 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int); SQLITE_PRIVATE void sqlite3StatusUp(int, int); SQLITE_PRIVATE void sqlite3StatusDown(int, int); SQLITE_PRIVATE void sqlite3StatusHighwater(int, int); +SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*); /* Access to mutexes used by sqlite3_status() */ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); @@ -14094,10 +17381,8 @@ struct PrintfArguments { sqlite3_value **apArg; /* The argument values */ }; -#define SQLITE_PRINTF_INTERNAL 0x01 -#define SQLITE_PRINTF_SQLFUNC 0x02 -SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, u32, const char*, va_list); -SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, u32, const char*, ...); +SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list); +SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...); SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) @@ -14109,6 +17394,7 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); #if defined(SQLITE_DEBUG) 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 sqlite3TreeViewSelect(TreeView*, const Select*, u8); SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); @@ -14117,7 +17403,8 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); -SQLITE_PRIVATE int sqlite3Dequote(char*); +SQLITE_PRIVATE void sqlite3Dequote(char*); +SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **); SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); @@ -14126,15 +17413,20 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int); SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int); SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int); SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int); +#endif SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); -SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*); +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 *sqlite3ExprFunction(Parse*,ExprList*, Token*); -SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); +SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int); SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); @@ -14143,13 +17435,16 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); +#ifndef SQLITE_OMIT_VIRTUALTABLE +SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); +#endif SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*); SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int); SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); -SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int); SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); +SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*); SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); @@ -14160,20 +17455,18 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*); #else # define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ #endif -SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*); +SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*); SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); -SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*); SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); 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 **); SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); -SQLITE_PRIVATE int sqlite3CodeOnce(Parse *); -#ifdef SQLITE_OMIT_BUILTIN_TEST +#ifdef SQLITE_UNTESTABLE # define sqlite3FaultSim(X) SQLITE_OK #else SQLITE_PRIVATE int sqlite3FaultSim(int); @@ -14186,7 +17479,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); #endif @@ -14233,12 +17526,12 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); -SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, - Expr*, int, int); +SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, + Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, - Expr*,ExprList*,u16,Expr*,Expr*); + Expr*,ExprList*,u32,Expr*,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int); @@ -14250,9 +17543,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); -SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*); +SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); @@ -14274,7 +17568,7 @@ SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); -SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8); +SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int); @@ -14282,26 +17576,31 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ +#define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); -SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); -SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); +#define LOCATE_VIEW 0x01 +#define LOCATE_NOERR 0x02 +SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); +SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); 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*); -SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*); +SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*); +SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int); SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); -SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); +SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3PrngSaveState(void); SQLITE_PRIVATE void sqlite3PrngRestoreState(void); #endif @@ -14309,14 +17608,14 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); -SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); -SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); +SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int); SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); +SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); @@ -14331,7 +17630,12 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int* SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, - u8,u8,int,int*); + u8,u8,int,int*,int*); +#ifdef SQLITE_ENABLE_NULL_TRIM +SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe*,Table*); +#else +# define sqlite3SetMakeRecordP5(A,B) +#endif SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int); @@ -14350,11 +17654,11 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*); #else # define sqlite3SelectSetName(A,B) #endif -SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); -SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8); -SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*); +SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); +SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); +SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); -SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void); +SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); @@ -14425,7 +17729,9 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3Atoi(const char*); +#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); +#endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); @@ -14433,7 +17739,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); #ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); #endif +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ + defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ + defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); +#endif +SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); +SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int); +SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int); /* ** Routines to read and write variable-length integers. These used to @@ -14463,11 +17776,13 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*); SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); +SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int); SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); SQLITE_PRIVATE void sqlite3Error(sqlite3*,int); +SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); @@ -14481,6 +17796,8 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); +SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); @@ -14500,12 +17817,14 @@ SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8); SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); -SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, +SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); +#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); +#endif SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION @@ -14515,7 +17834,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; SQLITE_PRIVATE const Token sqlite3IntTokens[]; SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; -SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions; +SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD SQLITE_PRIVATE int sqlite3PendingByte; #endif @@ -14527,7 +17846,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*); -SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int); +SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int); 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*); @@ -14550,7 +17869,6 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*); SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*); SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int); SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); -SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int); SQLITE_PRIVATE void sqlite3SchemaClear(void *); SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *); SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *); @@ -14561,11 +17879,13 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*); #endif -SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, +SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), FuncDestructor *pDestructor ); +SQLITE_PRIVATE void sqlite3OomFault(sqlite3*); +SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); @@ -14581,19 +17901,29 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *); SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); +#ifndef SQLITE_OMIT_SUBQUERY +SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*); +#else +# define sqlite3ExprCheckIN(x,y) SQLITE_OK +#endif + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void); -SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*); +SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( + Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*); SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord*); SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); +SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); #endif /* ** The interface to the LEMON-generated parser */ -SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64)); -SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); +#ifndef SQLITE_AMALGAMATION +SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64)); +SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); +#endif SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*); #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void*); @@ -14622,7 +17952,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*); # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 -# define sqlite3VtabLock(X) +# define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK @@ -14639,6 +17969,13 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*); +SQLITE_PRIVATE Module *sqlite3VtabCreateModule( + sqlite3*, + const char*, + const sqlite3_module*, + void*, + void(*)(void*) + ); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); @@ -14680,7 +18017,7 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8); ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign ** key functionality is available. If OMIT_TRIGGER is defined but ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In -** this case foreign keys are parsed, but no other functionality is +** this case foreign keys are parsed, but no other functionality is ** provided (enforcement of FK constraints requires the triggers sub-system). */ #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) @@ -14696,6 +18033,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *); #define sqlite3FkDropTable(a,b,c) #define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 + #define sqlite3FkReferences(a) 0 #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*); @@ -14714,10 +18052,10 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**); /* ** The interface to the code in fault.c used for identifying "benign" -** malloc failures. This is only present if SQLITE_OMIT_BUILTIN_TEST +** malloc failures. This is only present if SQLITE_UNTESTABLE ** is not defined. */ -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void); SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #else @@ -14739,21 +18077,17 @@ 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*); +SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*); -#ifdef SQLITE_ENABLE_ATOMIC_WRITE -SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); -SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); +SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); +SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); -SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p); -#else - #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile) - #define sqlite3JournalExists(p) 1 #endif +SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p); SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *); -SQLITE_PRIVATE int sqlite3MemJournalSize(void); -SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *); SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 @@ -14784,7 +18118,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *); /* ** If the SQLITE_ENABLE IOTRACE exists then the global variable ** sqlite3IoTrace is a pointer to a printf-like routine used to -** print I/O tracing messages. +** print I/O tracing messages. */ #ifdef SQLITE_ENABLE_IOTRACE # define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; } @@ -14818,7 +18152,7 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...); ** that allocations that might have been satisfied by lookaside are not ** passed back to non-lookaside free() routines. Asserts such as the ** example above are placed on the non-lookaside free() routines to verify -** this constraint. +** this constraint. ** ** All of this is no-op for a production build. It only comes into ** play when the SQLITE_MEMDEBUG compile-time option is used. @@ -14834,8 +18168,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ -#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ -#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ +#define MEMTYPE_PCACHE 0x04 /* Page cache allocations */ /* ** Threading interface @@ -14845,11 +18178,24 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); #endif +#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST) +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*); +#endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); #endif -#endif /* _SQLITEINT_H_ */ +SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr); +SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); +SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); +SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); + +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); +#endif + +#endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ /************** Begin file global.c ******************************************/ @@ -14925,6 +18271,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { ** isxdigit() 0x08 ** toupper() 0x20 ** SQLite identifier character 0x40 +** Quote character 0x80 ** ** Bit 0x20 is set if the mapped character requires translation to upper ** case. i.e. if the character is a lower-case ASCII character. @@ -14933,16 +18280,13 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { ** ** (x & ~(map[x]&0x20)) ** -** Standard function tolower() is implemented using the sqlite3UpperToLower[] +** The equivalent of tolower() is implemented using the sqlite3UpperToLower[] ** array. tolower() is used more often than toupper() by SQLite. ** -** Bit 0x40 is set if the character non-alphanumeric and can be used in an +** Bit 0x40 is set if the character is non-alphanumeric and can be used in an ** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any ** non-ASCII UTF character. Hence the test for whether or not a character is ** part of an identifier is 0x46. -** -** SQLite's versions are identical to the standard versions assuming a -** locale of "C". They are implemented as macros in sqliteInt.h. */ #ifdef SQLITE_ASCII SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { @@ -14950,7 +18294,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ - 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */ + 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */ 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */ @@ -14958,8 +18302,8 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */ - 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ - 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ + 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ + 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */ 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */ @@ -14994,9 +18338,16 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. +** +** URI filenames are enabled by default if SQLITE_HAS_CODEC is +** enabled. */ #ifndef SQLITE_USE_URI -# define SQLITE_USE_URI 0 +# ifdef SQLITE_HAS_CODEC +# define SQLITE_USE_URI 1 +# else +# define SQLITE_USE_URI 0 +# endif #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the @@ -15014,6 +18365,31 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { # define SQLITE_SORTER_PMASZ 250 #endif +/* Statement journals spill to disk when their size exceeds the following +** threshold (in bytes). 0 means that statement journals are created and +** written to disk immediately (the default behavior for SQLite versions +** before 3.12.0). -1 means always keep the entire statement journal in +** memory. (The statement journal is also always held entirely in memory +** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this +** setting.) +*/ +#ifndef SQLITE_STMTJRNL_SPILL +# define SQLITE_STMTJRNL_SPILL (64*1024) +#endif + +/* +** The default lookaside-configuration, the format "SZ,N". SZ is the +** number of bytes in each lookaside slot (should be a multiple of 8) +** and N is the number of slots. The lookaside-configuration can be +** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE) +** or at run-time for an individual database connection using +** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE); +*/ +#ifndef SQLITE_DEFAULT_LOOKASIDE +# define SQLITE_DEFAULT_LOOKASIDE 1200,100 +#endif + + /* ** The following singleton contains the global configuration for ** the SQLite library. @@ -15024,10 +18400,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_THREADSAFE==1, /* bFullMutex */ SQLITE_USE_URI, /* bOpenUri */ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ + 0, /* bSmallMalloc */ 0x7ffffffe, /* mxStrlen */ 0, /* neverCorrupt */ - 128, /* szLookaside */ - 500, /* nLookaside */ + SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ + SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ {0,0,0,0,0,0,0,0}, /* m */ {0,0,0,0,0,0,0,0,0}, /* mutex */ {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */ @@ -15036,9 +18413,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, 0, /* mnHeap, mxHeap */ SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */ SQLITE_MAX_MMAP_SIZE, /* mxMmap */ - (void*)0, /* pScratch */ - 0, /* szScratch */ - 0, /* nScratch */ (void*)0, /* pPage */ 0, /* szPage */ SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */ @@ -15063,10 +18437,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif - 0 /* bLocaltimeFault */ + 0, /* bLocaltimeFault */ + 0x7ffffffe /* iOnceResetThreshold */ }; /* @@ -15074,7 +18449,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { ** database connections. After initialization, this table is ** read-only. */ -SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions; +SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; /* ** Constant tokens for values 0 and 1. @@ -15089,7 +18464,7 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = { ** The value of the "pending" byte must be 0x40000000 (1 byte past the ** 1-gibabyte boundary) in a compatible database. SQLite never uses ** the database page that contains the pending byte. It never attempts -** to read or write that page. The pending byte page is set assign +** to read or write that page. The pending byte page is set aside ** for use by the VFS layers as space for managing file locks. ** ** During testing, it is often desirable to move the pending byte to @@ -15122,451 +18497,6 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; /************** End of global.c **********************************************/ -/************** Begin file ctime.c *******************************************/ -/* -** 2010 February 23 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file implements routines used to report what compile-time options -** SQLite was built with. -*/ - -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS - -/* #include "sqliteInt.h" */ - -/* -** An array of names of all compile-time options. This array should -** be sorted A-Z. -** -** This array looks large, but in a typical installation actually uses -** only a handful of compile-time options, so most times this array is usually -** rather short and uses little memory space. -*/ -static const char * const azCompileOpt[] = { - -/* These macros are provided to "stringify" the value of the define -** for those options in which the value is meaningful. */ -#define CTIMEOPT_VAL_(opt) #opt -#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) - -#if SQLITE_32BIT_ROWID - "32BIT_ROWID", -#endif -#if SQLITE_4_BYTE_ALIGNED_MALLOC - "4_BYTE_ALIGNED_MALLOC", -#endif -#if SQLITE_CASE_SENSITIVE_LIKE - "CASE_SENSITIVE_LIKE", -#endif -#if SQLITE_CHECK_PAGES - "CHECK_PAGES", -#endif -#if SQLITE_COVERAGE_TEST - "COVERAGE_TEST", -#endif -#if SQLITE_DEBUG - "DEBUG", -#endif -#if SQLITE_DEFAULT_LOCKING_MODE - "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), -#endif -#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) - "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), -#endif -#if SQLITE_DISABLE_DIRSYNC - "DISABLE_DIRSYNC", -#endif -#if SQLITE_DISABLE_LFS - "DISABLE_LFS", -#endif -#if SQLITE_ENABLE_8_3_NAMES - "ENABLE_8_3_NAMES", -#endif -#if SQLITE_ENABLE_API_ARMOR - "ENABLE_API_ARMOR", -#endif -#if SQLITE_ENABLE_ATOMIC_WRITE - "ENABLE_ATOMIC_WRITE", -#endif -#if SQLITE_ENABLE_CEROD - "ENABLE_CEROD", -#endif -#if SQLITE_ENABLE_COLUMN_METADATA - "ENABLE_COLUMN_METADATA", -#endif -#if SQLITE_ENABLE_DBSTAT_VTAB - "ENABLE_DBSTAT_VTAB", -#endif -#if SQLITE_ENABLE_EXPENSIVE_ASSERT - "ENABLE_EXPENSIVE_ASSERT", -#endif -#if SQLITE_ENABLE_FTS1 - "ENABLE_FTS1", -#endif -#if SQLITE_ENABLE_FTS2 - "ENABLE_FTS2", -#endif -#if SQLITE_ENABLE_FTS3 - "ENABLE_FTS3", -#endif -#if SQLITE_ENABLE_FTS3_PARENTHESIS - "ENABLE_FTS3_PARENTHESIS", -#endif -#if SQLITE_ENABLE_FTS4 - "ENABLE_FTS4", -#endif -#if SQLITE_ENABLE_FTS5 - "ENABLE_FTS5", -#endif -#if SQLITE_ENABLE_ICU - "ENABLE_ICU", -#endif -#if SQLITE_ENABLE_IOTRACE - "ENABLE_IOTRACE", -#endif -#if SQLITE_ENABLE_JSON1 - "ENABLE_JSON1", -#endif -#if SQLITE_ENABLE_LOAD_EXTENSION - "ENABLE_LOAD_EXTENSION", -#endif -#if SQLITE_ENABLE_LOCKING_STYLE - "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), -#endif -#if SQLITE_ENABLE_MEMORY_MANAGEMENT - "ENABLE_MEMORY_MANAGEMENT", -#endif -#if SQLITE_ENABLE_MEMSYS3 - "ENABLE_MEMSYS3", -#endif -#if SQLITE_ENABLE_MEMSYS5 - "ENABLE_MEMSYS5", -#endif -#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK - "ENABLE_OVERSIZE_CELL_CHECK", -#endif -#if SQLITE_ENABLE_RTREE - "ENABLE_RTREE", -#endif -#if defined(SQLITE_ENABLE_STAT4) - "ENABLE_STAT4", -#elif defined(SQLITE_ENABLE_STAT3) - "ENABLE_STAT3", -#endif -#if SQLITE_ENABLE_UNLOCK_NOTIFY - "ENABLE_UNLOCK_NOTIFY", -#endif -#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT - "ENABLE_UPDATE_DELETE_LIMIT", -#endif -#if SQLITE_HAS_CODEC - "HAS_CODEC", -#endif -#if HAVE_ISNAN || SQLITE_HAVE_ISNAN - "HAVE_ISNAN", -#endif -#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX - "HOMEGROWN_RECURSIVE_MUTEX", -#endif -#if SQLITE_IGNORE_AFP_LOCK_ERRORS - "IGNORE_AFP_LOCK_ERRORS", -#endif -#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS - "IGNORE_FLOCK_LOCK_ERRORS", -#endif -#ifdef SQLITE_INT64_TYPE - "INT64_TYPE", -#endif -#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS - "LIKE_DOESNT_MATCH_BLOBS", -#endif -#if SQLITE_LOCK_TRACE - "LOCK_TRACE", -#endif -#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc) - "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), -#endif -#ifdef SQLITE_MAX_SCHEMA_RETRY - "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), -#endif -#if SQLITE_MEMDEBUG - "MEMDEBUG", -#endif -#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT - "MIXED_ENDIAN_64BIT_FLOAT", -#endif -#if SQLITE_NO_SYNC - "NO_SYNC", -#endif -#if SQLITE_OMIT_ALTERTABLE - "OMIT_ALTERTABLE", -#endif -#if SQLITE_OMIT_ANALYZE - "OMIT_ANALYZE", -#endif -#if SQLITE_OMIT_ATTACH - "OMIT_ATTACH", -#endif -#if SQLITE_OMIT_AUTHORIZATION - "OMIT_AUTHORIZATION", -#endif -#if SQLITE_OMIT_AUTOINCREMENT - "OMIT_AUTOINCREMENT", -#endif -#if SQLITE_OMIT_AUTOINIT - "OMIT_AUTOINIT", -#endif -#if SQLITE_OMIT_AUTOMATIC_INDEX - "OMIT_AUTOMATIC_INDEX", -#endif -#if SQLITE_OMIT_AUTORESET - "OMIT_AUTORESET", -#endif -#if SQLITE_OMIT_AUTOVACUUM - "OMIT_AUTOVACUUM", -#endif -#if SQLITE_OMIT_BETWEEN_OPTIMIZATION - "OMIT_BETWEEN_OPTIMIZATION", -#endif -#if SQLITE_OMIT_BLOB_LITERAL - "OMIT_BLOB_LITERAL", -#endif -#if SQLITE_OMIT_BTREECOUNT - "OMIT_BTREECOUNT", -#endif -#if SQLITE_OMIT_BUILTIN_TEST - "OMIT_BUILTIN_TEST", -#endif -#if SQLITE_OMIT_CAST - "OMIT_CAST", -#endif -#if SQLITE_OMIT_CHECK - "OMIT_CHECK", -#endif -#if SQLITE_OMIT_COMPLETE - "OMIT_COMPLETE", -#endif -#if SQLITE_OMIT_COMPOUND_SELECT - "OMIT_COMPOUND_SELECT", -#endif -#if SQLITE_OMIT_CTE - "OMIT_CTE", -#endif -#if SQLITE_OMIT_DATETIME_FUNCS - "OMIT_DATETIME_FUNCS", -#endif -#if SQLITE_OMIT_DECLTYPE - "OMIT_DECLTYPE", -#endif -#if SQLITE_OMIT_DEPRECATED - "OMIT_DEPRECATED", -#endif -#if SQLITE_OMIT_DISKIO - "OMIT_DISKIO", -#endif -#if SQLITE_OMIT_EXPLAIN - "OMIT_EXPLAIN", -#endif -#if SQLITE_OMIT_FLAG_PRAGMAS - "OMIT_FLAG_PRAGMAS", -#endif -#if SQLITE_OMIT_FLOATING_POINT - "OMIT_FLOATING_POINT", -#endif -#if SQLITE_OMIT_FOREIGN_KEY - "OMIT_FOREIGN_KEY", -#endif -#if SQLITE_OMIT_GET_TABLE - "OMIT_GET_TABLE", -#endif -#if SQLITE_OMIT_INCRBLOB - "OMIT_INCRBLOB", -#endif -#if SQLITE_OMIT_INTEGRITY_CHECK - "OMIT_INTEGRITY_CHECK", -#endif -#if SQLITE_OMIT_LIKE_OPTIMIZATION - "OMIT_LIKE_OPTIMIZATION", -#endif -#if SQLITE_OMIT_LOAD_EXTENSION - "OMIT_LOAD_EXTENSION", -#endif -#if SQLITE_OMIT_LOCALTIME - "OMIT_LOCALTIME", -#endif -#if SQLITE_OMIT_LOOKASIDE - "OMIT_LOOKASIDE", -#endif -#if SQLITE_OMIT_MEMORYDB - "OMIT_MEMORYDB", -#endif -#if SQLITE_OMIT_OR_OPTIMIZATION - "OMIT_OR_OPTIMIZATION", -#endif -#if SQLITE_OMIT_PAGER_PRAGMAS - "OMIT_PAGER_PRAGMAS", -#endif -#if SQLITE_OMIT_PRAGMA - "OMIT_PRAGMA", -#endif -#if SQLITE_OMIT_PROGRESS_CALLBACK - "OMIT_PROGRESS_CALLBACK", -#endif -#if SQLITE_OMIT_QUICKBALANCE - "OMIT_QUICKBALANCE", -#endif -#if SQLITE_OMIT_REINDEX - "OMIT_REINDEX", -#endif -#if SQLITE_OMIT_SCHEMA_PRAGMAS - "OMIT_SCHEMA_PRAGMAS", -#endif -#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS - "OMIT_SCHEMA_VERSION_PRAGMAS", -#endif -#if SQLITE_OMIT_SHARED_CACHE - "OMIT_SHARED_CACHE", -#endif -#if SQLITE_OMIT_SUBQUERY - "OMIT_SUBQUERY", -#endif -#if SQLITE_OMIT_TCL_VARIABLE - "OMIT_TCL_VARIABLE", -#endif -#if SQLITE_OMIT_TEMPDB - "OMIT_TEMPDB", -#endif -#if SQLITE_OMIT_TRACE - "OMIT_TRACE", -#endif -#if SQLITE_OMIT_TRIGGER - "OMIT_TRIGGER", -#endif -#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION - "OMIT_TRUNCATE_OPTIMIZATION", -#endif -#if SQLITE_OMIT_UTF16 - "OMIT_UTF16", -#endif -#if SQLITE_OMIT_VACUUM - "OMIT_VACUUM", -#endif -#if SQLITE_OMIT_VIEW - "OMIT_VIEW", -#endif -#if SQLITE_OMIT_VIRTUALTABLE - "OMIT_VIRTUALTABLE", -#endif -#if SQLITE_OMIT_WAL - "OMIT_WAL", -#endif -#if SQLITE_OMIT_WSD - "OMIT_WSD", -#endif -#if SQLITE_OMIT_XFER_OPT - "OMIT_XFER_OPT", -#endif -#if SQLITE_PERFORMANCE_TRACE - "PERFORMANCE_TRACE", -#endif -#if SQLITE_PROXY_DEBUG - "PROXY_DEBUG", -#endif -#if SQLITE_RTREE_INT_ONLY - "RTREE_INT_ONLY", -#endif -#if SQLITE_SECURE_DELETE - "SECURE_DELETE", -#endif -#if SQLITE_SMALL_STACK - "SMALL_STACK", -#endif -#if SQLITE_SOUNDEX - "SOUNDEX", -#endif -#if SQLITE_SYSTEM_MALLOC - "SYSTEM_MALLOC", -#endif -#if SQLITE_TCL - "TCL", -#endif -#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc) - "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), -#endif -#if SQLITE_TEST - "TEST", -#endif -#if defined(SQLITE_THREADSAFE) - "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), -#endif -#if SQLITE_USE_ALLOCA - "USE_ALLOCA", -#endif -#if SQLITE_USER_AUTHENTICATION - "USER_AUTHENTICATION", -#endif -#if SQLITE_WIN32_MALLOC - "WIN32_MALLOC", -#endif -#if SQLITE_ZERO_MALLOC - "ZERO_MALLOC" -#endif -}; - -/* -** Given the name of a compile-time option, return true if that option -** was used and false if not. -** -** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix -** is not required for a match. -*/ -SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){ - int i, n; - -#if SQLITE_ENABLE_API_ARMOR - if( zOptName==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; - n = sqlite3Strlen30(zOptName); - - /* Since ArraySize(azCompileOpt) is normally in single digits, a - ** linear search is adequate. No need for a binary search. */ - for(i=0; i=0 && NaDb[] (or -1) */ - u8 nullRow; /* True if pointing to a row with no data */ - u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ - u8 isTable; /* True for rowid tables. False for indexes */ + u8 eCurType; /* One of the CURTYPE_* values above */ + i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ + u8 nullRow; /* True if pointing to a row with no data */ + u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ + u8 isTable; /* True for rowid tables. False for indexes */ #ifdef SQLITE_DEBUG - u8 seekOp; /* Most recent seek operation on this cursor */ + u8 seekOp; /* Most recent seek operation on this cursor */ + u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */ #endif - Bool isEphemeral:1; /* True for an ephemeral table */ - Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */ - Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ - Pgno pgnoRoot; /* Root page of the open btree cursor */ - i16 nField; /* Number of fields in the header */ - u16 nHdrParsed; /* Number of header fields parsed so far */ + Bool isEphemeral:1; /* True for an ephemeral table */ + Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ + Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ + Btree *pBtx; /* Separate file holding temporary table */ + i64 seqCount; /* Sequence counter */ + int *aAltMap; /* Mapping from table to index column numbers */ + + /* Cached OP_Column parse information is only valid if cacheStatus matches + ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of + ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that + ** the cache is out of date. */ + u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ + int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0 + ** if there have been no prior seeks on the cursor. */ + /* seekResult does not distinguish between "no seeks have ever occurred + ** on this cursor" and "the most recent seek was an exact match". + ** For CURTYPE_PSEUDO, seekResult is the register holding the record */ + + /* When a new VdbeCursor is allocated, only the fields above are zeroed. + ** The fields that follow are uninitialized, and must be individually + ** initialized prior to first use. */ + VdbeCursor *pAltCursor; /* Associated index cursor from which to read */ union { - BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */ - sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ - int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */ - VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ + BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */ + sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ + VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ } uc; - Btree *pBt; /* Separate file holding temporary table */ - KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ - int seekResult; /* Result of previous sqlite3BtreeMoveto() */ - i64 seqCount; /* Sequence counter */ - i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ + KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ + u32 iHdrOffset; /* Offset to next unparsed byte of the header */ + Pgno pgnoRoot; /* Root page of the open btree cursor */ + i16 nField; /* Number of fields in the header */ + u16 nHdrParsed; /* Number of header fields parsed so far */ + i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ + u32 *aOffset; /* Pointer to aType[nField] */ + const u8 *aRow; /* Data for the current row, if all on one page */ + u32 payloadSize; /* Total number of bytes in the record */ + u32 szRow; /* Byte available in aRow */ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK - u64 maskUsed; /* Mask of columns used by this cursor */ + u64 maskUsed; /* Mask of columns used by this cursor */ #endif - /* Cached information about the header for the data record that the - ** cursor is currently pointing to. Only valid if cacheStatus matches - ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of - ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that - ** the cache is out of date. - ** - ** aRow might point to (ephemeral) data for the current row, or it might - ** be NULL. - */ - u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ - u32 payloadSize; /* Total number of bytes in the record */ - u32 szRow; /* Byte available in aRow */ - u32 iHdrOffset; /* Offset to next unparsed byte of the header */ - const u8 *aRow; /* Data for the current row, if all on one page */ - u32 *aOffset; /* Pointer to aType[nField] */ - u32 aType[1]; /* Type values for all entries in the record */ /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for ** aType[] and nField+1 array slots for aOffset[] */ + u32 aType[1]; /* Type values record decode. MUST BE LAST */ }; -typedef struct VdbeCursor VdbeCursor; + + +/* +** A value for VdbeCursor.cacheStatus that means the cache is always invalid. +*/ +#define CACHE_STALE 0 /* ** When a sub-program is executed (OP_Program), a structure of this type @@ -15742,15 +18681,15 @@ struct VdbeFrame { Op *aOp; /* Program instructions for parent frame */ i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ - u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ + u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ + AuxData *pAuxData; /* Linked list of auxdata allocations */ int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ - int nOnceFlag; /* Number of entries in aOnceFlag */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ int nChange; /* Statement changes (Vdbe.nChange) */ @@ -15759,21 +18698,17 @@ struct VdbeFrame { #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) -/* -** A value for VdbeCursor.cacheValid that means the cache is always invalid. -*/ -#define CACHE_STALE 0 - /* ** Internally, the vdbe manipulates nearly all SQL values as Mem ** structures. Each Mem struct may cache multiple representations (string, ** integer etc.) of the same value. */ -struct Mem { +struct sqlite3_value { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ - int nZero; /* Used when bit MEM_Zero is set in flags */ + int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ + const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ @@ -15805,7 +18740,8 @@ struct Mem { ** representations of the value stored in the Mem struct. ** ** If the MEM_Null flag is set, then the value is an SQL NULL value. -** No other flags may be set in this case. +** For a pointer type created using sqlite3_bind_pointer() or +** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set. ** ** If the MEM_Str flag is set then Mem.z points at a string representation. ** Usually this is encoded in the same unicode encoding as the main @@ -15813,7 +18749,7 @@ struct Mem { ** set, then the string is nul terminated. The MEM_Int and MEM_Real ** flags may coexist with the MEM_Str flag. */ -#define MEM_Null 0x0001 /* Value is NULL */ +#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ @@ -15823,7 +18759,7 @@ struct Mem { #define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ -#define MEM_TypeMask 0x01ff /* Mask of type bits */ +#define MEM_TypeMask 0xc1ff /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of @@ -15831,17 +18767,24 @@ struct Mem { ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ -#define MEM_Term 0x0200 /* String rep is nul terminated */ +#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ #define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ #define MEM_Static 0x0800 /* Mem.z points to a static string */ #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ #define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ #define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ +#define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */ #ifdef SQLITE_OMIT_INCRBLOB #undef MEM_Zero #define MEM_Zero 0x0000 #endif +/* Return TRUE if Mem X contains dynamically allocated content - anything +** that needs to be deallocated to avoid a leak. +*/ +#define VdbeMemDynamic(X) \ + (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) + /* ** Clear any existing type flags from a Mem and replace them with f */ @@ -15864,11 +18807,11 @@ struct Mem { ** when the VM is halted (if not before). */ struct AuxData { - int iOp; /* Instruction number of OP_Function opcode */ - int iArg; /* Index of function argument. */ + int iAuxOp; /* Instruction number of OP_Function opcode */ + int iAuxArg; /* Index of function argument. */ void *pAux; /* Aux data pointer */ - void (*xDelete)(void *); /* Destructor for the aux data */ - AuxData *pNext; /* Next element in list */ + void (*xDeleteAux)(void*); /* Destructor for the aux data */ + AuxData *pNextAux; /* Next element in list */ }; /* @@ -15897,18 +18840,6 @@ struct sqlite3_context { sqlite3_value *argv[1]; /* Argument set */ }; -/* -** An Explain object accumulates indented output which is helpful -** in describing recursive data structures. -*/ -struct Explain { - Vdbe *pVdbe; /* Attach the explanation to this Vdbe */ - StrAccum str; /* The string being accumulated */ - int nIndent; /* Number of elements in aIndent */ - u16 aIndent[100]; /* Levels of indentation */ - char zBase[100]; /* Initial space */ -}; - /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ @@ -15933,53 +18864,56 @@ struct ScanStatus { */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ + Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ + Parse *pParse; /* Parsing context used to create this Vdbe */ + ynVar nVar; /* Number of entries in aVar[] */ + u32 magic; /* Magic number for sanity checking */ + int nMem; /* Number of memory locations currently allocated */ + int nCursor; /* Number of slots in apCsr[] */ + u32 cacheCtr; /* VdbeCursor row cache generation counter */ + 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) */ + 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 */ + + /* 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 */ Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ - Parse *pParse; /* Parsing context used to create this Vdbe */ - int nMem; /* Number of memory locations currently allocated */ - int nOp; /* Number of instructions in the program */ - int nCursor; /* Number of slots in apCsr[] */ - u32 magic; /* Magic number for sanity checking */ char *zErrMsg; /* Error message written here */ - Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ - char **azVar; /* Name of variables */ - ynVar nVar; /* Number of entries in aVar[] */ - ynVar nzVar; /* Number of entries in azVar[] */ - u32 cacheCtr; /* VdbeCursor row cache generation counter */ - int pc; /* The program counter */ - int rc; /* Value to return */ + 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() */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ + u8 prepFlags; /* SQLITE_PREPARE_* flags */ + bft expired:1; /* True if the VM needs to be recompiled */ + bft doingRerun:1; /* True if rerunning after an auto-reprepare */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft changeCntOn:1; /* True to update the change-counter */ - bft expired:1; /* True if the VM needs to be recompiled */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ - bft isPrepareV2:1; /* True if prepared with prepare_v2() */ - bft doingRerun:1; /* True if rerunning after an auto-reprepare */ - int nChange; /* Number of db changes made since last reset */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ - int iStatement; /* Statement number (or 0 if has not opened stmt) */ - u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */ -#ifndef SQLITE_OMIT_TRACE - i64 startTime; /* Time when query started - used for profiling */ -#endif - 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 */ + u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ @@ -15987,8 +18921,6 @@ struct Vdbe { int nFrame; /* Number of frames in pFrame list */ u32 expmask; /* Binding to these vars invalidates VM */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ - int nOnceFlag; /* Size of array aOnceFlag[] */ - u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS i64 *anExec; /* Number of times each op has been executed */ @@ -16000,10 +18932,31 @@ struct Vdbe { /* ** The following are allowed values for Vdbe.magic */ -#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ -#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ -#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */ -#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ +#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */ +#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */ +#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */ +#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */ +#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */ + +/* +** Structure used to store the context required by the +** sqlite3_preupdate_*() API functions. +*/ +struct PreUpdate { + Vdbe *v; + VdbeCursor *pCsr; /* Cursor to read old values from */ + int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ + u8 *aRecord; /* old.* database record */ + KeyInfo keyinfo; + UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ + UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ + int iNewReg; /* Register for new.* values */ + i64 iKey1; /* First key value passed to hook */ + i64 iKey2; /* Second key value passed to hook */ + Mem *aNew; /* Array of new.* values */ + Table *pTab; /* Schema object being upated */ + Index *pPk; /* PK index if pTab is WITHOUT ROWID */ +}; /* ** Function prototypes @@ -16011,7 +18964,7 @@ struct Vdbe { SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...); SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); -SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*); +SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*); SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); @@ -16021,7 +18974,7 @@ SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8); SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*); SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); -SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); +SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); @@ -16042,6 +18995,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #else SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); #endif +SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); @@ -16055,10 +19009,8 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8); -SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); -#define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); SQLITE_PRIVATE const char *sqlite3OpcodeName(int); SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); @@ -16066,22 +19018,29 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); +#endif SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); -SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +#if !defined(SQLITE_OMIT_SHARED_CACHE) SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); +#else # define sqlite3VdbeLeave(X) #endif @@ -16096,12 +19055,14 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); # define sqlite3VdbeCheckFk(p,i) 0 #endif -SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); #endif -SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); +#ifndef SQLITE_OMIT_UTF16 +SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); +SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); +#endif #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); @@ -16111,7 +19072,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); #define ExpandBlob(P) SQLITE_OK #endif -#endif /* !defined(_VDBEINT_H_) */ +#endif /* !defined(SQLITE_VDBEINT_H) */ /************** End of vdbeInt.h *********************************************/ /************** Continuing where we left off in status.c *********************/ @@ -16222,7 +19183,6 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){ : sqlite3MallocMutex()) ); assert( op==SQLITE_STATUS_MALLOC_SIZE || op==SQLITE_STATUS_PAGECACHE_SIZE - || op==SQLITE_STATUS_SCRATCH_SIZE || op==SQLITE_STATUS_PARSER_STACK ); if( newValue>wsdStat.mxValue[op] ){ wsdStat.mxValue[op] = newValue; @@ -16232,7 +19192,7 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){ /* ** Query status information. */ -SQLITE_API int SQLITE_STDCALL sqlite3_status64( +SQLITE_API int sqlite3_status64( int op, sqlite3_int64 *pCurrent, sqlite3_int64 *pHighwater, @@ -16257,8 +19217,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ return SQLITE_OK; } -SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ - sqlite3_int64 iCur, iHwtr; +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ + sqlite3_int64 iCur = 0, iHwtr = 0; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; @@ -16271,10 +19231,32 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwa return rc; } +/* +** Return the number of LookasideSlot elements on the linked list +*/ +static u32 countLookasideSlots(LookasideSlot *p){ + u32 cnt = 0; + while( p ){ + p = p->pNext; + cnt++; + } + return cnt; +} + +/* +** Count the number of slots of lookaside memory that are outstanding +*/ +SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ + u32 nInit = countLookasideSlots(db->lookaside.pInit); + u32 nFree = countLookasideSlots(db->lookaside.pFree); + if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; + return db->lookaside.nSlot - (nInit+nFree); +} + /* ** Query status information for a single database connection */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_status( +SQLITE_API int sqlite3_db_status( sqlite3 *db, /* The database connection whose status is desired */ int op, /* Status verb */ int *pCurrent, /* Write current value here */ @@ -16290,10 +19272,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status( sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { - *pCurrent = db->lookaside.nOut; - *pHighwater = db->lookaside.mxOut; + *pCurrent = sqlite3LookasideUsed(db, pHighwater); if( resetFlag ){ - db->lookaside.mxOut = db->lookaside.nOut; + LookasideSlot *p = db->lookaside.pFree; + if( p ){ + while( p->pNext ) p = p->pNext; + p->pNext = db->lookaside.pInit; + db->lookaside.pInit = db->lookaside.pFree; + db->lookaside.pFree = 0; + } } break; } @@ -16319,6 +19306,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status( ** by all pagers associated with the given database connection. The ** highwater mark is meaningless and is returned as zero. */ + case SQLITE_DBSTATUS_CACHE_USED_SHARED: case SQLITE_DBSTATUS_CACHE_USED: { int totalUsed = 0; int i; @@ -16327,7 +19315,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status( Btree *pBt = db->aDb[i].pBt; if( pBt ){ Pager *pPager = sqlite3BtreePager(pBt); - totalUsed += sqlite3PagerMemUsed(pPager); + int nByte = sqlite3PagerMemUsed(pPager); + if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ + nByte = nByte / sqlite3BtreeConnectionCount(pBt); + } + totalUsed += nByte; } } sqlite3BtreeLeaveAll(db); @@ -16499,54 +19491,80 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status( #ifndef SQLITE_OMIT_DATETIME_FUNCS +/* +** The MSVC CRT on Windows CE may not have a localtime() function. +** So declare a substitute. The substitute function itself is +** defined in "os_win.c". +*/ +#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ + (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) +struct tm *__cdecl localtime(const time_t *); +#endif /* ** A structure for holding a single date and time. */ typedef struct DateTime DateTime; struct DateTime { - sqlite3_int64 iJD; /* The julian day number times 86400000 */ - int Y, M, D; /* Year, month, and day */ - int h, m; /* Hour and minutes */ - int tz; /* Timezone offset in minutes */ - double s; /* Seconds */ - char validYMD; /* True (1) if Y,M,D are valid */ - char validHMS; /* True (1) if h,m,s are valid */ - char validJD; /* True (1) if iJD is valid */ - char validTZ; /* True (1) if tz is valid */ - char tzSet; /* Timezone was set explicitly */ + sqlite3_int64 iJD; /* The julian day number times 86400000 */ + int Y, M, D; /* Year, month, and day */ + int h, m; /* Hour and minutes */ + int tz; /* Timezone offset in minutes */ + double s; /* Seconds */ + char validJD; /* True (1) if iJD is valid */ + char rawS; /* Raw numeric value stored in s */ + char validYMD; /* True (1) if Y,M,D are valid */ + char validHMS; /* True (1) if h,m,s are valid */ + char validTZ; /* True (1) if tz is valid */ + char tzSet; /* Timezone was set explicitly */ + char isError; /* An overflow has occurred */ }; /* -** Convert zDate into one or more integers. Additional arguments -** come in groups of 5 as follows: +** Convert zDate into one or more integers according to the conversion +** specifier zFormat. ** -** N number of digits in the integer -** min minimum allowed value of the integer -** max maximum allowed value of the integer -** nextC first character after the integer -** pVal where to write the integers value. +** zFormat[] contains 4 characters for each integer converted, except for +** the last integer which is specified by three characters. The meaning +** of a four-character format specifiers ABCD is: +** +** A: number of digits to convert. Always "2" or "4". +** B: minimum value. Always "0" or "1". +** C: maximum value, decoded as: +** a: 12 +** b: 14 +** c: 24 +** d: 31 +** e: 59 +** f: 9999 +** D: the separator character, or \000 to indicate this is the +** last number to convert. +** +** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would +** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-". +** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates +** the 2-digit day which is the last integer in the set. ** -** Conversions continue until one with nextC==0 is encountered. ** The function returns the number of successful conversions. */ -static int getDigits(const char *zDate, ...){ +static int getDigits(const char *zDate, const char *zFormat, ...){ + /* The aMx[] array translates the 3rd character of each format + ** spec into a max size: a b c d e f */ + static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 }; va_list ap; - int val; - int N; - int min; - int max; - int nextC; - int *pVal; int cnt = 0; - va_start(ap, zDate); + char nextC; + va_start(ap, zFormat); do{ - N = va_arg(ap, int); - min = va_arg(ap, int); - max = va_arg(ap, int); - nextC = va_arg(ap, int); - pVal = va_arg(ap, int*); + char N = zFormat[0] - '0'; + char min = zFormat[1] - '0'; + int val = 0; + u16 max; + + assert( zFormat[2]>='a' && zFormat[2]<='f' ); + max = aMx[zFormat[2] - 'a']; + nextC = zFormat[3]; val = 0; while( N-- ){ if( !sqlite3Isdigit(*zDate) ){ @@ -16555,12 +19573,13 @@ static int getDigits(const char *zDate, ...){ val = val*10 + *zDate - '0'; zDate++; } - if( valmax || (nextC!=0 && nextC!=*zDate) ){ + if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){ goto end_getDigits; } - *pVal = val; + *va_arg(ap,int*) = val; zDate++; cnt++; + zFormat += 4; }while( nextC ); end_getDigits: va_end(ap); @@ -16601,7 +19620,7 @@ static int parseTimezone(const char *zDate, DateTime *p){ return c!=0; } zDate++; - if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){ + if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){ return 1; } zDate += 5; @@ -16622,13 +19641,13 @@ zulu_time: static int parseHhMmSs(const char *zDate, DateTime *p){ int h, m, s; double ms = 0.0; - if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){ + if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){ return 1; } zDate += 5; if( *zDate==':' ){ zDate++; - if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){ + if( getDigits(zDate, "20e", &s)!=1 ){ return 1; } zDate += 2; @@ -16646,6 +19665,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){ s = 0; } p->validJD = 0; + p->rawS = 0; p->validHMS = 1; p->h = h; p->m = m; @@ -16655,6 +19675,14 @@ static int parseHhMmSs(const char *zDate, DateTime *p){ return 0; } +/* +** Put the DateTime object into its error state. +*/ +static void datetimeError(DateTime *p){ + memset(p, 0, sizeof(*p)); + p->isError = 1; +} + /* ** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume ** that the YYYY-MM-DD is according to the Gregorian calendar. @@ -16674,6 +19702,10 @@ static void computeJD(DateTime *p){ M = 1; D = 1; } + if( Y<-4713 || Y>9999 || p->rawS ){ + datetimeError(p); + return; + } if( M<=2 ){ Y--; M += 12; @@ -16716,7 +19748,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ }else{ neg = 0; } - if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){ + if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){ return 1; } zDate += 10; @@ -16754,6 +19786,21 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ } } +/* +** Input "r" is a numeric quantity which might be a julian day number, +** or the number of seconds since 1970. If the value if r is within +** range of a julian day number, install it as such and set validJD. +** If the value is a valid unix timestamp, put it in p->s and set p->rawS. +*/ +static void setRawDateNumber(DateTime *p, double r){ + p->s = r; + p->rawS = 1; + if( r>=0.0 && r<5373484.5 ){ + p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); + p->validJD = 1; + } +} + /* ** Attempt to parse the given string into a julian day number. Return ** the number of errors. @@ -16780,16 +19827,33 @@ static int parseDateOrTime( return 0; }else if( parseHhMmSs(zDate, p)==0 ){ return 0; - }else if( sqlite3StrICmp(zDate,"now")==0){ + }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ - p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); - p->validJD = 1; + setRawDateNumber(p, r); return 0; } return 1; } +/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999. +** Multiplying this by 86400000 gives 464269060799999 as the maximum value +** for DateTime.iJD. +** +** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with +** such a large integer literal, so we have to encode it. +*/ +#define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff) + +/* +** Return TRUE if the given julian day number is within range. +** +** The input is the JulianDay times 86400000. +*/ +static int validJulianDay(sqlite3_int64 iJD){ + return iJD>=0 && iJD<=INT_464269060799999; +} + /* ** Compute the Year, Month, and Day from the julian day number. */ @@ -16800,6 +19864,9 @@ static void computeYMD(DateTime *p){ p->Y = 2000; p->M = 1; p->D = 1; + }else if( !validJulianDay(p->iJD) ){ + datetimeError(p); + return; }else{ Z = (int)((p->iJD + 43200000)/86400000); A = (int)((Z - 1867216.25)/36524.25); @@ -16831,6 +19898,7 @@ static void computeHMS(DateTime *p){ s -= p->h*3600; p->m = s/60; p->s += s - p->m*60; + p->rawS = 0; p->validHMS = 1; } @@ -16851,6 +19919,7 @@ static void clearYMD_HMS_TZ(DateTime *p){ p->validTZ = 0; } +#ifndef SQLITE_OMIT_LOCALTIME /* ** On recent Windows platforms, the localtime_s() function is available ** as part of the "Secure CRT". It is essentially equivalent to @@ -16869,7 +19938,6 @@ static void clearYMD_HMS_TZ(DateTime *p){ #define HAVE_LOCALTIME_S 1 #endif -#ifndef SQLITE_OMIT_LOCALTIME /* ** The following routine implements the rough equivalent of localtime_r() ** using whatever operating-system specific localtime facility that @@ -16892,14 +19960,14 @@ static int osLocaltime(time_t *t, struct tm *pTm){ #endif sqlite3_mutex_enter(mutex); pX = localtime(t); -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; #endif if( pX ) *pTm = *pX; sqlite3_mutex_leave(mutex); rc = pX==0; #else -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; #endif #if HAVE_LOCALTIME_R @@ -16970,13 +20038,38 @@ static sqlite3_int64 localtimeOffset( y.validYMD = 1; y.validHMS = 1; y.validJD = 0; + y.rawS = 0; y.validTZ = 0; + y.isError = 0; computeJD(&y); *pRc = SQLITE_OK; return y.iJD - x.iJD; } #endif /* SQLITE_OMIT_LOCALTIME */ +/* +** The following table defines various date transformations of the form +** +** 'NNN days' +** +** Where NNN is an arbitrary floating-point number and "days" can be one +** of several units of time. +*/ +static const struct { + u8 eType; /* Transformation type code */ + u8 nName; /* Length of th name */ + char *zName; /* Name of the transformation */ + double rLimit; /* Maximum NNN value for this transform */ + double rXform; /* Constant used for this transform */ +} aXformType[] = { + { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) }, + { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) }, + { 0, 4, "hour", 128963628.0, 86400000.0/24.0 }, + { 0, 3, "day", 5373485.0, 86400000.0 }, + { 1, 5, "month", 176546.0, 30.0*86400000.0 }, + { 2, 4, "year", 14713.0, 365.0*86400000.0 }, +}; + /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: @@ -17001,17 +20094,15 @@ static sqlite3_int64 localtimeOffset( ** to context pCtx. If the error is an unrecognized modifier, no error is ** written to pCtx. */ -static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ +static int parseModifier( + sqlite3_context *pCtx, /* Function context */ + const char *z, /* The text of the modifier */ + int n, /* Length of zMod in bytes */ + DateTime *p /* The date/time value to be modified */ +){ int rc = 1; - int n; double r; - char *z, zBuf[30]; - z = zBuf; - for(n=0; niJD += localtimeOffset(p, pCtx, &rc); clearYMD_HMS_TZ(p); @@ -17031,16 +20122,21 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ /* ** unixepoch ** - ** Treat the current value of p->iJD as the number of + ** Treat the current value of p->s as the number of ** seconds since 1970. Convert to a real julian day number. */ - if( strcmp(z, "unixepoch")==0 && p->validJD ){ - p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000; - clearYMD_HMS_TZ(p); - rc = 0; + if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ + r = p->s*1000.0 + 210866760000000.0; + if( r>=0.0 && r<464269060800000.0 ){ + clearYMD_HMS_TZ(p); + p->iJD = (sqlite3_int64)r; + p->validJD = 1; + p->rawS = 0; + rc = 0; + } } #ifndef SQLITE_OMIT_LOCALTIME - else if( strcmp(z, "utc")==0 ){ + else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ if( p->tzSet==0 ){ sqlite3_int64 c1; computeJD(p); @@ -17066,7 +20162,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ ** weekday N where 0==Sunday, 1==Monday, and so forth. If the ** date is already on the appropriate weekday, this is a no-op. */ - if( strncmp(z, "weekday ", 8)==0 + if( sqlite3_strnicmp(z, "weekday ", 8)==0 && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) && (n=(int)r)==r && n>=0 && r<7 ){ sqlite3_int64 Z; @@ -17089,23 +20185,24 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ ** Move the date backwards to the beginning of the current day, ** or month or year. */ - if( strncmp(z, "start of ", 9)!=0 ) break; + if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break; + if( !p->validJD && !p->validYMD && !p->validHMS ) break; z += 9; computeYMD(p); p->validHMS = 1; p->h = p->m = 0; p->s = 0.0; + p->rawS = 0; p->validTZ = 0; p->validJD = 0; - if( strcmp(z,"month")==0 ){ + if( sqlite3_stricmp(z,"month")==0 ){ p->D = 1; rc = 0; - }else if( strcmp(z,"year")==0 ){ - computeYMD(p); + }else if( sqlite3_stricmp(z,"year")==0 ){ p->M = 1; p->D = 1; rc = 0; - }else if( strcmp(z,"day")==0 ){ + }else if( sqlite3_stricmp(z,"day")==0 ){ rc = 0; } break; @@ -17123,6 +20220,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ case '8': case '9': { double rRounder; + int i; for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ rc = 1; @@ -17151,46 +20249,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){ rc = 0; break; } + + /* If control reaches this point, it means the transformation is + ** one of the forms like "+NNN days". */ z += n; while( sqlite3Isspace(*z) ) z++; n = sqlite3Strlen30(z); if( n>10 || n<3 ) break; - if( z[n-1]=='s' ){ z[n-1] = 0; n--; } + if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; computeJD(p); - rc = 0; + rc = 1; rRounder = r<0 ? -0.5 : +0.5; - if( n==3 && strcmp(z,"day")==0 ){ - p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder); - }else if( n==4 && strcmp(z,"hour")==0 ){ - p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder); - }else if( n==6 && strcmp(z,"minute")==0 ){ - p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder); - }else if( n==6 && strcmp(z,"second")==0 ){ - p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder); - }else if( n==5 && strcmp(z,"month")==0 ){ - int x, y; - computeYMD_HMS(p); - p->M += (int)r; - x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; - p->Y += x; - p->M -= x*12; - p->validJD = 0; - computeJD(p); - y = (int)r; - if( y!=r ){ - p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder); + for(i=0; i-aXformType[i].rLimit && rM += (int)r; + x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; + p->Y += x; + p->M -= x*12; + p->validJD = 0; + r -= (int)r; + break; + } + case 2: { /* Special processing to add years */ + int y = (int)r; + computeYMD_HMS(p); + p->Y += y; + p->validJD = 0; + r -= (int)r; + break; + } + } + computeJD(p); + p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); + rc = 0; + break; } - }else if( n==4 && strcmp(z,"year")==0 ){ - int y = (int)r; - computeYMD_HMS(p); - p->Y += y; - p->validJD = 0; - computeJD(p); - if( y!=r ){ - p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder); - } - }else{ - rc = 1; } clearYMD_HMS_TZ(p); break; @@ -17217,7 +20317,7 @@ static int isDate( sqlite3_value **argv, DateTime *p ){ - int i; + int i, n; const unsigned char *z; int eType; memset(p, 0, sizeof(*p)); @@ -17226,8 +20326,7 @@ static int isDate( } if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT || eType==SQLITE_INTEGER ){ - p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5); - p->validJD = 1; + setRawDateNumber(p, sqlite3_value_double(argv[0])); }else{ z = sqlite3_value_text(argv[0]); if( !z || parseDateOrTime(context, (char*)z, p) ){ @@ -17236,8 +20335,11 @@ static int isDate( } for(i=1; iisError || !validJulianDay(p->iJD) ) return 1; return 0; } @@ -17400,7 +20502,7 @@ static void strftimeFunc( sqlite3_result_error_toobig(context); return; }else{ - z = sqlite3DbMallocRaw(db, (int)n); + z = sqlite3DbMallocRawNN(db, (int)n); if( z==0 ){ sqlite3_result_error_nomem(context); return; @@ -17536,7 +20638,6 @@ static void currentTimeFunc( ){ time_t t; char *zFormat = (char *)sqlite3_user_data(context); - sqlite3 *db; sqlite3_int64 iT; struct tm *pTm; struct tm sNow; @@ -17569,13 +20670,13 @@ static void currentTimeFunc( ** external linkage. */ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){ - static SQLITE_WSD FuncDef aDateTimeFuncs[] = { + static FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS - DFUNCTION(julianday, -1, 0, 0, juliandayFunc ), - DFUNCTION(date, -1, 0, 0, dateFunc ), - DFUNCTION(time, -1, 0, 0, timeFunc ), - DFUNCTION(datetime, -1, 0, 0, datetimeFunc ), - DFUNCTION(strftime, -1, 0, 0, strftimeFunc ), + PURE_DATE(julianday, -1, 0, 0, juliandayFunc ), + PURE_DATE(date, -1, 0, 0, dateFunc ), + PURE_DATE(time, -1, 0, 0, timeFunc ), + PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), + PURE_DATE(strftime, -1, 0, 0, strftimeFunc ), DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), DFUNCTION(current_date, 0, 0, 0, cdateFunc ), @@ -17585,13 +20686,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){ STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc), #endif }; - int i; - FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); - FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs); - - for(i=0; ipMethods ){ - rc = pId->pMethods->xClose(pId); + pId->pMethods->xClose(pId); pId->pMethods = 0; } - return rc; } SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ DO_OS_MALLOC_TEST(id); @@ -17678,7 +20791,7 @@ SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){ } SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){ DO_OS_MALLOC_TEST(id); - return id->pMethods->xSync(id, flags); + return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ DO_OS_MALLOC_TEST(id); @@ -17708,8 +20821,8 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ #ifdef SQLITE_TEST if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite - ** is using a regular VFS, it is called after the corresponding - ** transaction has been committed. Injecting a fault at this point + ** is using a regular VFS, it is called after the corresponding + ** transaction has been committed. Injecting a fault at this point ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM ** but the transaction is committed anyway. ** @@ -17733,6 +20846,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ return id->pMethods->xDeviceCharacteristics(id); } +#ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ return id->pMethods->xShmLock(id, offset, n, flags); } @@ -17752,6 +20866,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap( DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } +#endif /* SQLITE_OMIT_WAL */ #if SQLITE_MAX_MMAP_SIZE>0 /* The real implementation of xFetch and xUnfetch */ @@ -17778,10 +20893,10 @@ SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ ** VFS methods. */ SQLITE_PRIVATE int sqlite3OsOpen( - sqlite3_vfs *pVfs, - const char *zPath, - sqlite3_file *pFile, - int flags, + sqlite3_vfs *pVfs, + const char *zPath, + sqlite3_file *pFile, + int flags, int *pFlagsOut ){ int rc; @@ -17800,18 +20915,18 @@ SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dir return pVfs->xDelete(pVfs, zPath, dirSync); } SQLITE_PRIVATE int sqlite3OsAccess( - sqlite3_vfs *pVfs, - const char *zPath, - int flags, + sqlite3_vfs *pVfs, + const char *zPath, + int flags, int *pResOut ){ DO_OS_MALLOC_TEST(0); return pVfs->xAccess(pVfs, zPath, flags, pResOut); } SQLITE_PRIVATE int sqlite3OsFullPathname( - sqlite3_vfs *pVfs, - const char *zPath, - int nPathOut, + sqlite3_vfs *pVfs, + const char *zPath, + int nPathOut, char *zPathOut ){ DO_OS_MALLOC_TEST(0); @@ -17838,6 +20953,9 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ return pVfs->xSleep(pVfs, nMicro); } +SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){ + return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0; +} SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ int rc; /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64() @@ -17857,13 +20975,13 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p } SQLITE_PRIVATE int sqlite3OsOpenMalloc( - sqlite3_vfs *pVfs, - const char *zFile, - sqlite3_file **ppFile, + sqlite3_vfs *pVfs, + const char *zFile, + sqlite3_file **ppFile, int flags, int *pOutFlags ){ - int rc = SQLITE_NOMEM; + int rc; sqlite3_file *pFile; pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); if( pFile ){ @@ -17873,15 +20991,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc( }else{ *ppFile = pFile; } + }else{ + rc = SQLITE_NOMEM_BKPT; } return rc; } -SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){ - int rc = SQLITE_OK; +SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){ assert( pFile ); - rc = sqlite3OsClose(pFile); + sqlite3OsClose(pFile); sqlite3_free(pFile); - return rc; } /* @@ -17892,7 +21010,7 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){ */ SQLITE_PRIVATE int sqlite3OsInit(void){ void *p = sqlite3_malloc(10); - if( p==0 ) return SQLITE_NOMEM; + if( p==0 ) return SQLITE_NOMEM_BKPT; sqlite3_free(p); return sqlite3_os_init(); } @@ -17907,7 +21025,7 @@ static sqlite3_vfs * SQLITE_WSD vfsList = 0; ** Locate a VFS by name. If no name is given, simply return the ** first VFS on the list. */ -SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfs){ +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ sqlite3_vfs *pVfs = 0; #if SQLITE_THREADSAFE sqlite3_mutex *mutex; @@ -17953,7 +21071,7 @@ static void vfsUnlink(sqlite3_vfs *pVfs){ ** VFS multiple times. The new VFS becomes the default if makeDflt is ** true. */ -SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); @@ -17981,7 +21099,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDf /* ** Unregister a VFS so that it is no longer accessible. */ -SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif @@ -18021,7 +21139,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ /* #include "sqliteInt.h" */ -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE /* ** Global variables. @@ -18079,7 +21197,7 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){ } } -#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */ +#endif /* #ifndef SQLITE_UNTESTABLE */ /************** End of fault.c ***********************************************/ /************** Begin file mem0.c ********************************************/ @@ -18204,7 +21322,9 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ */ #include #include +#ifdef SQLITE_MIGHT_BE_SINGLE_CORE #include +#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */ static malloc_zone_t* _sqliteZone_; #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); @@ -18272,7 +21392,9 @@ static malloc_zone_t* _sqliteZone_; */ static void *sqlite3MemMalloc(int nByte){ #ifdef SQLITE_MALLOCSIZE - void *p = SQLITE_MALLOC( nByte ); + void *p; + testcase( ROUND8(nByte)==nByte ); + p = SQLITE_MALLOC( nByte ); if( p==0 ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); @@ -18281,7 +21403,7 @@ static void *sqlite3MemMalloc(int nByte){ #else sqlite3_int64 *p; assert( nByte>0 ); - nByte = ROUND8(nByte); + testcase( ROUND8(nByte)!=nByte ); p = SQLITE_MALLOC( nByte+8 ); if( p ){ p[0] = nByte; @@ -18395,19 +21517,10 @@ static int sqlite3MemInit(void *NotUsed){ }else{ /* only 1 core, use our own zone to contention over global locks, ** e.g. we have our own dedicated locks */ - bool success; - malloc_zone_t* newzone = malloc_create_zone(4096, 0); - malloc_set_zone_name(newzone, "Sqlite_Heap"); - do{ - success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, - (void * volatile *)&_sqliteZone_); - }while(!_sqliteZone_); - if( !success ){ - /* somebody registered a zone first */ - malloc_destroy_zone(newzone); - } + _sqliteZone_ = malloc_create_zone(4096, 0); + malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap"); } -#endif +#endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */ UNUSED_PARAMETER(NotUsed); return SQLITE_OK; } @@ -19769,6 +22882,7 @@ static SQLITE_WSD struct Mem5Global { */ sqlite3_mutex *mutex; +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Performance statistics */ @@ -19780,6 +22894,7 @@ static SQLITE_WSD struct Mem5Global { u32 maxOut; /* Maximum instantaneous currentOut */ u32 maxCount; /* Maximum instantaneous currentCount */ u32 maxRequest; /* Largest allocation (exclusive of internal frag) */ +#endif /* ** Lists of free blocks. aiFreelist[0] is a list of free blocks of @@ -19891,14 +23006,17 @@ static void *memsys5MallocUnsafe(int nByte){ /* nByte must be a positive */ assert( nByte>0 ); + /* No more than 1GiB per allocation */ + if( nByte > 0x40000000 ) return 0; + +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* Keep track of the maximum allocation request. Even unfulfilled ** requests are counted */ if( (u32)nByte>mem5.maxRequest ){ - /* Abort if the requested allocation size is larger than the largest - ** power of two that we can represent using 32-bit signed integers. */ - if( nByte > 0x40000000 ) return 0; mem5.maxRequest = nByte; } +#endif + /* Round nByte up to the next valid power of two */ for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz0 ); assert( mem5.currentOut>=(size*mem5.szAtom) ); mem5.currentCount--; mem5.currentOut -= size*mem5.szAtom; assert( mem5.currentOut>0 || mem5.currentCount==0 ); assert( mem5.currentCount>0 || mem5.currentOut==0 ); +#endif mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; while( ALWAYS(iLogsize>iLogsize) & 1 ){ iBuddy = iBlock - size; + assert( iBuddy>=0 ); }else{ iBuddy = iBlock + size; + if( iBuddy>=mem5.nBlock ) break; } - assert( iBuddy>=0 ); - if( (iBuddy+(1<mem5.nBlock ) break; if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break; memsys5Unlink(iBuddy, iLogsize); iLogsize++; @@ -20322,7 +23445,7 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){ /* ** Retrieve a pointer to a static mutex or allocate a new dynamic one. */ -SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){ +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; @@ -20343,7 +23466,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){ /* ** Free a dynamic mutex. */ -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){ +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexFree ); sqlite3GlobalConfig.mutex.xMutexFree(p); @@ -20354,7 +23477,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){ ** Obtain the mutex p. If some other thread already has the mutex, block ** until it can be obtained. */ -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){ +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexEnter ); sqlite3GlobalConfig.mutex.xMutexEnter(p); @@ -20365,7 +23488,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){ ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. */ -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){ +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ int rc = SQLITE_OK; if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexTry ); @@ -20380,7 +23503,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){ ** is not currently entered. If a NULL pointer is passed as an argument ** this function is a no-op. */ -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){ +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ if( p ){ assert( sqlite3GlobalConfig.mutex.xMutexLeave ); sqlite3GlobalConfig.mutex.xMutexLeave(p); @@ -20392,11 +23515,11 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){ ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use inside assert() statements. */ -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){ +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); } -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){ +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); } @@ -21072,8 +24195,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ */ #ifdef SQLITE_PERFORMANCE_TRACE -/* -** hwtime.h contains inline assembler code for implementing +/* +** hwtime.h contains inline assembler code for implementing ** high-performance timing routines. */ /************** Include hwtime.h in the middle of os_common.h ****************/ @@ -21093,8 +24216,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. @@ -21162,7 +24285,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in os_common.h ******************/ @@ -21183,14 +24306,14 @@ static sqlite_uint64 g_elapsed; ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ -SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ -SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ -SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ -SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ -SQLITE_API int sqlite3_diskfull_pending = 0; -SQLITE_API int sqlite3_diskfull = 0; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) #define SimulateIOError(CODE) \ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ @@ -21216,17 +24339,17 @@ static void local_ioerr(){ #define SimulateIOErrorBenign(X) #define SimulateIOError(A) #define SimulateDiskfullError(A) -#endif +#endif /* defined(SQLITE_TEST) */ /* ** When testing, keep a count of the number of open files. */ -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_open_file_count = 0; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) sqlite3_open_file_count+=(X) #else #define OpenCounter(X) -#endif +#endif /* defined(SQLITE_TEST) */ #endif /* !defined(_OS_COMMON_H_) */ @@ -21252,8 +24375,8 @@ SQLITE_API int sqlite3_open_file_count = 0; ** ** This file contains code that is specific to Windows. */ -#ifndef _OS_WIN_H_ -#define _OS_WIN_H_ +#ifndef SQLITE_OS_WIN_H +#define SQLITE_OS_WIN_H /* ** Include the primary Windows SDK header file. @@ -21325,7 +24448,7 @@ SQLITE_API int sqlite3_open_file_count = 0; # define SQLITE_OS_WIN_THREADS 0 #endif -#endif /* _OS_WIN_H_ */ +#endif /* SQLITE_OS_WIN_H */ /************** End of os_win.h **********************************************/ /************** Continuing where we left off in mutex_w32.c ******************/ @@ -21393,8 +24516,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) __sync_synchronize(); -#elif !defined(SQLITE_DISABLE_INTRINSIC) && \ - defined(_MSC_VER) && _MSC_VER>=1300 +#elif MSVC_VERSION>=1300 _ReadWriteBarrier(); #elif defined(MemoryBarrier) MemoryBarrier(); @@ -21428,8 +24550,8 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */ */ static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; -SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void); /* os_win.c */ -SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ +SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ +SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ @@ -21605,8 +24727,8 @@ static void winMutexEnter(sqlite3_mutex *p){ p->owner = tid; p->nRef++; if( p->trace ){ - OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", - tid, p, p->trace, p->nRef)); + OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", + tid, p->id, p, p->trace, p->nRef)); } #endif } @@ -21648,8 +24770,8 @@ static int winMutexTry(sqlite3_mutex *p){ #endif #ifdef SQLITE_DEBUG if( p->trace ){ - OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n", - tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); + OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); } #endif return rc; @@ -21677,8 +24799,8 @@ static void winMutexLeave(sqlite3_mutex *p){ LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ - OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", - tid, p, p->trace, p->nRef)); + OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", + tid, p->id, p, p->trace, p->nRef)); } #endif } @@ -21729,7 +24851,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ ** held by SQLite. An example of non-essential memory is memory used to ** cache database pages that are not currently in use. */ -SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){ +SQLITE_API int sqlite3_release_memory(int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT return sqlite3PcacheReleaseMemory(n); #else @@ -21741,14 +24863,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){ #endif } -/* -** An instance of the following object records the location of -** each unused scratch buffer. -*/ -typedef struct ScratchFreeslot { - struct ScratchFreeslot *pNext; /* Next unused scratch buffer */ -} ScratchFreeslot; - /* ** State information local to the memory allocation subsystem. */ @@ -21756,22 +24870,12 @@ static SQLITE_WSD struct Mem0Global { sqlite3_mutex *mutex; /* Mutex to serialize access */ sqlite3_int64 alarmThreshold; /* The soft heap limit */ - /* - ** Pointers to the end of sqlite3GlobalConfig.pScratch memory - ** (so that a range test can be used to determine if an allocation - ** being freed came from pScratch) and a pointer to the list of - ** unused scratch allocations. - */ - void *pScratchEnd; - ScratchFreeslot *pScratchFree; - u32 nScratchFree; - /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; -} mem0 = { 0, 0, 0, 0, 0, 0 }; +} mem0 = { 0, 0, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) @@ -21788,7 +24892,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){ ** that was invoked when memory usage grew too large. Now it is a ** no-op. */ -SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm( +SQLITE_API int sqlite3_memory_alarm( void(*xCallback)(void *pArg, sqlite3_int64 used,int N), void *pArg, sqlite3_int64 iThreshold @@ -21804,7 +24908,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm( ** Set the soft heap-size limit for the library. Passing a zero or ** negative value indicates no limit. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){ +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; sqlite3_int64 excess; sqlite3_int64 nUsed; @@ -21826,7 +24930,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); return priorLimit; } -SQLITE_API void SQLITE_STDCALL sqlite3_soft_heap_limit(int n){ +SQLITE_API void sqlite3_soft_heap_limit(int n){ if( n<0 ) n = 0; sqlite3_soft_heap_limit64(n); } @@ -21841,28 +24945,6 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){ } memset(&mem0, 0, sizeof(mem0)); mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); - if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100 - && sqlite3GlobalConfig.nScratch>0 ){ - int i, n, sz; - ScratchFreeslot *pSlot; - sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch); - sqlite3GlobalConfig.szScratch = sz; - pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch; - n = sqlite3GlobalConfig.nScratch; - mem0.pScratchFree = pSlot; - mem0.nScratchFree = n; - for(i=0; ipNext = (ScratchFreeslot*)(sz+(char*)pSlot); - pSlot = pSlot->pNext; - } - pSlot->pNext = 0; - mem0.pScratchEnd = (void*)&pSlot[1]; - }else{ - mem0.pScratchEnd = 0; - sqlite3GlobalConfig.pScratch = 0; - sqlite3GlobalConfig.szScratch = 0; - sqlite3GlobalConfig.nScratch = 0; - } if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 || sqlite3GlobalConfig.nPage<=0 ){ sqlite3GlobalConfig.pPage = 0; @@ -21895,7 +24977,7 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){ /* ** Return the amount of memory currently checked out. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){ +SQLITE_API sqlite3_int64 sqlite3_memory_used(void){ sqlite3_int64 res, mx; sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0); return res; @@ -21906,7 +24988,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){ ** checked out since either the beginning of this process ** or since the most recent reset. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){ +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ sqlite3_int64 res, mx; sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag); return mx; @@ -21926,11 +25008,26 @@ static void sqlite3MallocAlarm(int nByte){ ** Do a memory allocation with statistics and alarms. Assume the ** lock is already held. */ -static int mallocWithAlarm(int n, void **pp){ - int nFull; +static void mallocWithAlarm(int n, void **pp){ void *p; + int nFull; assert( sqlite3_mutex_held(mem0.mutex) ); + assert( n>0 ); + + /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal + ** implementation of malloc_good_size(), which must be called in debug + ** mode and specifically when the DMD "Dark Matter Detector" is enabled + ** or else a crash results. Hence, do not attempt to optimize out the + ** following xRoundup() call. */ nFull = sqlite3GlobalConfig.m.xRoundup(n); + +#ifdef SQLITE_MAX_MEMORY + if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){ + *pp = 0; + return; + } +#endif + sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmThreshold>0 ){ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); @@ -21954,7 +25051,6 @@ static int mallocWithAlarm(int n, void **pp){ sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1); } *pp = p; - return nFull; } /* @@ -21986,118 +25082,19 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n){ ** First make sure the memory subsystem is initialized, then do the ** allocation. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int n){ +SQLITE_API void *sqlite3_malloc(int n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return n<=0 ? 0 : sqlite3Malloc(n); } -SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64 n){ +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return sqlite3Malloc(n); } -/* -** Each thread may only have a single outstanding allocation from -** xScratchMalloc(). We verify this constraint in the single-threaded -** case by setting scratchAllocOut to 1 when an allocation -** is outstanding clearing it when the allocation is freed. -*/ -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) -static int scratchAllocOut = 0; -#endif - - -/* -** Allocate memory that is to be used and released right away. -** This routine is similar to alloca() in that it is not intended -** for situations where the memory might be held long-term. This -** routine is intended to get memory to old large transient data -** structures that would not normally fit on the stack of an -** embedded processor. -*/ -SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){ - void *p; - assert( n>0 ); - - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n); - if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){ - p = mem0.pScratchFree; - mem0.pScratchFree = mem0.pScratchFree->pNext; - mem0.nScratchFree--; - sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3_mutex_leave(mem0.mutex); - p = sqlite3Malloc(n); - if( sqlite3GlobalConfig.bMemstat && p ){ - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); - sqlite3_mutex_leave(mem0.mutex); - } - sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); - } - assert( sqlite3_mutex_notheld(mem0.mutex) ); - - -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch - ** buffers per thread. - ** - ** This can only be checked in single-threaded mode. - */ - assert( scratchAllocOut==0 ); - if( p ) scratchAllocOut++; -#endif - - return p; -} -SQLITE_PRIVATE void sqlite3ScratchFree(void *p){ - if( p ){ - -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* Verify that no more than two scratch allocation per thread - ** is outstanding at one time. (This is only checked in the - ** single-threaded case since checking in the multi-threaded case - ** would be much more complicated.) */ - assert( scratchAllocOut>=1 && scratchAllocOut<=2 ); - scratchAllocOut--; -#endif - - if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){ - /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */ - ScratchFreeslot *pSlot; - pSlot = (ScratchFreeslot*)p; - sqlite3_mutex_enter(mem0.mutex); - pSlot->pNext = mem0.pScratchFree; - mem0.pScratchFree = pSlot; - mem0.nScratchFree++; - assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch ); - sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3_mutex_leave(mem0.mutex); - }else{ - /* Release memory back to the heap */ - assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) ); - assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) ); - sqlite3MemdebugSetType(p, MEMTYPE_HEAP); - if( sqlite3GlobalConfig.bMemstat ){ - int iSize = sqlite3MallocSize(p); - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize); - sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize); - sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); - sqlite3GlobalConfig.m.xFree(p); - sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3GlobalConfig.m.xFree(p); - } - } - } -} - /* ** TRUE if p is a lookaside memory allocation from db */ @@ -22120,7 +25117,7 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ assert( p!=0 ); if( db==0 || !isLookaside(db,p) ){ -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG if( db==0 ){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); @@ -22135,7 +25132,7 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ return db->lookaside.sz; } } -SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){ +SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return p ? sqlite3GlobalConfig.m.xSize(p) : 0; @@ -22144,7 +25141,7 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){ /* ** Free memory previously obtained from sqlite3Malloc(). */ -SQLITE_API void SQLITE_STDCALL sqlite3_free(void *p){ +SQLITE_API void sqlite3_free(void *p){ if( p==0 ) return; /* IMP: R-49053-54554 */ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); @@ -22169,11 +25166,12 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ /* ** Free memory that might be associated with a particular database -** connection. +** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. +** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. */ -SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ +SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); - if( p==0 ) return; + assert( p!=0 ); if( db ){ if( db->pnBytesFreed ){ measureAllocationSize(db, p); @@ -22181,13 +25179,12 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ } if( isLookaside(db, p) ){ LookasideSlot *pBuf = (LookasideSlot*)p; -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* Trash all content in the buffer being freed */ memset(p, 0xaa, db->lookaside.sz); #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; - db->lookaside.nOut--; return; } } @@ -22197,6 +25194,10 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } +SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ + assert( db==0 || sqlite3_mutex_held(db->mutex) ); + if( p ) sqlite3DbFreeNN(db, p); +} /* ** Change the size of an existing memory allocation @@ -22228,7 +25229,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; - if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= + if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); } @@ -22253,14 +25254,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ ** The public interface to sqlite3Realloc. Make sure that the memory ** subsystem is initialized prior to invoking sqliteRealloc. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void *pOld, int n){ +SQLITE_API void *sqlite3_realloc(void *pOld, int n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif if( n<0 ) n = 0; /* IMP: R-26507-47431 */ return sqlite3Realloc(pOld, n); } -SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ +SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif @@ -22284,16 +25285,31 @@ SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){ ** the mallocFailed flag in the connection pointer. */ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ - void *p = sqlite3DbMallocRaw(db, n); - if( p ){ - memset(p, 0, (size_t)n); - } + void *p; + testcase( db==0 ); + p = sqlite3DbMallocRaw(db, n); + if( p ) memset(p, 0, (size_t)n); + return p; +} + + +/* Finish the work of sqlite3DbMallocRawNN for the unusual and +** slower case when the allocation cannot be fulfilled using lookaside. +*/ +static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ + void *p; + assert( db!=0 ); + p = sqlite3Malloc(n); + if( !p ) sqlite3OomFault(db); + sqlite3MemdebugSetType(p, + (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); return p; } /* -** Allocate and zero memory. If the allocation fails, make -** the mallocFailed flag in the connection pointer. +** Allocate memory, either lookaside (if possible) or heap. +** If the allocation fails, set the mallocFailed flag in +** the connection pointer. ** ** If db!=0 and db->mallocFailed is true (indicating a prior malloc ** failure on the same database connection) then always return 0. @@ -22308,64 +25324,73 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ ** ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed ** that all prior mallocs (ex: "a") worked too. +** +** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is +** not a NULL pointer. */ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ void *p; - assert( db==0 || sqlite3_mutex_held(db->mutex) ); - assert( db==0 || db->pnBytesFreed==0 ); + if( db ) return sqlite3DbMallocRawNN(db, n); + p = sqlite3Malloc(n); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); + return p; +} +SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ #ifndef SQLITE_OMIT_LOOKASIDE - if( db ){ - LookasideSlot *pBuf; - if( db->mallocFailed ){ - return 0; - } - if( db->lookaside.bEnabled ){ - if( n>db->lookaside.sz ){ - db->lookaside.anStat[1]++; - }else if( (pBuf = db->lookaside.pFree)==0 ){ - db->lookaside.anStat[2]++; - }else{ - db->lookaside.pFree = pBuf->pNext; - db->lookaside.nOut++; - db->lookaside.anStat[0]++; - if( db->lookaside.nOut>db->lookaside.mxOut ){ - db->lookaside.mxOut = db->lookaside.nOut; - } - return (void*)pBuf; - } + LookasideSlot *pBuf; + assert( db!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( db->pnBytesFreed==0 ); + if( db->lookaside.bDisable==0 ){ + assert( db->mallocFailed==0 ); + if( n>db->lookaside.sz ){ + db->lookaside.anStat[1]++; + }else if( (pBuf = db->lookaside.pFree)!=0 ){ + db->lookaside.pFree = pBuf->pNext; + db->lookaside.anStat[0]++; + return (void*)pBuf; + }else if( (pBuf = db->lookaside.pInit)!=0 ){ + db->lookaside.pInit = pBuf->pNext; + db->lookaside.anStat[0]++; + return (void*)pBuf; + }else{ + db->lookaside.anStat[2]++; } + }else if( db->mallocFailed ){ + return 0; } #else - if( db && db->mallocFailed ){ + assert( db!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( db->pnBytesFreed==0 ); + if( db->mallocFailed ){ return 0; } #endif - p = sqlite3Malloc(n); - if( !p && db ){ - db->mallocFailed = 1; - } - sqlite3MemdebugSetType(p, - (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); - return p; + return dbMallocRawFinish(db, n); } +/* Forward declaration */ +static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n); + /* ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ + assert( db!=0 ); + if( p==0 ) return sqlite3DbMallocRawNN(db, n); + assert( sqlite3_mutex_held(db->mutex) ); + if( isLookaside(db,p) && n<=db->lookaside.sz ) return p; + return dbReallocFinish(db, p, n); +} +static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ void *pNew = 0; assert( db!=0 ); - assert( sqlite3_mutex_held(db->mutex) ); + assert( p!=0 ); if( db->mallocFailed==0 ){ - if( p==0 ){ - return sqlite3DbMallocRaw(db, n); - } if( isLookaside(db, p) ){ - if( n<=db->lookaside.sz ){ - return p; - } - pNew = sqlite3DbMallocRaw(db, n); + pNew = sqlite3DbMallocRawNN(db, n); if( pNew ){ memcpy(pNew, p, db->lookaside.sz); sqlite3DbFree(db, p); @@ -22376,10 +25401,10 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3_realloc64(p, n); if( !pNew ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } sqlite3MemdebugSetType(pNew, - (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); + (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } return pNew; @@ -22411,9 +25436,8 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ if( z==0 ){ return 0; } - n = sqlite3Strlen30(z) + 1; - assert( (n&0x7fffffff)==n ); - zNew = sqlite3DbMallocRaw(db, (int)n); + n = strlen(z) + 1; + zNew = sqlite3DbMallocRaw(db, n); if( zNew ){ memcpy(zNew, z, n); } @@ -22421,11 +25445,12 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ } SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; + assert( db!=0 ); if( z==0 ){ return 0; } assert( (n&0x7fffffff)==n ); - zNew = sqlite3DbMallocRaw(db, n+1); + zNew = sqlite3DbMallocRawNN(db, n+1); if( zNew ){ memcpy(zNew, z, (size_t)n); zNew[n] = 0; @@ -22441,13 +25466,45 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ *pz = sqlite3DbStrDup(db, zNew); } +/* +** Call this routine to record the fact that an OOM (out-of-memory) error +** has happened. This routine will set db->mallocFailed, and also +** temporarily disable the lookaside memory allocator and interrupt +** any running VDBEs. +*/ +SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ + if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ + db->mallocFailed = 1; + if( db->nVdbeExec>0 ){ + db->u1.isInterrupted = 1; + } + db->lookaside.bDisable++; + } +} + +/* +** This routine reactivates the memory allocator and clears the +** db->mallocFailed flag as necessary. +** +** The memory allocator is not restarted if there are running +** VDBEs. +*/ +SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){ + if( db->mallocFailed && db->nVdbeExec==0 ){ + db->mallocFailed = 0; + db->u1.isInterrupted = 0; + assert( db->lookaside.bDisable>0 ); + db->lookaside.bDisable--; + } +} + /* ** Take actions at the end of an API call to indicate an OOM error */ static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ - db->mallocFailed = 0; + sqlite3OomClear(db); sqlite3Error(db, SQLITE_NOMEM); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } /* @@ -22494,26 +25551,27 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ ** Conversion types fall into various categories as defined by the ** following enumeration. */ -#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ -#define etFLOAT 2 /* Floating point. %f */ -#define etEXP 3 /* Exponentional notation. %e and %E */ -#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */ -#define etSIZE 5 /* Return number of characters processed so far. %n */ -#define etSTRING 6 /* Strings. %s */ -#define etDYNSTRING 7 /* Dynamically allocated strings. %z */ -#define etPERCENT 8 /* Percent symbol. %% */ -#define etCHARX 9 /* Characters. %c */ +#define etRADIX 0 /* non-decimal integer types. %x %o */ +#define etFLOAT 1 /* Floating point. %f */ +#define etEXP 2 /* Exponentional notation. %e and %E */ +#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ +#define etSIZE 4 /* Return number of characters processed so far. %n */ +#define etSTRING 5 /* Strings. %s */ +#define etDYNSTRING 6 /* Dynamically allocated strings. %z */ +#define etPERCENT 7 /* Percent symbol. %% */ +#define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ -#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */ -#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '', +#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ +#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ -#define etTOKEN 12 /* a pointer to a Token structure */ -#define etSRCLIST 13 /* a pointer to a SrcList */ -#define etPOINTER 14 /* The %p conversion */ -#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */ -#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etTOKEN 11 /* a pointer to a Token structure */ +#define etSRCLIST 12 /* a pointer to a SrcList */ +#define etPOINTER 13 /* The %p conversion */ +#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ +#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etDECIMAL 16 /* %d or %u, but not %x, %o */ -#define etINVALID 0 /* Any unrecognized conversion type */ +#define etINVALID 17 /* Any unrecognized conversion type */ /* @@ -22537,9 +25595,8 @@ typedef struct et_info { /* Information about each format field */ /* ** Allowed values for et_info.flags */ -#define FLAG_SIGNED 1 /* True if the value to convert is signed */ -#define FLAG_INTERN 2 /* True if for internal use only */ -#define FLAG_STRING 4 /* Allow infinity precision */ +#define FLAG_SIGNED 1 /* True if the value to convert is signed */ +#define FLAG_STRING 4 /* Allow infinite precision */ /* @@ -22549,7 +25606,7 @@ typedef struct et_info { /* Information about each format field */ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; static const et_info fmtinfo[] = { - { 'd', 10, 1, etRADIX, 0, 0 }, + { 'd', 10, 1, etDECIMAL, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 4, etDYNSTRING, 0, 0 }, @@ -22558,7 +25615,7 @@ static const et_info fmtinfo[] = { { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, - { 'u', 10, 0, etRADIX, 0, 0 }, + { 'u', 10, 0, etDECIMAL, 0, 0 }, { 'x', 16, 0, etRADIX, 16, 1 }, { 'X', 16, 0, etRADIX, 0, 4 }, #ifndef SQLITE_OMIT_FLOATING_POINT @@ -22567,16 +25624,15 @@ static const et_info fmtinfo[] = { { 'E', 0, 1, etEXP, 14, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, #endif - { 'i', 10, 1, etRADIX, 0, 0 }, + { 'i', 10, 1, etDECIMAL, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, -/* All the rest have the FLAG_INTERN bit set and are thus for internal -** use only */ - { 'T', 0, 2, etTOKEN, 0, 0 }, - { 'S', 0, 2, etSRCLIST, 0, 0 }, - { 'r', 10, 3, etORDINAL, 0, 0 }, + /* All the rest are undocumented and are for internal use only */ + { 'T', 0, 0, etTOKEN, 0, 0 }, + { 'S', 0, 0, etSRCLIST, 0, 0 }, + { 'r', 10, 1, etORDINAL, 0, 0 }, }; /* @@ -22650,7 +25706,6 @@ static char *getTextArg(PrintfArguments *p){ */ SQLITE_PRIVATE void sqlite3VXPrintf( StrAccum *pAccum, /* Accumulate results here */ - u32 bFlags, /* SQLITE_PRINTF_* flags */ const char *fmt, /* Format string */ va_list ap /* arguments */ ){ @@ -22661,17 +25716,15 @@ SQLITE_PRIVATE void sqlite3VXPrintf( int idx; /* A general purpose loop counter */ int width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ - etByte flag_plussign; /* True if "+" flag is present */ - etByte flag_blanksign; /* True if " " flag is present */ + etByte flag_prefix; /* '+' or ' ' or 0 for prefix */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ - etByte flag_long; /* True if "l" flag is present */ - etByte flag_longlong; /* True if the "ll" flag is present */ + etByte flag_long; /* 1 for the "l" flag, 2 for "ll", 0 by default */ etByte done; /* Loop termination flag */ - etByte xtype = 0; /* Conversion paradigm */ + etByte cThousand; /* Thousands separator for %d and %u */ + etByte xtype = etINVALID; /* Conversion paradigm */ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ - u8 useIntern; /* Ok to use internal conversions (ex: %T) */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ @@ -22690,13 +25743,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( char buf[etBUFSIZE]; /* Conversion buffer */ bufpt = 0; - if( bFlags ){ - if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){ - pArgList = va_arg(ap, PrintfArguments*); - } - useIntern = bFlags & SQLITE_PRINTF_INTERNAL; + if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ + pArgList = va_arg(ap, PrintfArguments*); + bArgList = 1; }else{ - bArgList = useIntern = 0; + bArgList = 0; } for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ @@ -22714,17 +25765,18 @@ SQLITE_PRIVATE void sqlite3VXPrintf( break; } /* Find out what flags are present */ - flag_leftjustify = flag_plussign = flag_blanksign = + flag_leftjustify = flag_prefix = cThousand = flag_alternateform = flag_altform2 = flag_zeropad = 0; done = 0; do{ switch( c ){ case '-': flag_leftjustify = 1; break; - case '+': flag_plussign = 1; break; - case ' ': flag_blanksign = 1; break; + case '+': flag_prefix = '+'; break; + case ' ': flag_prefix = ' '; break; case '#': flag_alternateform = 1; break; case '!': flag_altform2 = 1; break; case '0': flag_zeropad = 1; break; + case ',': cThousand = ','; break; default: done = 1; break; } }while( !done && (c=(*++fmt))!=0 ); @@ -22794,13 +25846,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( flag_long = 1; c = *++fmt; if( c=='l' ){ - flag_longlong = 1; + flag_long = 2; c = *++fmt; - }else{ - flag_longlong = 0; } }else{ - flag_long = flag_longlong = 0; + flag_long = 0; } /* Fetch the info entry for the field */ infop = &fmtinfo[0]; @@ -22808,11 +25858,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( for(idx=0; idxflags & FLAG_INTERN)==0 ){ - xtype = infop->type; - }else{ - return; - } + xtype = infop->type; break; } } @@ -22822,15 +25868,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** ** flag_alternateform TRUE if a '#' is present. ** flag_altform2 TRUE if a '!' is present. - ** flag_plussign TRUE if a '+' is present. + ** flag_prefix '+' or ' ' or zero ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. - ** flag_long TRUE if the letter 'l' (ell) prefixed - ** the conversion character. - ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed - ** the conversion character. - ** flag_blanksign TRUE if a ' ' is present. + ** flag_long 1 for "l", 2 for "ll" ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default @@ -22840,19 +25882,24 @@ SQLITE_PRIVATE void sqlite3VXPrintf( */ switch( xtype ){ case etPOINTER: - flag_longlong = sizeof(char*)==sizeof(i64); - flag_long = sizeof(char*)==sizeof(long int); + flag_long = sizeof(char*)==sizeof(i64) ? 2 : + sizeof(char*)==sizeof(long int) ? 1 : 0; /* Fall through into the next case */ case etORDINAL: - case etRADIX: + case etRADIX: + cThousand = 0; + /* Fall through into the next case */ + case etDECIMAL: if( infop->flags & FLAG_SIGNED ){ i64 v; if( bArgList ){ v = getIntArg(pArgList); - }else if( flag_longlong ){ - v = va_arg(ap,i64); }else if( flag_long ){ - v = va_arg(ap,long int); + if( flag_long==2 ){ + v = va_arg(ap,i64) ; + }else{ + v = va_arg(ap,long int); + } }else{ v = va_arg(ap,int); } @@ -22865,17 +25912,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf( prefix = '-'; }else{ longvalue = v; - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; + prefix = flag_prefix; } }else{ if( bArgList ){ longvalue = (u64)getIntArg(pArgList); - }else if( flag_longlong ){ - longvalue = va_arg(ap,u64); }else if( flag_long ){ - longvalue = va_arg(ap,unsigned long int); + if( flag_long==2 ){ + longvalue = va_arg(ap,u64); + }else{ + longvalue = va_arg(ap,unsigned long int); + } }else{ longvalue = va_arg(ap,unsigned int); } @@ -22885,16 +25932,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( flag_zeropad && precision0 ); } length = (int)(&zOut[nOut-1]-bufpt); - for(idx=precision-length; idx>0; idx--){ + while( precision>length ){ *(--bufpt) = '0'; /* Zero pad */ + length++; + } + if( cThousand ){ + int nn = (length - 1)/3; /* Number of "," to insert */ + int ix = (length - 1)%3 + 1; + bufpt -= nn; + for(idx=0; nn>0; idx++){ + bufpt[idx] = bufpt[idx+nn]; + ix--; + if( ix==0 ){ + bufpt[++idx] = cThousand; + nn--; + ix = 3; + } + } } if( prefix ) *(--bufpt) = prefix; /* Add sign */ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ @@ -22943,9 +26006,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( realvalue = -realvalue; prefix = '-'; }else{ - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; + prefix = flag_prefix; } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); @@ -23131,7 +26192,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( precision>=0 ){ for(length=0; lengthprintfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; + pToken = va_arg(ap, Token*); assert( bArgList==0 ); if( pToken && pToken->n ){ sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n); @@ -23190,9 +26253,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf( break; } case etSRCLIST: { - SrcList *pSrc = va_arg(ap, SrcList*); - int k = va_arg(ap, int); - struct SrcList_item *pItem = &pSrc->a[k]; + SrcList *pSrc; + int k; + struct SrcList_item *pItem; + if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; + pSrc = va_arg(ap, SrcList*); + k = va_arg(ap, int); + pItem = &pSrc->a[k]; assert( bArgList==0 ); assert( k>=0 && knSrc ); if( pItem->zDatabase ){ @@ -23214,9 +26281,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** the output. */ width -= length; - if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); - sqlite3StrAccumAppend(pAccum, bufpt, length); - if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + if( width>0 ){ + if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + sqlite3StrAccumAppend(pAccum, bufpt, length); + if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + }else{ + sqlite3StrAccumAppend(pAccum, bufpt, length); + } if( zExtra ){ sqlite3DbFree(pAccum->db, zExtra); @@ -23245,9 +26316,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ setStrAccumError(p, STRACCUM_TOOBIG); return N; }else{ - char *zOld = p->bMalloced ? p->zText : 0; + char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; - assert( (p->zText==0 || p->zText==p->zBase)==(p->bMalloced==0) ); szNew += N + 1; if( szNew+p->nChar<=p->mxAlloc ){ /* Force exponential buffer size growth as long as it does not overflow, @@ -23268,10 +26338,10 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ } if( zNew ){ assert( p->zText!=0 || p->nChar==0 ); - if( !p->bMalloced && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); + if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; p->nAlloc = sqlite3DbMallocSize(p->db, zNew); - p->bMalloced = 1; + p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_NOMEM); @@ -23289,7 +26359,6 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ return; } - assert( (p->zText==p->zBase)==(p->bMalloced==0) ); while( (N--)>0 ) p->zText[p->nChar++] = c; } @@ -23307,7 +26376,6 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ memcpy(&p->zText[p->nChar], z, N); p->nChar += N; } - assert( (p->zText==0 || p->zText==p->zBase)==(p->bMalloced==0) ); } /* @@ -23321,7 +26389,7 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ assert( p->accError==0 || p->nAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); - }else{ + }else if( N ){ assert( p->zText ); p->nChar += N; memcpy(&p->zText[p->nChar-N], z, N); @@ -23341,18 +26409,24 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ ** Return a pointer to the resulting string. Return a NULL ** pointer if any kind of error was encountered. */ +static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ + char *zText; + assert( p->mxAlloc>0 && !isMalloced(p) ); + zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); + if( zText ){ + memcpy(zText, p->zText, p->nChar+1); + p->printfFlags |= SQLITE_PRINTF_MALLOCED; + }else{ + setStrAccumError(p, STRACCUM_NOMEM); + } + p->zText = zText; + return zText; +} SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ if( p->zText ){ - assert( (p->zText==p->zBase)==(p->bMalloced==0) ); p->zText[p->nChar] = 0; - if( p->mxAlloc>0 && p->bMalloced==0 ){ - p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); - if( p->zText ){ - memcpy(p->zText, p->zBase, p->nChar+1); - p->bMalloced = 1; - }else{ - setStrAccumError(p, STRACCUM_NOMEM); - } + if( p->mxAlloc>0 && !isMalloced(p) ){ + return strAccumFinishRealloc(p); } } return p->zText; @@ -23362,10 +26436,9 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ ** Reset an StrAccum string. Reclaim all malloced memory. */ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ - assert( (p->zText==0 || p->zText==p->zBase)==(p->bMalloced==0) ); - if( p->bMalloced ){ + if( isMalloced(p) ){ sqlite3DbFree(p->db, p->zText); - p->bMalloced = 0; + p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; } p->zText = 0; } @@ -23385,13 +26458,13 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ ** allocations will ever occur. */ SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ - p->zText = p->zBase = zBase; + p->zText = zBase; p->db = db; - p->nChar = 0; p->nAlloc = n; p->mxAlloc = mx; + p->nChar = 0; p->accError = 0; - p->bMalloced = 0; + p->printfFlags = 0; } /* @@ -23405,10 +26478,11 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a assert( db!=0 ); sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); - sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap); + acc.printfFlags = SQLITE_PRINTF_INTERNAL; + sqlite3VXPrintf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); if( acc.accError==STRACCUM_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } return z; } @@ -23430,7 +26504,7 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ ** Print into memory obtained from sqlite3_malloc(). Omit the internal ** %-conversion extensions. */ -SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap){ +SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; @@ -23445,7 +26519,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap if( sqlite3_initialize() ) return 0; #endif sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); - sqlite3VXPrintf(&acc, 0, zFormat, ap); + sqlite3VXPrintf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); return z; } @@ -23454,7 +26528,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap ** Print into memory obtained from sqlite3_malloc()(). Omit the internal ** %-conversion extensions. */ -SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){ +SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){ va_list ap; char *z; #ifndef SQLITE_OMIT_AUTOINIT @@ -23479,7 +26553,7 @@ SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){ ** ** sqlite3_vsnprintf() is the varargs version. */ -SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ +SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ StrAccum acc; if( n<=0 ) return zBuf; #ifdef SQLITE_ENABLE_API_ARMOR @@ -23490,10 +26564,11 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char } #endif sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); - sqlite3VXPrintf(&acc, 0, zFormat, ap); - return sqlite3StrAccumFinish(&acc); + sqlite3VXPrintf(&acc, zFormat, ap); + zBuf[acc.nChar] = 0; + return zBuf; } -SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ +SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ char *z; va_list ap; va_start(ap,zFormat); @@ -23521,7 +26596,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); - sqlite3VXPrintf(&acc, 0, zFormat, ap); + sqlite3VXPrintf(&acc, zFormat, ap); sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, sqlite3StrAccumFinish(&acc)); } @@ -23529,7 +26604,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ /* ** Format and write a message to the log if logging is enabled. */ -SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...){ +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){ va_list ap; /* Vararg list */ if( sqlite3GlobalConfig.xLog ){ va_start(ap, zFormat); @@ -23550,7 +26625,7 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ char zBuf[500]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); va_start(ap,zFormat); - sqlite3VXPrintf(&acc, 0, zFormat, ap); + sqlite3VXPrintf(&acc, zFormat, ap); va_end(ap); sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); @@ -23563,10 +26638,10 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ ** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument ** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. */ -SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){ +SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ va_list ap; va_start(ap,zFormat); - sqlite3VXPrintf(p, bFlags, zFormat, ap); + sqlite3VXPrintf(p, zFormat, ap); va_end(ap); } @@ -23637,8 +26712,9 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); } va_start(ap, zFormat); - sqlite3VXPrintf(&acc, 0, zFormat, ap); + sqlite3VXPrintf(&acc, zFormat, ap); va_end(ap); + assert( acc.nChar>0 ); if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); @@ -23672,17 +26748,17 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m char zLine[1000]; const struct Cte *pCte = &pWith->a[i]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3XPrintf(&x, 0, "%s", pCte->zName); + sqlite3XPrintf(&x, "%s", pCte->zName); if( pCte->pCols && pCte->pCols->nExpr>0 ){ char cSep = '('; int j; for(j=0; jpCols->nExpr; j++){ - sqlite3XPrintf(&x, 0, "%c%s", cSep, pCte->pCols->a[j].zName); + sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName); cSep = ','; } - sqlite3XPrintf(&x, 0, ")"); + sqlite3XPrintf(&x, ")"); } - sqlite3XPrintf(&x, 0, " AS"); + sqlite3XPrintf(&x, " AS"); sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); @@ -23694,11 +26770,15 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m /* -** Generate a human-readable description of a the Select object. +** Generate a human-readable description of a Select object. */ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; + if( p==0 ){ + sqlite3TreeViewLine(pView, "nil-SELECT"); + return; + } pView = sqlite3TreeViewPush(pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); @@ -23706,9 +26786,10 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPush(pView, 1); } do{ - sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x", + sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, + (int)p->nSelectRow ); if( cnt++ ) sqlite3TreeViewPop(pView); if( p->pPrior ){ @@ -23733,20 +26814,20 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m StrAccum x; char zLine[100]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor); + sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor); if( pItem->zDatabase ){ - sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName); + sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName); }else if( pItem->zName ){ - sqlite3XPrintf(&x, 0, " %s", pItem->zName); + sqlite3XPrintf(&x, " %s", pItem->zName); } if( pItem->pTab ){ - sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); + sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName); } if( pItem->zAlias ){ - sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); + sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias); } if( pItem->fg.jointype & JT_LEFT ){ - sqlite3XPrintf(&x, 0, " LEFT-JOIN"); + sqlite3XPrintf(&x, " LEFT-JOIN"); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); @@ -23806,7 +26887,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ - char zFlgs[30]; + char zFlgs[60]; pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); @@ -23814,7 +26895,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m return; } if( pExpr->flags ){ - sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags); + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d", + pExpr->flags, pExpr->iRightJoinTable); + }else{ + sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags); + } }else{ zFlgs[0] = 0; } @@ -23912,6 +26998,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; + case TK_SPAN: { + sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + case TK_COLLATE: { sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); @@ -23939,17 +27031,17 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { - sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { - sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); @@ -24012,6 +27104,26 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m break; } #endif + case TK_MATCH: { + sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", + pExpr->iTable, pExpr->iColumn, zFlgs); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); + break; + } + case TK_VECTOR: { + sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR"); + break; + } + case TK_SELECT_COLUMN: { + sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); + sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); + break; + } + case TK_IF_NULL_ROW: { + sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; @@ -24028,21 +27140,20 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewPop(pView); } + /* ** Generate a human-readable explanation of an expression list. */ -SQLITE_PRIVATE void sqlite3TreeViewExprList( +SQLITE_PRIVATE void sqlite3TreeViewBareExprList( TreeView *pView, const ExprList *pList, - u8 moreToFollow, const char *zLabel ){ - int i; - pView = sqlite3TreeViewPush(pView, moreToFollow); if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ + int i; sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; @@ -24054,6 +27165,15 @@ SQLITE_PRIVATE void sqlite3TreeViewExprList( if( j ) sqlite3TreeViewPop(pView); } } +} +SQLITE_PRIVATE void sqlite3TreeViewExprList( + TreeView *pView, + const ExprList *pList, + u8 moreToFollow, + const char *zLabel +){ + pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewBareExprList(pView, pList, zLabel); sqlite3TreeViewPop(pView); } @@ -24093,7 +27213,7 @@ static SQLITE_WSD struct sqlite3PrngType { /* ** Return N random bytes. */ -SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){ +SQLITE_API void sqlite3_randomness(int N, void *pBuf){ unsigned char t; unsigned char *zBuf = pBuf; @@ -24169,7 +27289,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){ sqlite3_mutex_leave(mutex); } -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE /* ** For testing purposes, we sometimes want to preserve the state of ** PRNG and restore the PRNG to its saved state at a later time, or @@ -24194,7 +27314,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){ sizeof(sqlite3Prng) ); } -#endif /* SQLITE_OMIT_BUILTIN_TEST */ +#endif /* SQLITE_UNTESTABLE */ /************** End of random.c **********************************************/ /************** Begin file threads.c *****************************************/ @@ -24263,7 +27383,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate( *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); - if( p==0 ) return SQLITE_NOMEM; + if( p==0 ) return SQLITE_NOMEM_BKPT; memset(p, 0, sizeof(*p)); p->xTask = xTask; p->pIn = pIn; @@ -24289,7 +27409,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ int rc; assert( ppOut!=0 ); - if( NEVER(p==0) ) return SQLITE_NOMEM; + if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; if( p->done ){ *ppOut = p->pOut; rc = SQLITE_OK; @@ -24354,7 +27474,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate( assert( xTask!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); - if( p==0 ) return SQLITE_NOMEM; + if( p==0 ) return SQLITE_NOMEM_BKPT; /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that ** forces worker threads to run sequentially and deterministically @@ -24386,7 +27506,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ BOOL bRc; assert( ppOut!=0 ); - if( NEVER(p==0) ) return SQLITE_NOMEM; + if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; if( p->xTask==0 ){ /* assert( p->id==GetCurrentThreadId() ); */ rc = WAIT_OBJECT_0; @@ -24434,7 +27554,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate( assert( xTask!=0 ); *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); - if( p==0 ) return SQLITE_NOMEM; + if( p==0 ) return SQLITE_NOMEM_BKPT; if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ p->xTask = xTask; p->pIn = pIn; @@ -24450,7 +27570,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate( SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ assert( ppOut!=0 ); - if( NEVER(p==0) ) return SQLITE_NOMEM; + if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; if( p->xTask ){ *ppOut = p->xTask(p->pIn); }else{ @@ -24461,7 +27581,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ #if defined(SQLITE_TEST) { void *pTstAlloc = sqlite3Malloc(10); - if (!pTstAlloc) return SQLITE_NOMEM; + if (!pTstAlloc) return SQLITE_NOMEM_BKPT; sqlite3_free(pTstAlloc); } #endif @@ -24708,7 +27828,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired rc = sqlite3VdbeMemMakeWriteable(pMem); if( rc!=SQLITE_OK ){ assert( rc==SQLITE_NOMEM ); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } zIn = (u8*)pMem->z; zTerm = &zIn[pMem->n&~1]; @@ -24750,7 +27870,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired zTerm = &zIn[pMem->n]; zOut = sqlite3DbMallocRaw(pMem->db, len); if( !zOut ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } z = zOut; @@ -24793,7 +27913,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired c = pMem->flags; sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask); + pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype)); pMem->enc = desiredEnc; pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; @@ -24809,7 +27929,9 @@ translate_out: #endif return SQLITE_OK; } +#endif /* SQLITE_OMIT_UTF16 */ +#ifndef SQLITE_OMIT_UTF16 /* ** This routine checks for a byte-order mark at the beginning of the ** UTF-16 string stored in *pMem. If one is present, it is removed and @@ -25052,7 +28174,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){ ** Return whatever integer value the test callback returns, or return ** SQLITE_OK if no test callback is installed. */ -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; return xCallback ? xCallback(iTest) : SQLITE_OK; @@ -25119,13 +28241,49 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ return 0x3fffffff & (int)strlen(z); } +/* +** Return the declared type of a column. Or return zDflt if the column +** has no declared type. +** +** The column type is an extra string stored after the zero-terminator on +** the column name if and only if the COLFLAG_HASTYPE flag is set. +*/ +SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){ + if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt; + return pCol->zName + strlen(pCol->zName) + 1; +} + +/* +** Helper function for sqlite3Error() - called rarely. Broken out into +** a separate routine to avoid unnecessary register saves on entry to +** sqlite3Error(). +*/ +static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){ + if( db->pErr ) sqlite3ValueSetNull(db->pErr); + sqlite3SystemError(db, err_code); +} + /* ** Set the current error code to err_code and clear any prior error message. +** Also set iSysErrno (by calling sqlite3System) if the err_code indicates +** that would be appropriate. */ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ assert( db!=0 ); db->errCode = err_code; - if( db->pErr ) sqlite3ValueSetNull(db->pErr); + if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); +} + +/* +** Load the sqlite3.iSysErrno field if that is an appropriate thing +** to do based on the SQLite error code in rc. +*/ +SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){ + if( rc==SQLITE_IOERR_NOMEM ) return; + rc &= 0xff; + if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){ + db->iSysErrno = sqlite3OsGetLastError(db->pVfs); + } } /* @@ -25152,6 +28310,7 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ assert( db!=0 ); db->errCode = err_code; + sqlite3SystemError(db, err_code); if( zFormat==0 ){ sqlite3Error(db, err_code); }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){ @@ -25215,18 +28374,13 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ ** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ -SQLITE_PRIVATE int sqlite3Dequote(char *z){ +SQLITE_PRIVATE void sqlite3Dequote(char *z){ char quote; int i, j; - if( z==0 ) return -1; + if( z==0 ) return; quote = z[0]; - switch( quote ){ - case '\'': break; - case '"': break; - case '`': break; /* For MySQL compatibility */ - case '[': quote = ']'; break; /* For MS SqlServer compatibility */ - default: return -1; - } + if( !sqlite3Isquote(quote) ) return; + if( quote=='[' ) quote = ']'; for(i=1, j=0;; i++){ assert( z[i] ); if( z[i]==quote ){ @@ -25241,7 +28395,14 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){ } } z[j] = 0; - return j; +} + +/* +** Generate a Token object from a string +*/ +SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){ + p->z = z; + p->n = sqlite3Strlen30(z); } /* Convenient short-hand */ @@ -25257,19 +28418,28 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){ ** case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){ - register unsigned char *a, *b; +SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ if( zLeft==0 ){ return zRight ? -1 : 0; }else if( zRight==0 ){ return 1; } + return sqlite3StrICmp(zLeft, zRight); +} +SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ + unsigned char *a, *b; + int c; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; - while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } - return UpperToLower[*a] - UpperToLower[*b]; + for(;;){ + c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; + if( c || *a==0 ) break; + a++; + b++; + } + return c; } -SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ +SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ register unsigned char *a, *b; if( zLeft==0 ){ return zRight ? -1 : 0; @@ -25317,7 +28487,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int eValid = 1; /* True exponent is either not used or is well-formed */ double result; int nDigits = 0; - int nonNum = 0; + int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -25330,7 +28500,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i=zEnd ) goto do_atof_calc; @@ -25378,7 +28546,12 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; - if( z>=zEnd ) goto do_atof_calc; + + /* This branch is needed to avoid a (harmless) buffer overread. The + ** special comment alerts the mutation tester that the correct answer + ** is obtained even if the branch is omitted */ + if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ + /* get sign of exponent */ if( *z=='-' ){ esign = -1; @@ -25395,9 +28568,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en } /* skip trailing spaces */ - if( nDigits && eValid ){ - while( z0 ){ - while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10; - }else{ - while( !(s%10) && e>0 ) e--,s/=10; + /* Attempt to reduce exponent. + ** + ** Branches that are not required for the correct answer but which only + ** help to obtain the correct answer faster are marked with special + ** comments, as a hint to the mutation tester. + */ + while( e>0 ){ /*OPTIMIZATION-IF-TRUE*/ + if( esign>0 ){ + if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/ + s *= 10; + }else{ + if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/ + s /= 10; + } + e--; } /* adjust the sign of significand */ s = sign<0 ? -s : s; - /* if exponent, scale significand as appropriate - ** and store in result. */ - if( e ){ + if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/ + result = (double)s; + }else{ LONGDOUBLE_TYPE scale = 1.0; /* attempt to handle extremely small/large numbers better */ - if( e>307 && e<342 ){ - while( e%308 ) { scale *= 1.0e+1; e -= 1; } - if( esign<0 ){ - result = s / scale; - result /= 1.0e+308; - }else{ - result = s * scale; - result *= 1.0e+308; - } - }else if( e>=342 ){ - if( esign<0 ){ - result = 0.0*s; - }else{ - result = 1e308*1e308*s; /* Infinity */ + if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/ + if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/ + while( e%308 ) { scale *= 1.0e+1; e -= 1; } + if( esign<0 ){ + result = s / scale; + result /= 1.0e+308; + }else{ + result = s * scale; + result *= 1.0e+308; + } + }else{ assert( e>=342 ); + if( esign<0 ){ + result = 0.0*s; + }else{ +#ifdef INFINITY + result = INFINITY*s; +#else + result = 1e308*1e308*s; /* Infinity */ +#endif + } } }else{ /* 1.0e+22 is the largest power of 10 than can be @@ -25456,8 +28641,6 @@ do_atof_calc: result = s * scale; } } - } else { - result = (double)s; } } @@ -25465,7 +28648,7 @@ do_atof_calc: *pResult = result; /* return true if number and no extra non-whitespace chracters after */ - return z>=zEnd && nDigits>0 && eValid && nonNum==0; + return z==zEnd && nDigits>0 && eValid && nonNum==0; #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ @@ -25506,16 +28689,12 @@ static int compare2pow63(const char *zNum, int incr){ ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** -** If the zNum value is representable as a 64-bit twos-complement -** integer, then write that value into *pNum and return 0. +** Returns: ** -** If zNum is exactly 9223372036854775808, return 2. This special -** case is broken out because while 9223372036854775808 cannot be a -** signed 64-bit integer, its negative -9223372036854775808 can be. -** -** If zNum is too big for a 64-bit integer and is not -** 9223372036854775808 or if zNum contains any non-numeric text, -** then return 1. +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is @@ -25527,7 +28706,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc int neg = 0; /* assume positive */ int i; int c = 0; - int nonNum = 0; + int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int rc; /* Baseline return code */ const char *zStart; const char *zEnd = zNum + length; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); @@ -25538,7 +28718,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i19*incr || nonNum ){ + if( &zNum[i]19*incr ){ /* Too many digits */ /* zNum is empty or contains non-numeric text or is longer ** than 19 digits (thus guaranteeing that it is too large) */ - return 1; + return 2; }else if( i<19*incr ){ /* Less than 19 digits, so we know that it fits in 64 bits */ assert( u<=LARGEST_INT64 ); - return 0; + return rc; }else{ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */ c = compare2pow63(zNum, incr); if( c<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); - return 0; + return rc; }else if( c>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ - return 1; + return 2; }else{ /* zNum is exactly 9223372036854775808. Fits if negative. The ** special case 2 overflow if positive */ assert( u-1==LARGEST_INT64 ); - return neg ? 0 : 2; + return neg ? rc : 3; } } } @@ -25601,14 +28788,14 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. -** 1 Integer too large for a 64-bit signed integer or is malformed -** 2 Special case of 9223372036854775808 +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 */ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ #ifndef SQLITE_OMIT_HEX_INTEGER if( z[0]=='0' && (z[1]=='x' || z[1]=='X') - && sqlite3Isxdigit(z[2]) ){ u64 u = 0; int i, k; @@ -25617,7 +28804,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); - return (z[k]==0 && k-i<=16) ? 0 : 1; + return (z[k]==0 && k-i<=16) ? 0 : 2; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { @@ -25664,6 +28851,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ } } #endif + if( !sqlite3Isdigit(zNum[0]) ) return 0; while( zNum[0]=='0' ) zNum++; for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; @@ -26078,7 +29266,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ */ SQLITE_PRIVATE int sqlite3VarintLen(u64 v){ int i; - for(i=1; (v >>= 7)!=0; i++){ assert( i<9 ); } + for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); } return i; } @@ -26091,13 +29279,11 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ u32 x; memcpy(&x,p,4); return x; -#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \ - && defined(__GNUC__) && GCC_VERSION>=4003000 +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u32 x; memcpy(&x,p,4); return __builtin_bswap32(x); -#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \ - && defined(_MSC_VER) && _MSC_VER>=1300 +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 u32 x; memcpy(&x,p,4); return _byteswap_ulong(x); @@ -26109,10 +29295,10 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ #if SQLITE_BYTEORDER==4321 memcpy(p,&v,4); -#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000 +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u32 x = __builtin_bswap32(v); memcpy(p,&x,4); -#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300 +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 u32 x = _byteswap_ulong(v); memcpy(p,&x,4); #else @@ -26152,7 +29338,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ char *zBlob; int i; - zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1); + zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1); n--; if( zBlob ){ for(i=0; i=5004000 && !defined(__INTEL_COMPILER) + return __builtin_add_overflow(*pA, iB, pA); +#else i64 iA = *pA; testcase( iA==0 ); testcase( iA==1 ); testcase( iB==-1 ); testcase( iB==0 ); @@ -26242,8 +29431,12 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ } *pA += iB; return 0; +#endif } SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) + return __builtin_sub_overflow(*pA, iB, pA); +#else testcase( iB==SMALLEST_INT64+1 ); if( iB==SMALLEST_INT64 ){ testcase( (*pA)==(-1) ); testcase( (*pA)==0 ); @@ -26253,38 +29446,28 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ }else{ return sqlite3AddInt64(pA, -iB); } +#endif } -#define TWOPOWER32 (((i64)1)<<32) -#define TWOPOWER31 (((i64)1)<<31) SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) + return __builtin_mul_overflow(*pA, iB, pA); +#else i64 iA = *pA; - i64 iA1, iA0, iB1, iB0, r; - - iA1 = iA/TWOPOWER32; - iA0 = iA % TWOPOWER32; - iB1 = iB/TWOPOWER32; - iB0 = iB % TWOPOWER32; - if( iA1==0 ){ - if( iB1==0 ){ - *pA *= iB; - return 0; + if( iB>0 ){ + if( iA>LARGEST_INT64/iB ) return 1; + if( iA0 ){ + if( iBLARGEST_INT64/-iB ) return 1; } - r = iA0*iB1; - }else if( iB1==0 ){ - r = iA1*iB0; - }else{ - /* If both iA1 and iB1 are non-zero, overflow will result */ - return 1; } - testcase( r==(-TWOPOWER31)-1 ); - testcase( r==(-TWOPOWER31) ); - testcase( r==TWOPOWER31 ); - testcase( r==TWOPOWER31-1 ); - if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1; - r *= TWOPOWER32; - if( sqlite3AddInt64(&r, iA0*iB0) ) return 1; - *pA = r; + *pA = iA*iB; return 0; +#endif } /* @@ -26368,8 +29551,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ if( x<2 ) return 0; while( x<8 ){ y -= 10; x <<= 1; } }else{ - while( x>255 ){ y += 40; x >>= 4; } +#if GCC_VERSION>=5004000 + int i = 60 - __builtin_clzll(x); + y += i*10; + x >>= i; +#else + while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ while( x>15 ){ y += 10; x >>= 1; } +#endif } return a[x&7] + y - 10; } @@ -26391,20 +29580,134 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){ } #endif /* SQLITE_OMIT_VIRTUALTABLE */ +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ + defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ + defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) /* ** Convert a LogEst into an integer. +** +** Note that this routine is only used when one or more of various +** non-standard compile-time options is enabled. */ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ u64 n; - if( x<10 ) return 1; n = x%10; x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; - if( x>=3 ){ - return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3); +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ + defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) + if( x>60 ) return (u64)LARGEST_INT64; +#else + /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input + ** possible to this routine is 310, resulting in a maximum x of 31 */ + assert( x<=60 ); +#endif + return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); +} +#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ + +/* +** Add a new name/number pair to a VList. This might require that the +** VList object be reallocated, so return the new VList. If an OOM +** error occurs, the original VList returned and the +** db->mallocFailed flag is set. +** +** A VList is really just an array of integers. To destroy a VList, +** simply pass it to sqlite3DbFree(). +** +** The first integer is the number of integers allocated for the whole +** VList. The second integer is the number of integers actually used. +** Each name/number pair is encoded by subsequent groups of 3 or more +** integers. +** +** Each name/number pair starts with two integers which are the numeric +** value for the pair and the size of the name/number pair, respectively. +** The text name overlays one or more following integers. The text name +** is always zero-terminated. +** +** Conceptually: +** +** struct VList { +** int nAlloc; // Number of allocated slots +** int nUsed; // Number of used slots +** struct VListEntry { +** int iValue; // Value for this entry +** int nSlot; // Slots used by this entry +** // ... variable name goes here +** } a[0]; +** } +** +** During code generation, pointers to the variable names within the +** VList are taken. When that happens, nAlloc is set to zero as an +** indication that the VList may never again be enlarged, since the +** accompanying realloc() would invalidate the pointers. +*/ +SQLITE_PRIVATE VList *sqlite3VListAdd( + sqlite3 *db, /* The database connection used for malloc() */ + VList *pIn, /* The input VList. Might be NULL */ + const char *zName, /* Name of symbol to add */ + int nName, /* Bytes of text in zName */ + int iVal /* Value to associate with zName */ +){ + int nInt; /* number of sizeof(int) objects needed for zName */ + char *z; /* Pointer to where zName will be stored */ + int i; /* Index in pIn[] where zName is stored */ + + nInt = nName/4 + 3; + 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; + VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); + if( pOut==0 ) return pIn; + if( pIn==0 ) pOut[1] = 2; + pIn = pOut; + pIn[0] = nAlloc; } - return (n+8)>>(3-x); + i = pIn[1]; + pIn[i] = iVal; + pIn[i+1] = nInt; + z = (char*)&pIn[i+2]; + pIn[1] = i+nInt; + assert( pIn[1]<=pIn[0] ); + memcpy(z, zName, nName); + z[nName] = 0; + return pIn; +} + +/* +** Return a pointer to the name of a variable in the given VList that +** has the value iVal. Or return a NULL if there is no such variable in +** the list +*/ +SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){ + int i, mx; + if( pIn==0 ) return 0; + mx = pIn[1]; + i = 2; + do{ + if( pIn[i]==iVal ) return (char*)&pIn[i+2]; + i += pIn[i+1]; + }while( iht ){ + if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; h = strHash(pKey) % pH->htsize; pEntry = &pH->ht[h]; @@ -26570,7 +29879,7 @@ static HashElem *findElementWithHash( elem = pH->first; count = pH->count; } - *pHash = h; + if( pHash ) *pHash = h; while( count-- ){ assert( elem!=0 ); if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ @@ -26578,7 +29887,7 @@ static HashElem *findElementWithHash( } elem = elem->next; } - return 0; + return &nullElement; } /* Remove a single entry from the hash table given a pointer to that @@ -26620,13 +29929,9 @@ static void removeElementGivenHash( ** found, or NULL if there is no match. */ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ - HashElem *elem; /* The element that matches key */ - unsigned int h; /* A hash on key */ - assert( pH!=0 ); assert( pKey!=0 ); - elem = findElementWithHash(pH, pKey, &h); - return elem ? elem->data : 0; + return findElementWithHash(pH, pKey, 0)->data; } /* Insert an element into the hash table pH. The key is pKey @@ -26651,7 +29956,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ assert( pH!=0 ); assert( pKey!=0 ); elem = findElementWithHash(pH,pKey,&h); - if( elem ){ + if( elem->data ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); @@ -26690,169 +29995,175 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ # define OpHelp(X) #endif SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ - static const char *const azName[] = { "?", - /* 1 */ "Savepoint" OpHelp(""), - /* 2 */ "AutoCommit" OpHelp(""), - /* 3 */ "Transaction" OpHelp(""), - /* 4 */ "SorterNext" OpHelp(""), - /* 5 */ "PrevIfOpen" OpHelp(""), - /* 6 */ "NextIfOpen" OpHelp(""), - /* 7 */ "Prev" OpHelp(""), - /* 8 */ "Next" OpHelp(""), - /* 9 */ "Checkpoint" OpHelp(""), - /* 10 */ "JournalMode" OpHelp(""), - /* 11 */ "Vacuum" OpHelp(""), - /* 12 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), - /* 13 */ "VUpdate" OpHelp("data=r[P3@P2]"), - /* 14 */ "Goto" OpHelp(""), - /* 15 */ "Gosub" OpHelp(""), - /* 16 */ "Return" OpHelp(""), - /* 17 */ "InitCoroutine" OpHelp(""), - /* 18 */ "EndCoroutine" OpHelp(""), + static const char *const azName[] = { + /* 0 */ "Savepoint" OpHelp(""), + /* 1 */ "AutoCommit" OpHelp(""), + /* 2 */ "Transaction" OpHelp(""), + /* 3 */ "SorterNext" OpHelp(""), + /* 4 */ "PrevIfOpen" OpHelp(""), + /* 5 */ "NextIfOpen" OpHelp(""), + /* 6 */ "Prev" OpHelp(""), + /* 7 */ "Next" OpHelp(""), + /* 8 */ "Checkpoint" OpHelp(""), + /* 9 */ "JournalMode" OpHelp(""), + /* 10 */ "Vacuum" OpHelp(""), + /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), + /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"), + /* 13 */ "Goto" OpHelp(""), + /* 14 */ "Gosub" OpHelp(""), + /* 15 */ "InitCoroutine" OpHelp(""), + /* 16 */ "Yield" OpHelp(""), + /* 17 */ "MustBeInt" OpHelp(""), + /* 18 */ "Jump" OpHelp(""), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), - /* 20 */ "Yield" OpHelp(""), - /* 21 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 22 */ "Halt" OpHelp(""), - /* 23 */ "Integer" OpHelp("r[P2]=P1"), - /* 24 */ "Int64" OpHelp("r[P2]=P4"), - /* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 26 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 27 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 28 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 29 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 30 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 31 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 32 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 33 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 34 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 35 */ "CollSeq" OpHelp(""), - /* 36 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 37 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), - /* 38 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 39 */ "MustBeInt" OpHelp(""), - /* 40 */ "RealAffinity" OpHelp(""), - /* 41 */ "Cast" OpHelp("affinity(r[P1])"), - /* 42 */ "Permutation" OpHelp(""), - /* 43 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 44 */ "Jump" OpHelp(""), - /* 45 */ "Once" OpHelp(""), - /* 46 */ "If" OpHelp(""), - /* 47 */ "IfNot" OpHelp(""), - /* 48 */ "Column" OpHelp("r[P3]=PX"), - /* 49 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 50 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 51 */ "Count" OpHelp("r[P2]=count()"), - /* 52 */ "ReadCookie" OpHelp(""), - /* 53 */ "SetCookie" OpHelp(""), - /* 54 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 55 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 56 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 57 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 58 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 59 */ "SorterOpen" OpHelp(""), - /* 60 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 61 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 62 */ "Close" OpHelp(""), - /* 63 */ "ColumnsUsed" OpHelp(""), - /* 64 */ "SeekLT" OpHelp("key=r[P3@P4]"), - /* 65 */ "SeekLE" OpHelp("key=r[P3@P4]"), - /* 66 */ "SeekGE" OpHelp("key=r[P3@P4]"), - /* 67 */ "SeekGT" OpHelp("key=r[P3@P4]"), - /* 68 */ "Seek" OpHelp("intkey=r[P2]"), - /* 69 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 70 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), - /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 73 */ "Found" OpHelp("key=r[P3@P4]"), - /* 74 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 75 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), - /* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), - /* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"), - /* 79 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"), - /* 80 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"), - /* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"), - /* 82 */ "Lt" OpHelp("if r[P1]=r[P3] goto P2"), - /* 84 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), - /* 89 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 90 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 91 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 95 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), + /* 20 */ "Once" OpHelp(""), + /* 21 */ "If" OpHelp(""), + /* 22 */ "IfNot" OpHelp(""), + /* 23 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), + /* 24 */ "SeekLT" OpHelp("key=r[P3@P4]"), + /* 25 */ "SeekLE" OpHelp("key=r[P3@P4]"), + /* 26 */ "SeekGE" OpHelp("key=r[P3@P4]"), + /* 27 */ "SeekGT" OpHelp("key=r[P3@P4]"), + /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 30 */ "Found" OpHelp("key=r[P3@P4]"), + /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"), + /* 32 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 33 */ "Last" OpHelp(""), + /* 34 */ "IfSmaller" OpHelp(""), + /* 35 */ "SorterSort" OpHelp(""), + /* 36 */ "Sort" OpHelp(""), + /* 37 */ "Rewind" OpHelp(""), + /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), + /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 46 */ "Program" OpHelp(""), + /* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), + /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), + /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), + /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"), + /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"), + /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"), + /* 56 */ "Lt" OpHelp("IF r[P3]=r[P1]"), + /* 58 */ "ElseNotEq" OpHelp(""), + /* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 60 */ "IncrVacuum" OpHelp(""), + /* 61 */ "VNext" OpHelp(""), + /* 62 */ "Init" OpHelp("Start at P2"), + /* 63 */ "Return" OpHelp(""), + /* 64 */ "EndCoroutine" OpHelp(""), + /* 65 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 66 */ "Halt" OpHelp(""), + /* 67 */ "Integer" OpHelp("r[P2]=P1"), + /* 68 */ "Int64" OpHelp("r[P2]=P4"), + /* 69 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 70 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 71 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 72 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 73 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 74 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 75 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 76 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 77 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 78 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 79 */ "CollSeq" OpHelp(""), + /* 80 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 81 */ "RealAffinity" OpHelp(""), + /* 82 */ "Cast" OpHelp("affinity(r[P1])"), + /* 83 */ "Permutation" OpHelp(""), + /* 84 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 85 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 86 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 88 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 89 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 90 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 91 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 92 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 93 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 94 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 95 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), + /* 96 */ "Column" OpHelp("r[P3]=PX"), /* 97 */ "String8" OpHelp("r[P2]='P4'"), - /* 98 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 99 */ "Delete" OpHelp(""), - /* 100 */ "ResetCount" OpHelp(""), - /* 101 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 102 */ "SorterData" OpHelp("r[P2]=data"), - /* 103 */ "RowKey" OpHelp("r[P2]=key"), - /* 104 */ "RowData" OpHelp("r[P2]=data"), - /* 105 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 106 */ "NullRow" OpHelp(""), - /* 107 */ "Last" OpHelp(""), - /* 108 */ "SorterSort" OpHelp(""), - /* 109 */ "Sort" OpHelp(""), - /* 110 */ "Rewind" OpHelp(""), - /* 111 */ "SorterInsert" OpHelp(""), - /* 112 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 113 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 114 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 115 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 116 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 117 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 118 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 119 */ "Destroy" OpHelp(""), - /* 120 */ "Clear" OpHelp(""), - /* 121 */ "ResetSorter" OpHelp(""), - /* 122 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), - /* 123 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), - /* 124 */ "ParseSchema" OpHelp(""), - /* 125 */ "LoadAnalysis" OpHelp(""), - /* 126 */ "DropTable" OpHelp(""), - /* 127 */ "DropIndex" OpHelp(""), - /* 128 */ "DropTrigger" OpHelp(""), - /* 129 */ "IntegrityCk" OpHelp(""), - /* 130 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 131 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 132 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 133 */ "Real" OpHelp("r[P2]=P4"), - /* 134 */ "Program" OpHelp(""), - /* 135 */ "Param" OpHelp(""), - /* 136 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 137 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 138 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 139 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 140 */ "SetIfNotPos" OpHelp("if r[P1]<=0 then r[P2]=P3"), - /* 141 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"), - /* 142 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 143 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"), - /* 144 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 145 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 146 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 147 */ "IncrVacuum" OpHelp(""), - /* 148 */ "Expire" OpHelp(""), - /* 149 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 150 */ "VBegin" OpHelp(""), - /* 151 */ "VCreate" OpHelp(""), - /* 152 */ "VDestroy" OpHelp(""), - /* 153 */ "VOpen" OpHelp(""), - /* 154 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 155 */ "VNext" OpHelp(""), - /* 156 */ "VRename" OpHelp(""), - /* 157 */ "Pagecount" OpHelp(""), - /* 158 */ "MaxPgcnt" OpHelp(""), - /* 159 */ "Init" OpHelp("Start at P2"), - /* 160 */ "CursorHint" OpHelp(""), - /* 161 */ "Noop" OpHelp(""), - /* 162 */ "Explain" OpHelp(""), + /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 100 */ "Count" OpHelp("r[P2]=count()"), + /* 101 */ "ReadCookie" OpHelp(""), + /* 102 */ "SetCookie" OpHelp(""), + /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 106 */ "OpenDup" OpHelp(""), + /* 107 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 108 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 109 */ "SorterOpen" OpHelp(""), + /* 110 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 111 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 112 */ "Close" OpHelp(""), + /* 113 */ "ColumnsUsed" OpHelp(""), + /* 114 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 115 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 116 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 117 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 118 */ "Delete" OpHelp(""), + /* 119 */ "ResetCount" OpHelp(""), + /* 120 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 121 */ "SorterData" OpHelp("r[P2]=data"), + /* 122 */ "RowData" OpHelp("r[P2]=data"), + /* 123 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 124 */ "NullRow" OpHelp(""), + /* 125 */ "SeekEnd" OpHelp(""), + /* 126 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 127 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 128 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 129 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 130 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 131 */ "Destroy" OpHelp(""), + /* 132 */ "Real" OpHelp("r[P2]=P4"), + /* 133 */ "Clear" OpHelp(""), + /* 134 */ "ResetSorter" OpHelp(""), + /* 135 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 136 */ "SqlExec" OpHelp(""), + /* 137 */ "ParseSchema" OpHelp(""), + /* 138 */ "LoadAnalysis" OpHelp(""), + /* 139 */ "DropTable" OpHelp(""), + /* 140 */ "DropIndex" OpHelp(""), + /* 141 */ "DropTrigger" OpHelp(""), + /* 142 */ "IntegrityCk" OpHelp(""), + /* 143 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 144 */ "Param" OpHelp(""), + /* 145 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 146 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 147 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 148 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 149 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 150 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 151 */ "Expire" OpHelp(""), + /* 152 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 153 */ "VBegin" OpHelp(""), + /* 154 */ "VCreate" OpHelp(""), + /* 155 */ "VDestroy" OpHelp(""), + /* 156 */ "VOpen" OpHelp(""), + /* 157 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 158 */ "VRename" OpHelp(""), + /* 159 */ "Pagecount" OpHelp(""), + /* 160 */ "MaxPgcnt" OpHelp(""), + /* 161 */ "PureFunc0" OpHelp(""), + /* 162 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 163 */ "PureFunc" OpHelp(""), + /* 164 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 165 */ "CursorHint" OpHelp(""), + /* 166 */ "Noop" OpHelp(""), + /* 167 */ "Explain" OpHelp(""), }; return azName[i]; } @@ -26933,12 +30244,26 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ # endif #endif +/* Use pread() and pwrite() if they are available */ +#if defined(__APPLE__) +# define HAVE_PREAD 1 +# define HAVE_PWRITE 1 +#endif +#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64) +# undef USE_PREAD +# define USE_PREAD64 1 +#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE) +# undef USE_PREAD64 +# define USE_PREAD 1 +#endif + /* ** standard include files. */ #include #include #include +#include #include /* #include */ #include @@ -26948,7 +30273,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #endif #if SQLITE_ENABLE_LOCKING_STYLE -# include +/* # include */ # include # include #endif /* SQLITE_ENABLE_LOCKING_STYLE */ @@ -27011,6 +30336,11 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ */ #define MAX_PATHNAME 512 +/* +** Maximum supported symbolic links +*/ +#define SQLITE_MAX_SYMLINKS 100 + /* Always cast the getpid() return type for compatibility with ** kernel modules in VxWorks. */ #define osGetpid(X) (pid_t)getpid() @@ -27053,7 +30383,7 @@ struct unixFile { unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ - UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ + UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ @@ -27064,10 +30394,8 @@ struct unixFile { sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ void *pMapRegion; /* Memory mapped region */ #endif -#ifdef __QNXNTO__ int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ -#endif #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif @@ -27163,8 +30491,8 @@ static pid_t randomnessPid = 0; */ #ifdef SQLITE_PERFORMANCE_TRACE -/* -** hwtime.h contains inline assembler code for implementing +/* +** hwtime.h contains inline assembler code for implementing ** high-performance timing routines. */ /************** Include hwtime.h in the middle of os_common.h ****************/ @@ -27184,8 +30512,8 @@ static pid_t randomnessPid = 0; ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. @@ -27253,7 +30581,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in os_common.h ******************/ @@ -27274,14 +30602,14 @@ static sqlite_uint64 g_elapsed; ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ -SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ -SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ -SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ -SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ -SQLITE_API int sqlite3_diskfull_pending = 0; -SQLITE_API int sqlite3_diskfull = 0; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) #define SimulateIOError(CODE) \ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ @@ -27307,17 +30635,17 @@ static void local_ioerr(){ #define SimulateIOErrorBenign(X) #define SimulateIOError(A) #define SimulateDiskfullError(A) -#endif +#endif /* defined(SQLITE_TEST) */ /* ** When testing, keep a count of the number of open files. */ -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_open_file_count = 0; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) sqlite3_open_file_count+=(X) #else #define OpenCounter(X) -#endif +#endif /* defined(SQLITE_TEST) */ #endif /* !defined(_OS_COMMON_H_) */ @@ -27370,6 +30698,20 @@ SQLITE_API int sqlite3_open_file_count = 0; # define lseek lseek64 #endif +#ifdef __linux__ +/* +** Linux-specific IOCTL magic numbers used for controlling F2FS +*/ +#define F2FS_IOCTL_MAGIC 0xf5 +#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32) +#define F2FS_FEATURE_ATOMIC_WRITE 0x0004 +#endif /* __linux__ */ + + /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). @@ -27447,7 +30789,7 @@ static struct unix_syscall { #else { "pread64", (sqlite3_syscall_ptr)0, 0 }, #endif -#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) +#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) { "write", (sqlite3_syscall_ptr)write, 0 }, #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) @@ -27465,7 +30807,7 @@ static struct unix_syscall { #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif -#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ +#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, @@ -27490,33 +30832,60 @@ static struct unix_syscall { { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) +#if defined(HAVE_FCHOWN) { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, +#else + { "fchown", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 - { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, + { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, +#else + { "mmap", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, +#else + { "munmap", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent) -#if HAVE_MREMAP +#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, #else { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent) +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, +#else + { "getpagesize", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent) +#if defined(HAVE_READLINK) { "readlink", (sqlite3_syscall_ptr)readlink, 0 }, +#else + { "readlink", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent) +#if defined(HAVE_LSTAT) + { "lstat", (sqlite3_syscall_ptr)lstat, 0 }, +#else + { "lstat", (sqlite3_syscall_ptr)0, 0 }, #endif +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) + + { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, +#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) }; /* End of the overrideable system calls */ @@ -27527,10 +30896,10 @@ static struct unix_syscall { ** we are not running as root. */ static int robustFchown(int fd, uid_t uid, gid_t gid){ -#if OS_VXWORKS - return 0; -#else +#if defined(HAVE_FCHOWN) return osGeteuid() ? 0 : osFchown(fd,uid,gid); +#else + return 0; #endif } @@ -28079,7 +31448,14 @@ struct unixFileId { #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID for vxworks. */ #else - ino_t ino; /* Inode number */ + /* We are told that some versions of Android contain a bug that + ** sizes ino_t at only 32-bits instead of 64-bits. (See + ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c) + ** To work around this, always allocate 64-bits for the inode number. + ** On small machines that only have 32-bit inodes, this wastes 4 bytes, + ** but that should not be a big deal. */ + /* WAS: ino_t ino; */ + u64 ino; /* Inode number */ #endif }; @@ -28115,7 +31491,8 @@ struct unixInodeInfo { /* ** A lists of all unixInodeInfo objects. */ -static unixInodeInfo *inodeList = 0; +static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ +static unsigned int nUnusedFd = 0; /* Total unused file descriptors */ /* ** @@ -28225,6 +31602,7 @@ static void closePendingFds(unixFile *pFile){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); sqlite3_free(p); + nUnusedFd--; } pInode->pUnused = 0; } @@ -28257,6 +31635,7 @@ static void releaseInodeInfo(unixFile *pFile){ sqlite3_free(pInode); } } + assert( inodeList!=0 || nUnusedFd==0 ); } /* @@ -28324,8 +31703,9 @@ static int findInodeInfo( #if OS_VXWORKS fileId.pId = pFile->pId; #else - fileId.ino = statbuf.st_ino; + fileId.ino = (u64)statbuf.st_ino; #endif + assert( inodeList!=0 || nUnusedFd==0 ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; @@ -28333,7 +31713,7 @@ static int findInodeInfo( if( pInode==0 ){ pInode = sqlite3_malloc64( sizeof(*pInode) ); if( pInode==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memset(pInode, 0, sizeof(*pInode)); memcpy(&pInode->fileId, &fileId, sizeof(fileId)); @@ -28358,7 +31738,8 @@ static int fileHasMoved(unixFile *pFile){ #else struct stat buf; return pFile->pInode!=0 && - (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino); + (osStat(pFile->zPath, &buf)!=0 + || (u64)buf.st_ino!=pFile->pInode->fileId.ino); #endif } @@ -28375,12 +31756,16 @@ static int fileHasMoved(unixFile *pFile){ static void verifyDbFile(unixFile *pFile){ struct stat buf; int rc; + + /* These verifications occurs for the main database only */ + if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return; + rc = osFstat(pFile->h, &buf); if( rc!=0 ){ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath); return; } - if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){ + if( buf.st_nlink==0 ){ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath); return; } @@ -28516,7 +31901,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid ** confusion with SQLite lock names). The algorithms are complicated - ** slightly in order to be compatible with windows systems simultaneously + ** slightly in order to be compatible with Windows95 systems simultaneously ** accessing the same database file, in case that is ever required. ** ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved @@ -28524,8 +31909,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** range', a range of 510 bytes at a well known offset. ** ** To obtain a SHARED lock, a read-lock is obtained on the 'pending - ** byte'. If this is successful, a random byte from the 'shared byte - ** range' is read-locked and the lock on the 'pending byte' released. + ** byte'. If this is successful, 'shared byte range' is read-locked + ** and the lock on the 'pending byte' released. (Legacy note: When + ** SQLite was first developed, Windows95 systems were still very common, + ** and Widnows95 lacks a shared-lock capability. So on Windows95, a + ** single randomly selected by from the 'shared byte range' is locked. + ** Windows95 is now pretty much extinct, but this work-around for the + ** lack of shared-locks on Windows95 lives on, for backwards + ** compatibility.) ** ** A process may only obtain a RESERVED lock after it has a SHARED lock. ** A RESERVED lock is implemented by grabbing a write-lock on the @@ -28544,11 +31935,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** range'. Since all other locks require a read-lock on one of the bytes ** within this range, this ensures that no other locks are held on the ** database. - ** - ** The reason a single byte cannot be used instead of the 'shared byte - ** range' is that some versions of windows do not support read-locks. By - ** locking a random byte from a range, concurrent SHARED locks may exist - ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -28739,11 +32125,12 @@ end_lock: */ static void setPendingFd(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; - UnixUnusedFd *p = pFile->pUnused; + UnixUnusedFd *p = pFile->pPreallocatedUnused; p->pNext = pInode->pUnused; pInode->pUnused = p; pFile->h = -1; - pFile->pUnused = 0; + pFile->pPreallocatedUnused = 0; + nUnusedFd++; } /* @@ -28968,7 +32355,7 @@ static int closeUnixFile(sqlite3_file *id){ #endif OSTRACE(("CLOSE %-3d\n", pFile->h)); OpenCounter(-1); - sqlite3_free(pFile->pUnused); + sqlite3_free(pFile->pPreallocatedUnused); memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } @@ -29305,7 +32692,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ + if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_OK; reserved=1; } @@ -29372,7 +32759,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) { OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ + if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_BUSY; } #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ @@ -29909,7 +33296,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ /* Can't reestablish the shared lock. Sqlite can't deal, this is ** a critical I/O error */ - rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : + rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 : SQLITE_IOERR_LOCK; goto afp_end_lock; } @@ -30189,7 +33576,7 @@ static int unixRead( /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 - assert( pFile->pUnused==0 + assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); @@ -30302,7 +33689,7 @@ static int unixWrite( /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 - assert( pFile->pUnused==0 + assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); @@ -30782,6 +34169,21 @@ static int unixGetTempname(int nBuf, char *zBuf); static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); + return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); + return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); + return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; + } +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; @@ -30832,6 +34234,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } + + /* The value of newLimit may be eventually cast to (size_t) and passed + ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a + ** 64-bit type. */ + if( newLimit>0 && sizeof(size_t)<8 ){ + newLimit = (newLimit & 0x7FFFFFFF); + } + *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; @@ -30865,30 +34275,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } /* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. +** If pFd->sectorSize is non-zero when this function is called, it is a +** no-op. Otherwise, the values of pFd->sectorSize and +** pFd->deviceCharacteristics are set according to the file-system +** characteristics. ** -** SQLite code assumes this function cannot fail. It also assumes that -** if two files are created in the same file-system directory (i.e. -** a database and its journal file) that the sector size will be the -** same for both. +** There are two versions of this function. One for QNX and one for all +** other systems. */ -#ifndef __QNXNTO__ -static int unixSectorSize(sqlite3_file *NotUsed){ - UNUSED_PARAMETER(NotUsed); - return SQLITE_DEFAULT_SECTOR_SIZE; -} -#endif +#ifndef __QNXNTO__ +static void setDeviceCharacteristics(unixFile *pFd){ + assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 ); + if( pFd->sectorSize==0 ){ +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + int res; + u32 f = 0; -/* -** The following version of unixSectorSize() is optimized for QNX. -*/ -#ifdef __QNXNTO__ + /* Check for support for F2FS atomic batch writes. */ + res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f); + if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){ + pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC; + } +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + + /* Set the POWERSAFE_OVERWRITE flag if requested. */ + if( pFd->ctrlFlags & UNIXFILE_PSOW ){ + pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; + } + + pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; + } +} +#else #include #include -static int unixSectorSize(sqlite3_file *id){ - unixFile *pFile = (unixFile*)id; +static void setDeviceCharacteristics(unixFile *pFile){ if( pFile->sectorSize == 0 ){ struct statvfs fsInfo; @@ -30957,9 +34378,24 @@ static int unixSectorSize(sqlite3_file *id){ pFile->deviceCharacteristics = 0; pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } - return pFile->sectorSize; } -#endif /* __QNXNTO__ */ +#endif + +/* +** Return the sector size in bytes of the underlying block device for +** the specified file. This is almost always 512 bytes, but may be +** larger for some devices. +** +** SQLite code assumes this function cannot fail. It also assumes that +** if two files are created in the same file-system directory (i.e. +** a database and its journal file) that the sector size will be the +** same for both. +*/ +static int unixSectorSize(sqlite3_file *id){ + unixFile *pFd = (unixFile*)id; + setDeviceCharacteristics(pFd); + return pFd->sectorSize; +} /* ** Return the device characteristics for the file. @@ -30975,16 +34411,9 @@ static int unixSectorSize(sqlite3_file *id){ ** available to turn it off and URI query parameter available to turn it off. */ static int unixDeviceCharacteristics(sqlite3_file *id){ - unixFile *p = (unixFile*)id; - int rc = 0; -#ifdef __QNXNTO__ - if( p->sectorSize==0 ) unixSectorSize(id); - rc = p->deviceCharacteristics; -#endif - if( p->ctrlFlags & UNIXFILE_PSOW ){ - rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; - } - return rc; + unixFile *pFd = (unixFile*)id; + setDeviceCharacteristics(pFd); + return pFd->deviceCharacteristics; } #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 @@ -31253,7 +34682,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ /* Allocate space for the new unixShm object. */ p = sqlite3_malloc64( sizeof(*p) ); - if( p==0 ) return SQLITE_NOMEM; + if( p==0 ) return SQLITE_NOMEM_BKPT; memset(p, 0, sizeof(*p)); assert( pDbFd->pShm==0 ); @@ -31285,7 +34714,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ #endif pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename ); if( pShmNode==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); @@ -31301,10 +34730,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ pShmNode->h = -1; pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ - rc = SQLITE_NOMEM; - goto shm_open_err; + if( sqlite3GlobalConfig.bCoreMutex ){ + pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->mutex==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto shm_open_err; + } } if( pInode->bProcessLock==0 ){ @@ -31476,7 +34907,7 @@ static int unixShmMap( pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ - rc = SQLITE_IOERR_NOMEM; + rc = SQLITE_IOERR_NOMEM_BKPT; goto shmpage_out; } pShmNode->apRegion = apNew; @@ -31496,7 +34927,7 @@ static int unixShmMap( }else{ pMem = sqlite3_malloc64(szRegion); if( pMem==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto shmpage_out; } memset(pMem, 0, szRegion); @@ -32240,17 +35671,6 @@ static int fillInUnixFile( assert( pNew->pInode==NULL ); - /* Usually the path zFilename should not be a relative pathname. The - ** exception is when opening the proxy "conch" file in builds that - ** include the special Apple locking styles. - */ -#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE - assert( zFilename==0 || zFilename[0]=='/' - || pVfs->pAppData==(void*)&autolockIoFinder ); -#else - assert( zFilename==0 || zFilename[0]=='/' ); -#endif - /* No locking occurs in temporary files */ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); @@ -32274,7 +35694,7 @@ static int fillInUnixFile( pNew->pId = vxworksFindFileId(zFilename); if( pNew->pId==0 ){ ctrlFlags |= UNIXFILE_NOLOCK; - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } #endif @@ -32330,7 +35750,7 @@ static int fillInUnixFile( afpLockingContext *pCtx; pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) ); if( pCtx==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ /* NB: zFilename exists and remains valid until the file is closed ** according to requirement F11141. So we do not need to make a @@ -32360,7 +35780,7 @@ static int fillInUnixFile( nFilename = (int)strlen(zFilename) + 6; zLockFile = (char *)sqlite3_malloc64(nFilename); if( zLockFile==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename); } @@ -32383,7 +35803,7 @@ static int fillInUnixFile( if( zSemName[n]=='/' ) zSemName[n] = '_'; pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1); if( pNew->pInode->pSem == SEM_FAILED ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; pNew->pInode->aSemName[0] = '\0'; } } @@ -32423,20 +35843,24 @@ static const char *unixTempFileDir(void){ "/tmp", "." }; - unsigned int i; + unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); - for(i=0; i=sizeof(azDirs)/sizeof(azDirs[0]) ) break; + zDir = azDirs[i++]; } - return zDir; + return 0; } /* @@ -32452,9 +35876,11 @@ static int unixGetTempname(int nBuf, char *zBuf){ ** using the io-error infrastructure to test that SQLite handles this ** function failing. */ + zBuf[0] = 0; SimulateIOError( return SQLITE_IOERR ); zDir = unixTempFileDir(); + if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH; do{ u64 r; sqlite3_randomness(sizeof(r), &r); @@ -32503,6 +35929,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ #if !OS_VXWORKS struct stat sStat; /* Results of stat() call */ + unixEnterMutex(); + /* A stat() call may fail for various reasons. If this happens, it is ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is @@ -32511,13 +35939,12 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ - if( 0==osStat(zPath, &sStat) ){ + if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; - unixEnterMutex(); pInode = inodeList; while( pInode && (pInode->fileId.dev!=sStat.st_dev - || pInode->fileId.ino!=sStat.st_ino) ){ + || pInode->fileId.ino!=(u64)sStat.st_ino) ){ pInode = pInode->pNext; } if( pInode ){ @@ -32525,15 +35952,37 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ + nUnusedFd--; *pp = pUnused->pNext; } } - unixLeaveMutex(); } + unixLeaveMutex(); #endif /* if !OS_VXWORKS */ return pUnused; } +/* +** Find the mode, uid and gid of file zFile. +*/ +static int getFileMode( + const char *zFile, /* File name */ + mode_t *pMode, /* OUT: Permissions of zFile */ + uid_t *pUid, /* OUT: uid of zFile. */ + gid_t *pGid /* OUT: gid of zFile. */ +){ + struct stat sStat; /* Output of stat() on database file */ + int rc = SQLITE_OK; + if( 0==osStat(zFile, &sStat) ){ + *pMode = sStat.st_mode & 0777; + *pUid = sStat.st_uid; + *pGid = sStat.st_gid; + }else{ + rc = SQLITE_IOERR_FSTAT; + } + return rc; +} + /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned @@ -32569,7 +36018,6 @@ static int findCreateFileMode( if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ - struct stat sStat; /* Output of stat() on database file */ /* zPath is a path to a WAL or journal file. The following block derives ** the path to the associated database file from zPath. This block handles @@ -32585,30 +36033,28 @@ static int findCreateFileMode( */ nDb = sqlite3Strlen30(zPath) - 1; while( zPath[nDb]!='-' ){ -#ifndef SQLITE_ENABLE_8_3_NAMES - /* In the normal case (8+3 filenames disabled) the journal filename - ** is guaranteed to contain a '-' character. */ - assert( nDb>0 ); - assert( sqlite3Isalnum(zPath[nDb]) ); -#else - /* If 8+3 names are possible, then the journal file might not contain - ** a '-' character. So check for that case and return early. */ + /* In normal operation, the journal file name will always contain + ** a '-' character. However in 8+3 filename mode, or if a corrupt + ** rollback journal specifies a master journal with a goofy name, then + ** the '-' might be missing. */ if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; -#endif nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; - if( 0==osStat(zDb, &sStat) ){ - *pMode = sStat.st_mode & 0777; - *pUid = sStat.st_uid; - *pGid = sStat.st_gid; - }else{ - rc = SQLITE_IOERR_FSTAT; - } + rc = getFileMode(zDb, pMode, pUid, pGid); }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; + }else if( flags & SQLITE_OPEN_URI ){ + /* If this is a main database file and the file was opened using a URI + ** filename, check for the "modeof" parameter. If present, interpret + ** its value as a filename and try to copy the mode, uid and gid from + ** that file. */ + const char *z = sqlite3_uri_parameter(zPath, "modeof"); + if( z ){ + rc = getFileMode(z, pMode, pUid, pGid); + } } return rc; } @@ -32724,10 +36170,10 @@ static int unixOpen( }else{ pUnused = sqlite3_malloc64(sizeof(*pUnused)); if( !pUnused ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } } - p->pUnused = pUnused; + p->pPreallocatedUnused = pUnused; /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into @@ -32764,7 +36210,7 @@ static int unixOpen( gid_t gid; /* Groupid for the file */ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); if( rc!=SQLITE_OK ){ - assert( !p->pUnused ); + assert( !p->pPreallocatedUnused ); assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); return rc; } @@ -32798,9 +36244,9 @@ static int unixOpen( *pOutFlags = flags; } - if( p->pUnused ){ - p->pUnused->fd = fd; - p->pUnused->flags = flags; + if( p->pPreallocatedUnused ){ + p->pPreallocatedUnused->fd = fd; + p->pPreallocatedUnused->flags = flags; } if( isDelete ){ @@ -32810,7 +36256,7 @@ static int unixOpen( zPath = sqlite3_mprintf("%s", zName); if( zPath==0 ){ robust_close(p, fd, __LINE__); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } #else osUnlink(zName); @@ -32821,9 +36267,6 @@ static int unixOpen( p->openFlags = openFlags; } #endif - - noLock = eType!=SQLITE_OPEN_MAIN_DB; - #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE if( fstatfs(fd, &fsInfo) == -1 ){ @@ -32842,6 +36285,7 @@ static int unixOpen( /* Set up appropriate ctrlFlags */ if( isDelete ) ctrlFlags |= UNIXFILE_DELETE; if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; + noLock = eType!=SQLITE_OPEN_MAIN_DB; if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK; if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC; if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI; @@ -32879,11 +36323,14 @@ static int unixOpen( } #endif + assert( zPath==0 || zPath[0]=='/' + || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL + ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ - sqlite3_free(p->pUnused); + sqlite3_free(p->pPreallocatedUnused); } return rc; } @@ -32918,12 +36365,7 @@ static int unixDelete( int fd; rc = osOpenDirectory(zPath, &fd); if( rc==SQLITE_OK ){ -#if OS_VXWORKS - if( fsync(fd)==-1 ) -#else - if( fsync(fd) ) -#endif - { + if( full_fsync(fd,0,0) ){ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } robust_close(0, fd, __LINE__); @@ -32969,6 +36411,32 @@ static int unixAccess( return SQLITE_OK; } +/* +** +*/ +static int mkFullPathname( + const char *zPath, /* Input path */ + char *zOut, /* Output buffer */ + int nOut /* Allocated size of buffer zOut */ +){ + int nPath = sqlite3Strlen30(zPath); + int iOff = 0; + if( zPath[0]!='/' ){ + if( osGetcwd(zOut, nOut-2)==0 ){ + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); + } + iOff = sqlite3Strlen30(zOut); + zOut[iOff++] = '/'; + } + if( (iOff+nPath+1)>nOut ){ + /* SQLite assumes that xFullPathname() nul-terminates the output buffer + ** even if it returns an error. */ + zOut[iOff] = '\0'; + return SQLITE_CANTOPEN_BKPT; + } + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + return SQLITE_OK; +} /* ** Turn a relative pathname into a full pathname. The relative path @@ -32985,7 +36453,17 @@ static int unixFullPathname( int nOut, /* Size of output buffer in bytes */ char *zOut /* Output buffer */ ){ +#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) + return mkFullPathname(zPath, zOut, nOut); +#else + int rc = SQLITE_OK; int nByte; + int nLink = 1; /* Number of symbolic links followed so far */ + const char *zIn = zPath; /* Input path for each iteration of loop */ + char *zDel = 0; + + assert( pVfs->mxPathname==MAX_PATHNAME ); + UNUSED_PARAMETER(pVfs); /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this @@ -32994,58 +36472,62 @@ static int unixFullPathname( */ SimulateIOError( return SQLITE_ERROR ); - assert( pVfs->mxPathname==MAX_PATHNAME ); - UNUSED_PARAMETER(pVfs); + do { - /* Attempt to resolve the path as if it were a symbolic link. If it is - ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if - ** the identified file is not a symbolic link or does not exist, then - ** zPath is copied directly into zOut. Either way, nByte is left set to - ** the size of the string copied into zOut[] in bytes. */ - nByte = osReadlink(zPath, zOut, nOut-1); - if( nByte<0 ){ - if( errno!=EINVAL && errno!=ENOENT ){ - return unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zPath); + /* Call stat() on path zIn. Set bLink to true if the path is a symbolic + ** link, or false otherwise. */ + int bLink = 0; + struct stat buf; + if( osLstat(zIn, &buf)!=0 ){ + if( errno!=ENOENT ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); + } + }else{ + bLink = S_ISLNK(buf.st_mode); } - sqlite3_snprintf(nOut, zOut, "%s", zPath); - nByte = sqlite3Strlen30(zOut); - }else{ - zOut[nByte] = '\0'; - } - /* If buffer zOut[] now contains an absolute path there is nothing more - ** to do. If it contains a relative path, do the following: - ** - ** * move the relative path string so that it is at the end of th - ** zOut[] buffer. - ** * Call getcwd() to read the path of the current working directory - ** into the start of the zOut[] buffer. - ** * Append a '/' character to the cwd string and move the - ** relative path back within the buffer so that it immediately - ** follows the '/'. - ** - ** This code is written so that if the combination of the CWD and relative - ** path are larger than the allocated size of zOut[] the CWD is silently - ** truncated to make it fit. This is Ok, as SQLite refuses to open any - ** file for which this function returns a full path larger than (nOut-8) - ** bytes in size. */ - testcase( nByte==nOut-5 ); - testcase( nByte==nOut-4 ); - if( zOut[0]!='/' && nByteSQLITE_MAX_SYMLINKS ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + if( rc==SQLITE_OK ){ + nByte = osReadlink(zIn, zDel, nOut-1); + if( nByte<0 ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); + }else{ + if( zDel[0]!='/' ){ + int n; + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); + if( nByte+n+1>nOut ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + memmove(&zDel[n], zDel, nByte+1); + memcpy(zDel, zIn, n); + nByte += n; + } + } + zDel[nByte] = '\0'; + } + } + + zIn = zDel; } - nCwd = sqlite3Strlen30(zOut); - assert( nCwd<=nRem-1 ); - zOut[nCwd] = '/'; - memmove(&zOut[nCwd+1], &zOut[nRem], nByte+1); - } - return SQLITE_OK; + assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); + if( rc==SQLITE_OK && zIn!=zOut ){ + rc = mkFullPathname(zIn, zOut, nOut); + } + if( bLink==0 ) break; + zIn = zOut; + }while( rc==SQLITE_OK ); + + sqlite3_free(zDel); + return rc; +#endif /* HAVE_READLINK && HAVE_LSTAT */ } @@ -33227,7 +36709,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ return rc; } -#if 0 /* Not used */ +#ifndef SQLITE_OMIT_DEPRECATED /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and @@ -33245,23 +36727,18 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ # define unixCurrentTime 0 #endif -#if 0 /* Not used */ /* -** We added the xGetLastError() method with the intention of providing -** better low-level error messages when operating-system problems come up -** during SQLite operation. But so far, none of that has been implemented -** in the core. So this routine is never called. For now, it is merely -** a place-holder. +** The xGetLastError() method is designed to return a better +** low-level error message when operating-system problems come up +** during SQLite operation. Only the integer return code is currently +** used. */ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ UNUSED_PARAMETER(NotUsed); UNUSED_PARAMETER(NotUsed2); UNUSED_PARAMETER(NotUsed3); - return 0; + return errno; } -#else -# define unixGetLastError 0 -#endif /* @@ -33551,7 +37028,7 @@ static int proxyCreateUnixFile( }else{ pUnused = sqlite3_malloc64(sizeof(*pUnused)); if( !pUnused ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } } if( fd<0 ){ @@ -33584,7 +37061,7 @@ static int proxyCreateUnixFile( pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew)); if( pNew==NULL ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto end_create_proxy; } memset(pNew, 0, sizeof(unixFile)); @@ -33594,7 +37071,7 @@ static int proxyCreateUnixFile( dummyVfs.zName = "dummy"; pUnused->fd = fd; pUnused->flags = openFlags; - pNew->pUnused = pUnused; + pNew->pPreallocatedUnused = pUnused; rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); if( rc==SQLITE_OK ){ @@ -33927,7 +37404,7 @@ static int proxyTakeConch(unixFile *pFile){ writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]); robust_ftruncate(conchFile->h, writeSize); rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0); - fsync(conchFile->h); + full_fsync(conchFile->h,0,0); /* If we created a new conch file (not just updated the contents of a ** valid conch file), try to match the permissions of the database */ @@ -33997,7 +37474,7 @@ static int proxyTakeConch(unixFile *pFile){ if( tempLockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath); if( !pCtx->lockProxyPath ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } } } @@ -34062,7 +37539,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ ** the name of the original database file. */ *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8); if( conchPath==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memcpy(conchPath, dbPath, len+1); @@ -34178,7 +37655,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { pCtx = sqlite3_malloc64( sizeof(*pCtx) ); if( pCtx==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memset(pCtx, 0, sizeof(*pCtx)); @@ -34214,7 +37691,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { if( rc==SQLITE_OK ){ pCtx->dbPath = sqlite3DbStrDup(0, dbPath); if( pCtx->dbPath==NULL ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } } if( rc==SQLITE_OK ){ @@ -34461,7 +37938,7 @@ static int proxyClose(sqlite3_file *id) { ** necessarily been initialized when this routine is called, and so they ** should not be used. */ -SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ +SQLITE_API int sqlite3_os_init(void){ /* ** The following macro defines an initializer for an sqlite3_vfs object. ** The name of the VFS is NAME. The pAppData is a pointer to a pointer @@ -34544,7 +38021,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==27 ); + assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ @@ -34560,7 +38037,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ ** to release dynamically allocated objects. But not on unix. ** This routine is a no-op for unix. */ -SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ +SQLITE_API int sqlite3_os_end(void){ return SQLITE_OK; } @@ -34627,8 +38104,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ */ #ifdef SQLITE_PERFORMANCE_TRACE -/* -** hwtime.h contains inline assembler code for implementing +/* +** hwtime.h contains inline assembler code for implementing ** high-performance timing routines. */ /************** Include hwtime.h in the middle of os_common.h ****************/ @@ -34648,8 +38125,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. @@ -34717,7 +38194,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in os_common.h ******************/ @@ -34738,14 +38215,14 @@ static sqlite_uint64 g_elapsed; ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ -SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ -SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ -SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ -SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ -SQLITE_API int sqlite3_diskfull_pending = 0; -SQLITE_API int sqlite3_diskfull = 0; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; #define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) #define SimulateIOError(CODE) \ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ @@ -34771,17 +38248,17 @@ static void local_ioerr(){ #define SimulateIOErrorBenign(X) #define SimulateIOError(A) #define SimulateDiskfullError(A) -#endif +#endif /* defined(SQLITE_TEST) */ /* ** When testing, keep a count of the number of open files. */ -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_open_file_count = 0; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) sqlite3_open_file_count+=(X) #else #define OpenCounter(X) -#endif +#endif /* defined(SQLITE_TEST) */ #endif /* !defined(_OS_COMMON_H_) */ @@ -34844,6 +38321,10 @@ SQLITE_API int sqlite3_open_file_count = 0; # define NTDDI_WINBLUE 0x06030000 #endif +#ifndef NTDDI_WINTHRESHOLD +# define NTDDI_WINTHRESHOLD 0x06040000 +#endif + /* ** Check to see if the GetVersionEx[AW] functions are deprecated on the ** target system. GetVersionEx was first deprecated in Win8.1. @@ -34856,6 +38337,19 @@ SQLITE_API int sqlite3_open_file_count = 0; # endif #endif +/* +** Check to see if the CreateFileMappingA function is supported on the +** target system. It is unavailable when using "mincore.lib" on Win10. +** When compiling for Windows 10, always assume "mincore.lib" is in use. +*/ +#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA +# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD +# define SQLITE_WIN32_CREATEFILEMAPPINGA 0 +# else +# define SQLITE_WIN32_CREATEFILEMAPPINGA 1 +# endif +#endif + /* ** This constant should already be defined (in the "WinDef.h" SDK file). */ @@ -35041,6 +38535,17 @@ struct winFile { #endif }; +/* +** The winVfsAppData structure is used for the pAppData member for all of the +** Win32 VFS variants. +*/ +typedef struct winVfsAppData winVfsAppData; +struct winVfsAppData { + const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */ + void *pAppData; /* The extra pAppData, if any. */ + BOOL bNoLock; /* Non-zero if locking is disabled. */ +}; + /* ** Allowed values for winFile.ctrlFlags */ @@ -35092,22 +38597,72 @@ struct winFile { ****************************************************************************** */ #ifndef SQLITE_WIN32_HEAP_CREATE -# define SQLITE_WIN32_HEAP_CREATE (TRUE) +# define SQLITE_WIN32_HEAP_CREATE (TRUE) +#endif + +/* + * This is the maximum possible initial size of the Win32-specific heap, in + * bytes. + */ +#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE +# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U) +#endif + +/* + * This is the extra space for the initial size of the Win32-specific heap, + * in bytes. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA +# define SQLITE_WIN32_HEAP_INIT_EXTRA (4194304) +#endif + +/* + * Calculate the maximum legal cache size, in pages, based on the maximum + * possible initial heap size and the default page size, setting aside the + * needed extra space. + */ +#ifndef SQLITE_WIN32_MAX_CACHE_SIZE +# define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \ + (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \ + (SQLITE_DEFAULT_PAGE_SIZE)) +#endif + +/* + * This is cache size used in the calculation of the initial size of the + * Win32-specific heap. It cannot be negative. + */ +#ifndef SQLITE_WIN32_CACHE_SIZE +# if SQLITE_DEFAULT_CACHE_SIZE>=0 +# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE) +# else +# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE)) +# endif +#endif + +/* + * Make sure that the calculated cache size, in pages, cannot cause the + * initial size of the Win32-specific heap to exceed the maximum amount + * of memory that can be specified in the call to HeapCreate. + */ +#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE +# undef SQLITE_WIN32_CACHE_SIZE +# define SQLITE_WIN32_CACHE_SIZE (2000) #endif /* * The initial size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_INIT_SIZE -# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \ - (SQLITE_DEFAULT_PAGE_SIZE) + 4194304) +# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \ + (SQLITE_DEFAULT_PAGE_SIZE) + \ + (SQLITE_WIN32_HEAP_INIT_EXTRA)) #endif /* * The maximum size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_MAX_SIZE -# define SQLITE_WIN32_HEAP_MAX_SIZE (0) +# define SQLITE_WIN32_HEAP_MAX_SIZE (0) #endif /* @@ -35115,7 +38670,7 @@ struct winFile { * zero for the default behavior. */ #ifndef SQLITE_WIN32_HEAP_FLAGS -# define SQLITE_WIN32_HEAP_FLAGS (0) +# define SQLITE_WIN32_HEAP_FLAGS (0) #endif @@ -35262,8 +38817,9 @@ static struct win_syscall { #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) -#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ + SQLITE_WIN32_CREATEFILEMAPPINGA { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, #else { "CreateFileMappingA", (SYSCALL)0, 0 }, @@ -35493,8 +39049,7 @@ static struct win_syscall { #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) -#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \ - SQLITE_WIN32_GETVERSIONEX +#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX { "GetVersionExA", (SYSCALL)GetVersionExA, 0 }, #else { "GetVersionExA", (SYSCALL)0, 0 }, @@ -35504,7 +39059,7 @@ static struct win_syscall { LPOSVERSIONINFOA))aSyscall[34].pCurrent) #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX + SQLITE_WIN32_GETVERSIONEX { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, #else { "GetVersionExW", (SYSCALL)0, 0 }, @@ -35955,7 +39510,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){ ** "pnLargest" argument, if non-zero, will be used to return the size of the ** largest committed free block in the heap, in bytes. */ -SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){ +SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ int rc = SQLITE_OK; UINT nLargest = 0; HANDLE hHeap; @@ -35973,7 +39528,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){ if( lastErrno==NO_ERROR ){ sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p", (void*)hHeap); - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p", osGetLastError(), (void*)hHeap); @@ -35995,12 +39550,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){ ** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will ** be returned and no changes will be made to the Win32 native heap. */ -SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){ +SQLITE_API int sqlite3_win32_reset_heap(){ int rc; MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ - MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); ) - MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); ) + MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) + MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) sqlite3_mutex_enter(pMaster); sqlite3_mutex_enter(pMem); winMemAssertMagic(); @@ -36040,11 +39595,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){ ** (if available). */ -SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){ +SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE]; int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */ if( nMin<-1 ) nMin = -1; /* all negative values become -1. */ assert( nMin==-1 || nMin==0 || nMin0 ){ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); @@ -36080,7 +39641,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int n static HANDLE sleepObj = NULL; #endif -SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){ +SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ #if SQLITE_OS_WINRT if ( sleepObj==NULL ){ sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, @@ -36115,7 +39676,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ ** the LockFileEx() API. */ -#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX +#if !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) #elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) @@ -36129,14 +39690,14 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ ** This function determines if the machine is running a version of Windows ** based on the NT kernel. */ -SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){ +SQLITE_API int sqlite3_win32_is_nt(void){ #if SQLITE_OS_WINRT /* ** NOTE: The WinRT sub-platform is always assumed to be based on the NT ** kernel. */ return 1; -#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX +#elif SQLITE_WIN32_GETVERSIONEX if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ #if defined(SQLITE_WIN32_HAS_ANSI) OSVERSIONINFOA sInfo; @@ -36293,7 +39854,7 @@ static int winMemInit(void *pAppData){ "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu", osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize, dwMaximumSize); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pWinMemData->bOwned = TRUE; assert( pWinMemData->bOwned ); @@ -36303,7 +39864,7 @@ static int winMemInit(void *pAppData){ if( !pWinMemData->hHeap ){ sqlite3_log(SQLITE_NOMEM, "failed to GetProcessHeap (%lu)", osGetLastError()); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pWinMemData->bOwned = FALSE; assert( !pWinMemData->bOwned ); @@ -36370,147 +39931,244 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ #endif /* SQLITE_WIN32_MALLOC */ /* -** Convert a UTF-8 string to Microsoft Unicode (UTF-16?). +** Convert a UTF-8 string to Microsoft Unicode. ** -** Space to hold the returned string is obtained from malloc. +** Space to hold the returned string is obtained from sqlite3_malloc(). */ -static LPWSTR winUtf8ToUnicode(const char *zFilename){ +static LPWSTR winUtf8ToUnicode(const char *zText){ int nChar; - LPWSTR zWideFilename; + LPWSTR zWideText; - nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); + nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0); if( nChar==0 ){ return 0; } - zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) ); - if( zWideFilename==0 ){ + zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) ); + if( zWideText==0 ){ return 0; } - nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, + nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, nChar); if( nChar==0 ){ - sqlite3_free(zWideFilename); - zWideFilename = 0; + sqlite3_free(zWideText); + zWideText = 0; } - return zWideFilename; + return zWideText; } /* -** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is -** obtained from sqlite3_malloc(). +** Convert a Microsoft Unicode string to UTF-8. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). */ -static char *winUnicodeToUtf8(LPCWSTR zWideFilename){ +static char *winUnicodeToUtf8(LPCWSTR zWideText){ int nByte; - char *zFilename; + char *zText; - nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); + nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0); if( nByte == 0 ){ return 0; } - zFilename = sqlite3MallocZero( nByte ); - if( zFilename==0 ){ + zText = sqlite3MallocZero( nByte ); + if( zText==0 ){ return 0; } - nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, + nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, 0, 0); if( nByte == 0 ){ - sqlite3_free(zFilename); - zFilename = 0; + sqlite3_free(zText); + zText = 0; } - return zFilename; + return zText; } /* -** Convert an ANSI string to Microsoft Unicode, based on the -** current codepage settings for file apis. +** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM +** code page. ** -** Space to hold the returned string is obtained -** from sqlite3_malloc. +** Space to hold the returned string is obtained from sqlite3_malloc(). */ -static LPWSTR winMbcsToUnicode(const char *zFilename){ +static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ int nByte; - LPWSTR zMbcsFilename; - int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP; + LPWSTR zMbcsText; + int codepage = useAnsi ? CP_ACP : CP_OEMCP; - nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL, + nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, 0)*sizeof(WCHAR); if( nByte==0 ){ return 0; } - zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) ); - if( zMbcsFilename==0 ){ + zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); + if( zMbcsText==0 ){ return 0; } - nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, + nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, nByte); if( nByte==0 ){ - sqlite3_free(zMbcsFilename); - zMbcsFilename = 0; + sqlite3_free(zMbcsText); + zMbcsText = 0; } - return zMbcsFilename; + return zMbcsText; } /* -** Convert Microsoft Unicode to multi-byte character string, based on the -** user's ANSI codepage. +** Convert a Microsoft Unicode string to a multi-byte character string, +** using the ANSI or OEM code page. ** -** Space to hold the returned string is obtained from -** sqlite3_malloc(). +** Space to hold the returned string is obtained from sqlite3_malloc(). */ -static char *winUnicodeToMbcs(LPCWSTR zWideFilename){ +static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ int nByte; - char *zFilename; - int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP; + char *zText; + int codepage = useAnsi ? CP_ACP : CP_OEMCP; - nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0); + nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0); if( nByte == 0 ){ return 0; } - zFilename = sqlite3MallocZero( nByte ); - if( zFilename==0 ){ + zText = sqlite3MallocZero( nByte ); + if( zText==0 ){ return 0; } - nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, + nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText, nByte, 0, 0); if( nByte == 0 ){ - sqlite3_free(zFilename); - zFilename = 0; + sqlite3_free(zText); + zText = 0; } - return zFilename; + return zText; } /* -** Convert multibyte character string to UTF-8. Space to hold the -** returned string is obtained from sqlite3_malloc(). +** Convert a multi-byte character string to UTF-8. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). */ -SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){ - char *zFilenameUtf8; +static char *winMbcsToUtf8(const char *zText, int useAnsi){ + char *zTextUtf8; LPWSTR zTmpWide; - zTmpWide = winMbcsToUnicode(zFilename); + zTmpWide = winMbcsToUnicode(zText, useAnsi); if( zTmpWide==0 ){ return 0; } - zFilenameUtf8 = winUnicodeToUtf8(zTmpWide); + zTextUtf8 = winUnicodeToUtf8(zTmpWide); sqlite3_free(zTmpWide); - return zFilenameUtf8; + return zTextUtf8; } /* -** Convert UTF-8 to multibyte character string. Space to hold the -** returned string is obtained from sqlite3_malloc(). +** Convert a UTF-8 string to a multi-byte character string. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). */ -SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){ - char *zFilenameMbcs; +static char *winUtf8ToMbcs(const char *zText, int useAnsi){ + char *zTextMbcs; LPWSTR zTmpWide; - zTmpWide = winUtf8ToUnicode(zFilename); + zTmpWide = winUtf8ToUnicode(zText); if( zTmpWide==0 ){ return 0; } - zFilenameMbcs = winUnicodeToMbcs(zTmpWide); + zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi); sqlite3_free(zTmpWide); - return zFilenameMbcs; + return zTextMbcs; +} + +/* +** This is a public wrapper for the winUtf8ToUnicode() function. +*/ +SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUtf8ToUnicode(zText); +} + +/* +** This is a public wrapper for the winUnicodeToUtf8() function. +*/ +SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zWideText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUnicodeToUtf8(zWideText); +} + +/* +** This is a public wrapper for the winMbcsToUtf8() function. +*/ +SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winMbcsToUtf8(zText, osAreFileApisANSI()); +} + +/* +** This is a public wrapper for the winMbcsToUtf8() function. +*/ +SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winMbcsToUtf8(zText, useAnsi); +} + +/* +** This is a public wrapper for the winUtf8ToMbcs() function. +*/ +SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUtf8ToMbcs(zText, osAreFileApisANSI()); +} + +/* +** This is a public wrapper for the winUtf8ToMbcs() function. +*/ +SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUtf8ToMbcs(zText, useAnsi); } /* @@ -36520,7 +40178,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename ** argument is the name of the directory to use. The return value will be ** SQLITE_OK if successful. */ -SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ +SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ char **ppDirectory = 0; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); @@ -36540,7 +40198,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zV if( zValue && zValue[0] ){ zValueUtf8 = winUnicodeToUtf8(zValue); if ( zValueUtf8==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } } sqlite3_free(*ppDirectory); @@ -36612,7 +40270,7 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); - zOut = sqlite3_win32_mbcs_to_utf8(zTemp); + zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); sqlite3EndBenignMalloc(); /* free the system buffer allocated by FormatMessage */ osLocalFree(zTemp); @@ -36754,16 +40412,17 @@ static void winLogIoerr(int nRetry, int lineno){ } } -#if SQLITE_OS_WINCE -/************************************************************************* -** This section contains code for WinCE only. -*/ -#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API /* -** The MSVC CRT on Windows CE may not have a localtime() function. So -** create a substitute. +** This #if does not rely on the SQLITE_OS_WINCE define because the +** corresponding section in "date.c" cannot use it. */ -/* #include */ +#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ + (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) +/* +** The MSVC CRT on Windows CE may not have a localtime() function. +** So define a substitute. +*/ +/* # include */ struct tm *__cdecl localtime(const time_t *t) { static struct tm y; @@ -36787,6 +40446,10 @@ struct tm *__cdecl localtime(const time_t *t) } #endif +#if SQLITE_OS_WINCE +/************************************************************************* +** This section contains code for WinCE only. +*/ #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] /* @@ -36817,7 +40480,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){ zName = winUtf8ToUnicode(zFilename); if( zName==0 ){ /* out of memory */ - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } /* Initialize the local lockdata */ @@ -37242,7 +40905,12 @@ static int winClose(sqlite3_file *id){ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 - winceDestroyLock(pFile); + { + winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; + if( pAppData==NULL || !pAppData->bNoLock ){ + winceDestroyLock(pFile); + } + } if( pFile->zDeleteOnClose ){ int cnt = 0; while( @@ -37800,9 +41468,8 @@ static int winLock(sqlite3_file *id, int locktype){ ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; - if( (pFile->locktype==NO_LOCK) - || ( (locktype==EXCLUSIVE_LOCK) - && (pFile->locktype==RESERVED_LOCK)) + if( pFile->locktype==NO_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) ){ int cnt = 3; while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, @@ -37975,6 +41642,44 @@ static int winUnlock(sqlite3_file *id, int locktype){ return rc; } +/****************************************************************************** +****************************** No-op Locking ********************************** +** +** Of the various locking implementations available, this is by far the +** simplest: locking is ignored. No attempt is made to lock the database +** file for reading or writing. +** +** This locking mode is appropriate for use on read-only databases +** (ex: databases that are burned into CD-ROM, for example.) It can +** also be used if the application employs some external mechanism to +** prevent simultaneous access of the same database by two or more +** database connections. But there is a serious risk of database +** corruption if this locking mode is used in situations where multiple +** database connections are accessing the same database file at the same +** time and one or more of those connections are writing. +*/ + +static int winNolockLock(sqlite3_file *id, int locktype){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(locktype); + return SQLITE_OK; +} + +static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(pResOut); + return SQLITE_OK; +} + +static int winNolockUnlock(sqlite3_file *id, int locktype){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(locktype); + return SQLITE_OK; +} + +/******************* End of the no-op lock implementation ********************* +******************************************************************************/ + /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. @@ -38008,7 +41713,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } - case SQLITE_LAST_ERRNO: { + case SQLITE_FCNTL_LAST_ERRNO: { *(int*)pArg = (int)pFile->lastErrno; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; @@ -38066,6 +41771,12 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } + case SQLITE_FCNTL_WIN32_GET_HANDLE: { + LPHANDLE phFile = (LPHANDLE)pArg; + *phFile = pFile->h; + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } #ifdef SQLITE_TEST case SQLITE_FCNTL_WIN32_SET_HANDLE: { LPHANDLE phFile = (LPHANDLE)pArg; @@ -38093,6 +41804,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } + + /* The value of newLimit may be eventually cast to (SIZE_T) and passed + ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at + ** least a 64-bit type. */ + if( newLimit>0 && sizeof(SIZE_T)<8 ){ + newLimit = (newLimit & 0x7FFFFFFF); + } + *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; @@ -38253,12 +41972,12 @@ struct winShm { /* ** Apply advisory locks for all n bytes beginning at ofst. */ -#define _SHM_UNLCK 1 -#define _SHM_RDLCK 2 -#define _SHM_WRLCK 3 +#define WINSHM_UNLCK 1 +#define WINSHM_RDLCK 2 +#define WINSHM_WRLCK 3 static int winShmSystemLock( winShmNode *pFile, /* Apply locks to this open shared-memory segment */ - int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */ + int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ int ofst, /* Offset to first byte to be locked/unlocked */ int nByte /* Number of bytes to lock or unlock */ ){ @@ -38271,12 +41990,12 @@ static int winShmSystemLock( pFile->hFile.h, lockType, ofst, nByte)); /* Release/Acquire the system-level lock */ - if( lockType==_SHM_UNLCK ){ + if( lockType==WINSHM_UNLCK ){ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ /* Initialize the locking parameters */ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; - if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } @@ -38288,7 +42007,7 @@ static int winShmSystemLock( } OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", - pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" : + pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); return rc; @@ -38366,12 +42085,12 @@ static int winOpenSharedMemory(winFile *pDbFd){ ** allocate space for a new winShmNode and filename. */ p = sqlite3MallocZero( sizeof(*p) ); - if( p==0 ) return SQLITE_IOERR_NOMEM; + if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; nName = sqlite3Strlen30(pDbFd->zPath); pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); if( pNew==0 ){ sqlite3_free(p); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } pNew->zFilename = (char*)&pNew[1]; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); @@ -38396,10 +42115,12 @@ static int winOpenSharedMemory(winFile *pDbFd){ pShmNode->pNext = winShmNodeList; winShmNodeList = pShmNode; - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ - rc = SQLITE_IOERR_NOMEM; - goto shm_open_err; + if( sqlite3GlobalConfig.bCoreMutex ){ + pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->mutex==0 ){ + rc = SQLITE_IOERR_NOMEM_BKPT; + goto shm_open_err; + } } rc = winOpen(pDbFd->pVfs, @@ -38414,7 +42135,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. */ - if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ + if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); if( rc!=SQLITE_OK ){ rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), @@ -38422,8 +42143,8 @@ static int winOpenSharedMemory(winFile *pDbFd){ } } if( rc==SQLITE_OK ){ - winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); - rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1); + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); } if( rc ) goto shm_open_err; } @@ -38452,7 +42173,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ /* Jump here on any error */ shm_open_err: - winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ sqlite3_free(p); sqlite3_free(pNew); @@ -38541,7 +42262,7 @@ static int winShmLock( /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ - rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n); + rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } @@ -38569,7 +42290,7 @@ static int winShmLock( /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ - rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n); + rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } @@ -38594,7 +42315,7 @@ static int winShmLock( ** also mark the local connection as being locked. */ if( rc==SQLITE_OK ){ - rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n); + rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; @@ -38703,7 +42424,7 @@ static int winShmMap( pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) ); if( !apNew ){ - rc = SQLITE_IOERR_NOMEM; + rc = SQLITE_IOERR_NOMEM_BKPT; goto shmpage_out; } pShmNode->aRegion = apNew; @@ -38720,7 +42441,7 @@ static int winShmMap( hMap = osCreateFileMappingW(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); -#elif defined(SQLITE_WIN32_HAS_ANSI) +#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA hMap = osCreateFileMappingA(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); @@ -38876,7 +42597,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); -#elif defined(SQLITE_WIN32_HAS_ANSI) +#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); @@ -39037,6 +42758,44 @@ static const sqlite3_io_methods winIoMethod = { winUnfetch /* xUnfetch */ }; +/* +** This vector defines all the methods that can operate on an +** sqlite3_file for win32 without performing any locking. +*/ +static const sqlite3_io_methods winIoNolockMethod = { + 3, /* iVersion */ + winClose, /* xClose */ + winRead, /* xRead */ + winWrite, /* xWrite */ + winTruncate, /* xTruncate */ + winSync, /* xSync */ + winFileSize, /* xFileSize */ + winNolockLock, /* xLock */ + winNolockUnlock, /* xUnlock */ + winNolockCheckReservedLock, /* xCheckReservedLock */ + winFileControl, /* xFileControl */ + winSectorSize, /* xSectorSize */ + winDeviceCharacteristics, /* xDeviceCharacteristics */ + winShmMap, /* xShmMap */ + winShmLock, /* xShmLock */ + winShmBarrier, /* xShmBarrier */ + winShmUnmap, /* xShmUnmap */ + winFetch, /* xFetch */ + winUnfetch /* xUnfetch */ +}; + +static winVfsAppData winAppData = { + &winIoMethod, /* pMethod */ + 0, /* pAppData */ + 0 /* bNoLock */ +}; + +static winVfsAppData winNolockAppData = { + &winIoNolockMethod, /* pMethod */ + 0, /* pAppData */ + 1 /* bNoLock */ +}; + /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** @@ -39057,7 +42816,7 @@ static char *winConvertToUtf8Filename(const void *zFilename){ } #ifdef SQLITE_WIN32_HAS_ANSI else{ - zConverted = sqlite3_win32_mbcs_to_utf8(zFilename); + zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); } #endif /* caller will handle out of memory */ @@ -39078,7 +42837,7 @@ static void *winConvertFromUtf8Filename(const char *zFilename){ } #ifdef SQLITE_WIN32_HAS_ANSI else{ - zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); + zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); } #endif /* caller will handle out of memory */ @@ -39133,7 +42892,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ zBuf = sqlite3MallocZero( nBuf ); if( !zBuf ){ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } /* Figure out the effective temporary directory. First, check if one @@ -39191,7 +42950,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ if( !zConverted ){ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( winIsDir(zConverted) ){ sqlite3_snprintf(nMax, zBuf, "%s", zDir); @@ -39204,7 +42963,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ if( !zConverted ){ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( cygwin_conv_path( osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir, @@ -39225,7 +42984,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ sqlite3_free(zConverted); sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } sqlite3_snprintf(nMax, zBuf, "%s", zUtf8); sqlite3_free(zUtf8); @@ -39243,7 +43002,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ if( !zWidePath ){ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( osGetTempPathW(nMax, zWidePath)==0 ){ sqlite3_free(zWidePath); @@ -39261,7 +43020,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ sqlite3_free(zWidePath); sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } } #ifdef SQLITE_WIN32_HAS_ANSI @@ -39271,7 +43030,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ if( !zMbcsPath ){ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( osGetTempPathA(nMax, zMbcsPath)==0 ){ sqlite3_free(zBuf); @@ -39279,14 +43038,14 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(), "winGetTempname3", 0); } - zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath); + zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI()); if( zUtf8 ){ sqlite3_snprintf(nMax, zBuf, "%s", zUtf8); sqlite3_free(zUtf8); }else{ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } } #endif /* SQLITE_WIN32_HAS_ANSI */ @@ -39365,11 +43124,19 @@ static int winIsDir(const void *zConverted){ return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); } +/* forward reference */ +static int winAccess( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to check */ + int flags, /* Type of test to make on this file */ + int *pResOut /* OUT: Result */ +); + /* ** Open a file. */ static int winOpen( - sqlite3_vfs *pVfs, /* Used to get maximum path name length */ + sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */ const char *zName, /* Name of the file (UTF-8) */ sqlite3_file *id, /* Write the SQLite file handle here */ int flags, /* Open mode flags */ @@ -39384,6 +43151,7 @@ static int winOpen( #if SQLITE_OS_WINCE int isTemp = 0; #endif + winVfsAppData *pAppData; winFile *pFile = (winFile*)id; void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ @@ -39478,7 +43246,7 @@ static int winOpen( if( zConverted==0 ){ sqlite3_free(zTmpname); OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name)); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( winIsDir(zConverted) ){ @@ -39540,37 +43308,52 @@ static int winOpen( extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParameters.lpSecurityAttributes = NULL; extendedParameters.hTemplateFile = NULL; - while( (h = osCreateFile2((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, - dwCreationDisposition, - &extendedParameters))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFile2((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, + dwCreationDisposition, + &extendedParameters); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int isRO = 0; + int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); #else - while( (h = osCreateFileW((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFileW((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int isRO = 0; + int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ - while( (h = osCreateFileA((LPCSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFileA((LPCSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int isRO = 0; + int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); } #endif winLogIoerr(cnt, __LINE__); @@ -39579,8 +43362,6 @@ static int winOpen( dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); if( h==INVALID_HANDLE_VALUE ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ @@ -39589,6 +43370,8 @@ static int winOpen( ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ + pFile->lastErrno = lastErrno; + winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); return SQLITE_CANTOPEN_BKPT; } } @@ -39605,15 +43388,20 @@ static int winOpen( "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); + pAppData = (winVfsAppData*)pVfs->pAppData; + #if SQLITE_OS_WINCE - if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB - && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK - ){ - osCloseHandle(h); - sqlite3_free(zConverted); - sqlite3_free(zTmpname); - OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); - return rc; + { + if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB + && ((pAppData==NULL) || !pAppData->bNoLock) + && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK + ){ + osCloseHandle(h); + sqlite3_free(zConverted); + sqlite3_free(zTmpname); + OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); + return rc; + } } if( isTemp ){ pFile->zDeleteOnClose = zConverted; @@ -39624,7 +43412,7 @@ static int winOpen( } sqlite3_free(zTmpname); - pFile->pMethod = &winIoMethod; + pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ @@ -39678,7 +43466,7 @@ static int winDelete( zConverted = winConvertFromUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( osIsNT() ){ do { @@ -39786,7 +43574,7 @@ static int winAccess( zConverted = winConvertFromUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( osIsNT() ){ int cnt = 0; @@ -39899,6 +43687,18 @@ static int winFullPathname( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) + DWORD nByte; + void *zConverted; + char *zOut; +#endif + + /* If this path name begins with "/X:", where "X" is any alphabetic + ** character, discard the initial "/" from the pathname. + */ + if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ + zRelative++; + } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); @@ -39913,7 +43713,7 @@ static int winFullPathname( */ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); if( !zOut ){ - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( cygwin_conv_path( (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | @@ -39925,7 +43725,7 @@ static int winFullPathname( char *zUtf8 = winConvertToUtf8Filename(zOut); if( !zUtf8 ){ sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", sqlite3_data_directory, winGetDirSep(), zUtf8); @@ -39935,7 +43735,7 @@ static int winFullPathname( }else{ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); if( !zOut ){ - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( cygwin_conv_path( (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), @@ -39947,7 +43747,7 @@ static int winFullPathname( char *zUtf8 = winConvertToUtf8Filename(zOut); if( !zUtf8 ){ sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); sqlite3_free(zUtf8); @@ -39977,17 +43777,6 @@ static int winFullPathname( #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) - DWORD nByte; - void *zConverted; - char *zOut; - - /* If this path name begins with "/X:", where "X" is any alphabetic - ** character, discard the initial "/" from the pathname. - */ - if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ - zRelative++; - } - /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the @@ -40007,7 +43796,7 @@ static int winFullPathname( } zConverted = winConvertFromUtf8Filename(zRelative); if( zConverted==0 ){ - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } if( osIsNT() ){ LPWSTR zTemp; @@ -40021,7 +43810,7 @@ static int winFullPathname( zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0); if( nByte==0 ){ @@ -40047,7 +43836,7 @@ static int winFullPathname( zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); if( nByte==0 ){ @@ -40057,7 +43846,7 @@ static int winFullPathname( "winFullPathname4", zRelative); } sqlite3_free(zConverted); - zOut = sqlite3_win32_mbcs_to_utf8(zTemp); + zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); sqlite3_free(zTemp); } #endif @@ -40066,7 +43855,7 @@ static int winFullPathname( sqlite3_free(zOut); return SQLITE_OK; }else{ - return SQLITE_IOERR_NOMEM; + return SQLITE_IOERR_NOMEM_BKPT; } #endif } @@ -40141,65 +43930,82 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ #define winDlClose 0 #endif +/* State information for the randomness gatherer. */ +typedef struct EntropyGatherer EntropyGatherer; +struct EntropyGatherer { + unsigned char *a; /* Gather entropy into this buffer */ + int na; /* Size of a[] in bytes */ + int i; /* XOR next input into a[i] */ + int nXor; /* Number of XOR operations done */ +}; + +#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) +/* Mix sz bytes of entropy into p. */ +static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){ + int j, k; + for(j=0, k=p->i; ja[k++] ^= x[j]; + if( k>=p->na ) k = 0; + } + p->i = k; + p->nXor += sz; +} +#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */ /* ** Write up to nBuf bytes of randomness into zBuf. */ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ - int n = 0; - UNUSED_PARAMETER(pVfs); #if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) - n = nBuf; + UNUSED_PARAMETER(pVfs); memset(zBuf, 0, nBuf); + return nBuf; #else - if( sizeof(SYSTEMTIME)<=nBuf-n ){ + EntropyGatherer e; + UNUSED_PARAMETER(pVfs); + memset(zBuf, 0, nBuf); + e.a = (unsigned char*)zBuf; + e.na = nBuf; + e.nXor = 0; + e.i = 0; + { SYSTEMTIME x; osGetSystemTime(&x); - memcpy(&zBuf[n], &x, sizeof(x)); - n += sizeof(x); + xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME)); } - if( sizeof(DWORD)<=nBuf-n ){ + { DWORD pid = osGetCurrentProcessId(); - memcpy(&zBuf[n], &pid, sizeof(pid)); - n += sizeof(pid); + xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); } #if SQLITE_OS_WINRT - if( sizeof(ULONGLONG)<=nBuf-n ){ + { ULONGLONG cnt = osGetTickCount64(); - memcpy(&zBuf[n], &cnt, sizeof(cnt)); - n += sizeof(cnt); + xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG)); } #else - if( sizeof(DWORD)<=nBuf-n ){ + { DWORD cnt = osGetTickCount(); - memcpy(&zBuf[n], &cnt, sizeof(cnt)); - n += sizeof(cnt); + xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); } -#endif - if( sizeof(LARGE_INTEGER)<=nBuf-n ){ +#endif /* SQLITE_OS_WINRT */ + { LARGE_INTEGER i; osQueryPerformanceCounter(&i); - memcpy(&zBuf[n], &i, sizeof(i)); - n += sizeof(i); + xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); } #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID - if( sizeof(UUID)<=nBuf-n ){ + { UUID id; memset(&id, 0, sizeof(UUID)); osUuidCreate(&id); - memcpy(&zBuf[n], &id, sizeof(UUID)); - n += sizeof(UUID); - } - if( sizeof(UUID)<=nBuf-n ){ - UUID id; + xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); memset(&id, 0, sizeof(UUID)); osUuidCreateSequential(&id); - memcpy(&zBuf[n], &id, sizeof(UUID)); - n += sizeof(UUID); + xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); } -#endif -#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */ - return n; +#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */ + return e.nXor>nBuf ? nBuf : e.nXor; +#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ } @@ -40315,62 +44121,114 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ ** sqlite3_errmsg(), possibly making IO errors easier to debug. */ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + DWORD e = osGetLastError(); UNUSED_PARAMETER(pVfs); - return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf); + if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf); + return e; } /* ** Initialize and deinitialize the operating system interface. */ -SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ +SQLITE_API int sqlite3_os_init(void){ static sqlite3_vfs winVfs = { - 3, /* iVersion */ - sizeof(winFile), /* szOsFile */ + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ - 0, /* pNext */ - "win32", /* zName */ - 0, /* pAppData */ - winOpen, /* xOpen */ - winDelete, /* xDelete */ - winAccess, /* xAccess */ - winFullPathname, /* xFullPathname */ - winDlOpen, /* xDlOpen */ - winDlError, /* xDlError */ - winDlSym, /* xDlSym */ - winDlClose, /* xDlClose */ - winRandomness, /* xRandomness */ - winSleep, /* xSleep */ - winCurrentTime, /* xCurrentTime */ - winGetLastError, /* xGetLastError */ - winCurrentTimeInt64, /* xCurrentTimeInt64 */ - winSetSystemCall, /* xSetSystemCall */ - winGetSystemCall, /* xGetSystemCall */ - winNextSystemCall, /* xNextSystemCall */ + 0, /* pNext */ + "win32", /* zName */ + &winAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ }; #if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathVfs = { - 3, /* iVersion */ - sizeof(winFile), /* szOsFile */ + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ - 0, /* pNext */ - "win32-longpath", /* zName */ - 0, /* pAppData */ - winOpen, /* xOpen */ - winDelete, /* xDelete */ - winAccess, /* xAccess */ - winFullPathname, /* xFullPathname */ - winDlOpen, /* xDlOpen */ - winDlError, /* xDlError */ - winDlSym, /* xDlSym */ - winDlClose, /* xDlClose */ - winRandomness, /* xRandomness */ - winSleep, /* xSleep */ - winCurrentTime, /* xCurrentTime */ - winGetLastError, /* xGetLastError */ - winCurrentTimeInt64, /* xCurrentTimeInt64 */ - winSetSystemCall, /* xSetSystemCall */ - winGetSystemCall, /* xGetSystemCall */ - winNextSystemCall, /* xNextSystemCall */ + 0, /* pNext */ + "win32-longpath", /* zName */ + &winAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#endif + static sqlite3_vfs winNolockVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-none", /* zName */ + &winNolockAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#if defined(SQLITE_WIN32_HAS_WIDE) + static sqlite3_vfs winLongPathNolockVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-longpath-none", /* zName */ + &winNolockAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ }; #endif @@ -40394,10 +44252,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ sqlite3_vfs_register(&winLongPathVfs, 0); #endif + sqlite3_vfs_register(&winNolockVfs, 0); + +#if defined(SQLITE_WIN32_HAS_WIDE) + sqlite3_vfs_register(&winLongPathNolockVfs, 0); +#endif + return SQLITE_OK; } -SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ +SQLITE_API int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ osCloseHandle(sleepObj); @@ -40590,7 +44454,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){ i = i%p->iDivisor; if( p->u.apSub[bin]==0 ){ p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); - if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM; + if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT; } p = p->u.apSub[bin]; } @@ -40625,7 +44489,7 @@ bitvec_set_rehash: int rc; u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash)); if( aiValues==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; }else{ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); memset(p->u.apSub, 0, sizeof(p->u.apSub)); @@ -40706,7 +44570,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ return p->iSize; } -#ifndef SQLITE_OMIT_BUILTIN_TEST +#ifndef SQLITE_UNTESTABLE /* ** Let V[] be an array of unsigned characters sufficient to hold ** up to N bits. Let I be an integer between 0 and N. 0<=IpDirtyNext. +** PCache.pDirty points to the first (newest) element in the list and +** pDirtyTail to the last (oldest). +** +** 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 +** 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 +** pointers). */ struct PCache { PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ @@ -40858,6 +44744,95 @@ struct PCache { sqlite3_pcache *pCache; /* Pluggable cache module */ }; +/********************************** Test and Debug Logic **********************/ +/* +** Debug tracing macros. Enable by by changing the "0" to "1" and +** recompiling. +** +** When sqlite3PcacheTrace is 1, single line trace messages are issued. +** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries +** is displayed for many operations, resulting in a lot of output. +*/ +#if defined(SQLITE_DEBUG) && 0 + int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ + int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ +# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} + void pcacheDump(PCache *pCache){ + int N; + int i, j; + sqlite3_pcache_page *pLower; + PgHdr *pPg; + unsigned char *a; + + if( sqlite3PcacheTrace<2 ) return; + if( pCache->pCache==0 ) return; + N = sqlite3PcachePagecount(pCache); + if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; + for(i=1; i<=N; i++){ + pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); + if( pLower==0 ) continue; + pPg = (PgHdr*)pLower->pExtra; + printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); + a = (unsigned char *)pLower->pBuf; + for(j=0; j<12; j++) printf("%02x", a[j]); + printf("\n"); + if( pPg->pPage==0 ){ + sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); + } + } + } + #else +# define pcacheTrace(X) +# define pcacheDump(X) +#endif + +/* +** Check invariants on a PgHdr entry. Return true if everything is OK. +** Return false if any invariant is violated. +** +** This routine is for use inside of assert() statements only. For +** example: +** +** assert( sqlite3PcachePageSanity(pPg) ); +*/ +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){ + PCache *pCache; + assert( pPg!=0 ); + assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */ + pCache = pPg->pCache; + assert( pCache!=0 ); /* Every page has an associated PCache */ + if( pPg->flags & PGHDR_CLEAN ){ + assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ + assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ + assert( pCache->pDirtyTail!=pPg ); + } + /* WRITEABLE pages must also be DIRTY */ + if( pPg->flags & PGHDR_WRITEABLE ){ + assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ + } + /* NEED_SYNC can be set independently of WRITEABLE. This can happen, + ** for example, when using the sqlite3PagerDontWrite() optimization: + ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK. + ** (2) Page X moved to freelist, WRITEABLE is cleared + ** (3) Page X reused, WRITEABLE is set again + ** If NEED_SYNC had been cleared in step 2, then it would not be reset + ** in step 3, and page might be written into the database without first + ** syncing the rollback journal, which might cause corruption on a power + ** loss. + ** + ** Another example is when the database page size is smaller than the + ** disk sector size. When any page of a sector is journalled, all pages + ** in that sector are marked NEED_SYNC even if they are still CLEAN, just + ** in case they are later modified, since all pages in the same sector + ** must be journalled and synced before any of those pages can be safely + ** written. + */ + return 1; +} +#endif /* SQLITE_DEBUG */ + + /********************************** Linked List Management ********************/ /* Allowed values for second argument to pcacheManageDirtyList() */ @@ -40874,17 +44849,16 @@ struct PCache { static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ PCache *p = pPage->pCache; + pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, + addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT", + pPage->pgno)); if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); assert( pPage->pDirtyPrev || pPage==p->pDirty ); /* Update the PCache1.pSynced variable if necessary. */ if( p->pSynced==pPage ){ - PgHdr *pSynced = pPage->pDirtyPrev; - while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ - pSynced = pSynced->pDirtyPrev; - } - p->pSynced = pSynced; + p->pSynced = pPage->pDirtyPrev; } if( pPage->pDirtyNext ){ @@ -40896,19 +44870,21 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ if( pPage->pDirtyPrev ){ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; }else{ + /* If there are now no dirty pages in the cache, set eCreate to 2. + ** This is an optimization that allows sqlite3PcacheFetch() to skip + ** searching for a dirty page to eject from the cache when it might + ** otherwise have to. */ assert( pPage==p->pDirty ); p->pDirty = pPage->pDirtyNext; - if( p->pDirty==0 && p->bPurgeable ){ - assert( p->eCreate==1 ); + assert( p->bPurgeable || p->eCreate==2 ); + if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/ + assert( p->bPurgeable==0 || p->eCreate==1 ); p->eCreate = 2; } } - pPage->pDirtyNext = 0; - pPage->pDirtyPrev = 0; } if( addRemove & PCACHE_DIRTYLIST_ADD ){ - assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); - + pPage->pDirtyPrev = 0; pPage->pDirtyNext = p->pDirty; if( pPage->pDirtyNext ){ assert( pPage->pDirtyNext->pDirtyPrev==0 ); @@ -40921,10 +44897,19 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ } } p->pDirty = pPage; - if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ + + /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set + ** pSynced to point to it. Checking the NEED_SYNC flag is an + ** optimization, as if pSynced points to a page with the NEED_SYNC + ** flag set sqlite3PcacheFetchStress() searches through all newer + ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ + if( !p->pSynced + && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ + ){ p->pSynced = pPage; } } + pcacheDump(p); } /* @@ -40933,7 +44918,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ */ static void pcacheUnpin(PgHdr *p){ if( p->pCache->bPurgeable ){ + pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno)); sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); + pcacheDump(p->pCache); } } @@ -40985,6 +44972,12 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); } ** has already been allocated and is passed in as the p pointer. ** The caller discovers how much space needs to be allocated by ** calling sqlite3PcacheSize(). +** +** szExtra is some extra space allocated for each page. The first +** 8 bytes of the extra space will be zeroed as the page is allocated, +** but remaining content will be uninitialized. Though it is opaque +** to this module, the extra space really ends up being the MemPage +** structure in the pager. */ SQLITE_PRIVATE int sqlite3PcacheOpen( int szPage, /* Size of every page */ @@ -40997,12 +44990,14 @@ SQLITE_PRIVATE int sqlite3PcacheOpen( memset(p, 0, sizeof(PCache)); p->szPage = 1; p->szExtra = szExtra; + assert( szExtra>=8 ); /* First 8 bytes will be zeroed */ p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; p->szSpill = 1; + pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable)); return sqlite3PcacheSetPageSize(p, szPage); } @@ -41018,13 +45013,14 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), pCache->bPurgeable ); - if( pNew==0 ) return SQLITE_NOMEM; + if( pNew==0 ) return SQLITE_NOMEM_BKPT; sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); if( pCache->pCache ){ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } pCache->pCache = pNew; pCache->szPage = szPage; + pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage)); } return SQLITE_OK; } @@ -41059,11 +45055,12 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( int createFlag /* If true, create page if it does not exist already */ ){ int eCreate; + sqlite3_pcache_page *pRes; assert( pCache!=0 ); assert( pCache->pCache!=0 ); assert( createFlag==3 || createFlag==0 ); - assert( pgno>0 ); + assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) @@ -41076,12 +45073,15 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); - return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); + pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); + pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno, + createFlag?" create":"",pRes)); + return pRes; } /* ** If the sqlite3PcacheFetch() routine is unable to allocate a new -** page because new clean pages are available for reuse and the cache +** page because no clean pages are available for reuse and the cache ** size limit has been reached, then this routine can be invoked to ** try harder to allocate a page. This routine might invoke the stress ** callback to spill dirty pages to the journal. It will then try to @@ -41103,7 +45103,11 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress( ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC ** cleared), but if that is not possible settle for any other ** unreferenced dirty page. - */ + ** + ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC + ** flag is currently referenced, then the following may leave pSynced + ** set incorrectly (pointing to other than the LRU page with NEED_SYNC + ** cleared). This is Ok, as pSynced is just an optimization. */ for(pPg=pCache->pSynced; pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); pPg=pPg->pDirtyPrev @@ -41121,14 +45125,16 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress( sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif + pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); rc = pCache->xStress(pCache->pStress, pPg); + pcacheDump(pCache); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ return rc; } } } *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); - return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK; + return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; } /* @@ -41149,11 +45155,11 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( assert( pPage!=0 ); pPgHdr = (PgHdr*)pPage->pExtra; assert( pPgHdr->pPage==0 ); - memset(pPgHdr, 0, sizeof(PgHdr)); + memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty)); pPgHdr->pPage = pPage; pPgHdr->pData = pPage->pBuf; pPgHdr->pExtra = (void *)&pPgHdr[1]; - memset(pPgHdr->pExtra, 0, pCache->szExtra); + memset(pPgHdr->pExtra, 0, 8); pPgHdr->pCache = pCache; pPgHdr->pgno = pgno; pPgHdr->flags = PGHDR_CLEAN; @@ -41181,6 +45187,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish( } pCache->nRefSum++; pPgHdr->nRef++; + assert( sqlite3PcachePageSanity(pPgHdr) ); return pPgHdr; } @@ -41194,8 +45201,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); - }else if( p->pDirtyPrev!=0 ){ - /* Move the page to the head of the dirty list. */ + }else{ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -41206,6 +45212,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ */ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){ assert(p->nRef>0); + assert( sqlite3PcachePageSanity(p) ); p->nRef++; p->pCache->nRefSum++; } @@ -41217,6 +45224,7 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){ */ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ assert( p->nRef==1 ); + assert( sqlite3PcachePageSanity(p) ); if( p->flags&PGHDR_DIRTY ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); } @@ -41230,13 +45238,16 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ */ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ assert( p->nRef>0 ); - if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ + assert( sqlite3PcachePageSanity(p) ); + if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_CLEAN ){ p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); + pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); } + assert( sqlite3PcachePageSanity(p) ); } } @@ -41245,11 +45256,14 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ ** make it so. */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ - if( (p->flags & PGHDR_DIRTY) ){ + assert( sqlite3PcachePageSanity(p) ); + if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){ assert( (p->flags & PGHDR_CLEAN)==0 ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); p->flags |= PGHDR_CLEAN; + pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); + assert( sqlite3PcachePageSanity(p) ); if( p->nRef==0 ){ pcacheUnpin(p); } @@ -41261,11 +45275,24 @@ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ */ SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; + pcacheTrace(("%p.CLEAN-ALL\n",pCache)); while( (p = pCache->pDirty)!=0 ){ sqlite3PcacheMakeClean(p); } } +/* +** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages. +*/ +SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){ + PgHdr *p; + pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache)); + for(p=pCache->pDirty; p; p=p->pDirtyNext){ + p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE); + } + pCache->pSynced = pCache->pDirtyTail; +} + /* ** Clear the PGHDR_NEED_SYNC flag from all dirty pages. */ @@ -41284,6 +45311,8 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; assert( p->nRef>0 ); assert( newPgno>0 ); + assert( sqlite3PcachePageSanity(p) ); + pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ @@ -41304,6 +45333,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ if( pCache->pCache ){ PgHdr *p; PgHdr *pNext; + pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno)); for(p=pCache->pDirty; p; p=pNext){ pNext = p->pDirtyNext; /* This routine never gets call with a positive pgno except right @@ -41311,7 +45341,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ ** it must be that pgno==0. */ assert( p->pgno>0 ); - if( ALWAYS(p->pgno>pgno) ){ + if( p->pgno>pgno ){ assert( p->flags&PGHDR_DIRTY ); sqlite3PcacheMakeClean(p); } @@ -41334,6 +45364,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ */ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){ assert( pCache->pCache!=0 ); + pcacheTrace(("%p.CLOSE\n",pCache)); sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } @@ -41346,29 +45377,31 @@ SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){ /* ** Merge two lists of pages connected by pDirty and in pgno order. -** Do not both fixing the pDirtyPrev pointers. +** Do not bother fixing the pDirtyPrev pointers. */ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ PgHdr result, *pTail; pTail = &result; - while( pA && pB ){ + assert( pA!=0 && pB!=0 ); + for(;;){ if( pA->pgnopgno ){ pTail->pDirty = pA; pTail = pA; pA = pA->pDirty; + if( pA==0 ){ + pTail->pDirty = pB; + break; + } }else{ pTail->pDirty = pB; pTail = pB; pB = pB->pDirty; + if( pB==0 ){ + pTail->pDirty = pA; + break; + } } } - if( pA ){ - pTail->pDirty = pA; - }else if( pB ){ - pTail->pDirty = pB; - }else{ - pTail->pDirty = 0; - } return result.pDirty; } @@ -41409,7 +45442,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ } p = a[0]; for(i=1; ipDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++; + return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; +} #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* @@ -41617,7 +45662,6 @@ typedef struct PGroup PGroup; struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ - u8 isPinned; /* Page in use, not on the LRU list */ u8 isBulkLocal; /* This page from bulk local storage */ u8 isAnchor; /* This is the PGroup.lru element */ PgHdr1 *pNext; /* Next in hash table chain */ @@ -41626,6 +45670,12 @@ struct PgHdr1 { PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ }; +/* +** A page is pinned if it is no on the LRU list +*/ +#define PAGE_IS_PINNED(p) ((p)->pLruNext==0) +#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) + /* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each other's unpinned ** pages when they are under memory pressure. A PGroup is an instance of @@ -41653,7 +45703,7 @@ struct PGroup { unsigned int nMaxPage; /* Sum of nMax for purgeable caches */ unsigned int nMinPage; /* Sum of nMin for purgeable caches */ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */ - unsigned int nCurrentPage; /* Number of purgeable pages allocated */ + unsigned int nPurgeable; /* Number of purgeable pages allocated */ PgHdr1 lru; /* The beginning and end of the LRU list */ }; @@ -41667,11 +45717,13 @@ struct PGroup { */ struct PCache1 { /* Cache configuration parameters. Page size (szPage) and the purgeable - ** flag (bPurgeable) are set when the cache is created. nMax may be + ** flag (bPurgeable) and the pnPurgeable pointer are all set when the + ** cache is created and are never changed thereafter. nMax may be ** modified at any time by a call to the pcache1Cachesize() method. ** The PGroup mutex must be held when accessing nMax. */ PGroup *pGroup; /* PGroup this cache belongs to */ + unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */ int szPage; /* Size of database content section */ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szAlloc; /* Total size of one pcache line */ @@ -41766,6 +45818,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ if( pcache1.isInit ){ PgFreeslot *p; if( pBuf==0 ) sz = n = 0; + if( n==0 ) sz = 0; sz = ROUNDDOWN8(sz); pcache1.szSlot = sz; pcache1.nSlot = pcache1.nFreeSlot = n; @@ -41800,14 +45853,13 @@ static int pcache1InitBulk(PCache1 *pCache){ szBulk = -1024 * (i64)pcache1.nInitPage; } if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){ - szBulk = pCache->szAlloc*pCache->nMax; + szBulk = pCache->szAlloc*(i64)pCache->nMax; } zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); sqlite3EndBenignMalloc(); if( zBulk ){ int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; - int i; - for(i=0; iszPage]; pX->page.pBuf = zBulk; pX->page.pExtra = &pX[1]; @@ -41816,7 +45868,7 @@ static int pcache1InitBulk(PCache1 *pCache){ pX->pNext = pCache->pFree; pCache->pFree = pX; zBulk += pCache->szAlloc; - } + }while( --nBulk ); } return pCache->pFree!=0; } @@ -41869,7 +45921,6 @@ static void *pcache1Alloc(int nByte){ ** Free an allocated buffer obtained from pcache1Alloc(). */ static void pcache1Free(void *p){ - int nFreed = 0; if( p==0 ) return; if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){ PgFreeslot *pSlot; @@ -41886,10 +45937,13 @@ static void pcache1Free(void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); #ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS - nFreed = sqlite3MallocSize(p); - sqlite3_mutex_enter(pcache1.mutex); - sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed); - sqlite3_mutex_leave(pcache1.mutex); + { + int nFreed = 0; + nFreed = sqlite3MallocSize(p); + sqlite3_mutex_enter(pcache1.mutex); + sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed); + sqlite3_mutex_leave(pcache1.mutex); + } #endif sqlite3_free(p); } @@ -41957,9 +46011,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ p->isBulkLocal = 0; p->isAnchor = 0; } - if( pCache->bPurgeable ){ - pCache->pGroup->nCurrentPage++; - } + (*pCache->pnPurgeable)++; return p; } @@ -41980,9 +46032,7 @@ static void pcache1FreePage(PgHdr1 *p){ sqlite3_free(p); #endif } - if( pCache->bPurgeable ){ - pCache->pGroup->nCurrentPage--; - } + (*pCache->pnPurgeable)--; } /* @@ -42077,22 +46127,18 @@ static void pcache1ResizeHash(PCache1 *p){ ** The PGroup mutex must be held when this function is called. */ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){ - PCache1 *pCache; - assert( pPage!=0 ); - assert( pPage->isPinned==0 ); - pCache = pPage->pCache; + assert( PAGE_IS_UNPINNED(pPage) ); assert( pPage->pLruNext ); assert( pPage->pLruPrev ); - assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); + assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) ); pPage->pLruPrev->pLruNext = pPage->pLruNext; pPage->pLruNext->pLruPrev = pPage->pLruPrev; pPage->pLruNext = 0; pPage->pLruPrev = 0; - pPage->isPinned = 1; assert( pPage->isAnchor==0 ); - assert( pCache->pGroup->lru.isAnchor==1 ); - pCache->nRecyclable--; + assert( pPage->pCache->pGroup->lru.isAnchor==1 ); + pPage->pCache->nRecyclable--; return pPage; } @@ -42126,11 +46172,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){ PGroup *pGroup = pCache->pGroup; PgHdr1 *p; assert( sqlite3_mutex_held(pGroup->mutex) ); - while( pGroup->nCurrentPage>pGroup->nMaxPage + while( pGroup->nPurgeable>pGroup->nMaxPage && (p=pGroup->lru.pLruPrev)->isAnchor==0 ){ assert( p->pCache->pGroup==pGroup ); - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } @@ -42151,25 +46197,45 @@ static void pcache1TruncateUnsafe( PCache1 *pCache, /* The cache to truncate */ unsigned int iLimit /* Drop pages with this pgno or larger */ ){ - TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */ - unsigned int h; + TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */ + unsigned int h, iStop; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); - for(h=0; hnHash; h++){ - PgHdr1 **pp = &pCache->apHash[h]; + assert( pCache->iMaxKey >= iLimit ); + assert( pCache->nHash > 0 ); + if( pCache->iMaxKey - iLimit < pCache->nHash ){ + /* If we are just shaving the last few pages off the end of the + ** cache, then there is no point in scanning the entire hash table. + ** Only scan those hash slots that might contain pages that need to + ** be removed. */ + h = iLimit % pCache->nHash; + iStop = pCache->iMaxKey % pCache->nHash; + TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */ + }else{ + /* This is the general case where many pages are being removed. + ** It is necessary to scan the entire hash table */ + h = pCache->nHash/2; + iStop = h - 1; + } + for(;;){ + PgHdr1 **pp; PgHdr1 *pPage; + assert( hnHash ); + pp = &pCache->apHash[h]; while( (pPage = *pp)!=0 ){ if( pPage->iKey>=iLimit ){ pCache->nPage--; *pp = pPage->pNext; - if( !pPage->isPinned ) pcache1PinPage(pPage); + if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage); pcache1FreePage(pPage); }else{ pp = &pPage->pNext; - TESTONLY( nPage++; ) + TESTONLY( if( nPage>=0 ) nPage++; ) } } + if( h==iStop ) break; + h = (h+1) % pCache->nHash; } - assert( pCache->nPage==nPage ); + assert( nPage<0 || pCache->nPage==(unsigned)nPage ); } /******************************************************************************/ @@ -42209,8 +46275,8 @@ static int pcache1Init(void *NotUsed){ #if SQLITE_THREADSAFE if( sqlite3GlobalConfig.bCoreMutex ){ - pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); - pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM); + pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU); + pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM); } #endif if( pcache1.separateCache @@ -42277,6 +46343,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->nMin = 10; pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; + pCache->pnPurgeable = &pGroup->nPurgeable; + }else{ + static unsigned int dummyCurrentPage; + pCache->pnPurgeable = &dummyCurrentPage; } pcache1LeaveMutex(pGroup); if( pCache->nHash==0 ){ @@ -42378,7 +46448,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ){ PCache1 *pOther; pPage = pGroup->lru.pLruPrev; - assert( pPage->isPinned==0 ); + assert( PAGE_IS_UNPINNED(pPage) ); pcache1RemoveFromHash(pPage, 0); pcache1PinPage(pPage); pOther = pPage->pCache; @@ -42386,7 +46456,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pcache1FreePage(pPage); pPage = 0; }else{ - pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); + pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable); } } @@ -42405,7 +46475,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pPage->pCache = pCache; pPage->pLruPrev = 0; pPage->pLruNext = 0; - pPage->isPinned = 1; *(void **)pPage->page.pExtra = 0; pCache->apHash[h] = pPage; if( iKey>pCache->iMaxKey ){ @@ -42491,7 +46560,7 @@ static PgHdr1 *pcache1FetchNoMutex( ** Otherwise (page not in hash and createFlag!=0) continue with ** subsequent steps to try to create the page. */ if( pPage ){ - if( !pPage->isPinned ){ + if( PAGE_IS_UNPINNED(pPage) ){ return pcache1PinPage(pPage); }else{ return pPage; @@ -42566,9 +46635,9 @@ static void pcache1Unpin( ** part of the PGroup LRU list. */ assert( pPage->pLruPrev==0 && pPage->pLruNext==0 ); - assert( pPage->isPinned==1 ); + assert( PAGE_IS_PINNED(pPage) ); - if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){ + if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ pcache1RemoveFromHash(pPage, 1); }else{ /* Add the page to the PGroup LRU list. */ @@ -42577,7 +46646,6 @@ static void pcache1Unpin( (pPage->pLruNext = *ppFirst)->pLruPrev = pPage; *ppFirst = pPage; pCache->nRecyclable++; - pPage->isPinned = 0; } pcache1LeaveMutex(pCache->pGroup); @@ -42646,7 +46714,7 @@ static void pcache1Destroy(sqlite3_pcache *p){ PGroup *pGroup = pCache->pGroup; assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) ); pcache1EnterMutex(pGroup); - pcache1TruncateUnsafe(pCache, 0); + if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0); assert( pGroup->nMaxPage >= pCache->nMax ); pGroup->nMaxPage -= pCache->nMax; assert( pGroup->nMinPage >= pCache->nMin ); @@ -42710,7 +46778,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); assert( sqlite3_mutex_notheld(pcache1.mutex) ); - if( sqlite3GlobalConfig.nPage==0 ){ + if( sqlite3GlobalConfig.pPage==0 ){ PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFreeisPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } @@ -42745,10 +46813,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats( PgHdr1 *p; int nRecyclable = 0; for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){ - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); nRecyclable++; } - *pnCurrent = pcache1.grp.nCurrentPage; + *pnCurrent = pcache1.grp.nPurgeable; *pnMax = (int)pcache1.grp.nMaxPage; *pnMin = (int)pcache1.grp.nMinPage; *pnRecyclable = nRecyclable; @@ -42816,8 +46884,9 @@ SQLITE_PRIVATE void sqlite3PcacheStats( ** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST ** primitives are constant time. The cost of DESTROY is O(N). ** -** There is an added cost of O(N) when switching between TEST and -** SMALLEST primitives. +** TEST and SMALLEST may not be used by the same RowSet. This used to +** be possible, but the feature was not used, so it was removed in order +** to simplify the code. */ /* #include "sqliteInt.h" */ @@ -42938,9 +47007,11 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){ */ static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){ assert( p!=0 ); - if( p->nFresh==0 ){ + if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/ + /* We could allocate a fresh RowSetEntry each time one is needed, but it + ** is more efficient to pull a preallocated entry from the pool */ struct RowSetChunk *pNew; - pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew)); + pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew)); if( pNew==0 ){ return 0; } @@ -42972,7 +47043,9 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){ pEntry->pRight = 0; pLast = p->pLast; if( pLast ){ - if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){ + if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/ + /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags + ** where possible */ p->rsFlags &= ~ROWSET_SORTED; } pLast->pRight = pEntry; @@ -42996,28 +47069,26 @@ static struct RowSetEntry *rowSetEntryMerge( struct RowSetEntry *pTail; pTail = &head; - while( pA && pB ){ + assert( pA!=0 && pB!=0 ); + for(;;){ assert( pA->pRight==0 || pA->v<=pA->pRight->v ); assert( pB->pRight==0 || pB->v<=pB->pRight->v ); - if( pA->vv ){ - pTail->pRight = pA; + if( pA->v<=pB->v ){ + if( pA->vv ) pTail = pTail->pRight = pA; pA = pA->pRight; - pTail = pTail->pRight; - }else if( pB->vv ){ - pTail->pRight = pB; - pB = pB->pRight; - pTail = pTail->pRight; + if( pA==0 ){ + pTail->pRight = pB; + break; + } }else{ - pA = pA->pRight; + pTail = pTail->pRight = pB; + pB = pB->pRight; + if( pB==0 ){ + pTail->pRight = pA; + break; + } } } - if( pA ){ - assert( pA->pRight==0 || pA->v<=pA->pRight->v ); - pTail->pRight = pA; - }else{ - assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v ); - pTail->pRight = pB; - } return head.pRight; } @@ -43040,9 +47111,10 @@ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){ aBucket[i] = pIn; pIn = pNext; } - pIn = 0; - for(i=0; i1 ){ /*OPTIMIZATION-IF-TRUE*/ + /* This branch causes a *balanced* tree to be generated. A valid tree + ** is still generated without this branch, but the tree is wildly + ** unbalanced and inefficient. */ + pLeft = rowSetNDeepTree(ppList, iDepth-1); + p = *ppList; + if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/ + /* It is safe to always return here, but the resulting tree + ** would be unbalanced */ + return pLeft; + } + p->pLeft = pLeft; + *ppList = p->pRight; + p->pRight = rowSetNDeepTree(ppList, iDepth-1); + }else{ p = *ppList; *ppList = p->pRight; p->pLeft = p->pRight = 0; - return p; } - pLeft = rowSetNDeepTree(ppList, iDepth-1); - p = *ppList; - if( p==0 ){ - return pLeft; - } - p->pLeft = pLeft; - *ppList = p->pRight; - p->pRight = rowSetNDeepTree(ppList, iDepth-1); return p; } @@ -43137,59 +47215,37 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){ return p; } -/* -** Take all the entries on p->pEntry and on the trees in p->pForest and -** sort them all together into one big ordered list on p->pEntry. -** -** This routine should only be called once in the life of a RowSet. -*/ -static void rowSetToList(RowSet *p){ - - /* This routine is called only once */ - assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); - - if( (p->rsFlags & ROWSET_SORTED)==0 ){ - p->pEntry = rowSetEntrySort(p->pEntry); - } - - /* While this module could theoretically support it, sqlite3RowSetNext() - ** is never called after sqlite3RowSetText() for the same RowSet. So - ** there is never a forest to deal with. Should this change, simply - ** remove the assert() and the #if 0. */ - assert( p->pForest==0 ); -#if 0 - while( p->pForest ){ - struct RowSetEntry *pTree = p->pForest->pLeft; - if( pTree ){ - struct RowSetEntry *pHead, *pTail; - rowSetTreeToList(pTree, &pHead, &pTail); - p->pEntry = rowSetEntryMerge(p->pEntry, pHead); - } - p->pForest = p->pForest->pRight; - } -#endif - p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */ -} - /* ** Extract the smallest element from the RowSet. ** Write the element into *pRowid. Return 1 on success. Return ** 0 if the RowSet is already empty. ** ** After this routine has been called, the sqlite3RowSetInsert() -** routine may not be called again. +** routine may not be called again. +** +** This routine may not be called after sqlite3RowSetTest() has +** been used. Older versions of RowSet allowed that, but as the +** capability was not used by the code generator, it was removed +** for code economy. */ SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ assert( p!=0 ); + assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */ /* Merge the forest into a single sorted list on first call */ - if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p); + if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + p->pEntry = rowSetEntrySort(p->pEntry); + } + p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT; + } /* Return the next entry on the list */ if( p->pEntry ){ *pRowid = p->pEntry->v; p->pEntry = p->pEntry->pRight; - if( p->pEntry==0 ){ + if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/ + /* Free memory immediately, rather than waiting on sqlite3_finalize() */ sqlite3RowSetClear(p); } return 1; @@ -43212,13 +47268,15 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 /* This routine is never called after sqlite3RowSetNext() */ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); - /* Sort entries into the forest on the first test of a new batch + /* Sort entries into the forest on the first test of a new batch. + ** To save unnecessary work, only do this when the batch number changes. */ - if( iBatch!=pRowSet->iBatch ){ + if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/ p = pRowSet->pEntry; if( p ){ struct RowSetEntry **ppPrevTree = &pRowSet->pForest; - if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ + if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + /* Only sort the current set of entiries if they need it */ p = rowSetEntrySort(p); } for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ @@ -43308,21 +47366,21 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 ** the implementation of each function in log.c for further details. */ -#ifndef _WAL_H_ -#define _WAL_H_ +#ifndef SQLITE_WAL_H +#define SQLITE_WAL_H /* #include "sqliteInt.h" */ -/* Additional values that can be added to the sync_flags argument of -** sqlite3WalFrames(): +/* Macros for extracting appropriate sync flags for either transaction +** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)): */ -#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */ -#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */ +#define WAL_SYNC_FLAGS(X) ((X)&0x03) +#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03) #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 # define sqlite3WalLimit(x,y) -# define sqlite3WalClose(w,x,y,z) 0 +# define sqlite3WalClose(v,w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) # define sqlite3WalDbsize(y) 0 @@ -43332,7 +47390,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 -# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0 +# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalHeapMemory(z) 0 @@ -43350,7 +47408,7 @@ typedef struct Wal Wal; /* Open and close a connection to a write-ahead log. */ SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**); -SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); +SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *); /* Set the limiting size of a WAL file. */ SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64); @@ -43393,6 +47451,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int); /* Copy pages from the log to the database file */ SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Write-ahead log connection */ + sqlite3 *db, /* Check this handle's interrupt flag */ int eMode, /* One of PASSIVE, FULL and RESTART */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ @@ -43424,6 +47483,7 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); #ifdef SQLITE_ENABLE_SNAPSHOT SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal); #endif #ifdef SQLITE_ENABLE_ZIPVFS @@ -43437,7 +47497,7 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal); #endif /* ifndef SQLITE_OMIT_WAL */ -#endif /* _WAL_H_ */ +#endif /* SQLITE_WAL_H */ /************** End of wal.h *************************************************/ /************** Continuing where we left off in pager.c **********************/ @@ -43548,8 +47608,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file ** struct as its argument. */ -#define PAGERID(p) ((int)(p->fd)) -#define FILEHANDLEID(fd) ((int)fd) +#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd)) +#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd)) /* ** The Pager.eState variable stores the current 'state' of a pager. A @@ -43848,6 +47908,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ */ #define MAX_SECTOR_SIZE 0x10000 + /* ** An instance of the following structure is allocated for each active ** savepoint and statement transaction in the system. All such structures @@ -44035,6 +48096,18 @@ struct PagerSavepoint { ** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode ** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX ** sub-codes. +** +** syncFlags, walSyncFlags +** +** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03). +** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode +** and contains the flags used to sync the checkpoint operations in the +** lower two bits, and sync flags used for transaction commits in the WAL +** file in bits 0x04 and 0x08. In other words, to get the correct sync flags +** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct +** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note +** that with synchronous=NORMAL in WAL mode, transaction commit is not synced +** meaning that the 0x04 and 0x08 bits are both zero. */ struct Pager { sqlite3_vfs *pVfs; /* OS functions to use for IO */ @@ -44043,9 +48116,9 @@ struct Pager { u8 useJournal; /* Use a rollback journal on this file */ u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ - u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ - u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ + u8 extraSync; /* sync directory after journal delete */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ + u8 walSyncFlags; /* See description above */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ @@ -44111,6 +48184,7 @@ struct Pager { int nRead; /* Database pages read */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ + int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ #ifdef SQLITE_HAS_CODEC void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ @@ -44231,13 +48305,20 @@ static const unsigned char aJournalMagic[] = { #define isOpen(pFd) ((pFd)->pMethods!=0) /* -** Return true if this pager uses a write-ahead log instead of the usual -** rollback journal. Otherwise false. +** 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. */ -#ifndef SQLITE_OMIT_WAL -static int pagerUseWal(Pager *pPager){ - return (pPager->pWal!=0); +#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; } +#endif +#ifndef SQLITE_OMIT_WAL +# define pagerUseWal(x) ((x)->pWal!=0) #else # define pagerUseWal(x) 0 # define pagerRollbackWal(x) 0 @@ -44290,6 +48371,7 @@ static int assert_pager_state(Pager *p){ ** state. */ if( MEMDB ){ + assert( !isOpen(p->fd) ); assert( p->noSync ); assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_MEMORY @@ -44356,6 +48438,7 @@ static int assert_pager_state(Pager *p){ assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL + || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); assert( pPager->dbOrigSize<=pPager->dbHintSize ); break; @@ -44367,6 +48450,7 @@ static int assert_pager_state(Pager *p){ assert( isOpen(p->jfd) || p->journalMode==PAGER_JOURNALMODE_OFF || p->journalMode==PAGER_JOURNALMODE_WAL + || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); break; @@ -44376,7 +48460,7 @@ static int assert_pager_state(Pager *p){ ** back to OPEN state. */ assert( pPager->errCode!=SQLITE_OK ); - assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); + assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile ); break; } @@ -44435,6 +48519,33 @@ static char *print_pager_state(Pager *p){ } #endif +/* Forward references to the various page getters */ +static int getPageNormal(Pager*,Pgno,DbPage**,int); +static int getPageError(Pager*,Pgno,DbPage**,int); +#if SQLITE_MAX_MMAP_SIZE>0 +static int getPageMMap(Pager*,Pgno,DbPage**,int); +#endif + +/* +** Set the Pager.xGet method for the appropriate routine used to fetch +** content from the pager. +*/ +static void setGetterMethod(Pager *pPager){ + if( pPager->errCode ){ + pPager->xGet = getPageError; +#if SQLITE_MAX_MMAP_SIZE>0 + }else if( USEFETCH(pPager) +#ifdef SQLITE_HAS_CODEC + && pPager->xCodec==0 +#endif + ){ + pPager->xGet = getPageMMap; +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + }else{ + pPager->xGet = getPageNormal; + } +} + /* ** Return true if it is necessary to write page *pPg into the sub-journal. ** A page needs to be written into the sub-journal if there exists one @@ -44550,34 +48661,47 @@ static int pagerLockDb(Pager *pPager, int eLock){ } /* -** This function determines whether or not the atomic-write optimization -** can be used with this pager. The optimization can be used if: +** This function determines whether or not the atomic-write or +** atomic-batch-write optimizations can be used with this pager. The +** atomic-write optimization can be used if: ** ** (a) the value returned by OsDeviceCharacteristics() indicates that ** a database page may be written atomically, and ** (b) the value returned by OsSectorSize() is less than or equal ** to the page size. ** -** The optimization is also always enabled for temporary files. It is -** an error to call this function if pPager is opened on an in-memory -** database. +** If it can be used, then the value returned is the size of the journal +** file when it contains rollback data for exactly one page. ** -** If the optimization cannot be used, 0 is returned. If it can be used, -** then the value returned is the size of the journal file when it -** contains rollback data for exactly one page. +** The atomic-batch-write optimization can be used if OsDeviceCharacteristics() +** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is +** returned in this case. +** +** If neither optimization can be used, 0 is returned. */ -#ifdef SQLITE_ENABLE_ATOMIC_WRITE static int jrnlBufferSize(Pager *pPager){ assert( !MEMDB ); - if( !pPager->tempFile ){ - int dc; /* Device characteristics */ - int nSector; /* Sector size */ - int szPage; /* Page size */ - assert( isOpen(pPager->fd) ); - dc = sqlite3OsDeviceCharacteristics(pPager->fd); - nSector = pPager->sectorSize; - szPage = pPager->pageSize; +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + int dc; /* Device characteristics */ + + assert( isOpen(pPager->fd) ); + dc = sqlite3OsDeviceCharacteristics(pPager->fd); +#else + UNUSED_PARAMETER(pPager); +#endif + +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){ + return -1; + } +#endif + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + { + int nSector = pPager->sectorSize; + int szPage = pPager->pageSize; assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); @@ -44587,9 +48711,11 @@ static int jrnlBufferSize(Pager *pPager){ } return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); -} #endif + return 0; +} + /* ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking ** on the cache using a hash function. This is used for testing @@ -44671,6 +48797,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) || len>=nMaster + || len>szJ-16 || len==0 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) @@ -44748,6 +48875,7 @@ static i64 journalHdrOffset(Pager *pPager){ static int zeroJournalHdr(Pager *pPager, int doTruncate){ int rc = SQLITE_OK; /* Return code */ assert( isOpen(pPager->jfd) ); + assert( !sqlite3JournalIsInMemory(pPager->jfd) ); if( pPager->journalOff ){ const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */ @@ -45129,7 +49257,7 @@ static void releaseAllSavepoints(Pager *pPager){ for(ii=0; iinSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } - if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){ + if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){ sqlite3OsClose(pPager->sjfd); } sqlite3_free(pPager->aSavepoint); @@ -45235,13 +49363,18 @@ static void pager_unlock(Pager *pPager){ ** it can safely move back to PAGER_OPEN state. This happens in both ** normal and exclusive-locking mode. */ + assert( pPager->errCode==SQLITE_OK || !MEMDB ); if( pPager->errCode ){ - assert( !MEMDB ); - pager_reset(pPager); - pPager->changeCountDone = pPager->tempFile; - pPager->eState = PAGER_OPEN; - pPager->errCode = SQLITE_OK; + if( pPager->tempFile==0 ){ + pager_reset(pPager); + pPager->changeCountDone = 0; + pPager->eState = PAGER_OPEN; + }else{ + pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER); + } if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); + pPager->errCode = SQLITE_OK; + setGetterMethod(pPager); } pPager->journalOff = 0; @@ -45279,12 +49412,36 @@ static int pager_error(Pager *pPager, int rc){ if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){ pPager->errCode = rc; pPager->eState = PAGER_ERROR; + setGetterMethod(pPager); } return rc; } static int pager_truncate(Pager *pPager, Pgno nPage); +/* +** The write transaction open on pPager is being committed (bCommit==1) +** or rolled back (bCommit==0). +** +** Return TRUE if and only if all dirty pages should be flushed to disk. +** +** Rules: +** +** * For non-TEMP databases, always sync to disk. This is necessary +** for transactions to be durable. +** +** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing +** file has been created already (via a spill on pagerStress()) and +** when the number of dirty pages in memory exceeds 25% of the total +** cache size. +*/ +static int pagerFlushOnCommit(Pager *pPager, int bCommit){ + if( pPager->tempFile==0 ) return 1; + if( !bCommit ) return 0; + if( !isOpen(pPager->fd) ) return 0; + return (sqlite3PCachePercentDirty(pPager->pPCache)>=25); +} + /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called @@ -45362,13 +49519,15 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ } releaseAllSavepoints(pPager); - assert( isOpen(pPager->jfd) || pPager->pInJournal==0 ); + assert( isOpen(pPager->jfd) || pPager->pInJournal==0 + || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC) + ); if( isOpen(pPager->jfd) ){ assert( !pagerUseWal(pPager) ); /* Finalize the journal file. */ - if( sqlite3IsMemJournal(pPager->jfd) ){ - assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); + if( sqlite3JournalIsInMemory(pPager->jfd) ){ + /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */ sqlite3OsClose(pPager->jfd); }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){ if( pPager->journalOff==0 ){ @@ -45388,22 +49547,23 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ - rc = zeroJournalHdr(pPager, hasMaster); + rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile); pPager->journalOff = 0; }else{ /* This branch may be executed with Pager.journalMode==MEMORY if ** a hot-journal was just rolled back. In this case the journal ** file should be closed and deleted. If this connection writes to - ** the database file, it will do so using an in-memory journal. + ** the database file, it will do so using an in-memory journal. */ - int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd)); + int bDelete = !pPager->tempFile; + assert( sqlite3JournalIsInMemory(pPager->jfd)==0 ); assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE || pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->journalMode==PAGER_JOURNALMODE_WAL ); sqlite3OsClose(pPager->jfd); if( bDelete ){ - rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); + rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, pPager->extraSync); } } } @@ -45422,8 +49582,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; pPager->nRec = 0; - sqlite3PcacheCleanAll(pPager->pPCache); - sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); + if( rc==SQLITE_OK ){ + if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){ + sqlite3PcacheCleanAll(pPager->pPCache); + }else{ + sqlite3PcacheClearWritable(pPager->pPCache); + } + sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); + } if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in @@ -45601,6 +49767,11 @@ static int pager_playback_one_page( char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ +#ifdef SQLITE_HAS_CODEC + /* The jrnlEnc flag is true if Journal pages should be passed through + ** the codec. It is false for pure in-memory journals. */ + const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); +#endif assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ @@ -45707,7 +49878,7 @@ static int pager_playback_one_page( pPg = sqlite3PagerLookup(pPager, pgno); } assert( pPg || !MEMDB ); - assert( pPager->eState!=PAGER_OPEN || pPg==0 ); + assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile ); PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n", PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData), (isMainJrnl?"main-journal":"sub-journal") @@ -45724,14 +49895,34 @@ static int pager_playback_one_page( i64 ofst = (pgno-1)*(i64)pPager->pageSize; testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); assert( !pagerUseWal(pPager) ); + + /* Write the data read from the journal back into the database file. + ** This is usually safe even for an encrypted database - as the data + ** was encrypted before it was written to the journal file. The exception + ** is if the data was just read from an in-memory sub-journal. In that + ** case it must be encrypted here before it is copied into the database + ** file. */ +#ifdef SQLITE_HAS_CODEC + if( !jrnlEnc ){ + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); + rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + }else +#endif rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ - CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM); +#ifdef SQLITE_HAS_CODEC + if( jrnlEnc ){ + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); + }else +#endif sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); - CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData); } }else if( !isMainJrnl && pPg==0 ){ /* If this is a rollback of a savepoint and data was not written to @@ -45757,7 +49948,6 @@ static int pager_playback_one_page( assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 ); pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK; if( rc!=SQLITE_OK ) return rc; - pPg->flags &= ~PGHDR_NEED_READ; sqlite3PcacheMakeDirty(pPg); } if( pPg ){ @@ -45771,29 +49961,10 @@ static int pager_playback_one_page( pData = pPg->pData; memcpy(pData, (u8*)aData, pPager->pageSize); pPager->xReiniter(pPg); - if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){ - /* If the contents of this page were just restored from the main - ** journal file, then its content must be as they were when the - ** transaction was first opened. In this case we can mark the page - ** as clean, since there will be no need to write it out to the - ** database. - ** - ** There is one exception to this rule. If the page is being rolled - ** back as part of a savepoint (or statement) rollback from an - ** unsynced portion of the main journal file, then it is not safe - ** to mark the page as clean. This is because marking the page as - ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is - ** already in the journal file (recorded in Pager.pInJournal) and - ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to - ** again within this transaction, it will be marked as dirty but - ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially - ** be written out into the database file before its journal file - ** segment is synced. If a crash occurs during or following this, - ** database corruption may ensue. - */ - assert( !pagerUseWal(pPager) ); - sqlite3PcacheMakeClean(pPg); - } + /* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But + ** that call was dangerous and had no detectable benefit since the cache + ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so + ** has been removed. */ pager_set_pagehash(pPg); /* If this was page 1, then restore the value of Pager.dbFileVers. @@ -45803,7 +49974,9 @@ static int pager_playback_one_page( } /* Decode the page just read from disk */ - CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM); +#if SQLITE_HAS_CODEC + if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } +#endif sqlite3PcacheRelease(pPg); } return rc; @@ -45869,7 +50042,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){ pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); if( !pMaster ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); @@ -45886,7 +50059,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){ nMasterPtr = pVfs->mxPathname+1; zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); if( !zMasterJournal ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto delmaster_out; } zMasterPtr = &zMasterJournal[nMasterJournal+1]; @@ -46116,6 +50289,7 @@ static int pager_playback(Pager *pPager, int isHot){ char *zMaster = 0; /* Name of master journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ int nPlayback = 0; /* Total number of pages restored from journal */ + u32 savedPageSize = pPager->pageSize; /* Figure out how many records are in the journal. Abort early if ** the journal is empty. @@ -46134,7 +50308,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** TODO: Technically the following is an error because it assumes that ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c, - ** mxPathname is 512, which is the same as the minimum allowable value + ** mxPathname is 512, which is the same as the minimum allowable value ** for pageSize. */ zMaster = pPager->pTmpSpace; @@ -46245,6 +50419,9 @@ static int pager_playback(Pager *pPager, int isHot){ assert( 0 ); end_playback: + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1); + } /* Following a rollback, the database file should be back in its original ** state prior to the start of the transaction, so invoke the ** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the @@ -46303,7 +50480,8 @@ end_playback: /* -** Read the content for page pPg out of the database file and into +** Read the content for page pPg out of the database file (or out of +** the WAL if that is where the most recent copy if found) into ** pPg->pData. A shared lock or greater must be held on the database ** file before this function is called. ** @@ -46313,30 +50491,33 @@ end_playback: ** If an IO error occurs, then the IO error is returned to the caller. ** Otherwise, SQLITE_OK is returned. */ -static int readDbPage(PgHdr *pPg, u32 iFrame){ +static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ - Pgno pgno = pPg->pgno; /* Page number to read */ int rc = SQLITE_OK; /* Return code */ - int pgsz = pPager->pageSize; /* Number of bytes to read */ + +#ifndef SQLITE_OMIT_WAL + u32 iFrame = 0; /* Frame of WAL containing pgno */ assert( pPager->eState>=PAGER_READER && !MEMDB ); assert( isOpen(pPager->fd) ); -#ifndef SQLITE_OMIT_WAL + if( pagerUseWal(pPager) ){ + rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); + if( rc ) return rc; + } if( iFrame ){ - /* Try to pull the page from the write-ahead log. */ - rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); + rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData); }else #endif { - i64 iOffset = (pgno-1)*(i64)pPager->pageSize; - rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); + i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize; + rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } - if( pgno==1 ){ + if( pPg->pgno==1 ){ if( rc ){ /* If the read is unsuccessful, set the dbFileVers[] to something ** that will never be a valid file version. dbFileVers[] is a copy @@ -46356,13 +50537,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } - CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM); + CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); - IOTRACE(("PGIN %p %d\n", pPager, pgno)); + IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); PAGERTRACE(("FETCH %d page %d hash(%08x)\n", - PAGERID(pPager), pgno, pager_pagehash(pPg))); + PAGERID(pPager), pPg->pgno, pager_pagehash(pPg))); return rc; } @@ -46413,11 +50594,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){ if( sqlite3PcachePageRefcount(pPg)==1 ){ sqlite3PcacheDrop(pPg); }else{ - u32 iFrame = 0; - rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); - if( rc==SQLITE_OK ){ - rc = readDbPage(pPg, iFrame); - } + rc = readDbPage(pPg); if( rc==SQLITE_OK ){ pPager->xReiniter(pPg); } @@ -46584,21 +50761,20 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ */ assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK ); + assert( isOpen(pPager->fd) ); + assert( pPager->tempFile==0 ); nPage = sqlite3WalDbsize(pPager->pWal); /* If the number of pages in the database is not available from the - ** WAL sub-system, determine the page counte based on the size of + ** WAL sub-system, determine the page count based on the size of ** the database file. If the size of the database file is not an ** integer multiple of the page-size, round up the result. */ - if( nPage==0 ){ + if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){ i64 n = 0; /* Size of db file in bytes */ - assert( isOpen(pPager->fd) || pPager->tempFile ); - if( isOpen(pPager->fd) ){ - int rc = sqlite3OsFileSize(pPager->fd, &n); - if( rc!=SQLITE_OK ){ - return rc; - } + int rc = sqlite3OsFileSize(pPager->fd, &n); + if( rc!=SQLITE_OK ){ + return rc; } nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize); } @@ -46641,23 +50817,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){ if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ - Pgno nPage; /* Size of the database file */ - - rc = pagerPagecount(pPager, &nPage); - if( rc ) return rc; - if( nPage==0 ){ - rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); - if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK; - isWal = 0; - }else{ - rc = sqlite3OsAccess( - pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal - ); - } + rc = sqlite3OsAccess( + pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal + ); if( rc==SQLITE_OK ){ if( isWal ){ - testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); - rc = sqlite3PagerOpenWal(pPager, 0); + Pgno nPage; /* Size of the database file */ + + rc = pagerPagecount(pPager, &nPage); + if( rc ) return rc; + if( nPage==0 ){ + rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); + }else{ + testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); + rc = sqlite3PagerOpenWal(pPager, 0); + } }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } @@ -46716,7 +50890,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ if( pSavepoint ){ pDone = sqlite3BitvecCreate(pSavepoint->nOrig); if( !pDone ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } } @@ -46837,6 +51011,7 @@ static void pagerFixMaplimit(Pager *pPager){ sqlite3_int64 sz; sz = pPager->szMmap; pPager->bUseFetch = (sz>0); + setGetterMethod(pPager); sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz); } #endif @@ -46863,7 +51038,7 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){ ** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness ** of the database to damage due to OS crashes or power failures by ** changing the number of syncs()s when writing the journals. -** There are three levels: +** There are four levels: ** ** OFF sqlite3OsSync() is never called. This is the default ** for temporary and transient files. @@ -46883,6 +51058,10 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){ ** assurance that the journal will not be corrupted to the ** point of causing damage to the database during rollback. ** +** EXTRA This is like FULL except that is also syncs the directory +** that contains the rollback journal after the rollback +** journal is unlinked. +** ** The above is for a rollback-journal mode. For WAL mode, OFF continues ** to mean that no syncs ever occur. NORMAL means that the WAL is synced ** prior to the start of checkpoint and that the database file is synced @@ -46890,7 +51069,8 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){ ** was written back into the database. But no sync operations occur for ** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL ** file is synced following each commit operation, in addition to the -** syncs associated with NORMAL. +** syncs associated with NORMAL. There is no difference between FULL +** and EXTRA for WAL mode. ** ** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The ** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync @@ -46909,25 +51089,28 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags( unsigned pgFlags /* Various flags */ ){ unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; - assert( level>=1 && level<=3 ); - pPager->noSync = (level==1 || pPager->tempFile) ?1:0; - pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0; + if( pPager->tempFile ){ + pPager->noSync = 1; + pPager->fullSync = 0; + pPager->extraSync = 0; + }else{ + pPager->noSync = level==PAGER_SYNCHRONOUS_OFF ?1:0; + pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0; + pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0; + } if( pPager->noSync ){ pPager->syncFlags = 0; - pPager->ckptSyncFlags = 0; }else if( pgFlags & PAGER_FULLFSYNC ){ pPager->syncFlags = SQLITE_SYNC_FULL; - pPager->ckptSyncFlags = SQLITE_SYNC_FULL; - }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){ - pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->ckptSyncFlags = SQLITE_SYNC_FULL; }else{ pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; } - pPager->walSyncFlags = pPager->syncFlags; + pPager->walSyncFlags = (pPager->syncFlags<<2); if( pPager->fullSync ){ - pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS; + pPager->walSyncFlags |= pPager->syncFlags; + } + if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){ + pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2); } if( pgFlags & PAGER_CACHESPILL ){ pPager->doNotSpill &= ~SPILLFLAG_OFF; @@ -47073,7 +51256,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR } if( rc==SQLITE_OK ){ pNew = (char *)sqlite3PageMalloc(pageSize); - if( !pNew ) rc = SQLITE_NOMEM; + if( !pNew ) rc = SQLITE_NOMEM_BKPT; } if( rc==SQLITE_OK ){ @@ -47322,6 +51505,7 @@ static int pagerSyncHotJournal(Pager *pPager){ return rc; } +#if SQLITE_MAX_MMAP_SIZE>0 /* ** Obtain a reference to a memory mapped page object for page number pgno. ** The new object will use the pointer pData, obtained from xFetch(). @@ -47344,12 +51528,13 @@ static int pagerAcquireMapPage( *ppPage = p = pPager->pMmapFreelist; pPager->pMmapFreelist = p->pDirty; p->pDirty = 0; - memset(p->pExtra, 0, pPager->nExtra); + assert( pPager->nExtra>=8 ); + memset(p->pExtra, 0, 8); }else{ *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra); if( p==0 ){ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } p->pExtra = (void *)&p[1]; p->flags = PGHDR_MMAP; @@ -47369,6 +51554,7 @@ static int pagerAcquireMapPage( return SQLITE_OK; } +#endif /* ** Release a reference to page pPg. pPg must have been returned by an @@ -47411,9 +51597,10 @@ static void pagerFreeMapHdrs(Pager *pPager){ ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ -SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){ +SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ u8 *pTmp = (u8 *)pPager->pTmpSpace; + assert( db || pagerUseWal(pPager)==0 ); assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); @@ -47421,7 +51608,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){ /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL - sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); + assert( db || pPager->pWal==0 ); + sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, + (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp) + ); pPager->pWal = 0; #endif pager_reset(pPager); @@ -47663,8 +51853,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ /* This function is only called for rollback pagers in WRITER_DBMOD state. */ assert( !pagerUseWal(pPager) ); - assert( pPager->eState==PAGER_WRITER_DBMOD ); + assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD ); assert( pPager->eLock==EXCLUSIVE_LOCK ); + assert( isOpen(pPager->fd) || pList->pDirty==0 ); /* If the file is a temp-file has not yet been opened, open it now. It ** is not possible for rc to be other than SQLITE_OK if this branch @@ -47707,7 +51898,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ if( pList->pgno==1 ) pager_write_changecounter(pList); /* Encode the database */ - CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData); + CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); @@ -47752,11 +51943,14 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ static int openSubJournal(Pager *pPager){ int rc = SQLITE_OK; if( !isOpen(pPager->sjfd) ){ + const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE + | SQLITE_OPEN_DELETEONCLOSE; + int nStmtSpill = sqlite3Config.nStmtSpill; if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){ - sqlite3MemJournalOpen(pPager->sjfd); - }else{ - rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL); + nStmtSpill = -1; } + rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill); } return rc; } @@ -47793,8 +51987,13 @@ static int subjournalPage(PgHdr *pPg){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; - - CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2); + +#if SQLITE_HAS_CODEC + if( !pPager->subjInMemory ){ + CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + }else +#endif + pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); if( rc==SQLITE_OK ){ @@ -47878,6 +52077,13 @@ static int pagerStress(void *p, PgHdr *pPg){ rc = pagerWalFrames(pPager, pPg, 0, 0); } }else{ + +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( pPager->tempFile==0 ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ) return pager_error(pPager, rc); + } +#endif /* Sync the journal file if required. */ if( pPg->flags&PGHDR_NEED_SYNC @@ -47936,7 +52142,9 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){ ** ** The nExtra parameter specifies the number of bytes of space allocated ** along with each page reference. This space is available to the user -** via the sqlite3PagerGetExtra() API. +** via the sqlite3PagerGetExtra() API. When a new page is allocated, the +** first 8 bytes of this space are zeroed but the remainder is uninitialized. +** (The extra space is used by btree as the MemPage object.) ** ** The flags argument is used to specify properties that affect the ** operation of the pager. It should be passed some bitwise combination @@ -47977,18 +52185,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen( int nUri = 0; /* Number of bytes of URI args at *zUri */ /* Figure out how much space is required for each journal file-handle - ** (there are two of them, the main journal and the sub-journal). This - ** is the maximum space required for an in-memory journal file handle - ** and a regular journal file-handle. Note that a "regular journal-handle" - ** may be a wrapper capable of caching the first portion of the journal - ** file in memory to implement the atomic-write optimization (see - ** source file journal.c). - */ - if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){ - journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); - }else{ - journalFileSize = ROUND8(sqlite3MemJournalSize()); - } + ** (there are two of them, the main journal and the sub-journal). */ + journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); /* Set the output variable to NULL in case an error occurs. */ *ppPager = 0; @@ -47998,7 +52196,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( memDb = 1; if( zFilename && zFilename[0] ){ zPathname = sqlite3DbStrDup(0, zFilename); - if( zPathname==0 ) return SQLITE_NOMEM; + if( zPathname==0 ) return SQLITE_NOMEM_BKPT; nPathname = sqlite3Strlen30(zPathname); zFilename = 0; } @@ -48014,7 +52212,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( nPathname = pVfs->mxPathname+1; zPathname = sqlite3DbMallocRaw(0, nPathname*2); if( zPathname==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); @@ -48067,7 +52265,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); if( !pPtr ){ sqlite3DbFree(0, zPathname); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pPager = (Pager*)(pPtr); pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager))); @@ -48176,8 +52374,8 @@ act_like_temp_file: /* Initialize the PCache object. */ if( rc==SQLITE_OK ){ - assert( nExtra<1000 ); nExtra = ROUND8(nExtra); + assert( nExtra>=8 && nExtra<1000 ); rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); } @@ -48216,14 +52414,14 @@ act_like_temp_file: pPager->noSync = pPager->tempFile; if( pPager->noSync ){ assert( pPager->fullSync==0 ); + assert( pPager->extraSync==0 ); assert( pPager->syncFlags==0 ); assert( pPager->walSyncFlags==0 ); - assert( pPager->ckptSyncFlags==0 ); }else{ pPager->fullSync = 1; + pPager->extraSync = 0; pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS; - pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; + pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2); } /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ @@ -48240,6 +52438,7 @@ act_like_temp_file: /* pPager->xBusyHandler = 0; */ /* pPager->pBusyHandlerArg = 0; */ pPager->xReiniter = xReinit; + setGetterMethod(pPager); /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ @@ -48337,6 +52536,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ if( rc==SQLITE_OK && !locked ){ Pgno nPage; /* Number of pages in database file */ + assert( pPager->tempFile==0 ); rc = pagerPagecount(pPager, &nPage); if( rc==SQLITE_OK ){ /* If the database is zero pages in size, that means that either (1) the @@ -48429,17 +52629,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ /* This routine is only called from b-tree and only when there are no ** outstanding pages. This implies that the pager state should either ** be OPEN or READER. READER is only possible if the pager is or was in - ** exclusive access mode. - */ + ** exclusive access mode. */ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER ); - if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; } + assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){ int bHotJournal = 1; /* True if there exists a hot journal-file */ assert( !MEMDB ); + assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ @@ -48525,7 +52725,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ assert( rc==SQLITE_OK ); rc = pagerSyncHotJournal(pPager); if( rc==SQLITE_OK ){ - rc = pager_playback(pPager, 1); + rc = pager_playback(pPager, !pPager->tempFile); pPager->eState = PAGER_OPEN; } }else if( !pPager->exclusiveMode ){ @@ -48576,19 +52776,14 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** detected. The chance of an undetected change is so small that ** it can be neglected. */ - Pgno nPage = 0; char dbFileVers[sizeof(pPager->dbFileVers)]; - rc = pagerPagecount(pPager, &nPage); - if( rc ) goto failed; - - if( nPage>0 ){ - IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); - rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); - if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ + IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); + if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_IOERR_SHORT_READ ){ goto failed; } - }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } @@ -48621,7 +52816,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ rc = pagerBeginReadTransaction(pPager); } - if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ + if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ rc = pagerPagecount(pPager, &pPager->dbSize); } @@ -48646,16 +52841,24 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** nothing to rollback, so this routine is a no-op. */ static void pagerUnlockIfUnused(Pager *pPager){ - if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ + if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){ + assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */ pagerUnlockAndRollback(pPager); } } /* -** Acquire a reference to page number pgno in pager pPager (a page -** reference has type DbPage*). If the requested reference is +** The page getter methods each try to acquire a reference to a +** page with page number pgno. If the requested reference is ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned. ** +** There are different implementations of the getter method depending +** on the current state of the pager. +** +** getPageNormal() -- The normal getter +** getPageError() -- Used if the pager is in an error state +** getPageMmap() -- Used if memory-mapped I/O is enabled +** ** If the requested page is already in the cache, it is returned. ** Otherwise, a new page object is allocated and populated with data ** read from the database file. In some cases, the pcache module may @@ -48667,14 +52870,14 @@ static void pagerUnlockIfUnused(Pager *pPager){ ** already in the cache when this function is called, then the extra ** data is left as it was when the page object was last used. ** -** If the database image is smaller than the requested page or if a -** non-zero value is passed as the noContent parameter and the +** If the database image is smaller than the requested page or if +** the flags parameter contains the PAGER_GET_NOCONTENT bit and the ** requested page is not already stored in the cache, then no ** actual disk read occurs. In this case the memory image of the ** page is initialized to all zeros. ** -** If noContent is true, it means that we do not care about the contents -** of the page. This occurs in two scenarios: +** If PAGER_GET_NOCONTENT is true, it means that we do not care about +** the contents of the page. This occurs in two scenarios: ** ** a) When reading a free-list leaf page from the database, and ** @@ -48682,8 +52885,8 @@ static void pagerUnlockIfUnused(Pager *pPager){ ** a new page into the cache to be filled with the data read ** from the savepoint journal. ** -** If noContent is true, then the data returned is zeroed instead of -** being read from the database. Additionally, the bits corresponding +** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead +** of being read from the database. Additionally, the bits corresponding ** to pgno in Pager.pInJournal (bitvec of pages already written to the ** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open ** savepoints are set. This means if the page is made writable at any @@ -48701,106 +52904,39 @@ static void pagerUnlockIfUnused(Pager *pPager){ ** Since Lookup() never goes to disk, it never has to deal with locks ** or journal files. */ -SQLITE_PRIVATE int sqlite3PagerGet( +static int getPageNormal( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ int rc = SQLITE_OK; - PgHdr *pPg = 0; - u32 iFrame = 0; /* Frame to read from WAL file */ - const int noContent = (flags & PAGER_GET_NOCONTENT); + PgHdr *pPg; + u8 noContent; /* True if PAGER_GET_NOCONTENT is set */ + sqlite3_pcache_page *pBase; - /* It is acceptable to use a read-only (mmap) page for any page except - ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY - ** flag was specified by the caller. And so long as the db is not a - ** temporary or in-memory database. */ - const int bMmapOk = (pgno>1 && USEFETCH(pPager) - && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) -#ifdef SQLITE_HAS_CODEC - && pPager->xCodec==0 -#endif - ); - - /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here - ** allows the compiler optimizer to reuse the results of the "pgno>1" - ** test in the previous statement, and avoid testing pgno==0 in the - ** common case where pgno is large. */ - if( pgno<=1 && pgno==0 ){ - return SQLITE_CORRUPT_BKPT; - } + assert( pPager->errCode==SQLITE_OK ); assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); - assert( noContent==0 || bMmapOk==0 ); - assert( pPager->hasHeldSharedLock==1 ); - /* If the pager is in the error state, return an error immediately. - ** Otherwise, request the page from the PCache layer. */ - if( pPager->errCode!=SQLITE_OK ){ - rc = pPager->errCode; - }else{ - if( bMmapOk && pagerUseWal(pPager) ){ - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); - if( rc!=SQLITE_OK ) goto pager_acquire_err; - } - - if( bMmapOk && iFrame==0 ){ - void *pData = 0; - - rc = sqlite3OsFetch(pPager->fd, - (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData - ); - - if( rc==SQLITE_OK && pData ){ - if( pPager->eState>PAGER_READER ){ - pPg = sqlite3PagerLookup(pPager, pgno); - } - if( pPg==0 ){ - rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); - }else{ - sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); - } - if( pPg ){ - assert( rc==SQLITE_OK ); - *ppPage = pPg; - return SQLITE_OK; - } - } - if( rc!=SQLITE_OK ){ - goto pager_acquire_err; - } - } - - { - sqlite3_pcache_page *pBase; - pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); - if( pBase==0 ){ - rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); - if( rc!=SQLITE_OK ) goto pager_acquire_err; - if( pBase==0 ){ - pPg = *ppPage = 0; - rc = SQLITE_NOMEM; - goto pager_acquire_err; - } - } - pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); - assert( pPg!=0 ); - } - } - - if( rc!=SQLITE_OK ){ - /* Either the call to sqlite3PcacheFetch() returned an error or the - ** pager was already in the error-state when this function was called. - ** Set pPg to 0 and jump to the exception handler. */ + if( pgno==0 ) return SQLITE_CORRUPT_BKPT; + pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); + if( pBase==0 ){ pPg = 0; - goto pager_acquire_err; + rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); + if( rc!=SQLITE_OK ) goto pager_acquire_err; + if( pBase==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto pager_acquire_err; + } } + pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); assert( pPg==(*ppPage) ); assert( pPg->pgno==pgno ); assert( pPg->pPager==pPager || pPg->pPager==0 ); + noContent = (flags & PAGER_GET_NOCONTENT)!=0; if( pPg->pPager && !noContent ){ /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ @@ -48810,18 +52946,20 @@ SQLITE_PRIVATE int sqlite3PagerGet( }else{ /* The pager cache has created a new page. Its content needs to - ** be initialized. */ - - pPg->pPager = pPager; - - /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page - ** number greater than this, or the unused locking-page, is requested. */ + ** be initialized. But first some error checks: + ** + ** (1) The maximum page number is 2^31 + ** (2) Never try to fetch the locking page + */ if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } - if( MEMDB || pPager->dbSizefd) ){ + pPg->pPager = pPager; + + assert( !isOpen(pPager->fd) || !MEMDB ); + if( !isOpen(pPager->fd) || pPager->dbSizepPager->mxPgno ){ rc = SQLITE_FULL; goto pager_acquire_err; @@ -48845,20 +52983,15 @@ SQLITE_PRIVATE int sqlite3PagerGet( memset(pPg->pData, 0, pPager->pageSize); IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ - if( pagerUseWal(pPager) && bMmapOk==0 ){ - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); - if( rc!=SQLITE_OK ) goto pager_acquire_err; - } assert( pPg->pPager==pPager ); pPager->aStat[PAGER_STAT_MISS]++; - rc = readDbPage(pPg, iFrame); + rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } } pager_set_pagehash(pPg); } - return SQLITE_OK; pager_acquire_err: @@ -48867,11 +53000,109 @@ pager_acquire_err: sqlite3PcacheDrop(pPg); } pagerUnlockIfUnused(pPager); - *ppPage = 0; return rc; } +#if SQLITE_MAX_MMAP_SIZE>0 +/* The page getter for when memory-mapped I/O is enabled */ +static int getPageMMap( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + int rc = SQLITE_OK; + PgHdr *pPg = 0; + u32 iFrame = 0; /* Frame to read from WAL file */ + + /* It is acceptable to use a read-only (mmap) page for any page except + ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY + ** flag was specified by the caller. And so long as the db is not a + ** temporary or in-memory database. */ + const int bMmapOk = (pgno>1 + && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) + ); + + assert( USEFETCH(pPager) ); +#ifdef SQLITE_HAS_CODEC + assert( pPager->xCodec==0 ); +#endif + + /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here + ** allows the compiler optimizer to reuse the results of the "pgno>1" + ** test in the previous statement, and avoid testing pgno==0 in the + ** common case where pgno is large. */ + if( pgno<=1 && pgno==0 ){ + return SQLITE_CORRUPT_BKPT; + } + assert( pPager->eState>=PAGER_READER ); + assert( assert_pager_state(pPager) ); + assert( pPager->hasHeldSharedLock==1 ); + assert( pPager->errCode==SQLITE_OK ); + + if( bMmapOk && pagerUseWal(pPager) ){ + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); + if( rc!=SQLITE_OK ){ + *ppPage = 0; + return rc; + } + } + if( bMmapOk && iFrame==0 ){ + void *pData = 0; + rc = sqlite3OsFetch(pPager->fd, + (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData + ); + if( rc==SQLITE_OK && pData ){ + if( pPager->eState>PAGER_READER || pPager->tempFile ){ + pPg = sqlite3PagerLookup(pPager, pgno); + } + if( pPg==0 ){ + rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); + }else{ + sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); + } + if( pPg ){ + assert( rc==SQLITE_OK ); + *ppPage = pPg; + return SQLITE_OK; + } + } + if( rc!=SQLITE_OK ){ + *ppPage = 0; + return rc; + } + } + return getPageNormal(pPager, pgno, ppPage, flags); +} +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + +/* The page getter method for when the pager is an error state */ +static int getPageError( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + UNUSED_PARAMETER(pgno); + UNUSED_PARAMETER(flags); + assert( pPager->errCode!=SQLITE_OK ); + *ppPage = 0; + return pPager->errCode; +} + + +/* Dispatch all page fetch requests to the appropriate getter method. +*/ +SQLITE_PRIVATE int sqlite3PagerGet( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + return pPager->xGet(pPager, pgno, ppPage, flags); +} + /* ** Acquire a page if it is already in the in-memory cache. Do ** not read the page from disk. Return a pointer to the page, @@ -48897,25 +53128,39 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ /* ** Release a page reference. ** -** If the number of references to the page drop to zero, then the -** page is added to the LRU list. When all references to all pages -** are released, a rollback occurs and the lock on the database is -** removed. +** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be +** used if we know that the page being released is not the last page. +** The btree layer always holds page1 open until the end, so these first +** to routines can be used to release any page other than BtShared.pPage1. +** +** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine +** checks the total number of outstanding pages and if the number of +** pages reaches zero it drops the database lock. */ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){ - Pager *pPager; + TESTONLY( Pager *pPager = pPg->pPager; ) assert( pPg!=0 ); - pPager = pPg->pPager; if( pPg->flags & PGHDR_MMAP ){ + assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */ pagerReleaseMapPage(pPg); }else{ sqlite3PcacheRelease(pPg); } - pagerUnlockIfUnused(pPager); + /* Do not use this routine to release the last reference to page1 */ + assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); } SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){ if( pPg ) sqlite3PagerUnrefNotNull(pPg); } +SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){ + Pager *pPager; + assert( pPg!=0 ); + assert( pPg->pgno==1 ); + assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */ + pPager = pPg->pPager; + sqlite3PcacheRelease(pPg); + pagerUnlockIfUnused(pPager); +} /* ** This function is called at the start of every write transaction. @@ -48955,7 +53200,7 @@ static int pager_open_journal(Pager *pPager){ if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize); if( pPager->pInJournal==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } /* Open the journal file if it is not already open. */ @@ -48963,24 +53208,24 @@ static int pager_open_journal(Pager *pPager){ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ sqlite3MemJournalOpen(pPager->jfd); }else{ - const int flags = /* VFS flags to open journal file */ - SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| - (pPager->tempFile ? - (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL): - (SQLITE_OPEN_MAIN_JOURNAL) - ); + int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; + int nSpill; + if( pPager->tempFile ){ + flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); + nSpill = sqlite3Config.nStmtSpill; + }else{ + flags |= SQLITE_OPEN_MAIN_JOURNAL; + nSpill = jrnlBufferSize(pPager); + } + /* Verify that the database still has the same name as it did when ** it was originally opened. */ rc = databaseIsUnmoved(pPager); if( rc==SQLITE_OK ){ -#ifdef SQLITE_ENABLE_ATOMIC_WRITE - rc = sqlite3JournalOpen( - pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager) + rc = sqlite3JournalOpen ( + pVfs, pPager->zJournal, pPager->jfd, flags, nSpill ); -#else - rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0); -#endif } } assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); @@ -49110,7 +53355,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); - CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2); + CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the @@ -49345,12 +53590,13 @@ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){ assert( (pPg->flags & PGHDR_MMAP)==0 ); assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); - if( pPager->errCode ){ - return pPager->errCode; - }else if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){ + if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){ if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg); return SQLITE_OK; + }else if( pPager->errCode ){ + return pPager->errCode; }else if( pPager->sectorSize > (u32)pPager->pageSize ){ + assert( pPager->tempFile==0 ); return pagerWriteLargeSector(pPg); }else{ return pager_write(pPg); @@ -49381,14 +53627,21 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){ ** ** Tests show that this optimization can quadruple the speed of large ** DELETE operations. +** +** This optimization cannot be used with a temp-file, as the page may +** have been dirty at the start of the transaction. In that case, if +** memory pressure forces page pPg out of the cache, the data does need +** to be written out to disk so that it may be read back in if the +** current transaction is rolled back. */ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; - if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){ + if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){ PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager))); IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) pPg->flags |= PGHDR_DONT_WRITE; pPg->flags &= ~PGHDR_WRITEABLE; + testcase( pPg->flags & PGHDR_NEED_SYNC ); pager_set_pagehash(pPg); } } @@ -49467,7 +53720,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); - CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf); + CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; @@ -49583,17 +53836,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( /* If a prior error occurred, report that error again. */ if( NEVER(pPager->errCode) ) return pPager->errCode; + /* Provide the ability to easily simulate an I/O error during testing */ + if( sqlite3FaultSim(400) ) return SQLITE_IOERR; + PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", pPager->zFilename, zMaster, pPager->dbSize)); /* If no database changes have been made, return early. */ if( pPager->eStatetempFile ); + assert( isOpen(pPager->fd) || pPager->tempFile ); + if( 0==pagerFlushOnCommit(pPager, 1) ){ /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is mostly a no-op. However, any - ** backup in progress needs to be restarted. - */ + ** backup in progress needs to be restarted. */ sqlite3BackupRestart(pPager->pBackup); }else{ if( pagerUseWal(pPager) ){ @@ -49615,6 +53872,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( sqlite3PcacheCleanAll(pPager->pPCache); } }else{ + /* The bBatch boolean is true if the batch-atomic-write commit method + ** should be used. No rollback journal is created if batch-atomic-write + ** is enabled. + */ + sqlite3_file *fd = pPager->fd; +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ + && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) + && !pPager->noSync + && sqlite3JournalIsInMemory(pPager->jfd); +#else +# define bBatch 0 +#endif + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE /* The following block updates the change-counter. Exactly how it ** does this depends on whether or not the atomic-update optimization ** was enabled at compile time, and if this transaction meets the @@ -49638,33 +53910,40 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( ** in 'direct' mode. In this case the journal file will never be ** created for this transaction. */ - #ifdef SQLITE_ENABLE_ATOMIC_WRITE - PgHdr *pPg; - assert( isOpen(pPager->jfd) - || pPager->journalMode==PAGER_JOURNALMODE_OFF - || pPager->journalMode==PAGER_JOURNALMODE_WAL - ); - if( !zMaster && isOpen(pPager->jfd) - && pPager->journalOff==jrnlBufferSize(pPager) - && pPager->dbSize>=pPager->dbOrigSize - && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) - ){ - /* Update the db file change counter via the direct-write method. The - ** following call will modify the in-memory representation of page 1 - ** to include the updated change counter and then write page 1 - ** directly to the database file. Because of the atomic-write - ** property of the host file-system, this is safe. - */ - rc = pager_incr_changecounter(pPager, 1); - }else{ - rc = sqlite3JournalCreate(pPager->jfd); - if( rc==SQLITE_OK ){ - rc = pager_incr_changecounter(pPager, 0); + if( bBatch==0 ){ + PgHdr *pPg; + assert( isOpen(pPager->jfd) + || pPager->journalMode==PAGER_JOURNALMODE_OFF + || pPager->journalMode==PAGER_JOURNALMODE_WAL + ); + if( !zMaster && isOpen(pPager->jfd) + && pPager->journalOff==jrnlBufferSize(pPager) + && pPager->dbSize>=pPager->dbOrigSize + && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) + ){ + /* Update the db file change counter via the direct-write method. The + ** following call will modify the in-memory representation of page 1 + ** to include the updated change counter and then write page 1 + ** directly to the database file. Because of the atomic-write + ** property of the host file-system, this is safe. + */ + rc = pager_incr_changecounter(pPager, 1); + }else{ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc==SQLITE_OK ){ + rc = pager_incr_changecounter(pPager, 0); + } } } - #else +#else +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( zMaster ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + } +#endif rc = pager_incr_changecounter(pPager, 0); - #endif +#endif if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the master journal name into the journal file. If a master @@ -49687,8 +53966,24 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( */ rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; - + + if( bBatch ){ + /* The pager is now in DBMOD state. But regardless of what happens + ** next, attempting to play the journal back into the database would + ** be unsafe. Close it now to make sure that does not happen. */ + sqlite3OsClose(pPager->jfd); + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + } rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); + if( bBatch ){ + if( rc==SQLITE_OK ){ + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); + }else{ + sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); + } + } + if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; @@ -49832,6 +54127,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ */ pPager->errCode = SQLITE_ABORT; pPager->eState = PAGER_ERROR; + setGetterMethod(pPager); return rc; } }else{ @@ -49932,10 +54228,10 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i } /* -** Return true if this is an in-memory pager. +** Return true if this is an in-memory or temp-file backed pager. */ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){ - return MEMDB; + return pPager->tempFile; } /* @@ -49966,7 +54262,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){ pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint ); if( !aNew ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint)); pPager->aSavepoint = aNew; @@ -49982,7 +54278,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){ aNew[ii].iSubRec = pPager->nSubRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); if( !aNew[ii].pInSavepoint ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } if( pagerUseWal(pPager) ){ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData); @@ -50036,7 +54332,11 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ ** savepoint. If no errors occur, SQLITE_OK is returned. */ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ - int rc = pPager->errCode; /* Return code */ + int rc = pPager->errCode; + +#ifdef SQLITE_ENABLE_ZIPVFS + if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK; +#endif assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK ); @@ -50060,7 +54360,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ if( op==SAVEPOINT_RELEASE ){ if( nNew==0 && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ - if( sqlite3IsMemJournal(pPager->sjfd) ){ + if( sqlite3JournalIsInMemory(pPager->sjfd) ){ rc = sqlite3OsTruncate(pPager->sjfd, 0); assert( rc==SQLITE_OK ); } @@ -50077,6 +54377,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ rc = pagerPlaybackSavepoint(pPager, pSavepoint); assert(rc!=SQLITE_DONE); } + +#ifdef SQLITE_ENABLE_ZIPVFS + /* If the cache has been modified but the savepoint cannot be rolled + ** back journal_mode=off, put the pager in the error state. This way, + ** if the VFS used by this pager includes ZipVFS, the entire transaction + ** can be rolled back at the ZipVFS level. */ + else if( + pPager->journalMode==PAGER_JOURNALMODE_OFF + && pPager->eState>=PAGER_WRITER_CACHEMOD + ){ + pPager->errCode = SQLITE_ABORT; + pPager->eState = PAGER_ERROR; + setGetterMethod(pPager); + } +#endif } return rc; @@ -50131,14 +54446,6 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } -/* -** Return true if fsync() calls are disabled for this pager. Return FALSE -** if fsync()s are executed normally. -*/ -SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){ - return pPager->noSync; -} - #ifdef SQLITE_HAS_CODEC /* ** Set or retrieve the codec for this pager @@ -50155,6 +54462,7 @@ SQLITE_PRIVATE void sqlite3PagerSetCodec( pPager->xCodecSizeChng = xCodecSizeChng; pPager->xCodecFree = xCodecFree; pPager->pCodec = pCodec; + setGetterMethod(pPager); pagerReportSize(pPager); } SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ @@ -50223,7 +54531,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i /* In order to be able to rollback, an in-memory database must journal ** the page we are moving from. */ - if( MEMDB ){ + assert( pPager->tempFile || !MEMDB ); + if( pPager->tempFile ){ rc = sqlite3PagerWrite(pPg); if( rc ) return rc; } @@ -50280,7 +54589,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i assert( !pPgOld || pPgOld->nRef==1 ); if( pPgOld ){ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); - if( MEMDB ){ + if( pPager->tempFile ){ /* Do not discard pages from an in-memory database since we might ** need to rollback later. Just move the page out of the way. */ sqlite3PcacheMove(pPgOld, pPager->dbSize+1); @@ -50297,8 +54606,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i ** to exist, in case the transaction needs to roll back. Use pPgOld ** as the original page since it has already been allocated. */ - if( MEMDB ){ - assert( pPgOld ); + if( pPager->tempFile && pPgOld ){ sqlite3PcacheMove(pPgOld, origPgno); sqlite3PagerUnrefNotNull(pPgOld); } @@ -50550,10 +54858,12 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){ ** Unless this is an in-memory or temporary database, clear the pager cache. */ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){ - if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager); + assert( MEMDB==0 || pPager->tempFile ); + if( pPager->tempFile==0 ) pager_reset(pPager); } #endif + #ifndef SQLITE_OMIT_WAL /* ** This function is called when the user invokes "PRAGMA wal_checkpoint", @@ -50562,13 +54872,19 @@ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){ ** ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. */ -SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){ +SQLITE_PRIVATE int sqlite3PagerCheckpoint( + Pager *pPager, /* Checkpoint on this pager */ + sqlite3 *db, /* Db handle used to check for interrupts */ + int eMode, /* Type of checkpoint */ + int *pnLog, /* OUT: Final number of frames in log */ + int *pnCkpt /* OUT: Final number of checkpointed frames */ +){ int rc = SQLITE_OK; if( pPager->pWal ){ - rc = sqlite3WalCheckpoint(pPager->pWal, eMode, + rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, - pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, + pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); } @@ -50585,6 +54901,7 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){ */ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){ const sqlite3_io_methods *pMethods = pPager->fd->pMethods; + if( pPager->noLock ) return 0; return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap); } @@ -50696,7 +55013,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal( ** error (SQLITE_BUSY) is returned and the log connection is not closed. ** If successful, the EXCLUSIVE lock is not released before returning. */ -SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){ +SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ int rc = SQLITE_OK; assert( pPager->journalMode==PAGER_JOURNALMODE_WAL ); @@ -50724,10 +55041,11 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ - rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, + rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pWal = 0; pagerFixMaplimit(pPager); + if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } } return rc; @@ -50760,6 +55078,20 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSn } return rc; } + +/* +** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this +** is not a WAL database, return an error. +*/ +SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){ + int rc; + if( pPager->pWal ){ + rc = sqlite3WalSnapshotRecover(pPager->pWal); + }else{ + rc = SQLITE_ERROR; + } + return rc; +} #endif /* SQLITE_ENABLE_SNAPSHOT */ #endif /* !SQLITE_OMIT_WAL */ @@ -50777,7 +55109,6 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ } #endif - #endif /* SQLITE_OMIT_DISKIO */ /************** End of pager.c ***********************************************/ @@ -51229,6 +55560,7 @@ struct Wal { u8 padToSectorBoundary; /* Pad transactions out to the next sector */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ + u32 iReCksum; /* On commit, recalculate checksums from here */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ #ifdef SQLITE_DEBUG @@ -51329,7 +55661,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); if( !apNew ){ *ppPage = 0; - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memset((void*)&apNew[pWal->nWiData], 0, sizeof(u32*)*(iPage+1-pWal->nWiData)); @@ -51341,7 +55673,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ if( pWal->apWiData[iPage]==0 ){ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); - if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM; + if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; }else{ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] @@ -51482,14 +55814,18 @@ static void walEncodeFrame( assert( WAL_FRAME_HDRSIZE==24 ); sqlite3Put4byte(&aFrame[0], iPage); sqlite3Put4byte(&aFrame[4], nTruncate); - memcpy(&aFrame[8], pWal->hdr.aSalt, 8); + if( pWal->iReCksum==0 ){ + memcpy(&aFrame[8], pWal->hdr.aSalt, 8); - nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); - walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); - walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); + nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); + walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); + walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); - sqlite3Put4byte(&aFrame[16], aCksum[0]); - sqlite3Put4byte(&aFrame[20], aCksum[1]); + sqlite3Put4byte(&aFrame[16], aCksum[0]); + sqlite3Put4byte(&aFrame[20], aCksum[1]); + }else{ + memset(&aFrame[8], 0, 16); + } } /* @@ -51952,7 +56288,7 @@ static int walIndexRecover(Wal *pWal){ szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( !aFrame ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto recovery_error; } aData = &aFrame[WAL_FRAME_HDRSIZE]; @@ -52090,7 +56426,7 @@ SQLITE_PRIVATE int sqlite3WalOpen( *ppWal = 0; pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile); if( !pRet ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pRet->pVfs = pVfs; @@ -52354,7 +56690,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ + iLast*sizeof(ht_slot); p = (WalIterator *)sqlite3_malloc64(nByte); if( !p ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memset(p, 0, nByte); p->nSegment = nSegment; @@ -52366,7 +56702,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) ); if( !aTmp ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } for(i=0; rc==SQLITE_OK && inBackfillAttempted = mxSafeFrame; /* Sync the WAL to disk */ - if( sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags); - } + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. @@ -52596,6 +56931,10 @@ static int walCheckpoint( while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); + if( db->u1.isInterrupted ){ + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; + break; + } if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ continue; } @@ -52615,8 +56954,8 @@ static int walCheckpoint( i64 szDb = pWal->hdr.nPage*(i64)szPage; testcase( IS_BIG_INT(szDb) ); rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK && sync_flags ){ - rc = sqlite3OsSync(pWal->pDbFd, sync_flags); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); } } if( rc==SQLITE_OK ){ @@ -52700,6 +57039,7 @@ static void walLimitSize(Wal *pWal, i64 nMax){ */ SQLITE_PRIVATE int sqlite3WalClose( Wal *pWal, /* Wal to close */ + sqlite3 *db, /* For interrupt flag */ int sync_flags, /* Flags to pass to OsSync() (or 0) */ int nBuf, u8 *zBuf /* Buffer of at least nBuf bytes */ @@ -52716,13 +57056,14 @@ SQLITE_PRIVATE int sqlite3WalClose( ** ** The EXCLUSIVE lock is not released before returning. */ - rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE); - if( rc==SQLITE_OK ){ + if( zBuf!=0 + && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE)) + ){ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } - rc = sqlite3WalCheckpoint( - pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 + rc = sqlite3WalCheckpoint(pWal, db, + SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 ); if( rc==SQLITE_OK ){ int bPersist = -1; @@ -53151,6 +57492,84 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ return rc; } +#ifdef SQLITE_ENABLE_SNAPSHOT +/* +** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted +** variable so that older snapshots can be accessed. To do this, loop +** through all wal frames from nBackfillAttempted to (nBackfill+1), +** comparing their content to the corresponding page with the database +** file, if any. Set nBackfillAttempted to the frame number of the +** first frame for which the wal file content matches the db file. +** +** This is only really safe if the file-system is such that any page +** writes made by earlier checkpointers were atomic operations, which +** is not always true. It is also possible that nBackfillAttempted +** may be left set to a value larger than expected, if a wal frame +** contains content that duplicate of an earlier version of the same +** page. +** +** SQLITE_OK is returned if successful, or an SQLite error code if an +** error occurs. It is not an error if nBackfillAttempted cannot be +** decreased at all. +*/ +SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ + int rc; + + assert( pWal->readLock>=0 ); + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + if( rc==SQLITE_OK ){ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + int szPage = (int)pWal->szPage; + i64 szDb; /* Size of db file in bytes */ + + rc = sqlite3OsFileSize(pWal->pDbFd, &szDb); + if( rc==SQLITE_OK ){ + void *pBuf1 = sqlite3_malloc(szPage); + void *pBuf2 = sqlite3_malloc(szPage); + if( pBuf1==0 || pBuf2==0 ){ + rc = SQLITE_NOMEM; + }else{ + u32 i = pInfo->nBackfillAttempted; + for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){ + volatile ht_slot *dummy; + volatile u32 *aPgno; /* Array of page numbers */ + u32 iZero; /* Frame corresponding to aPgno[0] */ + u32 pgno; /* Page number in db file */ + i64 iDbOff; /* Offset of db file entry */ + i64 iWalOff; /* Offset of wal file entry */ + + rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero); + if( rc!=SQLITE_OK ) break; + pgno = aPgno[i-iZero]; + iDbOff = (i64)(pgno-1) * szPage; + + if( iDbOff+szPage<=szDb ){ + iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE; + rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); + + if( rc==SQLITE_OK ){ + rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff); + } + + if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){ + break; + } + } + + pInfo->nBackfillAttempted = i-1; + } + } + + sqlite3_free(pBuf1); + sqlite3_free(pBuf2); + } + walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); + } + + return rc; +} +#endif /* SQLITE_ENABLE_SNAPSHOT */ + /* ** Begin a read transaction on the database. ** @@ -53213,7 +57632,11 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ ** has not yet set the pInfo->nBackfillAttempted variable to indicate ** its intent. To avoid the race condition this leads to, ensure that ** there is no checkpointer process by taking a shared CKPT lock - ** before checking pInfo->nBackfillAttempted. */ + ** before checking pInfo->nBackfillAttempted. + ** + ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing + ** this already? + */ rc = walLockShared(pWal, WAL_CKPT_LOCK); if( rc==SQLITE_OK ){ @@ -53416,6 +57839,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ /* Cannot start a write transaction without first holding a read ** transaction. */ assert( pWal->readLock>=0 ); + assert( pWal->writeLock==0 && pWal->iReCksum==0 ); if( pWal->readOnly ){ return SQLITE_READONLY; @@ -53451,6 +57875,7 @@ SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){ if( pWal->writeLock ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; + pWal->iReCksum = 0; pWal->truncateOnCommit = 0; } return SQLITE_OK; @@ -53636,8 +58061,8 @@ static int walWriteToLog( iOffset += iFirstAmt; iAmt -= iFirstAmt; pContent = (void*)(iFirstAmt + (char*)pContent); - assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) ); - rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK); + assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 ); + rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags)); if( iAmt==0 || rc ) return rc; } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); @@ -53657,7 +58082,7 @@ static int walWriteOneFrame( void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ #if defined(SQLITE_HAS_CODEC) - if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM; + if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; #else pData = pPage->pData; #endif @@ -53669,6 +58094,59 @@ static int walWriteOneFrame( return rc; } +/* +** This function is called as part of committing a transaction within which +** one or more frames have been overwritten. It updates the checksums for +** all frames written to the wal file by the current transaction starting +** with the earliest to have been overwritten. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int walRewriteChecksums(Wal *pWal, u32 iLast){ + const int szPage = pWal->szPage;/* Database page size */ + int rc = SQLITE_OK; /* Return code */ + u8 *aBuf; /* Buffer to load data from wal file into */ + u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */ + u32 iRead; /* Next frame to read from wal file */ + i64 iCksumOff; + + aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE); + if( aBuf==0 ) return SQLITE_NOMEM_BKPT; + + /* Find the checksum values to use as input for the recalculating the + ** first checksum. If the first frame is frame 1 (implying that the current + ** transaction restarted the wal file), these values must be read from the + ** wal-file header. Otherwise, read them from the frame header of the + ** previous frame. */ + assert( pWal->iReCksum>0 ); + if( pWal->iReCksum==1 ){ + iCksumOff = 24; + }else{ + iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16; + } + rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff); + pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); + pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); + + iRead = pWal->iReCksum; + pWal->iReCksum = 0; + for(; rc==SQLITE_OK && iRead<=iLast; iRead++){ + i64 iOff = walFrameOffset(iRead, szPage); + rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff); + if( rc==SQLITE_OK ){ + u32 iPgno, nDbSize; + iPgno = sqlite3Get4byte(aBuf); + nDbSize = sqlite3Get4byte(&aBuf[4]); + + walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame); + rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff); + } + } + + sqlite3_free(aBuf); + return rc; +} + /* ** Write a set of frames to the log. The caller must hold the write-lock ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). @@ -53689,6 +58167,8 @@ SQLITE_PRIVATE int sqlite3WalFrames( int szFrame; /* The size of a single frame */ i64 iOffset; /* Next byte to write in WAL file */ WalWriter w; /* The writer */ + u32 iFirst = 0; /* First frame that may be overwritten */ + WalIndexHdr *pLive; /* Pointer to shared header */ assert( pList ); assert( pWal->writeLock ); @@ -53704,6 +58184,11 @@ SQLITE_PRIVATE int sqlite3WalFrames( } #endif + pLive = (WalIndexHdr*)walIndexHdr(pWal); + if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){ + iFirst = pLive->mxFrame+1; + } + /* See if it is possible to write these frames into the start of the ** log file, instead of appending to it at pWal->hdr.mxFrame. */ @@ -53747,10 +58232,10 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** an out-of-order write following a WAL restart could result in ** database corruption. See the ticket: ** - ** http://localhost:591/sqlite/info/ff5be73dee + ** https://sqlite.org/src/info/ff5be73dee */ - if( pWal->syncHeader && sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK); + if( pWal->syncHeader ){ + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); if( rc ) return rc; } } @@ -53768,6 +58253,33 @@ SQLITE_PRIVATE int sqlite3WalFrames( /* Write all frames into the log file exactly once */ for(p=pList; p; p=p->pDirty){ int nDbSize; /* 0 normally. Positive == commit flag */ + + /* Check if this page has already been written into the wal file by + ** the current transaction. If so, overwrite the existing frame and + ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that + ** checksums must be recomputed when the transaction is committed. */ + if( iFirst && (p->pDirty || isCommit==0) ){ + u32 iWrite = 0; + VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite); + assert( rc==SQLITE_OK || iWrite==0 ); + if( iWrite>=iFirst ){ + i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; + void *pData; + if( pWal->iReCksum==0 || iWriteiReCksum ){ + pWal->iReCksum = iWrite; + } +#if defined(SQLITE_HAS_CODEC) + if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; +#else + pData = p->pData; +#endif + rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); + if( rc ) return rc; + p->flags &= ~PGHDR_WAL_APPEND; + continue; + } + } + iFrame++; assert( iOffset==walFrameOffset(iFrame, szPage) ); nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0; @@ -53775,6 +58287,13 @@ SQLITE_PRIVATE int sqlite3WalFrames( if( rc ) return rc; pLast = p; iOffset += szFrame; + p->flags |= PGHDR_WAL_APPEND; + } + + /* Recalculate checksums within the wal file if required. */ + if( isCommit && pWal->iReCksum ){ + rc = walRewriteChecksums(pWal, iFrame); + if( rc ) return rc; } /* If this is the end of a transaction, then we might need to pad @@ -53791,18 +58310,23 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ - if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ + if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){ + int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; + bSync = (w.iSyncPoint==iOffset); + testcase( bSync ); while( iOffsethdr.mxFrame; for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ + if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; iFrame++; rc = walIndexAppend(pWal, iFrame, p->pgno); } @@ -53868,6 +58393,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( */ SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Wal connection */ + sqlite3 *db, /* Check this handle's interrupt flag */ int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ @@ -53938,10 +58464,11 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ - rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); + rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); } /* If no error occurred, set the output variables. */ @@ -54061,12 +58588,17 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){ int rc = SQLITE_OK; WalIndexHdr *pRet; + static const u32 aZero[4] = { 0, 0, 0, 0 }; assert( pWal->readLock>=0 && pWal->writeLock==0 ); + if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){ + *ppSnapshot = 0; + return SQLITE_ERROR; + } pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr)); if( pRet==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr)); *ppSnapshot = (sqlite3_snapshot*)pRet; @@ -54080,6 +58612,23 @@ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapsho SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){ pWal->pSnapshot = (WalIndexHdr*)pSnapshot; } + +/* +** Return a +ve value if snapshot p1 is newer than p2. A -ve value if +** p1 is older than p2 and zero if p1 and p2 are the same snapshot. +*/ +SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){ + WalIndexHdr *pHdr1 = (WalIndexHdr*)p1; + WalIndexHdr *pHdr2 = (WalIndexHdr*)p2; + + /* aSalt[0] is a copy of the value stored in the wal file header. It + ** is incremented each time the wal file is restarted. */ + if( pHdr1->aSalt[0]aSalt[0] ) return -1; + if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1; + if( pHdr1->mxFramemxFrame ) return -1; + if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; + return 0; +} #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_ZIPVFS @@ -54384,38 +58933,39 @@ typedef struct CellInfo CellInfo; #define PTF_LEAF 0x08 /* -** As each page of the file is loaded into memory, an instance of the following -** structure is appended and initialized to zero. This structure stores -** information about the page that is decoded from the raw file page. +** An instance of this object stores information about each a single database +** page that has been loaded into memory. The information in this object +** is derived from the raw on-disk page content. ** -** The pParent field points back to the parent page. This allows us to -** walk up the BTree from any leaf to the root. Care must be taken to -** unref() the parent page pointer when this page is no longer referenced. -** The pageDestructor() routine handles that chore. +** As each database page is loaded into memory, the pager allocats an +** instance of this object and zeros the first 8 bytes. (This is the +** "extra" information associated with each page of the pager.) ** ** Access to all fields of this structure is controlled by the mutex ** stored in MemPage.pBt->mutex. */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ - u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ + u8 bBusy; /* Prevent endless loops on corrupt database files */ u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKeyLeaf; /* True if the leaf of an intKey table */ - u8 noPayload; /* True if internal intKey page (thus w/o data) */ + Pgno pgno; /* Page number for this page */ + /* Only the first 8 bytes (above) are zeroed by pager.c when a new page + ** is allocated. All fields that follow must be initialized before use */ u8 leaf; /* True if a leaf page */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 max1bytePayload; /* min(maxLocal,127) */ - u8 bBusy; /* Prevent endless loops on corrupt database files */ + u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ 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 */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ - u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th + u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th ** non-overflow cell */ - u8 *apOvfl[5]; /* Pointers to the body of overflow cells */ + u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ BtShared *pBt; /* Pointer to BtShared that this page is part of */ u8 *aData; /* Pointer to disk image of the page data */ u8 *aDataEnd; /* One byte past the end of usable data */ @@ -54424,16 +58974,8 @@ struct MemPage { DbPage *pDbPage; /* Pager page handle */ u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */ void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */ - Pgno pgno; /* Page number for this page */ }; -/* -** The in-memory image of a disk page has the auxiliary information appended -** to the end. EXTRA_SIZE is the number of bytes of space needed to hold -** that extra information. -*/ -#define EXTRA_SIZE sizeof(MemPage) - /* ** A linked list of the following structures is stored at BtShared.pLock. ** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor @@ -54580,10 +59122,12 @@ struct BtShared { #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ #define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */ -#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */ -#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */ -#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */ -#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */ +#define BTS_OVERWRITE 0x0008 /* Overwrite deleted content with zeros */ +#define BTS_FAST_SECURE 0x000c /* Combination of the previous two */ +#define BTS_INITIALLY_EMPTY 0x0010 /* Database was empty at trans start */ +#define BTS_NO_WAL 0x0020 /* Do not open write-ahead-log files */ +#define BTS_EXCLUSIVE 0x0040 /* pWriter has an exclusive lock */ +#define BTS_PENDING 0x0080 /* Waiting for read-locks to clear */ /* ** An instance of the following structure is used to hold information @@ -54629,6 +59173,11 @@ struct CellInfo { ** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { + u8 eState; /* One of the CURSOR_XXX constants (see below) */ + u8 curFlags; /* zero or more BTCF_* flags defined below */ + u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ + u8 hints; /* As configured by CursorSetHints() */ + int nOvflAlloc; /* Allocated size of aOverflow[] array */ Btree *pBtree; /* The Btree to which this cursor belongs */ BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext; /* Forms a linked list of all cursors */ @@ -54637,22 +59186,18 @@ struct BtCursor { i64 nKey; /* Size of pKey, or last integer key */ void *pKey; /* Saved key that was cursor last known position */ Pgno pgnoRoot; /* The root page of this tree */ - int nOvflAlloc; /* Allocated size of aOverflow[] array */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive. ** Error code if eState==CURSOR_FAULT */ - u8 curFlags; /* zero or more BTCF_* flags defined below */ - u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ - u8 eState; /* One of the CURSOR_XXX constants (see below) */ - u8 hints; /* As configured by CursorSetHints() */ /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ i8 iPage; /* Index of current page in apPage */ u8 curIntKey; /* Value of apPage[0]->intKey */ - struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ - void *padding1; /* Make object size a multiple of 16 */ - u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ - MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ + u16 ix; /* Current index for apPage[iPage] */ + u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */ + struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */ + MemPage *pPage; /* Current page */ + MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */ }; /* @@ -54824,11 +59369,9 @@ struct IntegrityCk { */ #if SQLITE_BYTEORDER==4321 # define get2byteAligned(x) (*(u16*)(x)) -#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \ - && GCC_VERSION>=4008000 +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000 # define get2byteAligned(x) __builtin_bswap16(*(u16*)(x)) -#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \ - && defined(_MSC_VER) && _MSC_VER>=1300 +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 # define get2byteAligned(x) _byteswap_ushort(*(u16*)(x)) #else # define get2byteAligned(x) ((x)[0]<<8 | (x)[1]) @@ -54989,21 +59532,6 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ #endif -#ifndef SQLITE_OMIT_INCRBLOB -/* -** Enter and leave a mutex on a Btree given a cursor owned by that -** Btree. These entry points are used by incremental I/O and can be -** omitted if that module is not used. -*/ -SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ - sqlite3BtreeEnter(pCur->pBtree); -} -SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ - sqlite3BtreeLeave(pCur->pBtree); -} -#endif /* SQLITE_OMIT_INCRBLOB */ - - /* ** Enter the mutex on every Btree associated with a database ** connection. This is needed (for example) prior to parsing @@ -55018,16 +59546,24 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ ** two or more btrees in common both try to lock all their btrees ** at the same instant. */ -SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ +static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ int i; + int skipOk = 1; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inDb; i++){ p = db->aDb[i].pBt; - if( p ) sqlite3BtreeEnter(p); + if( p && p->sharable ){ + sqlite3BtreeEnter(p); + skipOk = 0; + } } + db->skipBtreeMutex = skipOk; } -SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ +SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ + if( db->skipBtreeMutex==0 ) btreeEnterAll(db); +} +static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ int i; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); @@ -55036,13 +59572,8 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ if( p ) sqlite3BtreeLeave(p); } } - -/* -** Return true if a particular Btree requires a lock. Return FALSE if -** no lock is ever required since it is not sharable. -*/ -SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ - return p->sharable; +SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ + if( db->skipBtreeMutex==0 ) btreeLeaveAll(db); } #ifndef NDEBUG @@ -55118,6 +59649,25 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ } } #endif /* if SQLITE_THREADSAFE */ + +#ifndef SQLITE_OMIT_INCRBLOB +/* +** Enter a mutex on a Btree given a cursor owned by that Btree. +** +** These entry points are used by incremental I/O only. Enter() is required +** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not +** the build is threadsafe. Leave() is only required by threadsafe builds. +*/ +SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ + sqlite3BtreeEnter(pCur->pBtree); +} +# if SQLITE_THREADSAFE +SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ + sqlite3BtreeLeave(pCur->pBtree); +} +# endif +#endif /* ifndef SQLITE_OMIT_INCRBLOB */ + #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ /************** End of btmutex.c *********************************************/ @@ -55210,7 +59760,7 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; ** The shared cache setting effects only future calls to ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){ +SQLITE_API int sqlite3_enable_shared_cache(int enable){ sqlite3GlobalConfig.sharedCacheEnabled = enable; return SQLITE_OK; } @@ -55276,7 +59826,7 @@ static int hasSharedCacheTableLock( ** Return true immediately. */ if( (pBtree->sharable==0) - || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) + || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit)) ){ return 1; } @@ -55353,7 +59903,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( p->pgnoRoot==iRoot && p->pBtree!=pBtree - && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted) + && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit) ){ return 1; } @@ -55375,7 +59925,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); - assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); + assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 ); /* If requesting a write-lock, then the Btree must have an open write ** transaction on this file. And, obviously, for this to be so there @@ -55453,7 +60003,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ ** obtain a read-lock using this function. The only read-lock obtained ** by a connection in read-uncommitted mode is on the sqlite_master ** table, and that lock is obtained in BtreeBeginTrans(). */ - assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK ); + assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); /* This function should only be called on a sharable b-tree after it ** has been determined that no other b-tree holds a conflicting lock. */ @@ -55474,7 +60024,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ if( !pLock ){ pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); if( !pLock ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pLock->iTable = iTable; pLock->pBtree = p; @@ -55563,7 +60113,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){ #endif /* SQLITE_OMIT_SHARED_CACHE */ -static void releasePage(MemPage *pPage); /* Forward reference */ +static void releasePage(MemPage *pPage); /* Forward reference */ +static void releasePageOne(MemPage *pPage); /* Forward reference */ +static void releasePageNotNull(MemPage *pPage); /* Forward reference */ /* ***** This routine is used inside of assert() only **** @@ -55574,6 +60126,19 @@ static void releasePage(MemPage *pPage); /* Forward reference */ static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } + +/* Verify that the cursor and the BtShared agree about what is the current +** database connetion. This is important in shared-cache mode. If the database +** connection pointers get out-of-sync, it is possible for routines like +** btreeInitPage() to reference an stale connection pointer that references a +** a connection that has already closed. This routine is used inside assert() +** statements only and for the purpose of double-checking that the btree code +** does keep the database connection pointers up-to-date. +*/ +static int cursorOwnsBtShared(BtCursor *p){ + assert( cursorHoldsMutex(p) ); + return (p->pBtree->db==p->pBt->db); +} #endif /* @@ -55610,6 +60175,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){ */ static void invalidateIncrblobCursors( Btree *pBtree, /* The database file to check */ + Pgno pgnoRoot, /* The table that might be changing */ i64 iRow, /* The rowid that might be changing */ int isClearTable /* True if all rows are being deleted */ ){ @@ -55620,7 +60186,7 @@ static void invalidateIncrblobCursors( for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( (p->curFlags & BTCF_Incrblob)!=0 ){ pBtree->hasIncrblobCur = 1; - if( isClearTable || p->info.nKey==iRow ){ + if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } @@ -55629,7 +60195,7 @@ static void invalidateIncrblobCursors( #else /* Stub function when INCRBLOB is omitted */ - #define invalidateIncrblobCursors(x,y,z) + #define invalidateIncrblobCursors(w,x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ /* @@ -55673,7 +60239,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ assert( pgno<=pBt->nPage ); pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage); if( !pBt->pHasContent ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } } if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){ @@ -55708,11 +60274,13 @@ static void btreeClearHasContent(BtShared *pBt){ */ static void btreeReleaseAllCursorPages(BtCursor *pCur){ int i; - for(i=0; i<=pCur->iPage; i++){ - releasePage(pCur->apPage[i]); - pCur->apPage[i] = 0; + if( pCur->iPage>=0 ){ + for(i=0; iiPage; i++){ + releasePageNotNull(pCur->apPage[i]); + } + releasePageNotNull(pCur->pPage); + pCur->iPage = -1; } - pCur->iPage = -1; } /* @@ -55729,30 +60297,28 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){ ** the key. */ static int saveCursorKey(BtCursor *pCur){ - int rc; + int rc = SQLITE_OK; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); - rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); - assert( rc==SQLITE_OK ); /* KeySize() cannot fail */ - - /* If this is an intKey table, then the above call to BtreeKeySize() - ** stores the integer key in pCur->nKey. In this case this value is - ** all that is required. Otherwise, if pCur is not open on an intKey - ** table, then malloc space for and store the pCur->nKey bytes of key - ** data. */ - if( 0==pCur->curIntKey ){ - void *pKey = sqlite3Malloc( pCur->nKey ); + if( pCur->curIntKey ){ + /* Only the rowid is required for a table btree */ + pCur->nKey = sqlite3BtreeIntegerKey(pCur); + }else{ + /* For an index btree, save the complete key content */ + void *pKey; + pCur->nKey = sqlite3BtreePayloadSize(pCur); + pKey = sqlite3Malloc( pCur->nKey ); if( pKey ){ - rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); + rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ sqlite3_free(pKey); } }else{ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } } assert( !pCur->curIntKey || !pCur->pKey ); @@ -55843,7 +60409,7 @@ static int SQLITE_NOINLINE saveCursorsOnList( return rc; } }else{ - testcase( p->iPage>0 ); + testcase( p->iPage>=0 ); btreeReleaseAllCursorPages(p); } } @@ -55876,26 +60442,23 @@ static int btreeMoveto( ){ int rc; /* Status code */ UnpackedRecord *pIdxKey; /* Unpacked index key */ - char aSpace[200]; /* Temp space for pIdxKey - to avoid a malloc */ - char *pFree = 0; if( pKey ){ assert( nKey==(i64)(int)nKey ); - pIdxKey = sqlite3VdbeAllocUnpackedRecord( - pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree - ); - if( pIdxKey==0 ) return SQLITE_NOMEM; + pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); + if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 ){ - sqlite3DbFree(pCur->pKeyInfo->db, pFree); - return SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_BKPT; + goto moveto_done; } }else{ pIdxKey = 0; } rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); - if( pFree ){ - sqlite3DbFree(pCur->pKeyInfo->db, pFree); +moveto_done: + if( pIdxKey ){ + sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); } return rc; } @@ -55910,7 +60473,7 @@ static int btreeMoveto( static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; int skipNext; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; @@ -55950,6 +60513,17 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ return pCur->eState!=CURSOR_VALID; } +/* +** Return a pointer to a fake BtCursor object that will always answer +** false to the sqlite3BtreeCursorHasMoved() routine above. The fake +** cursor returned must not be used with any other Btree interface. +*/ +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){ + static u8 fakeCursor = CURSOR_VALID; + assert( offsetof(BtCursor, eState)==0 ); + return (BtCursor*)&fakeCursor; +} + /* ** This routine restores a cursor back to its original position after it ** has been moved by some outside activity (such as a btree rebalance or @@ -56115,7 +60689,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); - if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; + if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } @@ -56199,7 +60773,6 @@ static void btreeParseCellPtrNoPayload( ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->leaf==0 ); - assert( pPage->noPayload ); assert( pPage->childPtrSize==4 ); #ifndef SQLITE_DEBUG UNUSED_PARAMETER(pPage); @@ -56221,8 +60794,6 @@ static void btreeParseCellPtr( assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->leaf==0 || pPage->leaf==1 ); - assert( pPage->intKeyLeaf || pPage->noPayload ); - assert( pPage->noPayload==0 ); assert( pPage->intKeyLeaf ); assert( pPage->childPtrSize==0 ); pIter = pCell; @@ -56291,7 +60862,6 @@ static void btreeParseCellPtrIndex( assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->leaf==0 || pPage->leaf==1 ); assert( pPage->intKeyLeaf==0 ); - assert( pPage->noPayload==0 ); pIter = pCell + pPage->childPtrSize; nPayload = *pIter; if( nPayload>=0x80 ){ @@ -56352,7 +60922,6 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ pPage->xParseCell(pPage, pCell, &debuginfo); #endif - assert( pPage->noPayload==0 ); nSize = *pIter; if( nSize>=0x80 ){ pEnd = &pIter[8]; @@ -56438,17 +61007,18 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ /* -** Defragment the page given. All Cells are moved to the -** end of the page and all free space is collected into one -** big FreeBlk that occurs in between the header and cell -** pointer array and the cell content area. +** Defragment the page given. This routine reorganizes cells within the +** page so that there are no free-blocks on the free-block list. +** +** Parameter nMaxFrag is the maximum amount of fragmented space that may be +** present in the page after this routine returns. ** ** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a ** b-tree page so that there are no freeblocks or fragment bytes, all ** unused bytes are contained in the unallocated space region, and all ** cells are packed tightly at the end of the page. */ -static int defragmentPage(MemPage *pPage){ +static int defragmentPage(MemPage *pPage, int nMaxFrag){ int i; /* Loop counter */ int pc; /* Address of the i-th cell */ int hdr; /* Offset to the page header */ @@ -56463,7 +61033,6 @@ static int defragmentPage(MemPage *pPage){ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ - assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); @@ -56475,9 +61044,59 @@ static int defragmentPage(MemPage *pPage){ cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) ); - usableSize = pPage->pBt->usableSize; - cbrk = usableSize; iCellFirst = cellOffset + 2*nCell; + usableSize = pPage->pBt->usableSize; + + /* This block handles pages with two or fewer free blocks and nMaxFrag + ** or fewer fragmented bytes. In this case it is faster to move the + ** two (or one) blocks of cells using memmove() and add the required + ** offsets to each pointer in the cell-pointer array than it is to + ** reconstruct the entire page. */ + if( (int)data[hdr+7]<=nMaxFrag ){ + int iFree = get2byte(&data[hdr+1]); + 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( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ + u8 *pEnd = &data[cellOffset + nCell*2]; + u8 *pAddr; + int sz2 = 0; + int sz = get2byte(&data[iFree+2]); + int top = get2byte(&data[hdr+5]); + if( top>=iFree ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + if( iFree2 ){ + assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */ + sz2 = get2byte(&data[iFree2+2]); + assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize ); + memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); + sz += sz2; + } + cbrk = top+sz; + assert( cbrk+(iFree-top) <= usableSize ); + memmove(&data[cbrk], &data[top], iFree-top); + for(pAddr=&data[cellOffset]; pAddriCellLast ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } assert( pc>=iCellFirst && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrkusableSize ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); testcase( cbrk+size==usableSize ); @@ -56511,16 +61130,18 @@ static int defragmentPage(MemPage *pPage){ } memcpy(&data[cbrk], &src[pc], size); } + data[hdr+7] = 0; + + defragment_out: + if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); data[hdr+1] = 0; data[hdr+2] = 0; - data[hdr+7] = 0; memset(&data[iCellFirst], 0, cbrk-iCellFirst); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); - if( cbrk-iCellFirst!=pPage->nFree ){ - return SQLITE_CORRUPT_BKPT; - } return SQLITE_OK; } @@ -56545,16 +61166,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ int pc = get2byte(&aData[iAddr]); int x; int usableSize = pPg->pBt->usableSize; + int size; /* Size of the free slot */ assert( pc>0 ); - do{ - int size; /* Size of the free slot */ - /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of - ** increasing offset. */ - if( pc>usableSize-4 || pc=0 ){ testcase( x==4 ); testcase( x==3 ); - if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){ - *pRc = SQLITE_CORRUPT_BKPT; + if( size+pc > usableSize ){ + *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno); return 0; }else if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total @@ -56583,7 +61198,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ } iAddr = pc; pc = get2byte(&aData[pc]); - }while( pc ); + if( pcpgno); + } return 0; } @@ -56630,7 +61249,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } } @@ -56658,10 +61277,10 @@ 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 ); - rc = defragmentPage(pPage); + rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); - assert( gap+nByte<=top ); + assert( gap+2+nByte<=top ); } @@ -56697,7 +61316,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ u8 hdr; /* Page header size. 0 or 100 */ u8 nFrag = 0; /* Reduction in fragmentation */ u16 iOrigSize = iSize; /* Original value of iSize */ - u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */ + u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ @@ -56707,13 +61326,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ - assert( iStart<=iLast ); - - /* Overwrite deleted information with zeros when the secure_delete - ** option is enabled */ - if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){ - memset(&data[iStart], 0, iSize); - } + assert( iStart<=pPage->pBt->usableSize-4 ); /* The list of freeblocks must be in ascending order. Find the ** spot on the list where iStart should be inserted. @@ -56723,11 +61336,16 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( data[iPtr+1]==0 && data[iPtr]==0 ){ iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */ }else{ - while( (iFreeBlk = get2byte(&data[iPtr]))>0 && iFreeBlkpgno); + } iPtr = iFreeBlk; } - if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT; + if( iFreeBlk>pPage->pBt->usableSize-4 ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } assert( iFreeBlk>iPtr || iFreeBlk==0 ); /* At this point: @@ -56738,9 +61356,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; - if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PGNO(pPage->pgno); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT; + if( iEnd > pPage->pBt->usableSize ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); } @@ -56752,28 +61372,34 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ - if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT; + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PGNO(pPage->pgno); nFrag += iStart - iPtrEnd; iSize = iEnd - iPtr; iStart = iPtr; } } - if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT; + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno); data[hdr+7] -= nFrag; } - if( iStart==get2byte(&data[hdr+5]) ){ + x = get2byte(&data[hdr+5]); + if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ - if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT; + if( iStartpgno); put2byte(&data[hdr+1], iFreeBlk); put2byte(&data[hdr+5], iEnd); }else{ /* Insert the new freeblock into the freelist */ put2byte(&data[iPtr], iStart); - put2byte(&data[iStart], iFreeBlk); - put2byte(&data[iStart+2], iSize); } + if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){ + /* Overwrite deleted information with zeros when the secure_delete + ** option is enabled */ + memset(&data[iStart], 0, iSize); + } + put2byte(&data[iStart], iFreeBlk); + put2byte(&data[iStart+2], iSize); pPage->nFree += iOrigSize; return SQLITE_OK; } @@ -56801,42 +61427,39 @@ static int decodeFlags(MemPage *pPage, int flagByte){ pPage->xCellSize = cellSizePtr; pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ - /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior - ** table b-tree page. */ + /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an + ** interior table b-tree page. */ assert( (PTF_LEAFDATA|PTF_INTKEY)==5 ); - /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf - ** table b-tree page. */ + /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a + ** leaf table b-tree page. */ assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); pPage->intKey = 1; if( pPage->leaf ){ pPage->intKeyLeaf = 1; - pPage->noPayload = 0; pPage->xParseCell = btreeParseCellPtr; }else{ pPage->intKeyLeaf = 0; - pPage->noPayload = 1; pPage->xCellSize = cellSizePtrNoPayload; pPage->xParseCell = btreeParseCellPtrNoPayload; } pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else if( flagByte==PTF_ZERODATA ){ - /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior - ** index b-tree page. */ + /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an + ** interior index b-tree page. */ assert( (PTF_ZERODATA)==2 ); - /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf - ** index b-tree page. */ + /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a + ** leaf index b-tree page. */ assert( (PTF_ZERODATA|PTF_LEAF)==10 ); pPage->intKey = 0; pPage->intKeyLeaf = 0; - pPage->noPayload = 0; pPage->xParseCell = btreeParseCellPtrIndex; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is ** an error. */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; @@ -56852,6 +61475,16 @@ static int decodeFlags(MemPage *pPage, int flagByte){ ** we failed to detect any corruption. */ static int btreeInitPage(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 */ + int iCellLast; /* Last possible cell or freeblock offset */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); @@ -56859,122 +61492,119 @@ 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 ); - if( !pPage->isInit ){ - u16 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 */ - int iCellLast; /* Last possible cell or freeblock offset */ + pBt = pPage->pBt; + 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_PGNO(pPage->pgno); + } + 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_PGNO(pPage->pgno); + } + 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 ); - pBt = pPage->pBt; + /* 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; + iCellLast = usableSize - 4; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ - 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_BKPT; - 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_BKPT; - } - 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; - 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_BKPT; - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_BKPT; - } - } - 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 - ** start of the first freeblock on the page, or is zero if there are no - ** freeblocks. */ - pc = get2byte(&data[hdr+1]); - nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ - while( pc>0 ){ - u16 next, size; + if( !pPage->leaf ) iCellLast--; + for(i=0; inCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); if( pciCellLast ){ - /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will - ** always be at least one cell before the first freeblock. - ** - ** Or, the freeblock is off the end of the page - */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + } + 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 + ** start of the first freeblock on the page, or is zero if there are no + ** freeblocks. */ + pc = get2byte(&data[hdr+1]); + nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ + if( pc>0 ){ + u32 next, size; + if( pcpgno); + } + while( 1 ){ + if( pc>iCellLast ){ + /* Freeblock off the end of the page */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); - if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){ - /* Free blocks must be in ascending order. And the last byte of - ** the free-block must lie on the database page. */ - return SQLITE_CORRUPT_BKPT; - } nFree = nFree + size; + if( next<=pc+size+3 ) break; pc = next; } - - /* At this point, nFree contains the sum of the offset to the start - ** of the cell-content area plus the number of free bytes within - ** the cell-content area. If this is greater than the usable-size - ** of the page, then the page must be corrupted. This check also - ** 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 ){ - return SQLITE_CORRUPT_BKPT; + if( next>0 ){ + /* Freeblock not in ascending order */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + if( pc+size>(unsigned int)usableSize ){ + /* Last freeblock extends past page end */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } - pPage->nFree = (u16)(nFree - iCellFirst); - pPage->isInit = 1; } + + /* At this point, nFree contains the sum of the offset to the start + ** of the cell-content area plus the number of free bytes within + ** the cell-content area. If this is greater than the usable-size + ** of the page, then the page must be corrupted. This check also + ** 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 ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + pPage->nFree = (u16)(nFree - iCellFirst); + pPage->isInit = 1; return SQLITE_OK; } @@ -56993,7 +61623,7 @@ static void zeroPage(MemPage *pPage, int flags){ assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); - if( pBt->btsFlags & BTS_SECURE_DELETE ){ + if( pBt->btsFlags & BTS_FAST_SECURE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; @@ -57084,7 +61714,7 @@ static Pgno btreePagecount(BtShared *pBt){ } SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); - assert( ((p->pBt->nPage)&0x8000000)==0 ); + assert( ((p->pBt->nPage)&0x80000000)==0 ); return btreePagecount(p->pBt); } @@ -57111,7 +61741,7 @@ static int getAndInitPage( int rc; DbPage *pDbPage; assert( sqlite3_mutex_held(pBt->mutex) ); - assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] ); + assert( pCur==0 || ppPage==&pCur->pPage ); assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); assert( pCur==0 || pCur->iPage>0 ); @@ -57138,14 +61768,17 @@ static int getAndInitPage( /* If obtaining a child page for a cursor, we must verify that the page is ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pgno); releasePage(*ppPage); goto getAndInitPage_error; } return SQLITE_OK; getAndInitPage_error: - if( pCur ) pCur->iPage--; + if( pCur ){ + pCur->iPage--; + pCur->pPage = pCur->apPage[pCur->iPage]; + } testcase( pgno==0 ); assert( pgno!=0 || rc==SQLITE_CORRUPT ); return rc; @@ -57154,6 +61787,8 @@ getAndInitPage_error: /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. +** +** Page1 is a special case and must be released using releasePageOne(). */ static void releasePageNotNull(MemPage *pPage){ assert( pPage->aData ); @@ -57167,6 +61802,16 @@ static void releasePageNotNull(MemPage *pPage){ static void releasePage(MemPage *pPage){ if( pPage ) releasePageNotNull(pPage); } +static void releasePageOne(MemPage *pPage){ + assert( pPage!=0 ); + assert( pPage->aData ); + assert( pPage->pBt ); + assert( pPage->pDbPage!=0 ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + sqlite3PagerUnrefPageOne(pPage->pDbPage); +} /* ** Get an unused page. @@ -57304,7 +61949,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( } p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } p->inTrans = TRANS_NONE; p->db = db; @@ -57328,7 +61973,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( p->sharable = 1; if( !zFullPathname ){ sqlite3_free(p); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } if( isMemdb ){ memcpy(zFullPathname, zFilename, nFilename); @@ -57396,11 +62041,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( pBt = sqlite3MallocZero( sizeof(*pBt) ); if( pBt==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, - EXTRA_SIZE, flags, vfsFlags, pageReinit); + sizeof(MemPage), flags, vfsFlags, pageReinit); if( rc==SQLITE_OK ){ sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap); rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); @@ -57416,8 +62061,10 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( pBt->pCursor = 0; pBt->pPage1 = 0; if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY; -#ifdef SQLITE_SECURE_DELETE +#if defined(SQLITE_SECURE_DELETE) pBt->btsFlags |= BTS_SECURE_DELETE; +#elif defined(SQLITE_FAST_SECURE_DELETE) + pBt->btsFlags |= BTS_OVERWRITE; #endif /* EVIDENCE-OF: R-51873-39618 The page size for a database file is ** determined by the 2-byte integer located at an offset of 16 bytes from @@ -57458,15 +62105,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ + pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) - pBt->nRef = 1; MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ - rc = SQLITE_NOMEM; - db->mallocFailed = 0; + rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } } @@ -57489,12 +62135,12 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( for(i=0; inDb; i++){ if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){ while( pSib->pPrev ){ pSib = pSib->pPrev; } - if( p->pBtpBt ){ + if( (uptr)p->pBt<(uptr)pSib->pBt ){ p->pNext = pSib; p->pPrev = 0; pSib->pPrev = p; }else{ - while( pSib->pNext && pSib->pNext->pBtpBt ){ + while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){ pSib = pSib->pNext; } p->pNext = pSib->pNext; @@ -57514,12 +62160,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ - sqlite3PagerClose(pBt->pPager); + sqlite3PagerClose(pBt->pPager, 0); } sqlite3_free(pBt); sqlite3_free(p); *ppBtree = 0; }else{ + sqlite3_file *pFile; + /* If the B-Tree was successfully opened, set the pager-cache size to the ** default value. Except, when opening on an existing shared pager-cache, ** do not change the pager-cache size. @@ -57527,11 +62175,17 @@ btree_open_out: if( sqlite3BtreeSchema(p, 0, 0)==0 ){ sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); } + + pFile = sqlite3PagerFile(pBt->pPager); + if( pFile->pMethods ){ + sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db); + } } if( mutexOpen ){ assert( sqlite3_mutex_held(mutexOpen) ); sqlite3_mutex_leave(mutexOpen); } + assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 ); return rc; } @@ -57655,7 +62309,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ ** Clean out and delete the BtShared object. */ assert( !pBt->pCursor ); - sqlite3PagerClose(pBt->pPager); + sqlite3PagerClose(pBt->pPager, p->db); if( pBt->xFreeSchema && pBt->pSchema ){ pBt->xFreeSchema(pBt->pSchema); } @@ -57748,21 +62402,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags( } #endif -/* -** Return TRUE if the given btree is set to safety level 1. In other -** words, return TRUE if no sync() occurs on the disk files. -*/ -SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){ - BtShared *pBt = p->pBt; - int rc; - assert( sqlite3_mutex_held(p->db->mutex) ); - sqlite3BtreeEnter(p); - assert( pBt && pBt->pPager ); - rc = sqlite3PagerNosync(pBt->pPager); - sqlite3BtreeLeave(p); - return rc; -} - /* ** Change the default pages size and the number of reserved bytes per page. ** Or, if the page size has already been fixed, return SQLITE_READONLY @@ -57873,19 +62512,34 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ } /* -** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1, -** then make no changes. Always return the value of the BTS_SECURE_DELETE -** setting after the change. +** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags: +** +** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared +** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared +** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set +** newFlag==(-1) No changes +** +** This routine acts as a query if newFlag is less than zero +** +** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but +** freelist leaf pages are not written back to the database. Thus in-page +** deleted content is cleared, but freelist deleted content is not. +** +** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition +** that freelist leaf pages are written back into the database, increasing +** the amount of disk I/O. */ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ int b; if( p==0 ) return 0; sqlite3BtreeEnter(p); + assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 ); + assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ - p->pBt->btsFlags &= ~BTS_SECURE_DELETE; - if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE; - } - b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0; + p->pBt->btsFlags &= ~BTS_FAST_SECURE; + p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; + } + b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); return b; } @@ -57936,6 +62590,32 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ #endif } +/* +** If the user has not set the safety-level for this database connection +** using "PRAGMA synchronous", and if the safety-level is not already +** set to the value passed to this function as the second parameter, +** set it so. +*/ +#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \ + && !defined(SQLITE_OMIT_WAL) +static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){ + sqlite3 *db; + Db *pDb; + if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){ + while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; } + if( pDb->bSyncSet==0 + && pDb->safety_level!=safety_level + && pDb!=&db->aDb[1] + ){ + pDb->safety_level = safety_level; + sqlite3PagerSetFlags(pBt->pPager, + pDb->safety_level | (db->flags & PAGER_FLAGS_MASK)); + } + } +} +#else +# define setDefaultSyncFlag(pBt,safety_level) +#endif /* ** Get a reference to pPage1 of the database file. This will @@ -58008,11 +62688,16 @@ static int lockBtree(BtShared *pBt){ rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen); if( rc!=SQLITE_OK ){ goto page1_init_failed; - }else if( isOpen==0 ){ - releasePage(pPage1); - return SQLITE_OK; + }else{ + setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1); + if( isOpen==0 ){ + releasePageOne(pPage1); + return SQLITE_OK; + } } rc = SQLITE_NOTADB; + }else{ + setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1); } #endif @@ -58053,7 +62738,7 @@ static int lockBtree(BtShared *pBt){ ** zero and return SQLITE_OK. The caller will call this function ** again with the correct page-size. */ - releasePage(pPage1); + releasePageOne(pPage1); pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); @@ -58061,7 +62746,7 @@ static int lockBtree(BtShared *pBt){ pageSize-usableSize); return rc; } - if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){ + if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } @@ -58107,7 +62792,7 @@ static int lockBtree(BtShared *pBt){ return SQLITE_OK; page1_init_failed: - releasePage(pPage1); + releasePageOne(pPage1); pBt->pPage1 = 0; return rc; } @@ -58152,7 +62837,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){ assert( pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); pBt->pPage1 = 0; - releasePageNotNull(pPage1); + releasePageOne(pPage1); } } @@ -58250,7 +62935,6 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ ** proceed. */ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ - sqlite3 *pBlock = 0; BtShared *pBt = p->pBt; int rc = SQLITE_OK; @@ -58273,27 +62957,30 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } #ifndef SQLITE_OMIT_SHARED_CACHE - /* If another database handle has already opened a write transaction - ** on this shared-btree structure and a second write transaction is - ** requested, return SQLITE_LOCKED. - */ - if( (wrflag && pBt->inTransaction==TRANS_WRITE) - || (pBt->btsFlags & BTS_PENDING)!=0 - ){ - pBlock = pBt->pWriter->db; - }else if( wrflag>1 ){ - BtLock *pIter; - for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ - if( pIter->pBtree!=p ){ - pBlock = pIter->pBtree->db; - break; + { + sqlite3 *pBlock = 0; + /* If another database handle has already opened a write transaction + ** on this shared-btree structure and a second write transaction is + ** requested, return SQLITE_LOCKED. + */ + if( (wrflag && pBt->inTransaction==TRANS_WRITE) + || (pBt->btsFlags & BTS_PENDING)!=0 + ){ + pBlock = pBt->pWriter->db; + }else if( wrflag>1 ){ + BtLock *pIter; + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->pBtree!=p ){ + pBlock = pIter->pBtree->db; + break; + } } } - } - if( pBlock ){ - sqlite3ConnectionBlocked(p->db, pBlock); - rc = SQLITE_LOCKED_SHAREDCACHE; - goto trans_begun; + if( pBlock ){ + sqlite3ConnectionBlocked(p->db, pBlock); + rc = SQLITE_LOCKED_SHAREDCACHE; + goto trans_begun; + } } #endif @@ -58399,14 +63086,11 @@ static int setChildPtrmaps(MemPage *pPage){ int nCell; /* Number of cells in page pPage */ int rc; /* Return code */ BtShared *pBt = pPage->pBt; - u8 isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - rc = btreeInitPage(pPage); - if( rc!=SQLITE_OK ){ - goto set_child_ptrmaps_out; - } + rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); + if( rc!=SQLITE_OK ) return rc; nCell = pPage->nCell; for(i=0; iisInit = isInitOrig; return rc; } @@ -58450,16 +63132,15 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } put4byte(pPage->aData, iTo); }else{ - u8 isInitOrig = pPage->isInit; int i; int nCell; int rc; - rc = btreeInitPage(pPage); + rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc ) return rc; nCell = pPage->nCell; @@ -58468,12 +63149,14 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW1 ){ CellInfo info; pPage->xParseCell(pPage, pCell, &info); - if( info.nLocalaData+pPage->maskPage - && iFrom==get4byte(pCell+info.nSize-4) - ){ - put4byte(pCell+info.nSize-4, iTo); - break; + if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } + if( iFrom==get4byte(pCell+info.nSize-4) ){ + put4byte(pCell+info.nSize-4, iTo); + break; + } } }else{ if( get4byte(pCell)==iFrom ){ @@ -58486,12 +63169,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( i==nCell ){ if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pPage->pgno); } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } - - pPage->isInit = isInitOrig; } return SQLITE_OK; } @@ -59008,7 +63689,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr if( pBtree ){ sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ rc = saveCursorPosition(p); @@ -59022,10 +63702,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr p->eState = CURSOR_FAULT; p->skipNext = errCode; } - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; - } + btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } @@ -59082,7 +63759,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); testcase( pBt->nPage!=nPage ); pBt->nPage = nPage; - releasePage(pPage1); + releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); pBt->inTransaction = TRANS_READ; @@ -59150,7 +63827,12 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) ); sqlite3BtreeEnter(p); - rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); + if( op==SAVEPOINT_ROLLBACK ){ + rc = saveAllCursors(pBt, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); + } if( rc==SQLITE_OK ){ if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){ pBt->nPage = 0; @@ -59175,13 +63857,13 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ ** on the database already. If a write-cursor is requested, then ** the caller is assumed to have an open write transaction. ** -** If wrFlag==0, then the cursor can only be used for reading. -** If wrFlag==1, then the cursor can be used for reading or for -** writing if other conditions for writing are also met. These -** are the conditions that must be met in order for writing to -** be allowed: +** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only +** be used for reading. If the BTREE_WRCSR bit is set, then the cursor +** can be used for reading or for writing if other conditions for writing +** are also met. These are the conditions that must be met in order +** for writing to be allowed: ** -** 1: The cursor must have been opened with wrFlag==1 +** 1: The cursor must have been opened with wrFlag containing BTREE_WRCSR ** ** 2: Other database connections that share the same pager cache ** but which are not in the READ_UNCOMMITTED state may not have @@ -59193,6 +63875,16 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ ** ** 4: There must be an active transaction. ** +** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR +** is set. If FORDELETE is set, that is a hint to the implementation that +** this cursor will only be used to seek to and delete entries of an index +** as part of a larger DELETE statement. The FORDELETE hint is not used by +** this implementation. But in a hypothetical alternative storage engine +** in which index entries are automatically deleted when corresponding table +** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE +** operations on this cursor can be no-ops and all READ operations can +** return a null row (2-bytes: 0x01 0x00). +** ** No checking is done to make sure that page iTable really is the ** root page of a b-tree. If it is not, then the cursor acquired ** will not work correctly. @@ -59231,7 +63923,7 @@ static int btreeCursor( if( wrFlag ){ allocateTempSpace(pBt); - if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM; + if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT; } if( iTable==1 && btreePagecount(pBt)==0 ){ assert( wrFlag==0 ); @@ -59309,10 +64001,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ - int i; BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); - sqlite3BtreeClearCursor(pCur); assert( pBt->pCursor!=0 ); if( pBt->pCursor==pCur ){ pBt->pCursor = pCur->pNext; @@ -59326,12 +64016,10 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } - for(i=0; i<=pCur->iPage; i++){ - releasePage(pCur->apPage[i]); - } + btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); - /* sqlite3_free(pCur); */ + sqlite3_free(pCur->pKey); sqlite3BtreeLeave(pBtree); } return SQLITE_OK; @@ -59348,9 +64036,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ #ifndef NDEBUG static void assertCellInfo(BtCursor *pCur){ CellInfo info; - int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); - btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info); + btreeParseCell(pCur->pPage, pCur->ix, &info); assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 ); } #else @@ -59358,9 +64045,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ #endif static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ - int iPage = pCur->iPage; pCur->curFlags |= BTCF_ValidNKey; - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); + btreeParseCell(pCur->pPage,pCur->ix,&pCur->info); }else{ assertCellInfo(pCur); } @@ -59376,48 +64062,39 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ - -/* -** Set *pSize to the size of the buffer needed to hold the value of -** the key for the current entry. If the cursor is not pointing -** to a valid entry, *pSize is set to 0. -** -** For a table with the INTKEY flag set, this routine returns the key -** itself, not the number of bytes in the key. -** -** The caller must position the cursor prior to invoking this routine. -** -** This routine cannot fail. It always returns SQLITE_OK. -*/ -SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ - assert( cursorHoldsMutex(pCur) ); - assert( pCur->eState==CURSOR_VALID ); - getCellInfo(pCur); - *pSize = pCur->info.nKey; - return SQLITE_OK; +SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){ + assert( pCur!=0 ); + return pCur->eState==CURSOR_VALID; } /* -** Set *pSize to the number of bytes of data in the entry the -** cursor currently points to. +** Return the value of the integer key or "rowid" for a table btree. +** This routine is only valid for a cursor that is pointing into a +** ordinary table btree. If the cursor points to an index btree or +** is invalid, the result of this routine is undefined. +*/ +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->curIntKey ); + getCellInfo(pCur); + return pCur->info.nKey; +} + +/* +** Return the number of bytes of payload for the entry that pCur is +** currently pointing to. For table btrees, this will be the amount +** of data. For index btrees, this will be the size of the key. ** ** The caller must guarantee that the cursor is pointing to a non-NULL ** valid entry. In other words, the calling procedure must guarantee ** that the cursor has Cursor.eState==CURSOR_VALID. -** -** Failure is not possible. This function always returns SQLITE_OK. -** It might just as well be a procedure (returning void) but we continue -** to return an integer result code for historical reasons. */ -SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ +SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 ); - assert( pCur->iPageapPage[pCur->iPage]->intKeyLeaf==1 ); getCellInfo(pCur); - *pSize = pCur->info.nPayload; - return SQLITE_OK; + return pCur->info.nPayload; } /* @@ -59535,7 +64212,6 @@ static int copyPayload( ** ** 0: The operation is a read. Populate the overflow cache. ** 1: The operation is a write. Populate the overflow cache. -** 2: The operation is a read. Do not populate the overflow cache. ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. @@ -59543,13 +64219,13 @@ static int copyPayload( ** The content being read or written might appear on the main page ** or be scattered out on multiple overflow pages. ** -** If the current cursor entry uses one or more overflow pages and the -** eOp argument is not 2, this function may allocate space for and lazily -** populates the overflow page-list cache array (BtCursor.aOverflow). +** If the current cursor entry uses one or more overflow pages +** this function may allocate space for and lazily populate +** the overflow page-list cache array (BtCursor.aOverflow). ** Subsequent calls use this cache to make seeking to the supplied offset ** more efficient. ** -** Once an overflow page-list cache has been allocated, it may be +** Once an overflow page-list cache has been allocated, it must be ** invalidated if some other cursor writes to the same table, or if ** the cursor is moved to a different row. Additionally, in auto-vacuum ** mode, the following events may invalidate an overflow page-list cache. @@ -59568,29 +64244,30 @@ static int accessPayload( unsigned char *aPayload; int rc = SQLITE_OK; int iIdx = 0; - MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ + MemPage *pPage = pCur->pPage; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ - unsigned char * const pBufStart = pBuf; - int bEnd; /* True if reading to end of data */ + unsigned char * const pBufStart = pBuf; /* Start of original out buffer */ #endif assert( pPage ); + assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->aiIdx[pCur->iPage]nCell ); + assert( pCur->ixnCell ); assert( cursorHoldsMutex(pCur) ); - assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ getCellInfo(pCur); aPayload = pCur->info.pPayload; -#ifdef SQLITE_DIRECT_OVERFLOW_READ - bEnd = offset+amt==pCur->info.nPayload; -#endif assert( offset+amt <= pCur->info.nPayload ); - if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){ - /* Trying to read or write past the end of the data is an error */ - return SQLITE_CORRUPT_BKPT; + assert( aPayload > pPage->aData ); + if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){ + /* Trying to read or write past the end of the data is an error. The + ** conditional above is really: + ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] + ** but is recast into its current form to avoid integer overflow problems + */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } /* Check if data must be read/written to/from the btree page itself. */ @@ -59599,7 +64276,7 @@ static int accessPayload( if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; } - rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage); + rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); offset = 0; pBuf += a; amt -= a; @@ -59615,53 +64292,46 @@ static int accessPayload( nextPage = get4byte(&aPayload[pCur->info.nLocal]); /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. - ** Except, do not allocate aOverflow[] for eOp==2. ** ** The aOverflow[] array is sized at one entry for each overflow page ** in the overflow chain. The page number of the first overflow page is ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array ** means "not yet known" (the cache is lazily populated). */ - if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){ + if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; if( nOvfl>pCur->nOvflAlloc ){ Pgno *aNew = (Pgno*)sqlite3Realloc( pCur->aOverflow, nOvfl*2*sizeof(Pgno) ); if( aNew==0 ){ - rc = SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; }else{ pCur->nOvflAlloc = nOvfl*2; pCur->aOverflow = aNew; } } - if( rc==SQLITE_OK ){ - memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); - pCur->curFlags |= BTCF_ValidOvfl; + memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); + pCur->curFlags |= BTCF_ValidOvfl; + }else{ + /* If the overflow page-list cache has been allocated and the + ** entry for the first required overflow page is valid, skip + ** directly to it. + */ + if( pCur->aOverflow[offset/ovflSize] ){ + iIdx = (offset/ovflSize); + nextPage = pCur->aOverflow[iIdx]; + offset = (offset%ovflSize); } } - /* If the overflow page-list cache has been allocated and the - ** entry for the first required overflow page is valid, skip - ** directly to it. - */ - if( (pCur->curFlags & BTCF_ValidOvfl)!=0 - && pCur->aOverflow[offset/ovflSize] - ){ - iIdx = (offset/ovflSize); - nextPage = pCur->aOverflow[iIdx]; - offset = (offset%ovflSize); - } - - for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ - + assert( rc==SQLITE_OK && amt>0 ); + while( nextPage ){ /* If required, populate the overflow page-list cache. */ - if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){ - assert( pCur->aOverflow[iIdx]==0 - || pCur->aOverflow[iIdx]==nextPage - || CORRUPT_DB ); - pCur->aOverflow[iIdx] = nextPage; - } + assert( pCur->aOverflow[iIdx]==0 + || pCur->aOverflow[iIdx]==nextPage + || CORRUPT_DB ); + pCur->aOverflow[iIdx] = nextPage; if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page @@ -59669,11 +64339,7 @@ static int accessPayload( ** data is not required. So first try to lookup the overflow ** page-list cache, if any, then fall back to the getOverflowPage() ** function. - ** - ** Note that the aOverflow[] array must be allocated because eOp!=2 - ** here. If eOp==2, then offset==0 and this branch is never taken. */ - assert( eOp!=2 ); assert( pCur->curFlags & BTCF_ValidOvfl ); assert( pCur->pBtree->db==pBt->db ); if( pCur->aOverflow[iIdx+1] ){ @@ -59687,7 +64353,7 @@ static int accessPayload( ** range of data that is being read (eOp==0) or written (eOp!=0). */ #ifdef SQLITE_DIRECT_OVERFLOW_READ - sqlite3_file *fd; + sqlite3_file *fd; /* File from which to do direct overflow read */ #endif int a = amt; if( a + offset > ovflSize ){ @@ -59699,27 +64365,25 @@ static int accessPayload( ** ** 1) this is a read operation, and ** 2) data is required from the start of this overflow page, and - ** 3) the database is file-backed, and - ** 4) there is no open write-transaction, and - ** 5) the database is not a WAL database, - ** 6) all data from the page is being read. - ** 7) at least 4 bytes have already been read into the output buffer + ** 3) there is no open write-transaction, and + ** 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 ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds ** up loading large records that span many overflow pages. */ - if( (eOp&0x01)==0 /* (1) */ + if( eOp==0 /* (1) */ && offset==0 /* (2) */ - && (bEnd || a==ovflSize) /* (6) */ - && pBt->inTransaction==TRANS_READ /* (4) */ - && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */ - && pBt->pPage1->aData[19]==0x01 /* (5) */ - && &pBuf[-4]>=pBufStart /* (7) */ + && pBt->inTransaction==TRANS_READ /* (3) */ + && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (4) */ + && 0==sqlite3PagerUseWal(pBt->pPager, nextPage) /* (5) */ + && &pBuf[-4]>=pBufStart /* (6) */ ){ u8 aSave[4]; u8 *aWrite = &pBuf[-4]; - assert( aWrite>=pBufStart ); /* hence (7) */ + assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); nextPage = get4byte(aWrite); @@ -59730,76 +64394,86 @@ static int accessPayload( { DbPage *pDbPage; rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage, - ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0) + (eOp==0 ? PAGER_GET_READONLY : 0) ); if( rc==SQLITE_OK ){ aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); - rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage); + rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); sqlite3PagerUnref(pDbPage); offset = 0; } } amt -= a; + if( amt==0 ) return rc; pBuf += a; } + if( rc ) break; + iIdx++; } } if( rc==SQLITE_OK && amt>0 ){ - return SQLITE_CORRUPT_BKPT; + /* Overflow chain ends prematurely */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } return rc; } /* -** Read part of the key associated with cursor pCur. Exactly -** "amt" bytes will be transferred into pBuf[]. The transfer +** Read part of the payload for the row at which that cursor pCur is currently +** pointing. "amt" bytes will be transferred into pBuf[]. The transfer ** begins at "offset". ** -** The caller must ensure that pCur is pointing to a valid row -** in the table. +** pCur can be pointing to either a table or an index b-tree. +** If pointing to a table btree, then the content section is read. If +** pCur is pointing to an index b-tree then the key section is read. +** +** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing +** to a valid row in the table. For sqlite3BtreePayloadChecked(), the +** cursor might be invalid or might need to be restored before being read. ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ -SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ +SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->iPage>=0 && pCur->pPage ); + assert( pCur->ixpPage->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* -** Read part of the data associated with cursor pCur. Exactly -** "amt" bytes will be transfered into pBuf[]. The transfer -** begins at "offset". -** -** Return SQLITE_OK on success or an error code if anything goes -** wrong. An error is returned if "offset+amt" is larger than -** the available payload. +** This variant of sqlite3BtreePayload() works even if the cursor has not +** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read() +** interface. */ -SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - int rc; - #ifndef SQLITE_OMIT_INCRBLOB +static SQLITE_NOINLINE int accessPayloadChecked( + BtCursor *pCur, + u32 offset, + u32 amt, + void *pBuf +){ + int rc; if ( pCur->eState==CURSOR_INVALID ){ return SQLITE_ABORT; } -#endif - - assert( cursorHoldsMutex(pCur) ); - rc = restoreCursorPosition(pCur); - if( rc==SQLITE_OK ){ - assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - rc = accessPayload(pCur, offset, amt, pBuf, 0); - } - return rc; + assert( cursorOwnsBtShared(pCur) ); + rc = btreeRestoreCursorPosition(pCur); + return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0); } +SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ + if( pCur->eState==CURSOR_VALID ){ + assert( cursorOwnsBtShared(pCur) ); + return accessPayload(pCur, offset, amt, pBuf, 0); + }else{ + return accessPayloadChecked(pCur, offset, amt, pBuf); + } +} +#endif /* SQLITE_OMIT_INCRBLOB */ /* ** Return a pointer to payload information from the entry that the @@ -59824,18 +64498,23 @@ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ - u32 amt; - assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); + int amt; + assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - assert( cursorHoldsMutex(pCur) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->ixpPage->nCell ); assert( pCur->info.nSize>0 ); - assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); - assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); - amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); - if( pCur->info.nLocalinfo.nLocal; - *pAmt = amt; + assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); + assert( pCur->info.pPayloadpPage->aDataEnd ||CORRUPT_DB); + amt = pCur->info.nLocal; + if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){ + /* There is too little space on the page for the expected amount + ** of local content. Database must be corrupt. */ + assert( CORRUPT_DB ); + amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload)); + } + *pAmt = (u32)amt; return (void*)pCur->info.pPayload; } @@ -59854,10 +64533,7 @@ static const void *fetchPayload( ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ -SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){ - return fetchPayload(pCur, pAmt); -} -SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){ +SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ return fetchPayload(pCur, pAmt); } @@ -59874,7 +64550,7 @@ SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){ static int moveToChild(BtCursor *pCur, u32 newPgno){ BtShared *pBt = pCur->pBt; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPageiPage>=0 ); @@ -59883,13 +64559,14 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->aiIdx[pCur->iPage] = pCur->ix; + pCur->apPage[pCur->iPage] = pCur->pPage; + pCur->ix = 0; pCur->iPage++; - pCur->aiIdx[pCur->iPage] = 0; - return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], - pCur, pCur->curPagerFlags); + return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags); } -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* ** Page pParent is an internal (non-leaf) tree page. This function ** asserts that page number iChild is the left-child if the iIdx'th @@ -59920,19 +64597,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ - assert( cursorHoldsMutex(pCur) ); + MemPage *pLeaf; + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); - assert( pCur->apPage[pCur->iPage] ); + assert( pCur->pPage ); assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], - pCur->apPage[pCur->iPage]->pgno + pCur->pPage->pgno ); testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); - releasePageNotNull(pCur->apPage[pCur->iPage--]); + pCur->ix = pCur->aiIdx[pCur->iPage-1]; + pLeaf = pCur->pPage; + pCur->pPage = pCur->apPage[--pCur->iPage]; + releasePageNotNull(pLeaf); } /* @@ -59944,9 +64625,9 @@ static void moveToParent(BtCursor *pCur){ ** single child page. This can only happen with the table rooted at page 1. ** ** If the b-tree structure is empty, the cursor state is set to -** CURSOR_INVALID. Otherwise, the cursor is set to point to the first -** cell located on the root (or virtual root) page and the cursor state -** is set to CURSOR_VALID. +** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise, +** the cursor is set to point to the first cell located on the root +** (or virtual root) page and the cursor state is set to CURSOR_VALID. ** ** If this function returns successfully, it may be assumed that the ** page-header flags indicate that the [virtual] root-page is the expected @@ -59960,38 +64641,44 @@ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; int rc = SQLITE_OK; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); - if( pCur->eState>=CURSOR_REQUIRESEEK ){ - if( pCur->eState==CURSOR_FAULT ){ - assert( pCur->skipNext!=SQLITE_OK ); - return pCur->skipNext; - } - sqlite3BtreeClearCursor(pCur); - } + assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 ); + assert( pCur->pgnoRoot>0 || pCur->iPage<0 ); if( pCur->iPage>=0 ){ - while( pCur->iPage ){ - assert( pCur->apPage[pCur->iPage]!=0 ); - releasePageNotNull(pCur->apPage[pCur->iPage--]); + if( pCur->iPage ){ + releasePageNotNull(pCur->pPage); + while( --pCur->iPage ){ + releasePageNotNull(pCur->apPage[pCur->iPage]); + } + pCur->pPage = pCur->apPage[0]; + goto skip_init; } }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; - return SQLITE_OK; + return SQLITE_EMPTY; }else{ assert( pCur->iPage==(-1) ); - rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + if( pCur->eState==CURSOR_FAULT ){ + assert( pCur->skipNext!=SQLITE_OK ); + return pCur->skipNext; + } + sqlite3BtreeClearCursor(pCur); + } + rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage, 0, pCur->curPagerFlags); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; - pCur->curIntKey = pCur->apPage[0]->intKey; + pCur->curIntKey = pCur->pPage->intKey; } - pRoot = pCur->apPage[0]; + pRoot = pCur->pPage; assert( pRoot->pgno==pCur->pgnoRoot ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor @@ -60006,13 +64693,15 @@ static int moveToRoot(BtCursor *pCur){ ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno); } - pCur->aiIdx[0] = 0; +skip_init: + pCur->ix = 0; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); + pRoot = pCur->pPage; if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ @@ -60023,6 +64712,7 @@ static int moveToRoot(BtCursor *pCur){ rc = moveToChild(pCur, subpage); }else{ pCur->eState = CURSOR_INVALID; + rc = SQLITE_EMPTY; } return rc; } @@ -60039,11 +64729,11 @@ static int moveToLeftmost(BtCursor *pCur){ int rc = SQLITE_OK; MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ - assert( pCur->aiIdx[pCur->iPage]nCell ); - pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage])); + while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ + assert( pCur->ixnCell ); + pgno = get4byte(findCell(pPage, pCur->ix)); rc = moveToChild(pCur, pgno); } return rc; @@ -60064,15 +64754,15 @@ static int moveToRightmost(BtCursor *pCur){ int rc = SQLITE_OK; MemPage *pPage = 0; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - pCur->aiIdx[pCur->iPage] = pPage->nCell; + pCur->ix = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; } - pCur->aiIdx[pCur->iPage] = pPage->nCell-1; + pCur->ix = pPage->nCell-1; assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); return SQLITE_OK; @@ -60085,18 +64775,17 @@ static int moveToRightmost(BtCursor *pCur){ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ - if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - *pRes = 1; - }else{ - assert( pCur->apPage[pCur->iPage]->nCell>0 ); - *pRes = 0; - rc = moveToLeftmost(pCur); - } + assert( pCur->pPage->nCell>0 ); + *pRes = 0; + rc = moveToLeftmost(pCur); + }else if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; } return rc; } @@ -60108,7 +64797,7 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ @@ -60120,28 +64809,26 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ for(ii=0; iiiPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } - assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 ); - assert( pCur->apPage[pCur->iPage]->leaf ); + assert( pCur->ix==pCur->pPage->nCell-1 ); + assert( pCur->pPage->leaf ); #endif return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ - if( CURSOR_INVALID==pCur->eState ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - *pRes = 1; + assert( pCur->eState==CURSOR_VALID ); + *pRes = 0; + rc = moveToRightmost(pCur); + if( rc==SQLITE_OK ){ + pCur->curFlags |= BTCF_AtLast; }else{ - assert( pCur->eState==CURSOR_VALID ); - *pRes = 0; - rc = moveToRightmost(pCur); - if( rc==SQLITE_OK ){ - pCur->curFlags |= BTCF_AtLast; - }else{ - pCur->curFlags &= ~BTCF_AtLast; - } - + pCur->curFlags &= ~BTCF_AtLast; } + }else if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; } return rc; } @@ -60186,23 +64873,44 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( int rc; RecordCompare xRecordCompare; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); + assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 - && pCur->curIntKey + if( pIdxKey==0 + && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } - if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKeyinfo.nKeycurFlags & BTCF_AtLast)!=0 ){ + *pRes = -1; + return SQLITE_OK; + } + /* If the requested key is one more than the previous key, then + ** 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 ){ + *pRes = 0; + rc = sqlite3BtreeNext(pCur, 0); + if( rc==SQLITE_OK ){ + getCellInfo(pCur); + if( pCur->info.nKey==intKey ){ + return SQLITE_OK; + } + }else if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + }else{ + return rc; + } + } } } @@ -60219,22 +64927,23 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( rc = moveToRoot(pCur); if( rc ){ + if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return SQLITE_OK; + } return rc; } - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit ); - assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 ); - if( pCur->eState==CURSOR_INVALID ){ - *pRes = -1; - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - return SQLITE_OK; - } - assert( pCur->apPage[0]->intKey==pCur->curIntKey ); + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); assert( pCur->curIntKey || pIdxKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; - MemPage *pPage = pCur->apPage[pCur->iPage]; + MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page @@ -60249,14 +64958,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ - pCur->aiIdx[pCur->iPage] = (u16)idx; + pCur->ix = (u16)idx; if( xRecordCompare==0 ){ for(;;){ i64 nCellKey; pCell = findCellPastPtr(pPage, idx); if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ - if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + if( pCell>=pPage->aDataEnd ){ + return SQLITE_CORRUPT_PGNO(pPage->pgno); + } } } getVarint(pCell, (u64*)&nCellKey); @@ -60268,16 +64979,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); - pCur->curFlags |= BTCF_ValidNKey; - pCur->info.nKey = nCellKey; - pCur->aiIdx[pCur->iPage] = (u16)idx; + pCur->ix = (u16)idx; if( !pPage->leaf ){ lwr = idx; goto moveto_next_layer; }else{ + pCur->curFlags |= BTCF_ValidNKey; + pCur->info.nKey = nCellKey; + pCur->info.nSize = 0; *pRes = 0; - rc = SQLITE_OK; - goto moveto_finish; + return SQLITE_OK; } } assert( lwr+upr>=0 ); @@ -60329,16 +65040,17 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pPage->pgno); goto moveto_finish; } pCellKey = sqlite3Malloc( nCell+18 ); if( pCellKey==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto moveto_finish; } - pCur->aiIdx[pCur->iPage] = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2); + pCur->ix = (u16)idx; + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; @@ -60358,8 +65070,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( assert( c==0 ); *pRes = 0; rc = SQLITE_OK; - pCur->aiIdx[pCur->iPage] = (u16)idx; - if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; + pCur->ix = (u16)idx; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; goto moveto_finish; } if( lwr>upr ) break; @@ -60370,8 +65082,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - pCur->aiIdx[pCur->iPage] = (u16)idx; + assert( pCur->ixpPage->nCell ); + pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_finish; @@ -60382,13 +65094,13 @@ moveto_next_layer: }else{ chldPg = get4byte(findCell(pPage, lwr)); } - pCur->aiIdx[pCur->iPage] = (u16)lwr; + pCur->ix = (u16)lwr; rc = moveToChild(pCur, chldPg); if( rc ) break; } moveto_finish: pCur->info.nSize = 0; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; } @@ -60409,10 +65121,37 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ } /* -** Advance the cursor to the next entry in the database. If -** successful then set *pRes=0. If the cursor -** was already pointing to the last entry in the database before -** this routine was called, then set *pRes=1. +** Return an estimate for the number of rows in the table that pCur is +** pointing to. Return a negative number if no estimate is currently +** available. +*/ +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ + i64 n; + u8 i; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + /* Currently this interface is only called by the OP_IfSmaller + ** opcode, and it that case the cursor will always be valid and + ** will always point to a leaf node. */ + if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1; + if( NEVER(pCur->pPage->leaf==0) ) return -1; + + n = pCur->pPage->nCell; + for(i=0; iiPage; i++){ + n *= pCur->apPage[i]->nCell; + } + return n; +} + +/* +** Advance the cursor to the next entry in the database. +** Return value: +** +** SQLITE_OK success +** SQLITE_DONE cursor is already pointing at the last element +** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreeNext(). That routine is optimized ** for the common case of merely incrementing the cell counter BtCursor.aiIdx @@ -60420,23 +65159,19 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ ** routine is called when it is necessary to move to a different page or ** to restore the cursor. ** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) +** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the +** cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument +** is a hint to the implement. SQLite btree implementation does not use +** this hint, but COMDB2 does. */ -static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ int rc; int idx; MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - assert( *pRes==0 ); if( pCur->eState!=CURSOR_VALID ){ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); @@ -60444,8 +65179,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ return rc; } if( CURSOR_INVALID==pCur->eState ){ - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } if( pCur->skipNext ){ assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); @@ -60458,8 +65192,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } } - pPage = pCur->apPage[pCur->iPage]; - idx = ++pCur->aiIdx[pCur->iPage]; + pPage = pCur->pPage; + idx = ++pCur->ix; assert( pPage->isInit ); /* If the database file is corrupt, it is possible for the value of idx @@ -60477,15 +65211,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } do{ if( pCur->iPage==0 ){ - *pRes = 1; pCur->eState = CURSOR_INVALID; - return SQLITE_OK; + return SQLITE_DONE; } moveToParent(pCur); - pPage = pCur->apPage[pCur->iPage]; - }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); + pPage = pCur->pPage; + }while( pCur->ix>=pPage->nCell ); if( pPage->intKey ){ - return sqlite3BtreeNext(pCur, pRes); + return sqlite3BtreeNext(pCur, 0); }else{ return SQLITE_OK; } @@ -60496,20 +65229,19 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ return moveToLeftmost(pCur); } } -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){ MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); + 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); - *pRes = 0; - if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); - pPage = pCur->apPage[pCur->iPage]; - if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){ - pCur->aiIdx[pCur->iPage]--; - return btreeNext(pCur, pRes); + if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur); + pPage = pCur->pPage; + if( (++pCur->ix)>=pPage->nCell ){ + pCur->ix--; + return btreeNext(pCur); } if( pPage->leaf ){ return SQLITE_OK; @@ -60519,10 +65251,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ } /* -** Step the cursor to the back to the previous entry in the database. If -** successful then set *pRes=0. If the cursor -** was already pointing to the first entry in the database before -** this routine was called, then set *pRes=1. +** Step the cursor to the back to the previous entry in the database. +** Return values: +** +** SQLITE_OK success +** SQLITE_DONE the cursor is already on the first element of the table +** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreePrevious(). That routine is optimized ** for the common case of merely decrementing the cell counter BtCursor.aiIdx @@ -60530,22 +65264,17 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** helper routine is called when it is necessary to move to a different page ** or to restore the cursor. ** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) +** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then +** the cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument is a +** hint to the implement. The native SQLite btree implementation does not +** use this hint, but COMDB2 does. */ -static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ int rc; MemPage *pPage; - assert( cursorHoldsMutex(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 ); + 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 ); @@ -60555,8 +65284,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ return rc; } if( CURSOR_INVALID==pCur->eState ){ - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } if( pCur->skipNext ){ assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); @@ -60569,50 +65297,48 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ } } - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; assert( pPage->isInit ); if( !pPage->leaf ){ - int idx = pCur->aiIdx[pCur->iPage]; + int idx = pCur->ix; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ - while( pCur->aiIdx[pCur->iPage]==0 ){ + while( pCur->ix==0 ){ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } moveToParent(pCur); } assert( pCur->info.nSize==0 ); - assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 ); + assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 ); - pCur->aiIdx[pCur->iPage]--; - pPage = pCur->apPage[pCur->iPage]; + pCur->ix--; + pPage = pCur->pPage; if( pPage->intKey && !pPage->leaf ){ - rc = sqlite3BtreePrevious(pCur, pRes); + rc = sqlite3BtreePrevious(pCur, 0); }else{ rc = SQLITE_OK; } } return rc; } -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ - assert( cursorHoldsMutex(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){ + assert( cursorOwnsBtShared(pCur) ); + assert( flags==0 || flags==1 ); assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - *pRes = 0; + UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID - || pCur->aiIdx[pCur->iPage]==0 - || pCur->apPage[pCur->iPage]->leaf==0 + || pCur->ix==0 + || pCur->pPage->leaf==0 ){ - return btreePrevious(pCur, pRes); + return btreePrevious(pCur); } - pCur->aiIdx[pCur->iPage]--; + pCur->ix--; return SQLITE_OK; } @@ -60718,7 +65444,7 @@ static int allocateBtreePage( } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } @@ -60747,7 +65473,7 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList @@ -60781,7 +65507,7 @@ static int allocateBtreePage( MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iNewTrunk==mxPage ); @@ -60846,7 +65572,7 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); @@ -61102,30 +65828,30 @@ static void freePage(MemPage *pPage, int *pRC){ static int clearCell( MemPage *pPage, /* The page that contains the Cell */ unsigned char *pCell, /* First byte of the Cell */ - u16 *pnSize /* Write the size of the Cell here */ + CellInfo *pInfo /* Size information about the cell */ ){ - BtShared *pBt = pPage->pBt; - CellInfo info; + BtShared *pBt; Pgno ovflPgno; int rc; int nOvfl; u32 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - pPage->xParseCell(pPage, pCell, &info); - *pnSize = info.nSize; - if( info.nLocal==info.nPayload ){ + pPage->xParseCell(pPage, pCell, pInfo); + if( pInfo->nLocal==pInfo->nPayload ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } - if( pCell+info.nSize-1 > pPage->aData+pPage->maskPage ){ - return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */ + if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){ + /* Cell extends past end of page */ + return SQLITE_CORRUPT_PGNO(pPage->pgno); } - ovflPgno = get4byte(pCell + info.nSize - 4); + ovflPgno = get4byte(pCell + pInfo->nSize - 4); + pBt = pPage->pBt; assert( pBt->usableSize > 4 ); ovflPageSize = pBt->usableSize - 4; - nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize; + nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize; assert( nOvfl>0 || - (CORRUPT_DB && (info.nPayload + ovflPageSize)nPayload + ovflPageSize)pBt; - Pgno pgnoOvfl = 0; + BtShared *pBt; + Pgno pgnoOvfl; int nHeader; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* pPage is not necessarily writeable since pCell might be auxiliary ** buffer space that is separate from the pPage buffer area */ - assert( pCellaData || pCell>=&pPage->aData[pBt->pageSize] + assert( pCellaData || pCell>=&pPage->aData[pPage->pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ nHeader = pPage->childPtrSize; - nPayload = nData + nZero; - if( pPage->intKeyLeaf ){ - nHeader += putVarint32(&pCell[nHeader], nPayload); - }else{ - assert( nData==0 ); - assert( nZero==0 ); - } - nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); - - /* Fill in the payload size */ if( pPage->intKey ){ - pSrc = pData; - nSrc = nData; - nData = 0; - }else{ - assert( nKey<=0x7fffffff && pKey!=0 ); - nPayload = (int)nKey; - pSrc = pKey; - nSrc = (int)nKey; + nPayload = pX->nData + pX->nZero; + pSrc = pX->pData; + nSrc = pX->nData; + assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */ + nHeader += putVarint32(&pCell[nHeader], nPayload); + nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey); + }else{ + assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); + nSrc = nPayload = (int)pX->nKey; + pSrc = pX->pKey; + nHeader += putVarint32(&pCell[nHeader], nPayload); } + + /* Fill in the payload */ + pPayload = &pCell[nHeader]; if( nPayload<=pPage->maxLocal ){ + /* This is the common case where everything fits on the btree page + ** and no overflow pages are required. */ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); if( n<4 ) n = 4; *pnSize = n; - spaceLeft = nPayload; - pPrior = pCell; - }else{ - int mn = pPage->minLocal; - n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); - testcase( n==pPage->maxLocal ); - testcase( n==pPage->maxLocal+1 ); - if( n > pPage->maxLocal ) n = mn; - spaceLeft = n; - *pnSize = n + nHeader + 4; - pPrior = &pCell[nHeader+n]; + assert( nSrc<=nPayload ); + testcase( nSrcminLocal; + n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); + testcase( n==pPage->maxLocal ); + testcase( n==pPage->maxLocal+1 ); + if( n > pPage->maxLocal ) n = mn; + spaceLeft = n; + *pnSize = n + nHeader + 4; + pPrior = &pCell[nHeader+n]; + pToRelease = 0; + pgnoOvfl = 0; + pBt = pPage->pBt; /* At this point variables should be set as follows: ** @@ -61261,20 +65990,47 @@ static int fillInCell( ** Use a call to btreeParseCellPtr() to verify that the values above ** were computed correctly. */ -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG { CellInfo info; pPage->xParseCell(pPage, pCell, &info); - assert( nHeader=(int)(info.pPayload - pCell) ); - assert( info.nKey==nKey ); + assert( nHeader==(int)(info.pPayload - pCell) ); + assert( info.nKey==pX->nKey ); assert( *pnSize == info.nSize ); assert( spaceLeft == info.nLocal ); } #endif /* Write the payload into the local Cell and any extra into overflow pages */ - while( nPayload>0 ){ + while( 1 ){ + n = nPayload; + if( n>spaceLeft ) n = spaceLeft; + + /* If pToRelease is not zero than pPayload points into the data area + ** of pToRelease. Make sure pToRelease is still writeable. */ + assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); + + /* If pPayload is part of the data area of pPage, then make sure pPage + ** is still writeable */ + assert( pPayloadaData || pPayload>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + if( nSrc>=n ){ + memcpy(pPayload, pSrc, n); + }else if( nSrc>0 ){ + n = nSrc; + memcpy(pPayload, pSrc, n); + }else{ + memset(pPayload, 0, n); + } + nPayload -= n; + if( nPayload<=0 ) break; + pPayload += n; + pSrc += n; + nSrc -= n; + spaceLeft -= n; if( spaceLeft==0 ){ + MemPage *pOvfl = 0; #ifndef SQLITE_OMIT_AUTOVACUUM Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ if( pBt->autoVacuum ){ @@ -61327,34 +66083,6 @@ static int fillInCell( pPayload = &pOvfl->aData[4]; spaceLeft = pBt->usableSize - 4; } - n = nPayload; - if( n>spaceLeft ) n = spaceLeft; - - /* If pToRelease is not zero than pPayload points into the data area - ** of pToRelease. Make sure pToRelease is still writeable. */ - assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); - - /* If pPayload is part of the data area of pPage, then make sure pPage - ** is still writeable */ - assert( pPayloadaData || pPayload>=&pPage->aData[pBt->pageSize] - || sqlite3PagerIswriteable(pPage->pDbPage) ); - - if( nSrc>0 ){ - if( n>nSrc ) n = nSrc; - assert( pSrc ); - memcpy(pPayload, pSrc, n); - }else{ - memset(pPayload, 0, n); - } - nPayload -= n; - pPayload += n; - pSrc += n; - nSrc -= n; - spaceLeft -= n; - if( nSrc==0 ){ - nSrc = nData; - pSrc = pData; - } } releasePage(pToRelease); return SQLITE_OK; @@ -61376,7 +66104,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; - assert( idx>=0 && idxnCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); @@ -61387,7 +66114,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ hdr = pPage->hdrOffset; testcase( pc==get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); - if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){ + if( pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; return; } @@ -61421,6 +66148,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. +** +** *pRC must be SQLITE_OK when this routine is called. */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ @@ -61436,8 +66165,7 @@ static void insertCell( u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ - if( *pRC ) return; - + assert( *pRC==SQLITE_OK ); assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); @@ -61459,7 +66187,10 @@ static void insertCell( put4byte(pCell, iChild); } j = pPage->nOverflow++; - assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) ); + /* Comparison against ArraySize-1 since we hold back one extra slot + ** as a contingency. In other words, never need more than 3 overflow + ** slots but 4 are allocated, just to be safe. */ + assert( j < ArraySize(pPage->apOvfl)-1 ); pPage->apOvfl[j] = pCell; pPage->aiOvfl[j] = (u16)i; @@ -61511,7 +66242,7 @@ static void insertCell( /* ** A CellArray object contains a cache of pointers and sizes for a -** consecutive sequence of cells that might be held multiple pages. +** consecutive sequence of cells that might be held on multiple pages. */ typedef struct CellArray CellArray; struct CellArray { @@ -61656,8 +66387,8 @@ static int pageInsertArray( u8 *pSlot; sz = cachedCellSize(pCArray, i); if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){ + if( (pData - pBegin)apCell[i] will never overlap on a well-formed @@ -61819,7 +66550,7 @@ static int editPage( for(i=0; iapCell[i+iNew]; int iOff = get2byteAligned(&pPg->aCellIdx[i*2]); - if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){ + if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){ pCell = &pTmp[pCell - aData]; } assert( 0==memcmp(pCell, &aData[iOff], @@ -61943,8 +66674,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ while( ((*(pOut++) = *(pCell++))&0x80) && pCellnCell, pSpace, (int)(pOut-pSpace), - 0, pPage->pgno, &rc); + if( rc==SQLITE_OK ){ + insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), + 0, pPage->pgno, &rc); + } /* Set the right-child pointer of pParent to point to the new page. */ put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); @@ -62153,7 +66886,7 @@ static int balance_nonroot( assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx ); if( !aOvflSpace ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } /* Find the sibling pages to balance. Also locate the cells in pParent @@ -62197,7 +66930,7 @@ static int balance_nonroot( nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; if( (i--)==0 ) break; - if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){ + if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ apDiv[i] = pParent->apOvfl[0]; pgno = get4byte(apDiv[i]); szNew[i] = pParent->xCellSize(pParent, apDiv[i]); @@ -62219,7 +66952,7 @@ static int balance_nonroot( ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ - if( pBt->btsFlags & BTS_SECURE_DELETE ){ + if( pBt->btsFlags & BTS_FAST_SECURE ){ int iOff; iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); @@ -62248,12 +66981,10 @@ static int balance_nonroot( + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ - /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer - ** that is more than 6 times the database page size. */ assert( szScratch<=6*(int)pBt->pageSize ); - b.apCell = sqlite3ScratchMalloc( szScratch ); + b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto balance_cleanup; } b.szCell = (u16*)&b.apCell[nMaxCells]; @@ -62312,9 +67043,8 @@ static int balance_nonroot( ** long be able to find the cells if a pointer to each cell is not saved ** first. */ - memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*limit); + memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ - memset(&b.szCell[b.nCell+limit], 0, sizeof(b.szCell[0])*pOld->nOverflow); limit = pOld->aiOvfl[0]; for(j=0; jnFree; - if( szNew[i]<0 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } for(j=0; jnOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); } @@ -62465,7 +67194,7 @@ static int balance_nonroot( assert( r szLeft-(b.szCell[r]+2)) ){ + && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){ break; } szRight += b.szCell[d] + 2; @@ -62689,9 +67418,9 @@ static int balance_nonroot( ** any cell). But it is important to pass the correct size to ** insertCell(), so reparse the cell now. ** - ** Note that this can never happen in an SQLite data file, as all - ** cells are at least 4 bytes. It only happens in b-trees used - ** to evaluate "IN (SELECT ...)" and similar clauses. + ** This can only happen for b-trees used to evaluate "IN (SELECT ...)" + ** and WITHOUT ROWID tables with exactly one column which is the + ** primary key. */ if( b.szCell[j]==4 ){ assert(leafCorrection==4); @@ -62788,7 +67517,7 @@ static int balance_nonroot( ** free space needs to be up front. */ assert( nNew==1 || CORRUPT_DB ); - rc = defragmentPage(apNew[0]); + 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) @@ -62831,7 +67560,7 @@ static int balance_nonroot( ** Cleanup before returning. */ balance_cleanup: - sqlite3ScratchFree(b.apCell); + sqlite3StackFree(0, b.apCell); for(i=0; iiPage; - MemPage *pPage = pCur->apPage[iPage]; + MemPage *pPage = pCur->pPage; if( iPage==0 ){ if( pPage->nOverflow ){ @@ -62939,13 +67668,16 @@ static int balance(BtCursor *pCur){ ** and copy the current contents of the root-page to it. The ** next iteration of the do-loop will balance the child page. */ - assert( (balance_deeper_called++)==0 ); + assert( balance_deeper_called==0 ); + VVA_ONLY( balance_deeper_called++ ); rc = balance_deeper(pPage, &pCur->apPage[1]); if( rc==SQLITE_OK ){ pCur->iPage = 1; + pCur->ix = 0; pCur->aiIdx[0] = 0; - pCur->aiIdx[1] = 0; - assert( pCur->apPage[1]->nOverflow ); + pCur->apPage[0] = pPage; + pCur->pPage = pCur->apPage[1]; + assert( pCur->pPage->nOverflow ); } }else{ break; @@ -62978,7 +67710,8 @@ static int balance(BtCursor *pCur){ ** function. If this were not verified, a subtle bug involving reuse ** of the aBalanceQuickSpace[] might sneak in. */ - assert( (balance_quick_called++)==0 ); + assert( balance_quick_called==0 ); + VVA_ONLY( balance_quick_called++ ); rc = balance_quick(pParent, pPage, aBalanceQuickSpace); }else #endif @@ -63024,6 +67757,7 @@ static int balance(BtCursor *pCur){ releasePage(pPage); pCur->iPage--; assert( pCur->iPage>=0 ); + pCur->pPage = pCur->apPage[pCur->iPage]; } }while( rc==SQLITE_OK ); @@ -63035,33 +67769,39 @@ static int balance(BtCursor *pCur){ /* -** Insert a new record into the BTree. The key is given by (pKey,nKey) -** and the data is given by (pData,nData). The cursor is used only to -** define what table the record should be inserted into. The cursor -** is left pointing at a random location. +** Insert a new record into the BTree. The content of the new record +** is described by the pX object. The pCur cursor is used only to +** define what table the record should be inserted into, and is left +** pointing at a random location. ** -** For an INTKEY table, only the nKey value of the key is used. pKey is -** ignored. For a ZERODATA table, the pData and nData are both ignored. +** For a table btree (used for rowid tables), only the pX.nKey value of +** the key is used. The pX.pKey value must be NULL. The pX.nKey is the +** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields +** hold the content of the row. +** +** For an index btree (used for indexes and WITHOUT ROWID tables), the +** key is an arbitrary byte sequence stored in pX.pKey,nKey. The +** pX.pData,nData,nZero fields must be zero. ** ** If the seekResult parameter is non-zero, then a successful call to -** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already -** been performed. seekResult is the search result returned (a negative -** number if pCur points at an entry that is smaller than (pKey, nKey), or -** a positive value if pCur points at an entry that is larger than -** (pKey, nKey)). +** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already +** been performed. In other words, if seekResult!=0 then the cursor +** is currently pointing to a cell that will be adjacent to the cell +** to be inserted. If seekResult<0 then pCur points to a cell that is +** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell +** that is larger than (pKey,nKey). ** -** If the seekResult parameter is non-zero, then the caller guarantees that -** cursor pCur is pointing at the existing copy of a row that is to be -** overwritten. If the seekResult parameter is 0, then cursor pCur may -** point to any entry or to no entry at all and so this function has to seek -** the cursor before the new key can be inserted. +** If seekResult==0, that means pCur is pointing at some unknown location. +** In that case, this routine must seek the cursor to the correct insertion +** point for (pKey,nKey) before doing the insertion. For index btrees, +** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked +** key values and pX->aMem can be used instead of pX->pKey to avoid having +** to decode the key. */ SQLITE_PRIVATE int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ - const void *pKey, i64 nKey, /* The key of the new record */ - const void *pData, int nData, /* The data of the new record */ - int nZero, /* Number of extra 0 bytes to append to data */ - int appendBias, /* True if this is likely an append */ + const BtreePayload *pX, /* Content of the row to be inserted */ + int flags, /* True if this is likely an append */ int seekResult /* Result of prior MovetoUnpacked() call */ ){ int rc; @@ -63074,12 +67814,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( unsigned char *oldCell; unsigned char *newCell = 0; + assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags ); + if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); @@ -63090,7 +67832,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ - assert( (pKey==0)==(pCur->pKeyInfo==0) ); + assert( (pX->pKey==0)==(pCur->pKeyInfo==0) ); /* Save the positions of any other cursors open on this table. ** @@ -63109,44 +67851,61 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( } if( pCur->pKeyInfo==0 ){ - assert( pKey==0 ); + assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ - invalidateIncrblobCursors(p, nKey, 0); + invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); + + /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing + ** to a row with the same key as the new entry being inserted. */ + assert( (flags & BTREE_SAVEPOSITION)==0 || + ((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) ); /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary ** btreeMoveto() call */ - if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 - && pCur->info.nKey==nKey-1 ){ - loc = -1; + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){ + loc = 0; }else if( loc==0 ){ - rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc); + rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); if( rc ) return rc; } - }else if( loc==0 ){ - rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc); + }else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ + if( pX->nMem ){ + UnpackedRecord r; + r.pKeyInfo = pCur->pKeyInfo; + r.aMem = pX->aMem; + r.nField = pX->nMem; + r.default_rc = 0; + r.errCode = 0; + r.r1 = 0; + r.r2 = 0; + r.eqSeen = 0; + rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); + }else{ + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + } if( rc ) return rc; } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); - pPage = pCur->apPage[pCur->iPage]; - assert( pPage->intKey || nKey>=0 ); + pPage = pCur->pPage; + assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", - pCur->pgnoRoot, nKey, nData, pPage->pgno, + pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); - rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); + rc = fillInCell(pPage, newCell, pX, &szNew); if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); - idx = pCur->aiIdx[pCur->iPage]; + idx = pCur->ix; if( loc==0 ){ - u16 szOld; + CellInfo info; assert( idxnCell ); rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ @@ -63156,16 +67915,35 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } - rc = clearCell(pPage, oldCell, &szOld); - dropCell(pPage, idx, szOld, &rc); + rc = clearCell(pPage, oldCell, &info); + if( info.nSize==szNew && info.nLocal==info.nPayload + && (!ISAUTOVACUUM || szNewminLocal) + ){ + /* Overwrite the old cell with the new if they are the same size. + ** We could also try to do this if the old cell is smaller, then add + ** the leftover space to the free list. But experiments show that + ** doing that is no faster then skipping this optimization and just + ** calling dropCell() and insertCell(). + ** + ** This optimization cannot be used on an autovacuum database if the + ** new entry uses overflow pages, as the insertCell() call below is + ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ + assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ + if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + memcpy(oldCell, newCell, szNew); + return SQLITE_OK; + } + dropCell(pPage, idx, info.nSize, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); - idx = ++pCur->aiIdx[pCur->iPage]; + idx = ++pCur->ix; + pCur->curFlags &= ~BTCF_ValidNKey; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); + assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() @@ -63189,7 +67967,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( ** row without seeking the cursor. This can be a big performance boost. */ pCur->info.nSize = 0; - if( rc==SQLITE_OK && pPage->nOverflow ){ + if( pPage->nOverflow ){ + assert( rc==SQLITE_OK ); pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); @@ -63197,10 +67976,24 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() ** from trying to save the current position of the cursor. */ - pCur->apPage[pCur->iPage]->nOverflow = 0; + pCur->pPage->nOverflow = 0; pCur->eState = CURSOR_INVALID; + if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){ + btreeReleaseAllCursorPages(pCur); + if( pCur->pKeyInfo ){ + assert( pCur->pKey==0 ); + pCur->pKey = sqlite3Malloc( pX->nKey ); + if( pCur->pKey==0 ){ + rc = SQLITE_NOMEM; + }else{ + memcpy(pCur->pKey, pX->pKey, pX->nKey); + } + } + pCur->eState = CURSOR_REQUIRESEEK; + pCur->nKey = pX->nKey; + } } - assert( pCur->apPage[pCur->iPage]->nOverflow==0 ); + assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; @@ -63209,13 +68002,21 @@ end_insert: /* ** Delete the entry that the cursor is pointing to. ** -** If the second parameter is zero, then the cursor is left pointing at an -** arbitrary location after the delete. If it is non-zero, then the cursor -** is left in a state such that the next call to BtreeNext() or BtreePrev() -** moves it to the same row as it would if the call to BtreeDelete() had -** been omitted. +** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then +** the cursor is left pointing at an arbitrary location after the delete. +** But if that bit is set, then the cursor is left in a state such that +** the next call to BtreeNext() or BtreePrev() moves it to the same row +** as it would have been on if the call to BtreeDelete() had been omitted. +** +** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes +** associated with a single table entry and its indexes. Only one of those +** deletes is considered the "primary" delete. The primary delete occurs +** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete +** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag. +** The BTREE_AUXDELETE bit is a hint that is not used by this implementation, +** but which might be used by alternative storage engines. */ -SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ +SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; int rc; /* Return code */ @@ -63223,49 +68024,25 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ unsigned char *pCell; /* Pointer to cell to delete */ int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ - u16 szCell; /* Size of the cell being deleted */ + CellInfo info; /* Size of the cell being deleted */ int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ + u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */ - assert( cursorHoldsMutex(pCur) ); + assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->ixpPage->nCell ); assert( pCur->eState==CURSOR_VALID ); + assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); iCellDepth = pCur->iPage; - iCellIdx = pCur->aiIdx[iCellDepth]; - pPage = pCur->apPage[iCellDepth]; + iCellIdx = pCur->ix; + pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); - /* If the page containing the entry to delete is not a leaf page, move - ** the cursor to the largest entry in the tree that is smaller than - ** the entry being deleted. This cell will replace the cell being deleted - ** from the internal node. The 'previous' entry is used for this instead - ** of the 'next' entry, as the previous entry is always a part of the - ** sub-tree headed by the child page of the cell being deleted. This makes - ** balancing the tree following the delete operation easier. */ - if( !pPage->leaf ){ - int notUsed = 0; - rc = sqlite3BtreePrevious(pCur, ¬Used); - if( rc ) return rc; - } - - /* Save the positions of any other cursors open on this table before - ** making any modifications. */ - if( pCur->curFlags & BTCF_Multiple ){ - rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); - if( rc ) return rc; - } - - /* If this is a delete operation to remove a row from a table b-tree, - ** invalidate any incrblob cursors open on the row being deleted. */ - if( pCur->pKeyInfo==0 ){ - invalidateIncrblobCursors(p, pCur->info.nKey, 0); - } - /* If the bPreserve flag is set to true, then the cursor position must ** be preserved following this delete operation. If the current delete ** will cause a b-tree rebalance, then this is done by saving the cursor @@ -63288,13 +68065,39 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ } } + /* If the page containing the entry to delete is not a leaf page, move + ** the cursor to the largest entry in the tree that is smaller than + ** the entry being deleted. This cell will replace the cell being deleted + ** from the internal node. The 'previous' entry is used for this instead + ** of the 'next' entry, as the previous entry is always a part of the + ** sub-tree headed by the child page of the cell being deleted. This makes + ** balancing the tree following the delete operation easier. */ + if( !pPage->leaf ){ + rc = sqlite3BtreePrevious(pCur, 0); + assert( rc!=SQLITE_DONE ); + if( rc ) return rc; + } + + /* Save the positions of any other cursors open on this table before + ** making any modifications. */ + if( pCur->curFlags & BTCF_Multiple ){ + rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); + if( rc ) return rc; + } + + /* If this is a delete operation to remove a row from a table b-tree, + ** invalidate any incrblob cursors open on the row being deleted. */ + if( pCur->pKeyInfo==0 ){ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); + } + /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; - rc = clearCell(pPage, pCell, &szCell); - dropCell(pPage, iCellIdx, szCell, &rc); + rc = clearCell(pPage, pCell, &info); + dropCell(pPage, iCellIdx, info.nSize, &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor @@ -63303,11 +68106,16 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ - MemPage *pLeaf = pCur->apPage[pCur->iPage]; + MemPage *pLeaf = pCur->pPage; int nCell; - Pgno n = pCur->apPage[iCellDepth+1]->pgno; + Pgno n; unsigned char *pTmp; + if( iCellDepthiPage-1 ){ + n = pCur->apPage[iCellDepth+1]->pgno; + }else{ + n = pCur->pPage->pgno; + } pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); @@ -63315,7 +68123,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); - insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); + if( rc==SQLITE_OK ){ + insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); + } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; } @@ -63337,29 +68147,34 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){ ** well. */ rc = balance(pCur); if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ + releasePageNotNull(pCur->pPage); + pCur->iPage--; while( pCur->iPage>iCellDepth ){ releasePage(pCur->apPage[pCur->iPage--]); } + pCur->pPage = pCur->apPage[pCur->iPage]; rc = balance(pCur); } if( rc==SQLITE_OK ){ if( bSkipnext ){ assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) ); - assert( pPage==pCur->apPage[pCur->iPage] ); + assert( pPage==pCur->pPage || CORRUPT_DB ); assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); pCur->eState = CURSOR_SKIPNEXT; if( iCellIdx>=pPage->nCell ){ pCur->skipNext = -1; - pCur->aiIdx[iCellDepth] = pPage->nCell-1; + pCur->ix = pPage->nCell-1; }else{ pCur->skipNext = 1; } }else{ rc = moveToRoot(pCur); if( bPreserve ){ + btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } + if( rc==SQLITE_EMPTY ) rc = SQLITE_OK; } } return rc; @@ -63542,7 +68357,7 @@ static int clearDatabasePage( unsigned char *pCell; int i; int hdr; - u16 szCell; + CellInfo info; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ @@ -63562,7 +68377,7 @@ static int clearDatabasePage( rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } - rc = clearCell(pPage, pCell, &szCell); + rc = clearCell(pPage, pCell, &info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ @@ -63610,7 +68425,7 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ /* Invalidate all incrblob cursors open on table iTable (assuming iTable ** is the root of a table b-tree - if it is not, the following call is ** a no-op). */ - invalidateIncrblobCursors(p, 0, 1); + invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); } sqlite3BtreeLeave(p); @@ -63653,19 +68468,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); - - /* It is illegal to drop a table if any cursors are open on the - ** database. This is because in auto-vacuum mode the backend may - ** need to move another root-page to fill a gap left by the deleted - ** root page. If an open cursor was using this page a problem would - ** occur. - ** - ** This error is caught long before control reaches this point. - */ - if( NEVER(pBt->pCursor) ){ - sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db); - return SQLITE_LOCKED_SHAREDCACHE; - } + assert( iTable>=2 ); rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; @@ -63677,76 +68480,67 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ *piMoved = 0; - if( iTable>1 ){ #ifdef SQLITE_OMIT_AUTOVACUUM - freePage(pPage, &rc); - releasePage(pPage); + freePage(pPage, &rc); + releasePage(pPage); #else - if( pBt->autoVacuum ){ - Pgno maxRootPgno; - sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); + if( pBt->autoVacuum ){ + Pgno maxRootPgno; + sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); - if( iTable==maxRootPgno ){ - /* If the table being dropped is the table with the largest root-page - ** number in the database, put the root page on the free list. - */ - freePage(pPage, &rc); - releasePage(pPage); - if( rc!=SQLITE_OK ){ - return rc; - } - }else{ - /* The table being dropped does not have the largest root-page - ** number in the database. So move the page that does into the - ** gap left by the deleted root-page. - */ - MemPage *pMove; - releasePage(pPage); - rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); - if( rc!=SQLITE_OK ){ - return rc; - } - rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); - releasePage(pMove); - if( rc!=SQLITE_OK ){ - return rc; - } - pMove = 0; - rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); - freePage(pMove, &rc); - releasePage(pMove); - if( rc!=SQLITE_OK ){ - return rc; - } - *piMoved = maxRootPgno; - } - - /* Set the new 'max-root-page' value in the database header. This - ** is the old value less one, less one more if that happens to - ** be a root-page number, less one again if that is the - ** PENDING_BYTE_PAGE. + if( iTable==maxRootPgno ){ + /* If the table being dropped is the table with the largest root-page + ** number in the database, put the root page on the free list. */ - maxRootPgno--; - while( maxRootPgno==PENDING_BYTE_PAGE(pBt) - || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ - maxRootPgno--; - } - assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); - - rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); - }else{ freePage(pPage, &rc); releasePage(pPage); + if( rc!=SQLITE_OK ){ + return rc; + } + }else{ + /* The table being dropped does not have the largest root-page + ** number in the database. So move the page that does into the + ** gap left by the deleted root-page. + */ + MemPage *pMove; + releasePage(pPage); + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); + releasePage(pMove); + if( rc!=SQLITE_OK ){ + return rc; + } + pMove = 0; + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + freePage(pMove, &rc); + releasePage(pMove); + if( rc!=SQLITE_OK ){ + return rc; + } + *piMoved = maxRootPgno; } -#endif - }else{ - /* If sqlite3BtreeDropTable was called on page 1. - ** This really never should happen except in a corrupt - ** database. + + /* Set the new 'max-root-page' value in the database header. This + ** is the old value less one, less one more if that happens to + ** be a root-page number, less one again if that is the + ** PENDING_BYTE_PAGE. */ - zeroPage(pPage, PTF_INTKEY|PTF_LEAF ); + maxRootPgno--; + while( maxRootPgno==PENDING_BYTE_PAGE(pBt) + || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ + maxRootPgno--; + } + assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); + + rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); + }else{ + freePage(pPage, &rc); releasePage(pPage); } +#endif return rc; } SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ @@ -63845,11 +68639,11 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ - if( pCur->pgnoRoot==0 ){ + rc = moveToRoot(pCur); + if( rc==SQLITE_EMPTY ){ *pnEntry = 0; return SQLITE_OK; } - rc = moveToRoot(pCur); /* Unless an error occurs, the following loop runs one iteration for each ** page in the B-Tree structure (not including overflow pages). @@ -63862,7 +68656,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ ** this page contains countable entries. Increment the entry counter ** accordingly. */ - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; if( pPage->leaf || !pPage->intKey ){ nEntry += pPage->nCell; } @@ -63885,16 +68679,16 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ return moveToRoot(pCur); } moveToParent(pCur); - }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); + }while ( pCur->ix>=pCur->pPage->nCell ); - pCur->aiIdx[pCur->iPage]++; - pPage = pCur->apPage[pCur->iPage]; + pCur->ix++; + pPage = pCur->pPage; } /* Descend to the child node of the cell that the cursor currently ** points at. This is the right-child if (iIdx==pPage->nCell). */ - iIdx = pCur->aiIdx[pCur->iPage]; + iIdx = pCur->ix; if( iIdx==pPage->nCell ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); }else{ @@ -63933,9 +68727,9 @@ static void checkAppendMsg( sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1); } if( pCheck->zPfx ){ - sqlite3XPrintf(&pCheck->errMsg, 0, pCheck->zPfx, pCheck->v1, pCheck->v2); + sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); } - sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap); + sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap); va_end(ap); if( pCheck->errMsg.accError==STRACCUM_NOMEM ){ pCheck->mallocFailed = 1; @@ -64279,6 +69073,7 @@ static int checkTreePage( checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey); } maxKey = info.nKey; + keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */ } /* Check the content overflow list */ @@ -64436,7 +69231,8 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); - assert( (nRef = sqlite3PagerRefcount(pBt->pPager))>=0 ); + VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); + assert( nRef>=0 ); sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = btreePagecount(sCheck.pBt); @@ -64449,6 +69245,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( sCheck.aPgRef = 0; sCheck.heap = 0; sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); + sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL; if( sCheck.nPage==0 ){ goto integrity_ck_cleanup; } @@ -64580,7 +69377,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * if( pBt->inTransaction!=TRANS_NONE ){ rc = SQLITE_LOCKED; }else{ - rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt); + rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); } sqlite3BtreeLeave(p); } @@ -64688,7 +69485,7 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ */ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; - assert( cursorHoldsMutex(pCsr) ); + assert( cursorOwnsBtShared(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert( pCsr->curFlags & BTCF_Incrblob ); @@ -64726,7 +69523,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); - assert( pCsr->apPage[pCsr->iPage]->intKey ); + assert( pCsr->pPage->intKey ); return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } @@ -64796,6 +69593,25 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ */ SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } +#if !defined(SQLITE_OMIT_SHARED_CACHE) +/* +** Return true if the Btree passed as the only argument is sharable. +*/ +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ + return p->sharable; +} + +/* +** Return the number of connections to the BtShared object accessed by +** the Btree handle passed as the only argument. For private caches +** this is always 1. For shared caches it may be 1 or greater. +*/ +SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ + testcase( p->sharable ); + return p->pBt->nRef; +} +#endif + /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* @@ -64883,22 +69699,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int i = sqlite3FindDbName(pDb, zDb); if( i==1 ){ - Parse *pParse; + Parse sParse; int rc = 0; - pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse)); - if( pParse==0 ){ - sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory"); - rc = SQLITE_NOMEM; - }else{ - pParse->db = pDb; - if( sqlite3OpenTempDatabase(pParse) ){ - sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg); - rc = SQLITE_ERROR; - } - sqlite3DbFree(pErrorDb, pParse->zErrMsg); - sqlite3ParserReset(pParse); - sqlite3StackFree(pErrorDb, pParse); + memset(&sParse, 0, sizeof(sParse)); + sParse.db = pDb; + if( sqlite3OpenTempDatabase(&sParse) ){ + sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); + rc = SQLITE_ERROR; } + sqlite3DbFree(pErrorDb, sParse.zErrMsg); + sqlite3ParserReset(&sParse); if( rc ){ return 0; } @@ -64944,7 +69754,7 @@ static int checkReadTransaction(sqlite3 *db, Btree *p){ ** If an error occurs, NULL is returned and an error code and error message ** stored in database handle pDestDb. */ -SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init( +SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3* pDestDb, /* Database to write to */ const char *zDestDb, /* Name of database within pDestDb */ sqlite3* pSrcDb, /* Database connection to read from */ @@ -64982,7 +69792,7 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init( ** sqlite3_backup_finish(). */ p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); if( !p ){ - sqlite3Error(pDestDb, SQLITE_NOMEM); + sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT); } } @@ -64996,7 +69806,6 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init( p->isAttached = 0; if( 0==p->pSrc || 0==p->pDest - || setDestPgsz(p)==SQLITE_NOMEM || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM @@ -65152,7 +69961,7 @@ static void attachBackupObject(sqlite3_backup *p){ /* ** Copy nPage pages from the source b-tree to the destination. */ -SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){ +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; int destMode; /* Destination journal mode */ int pgszSrc = 0; /* Source page size */ @@ -65184,14 +69993,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){ rc = SQLITE_OK; } - /* Lock the destination database, if it is not locked already. */ - if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) - ){ - p->bDestLocked = 1; - sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); - } - /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. @@ -65201,6 +70002,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){ bCloseTrans = 1; } + /* If the destination database has not yet been locked (i.e. if this + ** is the first call to backup_step() for the current backup operation), + ** try to set its page size to the same as the source database. This + ** is especially important on ZipVFS systems, as in that case it is + ** not possible to create a database file that uses one page size by + ** writing to it with another. */ + if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){ + rc = SQLITE_NOMEM; + } + + /* Lock the destination database, if it is not locked already. */ + if( SQLITE_OK==rc && p->bDestLocked==0 + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) + ){ + p->bDestLocked = 1; + sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); + } + /* Do not allow backup if the destination database is in WAL mode ** and the page sizes are different between source and destination */ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); @@ -65381,7 +70200,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){ } if( rc==SQLITE_IOERR_NOMEM ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } p->rc = rc; } @@ -65396,7 +70215,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* ** Release all resources associated with an sqlite3_backup* handle. */ -SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){ +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ sqlite3_backup **pp; /* Ptr to head of pagers backup list */ sqlite3 *pSrcDb; /* Source database connection */ int rc; /* Value to return */ @@ -65448,7 +70267,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){ ** Return the number of pages still to be backed up as of the most recent ** call to sqlite3_backup_step(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){ +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ){ (void)SQLITE_MISUSE_BKPT; @@ -65462,7 +70281,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){ ** Return the total number of pages in the source database as of the most ** recent call to sqlite3_backup_step(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){ +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ){ (void)SQLITE_MISUSE_BKPT; @@ -65577,10 +70396,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement ** checks this assumption - (p->rc) should be set to either SQLITE_DONE - ** or an error code. - */ + ** or an error code. */ sqlite3_backup_step(&b, 0x7FFFFFFF); assert( b.rc!=SQLITE_OK ); + rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; @@ -65627,7 +70446,7 @@ copy_finished: */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. - ** Mem.xDel is might not be initialized if MEM_Dyn is clear. + ** Mem.xDel might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); @@ -65640,6 +70459,35 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ /* Cannot be both MEM_Int and MEM_Real at the same time */ assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + if( p->flags & MEM_Null ){ + /* Cannot be both MEM_Null and some other type */ + assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob + |MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 ); + + /* If MEM_Null is set, then either the value is a pure NULL (the usual + ** case) or it is a pointer set using sqlite3_bind_pointer() or + ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be + ** set. + */ + if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){ + /* This is a pointer type. There may be a flag to indicate what to + ** do with the pointer. */ + assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + + ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); + + /* No other bits set */ + assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype + |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); + }else{ + /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, + ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */ + } + }else{ + /* The MEM_Cleared bit is only allowed on NULLs */ + assert( (p->flags & MEM_Cleared)==0 ); + } + /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) ); @@ -65716,6 +70564,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( (pMem->flags&MEM_RowSet)==0 ); + testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already ** contain a valid string or blob value. */ @@ -65724,26 +70573,25 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre assert( pMem->szMalloc==0 || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); - if( pMem->szMallocszMalloc>0 && pMem->z==pMem->zMalloc ){ - pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); - bPreserve = 0; - }else{ - if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); - pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); - } - if( pMem->zMalloc==0 ){ - sqlite3VdbeMemSetNull(pMem); - pMem->z = 0; - pMem->szMalloc = 0; - return SQLITE_NOMEM; - }else{ - 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; + }else{ + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); + pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); + } + if( pMem->zMalloc==0 ){ + sqlite3VdbeMemSetNull(pMem); + pMem->z = 0; + pMem->szMalloc = 0; + return SQLITE_NOMEM_BKPT; + }else{ + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } - if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){ + if( bPreserve && pMem->z ){ + assert( pMem->z!=pMem->zMalloc ); memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ @@ -65781,6 +70629,20 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ return SQLITE_OK; } +/* +** It is already known that pMem contains an unterminated string. +** Add the zero terminator. +*/ +static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ + if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ + return SQLITE_NOMEM_BKPT; + } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->flags |= MEM_Term; + return SQLITE_OK; +} + /* ** Change pMem so that its MEM_Str or MEM_Blob value is stored in ** MEM.zMalloc, where it can be safely written. @@ -65788,18 +70650,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ - int f; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( (pMem->flags&MEM_RowSet)==0 ); - ExpandBlob(pMem); - f = pMem->flags; - if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){ - if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ - return SQLITE_NOMEM; + if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ + if( ExpandBlob(pMem) ) return SQLITE_NOMEM; + if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ + int rc = vdbeMemAddTerminator(pMem); + if( rc ) return rc; } - pMem->z[pMem->n] = 0; - pMem->z[pMem->n+1] = 0; - pMem->flags |= MEM_Term; } pMem->flags &= ~MEM_Ephem; #ifdef SQLITE_DEBUG @@ -65815,43 +70673,28 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ */ #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ - if( pMem->flags & MEM_Zero ){ - int nByte; - assert( pMem->flags&MEM_Blob ); - assert( (pMem->flags&MEM_RowSet)==0 ); - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + int nByte; + assert( pMem->flags & MEM_Zero ); + assert( pMem->flags&MEM_Blob ); + assert( (pMem->flags&MEM_RowSet)==0 ); + 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 ){ - nByte = 1; - } - if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ - return SQLITE_NOMEM; - } - - memset(&pMem->z[pMem->n], 0, pMem->u.nZero); - pMem->n += pMem->u.nZero; - pMem->flags &= ~(MEM_Zero|MEM_Term); + /* Set nByte to the number of bytes required to store the expanded blob. */ + nByte = pMem->n + pMem->u.nZero; + if( nByte<=0 ){ + nByte = 1; } + if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ + return SQLITE_NOMEM_BKPT; + } + + memset(&pMem->z[pMem->n], 0, pMem->u.nZero); + pMem->n += pMem->u.nZero; + pMem->flags &= ~(MEM_Zero|MEM_Term); return SQLITE_OK; } #endif -/* -** It is already known that pMem contains an unterminated string. -** Add the zero terminator. -*/ -static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ - if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ - return SQLITE_NOMEM; - } - pMem->z[pMem->n] = 0; - pMem->z[pMem->n+1] = 0; - pMem->flags |= MEM_Term; - return SQLITE_OK; -} - /* ** Make sure the given Mem is \u0000 terminated. */ @@ -65893,7 +70736,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ - return SQLITE_NOMEM; + pMem->enc = 0; + return SQLITE_NOMEM_BKPT; } /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 @@ -65940,7 +70784,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ ctx.pFunc = pFunc; pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ assert( (pMem->flags & MEM_Dyn)==0 ); - if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); memcpy(pMem, &t, sizeof(t)); rc = ctx.isError; } @@ -65991,7 +70835,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ vdbeMemClearExternAndSetNull(p); } if( p->szMalloc ){ - sqlite3DbFree(p->db, p->zMalloc); + sqlite3DbFreeNN(p->db, p->zMalloc); p->szMalloc = 0; } p->z = 0; @@ -66019,7 +70863,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ ** If the double is out of range of a 64-bit signed integer then ** return the closest available 64-bit signed integer. */ -static i64 doubleToInt64(double r){ +static SQLITE_NOINLINE i64 doubleToInt64(double r){ #ifdef SQLITE_OMIT_FLOATING_POINT /* When floating-point is omitted, double and int64 are the same thing */ return r; @@ -66055,6 +70899,11 @@ static i64 doubleToInt64(double r){ ** ** If pMem represents a string value, its encoding might be changed. */ +static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ + i64 value = 0; + sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); + return value; +} SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ int flags; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -66065,10 +70914,8 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); }else if( flags & (MEM_Str|MEM_Blob) ){ - i64 value = 0; assert( pMem->z || pMem->n==0 ); - sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); - return value; + return memIntValue(pMem); }else{ return 0; } @@ -66080,6 +70927,12 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ +static SQLITE_NOINLINE double memRealValue(Mem *pMem){ + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + double val = (double)0; + sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); + return val; +} SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -66088,10 +70941,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ }else if( pMem->flags & MEM_Int ){ return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); - return val; + return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; @@ -66163,18 +71013,25 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + int rc; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ + rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc); + if( rc==0 ){ MemSetTypeFlag(pMem, MEM_Int); }else{ - pMem->u.r = sqlite3VdbeRealValue(pMem); - MemSetTypeFlag(pMem, MEM_Real); - sqlite3VdbeIntegerAffinity(pMem); + i64 i = pMem->u.i; + sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( rc==1 && pMem->u.r==(double)i ){ + pMem->u.i = i; + MemSetTypeFlag(pMem, MEM_Int); + }else{ + MemSetTypeFlag(pMem, MEM_Real); + } } } assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); - pMem->flags &= ~(MEM_Str|MEM_Blob); + pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); return SQLITE_OK; } @@ -66192,7 +71049,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ if( (pMem->flags & MEM_Blob)==0 ){ sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); - MemSetTypeFlag(pMem, MEM_Blob); + if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob); }else{ pMem->flags &= ~(MEM_TypeMask&~MEM_Blob); } @@ -66296,6 +71153,27 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ } } +/* A no-op destructor */ +static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } + +/* +** Set the value stored in *pMem should already be a NULL. +** Also store a pointer to go with it. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetPointer( + Mem *pMem, + void *pPtr, + const char *zPType, + void (*xDestructor)(void*) +){ + assert( pMem->flags==MEM_Null ); + pMem->u.zPType = zPType ? zPType : ""; + pMem->z = pPtr; + pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term; + pMem->eSubtype = 'p'; + pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor; +} + #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Delete any previous value and set the value stored in *pMem to val, @@ -66319,7 +71197,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){ assert( db!=0 ); assert( (pMem->flags & MEM_RowSet)==0 ); sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = sqlite3DbMallocRaw(db, 64); + pMem->zMalloc = sqlite3DbMallocRawNN(db, 64); if( db->mallocFailed ){ pMem->flags = MEM_Null; pMem->szMalloc = 0; @@ -66360,7 +71238,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; - for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){ + for(i=0, pX=pVdbe->aMem; inMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ pX->flags |= MEM_Undefined; pX->pScopyFrom = 0; @@ -66401,10 +71279,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; - /* The pFrom==0 case in the following assert() is when an sqlite3_value - ** from sqlite3_value_dup() is used as the argument - ** to sqlite3_result_value(). */ - assert( pTo->db==pFrom->db || pFrom->db==0 ); assert( (pFrom->flags & MEM_RowSet)==0 ); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); @@ -66480,7 +71354,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ - nByte = sqlite3Strlen30(z); + nByte = 0x7fffffff & (int)strlen(z); if( nByte>iLimit ) nByte = iLimit+1; }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} @@ -66504,7 +71378,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( testcase( nAlloc==31 ); testcase( nAlloc==32 ); if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memcpy(pMem->z, z, nAlloc); }else if( xDel==SQLITE_DYNAMIC ){ @@ -66524,7 +71398,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( #ifndef SQLITE_OMIT_UTF16 if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } #endif @@ -66537,10 +71411,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( /* ** Move data out of a btree key or data field and into a Mem structure. -** The data or key is taken from the entry that pCur is currently pointing +** The data is payload from the entry that pCur is currently pointing ** to. offset and amt determine what portion of the data or key to retrieve. -** key is true to get the key or false to get data. The result is written -** into the pMem element. +** The result is written into the pMem element. ** ** The pMem object must have been initialized. This routine will use ** pMem->zMalloc to hold the content from the btree, if possible. New @@ -66555,21 +71428,15 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ - int key, /* If true, retrieve from the btree key, not data. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ int rc; pMem->flags = MEM_Null; - if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){ - if( key ){ - rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); - }else{ - rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); - } + if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){ + rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z); if( rc==SQLITE_OK ){ - pMem->z[amt] = 0; - pMem->z[amt+1] = 0; - pMem->flags = MEM_Blob|MEM_Term; + pMem->z[amt] = 0; /* Overrun area used when reading malformed records */ + pMem->flags = MEM_Blob; pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); @@ -66581,7 +71448,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ - int key, /* If true, retrieve from the btree key, not data. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ char *zData; /* Data from the btree layer */ @@ -66594,11 +71460,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); - if( key ){ - zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); - }else{ - zData = (char *)sqlite3BtreeDataFetch(pCur, &available); - } + zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); if( offset+amt<=available ){ @@ -66606,7 +71468,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ - rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem); + rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem); } return rc; @@ -66624,10 +71486,8 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( (pVal->flags & MEM_RowSet)==0 ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ + if( ExpandBlob(pVal) ) return 0; pVal->flags |= MEM_Str; - if( pVal->flags & MEM_Zero ){ - sqlite3VdbeMemExpandBlob(pVal); - } if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); } @@ -66725,7 +71585,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ if( pRec ){ pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx); if( pRec->pKeyInfo ){ - assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); + assert( pRec->pKeyInfo->nAllField==nCol ); assert( pRec->pKeyInfo->enc==ENC(db) ); pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); for(i=0; iaMem[i].db = db; } }else{ - sqlite3DbFree(db, pRec); + sqlite3DbFreeNN(db, pRec); pRec = 0; } } @@ -66785,7 +71645,6 @@ static int valueFromFunction( FuncDef *pFunc = 0; /* Function definition */ sqlite3_value *pVal = 0; /* New value */ int rc = SQLITE_OK; /* Return code */ - int nName; /* Size of function name in bytes */ ExprList *pList = 0; /* Function arguments */ int i; /* Iterator variable */ @@ -66793,8 +71652,7 @@ static int valueFromFunction( assert( (p->flags & EP_TokenOnly)==0 ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; - nName = sqlite3Strlen30(p->u.zToken); - pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0); + pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) @@ -66805,7 +71663,7 @@ static int valueFromFunction( if( pList ){ apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal); if( apVal==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto value_from_function_out; } for(i=0; ixFunc(&ctx, nVal, apVal); + pFunc->xSFunc(&ctx, nVal, apVal); if( ctx.isError ){ rc = ctx.isError; sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); @@ -66847,7 +71705,7 @@ static int valueFromFunction( for(i=0; iop)==TK_UPLUS ) pExpr = pExpr->pLeft; + assert( pExpr!=0 ); + while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft; if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; /* Compressed expressions only appear when parsing the DEFAULT clause @@ -66938,7 +71793,7 @@ static int valueFromExpr( } }else if( op==TK_UMINUS ) { /* This branch happens for multiple negative signs. Ex: -(-5) */ - if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) + if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); @@ -66955,6 +71810,7 @@ static int valueFromExpr( }else if( op==TK_NULL ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; + sqlite3VdbeMemNumerify(pVal); } #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ @@ -66981,7 +71837,7 @@ static int valueFromExpr( return rc; no_mem: - db->mallocFailed = 1; + sqlite3OomFault(db); sqlite3DbFree(db, zVal); assert( *ppVal==0 ); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -66989,7 +71845,7 @@ no_mem: #else assert( pCtx==0 ); sqlite3ValueFree(pVal); #endif - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } /* @@ -67009,7 +71865,7 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr( u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ ){ - return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0); + return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0; } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -67040,7 +71896,7 @@ static void recordFunc( db = sqlite3_context_db_handle(context); nRet = 1 + nSerial + nVal; - aRet = sqlite3DbMallocRaw(db, nRet); + aRet = sqlite3DbMallocRawNN(db, nRet); if( aRet==0 ){ sqlite3_result_error_nomem(context); }else{ @@ -67048,7 +71904,7 @@ static void recordFunc( putVarint32(&aRet[1], iSerial); sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial); sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); - sqlite3DbFree(db, aRet); + sqlite3DbFreeNN(db, aRet); } } @@ -67056,15 +71912,10 @@ static void recordFunc( ** Register built-in functions used to help read ANALYZE data. */ SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){ - static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = { + static FuncDef aAnalyzeTableFuncs[] = { FUNCTION(sqlite_record, 1, 0, 0, recordFunc), }; - int i; - FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); - FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs); - for(i=0; iop!=TK_REGISTER || pExpr->op2!=TK_VARIABLE ); if( !pExpr ){ pVal = valueNew(db, pAlloc); if( pVal ){ sqlite3VdbeMemSetNull((Mem*)pVal); } - }else if( pExpr->op==TK_VARIABLE - || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) - ){ + }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *v; int iBindVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); @@ -67114,9 +71964,7 @@ static int stat4ValueFromExpr( pVal = valueNew(db, pAlloc); if( pVal ){ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); - if( rc==SQLITE_OK ){ - sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); - } + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); pVal->db = pParse->db; } } @@ -67134,9 +71982,9 @@ static int stat4ValueFromExpr( ** structures intended to be compared against sample index keys stored ** in the sqlite_stat4 table. ** -** A single call to this function attempts to populates field iVal (leftmost -** is 0 etc.) of the unpacked record with a value extracted from expression -** pExpr. Extraction of values is possible if: +** A single call to this function populates zero or more fields of the +** record starting with field iVal (fields are numbered from left to +** right starting with 0). A single field is populated if: ** ** * (pExpr==0). In this case the value is assumed to be an SQL NULL, ** @@ -67145,10 +71993,14 @@ static int stat4ValueFromExpr( ** * The sqlite3ValueFromExpr() function is able to extract a value ** from the expression (i.e. the expression is a literal value). ** -** If a value can be extracted, the affinity passed as the 5th argument -** is applied to it before it is copied into the UnpackedRecord. Output -** parameter *pbOk is set to true if a value is extracted, or false -** otherwise. +** Or, if pExpr is a TK_VECTOR, one field is populated for each of the +** vector components that match either of the two latter criteria listed +** above. +** +** Before any value is appended to the record, the affinity of the +** corresponding column within index pIdx is applied to it. Before +** this function returns, output parameter *pnExtract is set to the +** number of values appended to the record. ** ** When this function is called, *ppRec must either point to an object ** allocated by an earlier call to this function, or must be NULL. If it @@ -67164,22 +72016,33 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( Index *pIdx, /* Index being probed */ UnpackedRecord **ppRec, /* IN/OUT: Probe record */ Expr *pExpr, /* The expression to extract a value from */ - u8 affinity, /* Affinity to use */ + int nElem, /* Maximum number of values to append */ int iVal, /* Array element to populate */ - int *pbOk /* OUT: True if value was extracted */ + int *pnExtract /* OUT: Values appended to the record */ ){ - int rc; - sqlite3_value *pVal = 0; - struct ValueNewStat4Ctx alloc; + int rc = SQLITE_OK; + int nExtract = 0; - alloc.pParse = pParse; - alloc.pIdx = pIdx; - alloc.ppRec = ppRec; - alloc.iVal = iVal; + if( pExpr==0 || pExpr->op!=TK_SELECT ){ + int i; + struct ValueNewStat4Ctx alloc; - rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal); - assert( pVal==0 || pVal->db==pParse->db ); - *pbOk = (pVal!=0); + alloc.pParse = pParse; + alloc.pIdx = pIdx; + alloc.ppRec = ppRec; + + for(i=0; idb, pIdx, iVal+i); + alloc.iVal = iVal+i; + rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal); + if( !pVal ) break; + nExtract++; + } + } + + *pnExtract = nExtract; return rc; } @@ -67243,7 +72106,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column( if( iField>nRec ) return SQLITE_CORRUPT_BKPT; if( pMem==0 ){ pMem = *ppVal = sqlite3ValueNew(db); - if( pMem==0 ) return SQLITE_NOMEM; + if( pMem==0 ) return SQLITE_NOMEM_BKPT; } sqlite3VdbeSerialGet(&a[iField-szField], t, pMem); pMem->enc = ENC(db); @@ -67258,14 +72121,14 @@ SQLITE_PRIVATE int sqlite3Stat4Column( SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ if( pRec ){ int i; - int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField; + int nCol = pRec->pKeyInfo->nAllField; Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; ipKeyInfo); - sqlite3DbFree(db, pRec); + sqlite3DbFreeNN(db, pRec); } } #endif /* ifdef SQLITE_ENABLE_STAT4 */ @@ -67289,7 +72152,7 @@ SQLITE_PRIVATE void sqlite3ValueSetStr( SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; sqlite3VdbeMemRelease((Mem *)v); - sqlite3DbFree(((Mem*)v)->db, v); + sqlite3DbFreeNN(((Mem*)v)->db, v); } /* @@ -67342,8 +72205,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ sqlite3 *db = pParse->db; Vdbe *p; - p = sqlite3DbMallocZero(db, sizeof(Vdbe) ); + p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) ); if( p==0 ) return 0; + memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp)); p->db = db; if( db->pVdbe ){ db->pVdbe->pPrev = p; @@ -67353,10 +72217,12 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ db->pVdbe = p; p->magic = VDBE_MAGIC_INIT; p->pParse = pParse; + pParse->pVdbe = p; assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); assert( pParse->nOpAlloc==0 ); assert( pParse->szOpAlloc==0 ); + sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; } @@ -67374,23 +72240,14 @@ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ /* ** Remember the SQL string for a prepared statement. */ -SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ - assert( isPrepareV2==1 || isPrepareV2==0 ); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){ if( p==0 ) return; -#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG) - if( !isPrepareV2 ) return; -#endif + p->prepFlags = prepFlags; + if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){ + p->expmask = 0; + } assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); - p->isPrepareV2 = (u8)isPrepareV2; -} - -/* -** Return the SQL associated with a prepared statement -*/ -SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){ - Vdbe *p = (Vdbe *)pStmt; - return p ? p->zSql : 0; } /* @@ -67399,6 +72256,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ Vdbe tmp, *pTmp; char *zTmp; + assert( pA->db==pB->db ); tmp = *pA; *pA = *pB; *pB = tmp; @@ -67411,7 +72269,10 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; - pB->isPrepareV2 = pA->isPrepareV2; + pB->expmask = pA->expmask; + pB->prepFlags = pA->prepFlags; + memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); + pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++; } /* @@ -67442,6 +72303,12 @@ static int growOpArray(Vdbe *v, int nOp){ UNUSED_PARAMETER(nOp); #endif + /* Ensure that the size of a VDBE does not grow too large */ + if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){ + sqlite3OomFault(p->db); + return SQLITE_NOMEM; + } + assert( nOp<=(1024/sizeof(Op)) ); assert( nNew>=(p->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); @@ -67450,7 +72317,7 @@ static int growOpArray(Vdbe *v, int nOp){ p->nOpAlloc = p->szOpAlloc/sizeof(Op); v->aOp = pNew; } - return (pNew ? SQLITE_OK : SQLITE_NOMEM); + return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); } #ifdef SQLITE_DEBUG @@ -67492,7 +72359,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 ); + assert( op>=0 && op<0xff ); if( p->pParse->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } @@ -67512,9 +72379,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ if( p->db->flags & SQLITE_VdbeAddopTrace ){ int jj, kk; Parse *pParse = p->pParse; - for(jj=kk=0; jjnColCache; jj++){ struct yColCache *x = pParse->aColCache + jj; - if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue; printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn); kk++; } @@ -67562,6 +72428,9 @@ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){ ** "s" character in zTypes[], the register is a string if the argument is ** not NULL, or OP_Null if the value is a null pointer. For each "i" character ** in zTypes[], the register is initialized to an integer. +** +** If the input string does not end with "X" then an OP_ResultRow instruction +** is generated for the values inserted. */ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){ va_list ap; @@ -67571,13 +72440,15 @@ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, for(i=0; (c = zTypes[i])!=0; i++){ if( c=='s' ){ const char *z = va_arg(ap, const char*); - int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++); - if( z ) sqlite3VdbeChangeP4(p, addr, z, 0); + sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0); + }else if( c=='i' ){ + sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i); }else{ - assert( c=='i' ); - sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++); + goto skip_op_resultrow; } } + sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i); +skip_op_resultrow: va_end(ap); } @@ -67611,7 +72482,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( const u8 *zP4, /* The P4 operand */ int p4type /* P4 operand type */ ){ - char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8); + char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); if( p4copy ) memcpy(p4copy, zP4, 8); return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); } @@ -67626,8 +72497,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( */ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ int j; - int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0); - sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC); + sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); } @@ -67643,10 +72513,29 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int( int p4 /* The P4 operand as an integer */ ){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); - sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32); + if( p->db->mallocFailed==0 ){ + VdbeOp *pOp = &p->aOp[addr]; + pOp->p4type = P4_INT32; + pOp->p4.i = p4; + } return addr; } +/* Insert the end of a co-routine +*/ +SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); + + /* Clear the temporary register cache, thereby ensuring that each + ** co-routine has its own independent set of registers, because co-routines + ** might expect their registers to be preserved across an OP_Yield, and + ** that could cause problems if two or more co-routines are using the same + ** temporary register. + */ + v->pParse->nTempReg = 0; + v->pParse->nRangeReg = 0; +} + /* ** Create a new symbolic label for an instruction that has yet to be ** coded. The symbolic label is really just a negative number. The @@ -67689,7 +72578,6 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ if( p->aLabel ){ p->aLabel[j] = v->nOp; } - p->iFixedOp = v->nOp - 1; } /* @@ -67699,6 +72587,13 @@ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){ p->runOnlyOnce = 1; } +/* +** Mark the VDBE as one that can only be run multiple times. +*/ +SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){ + p->runOnlyOnce = 0; +} + #ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */ /* @@ -67781,7 +72676,8 @@ static Op *opIterNext(VdbeOpIter *p){ ** * OP_VUpdate ** * OP_VRename ** * OP_FkCounter with P2==0 (immediate foreign key constraint) -** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...) +** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine +** (for CREATE TABLE AS SELECT ...) ** ** Then check that the value of Parse.mayAbort is true if an ** ABORT may be thrown, or false otherwise. Return true if it does @@ -67809,7 +72705,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ hasAbort = 1; break; } - if( opcode==OP_CreateTable ) hasCreateTable = 1; + if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ @@ -67845,73 +72741,103 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** (4) Initialize the p4.xAdvance pointer on opcodes that use it. ** ** (5) Reclaim the memory allocated for storing labels. +** +** This routine will only function correctly if the mkopcodeh.tcl generator +** script numbers the opcodes correctly. Changes to this routine must be +** coordinated with changes to mkopcodeh.tcl. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ - int i; int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; p->readOnly = 1; p->bIsReader = 0; - for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ - u8 opcode = pOp->opcode; + pOp = &p->aOp[p->nOp-1]; + while(1){ - /* NOTE: Be sure to update mkopcodeh.awk when adding or removing - ** cases from this switch! */ - switch( opcode ){ - case OP_Transaction: { - if( pOp->p2!=0 ) p->readOnly = 0; - /* fall thru */ - } - case OP_AutoCommit: - case OP_Savepoint: { - p->bIsReader = 1; - break; - } + /* Only JUMP opcodes and the short list of special opcodes in the switch + ** below need to be considered. The mkopcodeh.tcl generator script groups + ** all these opcodes together near the front of the opcode list. Skip + ** any opcode that does not need processing by virtual of the fact that + ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization. + */ + if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){ + /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing + ** cases from this switch! */ + switch( pOp->opcode ){ + case OP_Transaction: { + if( pOp->p2!=0 ) p->readOnly = 0; + /* fall thru */ + } + case OP_AutoCommit: + case OP_Savepoint: { + p->bIsReader = 1; + break; + } #ifndef SQLITE_OMIT_WAL - case OP_Checkpoint: + case OP_Checkpoint: #endif - case OP_Vacuum: - case OP_JournalMode: { - p->readOnly = 0; - p->bIsReader = 1; - break; - } + case OP_Vacuum: + case OP_JournalMode: { + p->readOnly = 0; + p->bIsReader = 1; + break; + } + case OP_Next: + case OP_NextIfOpen: + case OP_SorterNext: { + pOp->p4.xAdvance = sqlite3BtreeNext; + pOp->p4type = P4_ADVANCE; + /* The code generator never codes any of these opcodes as a jump + ** to a label. They are always coded as a jump backwards to a + ** known address */ + assert( pOp->p2>=0 ); + break; + } + case OP_Prev: + case OP_PrevIfOpen: { + pOp->p4.xAdvance = sqlite3BtreePrevious; + pOp->p4type = P4_ADVANCE; + /* The code generator never codes any of these opcodes as a jump + ** to a label. They are always coded as a jump backwards to a + ** known address */ + assert( pOp->p2>=0 ); + break; + } #ifndef SQLITE_OMIT_VIRTUALTABLE - case OP_VUpdate: { - if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; - break; - } - case OP_VFilter: { - int n; - assert( p->nOp - i >= 3 ); - assert( pOp[-1].opcode==OP_Integer ); - n = pOp[-1].p1; - if( n>nMaxArgs ) nMaxArgs = n; - break; - } + case OP_VUpdate: { + if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; + break; + } + case OP_VFilter: { + int n; + assert( (pOp - p->aOp) >= 3 ); + assert( pOp[-1].opcode==OP_Integer ); + n = pOp[-1].p1; + if( n>nMaxArgs ) nMaxArgs = n; + /* Fall through into the default case */ + } #endif - case OP_Next: - case OP_NextIfOpen: - case OP_SorterNext: { - pOp->p4.xAdvance = sqlite3BtreeNext; - pOp->p4type = P4_ADVANCE; - break; - } - case OP_Prev: - case OP_PrevIfOpen: { - pOp->p4.xAdvance = sqlite3BtreePrevious; - pOp->p4type = P4_ADVANCE; - break; + default: { + if( pOp->p2<0 ){ + /* The mkopcodeh.tcl script has so arranged things that the only + ** 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 ); + pOp->p2 = aLabel[ADDR(pOp->p2)]; + } + break; + } } + /* The mkopcodeh.tcl script has so arranged things that the only + ** 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 || pOp->p2>=0); } - - pOp->opflags = sqlite3OpcodeProperty[opcode]; - if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ - assert( ADDR(pOp->p2)nLabel ); - pOp->p2 = aLabel[ADDR(pOp->p2)]; - } + if( pOp==p->aOp ) break; + pOp--; } sqlite3DbFree(p->db, pParse->aLabel); pParse->aLabel = 0; @@ -67928,6 +72854,36 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ return p->nOp; } +/* +** Verify that at least N opcode slots are available in p without +** having to malloc for more space (except when compiled using +** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing +** to verify that certain calls to sqlite3VdbeAddOpList() can never +** fail due to a OOM fault and hence that the return value from +** sqlite3VdbeAddOpList() will always be non-NULL. +*/ +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) +SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ + assert( p->nOp + N <= p->pParse->nOpAlloc ); +} +#endif + +/* +** Verify that the VM passed as the only argument does not contain +** an OP_ResultRow opcode. Fail an assert() if it does. This is used +** by code in pragma.c to ensure that the implementation of certain +** pragmas comports with the flags specified in the mkpragmatab.tcl +** script. +*/ +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) +SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ + int i; + for(i=0; inOp; i++){ + assert( p->aOp[i].opcode!=OP_ResultRow ); + } +} +#endif + /* ** This function returns a pointer to the array of opcodes associated with ** the Vdbe passed as the first argument. It is the callers responsibility @@ -67953,24 +72909,34 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg) } /* -** Add a whole list of operations to the operation stack. Return the -** address of the first operation added. +** Add a whole list of operations to the operation stack. Return a +** pointer to the first operation inserted. +** +** Non-zero P2 arguments to jump instructions are automatically adjusted +** so that the jump target is relative to the first operation inserted. */ -SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ - int addr, i; - VdbeOp *pOut; +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( + Vdbe *p, /* Add opcodes to the prepared statement */ + int nOp, /* Number of opcodes to add */ + VdbeOpList const *aOp, /* The opcodes to be added */ + int iLineno /* Source-file line number of first opcode */ +){ + int i; + VdbeOp *pOut, *pFirst; assert( nOp>0 ); assert( p->magic==VDBE_MAGIC_INIT ); if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ return 0; } - addr = p->nOp; - pOut = &p->aOp[addr]; + pFirst = pOut = &p->aOp[p->nOp]; for(i=0; iopcode = aOp->opcode; pOut->p1 = aOp->p1; pOut->p2 = aOp->p2; assert( aOp->p2>=0 ); + if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){ + pOut->p2 += p->nOp; + } pOut->p3 = aOp->p3; pOut->p4type = P4_NOTUSED; pOut->p4.p = 0; @@ -67985,12 +72951,12 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ - sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); + sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]); } #endif } p->nOp += nOp; - return addr; + return pFirst; } #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) @@ -68037,8 +73003,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ sqlite3VdbeGetOp(p,addr)->p3 = val; } -SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){ - sqlite3VdbeGetOp(p,-1)->p5 = p5; +SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ + assert( p->nOp>0 || p->db->mallocFailed ); + if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5; } /* @@ -68046,7 +73013,6 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){ ** the address of the next instruction to be coded. */ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ - p->pParse->iFixedOp = p->nOp - 1; sqlite3VdbeChangeP2(p, addr, p->nOp); } @@ -68056,8 +73022,8 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ ** the FuncDef is not ephermal, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ - if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ - sqlite3DbFree(db, pDef); + if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ + sqlite3DbFreeNN(db, pDef); } } @@ -68066,53 +73032,53 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** Delete a P4 value if necessary. */ +static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); + sqlite3DbFreeNN(db, p); +} +static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ + freeEphemeralFunction(db, p->pFunc); + sqlite3DbFreeNN(db, p); +} static void freeP4(sqlite3 *db, int p4type, void *p4){ - if( p4 ){ - assert( db ); - switch( p4type ){ - case P4_FUNCCTX: { - freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc); - /* Fall through into the next case */ - } - case P4_REAL: - case P4_INT64: - case P4_DYNAMIC: - case P4_INTARRAY: { - sqlite3DbFree(db, p4); - break; - } - case P4_KEYINFO: { - if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); - break; - } + assert( db ); + switch( p4type ){ + case P4_FUNCCTX: { + freeP4FuncCtx(db, (sqlite3_context*)p4); + break; + } + case P4_REAL: + case P4_INT64: + case P4_DYNAMIC: + case P4_INTARRAY: { + sqlite3DbFree(db, p4); + break; + } + case P4_KEYINFO: { + if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); + break; + } #ifdef SQLITE_ENABLE_CURSOR_HINTS - case P4_EXPR: { - sqlite3ExprDelete(db, (Expr*)p4); - break; - } + case P4_EXPR: { + sqlite3ExprDelete(db, (Expr*)p4); + break; + } #endif - case P4_MPRINTF: { - if( db->pnBytesFreed==0 ) sqlite3_free(p4); - break; - } - case P4_FUNCDEF: { - freeEphemeralFunction(db, (FuncDef*)p4); - break; - } - case P4_MEM: { - if( db->pnBytesFreed==0 ){ - sqlite3ValueFree((sqlite3_value*)p4); - }else{ - Mem *p = (Mem*)p4; - if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); - sqlite3DbFree(db, p); - } - break; - } - case P4_VTAB : { - if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); - break; + case P4_FUNCDEF: { + freeEphemeralFunction(db, (FuncDef*)p4); + break; + } + case P4_MEM: { + if( db->pnBytesFreed==0 ){ + sqlite3ValueFree((sqlite3_value*)p4); + }else{ + freeP4Mem(db, (Mem*)p4); } + break; + } + case P4_VTAB : { + if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); + break; } } } @@ -68125,14 +73091,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ if( aOp ){ Op *pOp; - for(pOp=aOp; pOp<&aOp[nOp]; pOp++){ - freeP4(db, pOp->p4type, pOp->p4.p); + for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){ + if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS sqlite3DbFree(db, pOp->zComment); #endif } + sqlite3DbFreeNN(db, aOp); } - sqlite3DbFree(db, aOp); } /* @@ -68148,14 +73114,16 @@ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ /* ** Change the opcode at addr into OP_Noop */ -SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ - if( addrnOp ){ - VdbeOp *pOp = &p->aOp[addr]; - sqlite3 *db = p->db; - freeP4(db, pOp->p4type, pOp->p4.p); - memset(pOp, 0, sizeof(pOp[0])); - pOp->opcode = OP_Noop; - } +SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ + VdbeOp *pOp; + if( p->db->mallocFailed ) return 0; + assert( addr>=0 && addrnOp ); + pOp = &p->aOp[addr]; + freeP4(p->db, pOp->p4type, pOp->p4.p); + pOp->p4type = P4_NOTUSED; + pOp->p4.z = 0; + pOp->opcode = OP_Noop; + return 1; } /* @@ -68163,9 +73131,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ ** then remove it. Return true if and only if an opcode was removed. */ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ - if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ - sqlite3VdbeChangeToNoop(p, p->nOp-1); - return 1; + if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){ + return sqlite3VdbeChangeToNoop(p, p->nOp-1); }else{ return 0; } @@ -68188,16 +73155,34 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ ** ** If addr<0 then change P4 on the most recently inserted instruction. */ +static void SQLITE_NOINLINE vdbeChangeP4Full( + Vdbe *p, + Op *pOp, + const char *zP4, + int n +){ + if( pOp->p4type ){ + freeP4(p->db, pOp->p4type, pOp->p4.p); + pOp->p4type = 0; + pOp->p4.p = 0; + } + if( n<0 ){ + sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); + }else{ + if( n==0 ) n = sqlite3Strlen30(zP4); + pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); + pOp->p4type = P4_DYNAMIC; + } +} SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; sqlite3 *db; assert( p!=0 ); db = p->db; assert( p->magic==VDBE_MAGIC_INIT ); - if( p->aOp==0 || db->mallocFailed ){ - if( n!=P4_VTAB ){ - freeP4(db, n, (void*)*(char**)&zP4); - } + assert( p->aOp!=0 || db->mallocFailed ); + if( db->mallocFailed ){ + if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); return; } assert( p->nOp>0 ); @@ -68206,43 +73191,45 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int addr = p->nOp - 1; } pOp = &p->aOp[addr]; - assert( pOp->p4type==P4_NOTUSED - || pOp->p4type==P4_INT32 - || pOp->p4type==P4_KEYINFO ); - freeP4(db, pOp->p4type, pOp->p4.p); - pOp->p4.p = 0; + if( n>=0 || pOp->p4type ){ + vdbeChangeP4Full(p, pOp, zP4, n); + return; + } if( n==P4_INT32 ){ /* Note: this cast is safe, because the origin data point was an int ** that was cast to a (const char *). */ pOp->p4.i = SQLITE_PTR_TO_INT(zP4); pOp->p4type = P4_INT32; - }else if( zP4==0 ){ - pOp->p4.p = 0; - pOp->p4type = P4_NOTUSED; - }else if( n==P4_KEYINFO ){ - pOp->p4.p = (void*)zP4; - pOp->p4type = P4_KEYINFO; -#ifdef SQLITE_ENABLE_CURSOR_HINTS - }else if( n==P4_EXPR ){ - /* Responsibility for deleting the Expr tree is handed over to the - ** VDBE by this operation. The caller should have already invoked - ** sqlite3ExprDup() or whatever other routine is needed to make a - ** private copy of the tree. */ - pOp->p4.pExpr = (Expr*)zP4; - pOp->p4type = P4_EXPR; -#endif - }else if( n==P4_VTAB ){ - pOp->p4.p = (void*)zP4; - pOp->p4type = P4_VTAB; - sqlite3VtabLock((VTable *)zP4); - assert( ((VTable *)zP4)->db==p->db ); - }else if( n<0 ){ + }else if( zP4!=0 ){ + assert( n<0 ); pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; + if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4); + } +} + +/* +** Change the P4 operand of the most recently coded instruction +** to the value defined by the arguments. This is a high-speed +** version of sqlite3VdbeChangeP4(). +** +** The P4 operand must not have been previously defined. And the new +** P4 must not be P4_INT32. Use sqlite3VdbeChangeP4() in either of +** those cases. +*/ +SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){ + VdbeOp *pOp; + assert( n!=P4_INT32 && n!=P4_VTAB ); + assert( n<=0 ); + if( p->db->mallocFailed ){ + freeP4(p->db, n, pP4); }else{ - if( n==0 ) n = sqlite3Strlen30(zP4); - pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); - pOp->p4type = P4_DYNAMIC; + assert( pP4!=0 ); + assert( p->nOp>0 ); + pOp = &p->aOp[p->nOp-1]; + assert( pOp->p4type==P4_NOTUSED ); + pOp->p4type = n; + pOp->p4.p = pP4; } } @@ -68252,10 +73239,11 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int */ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){ Vdbe *v = pParse->pVdbe; + KeyInfo *pKeyInfo; assert( v!=0 ); assert( pIdx!=0 ); - sqlite3VdbeChangeP4(v, -1, (char*)sqlite3KeyInfoOfIndex(pParse, pIdx), - P4_KEYINFO); + pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx); + if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS @@ -68367,12 +73355,21 @@ static int displayComment( const char *zSynopsis; int nOpName; int ii, jj; + char zAlt[50]; zOpName = sqlite3OpcodeName(pOp->opcode); nOpName = sqlite3Strlen30(zOpName); if( zOpName[nOpName+1] ){ int seenCom = 0; char c; zSynopsis = zOpName += nOpName + 1; + if( strncmp(zSynopsis,"IF ",3)==0 ){ + if( pOp->p5 & SQLITE_STOREP2 ){ + sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3); + }else{ + sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); + } + zSynopsis = zAlt; + } for(ii=jj=0; jjop ){ case TK_STRING: - sqlite3_snprintf(nTemp, zTemp, "%Q", pExpr->u.zToken); + sqlite3XPrintf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER: - sqlite3_snprintf(nTemp, zTemp, "%d", pExpr->u.iValue); + sqlite3XPrintf(p, "%d", pExpr->u.iValue); break; case TK_NULL: - sqlite3_snprintf(nTemp, zTemp, "NULL"); + sqlite3XPrintf(p, "NULL"); break; case TK_REGISTER: { - sqlite3_snprintf(nTemp, zTemp, "r[%d]", pExpr->iTable); + sqlite3XPrintf(p, "r[%d]", pExpr->iTable); break; } case TK_COLUMN: { if( pExpr->iColumn<0 ){ - sqlite3_snprintf(nTemp, zTemp, "rowid"); + sqlite3XPrintf(p, "rowid"); }else{ - sqlite3_snprintf(nTemp, zTemp, "c%d", (int)pExpr->iColumn); + sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn); } break; } @@ -68479,21 +73475,19 @@ static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){ case TK_NOTNULL: zOp = "NOTNULL"; break; default: - sqlite3_snprintf(nTemp, zTemp, "%s", "expr"); + sqlite3XPrintf(p, "%s", "expr"); break; } if( zOp ){ - sqlite3_snprintf(nTemp, zTemp, "%s(", zOp); - n = sqlite3Strlen30(zTemp); - n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pLeft); - if( npRight ){ - zTemp[n++] = ','; - n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pRight); + sqlite3XPrintf(p, "%s(", zOp); + displayP4Expr(p, pExpr->pLeft); + if( pExpr->pRight ){ + sqlite3StrAccumAppend(p, ",", 1); + displayP4Expr(p, pExpr->pRight); } - sqlite3_snprintf(nTemp-n, zTemp+n, ")"); + sqlite3StrAccumAppend(p, ")", 1); } - return sqlite3Strlen30(zTemp); } #endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */ @@ -68505,72 +73499,57 @@ static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){ */ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ char *zP4 = zTemp; + StrAccum x; assert( nTemp>=20 ); + sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0); switch( pOp->p4type ){ case P4_KEYINFO: { - int i, j; + int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->aSortOrder!=0 ); - sqlite3_snprintf(nTemp, zTemp, "k(%d", pKeyInfo->nField); - i = sqlite3Strlen30(zTemp); - for(j=0; jnField; j++){ + sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField); + for(j=0; jnKeyField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; - const char *zColl = pColl ? pColl->zName : "nil"; - int n = sqlite3Strlen30(zColl); - if( n==6 && memcmp(zColl,"BINARY",6)==0 ){ - zColl = "B"; - n = 1; - } - if( i+n>nTemp-7 ){ - memcpy(&zTemp[i],",...",4); - i += 4; - break; - } - zTemp[i++] = ','; - if( pKeyInfo->aSortOrder[j] ){ - zTemp[i++] = '-'; - } - memcpy(&zTemp[i], zColl, n+1); - i += n; + const char *zColl = pColl ? pColl->zName : ""; + if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; + sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl); } - zTemp[i++] = ')'; - zTemp[i] = 0; - assert( ip4.pExpr); + displayP4Expr(&x, pOp->p4.pExpr); break; } #endif case P4_COLLSEQ: { CollSeq *pColl = pOp->p4.pColl; - sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName); + sqlite3XPrintf(&x, "(%.20s)", pColl->zName); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; - sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); + sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } -#ifdef SQLITE_DEBUG +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) case P4_FUNCCTX: { FuncDef *pDef = pOp->p4.pCtx->pFunc; - sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); + sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } #endif case P4_INT64: { - sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64); + sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64); break; } case P4_INT32: { - sqlite3_snprintf(nTemp, zTemp, "%d", pOp->p4.i); + sqlite3XPrintf(&x, "%d", pOp->p4.i); break; } case P4_REAL: { - sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal); + sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal); break; } case P4_MEM: { @@ -68578,11 +73557,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ if( pMem->flags & MEM_Str ){ zP4 = pMem->z; }else if( pMem->flags & MEM_Int ){ - sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i); + sqlite3XPrintf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ - sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r); + sqlite3XPrintf(&x, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ - sqlite3_snprintf(nTemp, zTemp, "NULL"); + zP4 = "NULL"; }else{ assert( pMem->flags & MEM_Blob ); zP4 = "(blob)"; @@ -68592,22 +73571,34 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; - sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab); + sqlite3XPrintf(&x, "vtab:%p", pVtab); break; } #endif case P4_INTARRAY: { - sqlite3_snprintf(nTemp, zTemp, "intarray"); + int i; + int *ai = pOp->p4.ai; + int n = ai[0]; /* The first element of an INTARRAY is always the + ** count of the number of elements to follow */ + for(i=1; i<=n; i++){ + sqlite3XPrintf(&x, ",%d", ai[i]); + } + zTemp[0] = '['; + sqlite3StrAccumAppend(&x, "]", 1); break; } case P4_SUBPROGRAM: { - sqlite3_snprintf(nTemp, zTemp, "program"); + sqlite3XPrintf(&x, "program"); break; } case P4_ADVANCE: { zTemp[0] = 0; break; } + case P4_TABLE: { + sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName); + break; + } default: { zP4 = pOp->p4.z; if( zP4==0 ){ @@ -68616,6 +73607,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ } } } + sqlite3StrAccumFinish(&x); assert( zP4!=0 ); return zP4; } @@ -68638,7 +73630,7 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ } } -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +#if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** If SQLite is compiled to support shared-cache mode and to be threadsafe, ** this routine obtains the mutex associated with each BtShared structure @@ -68728,6 +73720,21 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ } #endif +/* +** Initialize an array of N Mem element. +*/ +static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ + while( (N--)>0 ){ + p->db = db; + p->flags = flags; + p->szMalloc = 0; +#ifdef SQLITE_DEBUG + p->pScopyFrom = 0; +#endif + p++; + } +} + /* ** Release an array of N Mem elements */ @@ -68735,7 +73742,6 @@ static void releaseMemArray(Mem *p, int N){ if( p && N ){ Mem *pEnd = &p[N]; sqlite3 *db = p->db; - u8 malloc_failed = db->mallocFailed; if( db->pnBytesFreed ){ do{ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); @@ -68765,13 +73771,12 @@ static void releaseMemArray(Mem *p, int N){ if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ - sqlite3DbFree(db, p->zMalloc); + sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; } p->flags = MEM_Undefined; }while( (++p)mallocFailed = malloc_failed; } } @@ -68787,6 +73792,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } releaseMemArray(aMem, p->nChildMem); + sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0); sqlite3DbFree(p->v->db, p); } @@ -68829,10 +73835,10 @@ SQLITE_PRIVATE int sqlite3VdbeList( releaseMemArray(pMem, 8); p->pResultSet = 0; - if( p->rc==SQLITE_NOMEM ){ + if( p->rc==SQLITE_NOMEM_BKPT ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ - db->mallocFailed = 1; + sqlite3OomFault(db); return SQLITE_ERROR; } @@ -68940,6 +73946,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( pMem->flags = MEM_Str|MEM_Term; zP4 = displayP4(pOp, pMem->z, pMem->szMalloc); if( zP4!=pMem->z ){ + pMem->n = 0; sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); }else{ assert( pMem->z!=0 ); @@ -69030,41 +74037,43 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ } #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ -/* -** Allocate space from a fixed size buffer and return a pointer to -** that space. If insufficient space is available, return NULL. +/* An instance of this object describes bulk memory available for use +** by subcomponents of a prepared statement. Space is allocated out +** 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 */ +}; + +/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf +** from the ReusableSpace object. Return a pointer to the allocated +** memory on success. If insufficient memory is available in the +** ReusableSpace object, increase the ReusableSpace.nNeeded +** value by the amount needed and return NULL. ** -** The pBuf parameter is the initial value of a pointer which will -** receive the new memory. pBuf is normally NULL. If pBuf is not -** NULL, it means that memory space has already been allocated and that -** this routine should not allocate any new memory. When pBuf is not -** NULL simply return pBuf. Only allocate new memory space when pBuf -** is NULL. +** If pBuf is not initially NULL, that means that the memory has already +** been allocated by a prior call to this routine, so just return a copy +** of pBuf and leave ReusableSpace unchanged. ** -** nByte is the number of bytes of space needed. -** -** pFrom points to *pnFrom bytes of available space. New space is allocated -** from the end of the pFrom buffer and *pnFrom is decremented. -** -** *pnNeeded is a counter of the number of bytes of space that have failed -** to allocate. If there is insufficient space in pFrom to satisfy the -** request, then increment *pnNeeded by the amount of the request. +** This allocator is employed to repurpose unused slots at the end of the +** opcode array of prepared state for other memory needs of the prepared +** statement. */ static void *allocSpace( - void *pBuf, /* Where return pointer will be stored */ - int nByte, /* Number of bytes to allocate */ - u8 *pFrom, /* Memory available for allocation */ - int *pnFrom, /* IN/OUT: Space available at pFrom */ - int *pnNeeded /* If allocation cannot be made, increment *pnByte */ + struct ReusableSpace *p, /* Bulk memory available for allocation */ + void *pBuf, /* Pointer to a prior allocation */ + int nByte /* Bytes of memory needed */ ){ - assert( EIGHT_BYTE_ALIGNMENT(pFrom) ); + assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ nByte = ROUND8(nByte); - if( nByte <= *pnFrom ){ - *pnFrom -= nByte; - pBuf = &pFrom[*pnFrom]; + if( nByte <= p->nFree ){ + p->nFree -= nByte; + pBuf = &p->pSpace[p->nFree]; }else{ - *pnNeeded += nByte; + p->nNeeded += nByte; } } assert( EIGHT_BYTE_ALIGNMENT(pBuf) ); @@ -69080,7 +74089,7 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ int i; #endif assert( p!=0 ); - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET ); /* There should be at least one opcode. */ @@ -69090,14 +74099,13 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ p->magic = VDBE_MAGIC_RUN; #ifdef SQLITE_DEBUG - for(i=1; inMem; i++){ + for(i=0; inMem; i++){ assert( p->aMem[i].db==p->db ); } #endif p->pc = -1; p->rc = SQLITE_OK; p->errorAction = OE_Abort; - p->magic = VDBE_MAGIC_RUN; p->nChange = 0; p->cacheCtr = 1; p->minWriteFileFormat = 255; @@ -69138,11 +74146,8 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( int nMem; /* Number of VM memory registers */ int nCursor; /* Number of cursors required */ int nArg; /* Number of arguments in subprograms */ - int nOnce; /* Number of OP_Once instructions */ int n; /* Loop counter */ - int nFree; /* Available free space */ - u8 *zCsr; /* Memory available for allocation */ - int nByte; /* How much extra memory is needed */ + struct ReusableSpace x; /* Reusable bulk memory */ assert( p!=0 ); assert( p->nOp>0 ); @@ -69155,35 +74160,25 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( nMem = pParse->nMem; nCursor = pParse->nTab; nArg = pParse->nMaxArg; - nOnce = pParse->nOnce; - if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */ - /* For each cursor required, also allocate a memory cell. Memory - ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by - ** the vdbe program. Instead they are used to allocate space for - ** VdbeCursor/BtCursor structures. The blob of memory associated with - ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1) - ** stores the blob of memory associated with cursor 1, etc. - ** + /* Each cursor uses a memory cell. The first cursor (cursor 0) can + ** use aMem[0] which is not otherwise used by the VDBE program. Allocate + ** space at the end of aMem[] for cursors 1 and greater. ** See also: allocateCursor(). */ nMem += nCursor; + if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */ - /* zCsr will initially point to nFree bytes of unused space at the - ** end of the opcode array, p->aOp. The computation of nFree is - ** conservative - it might be smaller than the true number of free - ** bytes, but never larger. nFree must be a multiple of 8 - it is - ** rounded down if is not. + /* Figure out how much reusable memory is available at the end of the + ** opcode array. This extra memory will be reallocated for other elements + ** of the prepared statement. */ - n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode space used */ - zCsr = &((u8*)p->aOp)[n]; /* Unused opcode space */ - assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); - nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused space */ - assert( nFree>=0 ); - if( nFree>0 ){ - memset(zCsr, 0, nFree); - assert( EIGHT_BYTE_ALIGNMENT(&zCsr[nFree]) ); - } + n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ + x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ + assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); + x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ + assert( x.nFree>=0 ); + assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); resolveP2Values(p, &nArg); p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); @@ -69192,58 +74187,48 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( } p->expired = 0; - /* Memory for registers, parameters, cursor, etc, is allocated in two - ** passes. On the first pass, we try to reuse unused space at the + /* Memory for registers, parameters, cursor, etc, is allocated in one or two + ** passes. On the first pass, we try to reuse unused memory at the ** end of the opcode array. If we are unable to satisfy all memory ** requirements by reusing the opcode array tail, then the second - ** pass will fill in the rest using a fresh allocation. + ** pass will fill in the remainder using a fresh memory allocation. ** ** This two-pass approach that reuses as much memory as possible from - ** the leftover space at the end of the opcode array can significantly + ** the leftover memory at the end of the opcode array. This can significantly ** reduce the amount of memory held by a prepared statement. */ do { - nByte = 0; - p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte); - p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte); - p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte); - p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), zCsr, &nFree, &nByte); - p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), - zCsr, &nFree, &nByte); - p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte); + 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*)); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte); + p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); #endif - if( nByte ){ - p->pFree = sqlite3DbMallocZero(db, nByte); - } - zCsr = p->pFree; - nFree = nByte; - }while( nByte && !db->mallocFailed ); + if( x.nNeeded==0 ) break; + x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); + x.nFree = x.nNeeded; + }while( !db->mallocFailed ); - p->nCursor = nCursor; - p->nOnceFlag = nOnce; - if( p->aVar ){ - p->nVar = (ynVar)nVar; - for(n=0; naVar[n].flags = MEM_Null; - p->aVar[n].db = db; - } - } - if( p->azVar && pParse->nzVar>0 ){ - p->nzVar = pParse->nzVar; - memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0])); - memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0])); - } - if( p->aMem ){ - p->aMem--; /* aMem[] goes from 1..nMem */ - p->nMem = nMem; /* not from 0..nMem-1 */ - for(n=1; n<=nMem; n++){ - p->aMem[n].flags = MEM_Undefined; - p->aMem[n].db = db; - } - } + p->pVList = pParse->pVList; + pParse->pVList = 0; p->explain = pParse->explain; + if( db->mallocFailed ){ + p->nVar = 0; + p->nCursor = 0; + p->nMem = 0; + }else{ + p->nCursor = nCursor; + p->nVar = (ynVar)nVar; + initMemArray(p->aVar, nVar, db, MEM_Null); + p->nMem = nMem; + initMemArray(p->aMem, nMem, db, MEM_Undefined); + memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*)); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + memset(p->anExec, 0, p->nOp*sizeof(i64)); +#endif + } sqlite3VdbeRewind(p); } @@ -69255,15 +74240,15 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } - assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE ); + assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx); break; } case CURTYPE_BTREE: { - if( pCx->pBt ){ - sqlite3BtreeClose(pCx->pBt); + if( pCx->isEphemeral ){ + if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx); /* The pCx->pCursor will be close automatically, if it exists, by ** the call above. */ }else{ @@ -69312,8 +74297,6 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS v->anExec = pFrame->anExec; #endif - v->aOnceFlag = pFrame->aOnceFlag; - v->nOnceFlag = pFrame->nOnceFlag; v->aOp = pFrame->aOp; v->nOp = pFrame->nOp; v->aMem = pFrame->aMem; @@ -69323,6 +74306,9 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ v->db->lastRowid = pFrame->lastRowid; v->nChange = pFrame->nChange; v->db->nChange = pFrame->nDbChange; + sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0); + v->pAuxData = pFrame->pAuxData; + pFrame->pAuxData = 0; return pFrame->pc; } @@ -69345,7 +74331,7 @@ static void closeAllCursors(Vdbe *p){ assert( p->nFrame==0 ); closeCursorsInFrame(p); if( p->aMem ){ - releaseMemArray(&p->aMem[1], p->nMem); + releaseMemArray(p->aMem, p->nMem); } while( p->pDelFrame ){ VdbeFrame *pDel = p->pDelFrame; @@ -69354,31 +74340,10 @@ static void closeAllCursors(Vdbe *p){ } /* Delete any auxdata allocations made by the VM */ - if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0); + if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0); assert( p->pAuxData==0 ); } -/* -** Clean up the VM after a single run. -*/ -static void Cleanup(Vdbe *p){ - sqlite3 *db = p->db; - -#ifdef SQLITE_DEBUG - /* Execute assert() statements to ensure that the Vdbe.apCsr[] and - ** Vdbe.aMem[] arrays have already been cleaned up. */ - int i; - if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); - if( p->aMem ){ - for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); - } -#endif - - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; - p->pResultSet = 0; -} - /* ** Set the number of result columns that will be returned by this SQL ** statement. This is now set at compile time, rather than during @@ -69386,21 +74351,18 @@ static void Cleanup(Vdbe *p){ ** be called on an SQL statement before sqlite3_step(). */ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ - Mem *pColName; int n; sqlite3 *db = p->db; - releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); - sqlite3DbFree(db, p->aColName); + if( p->nResColumn ){ + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + sqlite3DbFree(db, p->aColName); + } n = nResColumn*COLNAME_N; p->nResColumn = (u16)nResColumn; - p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n ); + p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); if( p->aColName==0 ) return; - while( n-- > 0 ){ - pColName->flags = MEM_Null; - pColName->db = p->db; - pColName++; - } + initMemArray(p->aColName, n, db, MEM_Null); } /* @@ -69426,7 +74388,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName( assert( vardb->mallocFailed ){ assert( !zName || xDel!=SQLITE_DYNAMIC ); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } assert( p->aColName!=0 ); pColName = &(p->aColName[idx+var*p->nResColumn]); @@ -69443,7 +74405,9 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName( */ static int vdbeCommit(sqlite3 *db, Vdbe *p){ int i; - int nTrans = 0; /* Number of databases with an active write-transaction */ + int nTrans = 0; /* Number of databases with an active write-transaction + ** that are candidates for a two-phase commit using a + ** master-journal */ int rc = SQLITE_OK; int needXcommit = 0; @@ -69471,10 +74435,28 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeIsInTrans(pBt) ){ + /* Whether or not a database might need a master journal depends upon + ** its journal mode (among other things). This matrix determines which + ** journal modes use a master journal and which do not */ + static const u8 aMJNeeded[] = { + /* DELETE */ 1, + /* PERSIST */ 1, + /* OFF */ 0, + /* TRUNCATE */ 1, + /* MEMORY */ 0, + /* WAL */ 0 + }; + Pager *pPager; /* Pager associated with pBt */ needXcommit = 1; - if( i!=1 ) nTrans++; sqlite3BtreeEnter(pBt); - rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt)); + pPager = sqlite3BtreePager(pBt); + if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF + && aMJNeeded[sqlite3PagerGetJournalMode(pPager)] + ){ + assert( i!=1 ); + nTrans++; + } + rc = sqlite3PagerExclusiveLock(pPager); sqlite3BtreeLeave(pBt); } } @@ -69532,7 +74514,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ #ifndef SQLITE_OMIT_DISKIO else{ sqlite3_vfs *pVfs = db->pVfs; - int needSync = 0; char *zMaster = 0; /* File-name for the master journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); sqlite3_file *pMaster = 0; @@ -69544,7 +74525,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ /* Select a master journal file name */ nMainFile = sqlite3Strlen30(zMainFile); zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile); - if( zMaster==0 ) return SQLITE_NOMEM; + if( zMaster==0 ) return SQLITE_NOMEM_BKPT; do { u32 iRandom; if( retryCount ){ @@ -69592,9 +74573,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ continue; /* Ignore TEMP and :memory: databases */ } assert( zFile[0]!=0 ); - if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ - needSync = 1; - } rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset); offset += sqlite3Strlen30(zFile)+1; if( rc!=SQLITE_OK ){ @@ -69609,8 +74587,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ /* Sync the master journal file. If the IOCAP_SEQUENTIAL device ** flag is set this is not required. */ - if( needSync - && 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) + if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL)) ){ sqlite3OsCloseFree(pMaster); @@ -69646,7 +74623,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ ** doing this the directory is synced again before any individual ** transaction files are deleted. */ - rc = sqlite3OsDelete(pVfs, zMaster, needSync); + rc = sqlite3OsDelete(pVfs, zMaster, 1); sqlite3DbFree(db, zMaster); zMaster = 0; if( rc ){ @@ -69720,60 +74697,59 @@ static void checkActiveVdbeCnt(sqlite3 *db){ ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. ** Otherwise SQLITE_OK. */ -SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ +static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ sqlite3 *const db = p->db; int rc = SQLITE_OK; + int i; + const int iSavepoint = p->iStatement-1; - /* If p->iStatement is greater than zero, then this Vdbe opened a - ** statement transaction that should be closed here. The only exception - ** is that an IO error may have occurred, causing an emergency rollback. - ** In this case (db->nStatement==0), and there is nothing to do. - */ - if( db->nStatement && p->iStatement ){ - int i; - const int iSavepoint = p->iStatement-1; + assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); + assert( db->nStatement>0 ); + assert( p->iStatement==(db->nStatement+db->nSavepoint) ); - assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); - assert( db->nStatement>0 ); - assert( p->iStatement==(db->nStatement+db->nSavepoint) ); - - for(i=0; inDb; i++){ - int rc2 = SQLITE_OK; - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - if( eOp==SAVEPOINT_ROLLBACK ){ - rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint); - } - if( rc2==SQLITE_OK ){ - rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint); - } - if( rc==SQLITE_OK ){ - rc = rc2; - } - } - } - db->nStatement--; - p->iStatement = 0; - - if( rc==SQLITE_OK ){ + for(i=0; inDb; i++){ + int rc2 = SQLITE_OK; + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ if( eOp==SAVEPOINT_ROLLBACK ){ - rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); + rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint); + } + if( rc2==SQLITE_OK ){ + rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint); } if( rc==SQLITE_OK ){ - rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); + rc = rc2; } } + } + db->nStatement--; + p->iStatement = 0; - /* If the statement transaction is being rolled back, also restore the - ** database handles deferred constraint counter to the value it had when - ** the statement transaction was opened. */ + if( rc==SQLITE_OK ){ if( eOp==SAVEPOINT_ROLLBACK ){ - db->nDeferredCons = p->nStmtDefCons; - db->nDeferredImmCons = p->nStmtDefImmCons; + rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); } + if( rc==SQLITE_OK ){ + rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); + } + } + + /* If the statement transaction is being rolled back, also restore the + ** database handles deferred constraint counter to the value it had when + ** the statement transaction was opened. */ + if( eOp==SAVEPOINT_ROLLBACK ){ + db->nDeferredCons = p->nStmtDefCons; + db->nDeferredImmCons = p->nStmtDefImmCons; } return rc; } +SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ + if( p->db->nStatement && p->iStatement ){ + return vdbeCloseStatement(p, eOp); + } + return SQLITE_OK; +} + /* ** This function is called when a transaction opened by the database @@ -69833,14 +74809,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ ** one, or the complete transaction if there is no statement transaction. */ - if( p->db->mallocFailed ){ - p->rc = SQLITE_NOMEM; - } - if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag); - closeAllCursors(p); if( p->magic!=VDBE_MAGIC_RUN ){ return SQLITE_OK; } + if( db->mallocFailed ){ + p->rc = SQLITE_NOMEM_BKPT; + } + closeAllCursors(p); checkActiveVdbeCnt(db); /* No commit or rollback needed if the program never started or if the @@ -69994,8 +74969,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ } p->magic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); - if( p->db->mallocFailed ){ - p->rc = SQLITE_NOMEM; + if( db->mallocFailed ){ + p->rc = SQLITE_NOMEM_BKPT; } /* If the auto-commit flag is set to true, then any locks that were held @@ -70031,16 +75006,16 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){ sqlite3 *db = p->db; int rc = p->rc; if( p->zErrMsg ){ - u8 mallocFailed = db->mallocFailed; + db->bBenignMalloc++; sqlite3BeginBenignMalloc(); if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db); sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); - db->mallocFailed = mallocFailed; - db->errCode = rc; - }else{ - sqlite3Error(db, rc); + db->bBenignMalloc--; + }else if( db->pErr ){ + sqlite3ValueSetNull(db->pErr); } + db->errCode = rc; return rc; } @@ -70077,6 +75052,10 @@ static void vdbeInvokeSqllog(Vdbe *v){ ** VDBE_MAGIC_INIT. */ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + int i; +#endif + sqlite3 *db; db = p->db; @@ -70094,8 +75073,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ if( p->pc>=0 ){ vdbeInvokeSqllog(p); sqlite3VdbeTransferError(p); - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; if( p->runOnlyOnce ) p->expired = 1; }else if( p->rc && p->expired ){ /* The expired flag was set on the VDBE before the first call @@ -70103,13 +75080,21 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ ** called), set the database error in this case as well. */ sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; } - /* Reclaim all memory used by the VDBE + /* Reset register contents and reclaim error message memory. */ - Cleanup(p); +#ifdef SQLITE_DEBUG + /* Execute assert() statements to ensure that the Vdbe.apCsr[] and + ** Vdbe.aMem[] arrays have already been cleaned up. */ + if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); + if( p->aMem ){ + for(i=0; inMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); + } +#endif + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = 0; + p->pResultSet = 0; /* Save profiling information from this VDBE run. */ @@ -70117,7 +75102,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ { FILE *out = fopen("vdbe_profile.out", "a"); if( out ){ - int i; fprintf(out, "---- "); for(i=0; inOp; i++){ fprintf(out, "%02x", p->aOp[i].opcode); @@ -70147,8 +75131,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ } } #endif - p->iCurrentTime = 0; - p->magic = VDBE_MAGIC_INIT; + p->magic = VDBE_MAGIC_RESET; return p->rc & db->errMask; } @@ -70182,21 +75165,22 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ ** * the corresponding bit in argument mask is clear (where the first ** function parameter corresponds to bit 0 etc.). */ -SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ - AuxData **pp = &pVdbe->pAuxData; +SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){ while( *pp ){ AuxData *pAux = *pp; if( (iOp<0) - || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg)))) + || (pAux->iAuxOp==iOp + && pAux->iAuxArg>=0 + && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg)))) ){ - testcase( pAux->iArg==31 ); - if( pAux->xDelete ){ - pAux->xDelete(pAux->pAux); + testcase( pAux->iAuxArg==31 ); + if( pAux->xDeleteAux ){ + pAux->xDeleteAux(pAux->pAux); } - *pp = pAux->pNext; - sqlite3DbFree(pVdbe->db, pAux); + *pp = pAux->pNextAux; + sqlite3DbFree(db, pAux); }else{ - pp= &pAux->pNext; + pp= &pAux->pNextAux; } } } @@ -70211,25 +75195,29 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ */ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ SubProgram *pSub, *pNext; - int i; assert( p->db==0 || p->db==db ); - releaseMemArray(p->aVar, p->nVar); releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); for(pSub=p->pProgram; pSub; pSub=pNext){ pNext = pSub->pNext; vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); sqlite3DbFree(db, pSub); } - for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); + if( p->magic!=VDBE_MAGIC_INIT ){ + releaseMemArray(p->aVar, p->nVar); + sqlite3DbFree(db, p->pVList); + sqlite3DbFree(db, p->pFree); + } vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); - sqlite3DbFree(db, p->pFree); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - for(i=0; inScan; i++){ - sqlite3DbFree(db, p->aScan[i].zName); + { + int i; + for(i=0; inScan; i++){ + sqlite3DbFree(db, p->aScan[i].zName); + } + sqlite3DbFree(db, p->aScan); } - sqlite3DbFree(db, p->aScan); #endif } @@ -70254,7 +75242,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ } p->magic = VDBE_MAGIC_DEAD; p->db = 0; - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } /* @@ -70324,14 +75312,20 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ ** If the cursor is already pointing to the correct row and that row has ** not been deleted out from under the cursor, then this routine is a no-op. */ -SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){ - if( p->eCurType==CURTYPE_BTREE ){ - if( p->deferredMoveto ){ - return handleDeferredMoveto(p); - } - if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ - return handleMovedCursor(p); +SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ + VdbeCursor *p = *pp; + assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO ); + if( p->deferredMoveto ){ + int iMap; + if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){ + *pp = p->pAltCursor; + *piCol = iMap - 1; + return SQLITE_OK; } + return handleDeferredMoveto(p); + } + if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ + return handleMovedCursor(p); } return SQLITE_OK; } @@ -70723,34 +75717,17 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( ** If an OOM error occurs, NULL is returned. */ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( - KeyInfo *pKeyInfo, /* Description of the record */ - char *pSpace, /* Unaligned space available */ - int szSpace, /* Size of pSpace[] in bytes */ - char **ppFree /* OUT: Caller should free this pointer */ + KeyInfo *pKeyInfo /* Description of the record */ ){ UnpackedRecord *p; /* Unpacked record to return */ - int nOff; /* Increment pSpace by nOff to align it */ int nByte; /* Number of bytes required for *p */ - - /* We want to shift the pointer pSpace up such that it is 8-byte aligned. - ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift - ** it by. If pSpace is already 8-byte aligned, nOff should be zero. - */ - nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7; - nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1); - if( nByte>szSpace+nOff ){ - p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); - *ppFree = (char *)p; - if( !p ) return 0; - }else{ - p = (UnpackedRecord*)&pSpace[nOff]; - *ppFree = 0; - } - + nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); + p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); + if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; assert( pKeyInfo->aSortOrder!=0 ); p->pKeyInfo = pKeyInfo; - p->nField = pKeyInfo->nField + 1; + p->nField = pKeyInfo->nKeyField + 1; return p; } @@ -70785,15 +75762,16 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( pMem->db = pKeyInfo->db; /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ pMem->szMalloc = 0; + pMem->z = 0; d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); pMem++; if( (++u)>=p->nField ) break; } - assert( u<=pKeyInfo->nField + 1 ); + assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* ** This function compares two index or table record keys in the same way ** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(), @@ -70838,9 +75816,9 @@ static int vdbeRecordCompareDebug( idx1 = getVarint32(aKey1, szHdr1); if( szHdr1>98307 ) return SQLITE_CORRUPT; d1 = szHdr1; - assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); + assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pKeyInfo->aSortOrder!=0 ); - assert( pKeyInfo->nField>0 ); + assert( pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type1; @@ -70898,16 +75876,16 @@ debugCompareEnd: } #endif -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* ** Count the number of fields (a.k.a. columns) in the record given by ** pKey,nKey. The verify that this count is less than or equal to the -** limit given by pKeyInfo->nField + pKeyInfo->nXField. +** limit given by pKeyInfo->nAllField. ** ** If this constraint is not satisfied, it means that the high-speed ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will ** not work correctly. If this assert() ever fires, it probably means -** that the KeyInfo.nField or KeyInfo.nXField values were computed +** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed ** incorrectly. */ static void vdbeAssertFieldCountWithinLimits( @@ -70928,7 +75906,7 @@ static void vdbeAssertFieldCountWithinLimits( idx += getVarint32(aKey+idx, notUsed); nField++; } - assert( nField <= pKeyInfo->nField+pKeyInfo->nXField ); + assert( nField <= pKeyInfo->nAllField ); } #else # define vdbeAssertFieldCountWithinLimits(A,B,C) @@ -70953,7 +75931,6 @@ static int vdbeCompareMemString( }else{ int rc; const void *v1, *v2; - int n1, n2; Mem c1; Mem c2; sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); @@ -70961,26 +75938,62 @@ static int vdbeCompareMemString( sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); - n1 = v1==0 ? 0 : c1.n; v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); - n2 = v2==0 ? 0 : c2.n; - rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); + if( (v1==0 || v2==0) ){ + if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + rc = 0; + }else{ + rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); + } sqlite3VdbeMemRelease(&c1); sqlite3VdbeMemRelease(&c2); - if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM; return rc; } } +/* +** The input pBlob is guaranteed to be a Blob that is not marked +** with MEM_Zero. Return true if it could be a zero-blob. +*/ +static int isAllZero(const char *z, int n){ + int i; + for(i=0; iz, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n); + int c; + int n1 = pB1->n; + int n2 = pB2->n; + + /* It is possible to have a Blob value that has some non-zero content + ** followed by zero content. But that only comes up for Blobs formed + ** by the OP_MakeRecord opcode, and such Blobs never get passed into + ** sqlite3MemCompare(). */ + assert( (pB1->flags & MEM_Zero)==0 || n1==0 ); + assert( (pB2->flags & MEM_Zero)==0 || n2==0 ); + + if( (pB1->flags|pB2->flags) & MEM_Zero ){ + if( pB1->flags & pB2->flags & MEM_Zero ){ + return pB1->u.nZero - pB2->u.nZero; + }else if( pB1->flags & MEM_Zero ){ + if( !isAllZero(pB2->z, pB2->n) ) return -1; + return pB1->u.nZero - n2; + }else{ + if( !isAllZero(pB1->z, pB1->n) ) return +1; + return n1 - pB2->u.nZero; + } + } + c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1); if( c ) return c; - return pB1->n - pB2->n; + return n1 - n2; } /* @@ -71198,10 +76211,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( } VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ - assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField + assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortOrder!=0 ); - assert( pPKey2->pKeyInfo->nField>0 ); + assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type; @@ -71286,6 +76299,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( /* RHS is a blob */ else if( pRhs->flags & MEM_Blob ){ + assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); getVarint32(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 || (serial_type & 0x01) ){ @@ -71297,6 +76311,12 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( if( (d1+nStr) > (unsigned)nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ + }else if( pRhs->flags & MEM_Zero ){ + if( !isAllZero((const char*)&aKey1[d1],nStr) ){ + rc = 1; + }else{ + rc = nStr - pRhs->u.nZero; + } }else{ int nCmp = MIN(nStr, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); @@ -71367,7 +76387,7 @@ static int vdbeRecordCompareInt( int res; u32 y; u64 x; - i64 v = pPKey2->aMem[0].u.i; + i64 v; i64 lhs; vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); @@ -71426,6 +76446,7 @@ static int vdbeRecordCompareInt( return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } + v = pPKey2->aMem[0].u.i; if( v>lhs ){ res = pPKey2->r1; }else if( vpKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){ + if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortOrder[0] ){ p->r1 = 1; @@ -71572,13 +76593,12 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); - assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ + nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); - rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); + rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); if( rc ){ return rc; } @@ -71650,8 +76670,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); - assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ + nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ @@ -71659,7 +76678,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); - rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); + rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); if( rc ){ return rc; } @@ -71710,6 +76729,13 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){ return v->db; } +/* +** Return the SQLITE_PREPARE flags for a Vdbe. +*/ +SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){ + return v->prepFlags; +} + /* ** Return a pointer to an sqlite3_value structure containing the value bound ** parameter iVar of VM v. Except, if the value is an SQL NULL, return @@ -71722,6 +76748,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ @@ -71741,13 +76768,36 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff */ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); - if( iVar>32 ){ - v->expmask = 0xffffffff; + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); + if( iVar>=32 ){ + v->expmask |= 0x80000000; }else{ v->expmask |= ((u32)1 << (iVar-1)); } } +/* +** Cause a function to throw an error if it was call from OP_PureFunc +** rather than OP_Function. +** +** OP_PureFunc means that the function must be deterministic, and should +** throw an error if it is given inputs that would make it non-deterministic. +** This routine is invoked by date/time functions that use non-deterministic +** features such as 'now'. +*/ +SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pCtx->pVdbe==0 ) return 1; +#endif + if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){ + sqlite3_result_error(pCtx, + "non-deterministic function in index expression or CHECK constraint", + -1); + return 0; + } + return 1; +} + #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored @@ -71755,14 +76805,105 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ ** in memory obtained from sqlite3DbMalloc). */ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ - sqlite3 *db = p->db; - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); - sqlite3_free(pVtab->zErrMsg); - pVtab->zErrMsg = 0; + if( pVtab->zErrMsg ){ + sqlite3 *db = p->db; + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); + sqlite3_free(pVtab->zErrMsg); + pVtab->zErrMsg = 0; + } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + +/* +** If the second argument is not NULL, release any allocations associated +** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord +** structure itself, using sqlite3DbFree(). +** +** This function is used to free UnpackedRecord structures allocated by +** the vdbeUnpackRecord() function found in vdbeapi.c. +*/ +static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ + if( p ){ + int i; + for(i=0; iaMem[i]; + if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem); + } + sqlite3DbFreeNN(db, p); + } +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call, +** then cursor passed as the second argument should point to the row about +** to be update or deleted. If the application calls sqlite3_preupdate_old(), +** the required value will be read from the row the cursor points to. +*/ +SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( + Vdbe *v, /* Vdbe pre-update hook is invoked by */ + VdbeCursor *pCsr, /* Cursor to grab old.* values from */ + int op, /* SQLITE_INSERT, UPDATE or DELETE */ + const char *zDb, /* Database name */ + Table *pTab, /* Modified table */ + i64 iKey1, /* Initial key value */ + int iReg /* Register for new.* record */ +){ + sqlite3 *db = v->db; + i64 iKey2; + PreUpdate preupdate; + const char *zTbl = pTab->zName; + static const u8 fakeSortOrder = 0; + + assert( db->pPreUpdate==0 ); + memset(&preupdate, 0, sizeof(PreUpdate)); + if( HasRowid(pTab)==0 ){ + iKey1 = iKey2 = 0; + preupdate.pPk = sqlite3PrimaryKeyIndex(pTab); + }else{ + if( op==SQLITE_UPDATE ){ + iKey2 = v->aMem[iReg].u.i; + }else{ + iKey2 = iKey1; + } + } + + assert( pCsr->nField==pTab->nCol + || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) + ); + + preupdate.v = v; + preupdate.pCsr = pCsr; + preupdate.op = op; + preupdate.iNewReg = iReg; + preupdate.keyinfo.db = db; + preupdate.keyinfo.enc = ENC(db); + preupdate.keyinfo.nKeyField = pTab->nCol; + preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder; + preupdate.iKey1 = iKey1; + preupdate.iKey2 = iKey2; + preupdate.pTab = pTab; + + db->pPreUpdate = &preupdate; + db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); + db->pPreUpdate = 0; + sqlite3DbFree(db, preupdate.aRecord); + vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); + vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); + if( preupdate.aNew ){ + int i; + for(i=0; inField; i++){ + sqlite3VdbeMemRelease(&preupdate.aNew[i]); + } + sqlite3DbFreeNN(db, preupdate.aNew); + } +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + /************** End of vdbeaux.c *********************************************/ /************** Begin file vdbeapi.c *****************************************/ /* @@ -71792,7 +76933,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ ** collating sequences are registered or if an authorizer function is ** added or changed. */ -SQLITE_API int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; return p==0 || p->expired; } @@ -71827,12 +76968,19 @@ static int vdbeSafetyNotNull(Vdbe *p){ */ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; + sqlite3_int64 iElapse; assert( p->startTime>0 ); - assert( db->xProfile!=0 ); + assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); - db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000); + iElapse = (iNow - p->startTime)*1000000; + if( db->xProfile ){ + db->xProfile(db->pProfileArg, p->zSql, iElapse); + } + if( db->mTrace & SQLITE_TRACE_PROFILE ){ + db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); + } p->startTime = 0; } /* @@ -71854,7 +77002,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ ** This routine sets the error code and string returned by ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){ int rc; if( pStmt==0 ){ /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL @@ -71881,7 +77029,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){ ** This routine sets the error code and string returned by ** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){ int rc; if( pStmt==0 ){ rc = SQLITE_OK; @@ -71902,7 +77050,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){ /* ** Set all the parameters in the compiled SQL statement to NULL. */ -SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ int i; int rc = SQLITE_OK; Vdbe *p = (Vdbe*)pStmt; @@ -71914,7 +77062,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; } - if( p->isPrepareV2 && p->expmask ){ + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); + if( p->expmask ){ p->expired = 1; } sqlite3_mutex_leave(mutex); @@ -71926,10 +77075,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){ ** The following routines extract information from a Mem or sqlite3_value ** structure. */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){ +SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ - if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ){ + if( ExpandBlob(p)!=SQLITE_OK ){ assert( p->flags==MEM_Null && p->z==0 ); return 0; } @@ -71939,35 +77088,49 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){ return sqlite3_value_text(pVal); } } -SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value *pVal){ +SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF8); } -SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value *pVal){ +SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE); } -SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value *pVal){ +SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){ return sqlite3VdbeRealValue((Mem*)pVal); } -SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){ +SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){ return (int)sqlite3VdbeIntValue((Mem*)pVal); } -SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){ +SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){ return sqlite3VdbeIntValue((Mem*)pVal); } -SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){ - return ((Mem*)pVal)->eSubtype; +SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){ + Mem *pMem = (Mem*)pVal; + return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0); } -SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){ +SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){ + Mem *p = (Mem*)pVal; + if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) == + (MEM_Null|MEM_Term|MEM_Subtype) + && zPType!=0 + && p->eSubtype=='p' + && strcmp(p->u.zPType, zPType)==0 + ){ + return (void*)p->z; + }else{ + return 0; + } +} +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value* pVal){ +SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); } -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value *pVal){ +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16BE); } -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal){ +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16LE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -71975,7 +77138,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating ** point number string BLOB NULL */ -SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){ +SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { SQLITE_BLOB, /* 0x00 */ SQLITE_NULL, /* 0x01 */ @@ -72015,7 +77178,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){ /* Make a copy of an sqlite3_value object */ -SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *pOrig){ +SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ sqlite3_value *pNew; if( pOrig==0 ) return 0; pNew = sqlite3_malloc( sizeof(*pNew) ); @@ -72038,7 +77201,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value * /* Destroy an sqlite3_value object previously obtained from ** sqlite3_value_dup(). */ -SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value *pOld){ +SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ sqlite3ValueFree(pOld); } @@ -72081,7 +77244,7 @@ static int invokeValueDestructor( if( pCtx ) sqlite3_result_error_toobig(pCtx); return SQLITE_TOOBIG; } -SQLITE_API void SQLITE_STDCALL sqlite3_result_blob( +SQLITE_API void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, int n, @@ -72091,7 +77254,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob( assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, 0, xDel); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64( +SQLITE_API void sqlite3_result_blob64( sqlite3_context *pCtx, const void *z, sqlite3_uint64 n, @@ -72105,41 +77268,55 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64( setResultStrOrError(pCtx, z, (int)n, 0, xDel); } } -SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context *pCtx, double rVal){ +SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ +SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; pCtx->fErrorOrAux = 1; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ +SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; pCtx->fErrorOrAux = 1; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif -SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context *pCtx, int iVal){ +SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ +SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){ +SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ - assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - pCtx->pOut->eSubtype = eSubtype & 0xff; +SQLITE_API void sqlite3_result_pointer( + sqlite3_context *pCtx, + void *pPtr, + const char *zPType, + void (*xDestructor)(void*) +){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + sqlite3VdbeMemRelease(pOut); + pOut->flags = MEM_Null; + sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_text( +SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + pOut->eSubtype = eSubtype & 0xff; + pOut->flags |= MEM_Subtype; +} +SQLITE_API void sqlite3_result_text( sqlite3_context *pCtx, const char *z, int n, @@ -72148,7 +77325,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text( assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_text64( +SQLITE_API void sqlite3_result_text64( sqlite3_context *pCtx, const char *z, sqlite3_uint64 n, @@ -72165,7 +77342,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text64( } } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16( +SQLITE_API void sqlite3_result_text16( sqlite3_context *pCtx, const void *z, int n, @@ -72174,7 +77351,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16( assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be( +SQLITE_API void sqlite3_result_text16be( sqlite3_context *pCtx, const void *z, int n, @@ -72183,7 +77360,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be( assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le( +SQLITE_API void sqlite3_result_text16le( sqlite3_context *pCtx, const void *z, int n, @@ -72193,15 +77370,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le( setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ +SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemCopy(pCtx->pOut, pValue); } -SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n); } -SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ +SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ @@ -72210,7 +77387,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); return SQLITE_OK; } -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ +SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode; pCtx->fErrorOrAux = 1; #ifdef SQLITE_DEBUG @@ -72223,7 +77400,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, } /* Force an SQLITE_TOOBIG error. */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx){ +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; pCtx->fErrorOrAux = 1; @@ -72232,12 +77409,12 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx } /* An SQLITE_NOMEM error. */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){ +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); - pCtx->isError = SQLITE_NOMEM; + pCtx->isError = SQLITE_NOMEM_BKPT; pCtx->fErrorOrAux = 1; - pCtx->pOut->db->mallocFailed = 1; + sqlite3OomFault(pCtx->pOut->db); } /* @@ -72255,8 +77432,8 @@ static int doWalCallbacks(sqlite3 *db){ sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); - if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ - rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry); + if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){ + rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); } } } @@ -72311,7 +77488,7 @@ static int sqlite3Step(Vdbe *p){ db = p->db; if( db->mallocFailed ){ p->rc = SQLITE_NOMEM; - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } if( p->pc<=0 && p->expired ){ @@ -72333,7 +77510,8 @@ static int sqlite3Step(Vdbe *p){ ); #ifndef SQLITE_OMIT_TRACE - if( db->xProfile && !db->init.busy && p->zSql ){ + if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0) + && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ assert( p->startTime==0 ); @@ -72364,7 +77542,7 @@ static int sqlite3Step(Vdbe *p){ if( rc!=SQLITE_ROW ) checkProfileCallback(db, p); #endif - if( rc==SQLITE_DONE ){ + if( rc==SQLITE_DONE && db->autoCommit ){ assert( p->rc==SQLITE_OK ); p->rc = doWalCallbacks(db); if( p->rc!=SQLITE_OK ){ @@ -72374,7 +77552,7 @@ static int sqlite3Step(Vdbe *p){ db->errCode = rc; if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){ - p->rc = SQLITE_NOMEM; + p->rc = SQLITE_NOMEM_BKPT; } end_of_step: /* At this point local variable rc holds the value that should be @@ -72388,8 +77566,11 @@ end_of_step: || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); - if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ - /* If this statement was prepared using sqlite3_prepare_v2(), and an + if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 + && rc!=SQLITE_ROW + && rc!=SQLITE_DONE + ){ + /* If this statement was prepared using saved SQL and an ** error has occurred, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ @@ -72403,9 +77584,8 @@ end_of_step: ** sqlite3Step() to do most of the work. If a schema error occurs, ** call sqlite3Reprepare() and try again. */ -SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; /* Result from sqlite3Step() */ - int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */ int cnt = 0; /* Counter to prevent infinite loop of reprepares */ sqlite3 *db; /* The database connection */ @@ -72419,32 +77599,31 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; - rc2 = rc = sqlite3Reprepare(v); - if( rc!=SQLITE_OK) break; + rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK ){ + /* This case occurs after failing to recompile an sql statement. + ** The error message from the SQL compiler has already been loaded + ** into the database handle. This block copies the error message + ** from the database handle into the statement and sets the statement + ** program counter to 0 to ensure that when the statement is + ** finalized or reset the parser error message is available via + ** sqlite3_errmsg() and sqlite3_errcode(). + */ + const char *zErr = (const char *)sqlite3_value_text(db->pErr); + sqlite3DbFree(db, v->zErrMsg); + if( !db->mallocFailed ){ + v->zErrMsg = sqlite3DbStrDup(db, zErr); + v->rc = rc = sqlite3ApiExit(db, rc); + } else { + v->zErrMsg = 0; + v->rc = rc = SQLITE_NOMEM_BKPT; + } + break; + } sqlite3_reset(pStmt); if( savedPc>=0 ) v->doingRerun = 1; assert( v->expired==0 ); } - if( rc2!=SQLITE_OK ){ - /* This case occurs after failing to recompile an sql statement. - ** The error message from the SQL compiler has already been loaded - ** into the database handle. This block copies the error message - ** from the database handle into the statement and sets the statement - ** program counter to 0 to ensure that when the statement is - ** finalized or reset the parser error message is available via - ** sqlite3_errmsg() and sqlite3_errcode(). - */ - const char *zErr = (const char *)sqlite3_value_text(db->pErr); - sqlite3DbFree(db, v->zErrMsg); - if( !db->mallocFailed ){ - v->zErrMsg = sqlite3DbStrDup(db, zErr); - v->rc = rc2; - } else { - v->zErrMsg = 0; - v->rc = rc = SQLITE_NOMEM; - } - } - rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } @@ -72454,7 +77633,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){ ** Extract the user data from a sqlite3_context structure and return a ** pointer to it. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){ +SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ assert( p && p->pFunc ); return p->pFunc->pUserData; } @@ -72469,7 +77648,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){ ** sqlite3_create_function16() routines that originally registered the ** application defined function. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){ +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ assert( p && p->pOut ); return p->pOut->db; } @@ -72545,8 +77724,8 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){ ** context is allocated on the first call. Subsequent calls return the ** same context that was returned on prior calls. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){ - assert( p && p->pFunc && p->pFunc->xStep ); +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ + assert( p && p->pFunc && p->pFunc->xFinalize ); assert( sqlite3_mutex_held(p->pOut->db->mutex) ); testcase( nByte<0 ); if( (p->pMem->flags & MEM_Agg)==0 ){ @@ -72559,8 +77738,14 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, in /* ** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then access a cache of +** auxiliary data pointers that is available to all functions within a +** single prepared statement. The iArg values must match. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); @@ -72569,19 +77754,26 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int i #else assert( pCtx->pVdbe!=0 ); #endif - for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ - if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + return pAuxData->pAux; + } } - - return (pAuxData ? pAuxData->pAux : 0); + return 0; } /* ** Set the auxiliary data pointer and delete function, for the iArg'th ** argument to the user-function defined by pCtx. Any previous value is ** deleted by calling the delete function specified when it was set. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then make the data available +** to all functions within the current prepared statement using iArg as an +** access code. */ -SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata( +SQLITE_API void sqlite3_set_auxdata( sqlite3_context *pCtx, int iArg, void *pAux, @@ -72591,33 +77783,34 @@ SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata( Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - if( iArg<0 ) goto failed; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( pVdbe==0 ) goto failed; #else assert( pVdbe!=0 ); #endif - for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ - if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + break; + } } if( pAuxData==0 ){ pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); if( !pAuxData ) goto failed; - pAuxData->iOp = pCtx->iOp; - pAuxData->iArg = iArg; - pAuxData->pNext = pVdbe->pAuxData; + pAuxData->iAuxOp = pCtx->iOp; + pAuxData->iAuxArg = iArg; + pAuxData->pNextAux = pVdbe->pAuxData; pVdbe->pAuxData = pAuxData; if( pCtx->fErrorOrAux==0 ){ pCtx->isError = 0; pCtx->fErrorOrAux = 1; } - }else if( pAuxData->xDelete ){ - pAuxData->xDelete(pAuxData->pAux); + }else if( pAuxData->xDeleteAux ){ + pAuxData->xDeleteAux(pAuxData->pAux); } pAuxData->pAux = pAux; - pAuxData->xDelete = xDelete; + pAuxData->xDeleteAux = xDelete; return; failed: @@ -72636,8 +77829,8 @@ failed: ** implementations should keep their own counts within their aggregate ** context. */ -SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){ - assert( p && p->pMem && p->pFunc && p->pFunc->xStep ); +SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){ + assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize ); return p->pMem->n; } #endif @@ -72645,7 +77838,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){ /* ** Return the number of columns in the result set for the statement pStmt. */ -SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; return pVm ? pVm->nResColumn : 0; } @@ -72654,7 +77847,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){ ** Return the number of values available from the current row of the ** currently executing statement pStmt. */ -SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; if( pVm==0 || pVm->pResultSet==0 ) return 0; return pVm->nResColumn; @@ -72708,14 +77901,13 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ Mem *pOut; pVm = (Vdbe *)pStmt; - if( pVm && pVm->pResultSet!=0 && inResColumn && i>=0 ){ - sqlite3_mutex_enter(pVm->db->mutex); + if( pVm==0 ) return (Mem*)columnNullValue(); + assert( pVm->db ); + sqlite3_mutex_enter(pVm->db->mutex); + if( pVm->pResultSet!=0 && inResColumn && i>=0 ){ pOut = &pVm->pResultSet[i]; }else{ - if( pVm && ALWAYS(pVm->db) ){ - sqlite3_mutex_enter(pVm->db->mutex); - sqlite3Error(pVm->db, SQLITE_RANGE); - } + sqlite3Error(pVm->db, SQLITE_RANGE); pOut = (Mem*)columnNullValue(); } return pOut; @@ -72748,6 +77940,8 @@ static void columnMallocFailure(sqlite3_stmt *pStmt) */ Vdbe *p = (Vdbe *)pStmt; if( p ){ + assert( p->db!=0 ); + assert( sqlite3_mutex_held(p->db->mutex) ); p->rc = sqlite3ApiExit(p->db, p->rc); sqlite3_mutex_leave(p->db->mutex); } @@ -72757,7 +77951,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt) ** The following routines are used to access elements of the current row ** in the result set. */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ const void *val; val = sqlite3_value_blob( columnMem(pStmt,i) ); /* Even though there is no encoding conversion, value_blob() might @@ -72767,37 +77961,37 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, i columnMallocFailure(pStmt); return val; } -SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_bytes( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } -SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_bytes16( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } -SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt *pStmt, int i){ +SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){ double val = sqlite3_value_double( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } -SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt *pStmt, int i){ +SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_int( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } -SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt *pStmt, int i){ +SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){ sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } -SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt *pStmt, int i){ +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } -SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStmt, int i){ +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ Mem *pOut = columnMem(pStmt, i); if( pOut->flags&MEM_Static ){ pOut->flags &= ~MEM_Static; @@ -72807,13 +78001,13 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStm return (sqlite3_value *)pOut; } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ const void *val = sqlite3_value_text16( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } #endif /* SQLITE_OMIT_UTF16 */ -SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt *pStmt, int i){ +SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ int iType = sqlite3_value_type( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return iType; @@ -72865,7 +78059,7 @@ static const void *columnName( ** is the case, clear the mallocFailed flag and return NULL. */ if( db->mallocFailed ){ - db->mallocFailed = 0; + sqlite3OomClear(db); ret = 0; } sqlite3_mutex_leave(db->mutex); @@ -72877,12 +78071,12 @@ static const void *columnName( ** Return the name of the Nth column of the result set returned by SQL ** statement pStmt. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt *pStmt, int N){ +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ return columnName( pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ return columnName( pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); } @@ -72902,12 +78096,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, ** Return the column declaration type (if applicable) of the 'i'th column ** of the result set of SQL statement pStmt. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ return columnName( pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ return columnName( pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); } @@ -72920,12 +78114,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pS ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ +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); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ +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); } @@ -72936,12 +78130,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stm ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ +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); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ +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); } @@ -72952,12 +78146,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt * ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ +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); } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ +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); } @@ -73013,9 +78207,8 @@ static int vdbeUnbind(Vdbe *p, int i){ ** as if there had been a schema change, on the first sqlite3_step() call ** following any change to the bindings of that parameter. */ - if( p->isPrepareV2 && - ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff) - ){ + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); + if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<expired = 1; } return SQLITE_OK; @@ -73044,8 +78237,10 @@ static int bindText( if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } - sqlite3Error(p->db, rc); - rc = sqlite3ApiExit(p->db, rc); + if( rc ){ + sqlite3Error(p->db, rc); + rc = sqlite3ApiExit(p->db, rc); + } } sqlite3_mutex_leave(p->db->mutex); }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){ @@ -73058,16 +78253,19 @@ static int bindText( /* ** Bind a blob value to an SQL statement variable. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob( +SQLITE_API int sqlite3_bind_blob( sqlite3_stmt *pStmt, int i, const void *zData, int nData, void (*xDel)(void*) ){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( nData<0 ) return SQLITE_MISUSE_BKPT; +#endif return bindText(pStmt, i, zData, nData, xDel, 0); } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64( +SQLITE_API int sqlite3_bind_blob64( sqlite3_stmt *pStmt, int i, const void *zData, @@ -73081,7 +78279,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64( return bindText(pStmt, i, zData, (int)nData, xDel, 0); } } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ +SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); @@ -73091,10 +78289,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, do } return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ +SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ return sqlite3_bind_int64(p, i, (i64)iValue); } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); @@ -73104,7 +78302,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sql } return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ +SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ int rc; Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, i); @@ -73113,7 +78311,25 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ } return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text( +SQLITE_API int sqlite3_bind_pointer( + sqlite3_stmt *pStmt, + int i, + void *pPtr, + const char *zPTtype, + void (*xDestructor)(void*) +){ + int rc; + Vdbe *p = (Vdbe*)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); + sqlite3_mutex_leave(p->db->mutex); + }else if( xDestructor ){ + xDestructor(pPtr); + } + return rc; +} +SQLITE_API int sqlite3_bind_text( sqlite3_stmt *pStmt, int i, const char *zData, @@ -73122,7 +78338,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text( ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64( +SQLITE_API int sqlite3_bind_text64( sqlite3_stmt *pStmt, int i, const char *zData, @@ -73139,7 +78355,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64( } } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16( +SQLITE_API int sqlite3_bind_text16( sqlite3_stmt *pStmt, int i, const void *zData, @@ -73149,7 +78365,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16( return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); } #endif /* SQLITE_OMIT_UTF16 */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ +SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ int rc; switch( sqlite3_value_type((sqlite3_value*)pValue) ){ case SQLITE_INTEGER: { @@ -73180,7 +78396,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, con } return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); @@ -73190,7 +78406,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, } return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ +SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ int rc; Vdbe *p = (Vdbe *)pStmt; sqlite3_mutex_enter(p->db->mutex); @@ -73209,7 +78425,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i ** Return the number of wildcards that can be potentially bound to. ** This routine is added to support DBD::SQLite. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; return p ? p->nVar : 0; } @@ -73220,12 +78436,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ ** ** The result is always UTF-8. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ Vdbe *p = (Vdbe*)pStmt; - if( p==0 || i<1 || i>p->nzVar ){ - return 0; - } - return p->azVar[i-1]; + if( p==0 ) return 0; + return sqlite3VListNumToName(p->pVList, i); } /* @@ -73234,21 +78448,10 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt * ** return 0. */ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){ - int i; - if( p==0 ){ - return 0; - } - if( zName ){ - for(i=0; inzVar; i++){ - const char *z = p->azVar[i]; - if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){ - return i+1; - } - } - } - return 0; + if( p==0 || zName==0 ) return 0; + return sqlite3VListNameToNum(p->pVList, zName, nName); } -SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName)); } @@ -73282,16 +78485,18 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt ** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise ** SQLITE_OK is returned. */ -SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ +SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ Vdbe *pFrom = (Vdbe*)pFromStmt; Vdbe *pTo = (Vdbe*)pToStmt; if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } - if( pTo->isPrepareV2 && pTo->expmask ){ + assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 ); + if( pTo->expmask ){ pTo->expired = 1; } - if( pFrom->isPrepareV2 && pFrom->expmask ){ + assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 ); + if( pFrom->expmask ){ pFrom->expired = 1; } return sqlite3TransferBindings(pFromStmt, pToStmt); @@ -73304,7 +78509,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, ** the first argument to the sqlite3_prepare() that was used to create ** the statement in the first place. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){ +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->db : 0; } @@ -73312,16 +78517,16 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){ ** Return true if the prepared statement is guaranteed to not modify the ** database. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; } /* ** Return true if the prepared statement is in need of being reset. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){ +SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; - return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN; + return v!=0 && v->magic==VDBE_MAGIC_RUN && v->pc>=0; } /* @@ -73330,7 +78535,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){ ** prepared statement for the database connection. Return NULL if there ** are no more. */ -SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ sqlite3_stmt *pNext; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(pDb) ){ @@ -73351,7 +78556,7 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_ /* ** Return the value of a status counter for a prepared statement */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ Vdbe *pVdbe = (Vdbe*)pStmt; u32 v; #ifdef SQLITE_ENABLE_API_ARMOR @@ -73360,16 +78565,246 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, i return 0; } #endif - v = pVdbe->aCounter[op]; - if( resetFlag ) pVdbe->aCounter[op] = 0; + if( op==SQLITE_STMTSTATUS_MEMUSED ){ + sqlite3 *db = pVdbe->db; + sqlite3_mutex_enter(db->mutex); + v = 0; + db->pnBytesFreed = (int*)&v; + sqlite3VdbeClearObject(db, pVdbe); + sqlite3DbFree(db, pVdbe); + db->pnBytesFreed = 0; + sqlite3_mutex_leave(db->mutex); + }else{ + v = pVdbe->aCounter[op]; + if( resetFlag ) pVdbe->aCounter[op] = 0; + } return (int)v; } +/* +** Return the SQL associated with a prepared statement +*/ +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + return p ? p->zSql : 0; +} + +/* +** Return the SQL associated with a prepared statement with +** bound parameters expanded. Space to hold the returned string is +** obtained from sqlite3_malloc(). The caller is responsible for +** freeing the returned string by passing it to sqlite3_free(). +** +** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of +** expanded bound parameters. +*/ +SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ +#ifdef SQLITE_OMIT_TRACE + return 0; +#else + char *z = 0; + const char *zSql = sqlite3_sql(pStmt); + if( zSql ){ + Vdbe *p = (Vdbe *)pStmt; + sqlite3_mutex_enter(p->db->mutex); + z = sqlite3VdbeExpandSql(p, zSql); + sqlite3_mutex_leave(p->db->mutex); + } + return z; +#endif +} + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Allocate and populate an UnpackedRecord structure based on the serialized +** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure +** if successful, or a NULL pointer if an OOM error is encountered. +*/ +static UnpackedRecord *vdbeUnpackRecord( + KeyInfo *pKeyInfo, + int nKey, + const void *pKey +){ + UnpackedRecord *pRet; /* Return value */ + + pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRet ){ + memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1)); + sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet); + } + return pRet; +} + +/* +** This function is called from within a pre-update callback to retrieve +** a field of the row currently being updated or deleted. +*/ +SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ + PreUpdate *p = db->pPreUpdate; + Mem *pMem; + int rc = SQLITE_OK; + + /* Test that this call is being made from within an SQLITE_DELETE or + ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */ + if( !p || p->op==SQLITE_INSERT ){ + rc = SQLITE_MISUSE_BKPT; + goto preupdate_old_out; + } + if( p->pPk ){ + iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + } + if( iIdx>=p->pCsr->nField || iIdx<0 ){ + rc = SQLITE_RANGE; + goto preupdate_old_out; + } + + /* If the old.* record has not yet been loaded into memory, do so now. */ + if( p->pUnpacked==0 ){ + u32 nRec; + u8 *aRec; + + nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); + aRec = sqlite3DbMallocRaw(db, nRec); + if( !aRec ) goto preupdate_old_out; + rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); + if( rc==SQLITE_OK ){ + p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); + if( !p->pUnpacked ) rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, aRec); + goto preupdate_old_out; + } + p->aRecord = aRec; + } + + pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey1); + }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 ){ + sqlite3VdbeMemRealify(pMem); + } + } + + preupdate_old_out: + sqlite3Error(db, rc); + return sqlite3ApiExit(db, rc); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is called from within a pre-update callback to retrieve +** the number of columns in the row being updated, deleted or inserted. +*/ +SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ + PreUpdate *p = db->pPreUpdate; + return (p ? p->keyinfo.nKeyField : 0); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is designed to be called from within a pre-update callback +** only. It returns zero if the change that caused the callback was made +** immediately by a user SQL statement. Or, if the change was made by a +** trigger program, it returns the number of trigger programs currently +** on the stack (1 for a top-level trigger, 2 for a trigger fired by a +** top-level trigger etc.). +** +** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL +** or SET DEFAULT action is considered a trigger. +*/ +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ + PreUpdate *p = db->pPreUpdate; + return (p ? p->v->nFrame : 0); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is called from within a pre-update callback to retrieve +** a field of the row currently being updated or inserted. +*/ +SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ + PreUpdate *p = db->pPreUpdate; + int rc = SQLITE_OK; + Mem *pMem; + + if( !p || p->op==SQLITE_DELETE ){ + rc = SQLITE_MISUSE_BKPT; + goto preupdate_new_out; + } + if( p->pPk && p->op!=SQLITE_UPDATE ){ + iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + } + if( iIdx>=p->pCsr->nField || iIdx<0 ){ + rc = SQLITE_RANGE; + goto preupdate_new_out; + } + + if( p->op==SQLITE_INSERT ){ + /* For an INSERT, memory cell p->iNewReg contains the serialized record + ** that is being inserted. Deserialize it. */ + UnpackedRecord *pUnpack = p->pNewUnpacked; + if( !pUnpack ){ + Mem *pData = &p->v->aMem[p->iNewReg]; + rc = ExpandBlob(pData); + if( rc!=SQLITE_OK ) goto preupdate_new_out; + pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z); + if( !pUnpack ){ + rc = SQLITE_NOMEM; + goto preupdate_new_out; + } + p->pNewUnpacked = pUnpack; + } + pMem = &pUnpack->aMem[iIdx]; + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey2); + }else if( iIdx>=pUnpack->nField ){ + pMem = (sqlite3_value *)columnNullValue(); + } + }else{ + /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required + ** value. Make a copy of the cell contents and return a pointer to it. + ** It is not safe to return a pointer to the memory cell itself as the + ** caller may modify the value text encoding. + */ + assert( p->op==SQLITE_UPDATE ); + if( !p->aNew ){ + p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField); + if( !p->aNew ){ + rc = SQLITE_NOMEM; + goto preupdate_new_out; + } + } + assert( iIdx>=0 && iIdxpCsr->nField ); + pMem = &p->aNew[iIdx]; + if( pMem->flags==0 ){ + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey2); + }else{ + rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]); + if( rc!=SQLITE_OK ) goto preupdate_new_out; + } + } + } + *ppValue = pMem; + + preupdate_new_out: + sqlite3Error(db, rc); + return sqlite3ApiExit(db, rc); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Return status data for a single loop within query pStmt. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus( +SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement being queried */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Which metric to return */ @@ -73428,7 +78863,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus( /* ** Zero all counters associated with the sqlite3_stmt_scanstatus() data. */ -SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ +SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; memset(p->anExec, 0, p->nOp * sizeof(i64)); } @@ -73519,10 +78954,13 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ +#ifndef SQLITE_OMIT_UTF16 + Mem utf8; /* Used to convert UTF16 into UTF8 for display */ +#endif char zBase[100]; /* Initial working space */ db = p->db; - sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase), + sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ @@ -73566,19 +79004,21 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( if( pVar->flags & MEM_Null ){ sqlite3StrAccumAppend(&out, "NULL", 4); }else if( pVar->flags & MEM_Int ){ - sqlite3XPrintf(&out, 0, "%lld", pVar->u.i); + sqlite3XPrintf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ - sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r); + sqlite3XPrintf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); - Mem utf8; if( enc!=SQLITE_UTF8 ){ memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); - sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8); + if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ + out.accError = STRACCUM_NOMEM; + out.nAlloc = 0; + } pVar = &utf8; } #endif @@ -73589,17 +79029,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( while( nOutn && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; } } #endif - sqlite3XPrintf(&out, 0, "'%.*q'", nOut, pVar->z); + sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ - sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut); + sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif #ifndef SQLITE_OMIT_UTF16 if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8); #endif }else if( pVar->flags & MEM_Zero ){ - sqlite3XPrintf(&out, 0, "zeroblob(%d)", pVar->u.nZero); + sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero); }else{ int nOut; /* Number of bytes of the blob to include in output */ assert( pVar->flags & MEM_Blob ); @@ -73609,17 +79049,18 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT; #endif for(i=0; iz[i]&0xff); + sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff); } sqlite3StrAccumAppend(&out, "'", 1); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ - sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut); + sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif } } } + if( out.accError ) sqlite3StrAccumReset(&out); return sqlite3StrAccumFinish(&out); } @@ -73715,6 +79156,16 @@ static void updateMaxBlobsize(Mem *p){ } #endif +/* +** This macro evaluates to true if either the update hook or the preupdate +** hook are enabled for database connect DB. +*/ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +# define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback) +#else +# define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback) +#endif + /* ** The next global variable is incremented each time the OP_Found opcode ** is executed. This is used to test whether or not the foreign key @@ -73730,7 +79181,7 @@ SQLITE_API int sqlite3_found_count = 0; ** Test a register to see if it exceeds the current maximum blob size. ** If it does, record the new maximum blob size. */ -#if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST) +#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else # define UPDATE_MAX_BLOBSIZE(P) @@ -73821,11 +79272,11 @@ static VdbeCursor *allocateCursor( ** be freed lazily via the sqlite3_release_memory() API. This ** minimizes the number of malloc calls made by the system. ** - ** Memory cells for cursors are allocated at the top of the address - ** space. Memory cell (p->nMem) corresponds to cursor 0. Space for - ** cursor 1 is managed by memory cell (p->nMem-1), etc. + ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from + ** the top of the register space. Cursor 1 is at Mem[p->nMem-1]. + ** Cursor 2 is at Mem[p->nMem-2]. And so forth. */ - Mem *pMem = &p->aMem[p->nMem-iCur]; + Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; int nByte; VdbeCursor *pCx = 0; @@ -73833,14 +79284,14 @@ static VdbeCursor *allocateCursor( ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); - assert( iCurnCursor ); - if( p->apCsr[iCur] ){ + assert( iCur>=0 && iCurnCursor ); + if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; - memset(pCx, 0, sizeof(VdbeCursor)); + memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); pCx->eCurType = eCurType; pCx->iDb = iDb; pCx->nField = nField; @@ -73911,7 +79362,7 @@ static void applyAffinity( if( affinity>=SQLITE_AFF_NUMERIC ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL || affinity==SQLITE_AFF_NUMERIC ); - if( (pRec->flags & MEM_Int)==0 ){ + if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags & MEM_Real)==0 ){ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); }else{ @@ -73921,10 +79372,13 @@ static void applyAffinity( }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string - ** representation. - */ - if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ - sqlite3VdbeMemStringify(pRec, enc, 1); + ** representation. It would be harmless to repeat the conversion if + ** 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)) ){ + sqlite3VdbeMemStringify(pRec, enc, 1); + } } pRec->flags &= ~(MEM_Real|MEM_Int); } @@ -73936,7 +79390,7 @@ static void applyAffinity( ** is appropriate. But only do the conversion if it is possible without ** loss of information and return the revised type of the argument. */ -SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value *pVal){ +SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; @@ -73970,7 +79424,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ 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)==SQLITE_OK ){ + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){ return MEM_Int; } return MEM_Real; @@ -74019,9 +79473,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ }else{ c = 's'; } - - sqlite3_snprintf(100, zCsr, "%c", c); - zCsr += sqlite3Strlen30(zCsr); + *(zCsr++) = c; sqlite3_snprintf(100, zCsr, "%d[", pMem->n); zCsr += sqlite3Strlen30(zCsr); for(i=0; i<16 && in; i++){ @@ -74033,9 +79485,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ if( z<32 || z>126 ) *zCsr++ = '.'; else *zCsr++ = z; } - - sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]); - zCsr += sqlite3Strlen30(zCsr); + *(zCsr++) = ']'; if( f & MEM_Zero ){ sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero); zCsr += sqlite3Strlen30(zCsr); @@ -74100,11 +79550,13 @@ static void memTracePrint(Mem *p){ sqlite3VdbeMemPrettyPrint(p, zBuf); printf(" %s", zBuf); } + if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); } static void registerTrace(int iReg, Mem *p){ printf("REG[%d] = ", iReg); memTracePrint(p); printf("\n"); + sqlite3VdbeCheckMemInvariants(p); } #endif @@ -74138,8 +79590,8 @@ static void registerTrace(int iReg, Mem *p){ ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. @@ -74207,7 +79659,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in vdbe.c ***********************/ @@ -74246,10 +79698,10 @@ static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ Mem *pOut; assert( pOp->p2>0 ); - assert( pOp->p2<=(p->nMem-p->nCursor) ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); pOut = &p->aMem[pOp->p2]; memAboutToChange(p, pOut); - if( VdbeMemDynamic(pOut) ){ + if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/ return out2PrereleaseWithClear(pOut); }else{ pOut->flags = MEM_Int; @@ -74269,23 +79721,24 @@ SQLITE_PRIVATE int sqlite3VdbeExec( Op *pOp = aOp; /* Current operation */ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) Op *pOrigOp; /* Value of pOp at the top of the loop */ +#endif +#ifdef SQLITE_DEBUG + int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ - int iCompare = 0; /* Result of last OP_Compare operation */ + int iCompare = 0; /* Result of last comparison */ unsigned nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */ + unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ Mem *pIn2 = 0; /* 2nd input operand */ Mem *pIn3 = 0; /* 3rd input operand */ Mem *pOut = 0; /* Output operand */ - int *aPermute = 0; /* Permutation of columns for OP_Compare */ - i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ #ifdef VDBE_PROFILE u64 start; /* CPU clock count at start of opcode */ #endif @@ -74300,7 +79753,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec( } assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); assert( p->bIsReader || p->readOnly!=0 ); - p->rc = SQLITE_OK; p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; @@ -74312,6 +79764,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec( 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 @@ -74341,9 +79795,12 @@ SQLITE_PRIVATE int sqlite3VdbeExec( } sqlite3EndBenignMalloc(); #endif - for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){ + for(pOp=&aOp[p->pc]; 1; pOp++){ + /* Errors are detected by individual opcodes, with an immediate + ** jumps to abort_due_to_error. */ + assert( rc==SQLITE_OK ); + assert( pOp>=aOp && pOp<&aOp[p->nOp]); - if( db->mallocFailed ) goto no_mem; #ifdef VDBE_PROFILE start = sqlite3Hwtime(); #endif @@ -74375,37 +79832,39 @@ SQLITE_PRIVATE int sqlite3VdbeExec( /* Sanity checking on other operands */ #ifdef SQLITE_DEBUG - assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); - if( (pOp->opflags & OPFLG_IN1)!=0 ){ - assert( pOp->p1>0 ); - assert( pOp->p1<=(p->nMem-p->nCursor) ); - assert( memIsValid(&aMem[pOp->p1]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); - REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); - } - if( (pOp->opflags & OPFLG_IN2)!=0 ){ - assert( pOp->p2>0 ); - assert( pOp->p2<=(p->nMem-p->nCursor) ); - assert( memIsValid(&aMem[pOp->p2]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); - REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); - } - if( (pOp->opflags & OPFLG_IN3)!=0 ){ - assert( pOp->p3>0 ); - assert( pOp->p3<=(p->nMem-p->nCursor) ); - assert( memIsValid(&aMem[pOp->p3]) ); - assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); - REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); - } - if( (pOp->opflags & OPFLG_OUT2)!=0 ){ - assert( pOp->p2>0 ); - assert( pOp->p2<=(p->nMem-p->nCursor) ); - memAboutToChange(p, &aMem[pOp->p2]); - } - if( (pOp->opflags & OPFLG_OUT3)!=0 ){ - assert( pOp->p3>0 ); - assert( pOp->p3<=(p->nMem-p->nCursor) ); - memAboutToChange(p, &aMem[pOp->p3]); + { + u8 opProperty = sqlite3OpcodeProperty[pOp->opcode]; + if( (opProperty & OPFLG_IN1)!=0 ){ + assert( pOp->p1>0 ); + assert( pOp->p1<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p1]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); + REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); + } + if( (opProperty & OPFLG_IN2)!=0 ){ + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p2]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); + REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); + } + if( (opProperty & OPFLG_IN3)!=0 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p3]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); + REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); + } + if( (opProperty & OPFLG_OUT2)!=0 ){ + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + memAboutToChange(p, &aMem[pOp->p2]); + } + if( (opProperty & OPFLG_OUT3)!=0 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + memAboutToChange(p, &aMem[pOp->p3]); + } } #endif #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) @@ -74466,7 +79925,7 @@ jump_to_p2_and_check_for_interrupt: pOp = &aOp[pOp->p2 - 1]; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, - ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon + ** OP_VNext, or OP_SorterNext) all jump here upon ** completion. Check to see if sqlite3_interrupt() has been called ** or if the progress callback needs to be invoked. ** @@ -74484,12 +79943,12 @@ check_for_interrupt: ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ - if( db->xProgress!=0 && nVmStep>=nProgressLimit ){ + if( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); if( db->xProgress(db->pProgressArg) ){ rc = SQLITE_INTERRUPT; - goto vdbe_error_halt; + goto abort_due_to_error; } } #endif @@ -74503,7 +79962,7 @@ check_for_interrupt: ** and then jump to address P2. */ case OP_Gosub: { /* jump */ - assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); memAboutToChange(p, pIn1); @@ -74543,7 +80002,7 @@ case OP_Return: { /* in1 */ ** See also: EndCoroutine */ case OP_InitCoroutine: { /* jump */ - assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p2>=0 && pOp->p2nOp ); assert( pOp->p3>=0 && pOp->p3nOp ); pOut = &aMem[pOp->p1]; @@ -74601,7 +80060,7 @@ case OP_Yield: { /* in1, jump */ } /* Opcode: HaltIfNull P1 P2 P3 P4 P5 -** Synopsis: if r[P3]=null halt +** Synopsis: if r[P3]=null halt ** ** Check the value in register P3. If it is NULL then Halt using ** parameter P1, P2, and P4 as if this were a Halt instruction. If the @@ -74645,8 +80104,6 @@ case OP_HaltIfNull: { /* in3 */ ** is the same as executing Halt. */ case OP_Halt: { - const char *zType; - const char *zLogFmt; VdbeFrame *pFrame; int pcx; @@ -74658,7 +80115,6 @@ case OP_Halt: { p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); pcx = sqlite3VdbeFrameRestore(pFrame); - lastRowid = db->lastRowid; if( pOp->p2==OE_Ignore ){ /* Instruction pcx is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt @@ -74675,34 +80131,28 @@ case OP_Halt: { p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pcx; + assert( pOp->p5<=4 ); if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", "FOREIGN KEY" }; - assert( pOp->p5>=1 && pOp->p5<=4 ); testcase( pOp->p5==1 ); testcase( pOp->p5==2 ); testcase( pOp->p5==3 ); testcase( pOp->p5==4 ); - zType = azType[pOp->p5-1]; + sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]); + if( pOp->p4.z ){ + p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z); + } }else{ - zType = 0; - } - assert( zType!=0 || pOp->p4.z!=0 ); - zLogFmt = "abort at %d in [%s]: %s"; - if( zType && pOp->p4.z ){ - sqlite3VdbeError(p, "%s constraint failed: %s", zType, pOp->p4.z); - }else if( pOp->p4.z ){ sqlite3VdbeError(p, "%s", pOp->p4.z); - }else{ - sqlite3VdbeError(p, "%s constraint failed", zType); } - sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg); + sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ - p->rc = rc = SQLITE_BUSY; + p->rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 ); @@ -74768,7 +80218,7 @@ case OP_String8: { /* same as TK_STRING, out2 */ #ifndef SQLITE_OMIT_UTF16 if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); - if( rc==SQLITE_TOOBIG ) goto too_big; + assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); @@ -74781,10 +80231,12 @@ 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; } + assert( rc==SQLITE_OK ); /* Fall through to the next case, OP_String */ } @@ -74793,10 +80245,12 @@ case OP_String8: { /* same as TK_STRING, out2 */ ** ** The string value P4 of length P1 (bytes) is stored in register P2. ** -** If P5!=0 and the content of register P3 is greater than zero, then +** If P3 is not zero and the content of register P3 is equal to P5, then ** the datatype of the register P2 is converted to BLOB. The content is ** the same sequence of bytes, it is merely interpreted as a BLOB instead -** of a string, as if it had been CAST. +** of a string, as if it had been CAST. In other words: +** +** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB) */ case OP_String: { /* out2 */ assert( pOp->p4.z!=0 ); @@ -74807,19 +80261,18 @@ case OP_String: { /* out2 */ pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS - if( pOp->p5 ){ - assert( pOp->p3>0 ); - assert( pOp->p3<=(p->nMem-p->nCursor) ); + if( pOp->p3>0 ){ + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); - if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; + if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; } #endif break; } /* Opcode: Null P1 P2 P3 * * -** Synopsis: r[P2..P3]=NULL +** Synopsis: r[P2..P3]=NULL ** ** Write a NULL into registers P2. If P3 greater than P2, then also write ** NULL into register P3 and every register in between P2 and P3. If P3 @@ -74835,20 +80288,22 @@ case OP_Null: { /* out2 */ u16 nullFlag; pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; - assert( pOp->p3<=(p->nMem-p->nCursor) ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; + pOut->n = 0; while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); sqlite3VdbeMemSetNull(pOut); pOut->flags = nullFlag; + pOut->n = 0; cnt--; } break; } /* Opcode: SoftNull P1 * * * * -** Synopsis: r[P1]=NULL +** Synopsis: r[P1]=NULL ** ** Set register P1 to have the value NULL as seen by the OP_MakeRecord ** instruction, but do not free any string or blob memory associated with @@ -74856,9 +80311,9 @@ case OP_Null: { /* out2 */ ** previously copied using OP_SCopy, the copies will continue to be valid. */ case OP_SoftNull: { - assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pOut = &aMem[pOp->p1]; - pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined; + pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null; break; } @@ -74889,19 +80344,19 @@ case OP_Variable: { /* out2 */ Mem *pVar; /* Value being transferred */ assert( pOp->p1>0 && pOp->p1<=p->nVar ); - assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] ); + assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } - pOut = out2Prerelease(p, pOp); + pOut = &aMem[pOp->p2]; sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Move P1 P2 P3 * * -** Synopsis: r[P2@P3]=r[P1@P3] +** Synopsis: r[P2@P3]=r[P1@P3] ** ** Move the P3 values in register P1..P1+P3-1 over into ** registers P2..P2+P3-1. Registers P1..P1+P3-1 are @@ -74923,8 +80378,8 @@ case OP_Move: { pIn1 = &aMem[p1]; pOut = &aMem[p2]; do{ - assert( pOut<=&aMem[(p->nMem-p->nCursor)] ); - assert( pIn1<=&aMem[(p->nMem-p->nCursor)] ); + assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] ); + assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); sqlite3VdbeMemMove(pOut, pIn1); @@ -75011,7 +80466,7 @@ case OP_IntCopy: { /* out2 */ } /* Opcode: ResultRow P1 P2 * * * -** Synopsis: output=r[P1@P2] +** Synopsis: output=r[P1@P2] ** ** The registers P1 through P1+P2-1 contain a single row of ** results. This opcode causes the sqlite3_step() call to terminate @@ -75024,17 +80479,17 @@ case OP_ResultRow: { int i; assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 ); - assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 ); + 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 + && nVmStep>=nProgressLimit && db->xProgress(db->pProgressArg)!=0 ){ rc = SQLITE_INTERRUPT; - goto vdbe_error_halt; + goto abort_due_to_error; } #endif @@ -75044,7 +80499,7 @@ case OP_ResultRow: { if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){ assert( db->flags&SQLITE_CountRows ); assert( p->usesStmtJournal ); - break; + goto abort_due_to_error; } /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then @@ -75064,9 +80519,7 @@ case OP_ResultRow: { */ assert( p->iStatement==0 || db->flags&SQLITE_CountRows ); rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE); - if( NEVER(rc!=SQLITE_OK) ){ - break; - } + assert( rc==SQLITE_OK ); /* Invalidate all ephemeral cursor row caches */ p->cacheCtr = (p->cacheCtr + 2)|1; @@ -75086,6 +80539,10 @@ case OP_ResultRow: { } if( db->mallocFailed ) goto no_mem; + if( db->mTrace & SQLITE_TRACE_ROW ){ + db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); + } + /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; @@ -75142,14 +80599,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ } /* Opcode: Add P1 P2 P3 * * -** Synopsis: r[P3]=r[P1]+r[P2] +** Synopsis: r[P3]=r[P1]+r[P2] ** ** Add the value in register P1 to the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Multiply P1 P2 P3 * * -** Synopsis: r[P3]=r[P1]*r[P2] +** Synopsis: r[P3]=r[P1]*r[P2] ** ** ** Multiply the value in register P1 by the value in register P2 @@ -75157,14 +80614,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ ** If either input is NULL, the result is NULL. */ /* Opcode: Subtract P1 P2 P3 * * -** Synopsis: r[P3]=r[P2]-r[P1] +** Synopsis: r[P3]=r[P2]-r[P1] ** ** Subtract the value in register P1 from the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Divide P1 P2 P3 * * -** Synopsis: r[P3]=r[P2]/r[P1] +** Synopsis: r[P3]=r[P2]/r[P1] ** ** Divide the value in register P1 by the value in register P2 ** and store the result in register P3 (P3=P2/P1). If the value in @@ -75172,7 +80629,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ ** NULL, the result is NULL. */ /* Opcode: Remainder P1 P2 P3 * * -** Synopsis: r[P3]=r[P2]%r[P1] +** Synopsis: r[P3]=r[P2]%r[P1] ** ** Compute the remainder after integer register P2 is divided by ** register P1 and store the result in register P3. @@ -75199,7 +80656,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ type2 = numericType(pIn2); pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; - if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; @@ -75223,6 +80679,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } pOut->u.i = iB; MemSetTypeFlag(pOut, MEM_Int); + }else if( (flags & MEM_Null)!=0 ){ + goto arithmetic_result_is_null; }else{ bIntint = 0; fp_math: @@ -75270,7 +80728,7 @@ arithmetic_result_is_null: /* Opcode: CollSeq P1 * * P4 ** -** P4 is a pointer to a CollSeq struct. If the next call to a user function +** P4 is a pointer to a CollSeq object. If the next call to a user function ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will ** be returned. This is used by the built-in min(), max() and nullif() ** functions. @@ -75291,134 +80749,22 @@ case OP_CollSeq: { break; } -/* Opcode: Function0 P1 P2 P3 P4 P5 -** Synopsis: r[P3]=func(r[P2@P5]) -** -** Invoke a user function (P4 is a pointer to a FuncDef object that -** defines the function) with P5 arguments taken from register P2 and -** successors. The result of the function is stored in register P3. -** Register P3 must not be one of the function inputs. -** -** P1 is a 32-bit bitmask indicating whether or not each argument to the -** function was determined to be constant at compile time. If the first -** argument was constant then bit 0 of P1 is set. This is used to determine -** whether meta data associated with a user function argument using the -** sqlite3_set_auxdata() API may be safely retained until the next -** invocation of this opcode. -** -** See also: Function, AggStep, AggFinal -*/ -/* Opcode: Function P1 P2 P3 P4 P5 -** Synopsis: r[P3]=func(r[P2@P5]) -** -** Invoke a user function (P4 is a pointer to an sqlite3_context object that -** contains a pointer to the function to be run) with P5 arguments taken -** from register P2 and successors. The result of the function is stored -** in register P3. Register P3 must not be one of the function inputs. -** -** P1 is a 32-bit bitmask indicating whether or not each argument to the -** function was determined to be constant at compile time. If the first -** argument was constant then bit 0 of P1 is set. This is used to determine -** whether meta data associated with a user function argument using the -** sqlite3_set_auxdata() API may be safely retained until the next -** invocation of this opcode. -** -** SQL functions are initially coded as OP_Function0 with P4 pointing -** to a FuncDef object. But on first evaluation, the P4 operand is -** automatically converted into an sqlite3_context object and the operation -** changed to this OP_Function opcode. In this way, the initialization of -** the sqlite3_context object occurs only once, rather than once for each -** evaluation of the function. -** -** See also: Function0, AggStep, AggFinal -*/ -case OP_Function0: { - int n; - sqlite3_context *pCtx; - - assert( pOp->p4type==P4_FUNCDEF ); - n = pOp->p5; - assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); - assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) ); - assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); - pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); - if( pCtx==0 ) goto no_mem; - pCtx->pOut = 0; - pCtx->pFunc = pOp->p4.pFunc; - pCtx->iOp = (int)(pOp - aOp); - pCtx->pVdbe = p; - pCtx->argc = n; - pOp->p4type = P4_FUNCCTX; - pOp->p4.pCtx = pCtx; - pOp->opcode = OP_Function; - /* Fall through into OP_Function */ -} -case OP_Function: { - int i; - sqlite3_context *pCtx; - - assert( pOp->p4type==P4_FUNCCTX ); - pCtx = pOp->p4.pCtx; - - /* If this function is inside of a trigger, the register array in aMem[] - ** might change from one evaluation to the next. The next block of code - ** checks to see if the register array has changed, and if so it - ** reinitializes the relavant parts of the sqlite3_context object */ - pOut = &aMem[pOp->p3]; - if( pCtx->pOut != pOut ){ - pCtx->pOut = pOut; - for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; - } - - memAboutToChange(p, pCtx->pOut); -#ifdef SQLITE_DEBUG - for(i=0; iargc; i++){ - assert( memIsValid(pCtx->argv[i]) ); - REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); - } -#endif - MemSetTypeFlag(pCtx->pOut, MEM_Null); - pCtx->fErrorOrAux = 0; - db->lastRowid = lastRowid; - (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */ - lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ - - /* If the function returned an error, throw an exception */ - if( pCtx->fErrorOrAux ){ - if( pCtx->isError ){ - sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut)); - rc = pCtx->isError; - } - sqlite3VdbeDeleteAuxData(p, pCtx->iOp, pOp->p1); - } - - /* Copy the result of the function into register P3 */ - if( pOut->flags & (MEM_Str|MEM_Blob) ){ - sqlite3VdbeChangeEncoding(pCtx->pOut, encoding); - if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big; - } - - REGISTER_TRACE(pOp->p3, pCtx->pOut); - UPDATE_MAX_BLOBSIZE(pCtx->pOut); - break; -} - /* Opcode: BitAnd P1 P2 P3 * * -** Synopsis: r[P3]=r[P1]&r[P2] +** Synopsis: r[P3]=r[P1]&r[P2] ** ** Take the bit-wise AND of the values in register P1 and P2 and ** store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: BitOr P1 P2 P3 * * -** Synopsis: r[P3]=r[P1]|r[P2] +** Synopsis: r[P3]=r[P1]|r[P2] ** ** Take the bit-wise OR of the values in register P1 and P2 and ** store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: ShiftLeft P1 P2 P3 * * -** Synopsis: r[P3]=r[P2]<>r[P1] +** Synopsis: r[P3]=r[P2]>>r[P1] ** ** Shift the integer value in register P2 to the right by the ** number of bits specified by the integer in register P1. @@ -75486,7 +80832,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ } /* Opcode: AddImm P1 P2 * * * -** Synopsis: r[P1]=r[P1]+P2 +** Synopsis: r[P1]=r[P1]+P2 ** ** Add the constant P2 to the value in register P1. ** The result is always an integer. @@ -75552,11 +80898,11 @@ case OP_RealAffinity: { /* in1 */ ** Force the value in register P1 to be the type defined by P2. ** **
      -**
    • TEXT -**
    • BLOB -**
    • NUMERIC -**
    • INTEGER -**
    • REAL +**
    • P2=='A' → BLOB +**
    • P2=='B' → TEXT +**
    • P2=='C' → NUMERIC +**
    • P2=='D' → INTEGER +**
    • P2=='E' → REAL **
    ** ** A NULL value is not changed by this routine. It remains NULL. @@ -75573,18 +80919,66 @@ case OP_Cast: { /* in1 */ rc = ExpandBlob(pIn1); sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); UPDATE_MAX_BLOBSIZE(pIn1); + if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_CAST */ +/* Opcode: Eq P1 P2 P3 P4 P5 +** Synopsis: IF r[P3]==r[P1] +** +** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then +** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then +** store the result of comparison in register P2. +** +** The SQLITE_AFF_MASK portion of P5 must be an affinity character - +** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made +** to coerce both inputs according to this affinity before the +** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric +** affinity is used. Note that the affinity conversions are stored +** back into the input registers P1 and P3. So this opcode can cause +** persistent changes to registers P1 and P3. +** +** Once any conversions have taken place, and neither value is NULL, +** the values are compared. If both values are blobs then memcmp() is +** used to determine the results of the comparison. If both values +** are text, then the appropriate collating function specified in +** P4 is used to do the comparison. If P4 is not specified then +** memcmp() is used to compare text string. If both values are +** numeric, then a numeric comparison is used. If the two values +** are of different types, then numbers are considered less than +** strings and strings are considered less than blobs. +** +** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either +** true or false and is never NULL. If both operands are NULL then the result +** of comparison is true. If either operand is NULL then the result is false. +** If neither operand is NULL the result is the same as it would be if +** the SQLITE_NULLEQ flag were omitted from P5. +** +** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the +** content of r[P2] is only changed if the new value is NULL or 0 (false). +** In other words, a prior r[P2] value will not be overwritten by 1 (true). +*/ +/* Opcode: Ne P1 P2 P3 P4 P5 +** Synopsis: IF r[P3]!=r[P1] +** +** This works just like the Eq opcode except that the jump is taken if +** the operands in registers P1 and P3 are not equal. See the Eq opcode for +** additional information. +** +** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the +** content of r[P2] is only changed if the new value is NULL or 1 (true). +** In other words, a prior r[P2] value will not be overwritten by 0 (false). +*/ /* Opcode: Lt P1 P2 P3 P4 P5 -** Synopsis: if r[P1]r[P3] goto P2 +** Synopsis: IF r[P3]>r[P1] ** ** This works just like the Lt opcode except that the jump is taken if ** the content of register P3 is greater than the content of ** register P1. See the Lt opcode for additional information. */ /* Opcode: Ge P1 P2 P3 P4 P5 -** Synopsis: if r[P1]>=r[P3] goto P2 +** Synopsis: IF r[P3]>=r[P1] ** ** This works just like the Lt opcode except that the jump is taken if ** the content of register P3 is greater than or equal to the content of @@ -75665,7 +81026,7 @@ case OP_Lt: /* same as TK_LT, jump, in1, in3 */ case OP_Le: /* same as TK_LE, jump, in1, in3 */ case OP_Gt: /* same as TK_GT, jump, in1, in3 */ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ - int res; /* Result of the comparison of pIn1 against pIn3 */ + int res, res2; /* Result of the comparison of pIn1 against pIn3 */ char affinity; /* Affinity to use for comparison */ u16 flags1; /* Copy of initial value of pIn1->flags */ u16 flags3; /* Copy of initial value of pIn3->flags */ @@ -75684,13 +81045,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); assert( (flags1 & MEM_Cleared)==0 ); assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 ); - if( (flags1&MEM_Null)!=0 - && (flags3&MEM_Null)!=0 + if( (flags1&flags3&MEM_Null)!=0 && (flags3&MEM_Cleared)==0 ){ - res = 0; /* Results are equal */ + res = 0; /* Operands are equal */ }else{ - res = 1; /* Results are not equal */ + res = 1; /* Operands are not equal */ } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, @@ -75699,6 +81059,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ */ if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; + iCompare = 1; /* Operands are not equal */ memAboutToChange(p, pOut); MemSetTypeFlag(pOut, MEM_Null); REGISTER_TRACE(pOp->p2, pOut); @@ -75714,11 +81075,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ /* Neither operand is NULL. Do a comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ - if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ - applyNumericAffinity(pIn1,0); + if( (flags1 | flags3)&MEM_Str ){ + if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn1,0); + testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */ + flags3 = pIn3->flags; + } + if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3,0); + } } - if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ - applyNumericAffinity(pIn3,0); + /* Handle the common case of integer comparison here, as an + ** optimization, to avoid a call to sqlite3MemCompare() */ + if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){ + if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; } + if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; } + res = 0; + goto compare_op; } }else if( affinity==SQLITE_AFF_TEXT ){ if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ @@ -75727,6 +81100,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ 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 ){ testcase( pIn3->flags & MEM_Int ); @@ -75737,23 +81111,26 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ } } assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); - if( flags1 & MEM_Zero ){ - sqlite3VdbeMemExpandBlob(pIn1); - flags1 &= ~MEM_Zero; - } - if( flags3 & MEM_Zero ){ - sqlite3VdbeMemExpandBlob(pIn3); - flags3 &= ~MEM_Zero; - } res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } - switch( pOp->opcode ){ - case OP_Eq: res = res==0; break; - case OP_Ne: res = res!=0; break; - case OP_Lt: res = res<0; break; - case OP_Le: res = res<=0; break; - case OP_Gt: res = res>0; break; - default: res = res>=0; break; +compare_op: + /* At this point, res is negative, zero, or positive if reg[P1] is + ** less than, equal to, or greater than reg[P3], respectively. Compute + ** the answer to this operator in res2, depending on what the comparison + ** operator actually is. The next block of code depends on the fact + ** that the 6 comparison operators are consecutive integers in this + ** order: NE, EQ, GT, LE, LT, GE */ + assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 ); + assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 ); + if( res<0 ){ /* ne, eq, gt, le, lt, ge */ + static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 }; + res2 = aLTb[pOp->opcode - OP_Ne]; + }else if( res==0 ){ + static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 }; + res2 = aEQb[pOp->opcode - OP_Ne]; + }else{ + static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 }; + res2 = aGTb[pOp->opcode - OP_Ne]; } /* Undo any changes made by applyAffinity() to the input registers. */ @@ -75764,32 +81141,71 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; + iCompare = res; + if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){ + /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1 + ** and prevents OP_Ne from overwriting NULL with 0. This flag + ** is only used in contexts where either: + ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0) + ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1) + ** Therefore it is not necessary to check the content of r[P2] for + ** NULL. */ + assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq ); + assert( res2==0 || res2==1 ); + testcase( res2==0 && pOp->opcode==OP_Eq ); + testcase( res2==1 && pOp->opcode==OP_Eq ); + testcase( res2==0 && pOp->opcode==OP_Ne ); + testcase( res2==1 && pOp->opcode==OP_Ne ); + if( (pOp->opcode==OP_Eq)==res2 ) break; + } memAboutToChange(p, pOut); MemSetTypeFlag(pOut, MEM_Int); - pOut->u.i = res; + pOut->u.i = res2; REGISTER_TRACE(pOp->p2, pOut); }else{ VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); - if( res ){ + if( res2 ){ goto jump_to_p2; } } break; } +/* Opcode: ElseNotEq * P2 * * * +** +** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator. +** If result of an OP_Eq comparison on the same two operands +** would have be NULL or false (0), then then jump to P2. +** If the result of an OP_Eq comparison on the two previous operands +** would have been true (1), then fall through. +*/ +case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ + assert( pOp>aOp ); + assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt ); + assert( pOp[-1].p5 & SQLITE_STOREP2 ); + VdbeBranchTaken(iCompare!=0, 2); + if( iCompare!=0 ) goto jump_to_p2; + break; +} + + /* Opcode: Permutation * * * P4 * ** -** Set the permutation used by the OP_Compare operator to be the array -** of integers in P4. +** Set the permutation used by the OP_Compare operator in the next +** instruction. The permutation is stored in the P4 operand. ** ** The permutation is only valid until the next OP_Compare that has ** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should ** occur immediately prior to the OP_Compare. +** +** The first integer in the P4 integer array is the length of the array +** and does not become part of the permutation. */ case OP_Permutation: { assert( pOp->p4type==P4_INTARRAY ); assert( pOp->p4.ai ); - aPermute = pOp->p4.ai; + assert( pOp[1].opcode==OP_Compare ); + assert( pOp[1].p5 & OPFLAG_PERMUTE ); break; } @@ -75822,23 +81238,32 @@ case OP_Compare: { int idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ + int *aPermute; /* The permutation */ - if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0; + if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){ + aPermute = 0; + }else{ + assert( pOp>aOp ); + assert( pOp[-1].opcode==OP_Permutation ); + assert( pOp[-1].p4type==P4_INTARRAY ); + aPermute = pOp[-1].p4.ai + 1; + assert( aPermute!=0 ); + } n = pOp->p3; pKeyInfo = pOp->p4.pKeyInfo; assert( n>0 ); assert( pKeyInfo!=0 ); p1 = pOp->p1; p2 = pOp->p2; -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG if( aPermute ){ int k, mx = 0; for(k=0; kmx ) mx = aPermute[k]; - assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 ); - assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 ); + assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 ); + assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 ); }else{ - assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 ); - assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 ); + assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 ); + assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 ); } #endif /* SQLITE_DEBUG */ for(i=0; inField ); + assert( inKeyField ); pColl = pKeyInfo->aColl[i]; bRev = pKeyInfo->aSortOrder[i]; iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); @@ -75856,7 +81281,6 @@ case OP_Compare: { break; } } - aPermute = 0; break; } @@ -75969,23 +81393,39 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ /* Opcode: Once P1 P2 * * * ** -** Check the "once" flag number P1. If it is set, jump to instruction P2. -** Otherwise, set the flag and fall through to the next instruction. -** In other words, this opcode causes all following opcodes up through P2 -** (but not including P2) to run just once and to be skipped on subsequent -** times through the loop. +** Fall through to the next instruction the first time this opcode is +** encountered on each invocation of the byte-code program. Jump to P2 +** on the second and all subsequent encounters during the same invocation. ** -** All "once" flags are initially cleared whenever a prepared statement -** first begins to run. +** Top-level programs determine first invocation by comparing the P1 +** operand against the P1 operand on the OP_Init opcode at the beginning +** of the program. If the P1 values differ, then fall through and make +** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are +** the same then take the jump. +** +** For subprograms, there is a bitmask in the VdbeFrame that determines +** whether or not the jump should be taken. The bitmask is necessary +** because the self-altering code trick does not work for recursive +** triggers. */ case OP_Once: { /* jump */ - assert( pOp->p1nOnceFlag ); - VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2); - if( p->aOnceFlag[pOp->p1] ){ - goto jump_to_p2; + u32 iAddr; /* Address of this instruction */ + assert( p->aOp[0].opcode==OP_Init ); + if( p->pFrame ){ + iAddr = (int)(pOp - p->aOp); + if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){ + VdbeBranchTaken(1, 2); + goto jump_to_p2; + } + p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7); }else{ - p->aOnceFlag[pOp->p1] = 1; + if( p->aOp[0].p1==pOp->p1 ){ + VdbeBranchTaken(1, 2); + goto jump_to_p2; + } } + VdbeBranchTaken(0, 2); + pOp->p1 = p->aOp[0].p1; break; } @@ -76023,7 +81463,7 @@ case OP_IfNot: { /* jump, in1 */ } /* Opcode: IsNull P1 P2 * * * -** Synopsis: if r[P1]==NULL goto P2 +** Synopsis: if r[P1]==NULL goto P2 ** ** Jump to P2 if the value in register P1 is NULL. */ @@ -76050,8 +81490,26 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ break; } +/* Opcode: IfNullRow P1 P2 P3 * * +** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 +** +** Check the cursor P1 to see if it is currently pointing at a NULL row. +** If it is, then set register P3 to NULL and jump immediately to P2. +** If P1 is not on a NULL row, then fall through without making any +** changes. +*/ +case OP_IfNullRow: { /* jump */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( p->apCsr[pOp->p1]!=0 ); + if( p->apCsr[pOp->p1]->nullRow ){ + sqlite3VdbeMemSetNull(aMem + pOp->p3); + goto jump_to_p2; + } + break; +} + /* Opcode: Column P1 P2 P3 P4 P5 -** Synopsis: r[P3]=PX +** Synopsis: r[P3]=PX ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional @@ -76061,7 +81519,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ ** ** The value extracted is stored in register P3. ** -** If the column contains fewer than P2 fields, then extract a NULL. Or, +** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. ** @@ -76070,13 +81528,12 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ ** The first OP_Column against a pseudo-table after the value of the content ** register has changed should have this bit set. ** -** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when +** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { - i64 payloadSize64; /* Number of bytes in the record */ int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ @@ -76088,78 +81545,64 @@ case OP_Column: { const u8 *zData; /* Part of the record being decoded */ const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ - u32 offset; /* Offset into the data */ u64 offset64; /* 64-bit offset */ - u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ - u16 fx; /* pDest->flags value */ Mem *pReg; /* PseudoTable input register */ + pC = p->apCsr[pOp->p1]; p2 = pOp->p2; - assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); + + /* If the cursor cache is stale (meaning it is not currently point at + ** the correct row) then bring it up-to-date by doing the necessary + ** B-Tree seek. */ + rc = sqlite3VdbeCursorMoveto(&pC, &p2); + if( rc ) goto abort_due_to_error; + + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1nCursor ); - pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2nField ); aOffset = pC->aOffset; assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); - pCrsr = pC->uc.pCursor; - /* If the cursor cache is stale, bring it up-to-date */ - rc = sqlite3VdbeCursorMoveto(pC); - if( rc ) goto abort_due_to_error; - if( pC->cacheStatus!=p->cacheCtr ){ + if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ if( pC->eCurType==CURTYPE_PSEUDO ){ - assert( pC->uc.pseudoTableReg>0 ); - pReg = &aMem[pC->uc.pseudoTableReg]; + /* For the special case of as pseudo-cursor, the seekResult field + ** identifies the register that holds the record */ + assert( pC->seekResult>0 ); + pReg = &aMem[pC->seekResult]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); - pC->payloadSize = pC->szRow = avail = pReg->n; + pC->payloadSize = pC->szRow = pReg->n; pC->aRow = (u8*)pReg->z; }else{ sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ + pCrsr = pC->uc.pCursor; assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); - if( pC->isTable==0 ){ - assert( sqlite3BtreeCursorIsValid(pCrsr) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64); - assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ - /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the - ** payload size, so it is impossible for payloadSize64 to be - ** larger than 32 bits. */ - assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 ); - pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail); - pC->payloadSize = (u32)payloadSize64; - }else{ - assert( sqlite3BtreeCursorIsValid(pCrsr) ); - VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize); - assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ - pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail); - } - assert( avail<=65536 ); /* Maximum page size is 64KiB */ - if( pC->payloadSize <= (u32)avail ){ - pC->szRow = pC->payloadSize; - }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + assert( sqlite3BtreeCursorIsValid(pCrsr) ); + pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); + pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); + assert( pC->szRow<=pC->payloadSize ); + assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ + if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; - }else{ - pC->szRow = avail; } } pC->cacheStatus = p->cacheCtr; - pC->iHdrOffset = getVarint32(pC->aRow, offset); + pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); pC->nHdrParsed = 0; - aOffset[0] = offset; - if( availszRowaRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be @@ -76176,18 +81619,28 @@ case OP_Column: { ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ - if( offset > 98307 || offset > pC->payloadSize ){ - rc = SQLITE_CORRUPT_BKPT; - goto op_column_error; + if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){ + goto op_column_corrupt; } + }else{ + /* This is an optimization. By skipping over the first few tests + ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a + ** measurable performance gain. + ** + ** This branch is taken even if aOffset[0]==0. Such a record is never + ** generated by SQLite, and could be considered corruption, but we + ** accept it for historical reasons. When aOffset[0]==0, the code this + ** branch jumps to reads past the end of the record, but never more + ** than a few bytes. Even if the record occurs at the end of the page + ** content area, the "page header" comes after the page content and so + ** this overread is harmless. Similar overreads can occur for a corrupt + ** database file. + */ + zData = pC->aRow; + assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + testcase( aOffset[0]==0 ); + goto op_column_read_header; } - - /* The following goto is an optimization. It can be omitted and - ** everything will still work. But OP_Column is measurably faster - ** by skipping the subsequent conditional, which is always true. - */ - assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ - goto op_column_read_header; } /* Make sure at least the first p2+1 entries of the header have been @@ -76197,24 +81650,24 @@ case OP_Column: { /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ - op_column_read_header: if( pC->iHdrOffsetaRow==0 ){ memset(&sMem, 0, sizeof(sMem)); - rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem); - if( rc!=SQLITE_OK ) goto op_column_error; + rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem); + if( rc!=SQLITE_OK ) goto abort_due_to_error; zData = (u8*)sMem.z; }else{ zData = pC->aRow; } /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ + op_column_read_header: i = pC->nHdrParsed; offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; - assert( i<=p2 && zHdr=zEndHdr ); do{ if( (t = zHdr[0])<0x80 ){ zHdr++; @@ -76226,10 +81679,7 @@ case OP_Column: { pC->aType[i++] = t; aOffset[i] = (u32)(offset64 & 0xffffffff); }while( i<=p2 && zHdrnHdrParsed = i; - pC->iHdrOffset = (u32)(zHdr - zData); - if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); - + /* The record is corrupt if any of the following are true: ** (1) the bytes of the header extend past the declared header size ** (2) the entire header was used but not all data was used @@ -76238,9 +81688,18 @@ case OP_Column: { if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize)) || (offset64 > pC->payloadSize) ){ - rc = SQLITE_CORRUPT_BKPT; - goto op_column_error; + if( aOffset[0]==0 ){ + i = 0; + zHdr = zEndHdr; + }else{ + if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); + goto op_column_corrupt; + } } + + pC->nHdrParsed = i; + pC->iHdrOffset = (u32)(zHdr - zData); + if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); }else{ t = 0; } @@ -76268,13 +81727,37 @@ case OP_Column: { assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); - if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); + if( VdbeMemDynamic(pDest) ){ + sqlite3VdbeMemSetNull(pDest); + } assert( t==pC->aType[p2] ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ - sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); + zData = pC->aRow + aOffset[p2]; + if( t<12 ){ + sqlite3VdbeSerialGet(zData, t, pDest); + }else{ + /* If the column value is a string, we need a persistent value, not + ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent + ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). + */ + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; + pDest->n = len = (t-12)/2; + pDest->enc = encoding; + if( pDest->szMalloc < len+2 ){ + pDest->flags = MEM_Null; + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + }else{ + pDest->z = pDest->zMalloc; + } + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = aFlag[t&1]; + } }else{ + pDest->enc = encoding; /* This branch happens only when content is on overflow pages */ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) @@ -76285,42 +81768,35 @@ case OP_Column: { ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. ** So we might as well use bogus content rather than reading - ** content from disk. NULL will work for the value for strings - ** and blobs and whatever is in the payloadSize64 variable - ** will work for everything else. */ - sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest); + ** content from disk. + ** + ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the + ** buffer passed to it, debugging function VdbeMemPrettyPrint() may + ** read up to 16. So 16 bytes of bogus content is supplied. + */ + static u8 aZero[16]; /* This is the bogus content */ + sqlite3VdbeSerialGet(aZero, t, pDest); }else{ - rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable, - pDest); - if( rc!=SQLITE_OK ){ - goto op_column_error; - } + rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest); + if( rc!=SQLITE_OK ) goto abort_due_to_error; sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); pDest->flags &= ~MEM_Ephem; } } - pDest->enc = encoding; op_column_out: - /* If the column value is an ephemeral string, go ahead and persist - ** that string in case the cursor moves before the column value is - ** used. The following code does the equivalent of Deephemeralize() - ** but does it faster. */ - if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){ - fx = pDest->flags & (MEM_Str|MEM_Blob); - assert( fx!=0 ); - zData = (const u8*)pDest->z; - len = pDest->n; - if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem; - memcpy(pDest->z, zData, len); - pDest->z[len] = 0; - pDest->z[len+1] = 0; - pDest->flags = fx|MEM_Term; - } -op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; + +op_column_corrupt: + if( aOp[0].p3>0 ){ + pOp = &aOp[aOp[0].p3-1]; + break; + }else{ + rc = SQLITE_CORRUPT_BKPT; + goto abort_due_to_error; + } } /* Opcode: Affinity P1 P2 * P4 * @@ -76328,24 +81804,24 @@ op_column_error: ** ** Apply affinities to a range of P2 registers starting with P1. ** -** P4 is a string that is P2 characters long. The nth character of the -** string indicates the column affinity that should be used for the nth +** P4 is a string that is P2 characters long. The N-th character of the +** string indicates the column affinity that should be used for the N-th ** memory cell in the range. */ case OP_Affinity: { const char *zAffinity; /* The affinity to be applied */ - char cAff; /* A single character of affinity */ zAffinity = pOp->p4.z; assert( zAffinity!=0 ); + assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; - while( (cAff = *(zAffinity++))!=0 ){ - assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] ); + do{ + assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); - applyAffinity(pIn1, cAff, encoding); + applyAffinity(pIn1, *(zAffinity++), encoding); pIn1++; - } + }while( zAffinity[0] ); break; } @@ -76356,8 +81832,8 @@ case OP_Affinity: { ** use as a data record in a database table or as a key ** in an index. The OP_Column opcode can decode the record later. ** -** P4 may be a string that is P2 characters long. The nth character of the -** string indicates the column affinity that should be used for the nth +** P4 may be a string that is P2 characters long. The N-th character of the +** string indicates the column affinity that should be used for the N-th ** field of the index key. ** ** The mapping from character to affinity is given by the SQLITE_AFF_ @@ -76403,7 +81879,7 @@ case OP_MakeRecord: { nZero = 0; /* Number of zero bytes at the end of the record */ nField = pOp->p1; zAffinity = pOp->p4.z; - assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 ); + assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 ); pData0 = &aMem[nField]; nField = pOp->p2; pLast = &pData0[nField-1]; @@ -76425,6 +81901,20 @@ case OP_MakeRecord: { }while( zAffinity[0] ); } +#ifdef SQLITE_ENABLE_NULL_TRIM + /* NULLs can be safely trimmed from the end of the record, as long as + ** as the schema format is 2 or more and none of the omitted columns + ** have a non-NULL default value. Also, the record must be left with + ** at least one field. If P5>0 then it will be one more than the + ** index of the right-most column with a non-NULL default value */ + if( pOp->p5 ){ + while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){ + pLast--; + nField--; + } + } +#endif + /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ @@ -76444,7 +81934,9 @@ case OP_MakeRecord: { testcase( serial_type==127 ); testcase( serial_type==128 ); nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); - }while( (--pRec)>=pData0 ); + if( pRec==pData0 ) break; + pRec--; + }while(1); /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint ** which determines the total number of bytes in the header. The varint @@ -76493,14 +81985,13 @@ case OP_MakeRecord: { assert( i==nHdr ); assert( j==nByte ); - assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); + 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; } - pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; @@ -76522,6 +82013,7 @@ case OP_Count: { /* out2 */ assert( pCrsr ); nEntry = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3BtreeCount(pCrsr, &nEntry); + if( rc ) goto abort_due_to_error; pOut = out2Prerelease(p, pOp); pOut->u.i = nEntry; break; @@ -76578,7 +82070,7 @@ case OP_Savepoint: { #endif /* Create a new savepoint structure. */ - pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1); + pNew = sqlite3DbMallocRawNN(db, sizeof(Savepoint)+nName+1); if( pNew ){ pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, zName, nName+1); @@ -76591,7 +82083,7 @@ case OP_Savepoint: { }else{ db->nSavepoint++; } - + /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; @@ -76645,7 +82137,7 @@ case OP_Savepoint: { int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ - isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; + isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0; for(ii=0; iinDb; ii++){ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT_ROLLBACK, @@ -76664,7 +82156,7 @@ case OP_Savepoint: { if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); - db->flags = (db->flags | SQLITE_InternChanges); + db->mDbFlags |= DBFLAG_SchemaChange; } } @@ -76699,6 +82191,7 @@ case OP_Savepoint: { } } } + if( rc ) goto abort_due_to_error; break; } @@ -76715,28 +82208,27 @@ case OP_Savepoint: { case OP_AutoCommit: { int desiredAutoCommit; int iRollback; - int turnOnAC; desiredAutoCommit = pOp->p1; iRollback = pOp->p2; - turnOnAC = desiredAutoCommit && !db->autoCommit; assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); assert( desiredAutoCommit==1 || iRollback==0 ); assert( db->nVdbeActive>0 ); /* At least this one VM is active */ assert( p->bIsReader ); - if( turnOnAC && !iRollback && db->nVdbeWrite>0 ){ - /* If this instruction implements a COMMIT and other VMs are writing - ** return an error indicating that the other VMs must complete first. - */ - sqlite3VdbeError(p, "cannot commit transaction - " - "SQL statements in progress"); - rc = SQLITE_BUSY; - }else if( desiredAutoCommit!=db->autoCommit ){ + if( desiredAutoCommit!=db->autoCommit ){ if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); db->autoCommit = 1; + }else if( desiredAutoCommit && db->nVdbeWrite>0 ){ + /* If this instruction implements a COMMIT and other VMs are writing + ** return an error indicating that the other VMs must complete first. + */ + sqlite3VdbeError(p, "cannot commit transaction - " + "SQL statements in progress"); + rc = SQLITE_BUSY; + goto abort_due_to_error; }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; }else{ @@ -76763,6 +82255,7 @@ case OP_AutoCommit: { "cannot commit - no transaction is active")); rc = SQLITE_ERROR; + goto abort_due_to_error; } break; } @@ -76820,12 +82313,12 @@ case OP_Transaction: { rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); testcase( rc==SQLITE_BUSY_SNAPSHOT ); testcase( rc==SQLITE_BUSY_RECOVERY ); - if( (rc&0xff)==SQLITE_BUSY ){ - p->pc = (int)(pOp - aOp); - p->rc = rc; - goto vdbe_return; - } if( rc!=SQLITE_OK ){ + if( (rc&0xff)==SQLITE_BUSY ){ + p->pc = (int)(pOp - aOp); + p->rc = rc; + goto vdbe_return; + } goto abort_due_to_error; } @@ -76852,10 +82345,9 @@ case OP_Transaction: { } /* Gather the schema version number for checking: - ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite - ** each time a query is executed to ensure that the internal cache of the - ** schema used when compiling the SQL query matches the schema of the - ** database against which the compiled query is actually executed. + ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema + ** version is checked to ensure that the schema has not changed since the + ** SQL statement was prepared. */ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); iGen = db->aDb[pOp->p1].pSchema->iGeneration; @@ -76885,6 +82377,7 @@ case OP_Transaction: { p->expired = 1; rc = SQLITE_SCHEMA; } + if( rc ) goto abort_due_to_error; break; } @@ -76921,15 +82414,15 @@ case OP_ReadCookie: { /* out2 */ /* Opcode: SetCookie P1 P2 P3 * * ** -** Write the content of register P3 (interpreted as an integer) -** into cookie number P2 of database P1. P2==1 is the schema version. -** P2==2 is the database format. P2==3 is the recommended pager cache +** Write the integer value P3 into cookie number P2 of database P1. +** P2==1 is the schema version. P2==2 is the database format. +** P2==3 is the recommended pager cache ** size, and so forth. P1==0 is the main database file and P1==1 is the ** database file used to store temporary tables. ** ** A transaction must be started before executing this opcode. */ -case OP_SetCookie: { /* in3 */ +case OP_SetCookie: { Db *pDb; assert( pOp->p2p1>=0 && pOp->p1nDb ); @@ -76938,17 +82431,15 @@ case OP_SetCookie: { /* in3 */ pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); - pIn3 = &aMem[pOp->p3]; - sqlite3VdbeMemIntegerify(pIn3); /* See note about index shifting on OP_ReadCookie */ - rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i); + rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3); if( pOp->p2==BTREE_SCHEMA_VERSION ){ /* When the schema cookie changes, record the new cookie internally */ - pDb->pSchema->schema_cookie = (int)pIn3->u.i; - db->flags |= SQLITE_InternChanges; + pDb->pSchema->schema_cookie = pOp->p3; + db->mDbFlags |= DBFLAG_SchemaChange; }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ - pDb->pSchema->file_format = (u8)pIn3->u.i; + pDb->pSchema->file_format = pOp->p3; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database @@ -76956,6 +82447,7 @@ case OP_SetCookie: { /* in3 */ sqlite3ExpirePreparedStatements(db); p->expired = 0; } + if( rc ) goto abort_due_to_error; break; } @@ -77053,7 +82545,7 @@ case OP_OpenWrite: if( p->expired ){ rc = SQLITE_ABORT_ROLLBACK; - break; + goto abort_due_to_error; } nField = 0; @@ -77077,26 +82569,23 @@ case OP_OpenWrite: } if( pOp->p5 & OPFLAG_P2ISREG ){ assert( p2>0 ); - assert( p2<=(p->nMem-p->nCursor) ); + assert( p2<=(p->nMem+1 - p->nCursor) ); pIn2 = &aMem[p2]; assert( memIsValid(pIn2) ); assert( (pIn2->flags & MEM_Int)!=0 ); sqlite3VdbeMemIntegerify(pIn2); p2 = (int)pIn2->u.i; - /* The p2 value always comes from a prior OP_CreateTable opcode and + /* The p2 value always comes from a prior OP_CreateBtree opcode and ** that opcode will always set the p2 value to 2 or more or else fail. ** If there were a failure, the prepared statement would have halted ** before reaching this instruction. */ - if( NEVER(p2<2) ) { - rc = SQLITE_CORRUPT_BKPT; - goto abort_due_to_error; - } + assert( p2>=2 ); } if( pOp->p4type==P4_KEYINFO ){ pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->enc==ENC(db) ); assert( pKeyInfo->db==db ); - nField = pKeyInfo->nField+pKeyInfo->nXField; + nField = pKeyInfo->nAllField; }else if( pOp->p4type==P4_INT32 ){ nField = pOp->p4.i; } @@ -77108,6 +82597,9 @@ case OP_OpenWrite: pCur->nullRow = 1; pCur->isOrdered = 1; pCur->pgnoRoot = p2; +#ifdef SQLITE_DEBUG + pCur->wrFlag = wrFlag; +#endif rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor); pCur->pKeyInfo = pKeyInfo; /* Set the VdbeCursor.isTable variable. Previous versions of @@ -77125,9 +82617,41 @@ open_cursor_set_hints: #endif sqlite3BtreeCursorHintFlags(pCur->uc.pCursor, (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); + if( rc ) goto abort_due_to_error; break; } +/* Opcode: OpenDup P1 P2 * * * +** +** Open a new cursor P1 that points to the same ephemeral table as +** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral +** opcode. Only ephemeral cursors may be duplicated. +** +** Duplicate ephemeral cursors are used for self-joins of materialized views. +*/ +case OP_OpenDup: { + VdbeCursor *pOrig; /* The original cursor to be duplicated */ + VdbeCursor *pCx; /* The new cursor */ + + pOrig = p->apCsr[pOp->p2]; + assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */ + + pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE); + if( pCx==0 ) goto no_mem; + pCx->nullRow = 1; + pCx->isEphemeral = 1; + pCx->pKeyInfo = pOrig->pKeyInfo; + pCx->isTable = pOrig->isTable; + rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, 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 + ** opcode is run, the sqlite3BtreeCursor() cannot fail */ + assert( rc==SQLITE_OK ); + break; +} + + /* Opcode: OpenEphemeral P1 P2 * P4 P5 ** Synopsis: nColumn=P2 ** @@ -77171,10 +82695,10 @@ case OP_OpenEphemeral: { if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->isEphemeral = 1; - rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pCx->pBt, 1); + rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1); } if( rc==SQLITE_OK ){ /* If a transient index is required, create it by calling @@ -77182,25 +82706,25 @@ case OP_OpenEphemeral: { ** opening it. If a transient table is required, just use the ** automatically created table with root-page 1 (an BLOB_INTKEY table). */ - if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ + if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ int pgno; assert( pOp->p4type==P4_KEYINFO ); - rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); + 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) ); - pCx->pKeyInfo = pKeyInfo; - rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR, + rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR, pKeyInfo, pCx->uc.pCursor); } pCx->isTable = 0; }else{ - rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR, + rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR, 0, pCx->uc.pCursor); pCx->isTable = 1; } } + if( rc ) goto abort_due_to_error; pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); break; } @@ -77226,6 +82750,7 @@ case OP_SorterOpen: { assert( pCx->pKeyInfo->db==db ); assert( pCx->pKeyInfo->enc==ENC(db) ); rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); + if( rc ) goto abort_due_to_error; break; } @@ -77271,8 +82796,13 @@ case OP_OpenPseudo: { pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; - pCx->uc.pseudoTableReg = pOp->p2; + pCx->seekResult = pOp->p2; pCx->isTable = 1; + /* Give this pseudo-cursor a fake BtCursor pointer so that pCx + ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test + ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto() + ** which is a performance optimization */ + pCx->uc.pCursor = sqlite3BtreeFakeValidCursor(); assert( pOp->p5==0 ); break; } @@ -77426,7 +82956,8 @@ case OP_SeekGT: { /* jump, in3 */ if( pC->isTable ){ /* The BTREE_SEEK_EQ flag is only set on index cursors */ - assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 ); + assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 + || CORRUPT_DB ); /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do @@ -77513,7 +83044,6 @@ case OP_SeekGT: { /* jump, in3 */ #ifdef SQLITE_DEBUG { int i; for(i=0; iuc.pCursor, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ @@ -77532,8 +83062,15 @@ case OP_SeekGT: { /* jump, in3 */ if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); if( res<0 || (res==0 && oc==OP_SeekGT) ){ res = 0; - rc = sqlite3BtreeNext(pC->uc.pCursor, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqlite3BtreeNext(pC->uc.pCursor, 0); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + res = 1; + }else{ + goto abort_due_to_error; + } + } }else{ res = 0; } @@ -77541,8 +83078,15 @@ case OP_SeekGT: { /* jump, in3 */ assert( oc==OP_SeekLT || oc==OP_SeekLE ); if( res>0 || (res==0 && oc==OP_SeekLT) ){ res = 0; - rc = sqlite3BtreePrevious(pC->uc.pCursor, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqlite3BtreePrevious(pC->uc.pCursor, 0); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + res = 1; + }else{ + goto abort_due_to_error; + } + } }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. @@ -77562,33 +83106,6 @@ seek_not_found: break; } -/* Opcode: Seek P1 P2 * * * -** Synopsis: intkey=r[P2] -** -** P1 is an open table cursor and P2 is a rowid integer. Arrange -** for P1 to move so that it points to the rowid given by P2. -** -** This is actually a deferred seek. Nothing actually happens until -** the cursor is used to read a record. That way, if no reads -** occur, no unnecessary I/O happens. -*/ -case OP_Seek: { /* in2 */ - VdbeCursor *pC; - - assert( pOp->p1>=0 && pOp->p1nCursor ); - pC = p->apCsr[pOp->p1]; - assert( pC!=0 ); - assert( pC->eCurType==CURTYPE_BTREE ); - assert( pC->uc.pCursor!=0 ); - assert( pC->isTable ); - pC->nullRow = 0; - pIn2 = &aMem[pOp->p2]; - pC->movetoTarget = sqlite3VdbeIntValue(pIn2); - pC->deferredMoveto = 1; - break; -} - - /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** @@ -77656,10 +83173,9 @@ case OP_Found: { /* jump, in3 */ int ii; VdbeCursor *pC; int res; - char *pFree; + UnpackedRecord *pFree; UnpackedRecord *pIdxKey; UnpackedRecord r; - char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*4 + 7]; #ifdef SQLITE_TEST if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++; @@ -77676,26 +83192,26 @@ case OP_Found: { /* jump, in3 */ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); - pFree = 0; if( pOp->p4.i>0 ){ r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; r.aMem = pIn3; +#ifdef SQLITE_DEBUG for(ii=0; iip3+ii, &r.aMem[ii]); -#endif } +#endif pIdxKey = &r; + pFree = 0; }else{ - pIdxKey = sqlite3VdbeAllocUnpackedRecord( - pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree - ); - if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); - ExpandBlob(pIn3); + rc = ExpandBlob(pIn3); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc ) goto no_mem; + pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); + if( pIdxKey==0 ) goto no_mem; sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; @@ -77712,9 +83228,9 @@ case OP_Found: { /* jump, in3 */ } } rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res); - sqlite3DbFree(db, pFree); + if( pFree ) sqlite3DbFreeNN(db, pFree); if( rc!=SQLITE_OK ){ - break; + goto abort_due_to_error; } pC->seekResult = res; alreadyExists = (res==0); @@ -77731,6 +83247,30 @@ case OP_Found: { /* jump, in3 */ break; } +/* Opcode: SeekRowid P1 P2 P3 * * +** Synopsis: intkey=r[P3] +** +** P1 is the index of a cursor open on an SQL table btree (with integer +** keys). If register P3 does not contain an integer or if P1 does not +** contain a record with rowid P3 then jump immediately to P2. +** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain +** a record with rowid P3 then +** leave the cursor pointing at that record and fall through to the next +** instruction. +** +** The OP_NotExists opcode performs the same operation, but with OP_NotExists +** the P3 register must be guaranteed to contain an integer value. With this +** opcode, register P3 might not contain an integer. +** +** The OP_NotFound opcode performs the same operation on index btrees +** (with arbitrary multi-value keys). +** +** This opcode leaves the cursor in a state where it cannot be advanced +** in either direction. In other words, the Next and Prev opcodes will +** not work following this opcode. +** +** See also: Found, NotFound, NoConflict, SeekRowid +*/ /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** @@ -77741,6 +83281,10 @@ case OP_Found: { /* jump, in3 */ ** leave the cursor pointing at that record and fall through to the next ** instruction. ** +** The OP_SeekRowid opcode performs the same operation but also allows the +** P3 register to contain a non-integer value, in which case the jump is +** always taken. This opcode requires that P3 always contain an integer. +** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** @@ -77748,14 +83292,21 @@ case OP_Found: { /* jump, in3 */ ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** -** See also: Found, NotFound, NoConflict +** See also: Found, NotFound, NoConflict, SeekRowid */ -case OP_NotExists: { /* jump, in3 */ +case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; + pIn3 = &aMem[pOp->p3]; + if( (pIn3->flags & MEM_Int)==0 ){ + applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); + if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; + } + /* Fall through into OP_NotExists */ +case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -77786,6 +83337,7 @@ case OP_NotExists: { /* jump, in3 */ goto jump_to_p2; } } + if( rc ) goto abort_due_to_error; break; } @@ -77873,8 +83425,7 @@ case OP_NewRowid: { /* out2 */ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); - rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v); - assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ + v = sqlite3BtreeIntegerKey(pC->uc.pCursor); if( v>=MAX_ROWID ){ pC->useRandomRowid = 1; }else{ @@ -77894,7 +83445,7 @@ case OP_NewRowid: { /* out2 */ pMem = &pFrame->aMem[pOp->p3]; }else{ /* Assert that P3 is a valid memory cell. */ - assert( pOp->p3<=(p->nMem-p->nCursor) ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pMem = &aMem[pOp->p3]; memAboutToChange(p, pMem); } @@ -77904,7 +83455,7 @@ case OP_NewRowid: { /* out2 */ sqlite3VdbeMemIntegerify(pMem); assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ - rc = SQLITE_FULL; /* IMP: R-12275-61338 */ + rc = SQLITE_FULL; /* IMP: R-17817-00630 */ goto abort_due_to_error; } if( vu.i+1 ){ @@ -77928,7 +83479,8 @@ case OP_NewRowid: { /* out2 */ 0, &res))==SQLITE_OK) && (res==0) && (++cnt<100)); - if( rc==SQLITE_OK && res==0 ){ + if( rc ) goto abort_due_to_error; + if( res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; } @@ -77955,22 +83507,19 @@ case OP_NewRowid: { /* out2 */ ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** -** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of -** the last seek operation (OP_NotExists) was a success, then this -** operation will not attempt to find the appropriate row before doing -** the insert but will instead overwrite the row that the cursor is -** currently pointing to. Presumably, the prior OP_NotExists opcode -** has already positioned the cursor correctly. This is an optimization -** that boosts performance by avoiding redundant seeks. +** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might +** run faster by avoiding an unnecessary seek on cursor P1. However, +** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior +** seeks on the cursor or if the most recent seek used a key equal to P3. ** ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an ** UPDATE operation. Otherwise (if the flag is clear) then this opcode ** is part of an INSERT operation. The difference is only important to ** the update hook. ** -** Parameter P4 may point to a string containing the table-name, or -** may be NULL. If it is not NULL, then the update-hook -** (sqlite3.xUpdateCallback) is invoked following a successful insert. +** Parameter P4 may point to a Table structure, or may be NULL. If it is +** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked +** following a successful insert. ** ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically ** allocated, then ownership of P2 is transferred to the pseudo-cursor @@ -77982,7 +83531,7 @@ case OP_NewRowid: { /* out2 */ ** for indices is OP_IdxInsert. */ /* Opcode: InsertInt P1 P2 P3 P4 P5 -** Synopsis: intkey=P3 data=r[P2] +** 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. @@ -77991,14 +83540,14 @@ case OP_Insert: case OP_InsertInt: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ - i64 iKey; /* The integer ROWID or key for the record to be inserted */ VdbeCursor *pC; /* Cursor to table into which insert is written */ - int nZero; /* Number of zero-bytes to append */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ - const char *zTbl; /* Table name - used by the opdate hook */ + Table *pTab; /* Table structure - used by update and pre-update hooks */ int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ + BtreePayload x; /* Payload to be inserted */ + op = 0; pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( memIsValid(pData) ); @@ -78006,7 +83555,8 @@ case OP_InsertInt: { assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); - assert( pC->isTable ); + assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); + assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); if( pOp->opcode==OP_Insert ){ @@ -78014,70 +83564,102 @@ case OP_InsertInt: { assert( pKey->flags & MEM_Int ); assert( memIsValid(pKey) ); REGISTER_TRACE(pOp->p3, pKey); - iKey = pKey->u.i; + x.nKey = pKey->u.i; }else{ assert( pOp->opcode==OP_InsertInt ); - iKey = pOp->p3; + x.nKey = pOp->p3; } - if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey; - if( pData->flags & MEM_Null ){ - pData->z = 0; - pData->n = 0; + if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ + assert( pC->iDb>=0 ); + zDb = db->aDb[pC->iDb].zDbSName; + pTab = pOp->p4.pTab; + assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) ); + op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); }else{ - assert( pData->flags & (MEM_Blob|MEM_Str) ); + pTab = 0; /* Not needed. Silence a compiler warning. */ + zDb = 0; /* Not needed. Silence a compiler warning. */ } + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + /* Invoke the pre-update hook, if any */ + if( db->xPreUpdateCallback + && pOp->p4type==P4_TABLE + && !(pOp->p5 & OPFLAG_ISUPDATE) + ){ + sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2); + } + if( pOp->p5 & OPFLAG_ISNOOP ) break; +#endif + + if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; + assert( pData->flags & (MEM_Blob|MEM_Str) ); + x.pData = pData->z; + x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ - nZero = pData->u.nZero; + x.nZero = pData->u.nZero; }else{ - nZero = 0; + x.nZero = 0; } - rc = sqlite3BtreeInsert(pC->uc.pCursor, 0, iKey, - pData->z, pData->n, nZero, - (pOp->p5 & OPFLAG_APPEND)!=0, seekResult + x.pKey = 0; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, + (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ - if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ - zDb = db->aDb[pC->iDb].zName; - zTbl = pOp->p4.z; - op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); - assert( pC->isTable ); - db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey); - assert( pC->iDb>=0 ); + if( rc ) goto abort_due_to_error; + if( db->xUpdateCallback && op ){ + db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey); } break; } -/* Opcode: Delete P1 P2 * P4 P5 +/* Opcode: Delete P1 P2 P3 P4 P5 ** ** Delete the record at which the P1 cursor is currently pointing. ** -** If the P5 parameter is non-zero, the cursor will be left pointing at -** either the next or the previous record in the table. If it is left -** pointing at the next record, then the next Next instruction will be a -** no-op. As a result, in this case it is OK to delete a record from within a -** Next loop. If P5 is zero, then the cursor is left in an undefined state. +** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then +** the cursor will be left pointing at either the next or the previous +** record in the table. If it is left pointing at the next record, then +** the next Next instruction will be a no-op. As a result, in this case +** it is ok to delete a record from within a Next loop. If +** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be +** left in an undefined state. ** -** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is -** incremented (otherwise not). +** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this +** delete one of several associated with deleting a table row and all its +** associated index entries. Exactly one of those deletes is the "primary" +** delete. The others are all on OPFLAG_FORDELETE cursors or else are +** marked with the AUXDELETE flag. +** +** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row +** change count is incremented (otherwise not). ** ** P1 must not be pseudo-table. It has to be a real table with ** multiple rows. ** -** If P4 is not NULL, then it is the name of the table that P1 is -** pointing to. The update hook will be invoked, if it exists. -** If P4 is not NULL then the P1 cursor must have been positioned -** using OP_NotFound prior to invoking this opcode. +** If P4 is not NULL then it points to a Table object. In this case either +** the update or pre-update hook, or both, may be invoked. The P1 cursor must +** have been positioned using OP_NotFound prior to invoking this opcode in +** this case. Specifically, if one is configured, the pre-update hook is +** invoked if P4 is not NULL. The update-hook is invoked if one is configured, +** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2. +** +** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address +** of the memory cell that contains the value that the rowid of the row will +** be set to by the update. */ case OP_Delete: { VdbeCursor *pC; - u8 hasUpdateCallback; + const char *zDb; + Table *pTab; + int opflags; + opflags = pOp->p2; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -78085,32 +83667,84 @@ case OP_Delete: { assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); - hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable; - if( pOp->p5 && hasUpdateCallback ){ - sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget); - } - #ifdef SQLITE_DEBUG - /* The seek operation that positioned the cursor prior to OP_Delete will - ** have also set the pC->movetoTarget field to the rowid of the row that - ** is being deleted */ - if( pOp->p4.z && pC->isTable && pOp->p5==0 ){ - i64 iKey = 0; - sqlite3BtreeKeySize(pC->uc.pCursor, &iKey); - assert( pC->movetoTarget==iKey ); + if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ + /* If p5 is zero, the seek operation that positioned the cursor prior to + ** 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 ); } #endif + + /* If the update-hook or pre-update-hook will be invoked, set zDb to + ** the name of the db to pass as to it. Also set local pTab to a copy + ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was + ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set + ** VdbeCursor.movetoTarget to the current rowid. */ + if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ + assert( pC->iDb>=0 ); + assert( pOp->p4.pTab!=0 ); + zDb = db->aDb[pC->iDb].zDbSName; + pTab = pOp->p4.pTab; + if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ + pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); + } + }else{ + zDb = 0; /* Not needed. Silence a compiler warning. */ + pTab = 0; /* Not needed. Silence a compiler warning. */ + } + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + /* Invoke the pre-update-hook if required. */ + if( db->xPreUpdateCallback && pOp->p4.pTab ){ + assert( !(opflags & OPFLAG_ISUPDATE) + || HasRowid(pTab)==0 + || (aMem[pOp->p3].flags & MEM_Int) + ); + sqlite3VdbePreUpdateHook(p, pC, + (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, + zDb, pTab, pC->movetoTarget, + pOp->p3 + ); + } + if( opflags & OPFLAG_ISNOOP ) break; +#endif + /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ + assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 ); + assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION ); + assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE ); + +#ifdef SQLITE_DEBUG + if( p->pFrame==0 ){ + if( pC->isEphemeral==0 + && (pOp->p5 & OPFLAG_AUXDELETE)==0 + && (pC->wrFlag & OPFLAG_FORDELETE)==0 + ){ + nExtraDelete++; + } + if( pOp->p2 & OPFLAG_NCHANGE ){ + nExtraDelete--; + } + } +#endif + rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5); pC->cacheStatus = CACHE_STALE; + pC->seekResult = 0; + if( rc ) goto abort_due_to_error; /* Invoke the update-hook if required. */ - if( rc==SQLITE_OK && hasUpdateCallback ){ - db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, - db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget); - assert( pC->iDb>=0 ); + if( opflags & OPFLAG_NCHANGE ){ + p->nChange++; + if( db->xUpdateCallback && HasRowid(pTab) ){ + db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, + pC->movetoTarget); + assert( pC->iDb>=0 ); + } } - if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; + break; } /* Opcode: ResetCount * * * * * @@ -78127,7 +83761,7 @@ case OP_ResetCount: { } /* Opcode: SorterCompare P1 P2 P3 P4 -** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 +** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the ** record blob in register P3 against a prefix of the entry that @@ -78154,6 +83788,7 @@ case OP_SorterCompare: { res = 0; rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); + if( rc ) goto abort_due_to_error; if( res ) goto jump_to_p2; break; }; @@ -78179,57 +83814,59 @@ case OP_SorterData: { rc = sqlite3VdbeSorterRowkey(pC, pOut); assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); assert( pOp->p1>=0 && pOp->p1nCursor ); + if( rc ) goto abort_due_to_error; p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } -/* Opcode: RowData P1 P2 * * * +/* Opcode: RowData P1 P2 P3 * * ** Synopsis: r[P2]=data ** -** Write into register P2 the complete row data for cursor P1. +** Write into register P2 the complete row content for the row at +** which cursor P1 is currently pointing. ** There is no interpretation of the data. ** It is just copied onto the P2 register exactly as ** it is found in the database file. ** -** If the P1 cursor must be pointing to a valid row (not a NULL row) -** of a real table, not a pseudo-table. -*/ -/* Opcode: RowKey P1 P2 * * * -** Synopsis: r[P2]=key -** -** Write into register P2 the complete row key for cursor P1. -** There is no interpretation of the data. -** The key is copied onto the P2 register exactly as -** it is found in the database file. +** If cursor P1 is an index, then the content is the key of the row. +** If cursor P2 is a table, then the content extracted is the data. ** ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. +** +** If P3!=0 then this opcode is allowed to make an ephermeral pointer +** into the database page. That means that the content of the output +** register will be invalidated as soon as the cursor moves - including +** moves caused by other cursors that "save" the the current cursors +** position in order that they can write to the same table. If P3==0 +** then a copy of the data is made into memory. P3!=0 is faster, but +** P3==0 is safer. +** +** If P3!=0 then the content of the P2 register is unsuitable for use +** in OP_Result and any OP_Result will invalidate the P2 register content. +** The P2 register content is invalidated by opcodes like OP_Function or +** by any use of another cursor pointing to the same table. */ -case OP_RowKey: case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; - i64 n64; - pOut = &aMem[pOp->p2]; - memAboutToChange(p, pOut); + pOut = out2Prerelease(p, pOp); - /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( isSorter(pC)==0 ); - assert( pC->isTable || pOp->opcode!=OP_RowData ); - assert( pC->isTable==0 || pOp->opcode==OP_RowData ); assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; - /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or - ** OP_Rewind/Op_Next with no intervening instructions that might invalidate - ** the cursor. If this where not the case, on of the following assert()s + /* The OP_RowData opcodes always follow OP_NotExists or + ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions + ** that might invalidate the cursor. + ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). @@ -78241,33 +83878,14 @@ case OP_RowData: { if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif - if( pC->isTable==0 ){ - assert( !pC->isTable ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64); - assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ - if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } - n = (u32)n64; - }else{ - VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n); - assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ - if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } + n = sqlite3BtreePayloadSize(pCrsr); + if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; } testcase( n==0 ); - if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ - goto no_mem; - } - pOut->n = n; - MemSetTypeFlag(pOut, MEM_Blob); - if( pC->isTable==0 ){ - rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z); - }else{ - rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z); - } - pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */ + rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut); + if( rc ) goto abort_due_to_error; + if( !pOp->p3 ) Deephemeralize(pOut); UPDATE_MAX_BLOBSIZE(pOut); REGISTER_TRACE(pOp->p2, pOut); break; @@ -78307,6 +83925,7 @@ case OP_Rowid: { /* out2 */ assert( pModule->xRowid ); rc = pModule->xRowid(pC->uc.pVCur, &v); sqlite3VtabImportErrmsg(p, pVtab); + if( rc ) goto abort_due_to_error; #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->eCurType==CURTYPE_BTREE ); @@ -78317,8 +83936,7 @@ case OP_Rowid: { /* out2 */ pOut->flags = MEM_Null; break; } - rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v); - assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ + v = sqlite3BtreeIntegerKey(pC->uc.pCursor); } pOut->u.i = v; break; @@ -78345,7 +83963,17 @@ case OP_NullRow: { break; } -/* Opcode: Last P1 P2 P3 * * +/* Opcode: SeekEnd P1 * * * * +** +** Position cursor P1 at the end of the btree for the purpose of +** appending a new entry onto the btree. +** +** It is assumed that the cursor is used only for appending and so +** if the cursor is valid, then the cursor must already be pointing +** at the end of the btree and so no changes are made to +** the cursor. +*/ +/* Opcode: Last P1 P2 * * * ** ** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. @@ -78357,6 +83985,7 @@ case OP_NullRow: { ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. */ +case OP_SeekEnd: case OP_Last: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; @@ -78369,14 +83998,21 @@ case OP_Last: { /* jump */ pCrsr = pC->uc.pCursor; res = 0; assert( pCrsr!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif + if( pOp->opcode==OP_SeekEnd ){ + assert( pOp->p2==0 ); + pC->seekResult = -1; + if( sqlite3BtreeCursorIsValidNN(pCrsr) ){ + break; + } + } rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; - pC->seekResult = pOp->p3; -#ifdef SQLITE_DEBUG - pC->seekOp = OP_Last; -#endif + if( rc ) goto abort_due_to_error; if( pOp->p2>0 ){ VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; @@ -78384,7 +84020,43 @@ case OP_Last: { /* jump */ break; } +/* Opcode: IfSmaller P1 P2 P3 * * +** +** Estimate the number of rows in the table P1. Jump to P2 if that +** estimate is less than approximately 2**(0.1*P3). +*/ +case OP_IfSmaller: { /* jump */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + i64 sz; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + pCrsr = pC->uc.pCursor; + assert( pCrsr ); + rc = sqlite3BtreeFirst(pCrsr, &res); + if( rc ) goto abort_due_to_error; + if( res==0 ){ + sz = sqlite3BtreeRowCountEst(pCrsr); + if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)p3 ) res = 1; + } + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; + break; +} + + +/* Opcode: SorterSort P1 P2 * * * +** +** After all records have been inserted into the Sorter object +** identified by P1, invoke this opcode to actually do the sorting. +** Jump to P2 if there are no records to be sorted. +** +** This opcode is an alias for OP_Sort and OP_Rewind that is used +** for Sorter objects. +*/ /* Opcode: Sort P1 P2 * * * ** ** This opcode does exactly the same thing as OP_Rewind except that @@ -78441,6 +84113,7 @@ case OP_Rewind: { /* jump */ pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } + if( rc ) goto abort_due_to_error; pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2nOp ); VdbeBranchTaken(res!=0,2); @@ -78511,14 +84184,19 @@ case OP_Rewind: { /* jump */ ** This opcode works just like Prev except that if cursor P1 is not ** open it behaves a no-op. */ +/* Opcode: SorterNext P1 P2 * * P5 +** +** This opcode works just like OP_Next except that P1 must be a +** sorter object for which the OP_SorterSort opcode has been +** invoked. This opcode advances the cursor to the next sorted +** record, or jumps to P2 if there are no more sorted records. +*/ case OP_SorterNext: { /* jump */ VdbeCursor *pC; - int res; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); - res = 0; - rc = sqlite3VdbeSorterNext(db, pC, &res); + rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; case OP_PrevIfOpen: /* jump */ case OP_NextIfOpen: /* jump */ @@ -78529,12 +84207,9 @@ case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5aCounter) ); pC = p->apCsr[pOp->p1]; - res = pOp->p3; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->eCurType==CURTYPE_BTREE ); - assert( res==0 || (res==1 && pC->isTable==0) ); - testcase( res==1 ); assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); @@ -78549,49 +84224,63 @@ case OP_Next: /* jump */ || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last ); - rc = pOp->p4.xAdvance(pC->uc.pCursor, &res); + rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3); next_tail: pC->cacheStatus = CACHE_STALE; - VdbeBranchTaken(res==0,2); - if( res==0 ){ + VdbeBranchTaken(rc==SQLITE_OK,2); + if( rc==SQLITE_OK ){ pC->nullRow = 0; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif goto jump_to_p2_and_check_for_interrupt; - }else{ - pC->nullRow = 1; } + if( rc!=SQLITE_DONE ) goto abort_due_to_error; + rc = SQLITE_OK; + pC->nullRow = 1; goto check_for_interrupt; } -/* Opcode: IdxInsert P1 P2 P3 * P5 +/* Opcode: IdxInsert P1 P2 P3 P4 P5 ** Synopsis: key=r[P2] ** ** Register P2 holds an SQL index key made using the ** MakeRecord instructions. This opcode writes that key ** into the index P1. Data for the entry is nil. ** -** P3 is a flag that provides a hint to the b-tree layer that this -** insert is likely to be an append. +** If P4 is not zero, then it is the number of values in the unpacked +** key of reg(P2). In that case, P3 is the index of the first register +** for the unpacked key. The availability of the unpacked key can sometimes +** be an optimization. +** +** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer +** that this insert is likely to be an append. ** ** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is ** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear, ** then the change counter is unchanged. ** -** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have -** just done a seek to the spot where the new entry is to be inserted. -** This flag avoids doing an extra seek. +** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might +** run faster by avoiding an unnecessary seek on cursor P1. However, +** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior +** seeks on the cursor or if the most recent seek used a key equivalent +** to P2. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ +/* Opcode: SorterInsert P1 P2 * * * +** Synopsis: key=r[P2] +** +** Register P2 holds an SQL index key made using the +** MakeRecord instructions. This opcode writes that key +** into the sorter P1. Data for the entry is nil. +*/ case OP_SorterInsert: /* in2 */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; - int nKey; - const char *zKey; + BtreePayload x; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; @@ -78603,19 +84292,22 @@ case OP_IdxInsert: { /* in2 */ assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); - if( rc==SQLITE_OK ){ - if( pOp->opcode==OP_SorterInsert ){ - rc = sqlite3VdbeSorterWrite(pC, pIn2); - }else{ - nKey = pIn2->n; - zKey = pIn2->z; - rc = sqlite3BtreeInsert(pC->uc.pCursor, zKey, nKey, "", 0, 0, pOp->p3, - ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) - ); - assert( pC->deferredMoveto==0 ); - pC->cacheStatus = CACHE_STALE; - } + if( rc ) goto abort_due_to_error; + if( pOp->opcode==OP_SorterInsert ){ + rc = sqlite3VdbeSorterWrite(pC, pIn2); + }else{ + x.nKey = pIn2->n; + x.pKey = pIn2->z; + x.aMem = aMem + pOp->p3; + x.nMem = (u16)pOp->p4.i; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, + (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), + ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) + ); + assert( pC->deferredMoveto==0 ); + pC->cacheStatus = CACHE_STALE; } + if( rc) goto abort_due_to_error; break; } @@ -78633,7 +84325,7 @@ case OP_IdxDelete: { UnpackedRecord r; assert( pOp->p3>0 ); - assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 ); + assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 ); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -78645,18 +84337,37 @@ case OP_IdxDelete: { r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; -#ifdef SQLITE_DEBUG - { int i; for(i=0; ideferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; + pC->seekResult = 0; break; } +/* Opcode: DeferredSeek P1 * P3 P4 * +** Synopsis: Move P3 to P1.rowid if needed +** +** P1 is an open index cursor and P3 is a cursor on the corresponding +** table. This opcode does a deferred seek of the P3 table cursor +** to the row that corresponds to the current row of P1. +** +** This is a deferred seek. Nothing actually happens until +** the cursor is used to read a record. That way, if no reads +** occur, no unnecessary I/O happens. +** +** P4 may be an array of integers (type P4_INTARRAY) containing +** one entry for each column in the P3 table. If array entry a(i) +** is non-zero, then reading column a(i)-1 from cursor P3 is +** equivalent to performing the deferred seek and then reading column i +** from P1. This information is stored in P3 and used to redirect +** reads against P3 over to P1, thus possibly avoiding the need to +** seek and read cursor P3. +*/ /* Opcode: IdxRowid P1 P2 * * * ** Synopsis: r[P2]=rowid ** @@ -78666,37 +84377,56 @@ case OP_IdxDelete: { ** ** See also: Rowid, MakeRecord. */ -case OP_IdxRowid: { /* out2 */ - BtCursor *pCrsr; - VdbeCursor *pC; - i64 rowid; +case OP_DeferredSeek: +case OP_IdxRowid: { /* out2 */ + VdbeCursor *pC; /* The P1 index cursor */ + VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */ + i64 rowid; /* Rowid that P1 current points to */ - pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); - pCrsr = pC->uc.pCursor; - assert( pCrsr!=0 ); - pOut->flags = MEM_Null; + assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); assert( pC->deferredMoveto==0 ); + assert( !pC->nullRow || pOp->opcode==OP_IdxRowid ); + + /* The IdxRowid and Seek opcodes are combined because of the commonality + ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */ + rc = sqlite3VdbeCursorRestore(pC); /* sqlite3VbeCursorRestore() can only fail if the record has been deleted - ** out from under the cursor. That will never happend for an IdxRowid - ** opcode, hence the NEVER() arround the check of the return value. - */ - rc = sqlite3VdbeCursorRestore(pC); + ** out from under the cursor. That will never happens for an IdxRowid + ** or Seek opcode */ if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; if( !pC->nullRow ){ rowid = 0; /* Not needed. Only used to silence a warning. */ - rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid); + rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - pOut->u.i = rowid; - pOut->flags = MEM_Int; + if( pOp->opcode==OP_DeferredSeek ){ + assert( pOp->p3>=0 && pOp->p3nCursor ); + pTabCur = p->apCsr[pOp->p3]; + assert( pTabCur!=0 ); + assert( pTabCur->eCurType==CURTYPE_BTREE ); + assert( pTabCur->uc.pCursor!=0 ); + assert( pTabCur->isTable ); + pTabCur->nullRow = 0; + pTabCur->movetoTarget = rowid; + pTabCur->deferredMoveto = 1; + assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); + pTabCur->aAltMap = pOp->p4.ai; + pTabCur->pAltCursor = pC; + }else{ + pOut = out2Prerelease(p, pOp); + pOut->u.i = rowid; + } + }else{ + assert( pOp->opcode==OP_IdxRowid ); + sqlite3VdbeMemSetNull(&aMem[pOp->p2]); } break; } @@ -78786,6 +84516,7 @@ case OP_IdxGE: { /* jump */ res++; } VdbeBranchTaken(res>0,2); + if( rc ) goto abort_due_to_error; if( res>0 ) goto jump_to_p2; break; } @@ -78803,10 +84534,17 @@ case OP_IdxGE: { /* jump */ ** might be moved into the newly deleted root page in order to keep all ** root pages contiguous at the beginning of the database. The former ** value of the root page that moved - its value before the move occurred - -** is stored in register P2. If no page -** movement was required (because the table being dropped was already -** the last one in the database) then a zero is stored in register P2. -** If AUTOVACUUM is disabled then a zero is stored in register P2. +** is stored in register P2. If no page movement was required (because the +** table being dropped was already the last one in the database) then a +** zero is stored in register P2. If AUTOVACUUM is disabled then a zero +** is stored in register P2. +** +** This opcode throws an error if there are any active reader VMs when +** it is invoked. This is done to avoid the difficulty associated with +** updating existing cursors when a root page is moved in an AUTOVACUUM +** database. This error is thrown even if the database is not an AUTOVACUUM +** db in order to avoid introducing an incompatibility between autovacuum +** and non-autovacuum modes. ** ** See also: Clear */ @@ -78815,11 +84553,13 @@ case OP_Destroy: { /* out2 */ int iDb; assert( p->readOnly==0 ); + assert( pOp->p1>1 ); pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Null; if( db->nVdbeRead > db->nVDestroy+1 ){ rc = SQLITE_LOCKED; p->errorAction = OE_Abort; + goto abort_due_to_error; }else{ iDb = pOp->p3; assert( DbMaskTest(p->btreeMask, iDb) ); @@ -78827,8 +84567,9 @@ case OP_Destroy: { /* out2 */ rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); pOut->flags = MEM_Int; pOut->u.i = iMoved; + if( rc ) goto abort_due_to_error; #ifndef SQLITE_OMIT_AUTOVACUUM - if( rc==SQLITE_OK && iMoved!=0 ){ + if( iMoved!=0 ){ sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1); /* All OP_Destroy operations occur on the same btree */ assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 ); @@ -78874,6 +84615,7 @@ case OP_Clear: { aMem[pOp->p3].u.i += nChange; } } + if( rc ) goto abort_due_to_error; break; } @@ -78897,58 +84639,50 @@ case OP_ResetSorter: { assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->isEphemeral ); rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor); + if( rc ) goto abort_due_to_error; } break; } -/* Opcode: CreateTable P1 P2 * * * -** Synopsis: r[P2]=root iDb=P1 +/* Opcode: CreateBtree P1 P2 P3 * * +** Synopsis: r[P2]=root iDb=P1 flags=P3 ** -** Allocate a new table in the main database file if P1==0 or in the -** auxiliary database file if P1==1 or in an attached database if -** P1>1. Write the root page number of the new table into -** register P2 -** -** The difference between a table and an index is this: A table must -** have a 4-byte integer key and can have arbitrary data. An index -** has an arbitrary key but no data. -** -** See also: CreateIndex +** Allocate a new b-tree in the main database file if P1==0 or in the +** TEMP database file if P1==1 or in an attached database if +** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table +** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table. +** The root page number of the new b-tree is stored in register P2. */ -/* Opcode: CreateIndex P1 P2 * * * -** Synopsis: r[P2]=root iDb=P1 -** -** Allocate a new index in the main database file if P1==0 or in the -** auxiliary database file if P1==1 or in an attached database if -** P1>1. Write the root page number of the new table into -** register P2. -** -** See documentation on OP_CreateTable for additional information. -*/ -case OP_CreateIndex: /* out2 */ -case OP_CreateTable: { /* out2 */ +case OP_CreateBtree: { /* out2 */ int pgno; - int flags; Db *pDb; pOut = out2Prerelease(p, pOp); pgno = 0; + assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); - if( pOp->opcode==OP_CreateTable ){ - /* flags = BTREE_INTKEY; */ - flags = BTREE_INTKEY; - }else{ - flags = BTREE_BLOBKEY; - } - rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); + rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3); + if( rc ) goto abort_due_to_error; pOut->u.i = pgno; break; } +/* Opcode: SqlExec * * * P4 * +** +** Run the SQL statement or statements specified in the P4 string. +*/ +case OP_SqlExec: { + db->nSqlExec++; + rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); + db->nSqlExec--; + if( rc ) goto abort_due_to_error; + break; +} + /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the SQLITE_MASTER table of database P1 @@ -78977,15 +84711,15 @@ case OP_ParseSchema: { assert( iDb>=0 && iDbnDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); /* Used to be a conditional */ { - zMaster = SCHEMA_TABLE(iDb); + zMaster = MASTER_NAME; initData.db = db; initData.iDb = pOp->p1; initData.pzErrMsg = &p->zErrMsg; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", - db->aDb[iDb].zName, zMaster, pOp->p4.z); + db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); if( zSql==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); db->init.busy = 1; @@ -78993,13 +84727,16 @@ case OP_ParseSchema: { assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_OK ) rc = initData.rc; - sqlite3DbFree(db, zSql); + sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } } - if( rc ) sqlite3ResetAllSchemasOfConnection(db); - if( rc==SQLITE_NOMEM ){ - goto no_mem; + if( rc ){ + sqlite3ResetAllSchemasOfConnection(db); + if( rc==SQLITE_NOMEM ){ + goto no_mem; + } + goto abort_due_to_error; } break; } @@ -79014,6 +84751,7 @@ case OP_ParseSchema: { case OP_LoadAnalysis: { assert( pOp->p1>=0 && pOp->p1nDb ); rc = sqlite3AnalysisLoad(db, pOp->p1); + if( rc ) goto abort_due_to_error; break; } #endif /* !defined(SQLITE_OMIT_ANALYZE) */ @@ -79059,20 +84797,19 @@ case OP_DropTrigger: { #ifndef SQLITE_OMIT_INTEGRITY_CHECK -/* Opcode: IntegrityCk P1 P2 P3 * P5 +/* Opcode: IntegrityCk P1 P2 P3 P4 P5 ** ** Do an analysis of the currently open database. Store in ** register P1 the text of an error message describing any problems. ** If no problems are found, store a NULL in register P1. ** -** The register P3 contains the maximum number of allowed errors. +** The register P3 contains one less than the maximum number of allowed errors. ** At most reg(P3) errors will be reported. ** In other words, the analysis stops as soon as reg(P1) errors are ** seen. Reg(P1) is updated with the number of errors remaining. ** -** The root page numbers of all tables in the database are integer -** stored in reg(P1), reg(P1+1), reg(P1+2), .... There are P2 tables -** total. +** The root page numbers of all tables in the database are integers +** stored in P4_INTARRAY argument. ** ** If P5 is not zero, the check is done on the auxiliary database ** file, not the main database file. @@ -79082,37 +84819,31 @@ case OP_DropTrigger: { case OP_IntegrityCk: { int nRoot; /* Number of tables to check. (Number of root pages.) */ int *aRoot; /* Array of rootpage numbers for tables to be checked */ - int j; /* Loop counter */ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ assert( p->bIsReader ); nRoot = pOp->p2; + aRoot = pOp->p4.ai; assert( nRoot>0 ); - aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) ); - if( aRoot==0 ) goto no_mem; - assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); + assert( aRoot[0]==nRoot ); + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); pIn1 = &aMem[pOp->p1]; - for(j=0; jp5nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); - z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, - (int)pnErr->u.i, &nErr); - sqlite3DbFree(db, aRoot); - pnErr->u.i -= nErr; + z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, + (int)pnErr->u.i+1, &nErr); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); }else if( z==0 ){ goto no_mem; }else{ + pnErr->u.i -= nErr-1; sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); } UPDATE_MAX_BLOBSIZE(pIn1); @@ -79122,9 +84853,9 @@ case OP_IntegrityCk: { #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* Opcode: RowSetAdd P1 P2 * * * -** Synopsis: rowset(P1)=r[P2] +** Synopsis: rowset(P1)=r[P2] ** -** Insert the integer value held by register P2 into a boolean index +** Insert the integer value held by register P2 into a RowSet object ** held in register P1. ** ** An assertion fails if P2 is not an integer. @@ -79142,10 +84873,11 @@ case OP_RowSetAdd: { /* in1, in2 */ } /* Opcode: RowSetRead P1 P2 P3 * * -** Synopsis: r[P3]=rowset(P1) +** Synopsis: r[P3]=rowset(P1) ** -** Extract the smallest value from boolean index P1 and put that value into -** register P3. Or, if boolean index P1 is initially empty, leave P3 +** Extract the smallest value from the RowSet object in P1 +** and put that value into register P3. +** Or, if RowSet object P1 is initially empty, leave P3 ** unchanged and jump to instruction P2. */ case OP_RowSetRead: { /* jump, in1, out3 */ @@ -79176,15 +84908,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */ ** integer in P3 into the RowSet and continue on to the ** next opcode. ** -** The RowSet object is optimized for the case where successive sets -** of integers, where each set contains no duplicates. Each set -** of values is identified by a unique P4 value. The first set -** must have P4==0, the final set P4=-1. P4 must be either -1 or -** non-negative. For non-negative values of P4 only the lower 4 -** bits are significant. +** The RowSet object is optimized for the case where sets of integers +** are inserted in distinct phases, which each set contains no duplicates. +** Each set is identified by a unique P4 value. The first set +** must have P4==0, the final set must have P4==-1, and for all other sets +** must have P4>0. ** ** This allows optimizations: (a) when P4==0 there is no need to test -** the rowset object for P3, as it is guaranteed not to contain it, +** the RowSet object for P3, as it is guaranteed not to contain it, ** (b) when P4==-1 there is no need to insert the value, as it will ** never be tested for, and (c) when a value that is part of set X is ** inserted, there is no need to search to see if the same value was @@ -79273,7 +85004,7 @@ case OP_Program: { /* jump */ if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "too many levels of trigger recursion"); - break; + goto abort_due_to_error; } /* Register pRt is used to store the memory required to save the state @@ -79287,10 +85018,12 @@ case OP_Program: { /* jump */ ** variable nMem (and later, VdbeFrame.nChildMem) to this value. */ nMem = pProgram->nMem + pProgram->nCsr; + assert( nMem>0 ); + if( pProgram->nCsr==0 ) nMem++; nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) - + pProgram->nCsr * sizeof(VdbeCursor *) - + pProgram->nOnce * sizeof(u8); + + pProgram->nCsr * sizeof(VdbeCursor*) + + (pProgram->nOp + 7)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; @@ -79310,8 +85043,6 @@ case OP_Program: { /* jump */ pFrame->aOp = p->aOp; pFrame->nOp = p->nOp; pFrame->token = pProgram->token; - pFrame->aOnceFlag = p->aOnceFlag; - pFrame->nOnceFlag = p->nOnceFlag; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; #endif @@ -79323,31 +85054,34 @@ case OP_Program: { /* jump */ } }else{ pFrame = pRt->u.pFrame; - assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem ); + assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem + || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); assert( pProgram->nCsr==pFrame->nChildCsr ); assert( (int)(pOp - aOp)==pFrame->pc ); } p->nFrame++; pFrame->pParent = p->pFrame; - pFrame->lastRowid = lastRowid; + pFrame->lastRowid = db->lastRowid; pFrame->nChange = p->nChange; pFrame->nDbChange = p->db->nChange; + assert( pFrame->pAuxData==0 ); + pFrame->pAuxData = p->pAuxData; + p->pAuxData = 0; p->nChange = 0; p->pFrame = pFrame; - p->aMem = aMem = &VdbeFrameMem(pFrame)[-1]; + p->aMem = aMem = VdbeFrameMem(pFrame); p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; - p->apCsr = (VdbeCursor **)&aMem[p->nMem+1]; + p->apCsr = (VdbeCursor **)&aMem[p->nMem]; + pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr]; + memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8); p->aOp = aOp = pProgram->aOp; p->nOp = pProgram->nOp; - p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; - p->nOnceFlag = pProgram->nOnce; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; #endif pOp = &aOp[-1]; - memset(p->aOnceFlag, 0, p->nOnceFlag); break; } @@ -79472,37 +85206,61 @@ case OP_IfPos: { /* jump, in1 */ break; } -/* Opcode: SetIfNotPos P1 P2 P3 * * -** Synopsis: if r[P1]<=0 then r[P2]=P3 +/* Opcode: OffsetLimit P1 P2 P3 * * +** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) ** -** Register P1 must contain an integer. -** If the value of register P1 is not positive (if it is less than 1) then -** set the value of register P2 to be the integer P3. +** This opcode performs a commonly used computation associated with +** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3] +** holds the offset counter. The opcode computes the combined value +** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2] +** value computed is the total number of rows that will need to be +** visited in order to complete the query. +** +** If r[P3] is zero or negative, that means there is no OFFSET +** and r[P2] is set to be the value of the LIMIT, r[P1]. +** +** if r[P1] is zero or negative, that means there is no LIMIT +** and r[P2] is set to -1. +** +** Otherwise, r[P2] is set to the sum of r[P1] and r[P3]. */ -case OP_SetIfNotPos: { /* in1, in2 */ +case OP_OffsetLimit: { /* in1, out2, in3 */ + i64 x; pIn1 = &aMem[pOp->p1]; - assert( pIn1->flags&MEM_Int ); - if( pIn1->u.i<=0 ){ - pOut = out2Prerelease(p, pOp); - pOut->u.i = pOp->p3; + pIn3 = &aMem[pOp->p3]; + pOut = out2Prerelease(p, pOp); + assert( pIn1->flags & MEM_Int ); + assert( pIn3->flags & MEM_Int ); + x = pIn1->u.i; + if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){ + /* If the LIMIT is less than or equal to zero, loop forever. This + ** is documented. But also, if the LIMIT+OFFSET exceeds 2^63 then + ** also loop forever. This is undocumented. In fact, one could argue + ** that the loop should terminate. But assuming 1 billion iterations + ** per second (far exceeding the capabilities of any current hardware) + ** it would take nearly 300 years to actually reach the limit. So + ** looping forever is a reasonable approximation. */ + pOut->u.i = -1; + }else{ + pOut->u.i = x; } break; } -/* Opcode: IfNotZero P1 P2 P3 * * -** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 +/* Opcode: IfNotZero P1 P2 * * * +** Synopsis: if r[P1]!=0 then r[P1]--, goto P2 ** ** Register P1 must contain an integer. If the content of register P1 is -** initially nonzero, then subtract P3 from the value in register P1 and -** jump to P2. If register P1 is initially zero, leave it unchanged -** and fall through. +** initially greater than zero, then decrement the value in register P1. +** If it is non-zero (negative or positive) and then also jump to P2. +** If register P1 is initially zero, leave it unchanged and fall through. */ case OP_IfNotZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i ){ - pIn1->u.i -= pOp->p3; + if( pIn1->u.i>0 ) pIn1->u.i--; goto jump_to_p2; } break; @@ -79511,34 +85269,19 @@ case OP_IfNotZero: { /* jump, in1 */ /* Opcode: DecrJumpZero P1 P2 * * * ** Synopsis: if (--r[P1])==0 goto P2 ** -** Register P1 must hold an integer. Decrement the value in register P1 -** then jump to P2 if the new value is exactly zero. +** Register P1 must hold an integer. Decrement the value in P1 +** and jump to P2 if the new value is exactly zero. */ case OP_DecrJumpZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - pIn1->u.i--; + if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; VdbeBranchTaken(pIn1->u.i==0, 2); if( pIn1->u.i==0 ) goto jump_to_p2; break; } -/* Opcode: JumpZeroIncr P1 P2 * * * -** Synopsis: if (r[P1]++)==0 ) goto P2 -** -** The register P1 must contain an integer. If register P1 is initially -** zero, then jump to P2. Increment register P1 regardless of whether or -** not the jump is taken. -*/ -case OP_JumpZeroIncr: { /* jump, in1 */ - pIn1 = &aMem[pOp->p1]; - assert( pIn1->flags&MEM_Int ); - VdbeBranchTaken(pIn1->u.i==0, 2); - if( (pIn1->u.i++)==0 ) goto jump_to_p2; - break; -} - /* Opcode: AggStep0 * P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** @@ -79573,10 +85316,10 @@ case OP_AggStep0: { assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; - assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); - assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) ); + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); - pCtx = sqlite3DbMallocRaw(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); + pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); if( pCtx==0 ) goto no_mem; pCtx->pMem = 0; pCtx->pFunc = pOp->p4.pFunc; @@ -79619,13 +85362,14 @@ case OP_AggStep: { pCtx->pOut = &t; pCtx->fErrorOrAux = 0; pCtx->skipFlag = 0; - (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ + (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ if( pCtx->fErrorOrAux ){ if( pCtx->isError ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(&t)); rc = pCtx->isError; } sqlite3VdbeMemRelease(&t); + if( rc ) goto abort_due_to_error; }else{ assert( t.flags==MEM_Null ); } @@ -79652,12 +85396,13 @@ case OP_AggStep: { */ case OP_AggFinal: { Mem *pMem; - assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) ); + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); + goto abort_due_to_error; } sqlite3VdbeChangeEncoding(pMem, encoding); UPDATE_MAX_BLOBSIZE(pMem); @@ -79693,7 +85438,8 @@ case OP_Checkpoint: { || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE ); rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]); - if( rc==SQLITE_BUSY ){ + if( rc ){ + if( rc!=SQLITE_BUSY ) goto abort_due_to_error; rc = SQLITE_OK; aRes[0] = 1; } @@ -79766,7 +85512,7 @@ case OP_JournalMode: { /* out2 */ "cannot change %s wal mode from within a transaction", (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") ); - break; + goto abort_due_to_error; }else{ if( eOld==PAGER_JOURNALMODE_WAL ){ @@ -79775,7 +85521,7 @@ case OP_JournalMode: { /* out2 */ ** file. An EXCLUSIVE lock may still be held on the database file ** after a successful return. */ - rc = sqlite3PagerCloseWal(pPager); + rc = sqlite3PagerCloseWal(pPager, db); if( rc==SQLITE_OK ){ sqlite3PagerSetJournalMode(pPager, eNew); } @@ -79796,9 +85542,7 @@ case OP_JournalMode: { /* out2 */ } #endif /* ifndef SQLITE_OMIT_WAL */ - if( rc ){ - eNew = eOld; - } + if( rc ) eNew = eOld; eNew = sqlite3PagerSetJournalMode(pPager, eNew); pOut->flags = MEM_Str|MEM_Static|MEM_Term; @@ -79806,20 +85550,21 @@ case OP_JournalMode: { /* out2 */ pOut->n = sqlite3Strlen30(pOut->z); pOut->enc = SQLITE_UTF8; sqlite3VdbeChangeEncoding(pOut, encoding); + if( rc ) goto abort_due_to_error; break; }; #endif /* SQLITE_OMIT_PRAGMA */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* Opcode: Vacuum * * * * * +/* Opcode: Vacuum P1 * * * * ** -** Vacuum the entire database. This opcode will cause other virtual -** machines to be created and run. It may not be called from within -** a transaction. +** 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. */ case OP_Vacuum: { assert( p->readOnly==0 ); - rc = sqlite3RunVacuum(&p->zErrMsg, db); + rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1); + if( rc ) goto abort_due_to_error; break; } #endif @@ -79840,7 +85585,8 @@ case OP_IncrVacuum: { /* jump */ pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); VdbeBranchTaken(rc==SQLITE_DONE,2); - if( rc==SQLITE_DONE ){ + if( rc ){ + if( rc!=SQLITE_DONE ) goto abort_due_to_error; rc = SQLITE_OK; goto jump_to_p2; } @@ -79885,15 +85631,18 @@ case OP_Expire: { */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; - if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ + if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){ int p1 = pOp->p1; assert( p1>=0 && p1nDb ); assert( DbMaskTest(p->btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); - if( (rc&0xFF)==SQLITE_LOCKED ){ - const char *z = pOp->p4.z; - sqlite3VdbeError(p, "database table is locked: %s", z); + if( rc ){ + if( (rc&0xFF)==SQLITE_LOCKED ){ + const char *z = pOp->p4.z; + sqlite3VdbeError(p, "database table is locked: %s", z); + } + goto abort_due_to_error; } } break; @@ -79915,6 +85664,7 @@ case OP_VBegin: { pVTab = pOp->p4.pVtab; rc = sqlite3VtabBegin(db, pVTab); if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab); + if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -79943,6 +85693,7 @@ case OP_VCreate: { rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg); } sqlite3VdbeMemRelease(&sMem); + if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -79957,6 +85708,7 @@ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; + if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -79980,25 +85732,25 @@ case OP_VOpen: { pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; - break; + goto abort_due_to_error; } pModule = pVtab->pModule; rc = pModule->xOpen(pVtab, &pVCur); sqlite3VtabImportErrmsg(p, pVtab); - if( SQLITE_OK==rc ){ - /* Initialize sqlite3_vtab_cursor base class */ - pVCur->pVtab = pVtab; + if( rc ) goto abort_due_to_error; - /* Initialize vdbe cursor object */ - pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB); - if( pCur ){ - pCur->uc.pVCur = pVCur; - pVtab->nRef++; - }else{ - assert( db->mallocFailed ); - pModule->xClose(pVCur); - goto no_mem; - } + /* Initialize sqlite3_vtab_cursor base class */ + pVCur->pVtab = pVtab; + + /* Initialize vdbe cursor object */ + pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB); + if( pCur ){ + pCur->uc.pVCur = pVCur; + pVtab->nRef++; + }else{ + assert( db->mallocFailed ); + pModule->xClose(pVCur); + goto no_mem; } break; } @@ -80060,9 +85812,8 @@ case OP_VFilter: { /* jump */ } rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg); sqlite3VtabImportErrmsg(p, pVtab); - if( rc==SQLITE_OK ){ - res = pModule->xEof(pVCur); - } + if( rc ) goto abort_due_to_error; + res = pModule->xEof(pVCur); pCur->nullRow = 0; VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; @@ -80086,7 +85837,7 @@ case OP_VColumn: { VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur->eCurType==CURTYPE_VTAB ); - assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); if( pCur->nullRow ){ @@ -80111,6 +85862,7 @@ case OP_VColumn: { if( sqlite3VdbeMemTooBig(pDest) ){ goto too_big; } + if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -80146,9 +85898,8 @@ case OP_VNext: { /* jump */ */ rc = pModule->xNext(pCur->uc.pVCur); sqlite3VtabImportErrmsg(p, pVtab); - if( rc==SQLITE_OK ){ - res = pModule->xEof(pCur->uc.pVCur); - } + if( rc ) goto abort_due_to_error; + res = pModule->xEof(pCur->uc.pVCur); VdbeBranchTaken(!res,2); if( !res ){ /* If there is data, jump to P2 */ @@ -80180,11 +85931,11 @@ case OP_VRename: { testcase( pName->enc==SQLITE_UTF16BE ); testcase( pName->enc==SQLITE_UTF16LE ); rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); - if( rc==SQLITE_OK ){ - rc = pVtab->pModule->xRename(pVtab, pName->z); - sqlite3VtabImportErrmsg(p, pVtab); - p->expired = 0; - } + if( rc ) goto abort_due_to_error; + rc = pVtab->pModule->xRename(pVtab, pName->z); + sqlite3VtabImportErrmsg(p, pVtab); + p->expired = 0; + if( rc ) goto abort_due_to_error; break; } #endif @@ -80233,7 +85984,7 @@ case OP_VUpdate: { pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; - break; + goto abort_due_to_error; } pModule = pVtab->pModule; nArg = pOp->p2; @@ -80254,7 +86005,7 @@ case OP_VUpdate: { sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); - db->lastRowid = lastRowid = rowid; + db->lastRowid = rowid; } if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ if( pOp->p5==OE_Ignore ){ @@ -80265,6 +86016,7 @@ case OP_VUpdate: { }else{ p->nChange++; } + if( rc ) goto abort_due_to_error; } break; } @@ -80308,9 +86060,124 @@ case OP_MaxPgcnt: { /* out2 */ } #endif +/* Opcode: Function0 P1 P2 P3 P4 P5 +** Synopsis: r[P3]=func(r[P2@P5]) +** +** Invoke a user function (P4 is a pointer to a FuncDef object that +** defines the function) with P5 arguments taken from register P2 and +** successors. The result of the function is stored in register P3. +** Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** See also: Function, AggStep, AggFinal +*/ +/* Opcode: Function P1 P2 P3 P4 P5 +** Synopsis: r[P3]=func(r[P2@P5]) +** +** Invoke a user function (P4 is a pointer to an sqlite3_context object that +** contains a pointer to the function to be run) with P5 arguments taken +** from register P2 and successors. The result of the function is stored +** in register P3. Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** SQL functions are initially coded as OP_Function0 with P4 pointing +** to a FuncDef object. But on first evaluation, the P4 operand is +** automatically converted into an sqlite3_context object and the operation +** changed to this OP_Function opcode. In this way, the initialization of +** the sqlite3_context object occurs only once, rather than once for each +** evaluation of the function. +** +** See also: Function0, AggStep, AggFinal +*/ +case OP_PureFunc0: +case OP_Function0: { + int n; + sqlite3_context *pCtx; -/* Opcode: Init * P2 * P4 * -** Synopsis: Start at P2 + assert( pOp->p4type==P4_FUNCDEF ); + n = pOp->p5; + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); + assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); + pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); + if( pCtx==0 ) goto no_mem; + pCtx->pOut = 0; + pCtx->pFunc = pOp->p4.pFunc; + pCtx->iOp = (int)(pOp - aOp); + pCtx->pVdbe = p; + pCtx->argc = n; + pOp->p4type = P4_FUNCCTX; + pOp->p4.pCtx = pCtx; + assert( OP_PureFunc == OP_PureFunc0+2 ); + assert( OP_Function == OP_Function0+2 ); + pOp->opcode += 2; + /* Fall through into OP_Function */ +} +case OP_PureFunc: +case OP_Function: { + int i; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCCTX ); + pCtx = pOp->p4.pCtx; + + /* If this function is inside of a trigger, the register array in aMem[] + ** might change from one evaluation to the next. The next block of code + ** checks to see if the register array has changed, and if so it + ** reinitializes the relavant parts of the sqlite3_context object */ + pOut = &aMem[pOp->p3]; + if( pCtx->pOut != pOut ){ + pCtx->pOut = pOut; + for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; + } + + memAboutToChange(p, pOut); +#ifdef SQLITE_DEBUG + for(i=0; iargc; i++){ + assert( memIsValid(pCtx->argv[i]) ); + REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); + } +#endif + MemSetTypeFlag(pOut, MEM_Null); + pCtx->fErrorOrAux = 0; + (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ + + /* If the function returned an error, throw an exception */ + if( pCtx->fErrorOrAux ){ + if( pCtx->isError ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut)); + rc = pCtx->isError; + } + sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); + if( rc ) goto abort_due_to_error; + } + + /* Copy the result of the function into register P3 */ + if( pOut->flags & (MEM_Str|MEM_Blob) ){ + sqlite3VdbeChangeEncoding(pOut, encoding); + if( sqlite3VdbeMemTooBig(pOut) ) goto too_big; + } + + REGISTER_TRACE(pOp->p3, pOut); + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + + +/* Opcode: Init P1 P2 P3 P4 * +** Synopsis: Start at P2 ** ** Programs contain a single instance of this opcode as the very first ** opcode. @@ -80320,27 +86187,57 @@ case OP_MaxPgcnt: { /* out2 */ ** Or if P4 is blank, use the string returned by sqlite3_sql(). ** ** If P2 is not zero, jump to instruction P2. +** +** Increment the value of P1 so that OP_Once opcodes will jump the +** first time they are evaluated for this run. +** +** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT +** error is encountered. */ case OP_Init: { /* jump */ char *zTrace; - char *z; + int i; + + /* If the P4 argument is not NULL, then it must be an SQL comment string. + ** The "--" string is broken up to prevent false-positives with srcck1.c. + ** + ** This assert() provides evidence for: + ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that + ** would have been returned by the legacy sqlite3_trace() interface by + ** using the X argument when X begins with "--" and invoking + ** sqlite3_expanded_sql(P) otherwise. + */ + assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); + assert( pOp==p->aOp ); /* Always instruction 0 */ #ifndef SQLITE_OMIT_TRACE - if( db->xTrace + if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ - z = sqlite3VdbeExpandSql(p, zTrace); - db->xTrace(db->pTraceArg, z); - sqlite3DbFree(db, z); +#ifndef SQLITE_OMIT_DEPRECATED + if( db->mTrace & SQLITE_TRACE_LEGACY ){ + void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; + char *z = sqlite3VdbeExpandSql(p, zTrace); + x(db->pTraceArg, z); + sqlite3_free(z); + }else +#endif + if( db->nVdbeExec>1 ){ + char *z = sqlite3MPrintf(db, "-- %s", zTrace); + (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z); + sqlite3DbFree(db, z); + }else{ + (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); + } } #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ - int i; - for(i=0; inDb; i++){ - if( DbMaskTest(p->btreeMask, i)==0 ) continue; - sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); + int j; + for(j=0; jnDb; j++){ + if( DbMaskTest(p->btreeMask, j)==0 ) continue; + sqlite3_file_control(db, db->aDb[j].zDbSName, SQLITE_FCNTL_TRACE, zTrace); } } #endif /* SQLITE_USE_FCNTL_TRACE */ @@ -80352,8 +86249,16 @@ case OP_Init: { /* jump */ } #endif /* SQLITE_DEBUG */ #endif /* SQLITE_OMIT_TRACE */ - if( pOp->p2 ) goto jump_to_p2; - break; + assert( pOp->p2>0 ); + if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){ + for(i=1; inOp; i++){ + if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0; + } + pOp->p1 = 0; + } + pOp->p1++; + p->aCounter[SQLITE_STMTSTATUS_RUN]++; + goto jump_to_p2; } #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -80421,11 +86326,12 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ + u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode]; if( rc!=0 ) printf("rc=%d\n",rc); - if( pOrigOp->opflags & (OPFLG_OUT2) ){ + if( opProperty & (OPFLG_OUT2) ){ registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } - if( pOrigOp->opflags & OPFLG_OUT3 ){ + if( opProperty & OPFLG_OUT3 ){ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } } @@ -80436,14 +86342,19 @@ default: { /* This is really OP_Noop and OP_Explain */ /* If we reach this point, it means that execution is finished with ** an error of some kind. */ -vdbe_error_halt: +abort_due_to_error: + if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT; assert( rc ); + if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ + sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); + } p->rc = rc; + sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(rc, "statement aborts at %d: [%s] %s", (int)(pOp - aOp), p->zSql, p->zErrMsg); sqlite3VdbeHalt(p); - if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1; + if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); rc = SQLITE_ERROR; if( resetSchemaOnFault>0 ){ sqlite3ResetOneSchema(db, resetSchemaOnFault-1); @@ -80453,10 +86364,12 @@ vdbe_error_halt: ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: - db->lastRowid = lastRowid; testcase( nVmStep>0 ); p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; sqlite3VdbeLeave(p); + assert( rc!=SQLITE_OK || nExtraDelete==0 + || sqlite3_strlike("DELETE%",p->zSql,0)!=0 + ); return rc; /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH @@ -80465,36 +86378,25 @@ vdbe_return: too_big: sqlite3VdbeError(p, "string or blob too big"); rc = SQLITE_TOOBIG; - goto vdbe_error_halt; + goto abort_due_to_error; /* Jump to here if a malloc() fails. */ no_mem: - db->mallocFailed = 1; + sqlite3OomFault(db); sqlite3VdbeError(p, "out of memory"); - rc = SQLITE_NOMEM; - goto vdbe_error_halt; - - /* Jump to here for any other kind of fatal error. The "rc" variable - ** should hold the error number. - */ -abort_due_to_error: - assert( p->zErrMsg==0 ); - if( db->mallocFailed ) rc = SQLITE_NOMEM; - if( rc!=SQLITE_IOERR_NOMEM ){ - sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); - } - goto vdbe_error_halt; + rc = SQLITE_NOMEM_BKPT; + goto abort_due_to_error; /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. */ abort_due_to_interrupt: assert( db->u1.isInterrupted ); - rc = SQLITE_INTERRUPT; + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; p->rc = rc; sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); - goto vdbe_error_halt; + goto abort_due_to_error; } @@ -80525,13 +86427,14 @@ abort_due_to_interrupt: */ typedef struct Incrblob Incrblob; struct Incrblob { - int flags; /* Copy of "flags" passed to sqlite3_blob_open() */ int nByte; /* Size of open blob, in bytes */ int iOffset; /* Byte offset of blob in cursor data */ - int iCol; /* Table column this handle is open on */ + u16 iCol; /* Table column this handle is open on */ BtCursor *pCsr; /* Cursor pointing at blob row */ sqlite3_stmt *pStmt; /* Statement holding cursor open */ sqlite3 *db; /* The associated database */ + char *zDb; /* Database name */ + Table *pTab; /* Table object */ }; @@ -80557,17 +86460,28 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ char *zErr = 0; /* Error message */ Vdbe *v = (Vdbe *)p->pStmt; - /* Set the value of the SQL statements only variable to integer iRow. - ** This is done directly instead of using sqlite3_bind_int64() to avoid - ** triggering asserts related to mutexes. + /* Set the value of register r[1] in the SQL statement to integer iRow. + ** This is done directly as a performance optimization */ - assert( v->aVar[0].flags&MEM_Int ); - v->aVar[0].u.i = iRow; + v->aMem[1].flags = MEM_Int; + v->aMem[1].u.i = iRow; - rc = sqlite3_step(p->pStmt); + /* If the statement has been run before (and is paused at the OP_ResultRow) + ** then back it up to the point where it does the OP_NotExists. This could + ** have been down with an extra OP_Goto, but simply setting the program + ** counter is faster. */ + if( v->pc>4 ){ + v->pc = 4; + assert( v->aOp[v->pc].opcode==OP_NotExists ); + rc = sqlite3VdbeExec(v); + }else{ + rc = sqlite3_step(p->pStmt); + } if( rc==SQLITE_ROW ){ VdbeCursor *pC = v->apCsr[0]; - u32 type = pC->aType[p->iCol]; + u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; + testcase( pC->nHdrParsed==p->iCol ); + testcase( pC->nHdrParsed==p->iCol+1 ); if( type<12 ){ zErr = sqlite3MPrintf(p->db, "cannot open value of type %s", type==0?"null": type==7?"real": "integer" @@ -80606,54 +86520,22 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ /* ** Open a blob handle. */ -SQLITE_API int SQLITE_STDCALL sqlite3_blob_open( +SQLITE_API int sqlite3_blob_open( sqlite3* db, /* The database connection */ const char *zDb, /* The attached database containing the blob */ const char *zTable, /* The table containing the blob */ const char *zColumn, /* The column containing the blob */ sqlite_int64 iRow, /* The row containing the glob */ - int flags, /* True -> read/write access, false -> read-only */ + int wrFlag, /* True -> read/write access, false -> read-only */ sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */ ){ int nAttempt = 0; int iCol; /* Index of zColumn in row-record */ - - /* This VDBE program seeks a btree cursor to the identified - ** db/table/row entry. The reason for using a vdbe program instead - ** of writing code to use the b-tree layer directly is that the - ** vdbe program will take advantage of the various transaction, - ** locking and error handling infrastructure built into the vdbe. - ** - ** After seeking the cursor, the vdbe executes an OP_ResultRow. - ** Code external to the Vdbe then "borrows" the b-tree cursor and - ** uses it to implement the blob_read(), blob_write() and - ** blob_bytes() functions. - ** - ** The sqlite3_blob_close() function finalizes the vdbe program, - ** which closes the b-tree cursor and (possibly) commits the - ** transaction. - */ - static const int iLn = VDBE_OFFSET_LINENO(4); - static const VdbeOpList openBlob[] = { - /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */ - {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */ - /* One of the following two instructions is replaced by an OP_Noop. */ - {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */ - {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */ - {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */ - {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */ - {OP_Column, 0, 0, 1}, /* 6 */ - {OP_ResultRow, 1, 0, 0}, /* 7 */ - {OP_Goto, 0, 4, 0}, /* 8 */ - {OP_Close, 0, 0, 0}, /* 9 */ - {OP_Halt, 0, 0, 0}, /* 10 */ - }; - int rc = SQLITE_OK; char *zErr = 0; Table *pTab; - Parse *pParse = 0; Incrblob *pBlob = 0; + Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( ppBlob==0 ){ @@ -80666,47 +86548,46 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open( return SQLITE_MISUSE_BKPT; } #endif - flags = !!flags; /* flags = (flags ? 1 : 0); */ + wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); - if( !pBlob ) goto blob_open_out; - pParse = sqlite3StackAllocRaw(db, sizeof(*pParse)); - if( !pParse ) goto blob_open_out; - do { - memset(pParse, 0, sizeof(Parse)); - pParse->db = db; + memset(&sParse, 0, sizeof(Parse)); + if( !pBlob ) goto blob_open_out; + sParse.db = db; sqlite3DbFree(db, zErr); zErr = 0; sqlite3BtreeEnterAll(db); - pTab = sqlite3LocateTable(pParse, 0, zTable, zDb); + pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb); if( pTab && IsVirtual(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable); } if( pTab && !HasRowid(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW if( pTab && pTab->pSelect ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif if( !pTab ){ - if( pParse->zErrMsg ){ + if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); - zErr = pParse->zErrMsg; - pParse->zErrMsg = 0; + zErr = sParse.zErrMsg; + sParse.zErrMsg = 0; } rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } + pBlob->pTab = pTab; + pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { @@ -80724,9 +86605,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open( /* If the value is being opened for writing, check that the ** column is not indexed, and that it is not part of a foreign key. - ** It is against the rules to open a column to which either of these - ** descriptions applies for writing. */ - if( flags ){ + */ + if( wrFlag ){ const char *zFault = 0; Index *pIdx; #ifndef SQLITE_OMIT_FOREIGN_KEY @@ -80764,63 +86644,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open( } } - pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse); + pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse); assert( pBlob->pStmt || db->mallocFailed ); if( pBlob->pStmt ){ + + /* This VDBE program seeks a btree cursor to the identified + ** db/table/row entry. The reason for using a vdbe program instead + ** of writing code to use the b-tree layer directly is that the + ** vdbe program will take advantage of the various transaction, + ** locking and error handling infrastructure built into the vdbe. + ** + ** After seeking the cursor, the vdbe executes an OP_ResultRow. + ** Code external to the Vdbe then "borrows" the b-tree cursor and + ** uses it to implement the blob_read(), blob_write() and + ** blob_bytes() functions. + ** + ** The sqlite3_blob_close() function finalizes the vdbe program, + ** which closes the b-tree cursor and (possibly) commits the + ** transaction. + */ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList openBlob[] = { + {OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */ + {OP_OpenRead, 0, 0, 0}, /* 1: Open a cursor */ + /* blobSeekToRow() will initialize r[1] to the desired rowid */ + {OP_NotExists, 0, 5, 1}, /* 2: Seek the cursor to rowid=r[1] */ + {OP_Column, 0, 0, 1}, /* 3 */ + {OP_ResultRow, 1, 0, 0}, /* 4 */ + {OP_Halt, 0, 0, 0}, /* 5 */ + }; Vdbe *v = (Vdbe *)pBlob->pStmt; int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + VdbeOp *aOp; - - sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags, + sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, pTab->pSchema->schema_cookie, pTab->pSchema->iGeneration); - sqlite3VdbeChangeP5(v, 1); - sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); + sqlite3VdbeChangeP5(v, 1); + assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed ); + aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); /* Make sure a mutex is held on the table to be accessed */ sqlite3VdbeUsesBtree(v, iDb); - /* Configure the OP_TableLock instruction */ + if( db->mallocFailed==0 ){ + assert( aOp!=0 ); + /* Configure the OP_TableLock instruction */ #ifdef SQLITE_OMIT_SHARED_CACHE - sqlite3VdbeChangeToNoop(v, 1); + aOp[0].opcode = OP_Noop; #else - sqlite3VdbeChangeP1(v, 1, iDb); - sqlite3VdbeChangeP2(v, 1, pTab->tnum); - sqlite3VdbeChangeP3(v, 1, flags); - sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); + aOp[0].p1 = iDb; + aOp[0].p2 = pTab->tnum; + aOp[0].p3 = wrFlag; + sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); + } + if( db->mallocFailed==0 ){ #endif - /* Remove either the OP_OpenWrite or OpenRead. Set the P2 - ** parameter of the other to pTab->tnum. */ - sqlite3VdbeChangeToNoop(v, 3 - flags); - sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum); - sqlite3VdbeChangeP3(v, 2 + flags, iDb); + /* Remove either the OP_OpenWrite or OpenRead. Set the P2 + ** parameter of the other to pTab->tnum. */ + if( wrFlag ) aOp[1].opcode = OP_OpenWrite; + aOp[1].p2 = pTab->tnum; + aOp[1].p3 = iDb; - /* Configure the number of columns. Configure the cursor to - ** think that the table has one more column than it really - ** does. An OP_Column to retrieve this imaginary column will - ** always return an SQL NULL. This is useful because it means - ** we can invoke OP_Column to fill in the vdbe cursors type - ** and offset cache without causing any IO. - */ - sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); - sqlite3VdbeChangeP2(v, 6, pTab->nCol); - if( !db->mallocFailed ){ - pParse->nVar = 1; - pParse->nMem = 1; - pParse->nTab = 1; - sqlite3VdbeMakeReady(v, pParse); + /* Configure the number of columns. Configure the cursor to + ** think that the table has one more column than it really + ** does. An OP_Column to retrieve this imaginary column will + ** always return an SQL NULL. This is useful because it means + ** we can invoke OP_Column to fill in the vdbe cursors type + ** and offset cache without causing any IO. + */ + aOp[1].p4type = P4_INT32; + aOp[1].p4.i = pTab->nCol+1; + aOp[3].p2 = pTab->nCol; + + sParse.nVar = 0; + sParse.nMem = 1; + sParse.nTab = 1; + sqlite3VdbeMakeReady(v, &sParse); } } - pBlob->flags = flags; pBlob->iCol = iCol; pBlob->db = db; sqlite3BtreeLeaveAll(db); if( db->mallocFailed ){ goto blob_open_out; } - sqlite3_bind_int64(pBlob->pStmt, 1, iRow); rc = blobSeekToRow(pBlob, iRow, &zErr); } while( (++nAttempt)mutex); return rc; @@ -80844,7 +86753,7 @@ blob_open_out: ** Close a blob handle that was previously created using ** sqlite3_blob_open(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *pBlob){ +SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; int rc; sqlite3 *db; @@ -80895,6 +86804,30 @@ static int blobReadWrite( */ assert( db == v->db ); sqlite3BtreeEnterCursor(p->pCsr); + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){ + /* If a pre-update hook is registered and this is a write cursor, + ** invoke it here. + ** + ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this + ** operation should really be an SQLITE_UPDATE. This is probably + ** incorrect, but is convenient because at this point the new.* values + ** are not easily obtainable. And for the sessions module, an + ** SQLITE_UPDATE where the PK columns do not change is handled in the + ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually + ** slightly more efficient). Since you cannot write to a PK column + ** using the incremental-blob API, this works. For the sessions module + ** anyhow. + */ + sqlite3_int64 iKey; + iKey = sqlite3BtreeIntegerKey(p->pCsr); + sqlite3VdbePreUpdateHook( + v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 + ); + } +#endif + rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ @@ -80913,14 +86846,14 @@ static int blobReadWrite( /* ** Read data from a blob handle. */ -SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){ - return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData); +SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){ + return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked); } /* ** Write data to a blob handle. */ -SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){ +SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){ return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData); } @@ -80930,7 +86863,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob ** so no mutex is required for access. */ -SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){ +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; return (p && p->pStmt) ? p->nByte : 0; } @@ -80945,7 +86878,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){ ** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) ** immediately return SQLITE_ABORT. */ -SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ +SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ int rc; Incrblob *p = (Incrblob *)pBlob; sqlite3 *db; @@ -81521,7 +87454,7 @@ static int vdbePmaReadBlob( int nNew = MAX(128, p->nAlloc*2); while( nByte>nNew ) nNew = nNew*2; aNew = sqlite3Realloc(p->aAlloc, nNew); - if( !aNew ) return SQLITE_NOMEM; + if( !aNew ) return SQLITE_NOMEM_BKPT; p->nAlloc = nNew; p->aAlloc = aNew; } @@ -81633,7 +87566,7 @@ static int vdbePmaReaderSeek( int iBuf = pReadr->iReadOff % pgsz; if( pReadr->aBuffer==0 ){ pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz); - if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM; + if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT; pReadr->nBuffer = pgsz; } if( rc==SQLITE_OK && iBuf ){ @@ -81718,7 +87651,7 @@ static int vdbePmaReaderInit( rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart); if( rc==SQLITE_OK ){ - u64 nByte; /* Size of PMA in bytes */ + u64 nByte = 0; /* Size of PMA in bytes */ rc = vdbePmaReadVarint(pReadr, &nByte); pReadr->iEof = pReadr->iReadOff + nByte; *pnByte += nByte; @@ -81796,15 +87729,15 @@ static int vdbeSorterCompareText( int n2; int res; - getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2; - getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2; - res = memcmp(v1, v2, MIN(n1, n2)); + getVarint32(&p1[1], n1); + getVarint32(&p2[1], n2); + res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2); if( res==0 ){ res = n1 - n2; } if( res==0 ){ - if( pTask->pSorter->pKeyInfo->nField>1 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); @@ -81839,42 +87772,41 @@ static int vdbeSorterCompareInt( assert( (s1>0 && s1<7) || s1==8 || s1==9 ); assert( (s2>0 && s2<7) || s2==8 || s2==9 ); - if( s1>7 && s2>7 ){ + if( s1==s2 ){ + /* The two values have the same sign. Compare using memcmp(). */ + static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 }; + const u8 n = aLen[s1]; + int i; + res = 0; + for(i=0; i7 && s2>7 ){ res = s1 - s2; }else{ - if( s1==s2 ){ - if( (*v1 ^ *v2) & 0x80 ){ - /* The two values have different signs */ - res = (*v1 & 0x80) ? -1 : +1; - }else{ - /* The two values have the same sign. Compare using memcmp(). */ - static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 }; - int i; - res = 0; - for(i=0; i7 ){ + res = +1; + }else if( s1>7 ){ + res = -1; }else{ - if( s2>7 ){ - res = +1; - }else if( s1>7 ){ - res = -1; - }else{ - res = s1 - s2; - } - assert( res!=0 ); + res = s1 - s2; + } + assert( res!=0 ); - if( res>0 ){ - if( *v1 & 0x80 ) res = -1; - }else{ - if( *v2 & 0x80 ) res = +1; - } + if( res>0 ){ + if( *v1 & 0x80 ) res = -1; + }else{ + if( *v2 & 0x80 ) res = +1; } } if( res==0 ){ - if( pTask->pSorter->pKeyInfo->nField>1 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); @@ -81889,7 +87821,7 @@ static int vdbeSorterCompareInt( /* ** Initialize the temporary index cursor just opened as a sorter cursor. ** -** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) +** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField) ** to determine the number of fields that should be compared from the ** records being sorted. However, if the value passed as argument nField ** is non-zero and the sorter is able to guarantee a stable sort, nField @@ -81912,7 +87844,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( ){ int pgsz; /* Page size of main database */ int i; /* Used to iterate through aTask[] */ - int mxCache; /* Cache size */ VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ @@ -81941,22 +87872,21 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( } #endif - assert( pCsr->pKeyInfo && pCsr->pBt==0 ); + assert( pCsr->pKeyInfo && pCsr->pBtx==0 ); assert( pCsr->eCurType==CURTYPE_SORTER ); - szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); + szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; if( pSorter==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ - pKeyInfo->nXField += (pKeyInfo->nField - nField); - pKeyInfo->nField = nField; + pKeyInfo->nKeyField = nField; } pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); pSorter->nTask = nWorker + 1; @@ -81969,25 +87899,32 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( } if( !sqlite3TempInMemory(db) ){ + i64 mxCache; /* Cache size in bytes*/ u32 szPma = sqlite3GlobalConfig.szPma; pSorter->mnPmaSize = szPma * pgsz; - mxCache = db->aDb[0].pSchema->cache_size; - if( mxCache<(int)szPma ) mxCache = (int)szPma; - pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ); - /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of - ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary - ** large heap allocations. - */ - if( sqlite3GlobalConfig.pScratch==0 ){ + mxCache = db->aDb[0].pSchema->cache_size; + if( mxCache<0 ){ + /* A negative cache-size value C indicates that the cache is abs(C) + ** KiB in size. */ + mxCache = mxCache * -1024; + }else{ + mxCache = mxCache * pgsz; + } + mxCache = MIN(mxCache, SQLITE_MAX_PMASZ); + pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache); + + /* Avoid large memory allocations if the application has requested + ** SQLITE_CONFIG_SMALL_MALLOC. */ + if( sqlite3GlobalConfig.bSmallMalloc==0 ){ assert( pSorter->iMemory==0 ); pSorter->nMemory = pgsz; pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); - if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM; + if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT; } } - if( (pKeyInfo->nField+pKeyInfo->nXField)<13 + if( pKeyInfo->nAllField<13 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) ){ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; @@ -82300,13 +88237,9 @@ static int vdbeSorterOpenTempFile( */ static int vdbeSortAllocUnpacked(SortSubtask *pTask){ if( pTask->pUnpacked==0 ){ - char *pFree; - pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord( - pTask->pSorter->pKeyInfo, 0, 0, &pFree - ); - assert( pTask->pUnpacked==(UnpackedRecord*)pFree ); - if( pFree==0 ) return SQLITE_NOMEM; - pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField; + pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo); + if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT; + pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField; pTask->pUnpacked->errCode = 0; } return SQLITE_OK; @@ -82315,19 +88248,18 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){ /* ** Merge the two sorted lists p1 and p2 into a single list. -** Set *ppOut to the head of the new list. */ -static void vdbeSorterMerge( +static SorterRecord *vdbeSorterMerge( SortSubtask *pTask, /* Calling thread context */ SorterRecord *p1, /* First list to merge */ - SorterRecord *p2, /* Second list to merge */ - SorterRecord **ppOut /* OUT: Head of merged list */ + SorterRecord *p2 /* Second list to merge */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; int bCached = 0; - while( p1 && p2 ){ + assert( p1!=0 && p2!=0 ); + for(;;){ int res; res = pTask->xCompare( pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal @@ -82337,15 +88269,22 @@ static void vdbeSorterMerge( *pp = p1; pp = &p1->u.pNext; p1 = p1->u.pNext; + if( p1==0 ){ + *pp = p2; + break; + } }else{ *pp = p2; pp = &p2->u.pNext; p2 = p2->u.pNext; bCached = 0; + if( p2==0 ){ + *pp = p1; + break; + } } } - *pp = p1 ? p1 : p2; - *ppOut = pFinal; + return pFinal; } /* @@ -82380,7 +88319,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); if( !aSlot ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } while( p ){ @@ -82398,7 +88337,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ p->u.pNext = 0; for(i=0; aSlot[i]; i++){ - vdbeSorterMerge(pTask, p, aSlot[i], &p); + p = vdbeSorterMerge(pTask, p, aSlot[i]); aSlot[i] = 0; } aSlot[i] = p; @@ -82407,7 +88346,8 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ p = 0; for(i=0; i<64; i++){ - vdbeSorterMerge(pTask, p, aSlot[i], &p); + if( aSlot[i]==0 ) continue; + p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i]; } pList->pList = p; @@ -82430,7 +88370,7 @@ static void vdbePmaWriterInit( memset(p, 0, sizeof(PmaWriter)); p->aBuffer = (u8*)sqlite3Malloc(nBuf); if( !p->aBuffer ){ - p->eFWErr = SQLITE_NOMEM; + p->eFWErr = SQLITE_NOMEM_BKPT; }else{ p->iBufEnd = p->iBufStart = (iStart % nBuf); p->iWriteOff = iStart - p->iBufStart; @@ -82718,7 +88658,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ pSorter->nMemory = sqlite3MallocSize(aMem); }else if( pSorter->list.aMemory ){ pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory); - if( !pSorter->list.aMemory ) return SQLITE_NOMEM; + if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT; } rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx); @@ -82802,27 +88742,28 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( if( nMin>pSorter->nMemory ){ u8 *aNew; + int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; int nNew = pSorter->nMemory * 2; 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; - pSorter->list.pList = (SorterRecord*)( - aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory) - ); + if( !aNew ) return SQLITE_NOMEM_BKPT; + pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; pSorter->list.aMemory = aNew; pSorter->nMemory = nNew; } pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory]; pSorter->iMemory += ROUND8(nReq); - pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory); + if( pSorter->list.pList ){ + pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory); + } }else{ pNew = (SorterRecord *)sqlite3Malloc(nReq); if( pNew==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pNew->u.pNext = pSorter->list.pList; } @@ -82969,7 +88910,7 @@ static int vdbeIncrMergerNew( pTask->file2.iEof += pIncr->mxSz; }else{ vdbeMergeEngineFree(pMerger); - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } return rc; } @@ -83274,10 +89215,10 @@ static int vdbeMergeEngineLevel0( int rc = SQLITE_OK; *ppOut = pNew = vdbeMergeEngineNew(nPMA); - if( pNew==0 ) rc = SQLITE_NOMEM; + if( pNew==0 ) rc = SQLITE_NOMEM_BKPT; for(i=0; iaReadr[i]; rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy); iOff = pReadr->iEof; @@ -83345,7 +89286,7 @@ static int vdbeSorterAddToTree( if( pReadr->pIncr==0 ){ MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); if( pNew==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr); } @@ -83390,7 +89331,7 @@ static int vdbeSorterMergeTreeBuild( assert( pSorter->bUseThreads || pSorter->nTask==1 ); if( pSorter->nTask>1 ){ pMain = vdbeMergeEngineNew(pSorter->nTask); - if( pMain==0 ) rc = SQLITE_NOMEM; + if( pMain==0 ) rc = SQLITE_NOMEM_BKPT; } #endif @@ -83408,7 +89349,7 @@ static int vdbeSorterMergeTreeBuild( int i; int iSeq = 0; pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); - if( pRoot==0 ) rc = SQLITE_NOMEM; + if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT; for(i=0; inPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){ MergeEngine *pMerger = 0; /* New level-0 PMA merger */ int nReader; /* Number of level-0 PMAs to merge */ @@ -83479,7 +89420,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ if( rc==SQLITE_OK ){ pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); pSorter->pReader = pReadr; - if( pReadr==0 ) rc = SQLITE_NOMEM; + if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT; } if( rc==SQLITE_OK ){ rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); @@ -83582,9 +89523,13 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ } /* -** Advance to the next element in the sorter. +** Advance to the next element in the sorter. Return value: +** +** SQLITE_OK success +** SQLITE_DONE end of data +** otherwise some kind of error. */ -SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){ VdbeSorter *pSorter; int rc; /* Return code */ @@ -83598,21 +89543,22 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in #if SQLITE_MAX_WORKER_THREADS>0 if( pSorter->bUseThreads ){ rc = vdbePmaReaderNext(pSorter->pReader); - *pbEof = (pSorter->pReader->pFd==0); + if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE; }else #endif /*if( !pSorter->bUseThreads )*/ { + int res = 0; assert( pSorter->pMerger!=0 ); assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); - rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); + rc = vdbeMergeEngineStep(pSorter->pMerger, &res); + if( rc==SQLITE_OK && res ) rc = SQLITE_DONE; } }else{ SorterRecord *pFree = pSorter->list.pList; pSorter->list.pList = pFree->u.pNext; pFree->u.pNext = 0; if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); - *pbEof = !pSorter->list.pList; - rc = SQLITE_OK; + rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE; } return rc; } @@ -83656,7 +89602,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ pSorter = pCsr->uc.pSorter; pKey = vdbeSorterRowkey(pSorter, &nKey); if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pOut->n = nKey; MemSetTypeFlag(pOut, MEM_Blob); @@ -83698,10 +89644,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( r2 = pSorter->pUnpacked; pKeyInfo = pCsr->pKeyInfo; if( r2==0 ){ - char *p; - r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); - assert( pSorter->pUnpacked==(UnpackedRecord*)p ); - if( r2==0 ) return SQLITE_NOMEM; + r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( r2==0 ) return SQLITE_NOMEM_BKPT; r2->nField = nKeyCol; } assert( r2->nField==nKeyCol ); @@ -83720,265 +89664,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( } /************** End of vdbesort.c ********************************************/ -/************** Begin file journal.c *****************************************/ -/* -** 2007 August 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file implements a special kind of sqlite3_file object used -** by SQLite to create journal files if the atomic-write optimization -** is enabled. -** -** The distinctive characteristic of this sqlite3_file is that the -** actual on disk file is created lazily. When the file is created, -** the caller specifies a buffer size for an in-memory buffer to -** be used to service read() and write() requests. The actual file -** on disk is not created or populated until either: -** -** 1) The in-memory representation grows too large for the allocated -** buffer, or -** 2) The sqlite3JournalCreate() function is called. -*/ -#ifdef SQLITE_ENABLE_ATOMIC_WRITE -/* #include "sqliteInt.h" */ - - -/* -** A JournalFile object is a subclass of sqlite3_file used by -** as an open file handle for journal files. -*/ -struct JournalFile { - sqlite3_io_methods *pMethod; /* I/O methods on journal files */ - int nBuf; /* Size of zBuf[] in bytes */ - char *zBuf; /* Space to buffer journal writes */ - int iSize; /* Amount of zBuf[] currently used */ - int flags; /* xOpen flags */ - sqlite3_vfs *pVfs; /* The "real" underlying VFS */ - sqlite3_file *pReal; /* The "real" underlying file descriptor */ - const char *zJournal; /* Name of the journal file */ -}; -typedef struct JournalFile JournalFile; - -/* -** If it does not already exists, create and populate the on-disk file -** for JournalFile p. -*/ -static int createFile(JournalFile *p){ - int rc = SQLITE_OK; - if( !p->pReal ){ - sqlite3_file *pReal = (sqlite3_file *)&p[1]; - rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0); - if( rc==SQLITE_OK ){ - p->pReal = pReal; - if( p->iSize>0 ){ - assert(p->iSize<=p->nBuf); - rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); - } - if( rc!=SQLITE_OK ){ - /* If an error occurred while writing to the file, close it before - ** returning. This way, SQLite uses the in-memory journal data to - ** roll back changes made to the internal page-cache before this - ** function was called. */ - sqlite3OsClose(pReal); - p->pReal = 0; - } - } - } - return rc; -} - -/* -** Close the file. -*/ -static int jrnlClose(sqlite3_file *pJfd){ - JournalFile *p = (JournalFile *)pJfd; - if( p->pReal ){ - sqlite3OsClose(p->pReal); - } - sqlite3_free(p->zBuf); - return SQLITE_OK; -} - -/* -** Read data from the file. -*/ -static int jrnlRead( - sqlite3_file *pJfd, /* The journal file from which to read */ - void *zBuf, /* Put the results here */ - int iAmt, /* Number of bytes to read */ - sqlite_int64 iOfst /* Begin reading at this offset */ -){ - int rc = SQLITE_OK; - JournalFile *p = (JournalFile *)pJfd; - if( p->pReal ){ - rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); - }else if( (iAmt+iOfst)>p->iSize ){ - rc = SQLITE_IOERR_SHORT_READ; - }else{ - memcpy(zBuf, &p->zBuf[iOfst], iAmt); - } - return rc; -} - -/* -** Write data to the file. -*/ -static int jrnlWrite( - sqlite3_file *pJfd, /* The journal file into which to write */ - const void *zBuf, /* Take data to be written from here */ - int iAmt, /* Number of bytes to write */ - sqlite_int64 iOfst /* Begin writing at this offset into the file */ -){ - int rc = SQLITE_OK; - JournalFile *p = (JournalFile *)pJfd; - if( !p->pReal && (iOfst+iAmt)>p->nBuf ){ - rc = createFile(p); - } - if( rc==SQLITE_OK ){ - if( p->pReal ){ - rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); - }else{ - memcpy(&p->zBuf[iOfst], zBuf, iAmt); - if( p->iSize<(iOfst+iAmt) ){ - p->iSize = (iOfst+iAmt); - } - } - } - return rc; -} - -/* -** Truncate the file. -*/ -static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ - int rc = SQLITE_OK; - JournalFile *p = (JournalFile *)pJfd; - if( p->pReal ){ - rc = sqlite3OsTruncate(p->pReal, size); - }else if( sizeiSize ){ - p->iSize = size; - } - return rc; -} - -/* -** Sync the file. -*/ -static int jrnlSync(sqlite3_file *pJfd, int flags){ - int rc; - JournalFile *p = (JournalFile *)pJfd; - if( p->pReal ){ - rc = sqlite3OsSync(p->pReal, flags); - }else{ - rc = SQLITE_OK; - } - return rc; -} - -/* -** Query the size of the file in bytes. -*/ -static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ - int rc = SQLITE_OK; - JournalFile *p = (JournalFile *)pJfd; - if( p->pReal ){ - rc = sqlite3OsFileSize(p->pReal, pSize); - }else{ - *pSize = (sqlite_int64) p->iSize; - } - return rc; -} - -/* -** Table of methods for JournalFile sqlite3_file object. -*/ -static struct sqlite3_io_methods JournalFileMethods = { - 1, /* iVersion */ - jrnlClose, /* xClose */ - jrnlRead, /* xRead */ - jrnlWrite, /* xWrite */ - jrnlTruncate, /* xTruncate */ - jrnlSync, /* xSync */ - jrnlFileSize, /* xFileSize */ - 0, /* xLock */ - 0, /* xUnlock */ - 0, /* xCheckReservedLock */ - 0, /* xFileControl */ - 0, /* xSectorSize */ - 0, /* xDeviceCharacteristics */ - 0, /* xShmMap */ - 0, /* xShmLock */ - 0, /* xShmBarrier */ - 0 /* xShmUnmap */ -}; - -/* -** Open a journal file. -*/ -SQLITE_PRIVATE int sqlite3JournalOpen( - sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ - const char *zName, /* Name of the journal file */ - sqlite3_file *pJfd, /* Preallocated, blank file handle */ - int flags, /* Opening flags */ - int nBuf /* Bytes buffered before opening the file */ -){ - JournalFile *p = (JournalFile *)pJfd; - memset(p, 0, sqlite3JournalSize(pVfs)); - if( nBuf>0 ){ - p->zBuf = sqlite3MallocZero(nBuf); - if( !p->zBuf ){ - return SQLITE_NOMEM; - } - }else{ - return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); - } - p->pMethod = &JournalFileMethods; - p->nBuf = nBuf; - p->flags = flags; - p->zJournal = zName; - p->pVfs = pVfs; - return SQLITE_OK; -} - -/* -** If the argument p points to a JournalFile structure, and the underlying -** file has not yet been created, create it now. -*/ -SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){ - if( p->pMethods!=&JournalFileMethods ){ - return SQLITE_OK; - } - return createFile((JournalFile *)p); -} - -/* -** The file-handle passed as the only argument is guaranteed to be an open -** file. It may or may not be of class JournalFile. If the file is a -** JournalFile, and the underlying file on disk has not yet been opened, -** return 0. Otherwise, return 1. -*/ -SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p){ - return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0); -} - -/* -** Return the number of bytes required to store a JournalFile that uses vfs -** pVfs to create the underlying on-disk files. -*/ -SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ - return (pVfs->szOsFile+sizeof(JournalFile)); -} -#endif - -/************** End of journal.c *********************************************/ /************** Begin file memjournal.c **************************************/ /* ** 2008 October 7 @@ -83995,6 +89680,15 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ ** This file contains code use to implement an in-memory rollback journal. ** The in-memory rollback journal is used to journal transactions for ** ":memory:" databases and when the journal_mode=MEMORY pragma is used. +** +** Update: The in-memory journal is also used to temporarily cache +** smaller journals that are not critical for power-loss recovery. +** For example, statement journals that are not too big will be held +** entirely in memory, thus reducing the number of file I/O calls, and +** more importantly, reducing temporary file creation events. If these +** journals become too large for memory, they are spilled to disk. But +** in the common case, they are usually small and no file I/O needs to +** occur. */ /* #include "sqliteInt.h" */ @@ -84003,24 +89697,28 @@ typedef struct MemJournal MemJournal; typedef struct FilePoint FilePoint; typedef struct FileChunk FileChunk; -/* Space to hold the rollback journal is allocated in increments of -** this many bytes. -** -** The size chosen is a little less than a power of two. That way, -** the FileChunk object will have a size that almost exactly fills -** a power-of-two allocation. This minimizes wasted space in power-of-two -** memory allocators. -*/ -#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*))) - /* ** The rollback journal is composed of a linked list of these structures. +** +** The zChunk array is always at least 8 bytes in size - usually much more. +** Its actual size is stored in the MemJournal.nChunkSize variable. */ struct FileChunk { FileChunk *pNext; /* Next chunk in the journal */ - u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */ + u8 zChunk[8]; /* Content of this chunk */ }; +/* +** By default, allocate this many bytes of memory for each FileChunk object. +*/ +#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024 + +/* +** For chunk size nChunkSize, return the number of bytes that should +** be allocated for each FileChunk structure. +*/ +#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8)) + /* ** An instance of this object serves as a cursor into the rollback journal. ** The cursor can be either for reading or writing. @@ -84031,14 +89729,22 @@ struct FilePoint { }; /* -** This subclass is a subclass of sqlite3_file. Each open memory-journal +** This structure is a subclass of sqlite3_file. Each open memory-journal ** is an instance of this class. */ struct MemJournal { - sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ + const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ + int nChunkSize; /* In-memory chunk-size */ + + int nSpill; /* Bytes of data before flushing */ + int nSize; /* Bytes of data currently in memory */ FileChunk *pFirst; /* Head of in-memory chunk-list */ FilePoint endpoint; /* Pointer to the end of the file */ FilePoint readpoint; /* Pointer to the end of the last xRead() */ + + int flags; /* xOpen flags */ + sqlite3_vfs *pVfs; /* The "real" underlying VFS */ + const char *zJournal; /* Name of the journal file */ }; /* @@ -84057,36 +89763,95 @@ static int memjrnlRead( int iChunkOffset; FileChunk *pChunk; - /* SQLite never tries to read past the end of a rollback journal file */ - assert( iOfst+iAmt<=p->endpoint.iOffset ); +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + if( (iAmt+iOfst)>p->endpoint.iOffset ){ + return SQLITE_IOERR_SHORT_READ; + } +#endif + assert( (iAmt+iOfst)<=p->endpoint.iOffset ); + assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 ); if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ sqlite3_int64 iOff = 0; for(pChunk=p->pFirst; - ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst; + ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst; pChunk=pChunk->pNext ){ - iOff += JOURNAL_CHUNKSIZE; + iOff += p->nChunkSize; } }else{ pChunk = p->readpoint.pChunk; + assert( pChunk!=0 ); } - iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE); + iChunkOffset = (int)(iOfst%p->nChunkSize); do { - int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset; - int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset)); - memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy); + int iSpace = p->nChunkSize - iChunkOffset; + int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset)); + memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy); zOut += nCopy; nRead -= iSpace; iChunkOffset = 0; } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 ); - p->readpoint.iOffset = iOfst+iAmt; + p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0; p->readpoint.pChunk = pChunk; return SQLITE_OK; } +/* +** Free the list of FileChunk structures headed at MemJournal.pFirst. +*/ +static void memjrnlFreeChunks(MemJournal *p){ + FileChunk *pIter; + FileChunk *pNext; + for(pIter=p->pFirst; pIter; pIter=pNext){ + pNext = pIter->pNext; + sqlite3_free(pIter); + } + p->pFirst = 0; +} + +/* +** Flush the contents of memory to a real file on disk. +*/ +static int memjrnlCreateFile(MemJournal *p){ + int rc; + sqlite3_file *pReal = (sqlite3_file*)p; + MemJournal copy = *p; + + memset(p, 0, sizeof(MemJournal)); + rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0); + if( rc==SQLITE_OK ){ + int nChunk = copy.nChunkSize; + i64 iOff = 0; + FileChunk *pIter; + for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){ + if( iOff + nChunk > copy.endpoint.iOffset ){ + nChunk = copy.endpoint.iOffset - iOff; + } + rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff); + if( rc ) break; + iOff += nChunk; + } + if( rc==SQLITE_OK ){ + /* No error has occurred. Free the in-memory buffers. */ + memjrnlFreeChunks(©); + } + } + if( rc!=SQLITE_OK ){ + /* If an error occurred while creating or writing to the file, restore + ** the original before returning. This way, SQLite uses the in-memory + ** journal data to roll back changes made to the internal page-cache + ** before this function was called. */ + sqlite3OsClose(pReal); + *p = copy; + } + return rc; +} + + /* ** Write data to the file. */ @@ -84100,38 +89865,63 @@ static int memjrnlWrite( int nWrite = iAmt; u8 *zWrite = (u8 *)zBuf; - /* An in-memory journal file should only ever be appended to. Random - ** access writes are not required by sqlite. - */ - assert( iOfst==p->endpoint.iOffset ); - UNUSED_PARAMETER(iOfst); - - while( nWrite>0 ){ - FileChunk *pChunk = p->endpoint.pChunk; - int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE); - int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset); - - if( iChunkOffset==0 ){ - /* New chunk is required to extend the file. */ - FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk)); - if( !pNew ){ - return SQLITE_IOERR_NOMEM; - } - pNew->pNext = 0; - if( pChunk ){ - assert( p->pFirst ); - pChunk->pNext = pNew; - }else{ - assert( !p->pFirst ); - p->pFirst = pNew; - } - p->endpoint.pChunk = pNew; + /* If the file should be created now, create it and write the new data + ** into the file on disk. */ + if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){ + int rc = memjrnlCreateFile(p); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst); } + return rc; + } - memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace); - zWrite += iSpace; - nWrite -= iSpace; - p->endpoint.iOffset += iSpace; + /* If the contents of this write should be stored in memory */ + else{ + /* An in-memory journal file should only ever be appended to. Random + ** access writes are not required. The only exception to this is when + ** the in-memory journal is being used by a connection using the + ** atomic-write optimization. In this case the first 28 bytes of the + ** journal file may be written as part of committing the transaction. */ + assert( iOfst==p->endpoint.iOffset || iOfst==0 ); +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + if( iOfst==0 && p->pFirst ){ + assert( p->nChunkSize>iAmt ); + memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); + }else +#else + assert( iOfst>0 || p->pFirst==0 ); +#endif + { + while( nWrite>0 ){ + FileChunk *pChunk = p->endpoint.pChunk; + int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize); + int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset); + + if( iChunkOffset==0 ){ + /* New chunk is required to extend the file. */ + FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize)); + if( !pNew ){ + return SQLITE_IOERR_NOMEM_BKPT; + } + pNew->pNext = 0; + if( pChunk ){ + assert( p->pFirst ); + pChunk->pNext = pNew; + }else{ + assert( !p->pFirst ); + p->pFirst = pNew; + } + p->endpoint.pChunk = pNew; + } + + memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); + zWrite += iSpace; + nWrite -= iSpace; + p->endpoint.iOffset += iSpace; + } + p->nSize = iAmt + iOfst; + } } return SQLITE_OK; @@ -84139,19 +89929,21 @@ static int memjrnlWrite( /* ** Truncate the file. +** +** If the journal file is already on disk, truncate it there. Or, if it +** is still in main memory but is being truncated to zero bytes in size, +** ignore */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ MemJournal *p = (MemJournal *)pJfd; - FileChunk *pChunk; - assert(size==0); - UNUSED_PARAMETER(size); - pChunk = p->pFirst; - while( pChunk ){ - FileChunk *pTmp = pChunk; - pChunk = pChunk->pNext; - sqlite3_free(pTmp); + if( ALWAYS(size==0) ){ + memjrnlFreeChunks(p); + p->nSize = 0; + p->endpoint.pChunk = 0; + p->endpoint.iOffset = 0; + p->readpoint.pChunk = 0; + p->readpoint.iOffset = 0; } - sqlite3MemJournalOpen(pJfd); return SQLITE_OK; } @@ -84159,21 +89951,19 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ ** Close the file. */ static int memjrnlClose(sqlite3_file *pJfd){ - memjrnlTruncate(pJfd, 0); + MemJournal *p = (MemJournal *)pJfd; + memjrnlFreeChunks(p); return SQLITE_OK; } - /* ** Sync the file. ** -** Syncing an in-memory journal is a no-op. And, in fact, this routine -** is never called in a working implementation. This implementation -** exists purely as a contingency, in case some malfunction in some other -** part of SQLite causes Sync to be called by mistake. +** If the real file has been created, call its xSync method. Otherwise, +** syncing an in-memory journal is a no-op. */ -static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ - UNUSED_PARAMETER2(NotUsed, NotUsed2); +static int memjrnlSync(sqlite3_file *pJfd, int flags){ + UNUSED_PARAMETER2(pJfd, flags); return SQLITE_OK; } @@ -84212,28 +90002,102 @@ static const struct sqlite3_io_methods MemJournalMethods = { }; /* -** Open a journal file. +** Open a journal file. +** +** The behaviour of the journal file depends on the value of parameter +** nSpill. If nSpill is 0, then the journal file is always create and +** accessed using the underlying VFS. If nSpill is less than zero, then +** all content is always stored in main-memory. Finally, if nSpill is a +** positive value, then the journal file is initially created in-memory +** but may be flushed to disk later on. In this case the journal file is +** flushed to disk either when it grows larger than nSpill bytes in size, +** or when sqlite3JournalCreate() is called. */ -SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){ - MemJournal *p = (MemJournal *)pJfd; - assert( EIGHT_BYTE_ALIGNMENT(p) ); - memset(p, 0, sqlite3MemJournalSize()); - p->pMethod = (sqlite3_io_methods*)&MemJournalMethods; +SQLITE_PRIVATE int sqlite3JournalOpen( + sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ + const char *zName, /* Name of the journal file */ + sqlite3_file *pJfd, /* Preallocated, blank file handle */ + int flags, /* Opening flags */ + int nSpill /* Bytes buffered before opening the file */ +){ + MemJournal *p = (MemJournal*)pJfd; + + /* Zero the file-handle object. If nSpill was passed zero, initialize + ** it using the sqlite3OsOpen() function of the underlying VFS. In this + ** case none of the code in this module is executed as a result of calls + ** made on the journal file-handle. */ + memset(p, 0, sizeof(MemJournal)); + if( nSpill==0 ){ + return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); + } + + if( nSpill>0 ){ + p->nChunkSize = nSpill; + }else{ + p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk); + assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); + } + + p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods; + p->nSpill = nSpill; + p->flags = flags; + p->zJournal = zName; + p->pVfs = pVfs; + return SQLITE_OK; } /* -** Return true if the file-handle passed as an argument is -** an in-memory journal +** Open an in-memory journal file. */ -SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){ - return pJfd->pMethods==&MemJournalMethods; +SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){ + sqlite3JournalOpen(0, 0, pJfd, 0, -1); +} + +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) +/* +** If the argument p points to a MemJournal structure that is not an +** in-memory-only journal file (i.e. is one that was opened with a +ve +** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying +** file has not yet been created, create it now. +*/ +SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){ + int rc = SQLITE_OK; + MemJournal *p = (MemJournal*)pJfd; + if( p->pMethod==&MemJournalMethods && ( +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + p->nSpill>0 +#else + /* While this appears to not be possible without ATOMIC_WRITE, the + ** paths are complex, so it seems prudent to leave the test in as + ** a NEVER(), in case our analysis is subtly flawed. */ + NEVER(p->nSpill>0) +#endif +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + || (p->flags & SQLITE_OPEN_MAIN_JOURNAL) +#endif + )){ + rc = memjrnlCreateFile(p); + } + return rc; +} +#endif + +/* +** The file-handle passed as the only argument is open on a journal file. +** Return true if this "journal file" is currently stored in heap memory, +** or false otherwise. +*/ +SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){ + return p->pMethods==&MemJournalMethods; } /* -** Return the number of bytes required to store a MemJournal file descriptor. +** Return the number of bytes required to store a JournalFile that uses vfs +** pVfs to create the underlying on-disk files. */ -SQLITE_PRIVATE int sqlite3MemJournalSize(void){ - return sizeof(MemJournal); +SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ + return MAX(pVfs->szOsFile, (int)sizeof(MemJournal)); } /************** End of memjournal.c ******************************************/ @@ -84267,32 +90131,40 @@ SQLITE_PRIVATE int sqlite3MemJournalSize(void){ ** ** WRC_Continue Continue descending down the tree. ** -** WRC_Prune Do not descend into child nodes. But allow +** WRC_Prune Do not descend into child nodes, but allow ** the walk to continue with sibling nodes. ** ** WRC_Abort Do no more callbacks. Unwind the stack and -** return the top-level walk call. +** return from the top-level walk call. ** ** The return value from this routine is WRC_Abort to abandon the tree walk ** and WRC_Continue to continue. */ -SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ +static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; - if( pExpr==0 ) return WRC_Continue; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); - rc = pWalker->xExprCallback(pWalker, pExpr); - if( rc==WRC_Continue - && !ExprHasProperty(pExpr,EP_TokenOnly) ){ - if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; - if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; - }else{ - if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + while(1){ + rc = pWalker->xExprCallback(pWalker, pExpr); + if( rc ) return rc & WRC_Abort; + if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ + if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; + assert( pExpr->x.pList==0 || pExpr->pRight==0 ); + if( pExpr->pRight ){ + pExpr = pExpr->pRight; + continue; + }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; + }else if( pExpr->x.pList ){ + if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + } } + break; } - return rc & WRC_Abort; + return WRC_Continue; +} +SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ + return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; } /* @@ -84342,7 +90214,7 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){ + if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc @@ -84362,8 +90234,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ ** ** If it is not NULL, the xSelectCallback() callback is invoked before ** the walk of the expressions and FROM clause. The xSelectCallback2() -** method, if it is not NULL, is invoked following the walk of the -** expressions and FROM clause. +** method is invoked following the walk of the expressions and FROM clause, +** but only if both xSelectCallback and xSelectCallback2 are both non-NULL +** and if the expressions and FROM clause both return WRC_Continue; ** ** Return WRC_Continue under normal conditions. Return WRC_Abort if ** there is an abort request. @@ -84373,29 +90246,22 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ */ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ int rc; - if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){ - return WRC_Continue; - } - rc = WRC_Continue; - pWalker->walkerDepth++; - while( p ){ - if( pWalker->xSelectCallback ){ - rc = pWalker->xSelectCallback(pWalker, p); - if( rc ) break; - } + if( p==0 ) return WRC_Continue; + if( pWalker->xSelectCallback==0 ) return WRC_Continue; + do{ + rc = pWalker->xSelectCallback(pWalker, p); + if( rc ) return rc & WRC_Abort; if( sqlite3WalkSelectExpr(pWalker, p) || sqlite3WalkSelectFrom(pWalker, p) ){ - pWalker->walkerDepth--; return WRC_Abort; } if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; - } - pWalker->walkerDepth--; - return rc & WRC_Abort; + }while( p!=0 ); + return WRC_Continue; } /************** End of walker.c **********************************************/ @@ -84417,8 +90283,6 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ ** table and column. */ /* #include "sqliteInt.h" */ -/* #include */ -/* #include */ /* ** Walk the expression tree pExpr and increase the aggregate function @@ -84623,8 +90487,8 @@ static int lookupName( zDb = 0; }else{ for(i=0; inDb; i++){ - assert( db->aDb[i].zName ); - if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ + assert( db->aDb[i].zDbSName ); + if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } @@ -84633,7 +90497,8 @@ static int lookupName( } /* Start at the inner-most context and move outward until a match is found */ - while( pNC && cnt==0 ){ + assert( pNC && cnt==0 ); + do{ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; @@ -84802,6 +90667,10 @@ static int lookupName( sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } + if( sqlite3ExprVectorSize(pOrig)!=1 ){ + sqlite3ErrorMsg(pParse, "row value misused"); + return WRC_Abort; + } resolveAlias(pParse, pEList, j, pExpr, "", nSubquery); cnt = 1; pMatch = 0; @@ -84814,11 +90683,11 @@ static int lookupName( /* Advance to the next name context. The loop will exit when either ** we have a match (cnt>0) or when we run out of name contexts. */ - if( cnt==0 ){ - pNC = pNC->pNext; - nSubquery++; - } - } + if( cnt ) break; + pNC = pNC->pNext; + nSubquery++; + }while( pNC ); + /* ** If X and Y are NULL (in other words if only the column name Z is @@ -84877,6 +90746,7 @@ static int lookupName( sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); + ExprSetProperty(pExpr, EP_Leaf); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); @@ -84915,7 +90785,6 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } - ExprSetProperty(p, EP_Resolved); } return p; } @@ -84975,8 +90844,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pParse = pNC->pParse; assert( pParse==pWalker->pParse ); - if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune; - ExprSetProperty(pExpr, EP_Resolved); #ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ SrcList *pSrcList = pNC->pSrcList; @@ -85008,34 +90875,38 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */ - /* A lone identifier is the name of a column. - */ - case TK_ID: { - return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr); - } - - /* A table name and column name: ID.ID + /* A column name: ID + ** Or table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID + ** + ** The TK_ID and TK_OUT cases are combined so that there will only + ** be one call to lookupName(). Then the compiler will in-line + ** lookupName() for a size reduction and performance increase. */ + case TK_ID: case TK_DOT: { const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; - /* if( pSrcList==0 ) break; */ - notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); - /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/ - pRight = pExpr->pRight; - if( pRight->op==TK_ID ){ + if( pExpr->op==TK_ID ){ zDb = 0; - zTable = pExpr->pLeft->u.zToken; - zColumn = pRight->u.zToken; + zTable = 0; + zColumn = pExpr->u.zToken; }else{ - assert( pRight->op==TK_DOT ); - zDb = pExpr->pLeft->u.zToken; - zTable = pRight->pLeft->u.zToken; - zColumn = pRight->pRight->u.zToken; + notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); + pRight = pExpr->pRight; + if( pRight->op==TK_ID ){ + zDb = 0; + zTable = pExpr->pLeft->u.zToken; + zColumn = pRight->u.zToken; + }else{ + assert( pRight->op==TK_DOT ); + zDb = pExpr->pLeft->u.zToken; + zTable = pRight->pLeft->u.zToken; + zColumn = pRight->pRight->u.zToken; + } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } @@ -85048,26 +90919,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ - int auth; /* Authorization to use the function */ int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - notValid(pParse, pNC, "functions", NC_PartIdx); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); - pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); + pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ - pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0); + pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0); if( pDef==0 ){ no_such_func = 1; }else{ wrong_num_args = 1; } }else{ - is_agg = pDef->xFunc==0; + is_agg = pDef->xFinalize!=0; if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); if( n==2 ){ @@ -85092,15 +90961,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } } #ifndef SQLITE_OMIT_AUTHORIZATION - auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); - if( auth!=SQLITE_OK ){ - if( auth==SQLITE_DENY ){ - sqlite3ErrorMsg(pParse, "not authorized to use function: %s", - pDef->zName); - pNC->nErr++; + { + int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0); + if( auth!=SQLITE_OK ){ + if( auth==SQLITE_DENY ){ + sqlite3ErrorMsg(pParse, "not authorized to use function: %s", + pDef->zName); + pNC->nErr++; + } + pExpr->op = TK_NULL; + return WRC_Prune; } - pExpr->op = TK_NULL; - return WRC_Prune; } #endif if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ @@ -85113,14 +90984,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* Date/time functions that use 'now', and other functions like ** sqlite_version() that might change over time cannot be used ** in an index. */ - notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr); + notValid(pParse, pNC, "non-deterministic functions", + NC_IdxExpr|NC_PartIdx); } } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; - }else if( no_such_func && pParse->db->init.busy==0 ){ + }else if( no_such_func && pParse->db->init.busy==0 +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + && pParse->explain==0 +#endif + ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); pNC->nErr++; }else if( wrong_num_args ){ @@ -85165,6 +91041,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); + pNC->ncFlags |= NC_VarSelect; } } break; @@ -85173,6 +91050,42 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; } + case TK_BETWEEN: + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_IS: + case TK_ISNOT: { + int nLeft, nRight; + if( pParse->db->mallocFailed ) break; + assert( pExpr->pLeft!=0 ); + nLeft = sqlite3ExprVectorSize(pExpr->pLeft); + if( pExpr->op==TK_BETWEEN ){ + nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); + if( nRight==nLeft ){ + nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr); + } + }else{ + assert( pExpr->pRight!=0 ); + nRight = sqlite3ExprVectorSize(pExpr->pRight); + } + if( nLeft!=nRight ){ + testcase( pExpr->op==TK_EQ ); + testcase( pExpr->op==TK_NE ); + testcase( pExpr->op==TK_LT ); + testcase( pExpr->op==TK_LE ); + testcase( pExpr->op==TK_GT ); + testcase( pExpr->op==TK_GE ); + testcase( pExpr->op==TK_IS ); + testcase( pExpr->op==TK_ISNOT ); + testcase( pExpr->op==TK_BETWEEN ); + sqlite3ErrorMsg(pParse, "row value misused"); + } + break; + } } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; } @@ -85263,7 +91176,7 @@ static int resolveOrderByTermToExprList( ** result-set entry. */ for(i=0; inExpr; i++){ - if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){ + if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){ return i+1; } } @@ -85314,12 +91227,10 @@ static int resolveCompoundOrderBy( pOrderBy = pSelect->pOrderBy; if( pOrderBy==0 ) return 0; db = pParse->db; -#if SQLITE_MAX_COLUMN if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; } -#endif for(i=0; inExpr; i++){ pOrderBy->a[i].done = 0; } @@ -85411,12 +91322,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy( struct ExprList_item *pItem; if( pOrderBy==0 || pParse->db->mallocFailed ) return 0; -#if SQLITE_MAX_COLUMN if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType); return 1; } -#endif pEList = pSelect->pEList; assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */ for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ @@ -85497,7 +91406,7 @@ static int resolveOrderGroupBy( return 1; } for(j=0; jpEList->nExpr; j++){ - if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ + if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ pItem->u.x.iOrderByCol = j+1; } } @@ -85783,35 +91692,29 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( u16 savedHasAgg; Walker w; - if( pExpr==0 ) return 0; -#if SQLITE_MAX_EXPR_DEPTH>0 - { - Parse *pParse = pNC->pParse; - if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){ - return 1; - } - pParse->nHeight += pExpr->nHeight; - } -#endif + if( pExpr==0 ) return SQLITE_OK; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); - memset(&w, 0, sizeof(w)); + w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; - w.pParse = pNC->pParse; + w.xSelectCallback2 = 0; w.u.pNC = pNC; +#if SQLITE_MAX_EXPR_DEPTH>0 + w.pParse->nHeight += pExpr->nHeight; + if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ + return SQLITE_ERROR; + } +#endif sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 - pNC->pParse->nHeight -= pExpr->nHeight; + w.pParse->nHeight -= pExpr->nHeight; #endif - if( pNC->nErr>0 || w.pParse->nErr>0 ){ - ExprSetProperty(pExpr, EP_Error); - } if( pNC->ncFlags & NC_HasAgg ){ ExprSetProperty(pExpr, EP_Agg); } pNC->ncFlags |= savedHasAgg; - return ExprHasProperty(pExpr, EP_Error); + return pNC->nErr>0 || w.pParse->nErr>0; } /* @@ -85852,9 +91755,9 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames( Walker w; assert( p!=0 ); - memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; + w.xSelectCallback2 = 0; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); @@ -85913,6 +91816,18 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference( */ /* #include "sqliteInt.h" */ +/* Forward declarations */ +static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int); +static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); + +/* +** Return the affinity character for a single column of a table. +*/ +SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ + assert( iColnCol ); + return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER; +} + /* ** Return the 'affinity' of the expression pExpr if any. ** @@ -85938,21 +91853,21 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ assert( pExpr->flags&EP_xIsSelect ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } + if( op==TK_REGISTER ) op = pExpr->op2; #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif - if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER) - && pExpr->pTab!=0 - ){ - /* op==TK_REGISTER && pExpr->pTab!=0 happens when pExpr was originally - ** a TK_COLUMN but was previously evaluated and cached in a register */ - int j = pExpr->iColumn; - if( j<0 ) return SQLITE_AFF_INTEGER; - assert( pExpr->pTab && jpTab->nCol ); - return pExpr->pTab->aCol[j].affinity; + if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){ + return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); + } + if( op==TK_SELECT_COLUMN ){ + assert( pExpr->pLeft->flags&EP_xIsSelect ); + return sqlite3ExprAffinity( + pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr + ); } return pExpr->affinity; } @@ -85984,8 +91899,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ Token s; assert( zC!=0 ); - s.z = zC; - s.n = sqlite3Strlen30(s.z); + sqlite3TokenInit(&s, (char*)zC); return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); } @@ -86012,6 +91926,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return NULL. ** +** See also: sqlite3ExprNNCollSeq() +** +** The sqlite3ExprNNCollSeq() works the same exact that it returns the +** default collation if pExpr has no defined collation. +** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take @@ -86076,6 +91995,32 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ return pColl; } +/* +** Return the collation sequence for the expression pExpr. If +** there is no defined collating sequence, return a pointer to the +** defautl collation sequence. +** +** See also: sqlite3ExprCollSeq() +** +** The sqlite3ExprCollSeq() routine works the same except that it +** returns NULL if there is no defined collation. +*/ +SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){ + CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr); + if( p==0 ) p = pParse->db->pDfltColl; + assert( p!=0 ); + return p; +} + +/* +** Return TRUE if the two expressions have equivalent collating sequences. +*/ +SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){ + CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); + CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); + return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; +} + /* ** pExpr is an operand of a comparison operator. aff2 is the ** type affinity of the other operand. This routine returns the @@ -86119,7 +92064,7 @@ static char comparisonAffinity(Expr *pExpr){ aff = sqlite3CompareAffinity(pExpr->pRight, aff); }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); - }else if( !aff ){ + }else if( aff==0 ){ aff = SQLITE_AFF_BLOB; } return aff; @@ -86209,6 +92154,270 @@ static int codeCompare( return addr; } +/* +** Return true if expression pExpr is a vector, or false otherwise. +** +** A vector is defined as any expression that results in two or more +** columns of result. Every TK_VECTOR node is an vector because the +** parser will not generate a TK_VECTOR with fewer than two entries. +** But a TK_SELECT might be either a vector or a scalar. It is only +** considered a vector if it has two or more result columns. +*/ +SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){ + return sqlite3ExprVectorSize(pExpr)>1; +} + +/* +** If the expression passed as the only argument is of type TK_VECTOR +** return the number of expressions in the vector. Or, if the expression +** is a sub-select, return the number of columns in the sub-select. For +** any other type of expression, return 1. +*/ +SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){ + u8 op = pExpr->op; + if( op==TK_REGISTER ) op = pExpr->op2; + if( op==TK_VECTOR ){ + return pExpr->x.pList->nExpr; + }else if( op==TK_SELECT ){ + return pExpr->x.pSelect->pEList->nExpr; + }else{ + return 1; + } +} + +/* +** Return a pointer to a subexpression of pVector that is the i-th +** column of the vector (numbered starting with 0). The caller must +** ensure that i is within range. +** +** If pVector is really a scalar (and "scalar" here includes subqueries +** that return a single column!) then return pVector unmodified. +** +** pVector retains ownership of the returned subexpression. +** +** If the vector is a (SELECT ...) then the expression returned is +** just the expression for the i-th term of the result set, and may +** not be ready for evaluation because the table cursor has not yet +** been positioned. +*/ +SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ + assert( iop2==0 || pVector->op==TK_REGISTER ); + if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ + return pVector->x.pSelect->pEList->a[i].pExpr; + }else{ + return pVector->x.pList->a[i].pExpr; + } + } + return pVector; +} + +/* +** Compute and return a new Expr object which when passed to +** sqlite3ExprCode() will generate all necessary code to compute +** the iField-th column of the vector expression pVector. +** +** It is ok for pVector to be a scalar (as long as iField==0). +** In that case, this routine works like sqlite3ExprDup(). +** +** The caller owns the returned Expr object and is responsible for +** ensuring that the returned value eventually gets freed. +** +** The caller retains ownership of pVector. If pVector is a TK_SELECT, +** then the returned object will reference pVector and so pVector must remain +** valid for the life of the returned object. If pVector is a TK_VECTOR +** or a scalar expression, then it can be deleted as soon as this routine +** returns. +** +** A trick to cause a TK_SELECT pVector to be deleted together with +** the returned Expr object is to attach the pVector to the pRight field +** of the returned TK_SELECT_COLUMN Expr object. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( + Parse *pParse, /* Parsing context */ + Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ + int iField /* Which column of the vector to return */ +){ + Expr *pRet; + if( pVector->op==TK_SELECT ){ + assert( pVector->flags & EP_xIsSelect ); + /* The TK_SELECT_COLUMN Expr node: + ** + ** pLeft: pVector containing TK_SELECT. Not deleted. + ** pRight: not used. But recursively deleted. + ** iColumn: Index of a column in pVector + ** iTable: 0 or the number of columns on the LHS of an assignment + ** pLeft->iTable: First in an array of register holding result, or 0 + ** if the result is not yet computed. + ** + ** sqlite3ExprDelete() specifically skips the recursive delete of + ** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector + ** can be attached to pRight to cause this node to take ownership of + ** pVector. Typically there will be multiple TK_SELECT_COLUMN nodes + ** with the same pLeft pointer to the pVector, but only one of them + ** will own the pVector. + */ + pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); + if( pRet ){ + pRet->iColumn = iField; + pRet->pLeft = pVector; + } + assert( pRet==0 || pRet->iTable==0 ); + }else{ + if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr; + pRet = sqlite3ExprDup(pParse->db, pVector, 0); + } + return pRet; +} + +/* +** If expression pExpr is of type TK_SELECT, generate code to evaluate +** it. Return the register in which the result is stored (or, if the +** sub-select returns more than one column, the first in an array +** of registers in which the result is stored). +** +** If pExpr is not a TK_SELECT expression, return 0. +*/ +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); + } +#endif + return reg; +} + +/* +** Argument pVector points to a vector expression - either a TK_VECTOR +** or TK_SELECT that returns more than one column. This function returns +** the register number of a register that contains the value of +** element iField of the vector. +** +** If pVector is a TK_SELECT expression, then code for it must have +** already been generated using the exprCodeSubselect() routine. In this +** case parameter regSelect should be the first in an array of registers +** containing the results of the sub-select. +** +** If pVector is of type TK_VECTOR, then code for the requested field +** is generated. In this case (*pRegFree) may be set to the number of +** a temporary register to be freed by the caller before returning. +** +** Before returning, output parameter (*ppExpr) is set to point to the +** Expr object corresponding to element iElem of the vector. +*/ +static int exprVectorRegister( + Parse *pParse, /* Parse context */ + Expr *pVector, /* Vector to extract element from */ + int iField, /* Field to extract from pVector */ + int regSelect, /* First in array of registers */ + Expr **ppExpr, /* OUT: Expression element */ + int *pRegFree /* OUT: Temp register to free */ +){ + u8 op = pVector->op; + assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT ); + if( op==TK_REGISTER ){ + *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField); + return pVector->iTable+iField; + } + if( op==TK_SELECT ){ + *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; + return regSelect+iField; + } + *ppExpr = pVector->x.pList->a[iField].pExpr; + return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); +} + +/* +** Expression pExpr is a comparison between two vector values. Compute +** the result of the comparison (1, 0, or NULL) and write that +** result into register dest. +** +** The caller must satisfy the following preconditions: +** +** if pExpr->op==TK_IS: op==TK_EQ and p5==SQLITE_NULLEQ +** if pExpr->op==TK_ISNOT: op==TK_NE and p5==SQLITE_NULLEQ +** otherwise: op==pExpr->op and p5==0 +*/ +static void codeVectorCompare( + Parse *pParse, /* Code generator context */ + Expr *pExpr, /* The comparison operation */ + int dest, /* Write results into this register */ + u8 op, /* Comparison operator */ + u8 p5 /* SQLITE_NULLEQ or zero */ +){ + Vdbe *v = pParse->pVdbe; + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; + int nLeft = sqlite3ExprVectorSize(pLeft); + int i; + int regLeft = 0; + int regRight = 0; + u8 opx = op; + int addrDone = sqlite3VdbeMakeLabel(v); + + if( nLeft!=sqlite3ExprVectorSize(pRight) ){ + sqlite3ErrorMsg(pParse, "row value misused"); + return; + } + assert( pExpr->op==TK_EQ || pExpr->op==TK_NE + || pExpr->op==TK_IS || pExpr->op==TK_ISNOT + || pExpr->op==TK_LT || pExpr->op==TK_GT + || pExpr->op==TK_LE || pExpr->op==TK_GE + ); + assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ) + || (pExpr->op==TK_ISNOT && op==TK_NE) ); + assert( p5==0 || pExpr->op!=op ); + assert( p5==SQLITE_NULLEQ || pExpr->op==op ); + + p5 |= SQLITE_STOREP2; + if( opx==TK_LE ) opx = TK_LT; + if( opx==TK_GE ) opx = TK_GT; + + regLeft = exprCodeSubselect(pParse, pLeft); + regRight = exprCodeSubselect(pParse, pRight); + + for(i=0; 1 /*Loop exits by "break"*/; i++){ + int regFree1 = 0, regFree2 = 0; + Expr *pL, *pR; + int r1, r2; + assert( i>=0 && i0 ) sqlite3ExprCachePush(pParse); + r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); + r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); + codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); + 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); + testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); + testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); + if( i>0 ) sqlite3ExprCachePop(pParse); + if( i==nLeft-1 ){ + break; + } + if( opx==TK_EQ ){ + sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v); + p5 |= SQLITE_KEEPNULL; + }else if( opx==TK_NE ){ + sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v); + p5 |= SQLITE_KEEPNULL; + }else{ + assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE ); + sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone); + VdbeCoverageIf(v, op==TK_LT); + VdbeCoverageIf(v, op==TK_GT); + VdbeCoverageIf(v, op==TK_LE); + VdbeCoverageIf(v, op==TK_GE); + if( i==nLeft-2 ) opx = op; + } + } + sqlite3VdbeResolveLabel(v, addrDone); +} + #if SQLITE_MAX_EXPR_DEPTH>0 /* ** Check that argument nHeight is less than or equal to the maximum @@ -86344,7 +92553,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ ** is allocated to hold the integer text and the dequote flag is ignored. */ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( - sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */ + sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */ int op, /* Expression opcode */ const Token *pToken, /* Token argument. Might be NULL */ int dequote /* True to dequote */ @@ -86353,6 +92562,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( int nExtra = 0; int iValue = 0; + assert( db!=0 ); if( pToken ){ if( op!=TK_INTEGER || pToken->z==0 || sqlite3GetInt32(pToken->z, &iValue)==0 ){ @@ -86360,24 +92570,23 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( assert( iValue>=0 ); } } - pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra); + pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ + memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ - pNew->flags |= EP_IntValue; + pNew->flags |= EP_IntValue|EP_Leaf; pNew->u.iValue = iValue; }else{ - int c; pNew->u.zToken = (char*)&pNew[1]; assert( pToken->z!=0 || pToken->n==0 ); if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); pNew->u.zToken[pToken->n] = 0; - if( dequote && nExtra>=3 - && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){ + if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ + if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted; sqlite3Dequote(pNew->u.zToken); - if( c=='"' ) pNew->flags |= EP_DblQuoted; } } } @@ -86399,7 +92608,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr( ){ Token x; x.z = zToken; - x.n = zToken ? sqlite3Strlen30(zToken) : 0; + x.n = sqlite3Strlen30(zToken); return sqlite3ExprAlloc(db, op, &x, 0); } @@ -86443,15 +92652,19 @@ SQLITE_PRIVATE Expr *sqlite3PExpr( Parse *pParse, /* Parsing context */ int op, /* Expression opcode */ Expr *pLeft, /* Left operand */ - Expr *pRight, /* Right operand */ - const Token *pToken /* Argument token */ + 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 = sqlite3ExprAlloc(pParse->db, op & TKFLG_MASK, pToken, 1); + p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = op & TKFLG_MASK; + p->iAgg = -1; + } sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); } if( p ) { @@ -86460,6 +92673,22 @@ SQLITE_PRIVATE Expr *sqlite3PExpr( return p; } +/* +** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due +** do a memory allocation failure) then delete the pSelect object. +*/ +SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ + if( pExpr ){ + pExpr->x.pSelect = pSelect; + ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery); + sqlite3ExprSetHeightAndFlags(pParse, pExpr); + }else{ + assert( pParse->db->mallocFailed ); + sqlite3SelectDelete(pParse->db, pSelect); + } +} + + /* ** If the expression is always either TRUE or FALSE (respectively), ** then return 1. If one cannot determine the truth value of the @@ -86538,7 +92767,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token * ** variable number. ** ** Wildcards of the form "?nnn" are assigned the number "nnn". We make -** sure "nnn" is not too be to avoid a denial of service attack when +** sure "nnn" is not too big to avoid a denial of service attack when ** the SQL statement comes from an external source. ** ** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number @@ -86546,28 +92775,34 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token * ** instance of the wildcard, the next sequential variable number is ** assigned. */ -SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ +SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){ sqlite3 *db = pParse->db; const char *z; + ynVar x; if( pExpr==0 ) return; assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); z = pExpr->u.zToken; assert( z!=0 ); assert( z[0]!=0 ); + assert( n==(u32)sqlite3Strlen30(z) ); if( z[1]==0 ){ /* Wildcard of the form "?". Assign the next variable number */ assert( z[0]=='?' ); - pExpr->iColumn = (ynVar)(++pParse->nVar); + x = (ynVar)(++pParse->nVar); }else{ - ynVar x = 0; - u32 n = sqlite3Strlen30(z); + int doAdd = 0; if( z[0]=='?' ){ /* Wildcard of the form "?nnn". Convert "nnn" to an integer and ** use it as the variable number */ i64 i; - int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8); - pExpr->iColumn = x = (ynVar)i; + int bOk; + if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/ + i = z[1]-'0'; /* The common case of ?N for a single digit N */ + bOk = 1; + }else{ + bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8); + } testcase( i==0 ); testcase( i==1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); @@ -86575,41 +92810,32 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); - x = 0; + return; } - if( i>pParse->nVar ){ - pParse->nVar = (int)i; + x = (ynVar)i; + if( x>pParse->nVar ){ + pParse->nVar = (int)x; + doAdd = 1; + }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){ + doAdd = 1; } }else{ /* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable ** number as the prior appearance of the same name, or if the name ** has never appeared before, reuse the same variable number */ - ynVar i; - for(i=0; inzVar; i++){ - if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){ - pExpr->iColumn = x = (ynVar)i+1; - break; - } - } - if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar); - } - if( x>0 ){ - if( x>pParse->nzVar ){ - char **a; - a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0])); - if( a==0 ) return; /* Error reported through db->mallocFailed */ - pParse->azVar = a; - memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0])); - pParse->nzVar = x; - } - if( z[0]!='?' || pParse->azVar[x-1]==0 ){ - sqlite3DbFree(db, pParse->azVar[x-1]); - pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n); + x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n); + if( x==0 ){ + x = (ynVar)(++pParse->nVar); + doAdd = 1; } } - } - if( !pParse->nErr && pParse->nVar>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ + if( doAdd ){ + pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); + } + } + pExpr->iColumn = x; + if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "too many SQL variables"); } } @@ -86617,26 +92843,37 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){ /* ** Recursively delete an expression tree. */ -SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ - if( p==0 ) return; +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 ); - if( !ExprHasProperty(p, EP_TokenOnly) ){ +#ifdef SQLITE_DEBUG + if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ + assert( p->pLeft==0 ); + assert( p->pRight==0 ); + assert( p->x.pSelect==0 ); + } +#endif + if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( p->x.pList==0 || p->pRight==0 ); - sqlite3ExprDelete(db, p->pLeft); - sqlite3ExprDelete(db, p->pRight); - if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); + if( p->pRight ){ + sqlite3ExprDeleteNN(db, p->pRight); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); } } + if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( !ExprHasProperty(p, EP_Static) ){ - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } } +SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ + if( p ) sqlite3ExprDeleteNN(db, p); +} /* ** Return the number of bytes allocated for the expression structure @@ -86688,7 +92925,7 @@ static int dupedExprStructSize(Expr *p, int flags){ assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); - if( 0==(flags&EXPRDUP_REDUCE) ){ + if( 0==flags || p->op==TK_SELECT_COLUMN ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); @@ -86750,87 +92987,94 @@ static int dupedExprSize(Expr *p, int flags){ ** if any. Before returning, *pzBuffer is set to the first byte past the ** portion of the buffer copied into by this function. */ -static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){ - Expr *pNew = 0; /* Value to return */ - assert( flags==0 || flags==EXPRDUP_REDUCE ); - if( p ){ - const int isReduced = (flags&EXPRDUP_REDUCE); - u8 *zAlloc; - u32 staticFlag = 0; +static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ + Expr *pNew; /* Value to return */ + u8 *zAlloc; /* Memory space from which to build Expr object */ + u32 staticFlag; /* EP_Static if space not obtained from malloc */ - assert( pzBuffer==0 || isReduced ); + assert( db!=0 ); + assert( p ); + assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE ); + assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE ); - /* Figure out where to write the new Expr structure. */ - if( pzBuffer ){ - zAlloc = *pzBuffer; - staticFlag = EP_Static; + /* Figure out where to write the new Expr structure. */ + if( pzBuffer ){ + zAlloc = *pzBuffer; + staticFlag = EP_Static; + }else{ + zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); + staticFlag = 0; + } + pNew = (Expr *)zAlloc; + + if( pNew ){ + /* Set nNewSize to the size allocated for the structure pointed to + ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or + ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed + ** by the copy of the p->u.zToken string (if any). + */ + const unsigned nStructSize = dupedExprStructSize(p, dupFlags); + const int nNewSize = nStructSize & 0xfff; + int nToken; + if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ + nToken = sqlite3Strlen30(p->u.zToken) + 1; }else{ - zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags)); + nToken = 0; + } + if( dupFlags ){ + assert( ExprHasProperty(p, EP_Reduced)==0 ); + memcpy(zAlloc, p, nNewSize); + }else{ + u32 nSize = (u32)exprStructSize(p); + memcpy(zAlloc, p, nSize); + if( nSizeu.zToken string (if any). - */ - const unsigned nStructSize = dupedExprStructSize(p, flags); - const int nNewSize = nStructSize & 0xfff; - int nToken; - if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nToken = sqlite3Strlen30(p->u.zToken) + 1; + /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ + pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); + pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); + pNew->flags |= staticFlag; + + /* Copy the p->u.zToken string, if any. */ + if( nToken ){ + char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize]; + memcpy(zToken, p->u.zToken, nToken); + } + + if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ + /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ + if( ExprHasProperty(p, EP_xIsSelect) ){ + pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ - nToken = 0; + pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); } - if( isReduced ){ - assert( ExprHasProperty(p, EP_Reduced)==0 ); - memcpy(zAlloc, p, nNewSize); - }else{ - u32 nSize = (u32)exprStructSize(p); - memcpy(zAlloc, p, nSize); - if( nSizepLeft and pNew->pRight. */ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ + 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; } - - /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ - pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); - pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); - pNew->flags |= staticFlag; - - /* Copy the p->u.zToken string, if any. */ - if( nToken ){ - char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize]; - memcpy(zToken, p->u.zToken, nToken); + if( pzBuffer ){ + *pzBuffer = zAlloc; } - - if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){ - /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ - if( ExprHasProperty(p, EP_xIsSelect) ){ - pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced); + }else{ + if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ + if( pNew->op==TK_SELECT_COLUMN ){ + pNew->pLeft = p->pLeft; + assert( p->iColumn==0 || p->pRight==0 ); + assert( p->pRight==0 || p->pRight==p->pLeft ); }else{ - pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced); - } - } - - /* Fill in pNew->pLeft and pNew->pRight. */ - if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ - zAlloc += dupedExprNodeSize(p, flags); - if( ExprHasProperty(pNew, EP_Reduced) ){ - pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc); - pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc); - } - if( pzBuffer ){ - *pzBuffer = zAlloc; - } - }else{ - if( !ExprHasProperty(p, EP_TokenOnly) ){ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); - pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); } + pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); } - } } return pNew; @@ -86882,26 +93126,40 @@ static With *withDup(sqlite3 *db, With *p){ */ SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){ assert( flags==0 || flags==EXPRDUP_REDUCE ); - return exprDup(db, p, flags, 0); + return p ? exprDup(db, p, flags, 0) : 0; } SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ ExprList *pNew; struct ExprList_item *pItem, *pOldItem; int i; + Expr *pPriorSelectCol = 0; + assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); + pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; - pNew->nExpr = i = p->nExpr; - if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){} - pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) ); - if( pItem==0 ){ - sqlite3DbFree(db, pNew); - return 0; - } + pNew->nExpr = p->nExpr; + pItem = pNew->a; pOldItem = p->a; for(i=0; inExpr; i++, pItem++, pOldItem++){ Expr *pOldExpr = pOldItem->pExpr; + Expr *pNewExpr; pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags); + if( pOldExpr + && pOldExpr->op==TK_SELECT_COLUMN + && (pNewExpr = pItem->pExpr)!=0 + ){ + assert( pNewExpr->iColumn==0 || i>0 ); + if( pNewExpr->iColumn==0 ){ + assert( pOldExpr->pLeft==pOldExpr->pRight ); + pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight; + }else{ + assert( i>0 ); + assert( pItem[-1].pExpr!=0 ); + assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 ); + assert( pPriorSelectCol==pItem[-1].pExpr->pLeft ); + pNewExpr->pLeft = pPriorSelectCol; + } + } pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); pItem->sortOrder = pOldItem->sortOrder; @@ -86924,9 +93182,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ SrcList *pNew; int i; int nByte; + assert( db!=0 ); if( p==0 ) return 0; nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); - pNew = sqlite3DbMallocRaw(db, nByte ); + pNew = sqlite3DbMallocRawNN(db, nByte ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ @@ -86951,7 +93210,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ } pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ - pTab->nRef++; + pTab->nTabRef++; } pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags); @@ -86963,13 +93222,14 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ IdList *pNew; int i; + assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); + pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) ); if( pNew==0 ) return 0; pNew->nId = p->nId; - pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) ); + pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) ); if( pNew->a==0 ){ - sqlite3DbFree(db, pNew); + sqlite3DbFreeNN(db, pNew); return 0; } /* Note that because the size of the allocation for p->a[] is not @@ -86983,32 +93243,41 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ } return pNew; } -SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ - Select *pNew, *pPrior; - if( p==0 ) return 0; - pNew = sqlite3DbMallocRaw(db, sizeof(*p) ); - if( pNew==0 ) return 0; - pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags); - pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags); - pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags); - pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags); - pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags); - pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags); - pNew->op = p->op; - pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags); - if( pPrior ) pPrior->pNext = pNew; - pNew->pNext = 0; - pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); - pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags); - pNew->iLimit = 0; - pNew->iOffset = 0; - pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; - pNew->nSelectRow = p->nSelectRow; - pNew->pWith = withDup(db, p->pWith); - sqlite3SelectSetName(pNew, p->zSelName); - return pNew; +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ + Select *pRet = 0; + Select *pNext = 0; + Select **pp = &pRet; + Select *p; + + assert( db!=0 ); + for(p=pDup; p; p=p->pPrior){ + Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) ); + if( pNew==0 ) break; + pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags); + pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags); + pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags); + pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags); + pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags); + pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags); + pNew->op = p->op; + pNew->pNext = pNext; + pNew->pPrior = 0; + pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); + pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags); + pNew->iLimit = 0; + pNew->iOffset = 0; + pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->nSelectRow = p->nSelectRow; + pNew->pWith = withDup(db, p->pWith); + sqlite3SelectSetName(pNew, p->zSelName); + *pp = pNew; + pp = &pNew->pPrior; + pNext = pNew; + } + + return pRet; } #else SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ @@ -87022,6 +93291,13 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ ** Add a new element to the end of an expression list. If pList is ** initially NULL, then create a new expression list. ** +** The pList argument must be either NULL or a pointer to an ExprList +** obtained from a prior call to sqlite3ExprListAppend(). This routine +** may not be used with an ExprList obtained from sqlite3ExprListDup(). +** Reason: This routine assumes that the number of slots in pList->a[] +** is a power of two. That is true for sqlite3ExprListAppend() returns +** but is not necessarily true from the return value of sqlite3ExprListDup(). +** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. @@ -87031,29 +93307,29 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ + struct ExprList_item *pItem; sqlite3 *db = pParse->db; + assert( db!=0 ); if( pList==0 ){ - pList = sqlite3DbMallocZero(db, sizeof(ExprList) ); + pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) ); if( pList==0 ){ goto no_mem; } - pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0])); - if( pList->a==0 ) goto no_mem; + pList->nExpr = 0; }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ - struct ExprList_item *a; - assert( pList->nExpr>0 ); - a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0])); - if( a==0 ){ + ExprList *pNew; + pNew = sqlite3DbRealloc(db, pList, + sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0])); + if( pNew==0 ){ goto no_mem; } - pList->a = a; - } - assert( pList->a!=0 ); - if( 1 ){ - struct ExprList_item *pItem = &pList->a[pList->nExpr++]; - memset(pItem, 0, sizeof(*pItem)); - pItem->pExpr = pExpr; + pList = pNew; } + pItem = &pList->a[pList->nExpr++]; + assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) ); + assert( offsetof(struct ExprList_item,pExpr)==0 ); + memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName)); + pItem->pExpr = pExpr; return pList; no_mem: @@ -87063,6 +93339,74 @@ no_mem: return 0; } +/* +** pColumns and pExpr form a vector assignment which is part of the SET +** clause of an UPDATE statement. Like this: +** +** (a,b,c) = (expr1,expr2,expr3) +** Or: (a,b,c) = (SELECT x,y,z FROM ....) +** +** For each term of the vector assignment, append new entries to the +** expression list pList. In the case of a subquery on the RHS, append +** TK_SELECT_COLUMN expressions. +*/ +SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + IdList *pColumns, /* List of names of LHS of the assignment */ + Expr *pExpr /* Vector expression to be appended. Might be NULL */ +){ + sqlite3 *db = pParse->db; + int n; + int i; + int iFirst = pList ? pList->nExpr : 0; + /* pColumns can only be NULL due to an OOM but an OOM will cause an + ** exit prior to this routine being invoked */ + if( NEVER(pColumns==0) ) goto vector_append_error; + if( pExpr==0 ) goto vector_append_error; + + /* If the RHS is a vector, then we can immediately check to see that + ** the size of the RHS and LHS match. But if the RHS is a SELECT, + ** wildcards ("*") in the result set of the SELECT must be expanded before + ** we can do the size check, so defer the size check until code generation. + */ + if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){ + sqlite3ErrorMsg(pParse, "%d columns assigned %d values", + pColumns->nId, n); + goto vector_append_error; + } + + for(i=0; inId; i++){ + Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i); + pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); + if( pList ){ + assert( pList->nExpr==iFirst+i+1 ); + pList->a[pList->nExpr-1].zName = pColumns->a[i].zName; + pColumns->a[i].zName = 0; + } + } + + if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){ + Expr *pFirst = pList->a[iFirst].pExpr; + assert( pFirst!=0 ); + assert( pFirst->op==TK_SELECT_COLUMN ); + + /* Store the SELECT statement in pRight so it will be deleted when + ** sqlite3ExprListDelete() is called */ + pFirst->pRight = pExpr; + pExpr = 0; + + /* Remember the size of the LHS in iTable so that we can check that + ** the RHS and LHS sizes match during code generation. */ + pFirst->iTable = pColumns->nId; + } + +vector_append_error: + sqlite3ExprDelete(db, pExpr); + sqlite3IdListDelete(db, pColumns); + return pList; +} + /* ** Set the sort order for the last element on the given ExprList. */ @@ -87098,7 +93442,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetName( pItem = &pList->a[pList->nExpr-1]; assert( pItem->zName==0 ); pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); - if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName); + if( dequote ) sqlite3Dequote(pItem->zName); } } @@ -87147,18 +93491,20 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength( /* ** Delete an entire expression list. */ -SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ - int i; - struct ExprList_item *pItem; - if( pList==0 ) return; - assert( pList->a!=0 || pList->nExpr==0 ); - for(pItem=pList->a, i=0; inExpr; i++, pItem++){ +static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ + int i = pList->nExpr; + struct ExprList_item *pItem = pList->a; + assert( pList->nExpr>0 ); + do{ sqlite3ExprDelete(db, pItem->pExpr); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zSpan); - } - sqlite3DbFree(db, pList->a); - sqlite3DbFree(db, pList); + pItem++; + }while( --i>0 ); + sqlite3DbFreeNN(db, pList); +} +SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ + if( pList ) exprListDeleteNN(db, pList); } /* @@ -87168,15 +93514,28 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ int i; u32 m = 0; - if( pList ){ - for(i=0; inExpr; i++){ - Expr *pExpr = pList->a[i].pExpr; - if( ALWAYS(pExpr) ) m |= pExpr->flags; - } + assert( pList!=0 ); + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + assert( pExpr!=0 ); + m |= pExpr->flags; } return m; } +/* +** This is a SELECT-node callback for the expression walker that +** always "fails". By "fail" in this case, we mean set +** pWalker->eCode to zero and abort. +** +** This callback is used by multiple expression walkers. +*/ +SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ + UNUSED_PARAMETER(NotUsed); + pWalker->eCode = 0; + return WRC_Abort; +} + /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The @@ -87233,10 +93592,12 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_AGG_COLUMN ); if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; - }else{ - pWalker->eCode = 0; - return WRC_Abort; } + /* Fall through */ + case TK_IF_NULL_ROW: + testcase( pExpr->op==TK_IF_NULL_ROW ); + pWalker->eCode = 0; + return WRC_Abort; case TK_VARIABLE: if( pWalker->eCode==5 ){ /* Silently convert bound parameters that appear inside of CREATE @@ -87251,22 +93612,19 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ } /* Fall through */ default: - testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ - testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */ + testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */ + testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */ return WRC_Continue; } } -static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ - UNUSED_PARAMETER(NotUsed); - pWalker->eCode = 0; - return WRC_Abort; -} static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = initFlag; w.xExprCallback = exprNodeIsConstant; - w.xSelectCallback = selectNodeIsConstant; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif w.u.iCur = iCur; sqlite3WalkExpr(&w, p); return w.eCode; @@ -87304,6 +93662,65 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){ return exprIsConst(p, 3, iCur); } + +/* +** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy(). +*/ +static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ + ExprList *pGroupBy = pWalker->u.pGroupBy; + int i; + + /* Check if pExpr is identical to any GROUP BY term. If so, consider + ** it constant. */ + for(i=0; inExpr; i++){ + Expr *p = pGroupBy->a[i].pExpr; + if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ + CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); + if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){ + return WRC_Prune; + } + } + } + + /* Check if pExpr is a sub-select. If so, consider it variable. */ + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + pWalker->eCode = 0; + return WRC_Abort; + } + + return exprNodeIsConstant(pWalker, pExpr); +} + +/* +** Walk the expression tree passed as the first argument. Return non-zero +** if the expression consists entirely of constants or copies of terms +** in pGroupBy that sort with the BINARY collation sequence. +** +** This routine is used to determine if a term of the HAVING clause can +** be promoted into the WHERE clause. In order for such a promotion to work, +** the value of the HAVING clause term must be the same for all members of +** a "group". The requirement that the GROUP BY term must be BINARY +** assumes that no other collating sequence will have a finer-grained +** grouping than binary. In other words (A=B COLLATE binary) implies +** A=B in every other collating sequence. The requirement that the +** GROUP BY be BINARY is stricter than necessary. It would also work +** to promote HAVING clauses that use the same alternative collating +** sequence as the GROUP BY term, but that is much harder to check, +** alternative collating sequences are uncommon, and this is only an +** optimization, so we take the easy way out and simply require the +** GROUP BY to use the BINARY collating sequence. +*/ +SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){ + Walker w; + w.eCode = 1; + w.xExprCallback = exprNodeIsConstantOrGroupBy; + w.xSelectCallback = 0; + w.u.pGroupBy = pGroupBy; + w.pParse = pParse; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + /* ** Walk an expression tree. Return non-zero if the expression is constant ** or a function call with constant arguments. Return and 0 if there @@ -87325,10 +93742,12 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ */ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = 1; w.xExprCallback = sqlite3ExprWalkNoop; - w.xSelectCallback = selectNodeIsConstant; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif sqlite3WalkExpr(&w, p); return w.eCode==0; } @@ -87342,6 +93761,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 an expression is an integer literal that fits in a signed 32-bit ** integer, then the EP_IntValue flag will have already been set */ @@ -87397,8 +93817,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ case TK_BLOB: return 0; case TK_COLUMN: - assert( p->pTab!=0 ); 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); default: return 1; @@ -87456,23 +93876,22 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ } /* -** Return true if we are able to the IN operator optimization on a -** query of the form -** -** x IN (SELECT ...) -** -** Where the SELECT... clause is as specified by the parameter to this -** routine. -** -** The Select object passed in has already been preprocessed and no -** errors have been found. +** pX is the RHS of an IN operator. If pX is a SELECT statement +** that can be simplified to a direct table access, then return +** a pointer to the SELECT statement. If pX is not a SELECT statement, +** or if the SELECT statement needs to be manifested into a transient +** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY -static int isCandidateForInOpt(Select *p){ +static Select *isCandidateForInOpt(Expr *pX){ + Select *p; SrcList *pSrc; ExprList *pEList; Table *pTab; - if( p==0 ) return 0; /* right-hand side of IN is SELECT */ + int i; + if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */ + if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ + p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); @@ -87488,25 +93907,22 @@ static int isCandidateForInOpt(Select *p){ if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ pTab = pSrc->a[0].pTab; - if( NEVER(pTab==0) ) return 0; + assert( pTab!=0 ); assert( pTab->pSelect==0 ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; - if( pEList->nExpr!=1 ) return 0; /* One column in the result set */ - if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */ - return 1; + assert( pEList!=0 ); + /* All SELECT results must be columns. */ + for(i=0; inExpr; i++){ + Expr *pRes = pEList->a[i].pExpr; + if( pRes->op!=TK_COLUMN ) return 0; + assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */ + } + return p; } #endif /* SQLITE_OMIT_SUBQUERY */ -/* -** Code an OP_Once instruction and allocate space for its flag. Return the -** address of the new instruction. -*/ -SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){ - Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ - return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++); -} - +#ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code that checks the left-most column of index table iCur to see if ** it contains any NULL entries. Cause the register at regHasNull to be set @@ -87522,6 +93938,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ VdbeComment((v, "first_entry_in(%d)", iCur)); sqlite3VdbeJumpHere(v, addr1); } +#endif #ifndef SQLITE_OMIT_SUBQUERY @@ -87566,7 +93983,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: ** -** SELECT FROM +** SELECT , ... FROM
    ** ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then @@ -87582,14 +93999,14 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** ** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate ** through the set members) then the b-tree must not contain duplicates. -** An epheremal table must be used unless the selected is guaranteed -** to be unique - either because it is an INTEGER PRIMARY KEY or it -** has a UNIQUE constraint or UNIQUE index. +** An epheremal table must be used unless the selected columns are guaranteed +** to be unique - either because it is an INTEGER PRIMARY KEY or due to +** a UNIQUE constraint or index. ** ** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used ** for fast set membership tests) then an epheremal table must -** be used unless is an INTEGER PRIMARY KEY or an index can -** be found with as its left-most column. +** be used unless is a single INTEGER PRIMARY KEY column or an +** index can be found with the specified as its left-most. ** ** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and ** if the RHS of the IN operator is a list (not a subquery) then this @@ -87610,9 +94027,26 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** the value in that register will be NULL if the b-tree contains one or more ** NULL values, and it will be some non-NULL value if the b-tree contains no ** NULL values. +** +** If the aiMap parameter is not NULL, it must point to an array containing +** one element for each column returned by the SELECT statement on the RHS +** of the IN(...) operator. The i'th entry of the array is populated with the +** offset of the index column that matches the i'th column returned by the +** SELECT. For example, if the expression and selected index are: +** +** (?,?,?) IN (SELECT a, b, c FROM t1) +** CREATE INDEX i1 ON t1(b, c, a); +** +** then aiMap[] is populated with {2, 0, 1}. */ #ifndef SQLITE_OMIT_SUBQUERY -SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ +SQLITE_PRIVATE int sqlite3FindInIndex( + Parse *pParse, /* Parsing context */ + 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 */ +){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab = pParse->nTab++; /* Cursor of the RHS table */ @@ -87622,38 +94056,46 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int assert( pX->op==TK_IN ); mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; + /* If the RHS of this IN(...) operator is a SELECT, and if it matters + ** whether or not the SELECT result contains NULL values, check whether + ** or not NULL is actually possible (it may not be, for example, due + ** to NOT NULL constraints in the schema). If no NULL values are possible, + ** set prRhsHasNull to 0 before continuing. */ + if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){ + int i; + ExprList *pEList = pX->x.pSelect->pEList; + for(i=0; inExpr; i++){ + if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break; + } + if( i==pEList->nExpr ){ + prRhsHasNull = 0; + } + } + /* Check to see if an existing table or index can be used to ** satisfy the query. This is preferable to generating a new - ** ephemeral table. - */ - p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0); - if( pParse->nErr==0 && isCandidateForInOpt(p) ){ + ** ephemeral table. */ + if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table
    . */ - Expr *pExpr; /* Expression */ - i16 iCol; /* Index of column */ i16 iDb; /* Database idx for pTab */ + ExprList *pEList = p->pEList; + int nExpr = pEList->nExpr; - assert( p ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ pTab = p->pSrc->a[0].pTab; - pExpr = p->pEList->a[0].pExpr; - iCol = (i16)pExpr->iColumn; - + /* Code an OP_Transaction and OP_TableLock for
    . */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - /* This function is only called from two places. In both cases the vdbe - ** has already been allocated. So assume sqlite3GetVdbe() is always - ** successful here. - */ - assert(v); - if( iCol<0 ){ - int iAddr = sqlite3CodeOnce(pParse); + assert(v); /* sqlite3GetVdbe() has always been previously called */ + if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ + /* The "x IN (SELECT rowid FROM table)" case */ + int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); @@ -87662,44 +94104,114 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int sqlite3VdbeJumpHere(v, iAddr); }else{ Index *pIdx; /* Iterator variable */ + int affinity_ok = 1; + int i; - /* The collation sequence used by the comparison. If an index is to - ** be used in place of a temp-table, it must be ordered according - ** to this collation sequence. */ - CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr); - - /* Check that the affinity that will be used to perform the - ** comparison is the same as the affinity of the column. If - ** it is not, it is not possible to use any index. - */ - int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity); - - for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ - if( (pIdx->aiColumn[0]==iCol) - && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq - && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx))) - ){ - int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); - sqlite3VdbeSetP4KeyInfo(pParse, pIdx); - VdbeComment((v, "%s", pIdx->zName)); - assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); - eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; - - if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ - *prRhsHasNull = ++pParse->nMem; - sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); - } - sqlite3VdbeJumpHere(v, iAddr); + /* Check that the affinity that will be used to perform each + ** comparison is the same as the affinity of each column in table + ** on the RHS of the IN operator. If it not, it is not possible to + ** use any index of the RHS table. */ + for(i=0; ipLeft, i); + int iCol = pEList->a[i].pExpr->iColumn; + char idxaff = sqlite3TableColumnAffinity(pTab,iCol); /* RHS table */ + char cmpaff = sqlite3CompareAffinity(pLhs, idxaff); + testcase( cmpaff==SQLITE_AFF_BLOB ); + testcase( cmpaff==SQLITE_AFF_TEXT ); + switch( cmpaff ){ + case SQLITE_AFF_BLOB: + break; + case SQLITE_AFF_TEXT: + /* sqlite3CompareAffinity() only returns TEXT if one side or the + ** other has no affinity and the other side is TEXT. Hence, + ** the only way for cmpaff to be TEXT is for idxaff to be TEXT + ** and for the term on the LHS of the IN to have no affinity. */ + assert( idxaff==SQLITE_AFF_TEXT ); + break; + default: + affinity_ok = sqlite3IsNumericAffinity(idxaff); } } - } - } + + if( affinity_ok ){ + /* Search for an existing index that will work for this IN operator */ + for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){ + Bitmask colUsed; /* Columns of the index used */ + Bitmask mCol; /* Mask for the current column */ + if( pIdx->nColumnnColumn==BMS-2 ); + testcase( pIdx->nColumn==BMS-1 ); + if( pIdx->nColumn>=BMS-1 ) continue; + if( mustBeUnique ){ + if( pIdx->nKeyCol>nExpr + ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx)) + ){ + continue; /* This index is not unique over the IN RHS columns */ + } + } + + colUsed = 0; /* Columns of index used so far */ + for(i=0; ipLeft, i); + Expr *pRhs = pEList->a[i].pExpr; + CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + int j; + + assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); + for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; + assert( pIdx->azColl[j] ); + if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){ + continue; + } + break; + } + if( j==nExpr ) break; + mCol = MASKBIT(j); + if( mCol & colUsed ) break; /* Each column used only once */ + colUsed |= mCol; + if( aiMap ) aiMap[i] = j; + } + + assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) ); + if( colUsed==(MASKBIT(nExpr)-1) ){ + /* If we reach this point, that means the index pIdx is usable */ + int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); +#ifndef SQLITE_OMIT_EXPLAIN + sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0, + sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName), + P4_DYNAMIC); +#endif + sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + VdbeComment((v, "%s", pIdx->zName)); + assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); + eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; + + if( prRhsHasNull ){ +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + i64 mask = (1<nMem; + if( nExpr==1 ){ + sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); + } + } + sqlite3VdbeJumpHere(v, iAddr); + } + } /* End loop over indexes */ + } /* End if( affinity_ok ) */ + } /* End if not an rowid index */ + } /* End attempt to optimize using an index */ /* If no preexisting index is available for the IN clause ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery - ** and the RHS is not contant or has two or fewer terms, + ** and the RHS is not constant or has two or fewer terms, ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ @@ -87710,7 +94222,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int ){ eType = IN_INDEX_NOOP; } - if( eType==0 ){ /* Could not find an existing table or index to use as the RHS b-tree. @@ -87732,10 +94243,85 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int }else{ pX->iTable = iTab; } + + if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){ + int i, n; + n = sqlite3ExprVectorSize(pX->pLeft); + for(i=0; ipLeft; + int nVal = sqlite3ExprVectorSize(pLeft); + Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0; + char *zRet; + + assert( pExpr->op==TK_IN ); + zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); + if( zRet ){ + int i; + for(i=0; ipEList->a[i].pExpr, a); + }else{ + zRet[i] = a; + } + } + zRet[nVal] = '\0'; + } + return zRet; +} +#endif + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Load the Parse object passed as the first argument with an error +** message of the form: +** +** "sub-select returns N columns - expected M" +*/ +SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ + const char *zFmt = "sub-select returns %d columns - expected %d"; + sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); +} +#endif + +/* +** Expression pExpr is a vector that has been used in a context where +** it is not permitted. If pExpr is a sub-select vector, this routine +** loads the Parse object with a message of the form: +** +** "sub-select returns N columns - expected 1" +** +** Or, if it is a regular scalar vector: +** +** "row value misused" +*/ +SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ +#ifndef SQLITE_OMIT_SUBQUERY + if( pExpr->flags & EP_xIsSelect ){ + sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); + }else +#endif + { + sqlite3ErrorMsg(pParse, "row value misused"); + } +} + /* ** Generate code for scalar subqueries used as a subquery expression, EXISTS, ** or IN operators. Examples: @@ -87761,7 +94347,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int ** value to non-NULL if the RHS is NULL-free. ** ** For a SELECT or EXISTS operator, return the register that holds the -** result. For IN operators or if an error occurs, the return value is 0. +** 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( @@ -87776,8 +94364,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( if( NEVER(v==0) ) return 0; sqlite3ExprCachePush(pParse); - /* This code must be run in its entirety every time it is encountered - ** if any of the following is true: + /* The evaluation of the IN/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 @@ -87787,7 +94375,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v); + jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } #ifndef SQLITE_OMIT_EXPLAIN @@ -87803,17 +94391,18 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( switch( pExpr->op ){ case TK_IN: { - char affinity; /* Affinity of the LHS of the IN */ int addr; /* Address of OP_OpenEphemeral instruction */ Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ - - affinity = sqlite3ExprAffinity(pLeft); + int nVal; /* Size of vector pLeft */ + + nVal = sqlite3ExprVectorSize(pLeft); + assert( !isRowid || nVal==1 ); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' ** expression it is handled the same way. An ephemeral table is - ** filled with single-field index keys representing the results - ** from the SELECT or the . + ** 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 @@ -87824,8 +94413,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** is used. */ pExpr->iTable = pParse->nTab++; - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid); - pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1); + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, + pExpr->iTable, (isRowid?0:nVal)); + pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* Case 1: expr IN (SELECT ...) @@ -87834,27 +94424,36 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; - SelectDest dest; - ExprList *pEList; + ExprList *pEList = pSelect->pEList; assert( !isRowid ); - sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); - dest.affSdst = (u8)affinity; - assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); - pSelect->iLimit = 0; - testcase( pSelect->selFlags & SF_Distinct ); - testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ - if( sqlite3Select(pParse, pSelect, &dest) ){ - sqlite3KeyInfoUnref(pKeyInfo); - return 0; + /* 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 + ); + } } - pEList = pSelect->pEList; - assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ - assert( pEList!=0 ); - assert( pEList->nExpr>0 ); - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, - pEList->a[0].pExpr); }else if( ALWAYS(pExpr->x.pList!=0) ){ /* Case 2: expr IN (exprlist) ** @@ -87863,11 +94462,13 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** 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; } @@ -87879,7 +94480,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); - if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); + 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; @@ -87907,7 +94508,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); sqlite3ExprCacheAffinityChange(pParse, r3, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1); } } } @@ -87923,26 +94524,37 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( case TK_EXISTS: case TK_SELECT: default: { - /* If this has to be a scalar SELECT. Generate code to put the - ** value of this select in a memory cell and record the number - ** of the memory cell in iColumn. If this is an EXISTS, write - ** an integer 0 (not exists) or 1 (exists) into a memory cell - ** and record that memory cell in iColumn. + /* 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. */ Select *pSel; /* SELECT statement to encode */ - SelectDest dest; /* How to deal with SELECt result */ + SelectDest dest; /* How to deal with SELECT result */ + int nReg; /* Registers to allocate */ 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; - sqlite3SelectDestInit(&dest, 0, ++pParse->nMem); + 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; - sqlite3VdbeAddOp2(v, OP_Null, 0, 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; @@ -87950,8 +94562,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( VdbeComment((v, "Init EXISTS result")); } sqlite3ExprDelete(pParse->db, pSel->pLimit); - pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, - &sqlite3IntTokens[1]); + pSel->pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER, + &sqlite3IntTokens[1], 0); pSel->iLimit = 0; pSel->selFlags &= ~SF_MultiValue; if( sqlite3Select(pParse, pSel, &dest) ){ @@ -87976,6 +94588,28 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( } #endif /* SQLITE_OMIT_SUBQUERY */ +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Expr pIn is an IN(...) expression. This function checks that the +** sub-select on the RHS of the IN() operator has the same number of +** columns as the vector on the LHS. Or, if the RHS of the IN() is not +** a sub-query, that the LHS is a vector of size 1. +*/ +SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ + int nVector = sqlite3ExprVectorSize(pIn->pLeft); + if( (pIn->flags & EP_xIsSelect) ){ + if( nVector!=pIn->x.pSelect->pEList->nExpr ){ + sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); + return 1; + } + }else if( nVector!=1 ){ + sqlite3VectorErrorMsg(pParse, pIn->pLeft); + return 1; + } + return 0; +} +#endif + #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code for an IN expression. @@ -87983,16 +94617,24 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ** x IN (SELECT ...) ** x IN (value, value, ...) ** -** The left-hand side (LHS) is a scalar expression. The right-hand side (RHS) -** is an array of zero or more values. The expression is true if the LHS is -** contained within the RHS. The value of the expression is unknown (NULL) -** if the LHS is NULL or if the LHS is not contained within the RHS and the -** RHS contains one or more NULL values. +** The left-hand side (LHS) is a scalar or vector expression. The +** right-hand side (RHS) is an array of zero or more scalar values, or a +** subquery. If the RHS is a subquery, the number of result columns must +** match the number of columns in the vector on the LHS. If the RHS is +** a list of values, the LHS must be a scalar. +** +** The IN operator is true if the LHS value is contained within the RHS. +** The result is false if the LHS is definitely not in the RHS. The +** result is NULL if the presence of the LHS in the RHS cannot be +** determined due to NULLs. ** ** This routine generates code that jumps to destIfFalse if the LHS is not ** contained within the RHS. If due to NULLs we cannot determine if the LHS ** is contained in the RHS then jump to destIfNull. If the LHS is contained ** within the RHS then fall through. +** +** See the separate in-operator.md documentation file in the canonical +** SQLite source tree for additional information. */ static void sqlite3ExprCodeIN( Parse *pParse, /* Parsing and code generating context */ @@ -88001,36 +94643,83 @@ static void sqlite3ExprCodeIN( int destIfNull /* Jump here if the results are unknown due to NULLs */ ){ int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */ - char affinity; /* Comparison affinity to use */ int eType; /* Type of the RHS */ - int r1; /* Temporary use register */ + int rLhs; /* Register(s) holding the LHS values */ + int rLhsOrig; /* LHS values prior to reordering by aiMap[] */ Vdbe *v; /* Statement under construction */ + int *aiMap = 0; /* Map from vector field to index column */ + char *zAff = 0; /* Affinity string for comparisons */ + int nVector; /* Size of vectors for this IN operator */ + int iDummy; /* Dummy parameter to exprCodeVector() */ + Expr *pLeft; /* The LHS of the IN operator */ + int i; /* loop counter */ + int destStep2; /* Where to jump when NULLs seen in step 2 */ + int destStep6 = 0; /* Start of code for Step 6 */ + 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 */ - /* Compute the RHS. After this step, the table with cursor - ** pExpr->iTable will contains the values that make up the RHS. - */ + pLeft = pExpr->pLeft; + if( sqlite3ExprCheckIN(pParse, pExpr) ) return; + zAff = exprINAffinity(pParse, pExpr); + nVector = sqlite3ExprVectorSize(pExpr->pLeft); + aiMap = (int*)sqlite3DbMallocZero( + pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 + ); + 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 + ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned, + ** the RHS has not yet been coded. */ v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, - destIfFalse==destIfNull ? 0 : &rRhsHasNull); + destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap); - /* Figure out the affinity to use to create a key from the results - ** of the expression. affinityStr stores a static string suitable for - ** P4 of OP_MakeRecord. - */ - affinity = comparisonAffinity(pExpr); + assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH + || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC + ); +#ifdef SQLITE_DEBUG + /* Confirm that aiMap[] contains nVector integer values between 0 and + ** nVector-1. */ + for(i=0; i from " IN (...)". + /* Code the LHS, the from " IN (...)". If the LHS is a + ** vector, then it is stored in an array of nVector registers starting + ** at r1. + ** + ** sqlite3FindInIndex() might have reordered the fields of the LHS vector + ** so that the fields are in the same order as an existing index. The + ** aiMap[] array contains a mapping from the original LHS field order to + ** the field order that matches the RHS index. */ sqlite3ExprCachePush(pParse); - r1 = sqlite3GetTempReg(pParse); - sqlite3ExprCode(pParse, pExpr->pLeft, r1); + rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); + for(i=0; ix.pList; @@ -88042,7 +94731,7 @@ static void sqlite3ExprCodeIN( assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull); + sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); } for(ii=0; iinExpr; ii++){ r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); @@ -88050,16 +94739,16 @@ static void sqlite3ExprCodeIN( sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); } if( iinExpr-1 || destIfNull!=destIfFalse ){ - sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2, + sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverageIf(v, iinExpr-1); VdbeCoverageIf(v, ii==pList->nExpr-1); - sqlite3VdbeChangeP5(v, affinity); + sqlite3VdbeChangeP5(v, zAff[0]); }else{ assert( destIfNull==destIfFalse ); - sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2, + sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); - sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL); + sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL); } sqlite3ReleaseTempReg(pParse, regToFree); } @@ -88069,78 +94758,113 @@ static void sqlite3ExprCodeIN( } sqlite3VdbeResolveLabel(v, labelOk); sqlite3ReleaseTempReg(pParse, regCkNull); + goto sqlite3ExprCodeIN_finished; + } + + /* Step 2: Check to see if the LHS contains any NULL columns. If the + ** LHS does contain NULLs then the result must be either FALSE or NULL. + ** We will then skip the binary search of the RHS. + */ + if( destIfNull==destIfFalse ){ + destStep2 = destIfFalse; }else{ - - /* If the LHS is NULL, then the result is either false or NULL depending - ** on whether the RHS is empty or not, respectively. - */ - if( sqlite3ExprCanBeNull(pExpr->pLeft) ){ - if( destIfNull==destIfFalse ){ - /* Shortcut for the common case where the false and NULL outcomes are - ** the same. */ - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); - }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); - sqlite3VdbeGoto(v, destIfNull); - sqlite3VdbeJumpHere(v, addr1); - } - } - - if( eType==IN_INDEX_ROWID ){ - /* In this case, the RHS is the ROWID of table b-tree - */ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); + destStep2 = destStep6 = sqlite3VdbeMakeLabel(v); + } + for(i=0; ipLeft, i); + if( sqlite3ExprCanBeNull(p) ){ + sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); VdbeCoverage(v); - }else{ - /* In this case, the RHS is an index b-tree. - */ - sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); - - /* If the set membership test fails, then the result of the - ** "x IN (...)" expression must be either 0 or NULL. If the set - ** contains no NULL values, then the result is 0. If the set - ** contains one or more NULL values, then the result of the - ** expression is also NULL. - */ - assert( destIfFalse!=destIfNull || rRhsHasNull==0 ); - if( rRhsHasNull==0 ){ - /* This branch runs if it is known at compile time that the RHS - ** cannot contain NULL values. This happens as the result - ** of a "NOT NULL" constraint in the database schema. - ** - ** Also run this branch if NULL is equivalent to FALSE - ** for this particular IN operator. - */ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); - VdbeCoverage(v); - }else{ - /* In this branch, the RHS of the IN might contain a NULL and - ** the presence of a NULL on the RHS makes a difference in the - ** outcome. - */ - int addr1; - - /* First check to see if the LHS is contained in the RHS. If so, - ** then the answer is TRUE the presence of NULLs in the RHS does - ** not matter. If the LHS is not contained in the RHS, then the - ** answer is NULL if the RHS contains NULLs and the answer is - ** FALSE if the RHS is NULL-free. - */ - addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull); - VdbeCoverage(v); - sqlite3VdbeGoto(v, destIfFalse); - sqlite3VdbeJumpHere(v, addr1); - } } } - sqlite3ReleaseTempReg(pParse, r1); + + /* Step 3. The LHS is now known to be non-NULL. Do the binary search + ** of the RHS using the LHS as a probe. If found, the result is + ** true. + */ + if( eType==IN_INDEX_ROWID ){ + /* 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); + 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, + 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, + rLhs, nVector); VdbeCoverage(v); + } + + /* Step 4. If the RHS is known to be non-NULL and we did not find + ** an match on the search above, then the result must be FALSE. + */ + if( rRhsHasNull && nVector==1 ){ + sqlite3VdbeAddOp2(v, OP_NotNull, rRhsHasNull, destIfFalse); + VdbeCoverage(v); + } + + /* Step 5. If we do not care about the difference between NULL and + ** FALSE, then just return false. + */ + if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse); + + /* Step 6: Loop through rows of the RHS. Compare each row to the LHS. + ** If any comparison is NULL, then the result is NULL. If all + ** comparisons are FALSE then the final result is FALSE. + ** + ** For a scalar LHS, it is sufficient to check just the first row + ** of the RHS. + */ + if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + if( nVector>1 ){ + destNotNull = sqlite3VdbeMakeLabel(v); + }else{ + /* For nVector==1, combine steps 6 and 7 by immediately returning + ** FALSE if the first comparison is not NULL */ + destNotNull = destIfFalse; + } + for(i=0; iiTable, i, r3); + sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, + (void*)pColl, P4_COLLSEQ); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, r3); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + if( nVector>1 ){ + sqlite3VdbeResolveLabel(v, destNotNull); + sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1); + VdbeCoverage(v); + + /* Step 7: If we reach this point, we know that the result must + ** be false. */ + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + } + + /* Jumps here in order to return true. */ + sqlite3VdbeJumpHere(v, addrTruthOp); + +sqlite3ExprCodeIN_finished: + if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); sqlite3ExprCachePop(pParse); VdbeComment((v, "end IN expr")); +sqlite3ExprCodeIN_oom_error: + sqlite3DbFree(pParse->db, aiMap); + sqlite3DbFree(pParse->db, zAff); } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -88184,35 +94908,38 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); - if( c==0 || (c==2 && negFlag) ){ - if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } - sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); - }else{ + if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else #ifndef SQLITE_OMIT_HEX_INTEGER if( sqlite3_strnicmp(z,"0x",2)==0 ){ - sqlite3ErrorMsg(pParse, "hex literal too big: %s", z); + sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z); }else #endif { codeReal(v, z, negFlag, iMem); } #endif + }else{ + if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } + sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } } /* -** Clear a cache entry. +** Erase column-cache entry number i */ -static void cacheEntryClear(Parse *pParse, struct yColCache *p){ - if( p->tempReg ){ +static void cacheEntryClear(Parse *pParse, int i){ + if( pParse->aColCache[i].tempReg ){ if( pParse->nTempRegaTempReg) ){ - pParse->aTempReg[pParse->nTempReg++] = p->iReg; + pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; } - p->tempReg = 0; + } + pParse->nColCache--; + if( inColCache ){ + pParse->aColCache[i] = pParse->aColCache[pParse->nColCache]; } } @@ -88243,43 +94970,33 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int ** that the object will never already be in cache. Verify this guarantee. */ #ifndef NDEBUG - for(i=0, p=pParse->aColCache; iiReg==0 || p->iTable!=iTab || p->iColumn!=iCol ); + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + assert( p->iTable!=iTab || p->iColumn!=iCol ); } #endif - /* Find an empty slot and replace it */ - for(i=0, p=pParse->aColCache; iiReg==0 ){ - p->iLevel = pParse->iCacheLevel; - p->iTable = iTab; - p->iColumn = iCol; - p->iReg = iReg; - p->tempReg = 0; - p->lru = pParse->iCacheCnt++; - return; + /* If the cache is already full, delete the least recently used entry */ + if( pParse->nColCache>=SQLITE_N_COLCACHE ){ + minLru = 0x7fffffff; + idxLru = -1; + for(i=0, p=pParse->aColCache; ilrulru; + } } + p = &pParse->aColCache[idxLru]; + }else{ + p = &pParse->aColCache[pParse->nColCache++]; } - /* Replace the last recently used */ - minLru = 0x7fffffff; - idxLru = -1; - for(i=0, p=pParse->aColCache; ilrulru; - } - } - if( ALWAYS(idxLru>=0) ){ - p = &pParse->aColCache[idxLru]; - p->iLevel = pParse->iCacheLevel; - p->iTable = iTab; - p->iColumn = iCol; - p->iReg = iReg; - p->tempReg = 0; - p->lru = pParse->iCacheCnt++; - return; - } + /* Add the new entry to the end of the cache */ + p->iLevel = pParse->iCacheLevel; + p->iTable = iTab; + p->iColumn = iCol; + p->iReg = iReg; + p->tempReg = 0; + p->lru = pParse->iCacheCnt++; } /* @@ -88287,14 +95004,13 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int ** Purge the range of registers from the column cache. */ SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){ - int i; - int iLast = iReg + nReg - 1; - struct yColCache *p; - for(i=0, p=pParse->aColCache; iiReg; - if( r>=iReg && r<=iLast ){ - cacheEntryClear(pParse, p); - p->iReg = 0; + int i = 0; + while( inColCache ){ + struct yColCache *p = &pParse->aColCache[i]; + if( p->iReg >= iReg && p->iReg < iReg+nReg ){ + cacheEntryClear(pParse, i); + }else{ + i++; } } } @@ -88319,8 +95035,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){ ** the cache to the state it was in prior the most recent Push. */ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ - int i; - struct yColCache *p; + int i = 0; assert( pParse->iCacheLevel>=1 ); pParse->iCacheLevel--; #ifdef SQLITE_DEBUG @@ -88328,10 +95043,11 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ printf("POP to %d\n", pParse->iCacheLevel); } #endif - for(i=0, p=pParse->aColCache; iiReg && p->iLevel>pParse->iCacheLevel ){ - cacheEntryClear(pParse, p); - p->iReg = 0; + while( inColCache ){ + if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){ + cacheEntryClear(pParse, i); + }else{ + i++; } } } @@ -88345,7 +95061,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; iaColCache; inColCache; i++, p++){ if( p->iReg==iReg ){ p->tempReg = 0; } @@ -88366,8 +95082,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn( if( iTabCol==XN_EXPR ){ assert( pIdx->aColExpr ); assert( pIdx->aColExpr->nExpr>iIdxCol ); - pParse->iSelfTab = iTabCur; + pParse->iSelfTab = iTabCur + 1; sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); + pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); @@ -88384,12 +95101,16 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( int iCol, /* Index of the column to extract */ int regOut /* Extract the value into this register */ ){ + if( pTab==0 ){ + sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut); + return; + } if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; - if( !HasRowid(pTab) ){ + if( !HasRowid(pTab) && !IsVirtual(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); @@ -88423,8 +95144,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn( int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; iiReg>0 && p->iTable==iTable && p->iColumn==iColumn ){ + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + if( p->iTable==iTable && p->iColumn==iColumn ){ p->lru = pParse->iCacheCnt++; sqlite3ExprCachePinRegister(pParse, p->iReg); return p->iReg; @@ -88456,19 +95177,20 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg( */ SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){ int i; - struct yColCache *p; -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ printf("CLEAR\n"); } #endif - for(i=0, p=pParse->aColCache; iiReg ){ - cacheEntryClear(pParse, p); - p->iReg = 0; + for(i=0; inColCache; i++){ + if( pParse->aColCache[i].tempReg + && pParse->nTempRegaTempReg) + ){ + pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; } } + pParse->nColCache = 0; } /* @@ -88500,7 +95222,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; iaColCache; inColCache; i++, p++){ int r = p->iReg; if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/ } @@ -88508,8 +95230,11 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ } #endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */ + /* -** Convert an expression node to a TK_REGISTER +** Convert a scalar expression node to a TK_REGISTER referencing +** register iReg. The caller must ensure that iReg already contains +** the correct value for the expression. */ static void exprToRegister(Expr *p, int iReg){ p->op2 = p->op; @@ -88518,6 +95243,42 @@ static void exprToRegister(Expr *p, int iReg){ ExprClearProperty(p, EP_Skip); } +/* +** Evaluate an expression (either a vector or a scalar expression) and store +** the result in continguous temporary registers. Return the index of +** the first register used to store the result. +** +** If the returned result register is a temporary scalar, then also write +** that register number into *piFreeable. If the returned result register +** is not a temporary or if the expression is a vector set *piFreeable +** to 0. +*/ +static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ + int iResult; + int nResult = sqlite3ExprVectorSize(p); + if( nResult==1 ){ + iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable); + }else{ + *piFreeable = 0; + if( p->op==TK_SELECT ){ +#if SQLITE_OMIT_SUBQUERY + iResult = 0; +#else + iResult = sqlite3CodeSubselect(pParse, p, 0, 0); +#endif + }else{ + int i; + iResult = pParse->nMem+1; + pParse->nMem += nResult; + for(i=0; ix.pList->a[i].pExpr, i+iResult); + } + } + } + return iResult; +} + + /* ** Generate code into the current Vdbe to evaluate the given ** expression. Attempt to store the results in register "target". @@ -88535,9 +95296,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) int inReg = target; /* Results stored in register inReg */ int regFree1 = 0; /* If non-zero free this temporary register */ int regFree2 = 0; /* If non-zero free this temporary register */ - int r1, r2, r3, r4; /* Various register numbers */ - sqlite3 *db = pParse->db; /* The database connection */ + int r1, r2; /* Various register numbers */ Expr tempX; /* Temporary expression node */ + int p5 = 0; assert( target>0 && target<=pParse->nMem ); if( v==0 ){ @@ -88556,52 +95317,49 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ assert( pCol->iMem>0 ); - inReg = pCol->iMem; - break; + return pCol->iMem; }else if( pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); - break; + return target; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { int iTab = pExpr->iTable; if( iTab<0 ){ - if( pParse->ckBase>0 ){ + if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ - inReg = pExpr->iColumn + pParse->ckBase; - break; + return pExpr->iColumn - pParse->iSelfTab; }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ - iTab = pParse->iSelfTab; + iTab = pParse->iSelfTab - 1; } } - inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, + return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, pExpr->iColumn, iTab, target, pExpr->op2); - break; } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); - break; + return target; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); codeReal(v, pExpr->u.zToken, 0, target); - break; + return target; } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); - break; + return target; } case TK_NULL: { sqlite3VdbeAddOp2(v, OP_Null, 0, target); - break; + return target; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { @@ -88616,7 +95374,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( z[n]=='\'' ); zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n); sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC); - break; + return target; } #endif case TK_VARIABLE: { @@ -88625,15 +95383,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); if( pExpr->u.zToken[1]!=0 ){ - assert( pExpr->u.zToken[0]=='?' - || strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 ); - sqlite3VdbeChangeP4(v, -1, pParse->azVar[pExpr->iColumn-1], P4_STATIC); + const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); + assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 ); + pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */ + sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); } - break; + return target; } case TK_REGISTER: { - inReg = pExpr->iTable; - break; + return pExpr->iTable; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { @@ -88647,42 +95405,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3AffinityType(pExpr->u.zToken, 0)); testcase( usedAsColumnCache(pParse, inReg, inReg) ); sqlite3ExprCacheAffinityChange(pParse, inReg, 1); - break; + return inReg; } #endif /* SQLITE_OMIT_CAST */ + case TK_IS: + case TK_ISNOT: + op = (op==TK_IS) ? TK_EQ : TK_NE; + p5 = SQLITE_NULLEQ; + /* fall-through */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - r1, r2, inReg, SQLITE_STOREP2); - assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); - assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); - assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); - assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); - assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); - assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); - testcase( regFree1==0 ); - testcase( regFree2==0 ); - break; - } - case TK_IS: - case TK_ISNOT: { - testcase( op==TK_IS ); - testcase( op==TK_ISNOT ); - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - op = (op==TK_IS) ? TK_EQ : TK_NE; - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ); - VdbeCoverageIf(v, op==TK_EQ); - VdbeCoverageIf(v, op==TK_NE); - testcase( regFree1==0 ); - testcase( regFree2==0 ); + Expr *pLeft = pExpr->pLeft; + if( sqlite3ExprIsVector(pLeft) ){ + codeVectorCompare(pParse, pExpr, target, op, p5); + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + codeCompare(pParse, pLeft, pExpr->pRight, op, + r1, r2, inReg, SQLITE_STOREP2 | p5); + assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); + assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); + assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); + assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); + assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); + testcase( regFree1==0 ); + testcase( regFree2==0 ); + } break; } case TK_AND: @@ -88720,10 +95473,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( pLeft ); if( pLeft->op==TK_INTEGER ){ codeInteger(pParse, pLeft, 1, target); + return target; #ifndef SQLITE_OMIT_FLOATING_POINT }else if( pLeft->op==TK_FLOAT ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); codeReal(v, pLeft->u.zToken, 1, target); + return target; #endif }else{ tempX.op = TK_INTEGER; @@ -88734,7 +95489,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); testcase( regFree2==0 ); } - inReg = target; break; } case TK_BITNOT: @@ -88743,7 +95497,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( TK_NOT==OP_Not ); testcase( op==TK_NOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); - inReg = target; sqlite3VdbeAddOp2(v, op, r1, inReg); break; } @@ -88768,7 +95521,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken); }else{ - inReg = pInfo->aFunc[pExpr->iAgg].iMem; + return pInfo->aFunc[pExpr->iAgg].iMem; } break; } @@ -88776,13 +95529,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ExprList *pFarg; /* List of function arguments */ int nFarg; /* Number of function arguments */ FuncDef *pDef; /* The function definition object */ - int nId; /* Length of the function name in bytes */ const char *zId; /* The function name */ u32 constMask = 0; /* Mask of function arguments that are constant */ int i; /* Loop counter */ + sqlite3 *db = pParse->db; /* The database connection */ u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ + if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ + /* SQL functions can be expensive. So try to move constant functions + ** out of the inner loop, even if that means an extra OP_Copy. */ + return sqlite3ExprCodeAtInit(pParse, pExpr, -1); + } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; @@ -88792,10 +95550,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; - nId = sqlite3Strlen30(zId); - pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); - if( pDef==0 || pDef->xFunc==0 ){ - sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); + pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + if( pDef==0 && pParse->explain ){ + pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); + } +#endif + if( pDef==0 || pDef->xFinalize!=0 ){ + sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); break; } @@ -88824,10 +95586,25 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) */ if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ assert( nFarg>=1 ); - inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); - break; + return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); } +#ifdef SQLITE_DEBUG + /* The AFFINITY() function evaluates to a string that describes + ** the type affinity of the argument. This is used for testing of + ** the SQLite type logic. + */ + if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){ + const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; + char aff; + assert( nFarg==1 ); + aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); + sqlite3VdbeLoadString(v, target, + aff ? azAff[aff-SQLITE_AFF_BLOB] : "none"); + return target; + } +#endif + for(i=0; ia[i].pExpr) ){ testcase( i==31 ); @@ -88894,22 +95671,41 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target, - (char*)pDef, P4_FUNCDEF); + sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0, + constMask, r1, target, (char*)pDef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nFarg); if( nFarg && constMask==0 ){ sqlite3ReleaseTempRange(pParse, r1, nFarg); } - break; + return target; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { + int nCol; testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); - inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); + if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ + sqlite3SubselectError(pParse, nCol, 1); + }else{ + return sqlite3CodeSubselect(pParse, pExpr, 0, 0); + } break; } + case TK_SELECT_COLUMN: { + int n; + if( pExpr->pLeft->iTable==0 ){ + pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0); + } + assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT ); + if( pExpr->iTable + && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) + ){ + sqlite3ErrorMsg(pParse, "%d columns assigned %d values", + pExpr->iTable, n); + } + return pExpr->pLeft->iTable + pExpr->iColumn; + } case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(v); int destIfNull = sqlite3VdbeMakeLabel(v); @@ -88919,7 +95715,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeResolveLabel(v, destIfFalse); sqlite3VdbeAddOp2(v, OP_AddImm, target, 0); sqlite3VdbeResolveLabel(v, destIfNull); - break; + return target; } #endif /* SQLITE_OMIT_SUBQUERY */ @@ -88936,34 +95732,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { - Expr *pLeft = pExpr->pLeft; - struct ExprList_item *pLItem = pExpr->x.pList->a; - Expr *pRight = pLItem->pExpr; - - r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); - testcase( regFree1==0 ); - testcase( regFree2==0 ); - r3 = sqlite3GetTempReg(pParse); - r4 = sqlite3GetTempReg(pParse); - codeCompare(pParse, pLeft, pRight, OP_Ge, - r1, r2, r3, SQLITE_STOREP2); VdbeCoverage(v); - pLItem++; - pRight = pLItem->pExpr; - sqlite3ReleaseTempReg(pParse, regFree2); - r2 = sqlite3ExprCodeTemp(pParse, pRight, ®Free2); - testcase( regFree2==0 ); - codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_And, r3, r4, target); - sqlite3ReleaseTempReg(pParse, r3); - sqlite3ReleaseTempReg(pParse, r4); - break; + exprCodeBetween(pParse, pExpr, target, 0, 0); + return target; } + case TK_SPAN: case TK_COLLATE: case TK_UPLUS: { - inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); - break; + return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); } case TK_TRIGGER: { @@ -89022,6 +95797,21 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) break; } + case TK_VECTOR: { + sqlite3ErrorMsg(pParse, "row value misused"); + break; + } + + case TK_IF_NULL_ROW: { + int addrINR; + addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); + sqlite3ExprCachePush(pParse); + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + sqlite3ExprCachePop(pParse); + sqlite3VdbeJumpHere(v, addrINR); + sqlite3VdbeChangeP3(v, addrINR, inReg); + break; + } /* ** Form A: @@ -89065,8 +95855,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) if( (pX = pExpr->pLeft)!=0 ){ tempX = *pX; testcase( pX->op==TK_COLUMN ); - exprToRegister(&tempX, sqlite3ExprCodeTemp(pParse, pX, ®Free1)); + exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1)); testcase( regFree1==0 ); + memset(&opCompare, 0, sizeof(opCompare)); opCompare.op = TK_EQ; opCompare.pLeft = &tempX; pTest = &opCompare; @@ -89100,7 +95891,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } - assert( db->mallocFailed || pParse->nErr>0 + assert( pParse->db->mallocFailed || pParse->nErr>0 || pParse->iCacheLevel==iCacheLevel ); sqlite3VdbeResolveLabel(v, endLabel); break; @@ -89141,24 +95932,40 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) /* ** Factor out the code of the given expression to initialization time. +** +** If regDest>=0 then the result is always stored in that register and the +** result is not reusable. If regDest<0 then this routine is free to +** store the value whereever it wants. The register where the expression +** is stored is returned. When regDest<0, two identical expressions will +** code to the same register. */ -SQLITE_PRIVATE void sqlite3ExprCodeAtInit( +SQLITE_PRIVATE int sqlite3ExprCodeAtInit( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The expression to code when the VDBE initializes */ - int regDest, /* Store the value in this register */ - u8 reusable /* True if this expression is reusable */ + int regDest /* Store the value in this register */ ){ ExprList *p; assert( ConstFactorOk(pParse) ); p = pParse->pConstExpr; + if( regDest<0 && p ){ + struct ExprList_item *pItem; + int i; + for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ + if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){ + return pItem->u.iConstExprReg; + } + } + } pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p = sqlite3ExprListAppend(pParse, p, pExpr); if( p ){ struct ExprList_item *pItem = &p->a[p->nExpr-1]; + pItem->reusable = regDest<0; + if( regDest<0 ) regDest = ++pParse->nMem; pItem->u.iConstExprReg = regDest; - pItem->reusable = reusable; } pParse->pConstExpr = p; + return regDest; } /* @@ -89181,19 +95988,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ && pExpr->op!=TK_REGISTER && sqlite3ExprIsConstantNotJoin(pExpr) ){ - ExprList *p = pParse->pConstExpr; - int i; *pReg = 0; - if( p ){ - struct ExprList_item *pItem; - for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ - if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){ - return pItem->u.iConstExprReg; - } - } - } - r2 = ++pParse->nMem; - sqlite3ExprCodeAtInit(pParse, pExpr, r2, 1); + r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); @@ -89247,7 +96043,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ */ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target, 0); + sqlite3ExprCodeAtInit(pParse, pExpr, target); }else{ sqlite3ExprCode(pParse, pExpr, target); } @@ -89281,7 +96077,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. ** -** Return the number of elements evaluated. +** Return the number of elements evaluated. The number returned will +** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF +** is defined. ** ** The SQLITE_ECEL_DUP flag prevents the arguments from being ** filled using OP_SCopy. OP_Copy must be used instead. @@ -89292,6 +96090,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ ** The SQLITE_ECEL_REF flag means that expressions in the list with ** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored ** in registers at srcReg, and so the value can be copied from there. +** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0 +** are simply omitted rather than being copied from srcReg. */ SQLITE_PRIVATE int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ @@ -89311,10 +96111,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; ipExpr; - if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){ - sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); + if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ + if( flags & SQLITE_ECEL_OMITREF ){ + i--; + n--; + }else{ + sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); + } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0); + sqlite3ExprCodeAtInit(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ @@ -89345,20 +96150,33 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( ** ** Code it as such, taking care to do the common subexpression ** elimination of x. +** +** The xJumpIf parameter determines details: +** +** NULL: Store the boolean result in reg[dest] +** sqlite3ExprIfTrue: Jump to dest if true +** sqlite3ExprIfFalse: Jump to dest if false +** +** The jumpIfNull parameter is ignored if xJumpIf is NULL. */ static void exprCodeBetween( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* The BETWEEN expression */ - int dest, /* Jump here if the jump is taken */ - int jumpIfTrue, /* Take the jump if the BETWEEN is true */ + int dest, /* Jump destination or storage location */ + void (*xJump)(Parse*,Expr*,int,int), /* Action to take */ int jumpIfNull /* Take the jump if the BETWEEN is NULL */ ){ - Expr exprAnd; /* The AND operator in x>=y AND x<=z */ + Expr exprAnd; /* The AND operator in x>=y AND x<=z */ Expr compLeft; /* The x>=y term */ Expr compRight; /* The x<=z term */ 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; exprAnd.op = TK_AND; @@ -89370,23 +96188,30 @@ static void exprCodeBetween( compRight.op = TK_LE; compRight.pLeft = &exprX; compRight.pRight = pExpr->x.pList->a[1].pExpr; - exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, ®Free1)); - if( jumpIfTrue ){ - sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull); + exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1)); + if( xJump ){ + xJump(pParse, &exprAnd, dest, jumpIfNull); }else{ - sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull); + /* Mark the expression is being from the ON or USING clause of a join + ** so that the sqlite3ExprCodeTarget() routine will not attempt to move + ** it into the Parse.pConstExpr list. We should use a new bit for this, + ** for clarity, but we are out of bits in the Expr.flags field so we + ** have to reuse the EP_FromJoin bit. Bummer. */ + exprX.flags |= EP_FromJoin; + sqlite3ExprCodeTarget(pParse, &exprAnd, dest); } sqlite3ReleaseTempReg(pParse, regFree1); /* Ensure adequate test coverage */ - testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1==0 ); - testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1!=0 ); - testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1==0 ); - testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1!=0 ); - testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1==0 ); - testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1!=0 ); - testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1==0 ); - testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1!=0 ); + testcase( xJump==0 ); } /* @@ -89438,12 +96263,20 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } + case TK_IS: + case TK_ISNOT: + testcase( op==TK_IS ); + testcase( op==TK_ISNOT ); + op = (op==TK_IS) ? TK_EQ : TK_NE; + jumpIfNull = SQLITE_NULLEQ; + /* Fall thru */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { + if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); @@ -89453,23 +96286,12 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); - assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); - assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); - testcase( regFree1==0 ); - testcase( regFree2==0 ); - break; - } - case TK_IS: - case TK_ISNOT: { - testcase( op==TK_IS ); - testcase( op==TK_ISNOT ); - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - op = (op==TK_IS) ? TK_EQ : TK_NE; - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - r1, r2, dest, SQLITE_NULLEQ); - VdbeCoverageIf(v, op==TK_EQ); - VdbeCoverageIf(v, op==TK_NE); + assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); + assert(TK_NE==OP_Ne); testcase(op==OP_Ne); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; @@ -89487,7 +96309,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int } case TK_BETWEEN: { testcase( jumpIfNull==0 ); - exprCodeBetween(pParse, pExpr, dest, 1, jumpIfNull); + exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -89501,6 +96323,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int } #endif default: { + default_expr: if( exprAlwaysTrue(pExpr) ){ sqlite3VdbeGoto(v, dest); }else if( exprAlwaysFalse(pExpr) ){ @@ -89594,12 +96417,20 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } + case TK_IS: + case TK_ISNOT: + testcase( pExpr->op==TK_IS ); + testcase( pExpr->op==TK_ISNOT ); + op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; + jumpIfNull = SQLITE_NULLEQ; + /* Fall thru */ case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { + if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); @@ -89609,23 +96440,12 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); - assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); - assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); - testcase( regFree1==0 ); - testcase( regFree2==0 ); - break; - } - case TK_IS: - case TK_ISNOT: { - testcase( pExpr->op==TK_IS ); - testcase( pExpr->op==TK_ISNOT ); - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; - codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - r1, r2, dest, SQLITE_NULLEQ); - VdbeCoverageIf(v, op==TK_EQ); - VdbeCoverageIf(v, op==TK_NE); + assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); + assert(TK_NE==OP_Ne); testcase(op==OP_Ne); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; @@ -89641,7 +96461,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int } case TK_BETWEEN: { testcase( jumpIfNull==0 ); - exprCodeBetween(pParse, pExpr, dest, 0, jumpIfNull); + exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull); break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -89657,6 +96477,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int } #endif default: { + default_expr: if( exprAlwaysFalse(pExpr) ){ sqlite3VdbeGoto(v, dest); }else if( exprAlwaysTrue(pExpr) ){ @@ -89689,6 +96510,41 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i sqlite3ExprDelete(db, pCopy); } +/* +** Expression pVar is guaranteed to be an SQL variable. pExpr may be any +** type of expression. +** +** If pExpr is a simple SQL value - an integer, real, string, blob +** or NULL value - then the VDBE currently being prepared is configured +** to re-prepare each time a new value is bound to variable pVar. +** +** Additionally, if pExpr is a simple SQL value and the value is the +** same as that currently bound to variable pVar, non-zero is returned. +** Otherwise, if the values are not the same or if pExpr is not a simple +** SQL value, zero is returned. +*/ +static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){ + int res = 0; + int iVar; + sqlite3_value *pL, *pR = 0; + + sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); + if( pR ){ + iVar = pVar->iColumn; + sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); + pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB); + if( pL ){ + if( sqlite3_value_type(pL)==SQLITE_TEXT ){ + sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */ + } + res = 0==sqlite3MemCompare(pL, pR, 0); + } + sqlite3ValueFree(pR); + sqlite3ValueFree(pL); + } + + return res; +} /* ** Do a deep comparison of two expression trees. Return 0 if the two @@ -89711,12 +96567,22 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. +** +** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in +** pParse->pReprepare can be matched against literals in pB. The +** pParse->pVdbe->expmask bitmask is updated for each variable referenced. +** If pParse is NULL (the normal case) then any TK_VARIABLE term in +** Argument pParse should normally be NULL. If it is not NULL and pA or +** pB causes a return value of 2. */ -SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ +SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } + if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ + return 0; + } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ @@ -89725,10 +96591,10 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ return 2; } if( pA->op!=pB->op ){ - if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){ + if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } - if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){ + if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){ return 1; } return 2; @@ -89743,8 +96609,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; - if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; - if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; + if( 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; if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ if( pA->iColumn!=pB->iColumn ) return 2; @@ -89779,11 +96645,22 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; - if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1; + if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1; } return 0; } +/* +** Like sqlite3ExprCompare() except COLLATE operators at the top-level +** are ignored. +*/ +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ + return sqlite3ExprCompare(0, + sqlite3ExprSkipCollate(pA), + sqlite3ExprSkipCollate(pB), + iTab); +} + /* ** 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 @@ -89800,29 +96677,88 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has ** Expr.iTable<0 then assume a table number given by iTab. ** +** If pParse is not NULL, then the values of bound variables in pE1 are +** compared against literal values in pE2 and pParse->pVdbe->expmask is +** modified to record which bound variables are referenced. If pParse +** is NULL, then false will be returned if pE1 contains any bound variables. +** ** When in doubt, return false. Returning true might give a performance ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ - if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){ +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){ + if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } if( pE2->op==TK_OR - && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) - || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab) + || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) ) ){ return 1; } - if( pE2->op==TK_NOTNULL - && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0 - && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS) - ){ - 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; } return 0; } +/* +** An instance of the following structure is used by the tree walker +** to determine if an expression can be evaluated by reference to the +** index only, without having to do a search for the corresponding +** table entry. The IdxCover.pIdx field is the index. IdxCover.iCur +** is the cursor for the table. +*/ +struct IdxCover { + Index *pIdx; /* The index to be tested for coverage */ + int iCur; /* Cursor number for the table corresponding to the index */ +}; + +/* +** Check to see if there are references to columns in table +** pWalker->u.pIdxCover->iCur can be satisfied using the index +** pWalker->u.pIdxCover->pIdx. +*/ +static int exprIdxCover(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN + && pExpr->iTable==pWalker->u.pIdxCover->iCur + && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 + ){ + pWalker->eCode = 1; + return WRC_Abort; + } + return WRC_Continue; +} + +/* +** Determine if an index pIdx on table with cursor iCur contains will +** the expression pExpr. Return true if the index does cover the +** expression and false if the pExpr expression references table columns +** that are not found in the index pIdx. +** +** An index covering an expression means that the expression can be +** evaluated using only the index and without having to lookup the +** corresponding table entry. +*/ +SQLITE_PRIVATE int sqlite3ExprCoveredByIndex( + Expr *pExpr, /* The index to be tested */ + int iCur, /* The cursor number for the corresponding table */ + Index *pIdx /* The index that might be used for coverage */ +){ + Walker w; + struct IdxCover xcov; + memset(&w, 0, sizeof(w)); + xcov.iCur = iCur; + xcov.pIdx = pIdx; + w.xExprCallback = exprIdxCover; + w.u.pIdxCover = &xcov; + sqlite3WalkExpr(&w, pExpr); + return !w.eCode; +} + + /* ** An instance of the following structure is used by the tree walker ** to count references to table columns in the arguments of an @@ -89871,8 +96807,8 @@ SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ Walker w; struct SrcCount cnt; assert( pExpr->op==TK_AGG_FUNCTION ); - memset(&w, 0, sizeof(w)); w.xExprCallback = exprSrcCount; + w.xSelectCallback = 0; w.u.pSrcCount = &cnt; cnt.pSrc = pSrcList; cnt.nThis = 0; @@ -90004,7 +96940,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; inFunc; i++, pItem++){ - if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){ + if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){ break; } } @@ -90020,7 +96956,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ pItem->iMem = ++pParse->nMem; assert( !ExprHasProperty(pExpr, EP_IntValue) ); pItem->pFunc = sqlite3FindFunction(pParse->db, - pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken), + pExpr->u.zToken, pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); if( pExpr->flags & EP_Distinct ){ pItem->iDistinct = pParse->nTab++; @@ -90044,10 +96980,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ - UNUSED_PARAMETER(pWalker); UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth++; return WRC_Continue; } +static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth--; +} /* ** Analyze the pExpr expression looking for aggregate functions and @@ -90060,9 +97000,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ */ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ Walker w; - memset(&w, 0, sizeof(w)); w.xExprCallback = analyzeAggregate; w.xSelectCallback = analyzeAggregatesInSelect; + w.xSelectCallback2 = analyzeAggregatesInSelectEnd; + w.walkerDepth = 0; w.u.pNC = pNC; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); @@ -90106,7 +97047,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && pParse->nTempRegaTempReg) ){ int i; struct yColCache *p; - for(i=0, p=pParse->aColCache; iaColCache; inColCache; i++, p++){ if( p->iReg==iReg ){ p->tempReg = 1; return; @@ -90117,10 +97058,11 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ } /* -** Allocate or deallocate a block of nReg consecutive registers +** Allocate or deallocate a block of nReg consecutive registers. */ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){ int i, n; + if( nReg==1 ) return sqlite3GetTempReg(pParse); i = pParse->iRangeReg; n = pParse->nRangeReg; if( nReg<=n ){ @@ -90134,6 +97076,10 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){ return i; } SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ + if( nReg==1 ){ + sqlite3ReleaseTempReg(pParse, iReg); + return; + } sqlite3ExprCacheRemove(pParse, iReg, nReg); if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; @@ -90149,6 +97095,29 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ pParse->nRangeReg = 0; } +/* +** Validate that no temporary register falls within the range of +** iFirst..iLast, inclusive. This routine is only call from within assert() +** statements. +*/ +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ + int i; + if( pParse->nRangeReg>0 + && pParse->iRangeReg+pParse->nRangeReg > iFirst + && pParse->iRangeReg <= iLast + ){ + return 0; + } + for(i=0; inTempReg; i++){ + if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){ + return 0; + } + } + return 1; +} +#endif /* SQLITE_DEBUG */ + /************** End of expr.c ************************************************/ /************** Begin file alter.c *******************************************/ /* @@ -90382,7 +97351,7 @@ static void renameTriggerFunc( ** Register built-in functions used to help implement ALTER TABLE */ SQLITE_PRIVATE void sqlite3AlterFunctions(void){ - static SQLITE_WSD FuncDef aAlterTableFuncs[] = { + static FuncDef aAlterTableFuncs[] = { FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc), #ifndef SQLITE_OMIT_TRIGGER FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc), @@ -90391,13 +97360,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){ FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc), #endif }; - int i; - FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); - FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs); - - for(i=0; i6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ + if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); return 1; } @@ -90562,9 +97525,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( char *zWhere = 0; /* Where clause to locate temp triggers */ #endif VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ - int savedDbFlags; /* Saved value of db->flags */ + u32 savedDbFlags; /* Saved value of db->mDbFlags */ - savedDbFlags = db->flags; + savedDbFlags = db->mDbFlags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); @@ -90572,8 +97535,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - zDb = db->aDb[iDb].zName; - db->flags |= SQLITE_PreferBuiltin; + zDb = db->aDb[iDb].zDbSName; + db->mDbFlags |= DBFLAG_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); @@ -90663,7 +97626,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_parent(sql, %Q, %Q) " - "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere); + "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere); sqlite3DbFree(db, zWhere); } } @@ -90687,7 +97650,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " "(type='table' OR type='index' OR type='trigger');", - zDb, SCHEMA_TABLE(iDb), zName, zName, zName, + zDb, MASTER_NAME, zName, zName, zName, #ifndef SQLITE_OMIT_TRIGGER zName, #endif @@ -90738,34 +97701,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); - db->flags = savedDbFlags; -} - - -/* -** Generate code to make sure the file format number is at least minFormat. -** The generated code will increase the file format number if necessary. -*/ -SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ - Vdbe *v; - v = sqlite3GetVdbe(pParse); - /* The VDBE should have been allocated before this routine is called. - ** If that allocation failed, we would have quit before reaching this - ** point */ - if( ALWAYS(v) ){ - int r1 = sqlite3GetTempReg(pParse); - int r2 = sqlite3GetTempReg(pParse); - int addr1; - sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); - sqlite3VdbeUsesBtree(v, iDb); - sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2); - addr1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2); - sqlite3VdbeJumpHere(v, addr1); - sqlite3ReleaseTempReg(pParse, r1); - sqlite3ReleaseTempReg(pParse, r2); - } + db->mDbFlags = savedDbFlags; } /* @@ -90786,15 +97722,18 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ + Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ + int r1; /* Temporary registers */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; + assert( v!=0 ); pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; @@ -90812,7 +97751,8 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ ** literal NULL, then set pDflt to 0. This simplifies checking ** for an SQL NULL default below. */ - if( pDflt && pDflt->op==TK_NULL ){ + assert( pDflt==0 || pDflt->op==TK_SPAN ); + if( pDflt && pDflt->pLeft->op==TK_NULL ){ pDflt = 0; } @@ -90848,7 +97788,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc!=SQLITE_OK ){ - db->mallocFailed = 1; + assert( db->mallocFailed == 1 ); return; } if( !pVal ){ @@ -90862,27 +97802,34 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; - int savedDbFlags = db->flags; + u32 savedDbFlags = db->mDbFlags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } - db->flags |= SQLITE_PreferBuiltin; + db->mDbFlags |= DBFLAG_PreferBuiltin; sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " "WHERE type = 'table' AND name = %Q", - zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, + zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqlite3DbFree(db, zCol); - db->flags = savedDbFlags; + db->mDbFlags = savedDbFlags; } - /* If the default value of the new column is NULL, then set the file - ** format to 2. If the default value of the new column is not NULL, - ** the file format becomes 3. + /* Make sure the schema version is at least 3. But do not upgrade + ** from less than 3 to 4, as that will corrupt any preexisting DESC + ** index. */ - sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); + sqlite3VdbeUsesBtree(v, iDb); + sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); + sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); + sqlite3ReleaseTempReg(pParse, r1); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); @@ -90948,7 +97895,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); if( !pNew ) goto exit_begin_add_column; pParse->pNewTable = pNew; - pNew->nRef = 1; + pNew->nTabRef = 1; pNew->nCol = pTab->nCol; assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; @@ -90956,7 +97903,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); if( !pNew->aCol || !pNew->zName ){ - db->mallocFailed = 1; + assert( db->mallocFailed ); goto exit_begin_add_column; } memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); @@ -90964,13 +97911,11 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ Column *pCol = &pNew->aCol[i]; pCol->zName = sqlite3DbStrDup(db, pCol->zName); pCol->zColl = 0; - pCol->zType = 0; pCol->pDflt = 0; - pCol->zDflt = 0; } pNew->pSchema = db->aDb[iDb].pSchema; pNew->addColOffset = pTab->addColOffset; - pNew->nRef = 1; + pNew->nTabRef = 1; /* Begin a transaction and increment the schema cookie. */ sqlite3BeginWriteOperation(pParse, 0, iDb); @@ -91198,14 +98143,14 @@ static void openStatTable( for(i=0; izName))==0 ){ + if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){ if( aTable[i].zCols ){ /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, - "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols + "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); aRoot[i] = pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; @@ -91220,7 +98165,7 @@ static void openStatTable( if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", - pDb->zName, zTab, zWhereType, zWhere + pDb->zDbSName, zTab, zWhereType, zWhere ); }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ @@ -91278,6 +98223,7 @@ struct Stat4Accum { Stat4Sample *aBest; /* Array of nCol best samples */ int iMin; /* Index in a[] of entry with minimum score */ int nSample; /* Current number of samples */ + int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */ int iGet; /* Index of current sample accessed by stat_get() */ Stat4Sample *a; /* Array of mxSample Stat4Sample objects */ sqlite3 *db; /* Database connection, for malloc() */ @@ -91301,7 +98247,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); - p->u.aRowid = sqlite3DbMallocRaw(db, n); + p->u.aRowid = sqlite3DbMallocRawNN(db, n); if( p->u.aRowid ){ p->nRowid = n; memcpy(p->u.aRowid, pData, n); @@ -91466,12 +98412,10 @@ static const FuncDef statInitFuncdef = { SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ - statInit, /* xFunc */ - 0, /* xStep */ + statInit, /* xSFunc */ 0, /* xFinalize */ "stat_init", /* zName */ - 0, /* pHash */ - 0 /* pDestructor */ + {0} }; #ifdef SQLITE_ENABLE_STAT4 @@ -91544,6 +98488,13 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ assert( IsStat4 || nEqZero==0 ); #ifdef SQLITE_ENABLE_STAT4 + /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0 + ** values in the anEq[] array of any sample in Stat4Accum.a[]. In + ** other words, if nMaxEqZero is n, then it is guaranteed that there + ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */ + if( nEqZero>p->nMaxEqZero ){ + p->nMaxEqZero = nEqZero; + } if( pNew->isPSample==0 ){ Stat4Sample *pUpgrade = 0; assert( pNew->anEq[pNew->iCol]>0 ); @@ -91641,12 +98592,22 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){ } } - /* Update the anEq[] fields of any samples already collected. */ + /* Check that no sample contains an anEq[] entry with an index of + ** p->nMaxEqZero or greater set to zero. */ for(i=p->nSample-1; i>=0; i--){ int j; - for(j=iChng; jnCol; j++){ - if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; + for(j=p->nMaxEqZero; jnCol; j++) assert( p->a[i].anEq[j]>0 ); + } + + /* Update the anEq[] fields of any samples already collected. */ + if( iChngnMaxEqZero ){ + for(i=p->nSample-1; i>=0; i--){ + int j; + for(j=iChng; jnCol; j++){ + if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; + } } + p->nMaxEqZero = iChng; } #endif @@ -91767,12 +98728,10 @@ static const FuncDef statPushFuncdef = { SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ - statPush, /* xFunc */ - 0, /* xStep */ + statPush, /* xSFunc */ 0, /* xFinalize */ "stat_push", /* zName */ - 0, /* pHash */ - 0 /* pDestructor */ + {0} }; #define STAT_GET_STAT1 0 /* "stat" column of stat1 table */ @@ -91789,6 +98748,12 @@ static const FuncDef statPushFuncdef = { ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** +** The stat_get(P,J) function is not available to generic SQL. It is +** inserted as part of a manually constructed bytecode program. (See +** the callStatGet() routine below.) It is guaranteed that the P +** parameter will always be a poiner to a Stat4Accum object, never a +** NULL. +** ** If neither STAT3 nor STAT4 are enabled, then J is always ** STAT_GET_STAT1 and is hence omitted and this routine becomes ** a one-parameter function, stat_get(P), that always returns the @@ -91914,12 +98879,10 @@ static const FuncDef statGetFuncdef = { SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ - statGet, /* xFunc */ - 0, /* xStep */ + statGet, /* xSFunc */ 0, /* xFinalize */ "stat_get", /* zName */ - 0, /* pHash */ - 0 /* pDestructor */ + {0} }; static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){ @@ -91931,8 +98894,8 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){ #else UNUSED_PARAMETER( iParam ); #endif - sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut); - sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF); + sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut, + (char*)&statGetFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 1 + IsStat34); } @@ -91988,7 +98951,7 @@ static void analyzeOneTable( assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, - db->aDb[iDb].zName ) ){ + db->aDb[iDb].zDbSName ) ){ return; } #endif @@ -92086,8 +99049,8 @@ static void analyzeOneTable( #endif sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); - sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4); - sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF); + sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4, + (char*)&statInitFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2+IsStat34); /* Implementation of the following: @@ -92106,7 +99069,7 @@ static void analyzeOneTable( if( nColTest>0 ){ int endDistinctTest = sqlite3VdbeMakeLabel(v); int *aGotoChng; /* Array of jump instruction addresses */ - aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest); + aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest); if( aGotoChng==0 ) continue; /* @@ -92174,7 +99137,7 @@ static void analyzeOneTable( regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); - assert( k>=0 && knCol ); + assert( k>=0 && knColumn ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); } @@ -92183,8 +99146,8 @@ static void analyzeOneTable( } #endif assert( regChng==(regStat4+1) ); - sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp); - sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF); + sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp, + (char*)&statPushFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2+IsStat34); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); @@ -92358,27 +99321,14 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ if( i==1 ) continue; /* Do not analyze the TEMP database */ analyzeDatabase(pParse, i); } - }else if( pName2->n==0 ){ - /* Form 2: Analyze the database or table named */ - iDb = sqlite3FindDb(db, pName1); - if( iDb>=0 ){ - analyzeDatabase(pParse, iDb); - }else{ - z = sqlite3NameFromToken(db, pName1); - if( z ){ - if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){ - analyzeTable(pParse, pIdx->pTable, pIdx); - }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){ - analyzeTable(pParse, pTab, 0); - } - sqlite3DbFree(db, z); - } - } + }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){ + /* Analyze the schema named as the argument */ + analyzeDatabase(pParse, iDb); }else{ - /* Form 3: Analyze the fully qualified table name */ + /* Form 3: Analyze the table or index named as an argument */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); if( iDb>=0 ){ - zDb = db->aDb[iDb].zName; + zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; z = sqlite3NameFromToken(db, pTableName); if( z ){ if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ @@ -92388,10 +99338,11 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ } sqlite3DbFree(db, z); } - } + } + } + if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){ + sqlite3VdbeAddOp0(v, OP_Expire); } - v = sqlite3GetVdbe(pParse); - if( v ) sqlite3VdbeAddOp0(v, OP_Expire); } /* @@ -92514,13 +99465,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ ** the old data with the new instead of allocating a new array. */ if( pIndex->aiRowEst==0 ){ pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol); - if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1; + if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db); } aiRowEst = pIndex->aiRowEst; #endif pIndex->bUnordered = 0; decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); - if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + pIndex->hasStat1 = 1; + if( pIndex->pPartIdxWhere==0 ){ + pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + pTable->tabFlags |= TF_HasStat1; + } }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; @@ -92529,6 +99484,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ #endif decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); pTable->szTabRow = fakeIdx.szIdxRow; + pTable->tabFlags |= TF_HasStat1; } return 0; @@ -92609,7 +99565,7 @@ static void initAvgEq(Index *pIdx){ } } - if( nDist100>nSum100 ){ + if( nDist100>nSum100 && sumEqaSample[] */ - assert( db->lookaside.bEnabled==0 ); + assert( db->lookaside.bDisable ); zSql = sqlite3MPrintf(db, zSql1, zDb); if( !zSql ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqlite3DbFree(db, zSql); @@ -92704,7 +99660,7 @@ static int loadStatTbl( pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ sqlite3_finalize(pStmt); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; pIdx->aAvgEq = pSpace; pSpace += nIdxCol; @@ -92720,7 +99676,7 @@ static int loadStatTbl( zSql = sqlite3MPrintf(db, zSql2, zDb); if( !zSql ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); sqlite3DbFree(db, zSql); @@ -92758,9 +99714,11 @@ static int loadStatTbl( pSample->p = sqlite3DbMallocZero(db, pSample->n + 2); if( pSample->p==0 ){ sqlite3_finalize(pStmt); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; + } + if( pSample->n ){ + memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n); } - memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n); pIdx->nSample++; } rc = sqlite3_finalize(pStmt); @@ -92775,7 +99733,7 @@ static int loadStatTbl( static int loadStat4(sqlite3 *db, const char *zDb){ int rc = SQLITE_OK; /* Result codes from subroutines */ - assert( db->lookaside.bEnabled==0 ); + assert( db->lookaside.bDisable ); if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){ rc = loadStatTbl(db, 0, "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", @@ -92820,49 +99778,56 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ analysisInfo sInfo; HashElem *i; char *zSql; - int rc; + int rc = SQLITE_OK; + Schema *pSchema = db->aDb[iDb].pSchema; assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); /* Clear any prior statistics */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){ + Table *pTab = sqliteHashData(i); + pTab->tabFlags &= ~TF_HasStat1; + } + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); - sqlite3DefaultRowEst(pIdx); + pIdx->hasStat1 = 0; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; #endif } - /* Check to make sure the sqlite_stat1 table exists */ - sInfo.db = db; - sInfo.zDatabase = db->aDb[iDb].zName; - if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ - return SQLITE_ERROR; - } - /* Load new statistics out of the sqlite_stat1 table */ - zSql = sqlite3MPrintf(db, - "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); - sqlite3DbFree(db, zSql); + sInfo.db = db; + sInfo.zDatabase = db->aDb[iDb].zDbSName; + if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ + zSql = sqlite3MPrintf(db, + "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); + if( zSql==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); + sqlite3DbFree(db, zSql); + } } + /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ + Index *pIdx = sqliteHashData(i); + if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); + } /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){ - int lookasideEnabled = db->lookaside.bEnabled; - db->lookaside.bEnabled = 0; + db->lookaside.bDisable++; rc = loadStat4(db, sInfo.zDatabase); - db->lookaside.bEnabled = lookasideEnabled; + db->lookaside.bDisable--; } - for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3_free(pIdx->aiRowEst); pIdx->aiRowEst = 0; @@ -92870,7 +99835,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ #endif if( rc==SQLITE_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } return rc; } @@ -92951,7 +99916,8 @@ static void attachFunc( char *zPath = 0; char *zErr = 0; unsigned int flags; - Db *aNew; + Db *aNew; /* New array of Db pointers */ + Db *pNew; /* Db object for the newly attached database */ char *zErrDyn = 0; sqlite3_vfs *pVfs; @@ -92974,12 +99940,8 @@ static void attachFunc( ); goto attach_error; } - if( !db->autoCommit ){ - zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); - goto attach_error; - } for(i=0; inDb; i++){ - char *z = db->aDb[i].zName; + char *z = db->aDb[i].zDbSName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); @@ -92991,7 +99953,7 @@ static void attachFunc( ** hash tables. */ if( db->aDb==db->aDbStatic ){ - aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 ); + aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ @@ -92999,8 +99961,8 @@ static void attachFunc( if( aNew==0 ) return; } db->aDb = aNew; - aNew = &db->aDb[db->nDb]; - memset(aNew, 0, sizeof(*aNew)); + pNew = &db->aDb[db->nDb]; + memset(pNew, 0, sizeof(*pNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may @@ -93009,43 +99971,45 @@ static void attachFunc( flags = db->openFlags; rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); if( rc!=SQLITE_OK ){ - if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; - rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); + rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); sqlite3_free( zPath ); db->nDb++; + db->skipBtreeMutex = 0; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; - aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); - if( !aNew->pSchema ){ - rc = SQLITE_NOMEM; - }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ + pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt); + if( !pNew->pSchema ){ + rc = SQLITE_NOMEM_BKPT; + }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){ zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } - sqlite3BtreeEnter(aNew->pBt); - pPager = sqlite3BtreePager(aNew->pBt); + sqlite3BtreeEnter(pNew->pBt); + pPager = sqlite3BtreePager(pNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); - sqlite3BtreeSecureDelete(aNew->pBt, + sqlite3BtreeSecureDelete(pNew->pBt, sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); #ifndef SQLITE_OMIT_PAGER_PRAGMAS - sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK)); + sqlite3BtreeSetPagerFlags(pNew->pBt, + PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif - sqlite3BtreeLeave(aNew->pBt); + sqlite3BtreeLeave(pNew->pBt); } - aNew->safety_level = 3; - aNew->zName = sqlite3DbStrDup(db, zName); - if( rc==SQLITE_OK && aNew->zName==0 ){ - rc = SQLITE_NOMEM; + pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + pNew->zDbSName = sqlite3DbStrDup(db, zName); + if( rc==SQLITE_OK && pNew->zDbSName==0 ){ + rc = SQLITE_NOMEM_BKPT; } @@ -93073,7 +100037,7 @@ static void attachFunc( case SQLITE_NULL: /* No key specified. Use the key from the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ + if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); } break; @@ -93111,7 +100075,7 @@ static void attachFunc( sqlite3ResetAllSchemasOfConnection(db); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); sqlite3DbFree(db, zErrDyn); zErrDyn = sqlite3MPrintf(db, "out of memory"); }else if( zErrDyn==0 ){ @@ -93156,7 +100120,7 @@ static void detachFunc( for(i=0; inDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; - if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; + if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break; } if( i>=db->nDb ){ @@ -93167,11 +100131,6 @@ static void detachFunc( sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } - if( !db->autoCommit ){ - sqlite3_snprintf(sizeof(zErr), zErr, - "cannot DETACH database within transaction"); - goto detach_error; - } if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; @@ -93206,6 +100165,7 @@ static void codeAttach( sqlite3* db = pParse->db; int regArgs; + if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; @@ -93241,11 +100201,11 @@ static void codeAttach( assert( v || db->mallocFailed ); if( v ){ - sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3); + sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3, + (char *)pFunc, P4_FUNCDEF); assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg ); sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg)); - sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); - + /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this ** statement only). For DETACH, set it to false (expire all existing ** statements). @@ -93270,12 +100230,10 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ - detachFunc, /* xFunc */ - 0, /* xStep */ + detachFunc, /* xSFunc */ 0, /* xFinalize */ "sqlite_detach", /* zName */ - 0, /* pHash */ - 0 /* pDestructor */ + {0} }; codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname); } @@ -93291,12 +100249,10 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ - attachFunc, /* xFunc */ - 0, /* xStep */ + attachFunc, /* xSFunc */ 0, /* xFinalize */ "sqlite_attach", /* zName */ - 0, /* pHash */ - 0 /* pDestructor */ + {0} }; codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); } @@ -93318,7 +100274,7 @@ SQLITE_PRIVATE void sqlite3FixInit( db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; - pFix->zDb = db->aDb[iDb].zName; + pFix->zDb = db->aDb[iDb].zDbSName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; @@ -93415,7 +100371,7 @@ SQLITE_PRIVATE int sqlite3FixExpr( return 1; } } - if( ExprHasProperty(pExpr, EP_TokenOnly) ) break; + if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; }else{ @@ -93536,7 +100492,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep( ** Setting the auth function to NULL disables this hook. The default ** setting of the auth function is NULL. */ -SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( +SQLITE_API int sqlite3_set_authorizer( sqlite3 *db, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg @@ -93576,21 +100532,20 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ - sqlite3 *db = pParse->db; /* Database handle */ - char *zDb = db->aDb[iDb].zName; /* Name of attached database */ - int rc; /* Auth callback return code */ + sqlite3 *db = pParse->db; /* Database handle */ + char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */ + int rc; /* Auth callback return code */ + if( db->init.busy ) return SQLITE_OK; rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser #endif ); if( rc==SQLITE_DENY ){ - if( db->nDb>2 || iDb!=0 ){ - sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol); - }else{ - sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol); - } + char *z = sqlite3_mprintf("%s.%s", zTab, zCol); + if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); + sqlite3ErrorMsg(pParse, "access to %z is prohibited", z); pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){ sqliteAuthBadReturnCode(pParse); @@ -93684,6 +100639,18 @@ SQLITE_PRIVATE int sqlite3AuthCheck( if( db->xAuth==0 ){ return SQLITE_OK; } + + /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the + ** callback are either NULL pointers or zero-terminated strings that + ** contain additional details about the action to be authorized. + ** + ** The following testcase() macros show that any of the 3rd through 6th + ** parameters can be either NULL or a string. */ + testcase( zArg1==0 ); + testcase( zArg2==0 ); + testcase( zArg3==0 ); + testcase( pParse->zAuthContext==0 ); + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser @@ -93756,25 +100723,16 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){ */ /* #include "sqliteInt.h" */ -/* -** This routine is called when a new SQL statement is beginning to -** be parsed. Initialize the pParse structure as needed. -*/ -SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){ - pParse->explain = (u8)explainFlag; - pParse->nVar = 0; -} - #ifndef SQLITE_OMIT_SHARED_CACHE /* ** The TableLock structure is only used by the sqlite3TableLock() and ** codeTableLocks() functions. */ struct TableLock { - int iDb; /* The database containing the table to be locked */ - int iTab; /* The root page of the table to be locked */ - u8 isWriteLock; /* True for write lock. False for a read lock */ - const char *zName; /* Name of the table */ + int iDb; /* The database containing the table to be locked */ + int iTab; /* The root page of the table to be locked */ + u8 isWriteLock; /* True for write lock. False for a read lock */ + const char *zLockName; /* Name of the table */ }; /* @@ -93800,6 +100758,8 @@ SQLITE_PRIVATE void sqlite3TableLock( TableLock *p; assert( iDb>=0 ); + if( iDb==1 ) return; + if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; for(i=0; inTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ @@ -93816,10 +100776,10 @@ SQLITE_PRIVATE void sqlite3TableLock( p->iDb = iDb; p->iTab = iTab; p->isWriteLock = isWriteLock; - p->zName = zName; + p->zLockName = zName; }else{ pToplevel->nTableLock = 0; - pToplevel->db->mallocFailed = 1; + sqlite3OomFault(pToplevel->db); } } @@ -93838,7 +100798,7 @@ static void codeTableLocks(Parse *pParse){ TableLock *p = &pParse->aTableLock[i]; int p1 = p->iDb; sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock, - p->zName, P4_STATIC); + p->zLockName, P4_STATIC); } } #else @@ -93887,15 +100847,14 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ assert( !pParse->isMultiWrite || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ - while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){} sqlite3VdbeAddOp0(v, OP_Halt); #if SQLITE_USER_AUTHENTICATION if( pParse->nTableLock>0 && db->init.busy==0 ){ sqlite3UserAuthInit(db); if( db->auth.authLevelrc = SQLITE_AUTH_USER; sqlite3ErrorMsg(pParse, "user not authenticated"); + pParse->rc = SQLITE_AUTH_USER; return; } } @@ -93914,14 +100873,16 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); sqlite3VdbeJumpHere(v, 0); for(iDb=0; iDbnDb; iDb++){ + Schema *pSchema; if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; sqlite3VdbeUsesBtree(v, iDb); + pSchema = db->aDb[iDb].pSchema; sqlite3VdbeAddOp4Int(v, OP_Transaction, /* Opcode */ iDb, /* P1 */ DbMaskTest(pParse->writeMask,iDb), /* P2 */ - pParse->cookieValue[iDb], /* P3 */ - db->aDb[iDb].pSchema->iGeneration /* P4 */ + pSchema->schema_cookie, /* P3 */ + pSchema->iGeneration /* P4 */ ); if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); VdbeComment((v, @@ -93969,15 +100930,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; - pParse->colNamesSet = 0; }else{ pParse->rc = SQLITE_ERROR; } - pParse->nTab = 0; - pParse->nMem = 0; - pParse->nSet = 0; - pParse->nVar = 0; - DbMaskZero(pParse->cookieMask); } /* @@ -93997,8 +100952,7 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ char *zSql; char *zErrMsg = 0; sqlite3 *db = pParse->db; -# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar)) - char saveBuf[SAVE_SZ]; + char saveBuf[PARSE_TAIL_SZ]; if( pParse->nErr ) return; assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ @@ -94009,12 +100963,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ return; /* A malloc must have failed */ } pParse->nested++; - memcpy(saveBuf, &pParse->nVar, SAVE_SZ); - memset(&pParse->nVar, 0, SAVE_SZ); + memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); + memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); sqlite3RunParser(pParse, zSql, &zErrMsg); sqlite3DbFree(db, zErrMsg); sqlite3DbFree(db, zSql); - memcpy(&pParse->nVar, saveBuf, SAVE_SZ); + memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; } @@ -94053,14 +101007,22 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha return 0; } #endif - for(i=OMIT_TEMPDB; inDb; i++){ - int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; - assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); - if( p ) break; + while(1){ + for(i=OMIT_TEMPDB; inDb; i++){ + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){ + assert( sqlite3SchemaMutexHeld(db, j, 0) ); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); + if( p ) return p; + } + } + /* Not found. If the name we were looking for was temp.sqlite_master + ** then change the name to sqlite_temp_master and try again. */ + if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break; + if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break; + zName = TEMP_MASTER_NAME; } - return p; + return 0; } /* @@ -94075,7 +101037,7 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha */ SQLITE_PRIVATE Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ - int isView, /* True if looking for a VIEW rather than a TABLE */ + u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */ const char *zName, /* Name of the table we are looking for */ const char *zDbase /* Name of the database. Might be NULL */ ){ @@ -94089,24 +101051,29 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ - const char *zMsg = isView ? "no such view" : "no such table"; + const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3FindDbName(pParse->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. */ Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); + if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ + pMod = sqlite3PragmaVtabRegister(pParse->db, zName); + } if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ return pMod->pEpoTab; } } #endif - if( zDbase ){ - sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); - }else{ - sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); + 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; } - pParse->checkSchema = 1; } return p; @@ -94123,18 +101090,18 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( */ SQLITE_PRIVATE Table *sqlite3LocateTableItem( Parse *pParse, - int isView, + u32 flags, struct SrcList_item *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); - zDb = pParse->db->aDb[iDb].zName; + zDb = pParse->db->aDb[iDb].zDbSName; }else{ zDb = p->zDatabase; } - return sqlite3LocateTable(pParse, isView, p->zName, zDb); + return sqlite3LocateTable(pParse, flags, p->zName, zDb); } /* @@ -94158,7 +101125,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); - if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; + if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; @@ -94211,7 +101178,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char } freeIndex(db, pIndex); } - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } /* @@ -94227,8 +101194,8 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ for(i=j=2; inDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ - sqlite3DbFree(db, pDb->zName); - pDb->zName = 0; + sqlite3DbFree(db, pDb->zDbSName); + pDb->zDbSName = 0; continue; } if( jaDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j])); db->nDb = j; if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); @@ -94247,28 +101213,26 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ /* ** Reset the schema for the database at index iDb. Also reset the -** TEMP schema. +** TEMP schema. The reset is deferred if db->nSchemaLock is not zero. +** Deferred resets may be run by calling with iDb<0. */ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ - Db *pDb; + int i; assert( iDbnDb ); - /* Case 1: Reset the single schema identified by iDb */ - pDb = &db->aDb[iDb]; - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); + if( iDb>=0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + DbSetProperty(db, iDb, DB_ResetWanted); + DbSetProperty(db, 1, DB_ResetWanted); + } - /* If any database other than TEMP is reset, then also reset TEMP - ** since TEMP might be holding triggers that reference tables in the - ** other database. - */ - if( iDb!=1 ){ - pDb = &db->aDb[1]; - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); + if( db->nSchemaLock==0 ){ + for(i=0; inDb; i++){ + if( DbHasProperty(db, i, DB_ResetWanted) ){ + sqlite3SchemaClear(db->aDb[i].pSchema); + } + } } - return; } /* @@ -94278,13 +101242,14 @@ 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); } } - db->flags &= ~SQLITE_InternChanges; + db->mDbFlags &= ~DBFLAG_SchemaChange; sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); sqlite3CollapseDatabaseArray(db); @@ -94294,7 +101259,7 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ ** This routine is called when a commit occurs. */ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){ - db->flags &= ~SQLITE_InternChanges; + db->mDbFlags &= ~DBFLAG_SchemaChange; } /* @@ -94309,8 +101274,6 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ for(i=0; inCol; i++, pCol++){ sqlite3DbFree(db, pCol->zName); sqlite3ExprDelete(db, pCol->pDflt); - sqlite3DbFree(db, pCol->zDflt); - sqlite3DbFree(db, pCol->zType); sqlite3DbFree(db, pCol->zColl); } sqlite3DbFree(db, pTable->aCol); @@ -94332,27 +101295,25 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ ** db parameter can be used with db->pnBytesFreed to measure the memory ** used by the Table object. */ -SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ +static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; - TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */ - - assert( !pTable || pTable->nRef>0 ); - - /* Do not delete the table until the reference count reaches zero. */ - if( !pTable ) return; - if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return; +#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. */ - TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ? - db->lookaside.nOut : 0 ); + int nLookaside = 0; + if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){ + nLookaside = sqlite3LookasideUsed(db, 0); + } +#endif /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; - assert( pIndex->pSchema==pTable->pSchema ); - if( !db || db->pnBytesFreed==0 ){ + assert( pIndex->pSchema==pTable->pSchema + || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); + if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 @@ -94379,8 +101340,15 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ - assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); + assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) ); } +SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ + /* Do not delete the table until the reference count reaches zero. */ + if( !pTable ) return; + if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return; + deleteTable(db, pTable); +} + /* ** Unlink the given table from the hash tables and the delete the @@ -94398,7 +101366,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); sqlite3DeleteTable(db, p); - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } /* @@ -94431,7 +101399,7 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ */ SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){ Vdbe *v = sqlite3GetVdbe(p); - sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb)); + sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5); if( p->nTab==0 ){ p->nTab = 1; @@ -94448,12 +101416,11 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){ int i = -1; /* Database number */ if( zName ){ Db *pDb; - int n = sqlite3Strlen30(zName); for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ - if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) && - 0==sqlite3StrICmp(pDb->zName, zName) ){ - break; - } + if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break; + /* "main" is always an acceptable alias for the primary database + ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */ + if( i==0 && 0==sqlite3_stricmp("main", zName) ) break; } } return i; @@ -94499,7 +101466,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName( int iDb; /* Database holding the object */ sqlite3 *db = pParse->db; - if( ALWAYS(pName2!=0) && pName2->n>0 ){ + assert( pName2!=0 ); + if( pName2->n>0 ){ if( db->init.busy ) { sqlite3ErrorMsg(pParse, "corrupt database"); return -1; @@ -94511,7 +101479,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName( return -1; } }else{ - assert( db->init.iDb==0 || db->init.busy ); + assert( db->init.iDb==0 || db->init.busy + || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } @@ -94588,62 +101557,46 @@ SQLITE_PRIVATE void sqlite3StartTable( int iDb; /* Database number to create the table in */ Token *pName; /* Unqualified name of the table to create */ - /* The table or view name to create is passed to this routine via tokens - ** pName1 and pName2. If the table name was fully qualified, for example: - ** - ** CREATE TABLE xxx.yyy (...); - ** - ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if - ** the table name is not fully qualified, i.e.: - ** - ** CREATE TABLE yyy(...); - ** - ** Then pName1 is set to "yyy" and pName2 is "". - ** - ** The call below sets the pName pointer to point at the token (pName1 or - ** pName2) that stores the unqualified table name. The variable iDb is - ** set to the index of the database that the table or view is to be - ** created in. - */ - iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); - if( iDb<0 ) return; - if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ - /* If creating a temp table, the name may not be qualified. Unless - ** the database name is "temp" anyway. */ - sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); - return; + if( db->init.busy && db->init.newTnum==1 ){ + /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */ + iDb = db->init.iDb; + zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); + pName = pName1; + }else{ + /* The common case */ + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); + if( iDb<0 ) return; + if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ + /* If creating a temp table, the name may not be qualified. Unless + ** the database name is "temp" anyway. */ + sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); + return; + } + if( !OMIT_TEMPDB && isTemp ) iDb = 1; + zName = sqlite3NameFromToken(db, pName); } - if( !OMIT_TEMPDB && isTemp ) iDb = 1; - pParse->sNameToken = *pName; - zName = sqlite3NameFromToken(db, pName); if( zName==0 ) return; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; #ifndef SQLITE_OMIT_AUTHORIZATION - assert( (isTemp & 1)==isTemp ); + assert( isTemp==0 || isTemp==1 ); + assert( isView==0 || isView==1 ); { - int code; - char *zDb = db->aDb[iDb].zName; + static const u8 aCode[] = { + SQLITE_CREATE_TABLE, + SQLITE_CREATE_TEMP_TABLE, + SQLITE_CREATE_VIEW, + SQLITE_CREATE_TEMP_VIEW + }; + char *zDb = db->aDb[iDb].zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto begin_table_error; } - if( isView ){ - if( !OMIT_TEMPDB && isTemp ){ - code = SQLITE_CREATE_TEMP_VIEW; - }else{ - code = SQLITE_CREATE_VIEW; - } - }else{ - if( !OMIT_TEMPDB && isTemp ){ - code = SQLITE_CREATE_TEMP_TABLE; - }else{ - code = SQLITE_CREATE_TABLE; - } - } - if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){ + if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], + zName, 0, zDb) ){ goto begin_table_error; } } @@ -94657,7 +101610,7 @@ SQLITE_PRIVATE void sqlite3StartTable( ** collisions. */ if( !IN_DECLARE_VTAB ){ - char *zDb = db->aDb[iDb].zName; + char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } @@ -94679,16 +101632,20 @@ SQLITE_PRIVATE void sqlite3StartTable( pTable = sqlite3DbMallocZero(db, sizeof(Table)); if( pTable==0 ){ - db->mallocFailed = 1; - pParse->rc = SQLITE_NOMEM; + assert( db->mallocFailed ); + pParse->rc = SQLITE_NOMEM_BKPT; pParse->nErr++; goto begin_table_error; } pTable->zName = zName; pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; - pTable->nRef = 1; + pTable->nTabRef = 1; +#ifdef SQLITE_DEFAULT_ROWEST + pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); +#else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); +#endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; @@ -94736,10 +101693,8 @@ SQLITE_PRIVATE void sqlite3StartTable( addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? 1 : SQLITE_MAX_FILE_FORMAT; - sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3); - sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); sqlite3VdbeJumpHere(v, addr1); /* This just creates a place-holder record in the sqlite_master table. @@ -94757,7 +101712,8 @@ SQLITE_PRIVATE void sqlite3StartTable( }else #endif { - pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2); + pParse->addrCrTab = + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenMasterTable(pParse, iDb); sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); @@ -94798,21 +101754,23 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ ** first to get things going. Then this routine is called for each ** column. */ -SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){ +SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ Table *p; int i; char *z; + char *zType; Column *pCol; sqlite3 *db = pParse->db; if( (p = pParse->pNewTable)==0 ) return; -#if SQLITE_MAX_COLUMN if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } -#endif - z = sqlite3NameFromToken(db, pName); + z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); if( z==0 ) return; + memcpy(z, pName->z, pName->n); + z[pName->n] = 0; + sqlite3Dequote(z); for(i=0; inCol; i++){ if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); @@ -94834,13 +101792,21 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){ pCol->zName = z; sqlite3ColumnPropertiesFromName(p, pCol); - /* If there is no type specified, columns have the default affinity - ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will - ** be called next to set pCol->affinity correctly. - */ - pCol->affinity = SQLITE_AFF_BLOB; - pCol->szEst = 1; + if( pType->n==0 ){ + /* If there is no type specified, columns have the default affinity + ** 'BLOB'. */ + pCol->affinity = SQLITE_AFF_BLOB; + pCol->szEst = 1; + }else{ + zType = z + sqlite3Strlen30(z) + 1; + memcpy(zType, pType->z, pType->n); + zType[pType->n] = 0; + sqlite3Dequote(zType); + pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst); + pCol->colFlags |= COLFLAG_HASTYPE; + } p->nCol++; + pParse->constraintName.n = 0; } /* @@ -94854,6 +101820,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; p->aCol[p->nCol-1].notNull = (u8)onError; + p->tabFlags |= TF_HasNotNull; } /* @@ -94886,7 +101853,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ char aff = SQLITE_AFF_NUMERIC; const char *zChar = 0; - if( zIn==0 ) return aff; + assert( zIn!=0 ); while( zIn[0] ){ h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff]; zIn++; @@ -94943,28 +101910,6 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ return aff; } -/* -** This routine is called by the parser while in the middle of -** parsing a CREATE TABLE statement. The pFirst token is the first -** token in the sequence of tokens that describe the type of the -** column currently under construction. pLast is the last token -** in the sequence. Use this information to construct a string -** that contains the typename of the column and store that string -** in zType. -*/ -SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){ - Table *p; - Column *pCol; - - p = pParse->pNewTable; - if( p==0 || NEVER(p->nCol<1) ) return; - pCol = &p->aCol[p->nCol-1]; - assert( pCol->zType==0 || CORRUPT_DB ); - sqlite3DbFree(pParse->db, pCol->zType); - pCol->zType = sqlite3NameFromToken(pParse->db, pType); - pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst); -} - /* ** The expression is the default value for the most recently added column ** of the table currently under construction. @@ -94990,11 +101935,16 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){ ** tokens that point to volatile memory. The 'span' of the expression ** is required by pragma table_info. */ + Expr x; sqlite3ExprDelete(db, pCol->pDflt); - pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE); - sqlite3DbFree(db, pCol->zDflt); - pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart, - (int)(pSpan->zEnd - pSpan->zStart)); + memset(&x, 0, sizeof(x)); + x.op = TK_SPAN; + x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart, + (int)(pSpan->zEnd - pSpan->zStart)); + x.pLeft = pSpan->pExpr; + x.flags = EP_Skip; + pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); + sqlite3DbFree(db, x.u.zToken); } } sqlite3ExprDelete(db, pSpan->pExpr); @@ -95050,10 +102000,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; - char *zType = 0; + Column *pCol = 0; int iCol = -1, i; int nTerm; - if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit; + if( pTab==0 ) goto primary_key_exit; if( pTab->tabFlags & TF_HasPrimaryKey ){ sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); @@ -95062,8 +102012,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( pTab->tabFlags |= TF_HasPrimaryKey; if( pList==0 ){ iCol = pTab->nCol - 1; - pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; - zType = pTab->aCol[iCol].zType; + pCol = &pTab->aCol[iCol]; + pCol->colFlags |= COLFLAG_PRIMKEY; nTerm = 1; }else{ nTerm = pList->nExpr; @@ -95075,8 +102025,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( const char *zCName = pCExpr->u.zToken; for(iCol=0; iColnCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ - pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; - zType = pTab->aCol[iCol].zType; + pCol = &pTab->aCol[iCol]; + pCol->colFlags |= COLFLAG_PRIMKEY; break; } } @@ -95084,7 +102034,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( } } if( nTerm==1 - && zType && sqlite3StrICmp(zType, "INTEGER")==0 + && pCol + && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 && sortOrder!=SQLITE_SO_DESC ){ pTab->iPKey = iCol; @@ -95098,12 +102049,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( "INTEGER PRIMARY KEY"); #endif }else{ - Index *p; - p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, - 0, sortOrder, 0); - if( p ){ - p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; - } + sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, + 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); pList = 0; } @@ -95222,15 +102169,16 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){ ** set back to prior value. But schema changes are infrequent ** and the probability of hitting the same cookie value is only ** 1 chance in 2^32. So we're safe enough. +** +** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments +** the schema-version whenever the schema changes. */ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){ - int r1 = sqlite3GetTempReg(pParse); sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1); - sqlite3ReleaseTempReg(pParse, r1); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, + db->aDb[iDb].pSchema->schema_cookie+1); } /* @@ -95312,7 +102260,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){ n += 35 + 6*p->nCol; zStmt = sqlite3DbMallocRaw(0, n); if( zStmt==0 ){ - db->mallocFailed = 1; + sqlite3OomFault(db); return 0; } sqlite3_snprintf(n, zStmt, "CREATE TABLE "); @@ -95365,7 +102313,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ assert( pIdx->isResized==0 ); nByte = (sizeof(char*) + sizeof(i16) + 1)*N; zExtra = sqlite3DbMallocZero(db, nByte); - if( zExtra==0 ) return SQLITE_NOMEM; + if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); pIdx->azColl = (const char**)zExtra; zExtra += sizeof(char*)*N; @@ -95422,21 +102370,22 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** -** (1) Convert the OP_CreateTable into an OP_CreateIndex. There is -** no rowid btree for a WITHOUT ROWID. Instead, the canonical -** data storage is a covering index btree. -** (2) Bypass the creation of the sqlite_master table entry +** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. +** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY +** into BTREE_BLOBKEY. +** (3) Bypass the creation of the sqlite_master table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. -** (3) Set the Index.tnum of the PRIMARY KEY Index object in the +** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. -** (4) Set all columns of the PRIMARY KEY schema object to be NOT NULL. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus -** columns are part of KeyInfo.nXField and are not used for +** columns are part of KeyInfo.nAllField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. +** +** For virtual tables, only (1) is performed. */ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; @@ -95446,13 +102395,26 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; - /* Convert the OP_CreateTable opcode that would normally create the - ** root-page for the table into an OP_CreateIndex opcode. The index - ** created will become the PRIMARY KEY index. + /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) + */ + if( !db->init.imposterTable ){ + for(i=0; inCol; i++){ + if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ + pTab->aCol[i].notNull = OE_Abort; + } + } + } + + /* The remaining transformations only apply to b-tree tables, not to + ** virtual tables */ + if( IN_DECLARE_VTAB ) return; + + /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY + ** into BTREE_BLOBKEY. */ if( pParse->addrCrTab ){ assert( v ); - sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex); + sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally @@ -95461,29 +102423,20 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( pTab->iPKey>=0 ){ ExprList *pList; Token ipkToken; - ipkToken.z = pTab->aCol[pTab->iPKey].zName; - ipkToken.n = sqlite3Strlen30(ipkToken.z); + sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); - pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); - if( pPk==0 ) return; - pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY; + sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, + SQLITE_IDXTYPE_PRIMARYKEY); + if( db->mallocFailed ) return; + pPk = sqlite3PrimaryKeyIndex(pTab); pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); - /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master - ** table entry. This is only required if currently generating VDBE - ** code for a CREATE TABLE (not when parsing one as part of reading - ** a database schema). */ - if( v ){ - assert( db->init.busy==0 ); - sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); - } - /* ** Remove all redundant columns from the PRIMARY KEY. For example, change ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later @@ -95498,17 +102451,18 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ } pPk->nKeyCol = j; } - pPk->isCovering = 1; assert( pPk!=0 ); + pPk->isCovering = 1; + if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nKeyCol; - /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except, - ** do not enforce this for imposter tables.) */ - if( !db->init.imposterTable ){ - for(i=0; iaCol[pPk->aiColumn[i]].notNull = OE_Abort; - } - pPk->uniqNotNull = 1; + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master + ** table entry. This is only required if currently generating VDBE + ** code for a CREATE TABLE (not when parsing one as part of reading + ** a database schema). */ + if( v && pPk->tnum>0 ){ + assert( db->init.busy==0 ); + sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); } /* The root page of the PRIMARY KEY is the table root page */ @@ -95605,9 +102559,13 @@ SQLITE_PRIVATE void sqlite3EndTable( ** So do not write to the disk again. Extract the root page number ** for the table from the db->init.newTnum field. (The page number ** should have been put there by the sqliteOpenCb routine.) + ** + ** If the root page number is 1, that means this is the sqlite_master + ** table itself. So mark it read-only. */ if( db->init.busy ){ p->tnum = db->init.newTnum; + if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } /* Special processing for WITHOUT ROWID Tables */ @@ -95708,7 +102666,7 @@ SQLITE_PRIVATE void sqlite3EndTable( sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); sqlite3Select(pParse, pSelect, &dest); - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); + sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); if( pParse->nErr ) return; pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); @@ -95750,7 +102708,7 @@ SQLITE_PRIVATE void sqlite3EndTable( "UPDATE %Q.%s " "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zDbSName, MASTER_NAME, zType, p->zName, p->zName, @@ -95765,13 +102723,13 @@ SQLITE_PRIVATE void sqlite3EndTable( /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ - if( p->tabFlags & TF_Autoincrement ){ + if( (p->tabFlags & TF_Autoincrement)!=0 ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", - pDb->zName + pDb->zDbSName ); } } @@ -95792,11 +102750,11 @@ SQLITE_PRIVATE void sqlite3EndTable( pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ - db->mallocFailed = 1; + sqlite3OomFault(db); return; } pParse->pNewTable = 0; - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; #ifndef SQLITE_OMIT_ALTERTABLE if( !p->pSelect ){ @@ -95895,14 +102853,21 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + int rc; +#endif +#ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ - u8 bEnabledLA; /* Saved db->lookaside.bEnabled state */ +#endif assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3VtabCallConnect(pParse, pTable) ){ - return SQLITE_ERROR; + db->nSchemaLock++; + rc = sqlite3VtabCallConnect(pParse, pTable); + db->nSchemaLock--; + if( rc ){ + return 1; } if( IsVirtual(pTable) ) return 0; #endif @@ -95942,45 +102907,56 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ ** statement that defines the view. */ assert( pTable->pSelect ); - bEnabledLA = db->lookaside.bEnabled; - if( pTable->pCheck ){ - db->lookaside.bEnabled = 0; - sqlite3ColumnsFromExprList(pParse, pTable->pCheck, - &pTable->nCol, &pTable->aCol); - }else{ - pSel = sqlite3SelectDup(db, pTable->pSelect, 0); - if( pSel ){ - n = pParse->nTab; - sqlite3SrcListAssignCursors(pParse, pSel->pSrc); - pTable->nCol = -1; - db->lookaside.bEnabled = 0; + pSel = sqlite3SelectDup(db, pTable->pSelect, 0); + if( pSel ){ + n = pParse->nTab; + sqlite3SrcListAssignCursors(pParse, pSel->pSrc); + pTable->nCol = -1; + db->lookaside.bDisable++; #ifndef SQLITE_OMIT_AUTHORIZATION - xAuth = db->xAuth; - db->xAuth = 0; - pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); - db->xAuth = xAuth; + xAuth = db->xAuth; + db->xAuth = 0; + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); + db->xAuth = xAuth; #else - pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); #endif - pParse->nTab = n; - if( pSelTab ){ - assert( pTable->aCol==0 ); - pTable->nCol = pSelTab->nCol; - pTable->aCol = pSelTab->aCol; - pSelTab->nCol = 0; - pSelTab->aCol = 0; - sqlite3DeleteTable(db, pSelTab); - assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); - }else{ - pTable->nCol = 0; - nErr++; + pParse->nTab = n; + if( pTable->pCheck ){ + /* CREATE VIEW name(arglist) AS ... + ** The names of the columns in the table are taken from + ** arglist which is stored in pTable->pCheck. The pCheck field + ** normally holds CHECK constraints on an ordinary table, but for + ** a VIEW it holds the list of column names. + */ + sqlite3ColumnsFromExprList(pParse, pTable->pCheck, + &pTable->nCol, &pTable->aCol); + if( db->mallocFailed==0 + && pParse->nErr==0 + && pTable->nCol==pSel->pEList->nExpr + ){ + sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel); } - sqlite3SelectDelete(db, pSel); - } else { + }else if( pSelTab ){ + /* CREATE VIEW name AS... without an argument list. Construct + ** the column names from the SELECT statement that defines the view. + */ + assert( pTable->aCol==0 ); + pTable->nCol = pSelTab->nCol; + pTable->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); + }else{ + pTable->nCol = 0; nErr++; } + sqlite3DeleteTable(db, pSelTab); + sqlite3SelectDelete(db, pSel); + db->lookaside.bDisable--; + } else { + nErr++; } - db->lookaside.bEnabled = bEnabledLA; pTable->pSchema->schemaFlags |= DB_UnresetViews; #endif /* SQLITE_OMIT_VIEW */ return nErr; @@ -96060,6 +103036,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 ); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM @@ -96074,7 +103051,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", - pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1); + pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1); #endif sqlite3ReleaseTempReg(pParse, r1); } @@ -96086,14 +103063,6 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ -#ifdef SQLITE_OMIT_AUTOVACUUM - Index *pIdx; - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - destroyRootPage(pParse, pTab->tnum, iDb); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - destroyRootPage(pParse, pIdx->tnum, iDb); - } -#else /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically @@ -96136,7 +103105,6 @@ static void destroyTable(Parse *pParse, Table *pTab){ iDestroyed = iLargest; } } -#endif } /* @@ -96150,7 +103118,7 @@ static void sqlite3ClearStatTables( const char *zName /* Name of index or table */ ){ int i; - const char *zDbName = pParse->db->aDb[iDb].zName; + const char *zDbName = pParse->db->aDb[iDb].zDbSName; for(i=1; i<=4; i++){ char zTab[24]; sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i); @@ -96203,7 +103171,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in if( pTab->tabFlags & TF_Autoincrement ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", - pDb->zName, pTab->zName + pDb->zDbSName, pTab->zName ); } #endif @@ -96217,7 +103185,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", - pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); + pDb->zDbSName, MASTER_NAME, pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } @@ -96250,6 +103218,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; + assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; @@ -96270,7 +103239,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, { int code; const char *zTab = SCHEMA_TABLE(iDb); - const char *zDb = db->aDb[iDb].zName; + const char *zDb = db->aDb[iDb].zDbSName; const char *zArg2 = 0; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; @@ -96445,7 +103414,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( pFKey->zTo, (void *)pFKey ); if( pNextTo==pFKey ){ - db->mallocFailed = 1; + sqlite3OomFault(db); goto fk_end; } if( pNextTo ){ @@ -96511,7 +103480,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, - db->aDb[iDb].zName ) ){ + db->aDb[iDb].zDbSName ) ){ return; } #endif @@ -96527,6 +103496,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ tnum = pIndex->tnum; } pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); + assert( pKey!=0 || db->mallocFailed || pParse->nErr ); /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; @@ -96550,8 +103520,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); - assert( pKey!=0 || db->mallocFailed || pParse->nErr ); - if( IsUniqueIndex(pIndex) && pKey!=0 ){ + if( IsUniqueIndex(pIndex) ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeGoto(v, j2); addr2 = sqlite3VdbeCurrentAddr(v); @@ -96562,8 +103531,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); - sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1); - sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); + sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); @@ -96620,12 +103589,8 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. -** -** If the index is created successfully, return a pointer to the new Index -** structure. This is used by sqlite3AddPrimaryKey() to mark the index -** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY) */ -SQLITE_PRIVATE Index *sqlite3CreateIndex( +SQLITE_PRIVATE void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ @@ -96635,9 +103600,9 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( Token *pStart, /* The CREATE token that begins this statement */ Expr *pPIWhere, /* WHERE clause for partial indices */ int sortOrder, /* Sort order of primary key when pList==NULL */ - int ifNotExist /* Omit error if index already exists */ + int ifNotExist, /* Omit error if index already exists */ + u8 idxType /* The index type */ ){ - Index *pRet = 0; /* Pointer to return */ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ @@ -96655,7 +103620,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ - if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){ + if( db->mallocFailed || pParse->nErr>0 ){ + goto exit_create_index; + } + if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ @@ -96764,7 +103732,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( goto exit_create_index; } } - if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ + if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); }else{ @@ -96781,13 +103749,20 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( if( zName==0 ){ goto exit_create_index; } + + /* Automatic index names generated from within sqlite3_declare_vtab() + ** must have names that are distinct from normal automatic index names. + ** The following statement converts "sqlite3_autoindex..." into + ** "sqlite3_butoindex..." in order to make the names distinct. + ** The "vtab_err.test" test demonstrates the need of this statement. */ + if( IN_DECLARE_VTAB ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { - const char *zDb = pDb->zName; + const char *zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } @@ -96805,8 +103780,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( */ if( pList==0 ){ Token prevCol; - prevCol.z = pTab->aCol[pTab->nCol-1].zName; - prevCol.n = sqlite3Strlen30(prevCol.z); + sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; @@ -96845,7 +103819,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; - pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE; + pIndex->idxType = idxType; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ @@ -96955,6 +103929,20 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( sqlite3DefaultRowEst(pIndex); if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); + /* If this index contains every column of its table, then mark + ** it as a covering index */ + assert( HasRowid(pTab) + || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 ); + if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ + pIndex->isCovering = 1; + for(j=0; jnCol; j++){ + if( j==pTab->iPKey ) continue; + if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue; + pIndex->isCovering = 0; + break; + } + } + if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or @@ -96992,7 +103980,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; z1 = pIdx->azColl[k]; z2 = pIndex->azColl[k]; - if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break; + if( sqlite3StrICmp(z1, z2) ) break; } if( k==pIdx->nKeyCol ){ if( pIdx->onError!=pIndex->onError ){ @@ -97011,7 +103999,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( pIdx->onError = pIndex->onError; } } - pRet = pIdx; + if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } @@ -97023,15 +104011,16 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; + assert( !IN_DECLARE_VTAB ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ - db->mallocFailed = 1; + sqlite3OomFault(db); goto exit_create_index; } - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; if( pTblName!=0 ){ pIndex->tnum = db->init.newTnum; } @@ -97067,7 +104056,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( ** that case the convertToWithoutRowidTable() routine will replace ** the Noop with a Goto to jump over the VDBE code generated below. */ pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); - sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem); + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable @@ -97088,7 +104077,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( */ sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName, pTab->zName, iMem, @@ -97104,7 +104093,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); - sqlite3VdbeAddOp1(v, OP_Expire, 0); + sqlite3VdbeAddOp0(v, OP_Expire); } sqlite3VdbeJumpHere(v, pIndex->tnum); @@ -97129,7 +104118,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex( pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } - pRet = pIndex; pIndex = 0; } @@ -97140,7 +104128,6 @@ exit_create_index: sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); - return pRet; } /* @@ -97168,11 +104155,15 @@ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; + /* Indexes with default row estimates should not have stat1 data */ + assert( !pIdx->hasStat1 ); + /* Set the first entry (number of rows in the index) to the estimated - ** number of rows in the table. Or 10, if the estimated number of rows - ** in the table is less than that. */ + ** number of rows in the table, or half the number of rows in the table + ** for a partial index. But do not let the estimate drop below 10. */ a[0] = pIdx->pTable->nRowLogEst; - if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); + if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ @@ -97223,7 +104214,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; - const char *zDb = db->aDb[iDb].zName; + const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; @@ -97241,7 +104232,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName + db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName ); sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); sqlite3ChangeCookie(pParse, iDb); @@ -97332,7 +104323,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ sqlite3DbFree(db, pList->a[i].zName); } sqlite3DbFree(db, pList->a); - sqlite3DbFree(db, pList); + sqlite3DbFreeNN(db, pList); } /* @@ -97384,7 +104375,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( /* Allocate additional space if needed */ if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; - int nAlloc = pSrc->nSrc+nExtra; + int nAlloc = pSrc->nSrc*2+nExtra; int nGot; pNew = sqlite3DbRealloc(db, pSrc, sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); @@ -97457,12 +104448,17 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( ){ struct SrcList_item *pItem; assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ + assert( db!=0 ); if( pList==0 ){ - pList = sqlite3DbMallocZero(db, sizeof(SrcList) ); + pList = sqlite3DbMallocRawNN(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); } - pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc); if( db->mallocFailed ){ sqlite3SrcListDelete(db, pList); return 0; @@ -97472,12 +104468,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( pDatabase = 0; } if( pDatabase ){ - Token *pTemp = pDatabase; - pDatabase = pTable; - pTable = pTemp; + pItem->zName = sqlite3NameFromToken(db, pDatabase); + pItem->zDatabase = sqlite3NameFromToken(db, pTable); + }else{ + pItem->zName = sqlite3NameFromToken(db, pTable); + pItem->zDatabase = 0; } - pItem->zName = sqlite3NameFromToken(db, pTable); - pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); return pList; } @@ -97517,7 +104513,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ sqlite3ExprDelete(db, pItem->pOn); sqlite3IdListDelete(db, pItem->pUsing); } - sqlite3DbFree(db, pList); + sqlite3DbFreeNN(db, pList); } /* @@ -97582,8 +104578,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( */ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); - if( p && ALWAYS(p->nSrc>0) ){ - struct SrcList_item *pItem = &p->a[p->nSrc-1]; + if( p && pIndexedBy->n>0 ){ + struct SrcList_item *pItem; + assert( p->nSrc>0 ); + pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); @@ -97593,7 +104591,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI pItem->fg.notIndexed = 1; }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); - pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0); + pItem->fg.isIndexedBy = 1; } } } @@ -97641,7 +104639,7 @@ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){ } /* -** Begin a transaction +** Generate VDBE code for a BEGIN statement. */ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ sqlite3 *db; @@ -97651,7 +104649,6 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ assert( pParse!=0 ); db = pParse->db; assert( db!=0 ); -/* if( db->aDb[0].pBt==0 ) return; */ if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ return; } @@ -97663,40 +104660,29 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ sqlite3VdbeUsesBtree(v, i); } } - sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0); + sqlite3VdbeAddOp0(v, OP_AutoCommit); } /* -** Commit a transaction +** Generate VDBE code for a COMMIT or ROLLBACK statement. +** Code for ROLLBACK is generated if eType==TK_ROLLBACK. Otherwise +** code is generated for a COMMIT. */ -SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){ +SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){ Vdbe *v; + int isRollback; assert( pParse!=0 ); assert( pParse->db!=0 ); - if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){ + assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK ); + isRollback = eType==TK_ROLLBACK; + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, + isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( v ){ - sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0); - } -} - -/* -** Rollback a transaction -*/ -SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){ - Vdbe *v; - - assert( pParse!=0 ); - assert( pParse->db!=0 ); - if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){ - return; - } - v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1); + sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback); } } @@ -97746,7 +104732,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ db->aDb[1].pBt = pBt; assert( db->aDb[1].pSchema ); if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){ - db->mallocFailed = 1; + sqlite3OomFault(db); return 1; } } @@ -97761,15 +104747,13 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ */ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - sqlite3 *db = pToplevel->db; - assert( iDb>=0 && iDbnDb ); - assert( db->aDb[iDb].pBt!=0 || iDb==1 ); + assert( iDb>=0 && iDbdb->nDb ); + assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDbdb, iDb, 0) ); if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ DbMaskSet(pToplevel->cookieMask, iDb); - pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); } @@ -97785,7 +104769,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb) int i; for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; - if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){ + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){ sqlite3CodeVerifySchema(pParse, i); } } @@ -97863,7 +104847,7 @@ SQLITE_PRIVATE void sqlite3HaltConstraint( sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); - if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg); + sqlite3VdbeChangeP5(v, p5Errmsg); } /* @@ -97881,14 +104865,16 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); if( pIdx->aColExpr ){ - sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName); + sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName); }else{ for(j=0; jnKeyCol; j++){ char *zCol; assert( pIdx->aiColumn[j]>=0 ); zCol = pTab->aCol[pIdx->aiColumn[j]].zName; if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); - sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol); + sqlite3StrAccumAppendAll(&errMsg, pTab->zName); + sqlite3StrAccumAppend(&errMsg, ".", 1); + sqlite3StrAccumAppendAll(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); @@ -98032,7 +105018,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ if( iDb<0 ) return; z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); @@ -98053,10 +105039,6 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ /* ** Return a KeyInfo structure that is appropriate for the given Index. ** -** The KeyInfo structure for an index is cached in the Index object. -** So there might be multiple references to the returned pointer. The -** caller should not try to modify the KeyInfo object. -** ** The caller should invoke sqlite3KeyInfoUnref() on the returned object ** when it has finished using it. */ @@ -98121,10 +105103,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd( }else{ pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); } - assert( zName!=0 || pNew==0 ); - assert( db->mallocFailed==0 || pNew==0 ); + assert( (pNew!=0 && zName!=0) || db->mallocFailed ); - if( pNew==0 ){ + if( db->mallocFailed ){ sqlite3ExprListDelete(db, pArglist); sqlite3SelectDelete(db, pQuery); sqlite3DbFree(db, zName); @@ -98282,7 +105263,7 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( ** from the main database is substituted, if one is available. */ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ - if( pColl ){ + if( pColl && pColl->xCmp==0 ){ const char *zName = pColl->zName; sqlite3 *db = pParse->db; CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName); @@ -98318,8 +105299,8 @@ static CollSeq *findCollSeqEntry( pColl = sqlite3HashFind(&db->aCollSeq, zName); if( 0==pColl && create ){ - int nName = sqlite3Strlen30(zName); - pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1); + int nName = sqlite3Strlen30(zName) + 1; + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; @@ -98329,7 +105310,6 @@ static CollSeq *findCollSeqEntry( pColl[2].zName = (char*)&pColl[3]; pColl[2].enc = SQLITE_UTF16BE; memcpy(pColl[0].zName, zName, nName); - pColl[0].zName[nName] = 0; pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); /* If a malloc() failure occurred in sqlite3HashInsert(), it will @@ -98338,7 +105318,7 @@ static CollSeq *findCollSeqEntry( */ assert( pDel==0 || pDel==pColl ); if( pDel!=0 ){ - db->mallocFailed = 1; + sqlite3OomFault(db); sqlite3DbFree(db, pDel); pColl = 0; } @@ -98404,8 +105384,8 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq( ** 5: UTF16 byte order conversion required - argument count matches exactly ** 6: Perfect match: encoding and argument count match exactly. ** -** If nArg==(-2) then any function with a non-null xStep or xFunc is -** a perfect match and any function with both xStep and xFunc NULL is +** If nArg==(-2) then any function with a non-null xSFunc is +** a perfect match and any function with xSFunc NULL is ** a non-match. */ #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ @@ -98417,7 +105397,7 @@ static int matchQuality( int match; /* nArg of -2 is a special case */ - if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH; + if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; /* Wrong number of arguments means "no match" */ if( p->nArg!=nArg && p->nArg>=0 ) return 0; @@ -98445,14 +105425,12 @@ static int matchQuality( ** a pointer to the matching FuncDef if found, or 0 if there is no match. */ static FuncDef *functionSearch( - FuncDefHash *pHash, /* Hash table to search */ int h, /* Hash of the name */ - const char *zFunc, /* Name of function */ - int nFunc /* Number of bytes in zFunc */ + const char *zFunc /* Name of function */ ){ FuncDef *p; - for(p=pHash->a[h]; p; p=p->pHash){ - if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){ + for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ + if( sqlite3StrICmp(p->zName, zFunc)==0 ){ return p; } } @@ -98462,23 +105440,27 @@ static FuncDef *functionSearch( /* ** Insert a new FuncDef into a FuncDefHash hash table. */ -SQLITE_PRIVATE void sqlite3FuncDefInsert( - FuncDefHash *pHash, /* The hash table into which to insert */ - FuncDef *pDef /* The function definition to insert */ +SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( + FuncDef *aDef, /* List of global functions to be inserted */ + int nDef /* Length of the apDef[] list */ ){ - FuncDef *pOther; - int nName = sqlite3Strlen30(pDef->zName); - u8 c1 = (u8)pDef->zName[0]; - int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a); - pOther = functionSearch(pHash, h, pDef->zName, nName); - if( pOther ){ - assert( pOther!=pDef && pOther->pNext!=pDef ); - pDef->pNext = pOther->pNext; - pOther->pNext = pDef; - }else{ - pDef->pNext = 0; - pDef->pHash = pHash->a[h]; - pHash->a[h] = pDef; + int i; + for(i=0; i='a' && zName[0]<='z' ); + pOther = functionSearch(h, zName); + if( pOther ){ + assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); + aDef[i].pNext = pOther->pNext; + pOther->pNext = &aDef[i]; + }else{ + aDef[i].pNext = 0; + aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h]; + sqlite3BuiltinFunctions.a[h] = &aDef[i]; + } } } @@ -98495,7 +105477,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert( ** no matching function previously existed. ** ** If nArg is -2, then the first valid function found is returned. A -** function is valid if either xFunc or xStep is non-zero. The nArg==(-2) +** function is valid if xSFunc is non-zero. The nArg==(-2) ** case is used to see if zName is a valid function name for some number ** of arguments. If nArg is -2, then createFlag must be 0. ** @@ -98505,8 +105487,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert( */ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( sqlite3 *db, /* An open database */ - const char *zName, /* Name of the function. Not null-terminated */ - int nName, /* Number of characters in the name */ + const char *zName, /* Name of the function. zero-terminated */ int nArg, /* Number of arguments. -1 means any number */ u8 enc, /* Preferred text encoding */ u8 createFlag /* Create new entry if true and does not otherwise exist */ @@ -98515,14 +105496,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( FuncDef *pBest = 0; /* Best match found so far */ int bestScore = 0; /* Score of best match */ int h; /* Hash value */ + int nName; /* Length of the name */ assert( nArg>=(-2) ); assert( nArg>=(-1) || createFlag==0 ); - h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a); + nName = sqlite3Strlen30(zName); /* First search for a match amongst the application-defined functions. */ - p = functionSearch(&db->aFunc, h, zName, nName); + p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName); while( p ){ int score = matchQuality(p, nArg, enc); if( score>bestScore ){ @@ -98534,7 +105516,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( /* If no match is found, search the built-in functions. ** - ** If the SQLITE_PreferBuiltin flag is set, then search the built-in + ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in ** functions even if a prior app-defined function was found. And give ** priority to built-in functions. ** @@ -98544,10 +105526,10 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( ** new function. But the FuncDefs for built-in functions are read-only. ** So we must not search for built-ins when creating a new function. */ - if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){ - FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); + if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; - p = functionSearch(pHash, h, zName, nName); + h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; + p = functionSearch(h, zName); while( p ){ int score = matchQuality(p, nArg, enc); if( score>bestScore ){ @@ -98564,15 +105546,22 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( */ if( createFlag && bestScorezName = (char *)&pBest[1]; + FuncDef *pOther; + pBest->zName = (const char*)&pBest[1]; pBest->nArg = (u16)nArg; pBest->funcFlags = enc; - memcpy(pBest->zName, zName, nName); - pBest->zName[nName] = 0; - sqlite3FuncDefInsert(&db->aFunc, pBest); + memcpy((char*)&pBest[1], zName, nName+1); + pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest); + if( pOther==pBest ){ + sqlite3DbFree(db, pBest); + sqlite3OomFault(db); + return 0; + }else{ + pBest->pNext = pOther; + } } - if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ + if( pBest && (pBest->xSFunc || createFlag) ){ return pBest; } return 0; @@ -98610,8 +105599,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ pSchema->pSeqTab = 0; if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; - pSchema->schemaFlags &= ~DB_SchemaLoaded; } + pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* @@ -98626,7 +105615,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema)); } if( !p ){ - db->mallocFailed = 1; + sqlite3OomFault(db); }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash); sqlite3HashInit(&p->idxHash); @@ -98677,7 +105666,7 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; if( pTab ){ - pTab->nRef++; + pTab->nTabRef++; } if( sqlite3IndexedByLookup(pParse, pItem) ){ pTab = 0; @@ -98743,7 +105732,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView( if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } @@ -98784,7 +105773,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( */ if( pOrderBy && (pLimit == 0) ) { sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType); - goto limit_where_cleanup_2; + goto limit_where_cleanup; } /* We only need to generate a select expression if there @@ -98805,17 +105794,17 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( ** ); */ - pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0); - if( pSelectRowid == 0 ) goto limit_where_cleanup_2; + pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); + if( pSelectRowid == 0 ) goto limit_where_cleanup; pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid); - if( pEList == 0 ) goto limit_where_cleanup_2; + if( pEList == 0 ) goto limit_where_cleanup; /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree ** and the SELECT subtree. */ pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0); if( pSelectSrc == 0 ) { sqlite3ExprListDelete(pParse->db, pEList); - goto limit_where_cleanup_2; + goto limit_where_cleanup; } /* generate the SELECT expression tree. */ @@ -98824,22 +105813,12 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( if( pSelect == 0 ) return 0; /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */ - pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0); - if( pWhereRowid == 0 ) goto limit_where_cleanup_1; - pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0); - if( pInClause == 0 ) goto limit_where_cleanup_1; - - pInClause->x.pSelect = pSelect; - pInClause->flags |= EP_xIsSelect; - sqlite3ExprSetHeightAndFlags(pParse, pInClause); + pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); + pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0; + sqlite3PExprAddSelect(pParse, pInClause, pSelect); return pInClause; - /* something went wrong. clean up anything allocated. */ -limit_where_cleanup_1: - sqlite3SelectDelete(pParse->db, pSelect); - return 0; - -limit_where_cleanup_2: +limit_where_cleanup: sqlite3ExprDelete(pParse->db, pWhere); sqlite3ExprListDelete(pParse->db, pOrderBy); sqlite3ExprDelete(pParse->db, pLimit); @@ -98863,7 +105842,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ - const char *zDb; /* Name of database holding pTab */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ @@ -98890,11 +105868,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( int addrBypass = 0; /* Address of jump over the delete logic */ int addrLoop = 0; /* Top of the delete loop */ int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ + int bComplex; /* True if there are triggers or FKs or + ** subqueries in the WHERE clause */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ - int bComplex; /* True if there are either triggers or FKs */ #endif memset(&sContext, 0, sizeof(sContext)); @@ -98922,7 +105901,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( #else # define pTrigger 0 # define isView 0 -# define bComplex 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView @@ -98940,8 +105918,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); - zDb = db->aDb[iDb].zName; - rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb); + rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, + db->aDb[iDb].zDbSName); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ goto delete_from_cleanup; @@ -99002,11 +105980,21 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Prior to version 3.6.5, ** this optimization caused the row change count (the value returned by - ** API function sqlite3_count_changes) to be set incorrectly. */ + ** API function sqlite3_count_changes) to be set incorrectly. + ** + ** The "rcauth==SQLITE_OK" terms is the + ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and + ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but + ** the truncate optimization is disabled and all rows are deleted + ** individually. + */ if( rcauth==SQLITE_OK && pWhere==0 && !bComplex && !IsVirtual(pTab) +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + && db->xPreUpdateCallback==0 +#endif ){ assert( !isView ); sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); @@ -99021,7 +106009,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { - u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; + u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE; + if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ /* For a rowid table, initialize the RowSet to an empty set */ @@ -99080,7 +106069,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ** one, so just keep it in its register(s) and fall through to the ** delete code. */ nKey = nPk; /* OP_Found will use an unpacked key */ - aToOpen = sqlite3DbMallocRaw(db, nIdx+2); + aToOpen = sqlite3DbMallocRawNN(db, nIdx+2); if( aToOpen==0 ){ sqlite3WhereEnd(pWInfo); goto delete_from_cleanup; @@ -99097,10 +106086,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, sqlite3IndexAffinityStr(pParse->db, pPk), nPk); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); }else{ /* Add the rowid of the row to be deleted to the RowSet */ - nKey = 1; /* OP_Seek always uses a single rowid */ + nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } } @@ -99120,13 +106109,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( */ if( !isView ){ int iAddrOnce = 0; - u8 p5 = (eOnePass==ONEPASS_OFF ? 0 : OPFLAG_FORDELETE); if( eOnePass==ONEPASS_MULTI ){ - iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); + iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } testcase( IsVirtual(pTab) ); - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, p5, iTabCur, - aToOpen, &iDataCur, &iIdxCur); + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE, + iTabCur, aToOpen, &iDataCur, &iIdxCur); assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce); @@ -99144,7 +106132,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( } }else if( pPk ){ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey); + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey); + }else{ + sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); + } assert( nKey==0 ); /* OP_Found will use a composite key */ }else{ addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey); @@ -99168,12 +106160,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( #endif { int count = (pParse->nested==0); /* True to count changes */ - int iIdxNoSeek = -1; - if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){ - iIdxNoSeek = aiCurOnePass[1]; - } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, - iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek); + iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); } /* End of the loop over all rowids/primary-keys. */ @@ -99187,14 +106175,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( sqlite3VdbeGoto(v, addrLoop); sqlite3VdbeJumpHere(v, addrLoop); } - - /* Close the cursors open on the table and its indexes. */ - if( !isView && !IsVirtual(pTab) ){ - if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur); - for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ - sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i); - } - } } /* End non-truncate path */ /* Update the sqlite_sequence table by storing the content of the @@ -99261,15 +106241,17 @@ delete_from_cleanup: ** ** If eMode is ONEPASS_MULTI, then this call is being made as part ** of a ONEPASS delete that affects multiple rows. In this case, if -** iIdxNoSeek is a valid cursor number (>=0), then its position should -** be preserved following the delete operation. Or, if iIdxNoSeek is not -** a valid cursor number, the position of iDataCur should be preserved -** instead. +** iIdxNoSeek is a valid cursor number (>=0) and is not the same as +** iDataCur, then its position should be preserved following the delete +** operation. Or, if iIdxNoSeek is not a valid cursor number, the +** position of iDataCur should be preserved instead. ** ** iIdxNoSeek: -** If iIdxNoSeek is a valid cursor number (>=0), then it identifies an -** index cursor (from within array of cursors starting at iIdxCur) that -** already points to the index entry to be deleted. +** If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur, +** then it identifies an index cursor (from within array of cursors +** starting at iIdxCur) that already points to the index entry to be deleted. +** Except, this optimization is disabled if there are BEFORE triggers since +** the trigger body might have moved the cursor. */ SQLITE_PRIVATE void sqlite3GenerateRowDelete( Parse *pParse, /* Parsing context */ @@ -99340,13 +106322,18 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( /* If any BEFORE triggers were coded, then seek the cursor to the ** row to be deleted again. It may be that the BEFORE triggers moved - ** the cursor or of already deleted the row that the cursor was + ** the cursor or already deleted the row that the cursor was ** pointing to. + ** + ** Also disable the iIdxNoSeek optimization since the BEFORE trigger + ** may have moved that cursor. */ if( addrStart=0 ); + iIdxNoSeek = -1; } /* Do FK processing. This call checks that any FK constraints that @@ -99357,17 +106344,29 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( /* Delete the index and table entries. Skip this step if pTab is really ** a view (in which case the only effect of the DELETE statement is to - ** fire the INSTEAD OF triggers). */ + ** fire the INSTEAD OF triggers). + ** + ** If variable 'count' is non-zero, then this OP_Delete instruction should + ** invoke the update-hook. The pre-update-hook, on the other hand should + ** be invoked unless table pTab is a system table. The difference is that + ** the update-hook is not invoked for rows removed by REPLACE, but the + ** pre-update-hook is. + */ if( pTab->pSelect==0 ){ + u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); - if( count ){ - sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT); + if( pParse->nested==0 ){ + sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); } - if( iIdxNoSeek>=0 ){ + if( eMode!=ONEPASS_OFF ){ + sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE); + } + if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){ sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek); } - sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI); + if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION; + sqlite3VdbeChangeP5(v, p5); } /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to @@ -99487,10 +106486,11 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); - pParse->iSelfTab = iDataCur; + pParse->iSelfTab = iDataCur + 1; sqlite3ExprCachePush(pParse); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); + pParse->iSelfTab = 0; }else{ *piPartIdxLabel = 0; } @@ -99517,6 +106517,10 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( } if( regOut ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); + if( pIdx->pTable->pSelect ){ + const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx); + sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); + } } sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; @@ -99614,16 +106618,20 @@ static void typeofFunc( int NotUsed, sqlite3_value **argv ){ - const char *z = 0; + static const char *azType[] = { "integer", "real", "text", "blob", "null" }; + int i = sqlite3_value_type(argv[0]) - 1; UNUSED_PARAMETER(NotUsed); - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_INTEGER: z = "integer"; break; - case SQLITE_TEXT: z = "text"; break; - case SQLITE_FLOAT: z = "real"; break; - case SQLITE_BLOB: z = "blob"; break; - default: z = "null"; break; - } - sqlite3_result_text(context, z, -1, SQLITE_STATIC); + assert( i>=0 && i0 ){ + if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ + zHaystack = sqlite3_value_blob(argv[0]); + zNeedle = sqlite3_value_blob(argv[1]); + isText = 0; + }else{ + zHaystack = sqlite3_value_text(argv[0]); + zNeedle = sqlite3_value_text(argv[1]); + isText = 1; + } + if( zNeedle==0 || (nHaystack && zHaystack==0) ) return; + while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ + N++; + do{ + nHaystack--; + zHaystack++; + }while( isText && (zHaystack[0]&0xc0)==0x80 ); + } + if( nNeedle>nHaystack ) N = 0; } - while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ - N++; - do{ - nHaystack--; - zHaystack++; - }while( isText && (zHaystack[0]&0xc0)==0x80 ); - } - if( nNeedle>nHaystack ) N = 0; sqlite3_result_int(context, N); } @@ -99777,7 +106788,8 @@ static void printfFunc( x.nUsed = 0; x.apArg = argv+1; sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); - sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x); + str.printfFlags = SQLITE_PRINTF_SQLFUNC; + sqlite3XPrintf(&str, zFormat, &x); n = str.nChar; sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, SQLITE_DYNAMIC); @@ -100105,10 +107117,10 @@ static void total_changes( ** A structure defining how to do GLOB-style comparisons. */ struct compareInfo { - u8 matchAll; - u8 matchOne; - u8 matchSet; - u8 noCase; + u8 matchAll; /* "*" or "%" */ + u8 matchOne; /* "?" or "_" */ + u8 matchSet; /* "[" or 0 */ + u8 noCase; /* true to ignore case differences */ }; /* @@ -100133,9 +107145,19 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; /* -** Compare two UTF-8 strings for equality where the first string can -** potentially be a "glob" or "like" expression. Return true (1) if they -** are the same and false (0) if they are different. +** Possible error returns from patternMatch() +*/ +#define SQLITE_MATCH 0 +#define SQLITE_NOMATCH 1 +#define SQLITE_NOWILDCARDMATCH 2 + +/* +** Compare two UTF-8 strings for equality where the first string is +** a GLOB or LIKE expression. Return values: +** +** SQLITE_MATCH: Match +** SQLITE_NOMATCH: No match +** SQLITE_NOWILDCARDMATCH: No match in spite of having * or % wildcards. ** ** Globbing rules: ** @@ -100171,22 +107193,14 @@ static int patternCompare( const u8 *zPattern, /* The glob pattern */ const u8 *zString, /* The string to compare against the glob */ const struct compareInfo *pInfo, /* Information about how to do the compare */ - u32 esc /* The escape character */ + u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */ ){ u32 c, c2; /* Next pattern and input string chars */ u32 matchOne = pInfo->matchOne; /* "?" or "_" */ u32 matchAll = pInfo->matchAll; /* "*" or "%" */ - u32 matchOther; /* "[" or the escape character */ u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ const u8 *zEscaped = 0; /* One past the last escaped input char */ - /* The GLOB operator does not have an ESCAPE clause. And LIKE does not - ** have the matchSet operator. So we either have to look for one or - ** the other, never both. Hence the single variable matchOther is used - ** to store the one we have to look for. - */ - matchOther = esc ? esc : pInfo->matchSet; - while( (c = Utf8Read(zPattern))!=0 ){ if( c==matchAll ){ /* Match "*" */ /* Skip over multiple "*" characters in the pattern. If there @@ -100194,30 +107208,31 @@ static int patternCompare( ** single character of the input string for each "?" skipped */ while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ - return 0; + return SQLITE_NOWILDCARDMATCH; } } if( c==0 ){ - return 1; /* "*" at the end of the pattern matches */ + return SQLITE_MATCH; /* "*" at the end of the pattern matches */ }else if( c==matchOther ){ - if( esc ){ + if( pInfo->matchSet==0 ){ c = sqlite3Utf8Read(&zPattern); - if( c==0 ) return 0; + if( c==0 ) return SQLITE_NOWILDCARDMATCH; }else{ /* "[...]" immediately follows the "*". We have to do a slow ** recursive search in this case, but it is an unusual case. */ assert( matchOther<0x80 ); /* '[' is a single-byte character */ - while( *zString - && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ + while( *zString ){ + int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther); + if( bMatch!=SQLITE_NOMATCH ) return bMatch; SQLITE_SKIP_UTF8(zString); } - return *zString!=0; + return SQLITE_NOWILDCARDMATCH; } } /* At this point variable c contains the first character of the ** pattern string past the "*". Search in the input string for the - ** first matching character and recursively contine the match from + ** first matching character and recursively continue the match from ** that point. ** ** For a case-insensitive search, set variable cx to be the same as @@ -100226,6 +107241,7 @@ static int patternCompare( */ if( c<=0x80 ){ u32 cx; + int bMatch; if( noCase ){ cx = sqlite3Toupper(c); c = sqlite3Tolower(c); @@ -100234,27 +107250,30 @@ static int patternCompare( } while( (c2 = *(zString++))!=0 ){ if( c2!=c && c2!=cx ) continue; - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + bMatch = patternCompare(zPattern,zString,pInfo,matchOther); + if( bMatch!=SQLITE_NOMATCH ) return bMatch; } }else{ + int bMatch; while( (c2 = Utf8Read(zString))!=0 ){ if( c2!=c ) continue; - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; + bMatch = patternCompare(zPattern,zString,pInfo,matchOther); + if( bMatch!=SQLITE_NOMATCH ) return bMatch; } } - return 0; + return SQLITE_NOWILDCARDMATCH; } if( c==matchOther ){ - if( esc ){ + if( pInfo->matchSet==0 ){ c = sqlite3Utf8Read(&zPattern); - if( c==0 ) return 0; + if( c==0 ) return SQLITE_NOMATCH; zEscaped = zPattern; }else{ u32 prior_c = 0; int seen = 0; int invert = 0; c = sqlite3Utf8Read(&zString); - if( c==0 ) return 0; + if( c==0 ) return SQLITE_NOMATCH; c2 = sqlite3Utf8Read(&zPattern); if( c2=='^' ){ invert = 1; @@ -100278,34 +107297,36 @@ static int patternCompare( c2 = sqlite3Utf8Read(&zPattern); } if( c2==0 || (seen ^ invert)==0 ){ - return 0; + return SQLITE_NOMATCH; } continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; - if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ + if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ continue; } if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; - return 0; + return SQLITE_NOMATCH; } - return *zString==0; + return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH; } /* -** The sqlite3_strglob() interface. +** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and +** non-zero if there is no match. */ -SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){ - return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0; +SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){ + return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); } /* -** The sqlite3_strlike() interface. +** The sqlite3_strlike() interface. Return 0 on a match and non-zero for +** a miss - like strcmp(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ - return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0; +SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ + return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); } /* @@ -100336,9 +107357,10 @@ static void likeFunc( sqlite3_value **argv ){ const unsigned char *zA, *zB; - u32 escape = 0; + u32 escape; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); + struct compareInfo *pInfo = sqlite3_user_data(context); #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( sqlite3_value_type(argv[0])==SQLITE_BLOB @@ -100378,14 +107400,15 @@ static void likeFunc( return; } escape = sqlite3Utf8Read(&zEsc); + }else{ + escape = pInfo->matchSet; } if( zA && zB ){ - struct compareInfo *pInfo = sqlite3_user_data(context); #ifdef SQLITE_TEST sqlite3_like_count++; #endif - - sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); + sqlite3_result_int(context, + patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); } } @@ -100860,6 +107883,26 @@ static void trimFunc( } +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION +/* +** The "unknown" function is automatically substituted in place of +** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN +** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used. +** When the "sqlite3" command-line shell is built using this functionality, +** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries +** involving application-defined functions to be examined in a generic +** sqlite3 shell. +*/ +static void unknownFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + /* no-op */ +} +#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ + + /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. @@ -100930,6 +107973,14 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3 *db = sqlite3_context_db_handle(context); char *zErrMsg = 0; + /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc + ** flag is set. See the sqlite3_enable_load_extension() API. + */ + if( (db->flags & SQLITE_LoadExtFunc)==0 ){ + sqlite3_result_error(context, "not authorized", -1); + return; + } + if( argc==2 ){ zProc = (const char *)sqlite3_value_text(argv[1]); }else{ @@ -101128,7 +108179,7 @@ static void groupConcatStep( zSep = ","; nSep = 1; } - if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); + if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); } zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); @@ -101155,11 +108206,11 @@ static void groupConcatFinalize(sqlite3_context *context){ ** of the built-in functions above are part of the global function set. ** This routine only deals with those that are not global. */ -SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ +SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ int rc = sqlite3_overload_function(db, "MATCH", 2); assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } } @@ -101168,8 +108219,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ */ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ FuncDef *pDef; - pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName), - 2, SQLITE_UTF8, 0); + pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); if( ALWAYS(pDef) ){ pDef->funcFlags |= flagVal; } @@ -101199,9 +108249,14 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) /* ** pExpr points to an expression which implements a function. If ** it is appropriate to apply the LIKE optimization to that function -** then set aWc[0] through aWc[2] to the wildcard characters and -** return TRUE. If the function is not a LIKE-style function then -** return FALSE. +** then set aWc[0] through aWc[2] to the wildcard characters and the +** escape character and then return TRUE. If the function is not a +** LIKE-style function then return FALSE. +** +** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE +** operator if c is a string literal that is exactly one byte in length. +** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is +** no ESCAPE clause. ** ** *pIsNocase is set to true if uppercase and lowercase are equivalent for ** the function (default for LIKE). If the function makes the distinction @@ -101210,19 +108265,26 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) */ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; - if( pExpr->op!=TK_FUNCTION - || !pExpr->x.pList - || pExpr->x.pList->nExpr!=2 - ){ + int nExpr; + if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){ return 0; } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - pDef = sqlite3FindFunction(db, pExpr->u.zToken, - sqlite3Strlen30(pExpr->u.zToken), - 2, SQLITE_UTF8, 0); + nExpr = pExpr->x.pList->nExpr; + pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ return 0; } + if( nExpr<3 ){ + aWc[3] = 0; + }else{ + Expr *pEscape = pExpr->x.pList->a[2].pExpr; + char *zEscape; + if( pEscape->op!=TK_STRING ) return 0; + zEscape = pEscape->u.zToken; + if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; + aWc[3] = zEscape[0]; + } /* The memcpy() statement assumes that the wildcard characters are ** the first three statements in the compareInfo structure. The @@ -101243,7 +108305,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas ** ** After this routine runs */ -SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ +SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ /* ** The following array holds FuncDef structures for all of the functions ** defined in this file. @@ -101251,8 +108313,30 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ ** The array cannot be constant since changes are made to the ** FuncDef.pHash elements at start-time. The elements of this array ** are read-only after initialization is complete. + ** + ** For peak efficiency, put the most frequently used function last. */ - static SQLITE_WSD FuncDef aBuiltinFunc[] = { + static FuncDef aBuiltinFunc[] = { +#ifdef SQLITE_SOUNDEX + FUNCTION(soundex, 1, 0, 0, soundexFunc ), +#endif +#ifndef SQLITE_OMIT_LOAD_EXTENSION + VFUNCTION(load_extension, 1, 0, 0, loadExt ), + VFUNCTION(load_extension, 2, 0, 0, loadExt ), +#endif +#if SQLITE_USER_AUTHENTICATION + FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), +#endif +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), + DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), +#ifdef SQLITE_DEBUG + FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY), +#endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), FUNCTION(rtrim, 1, 2, 0, trimFunc ), @@ -101270,8 +108354,6 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), - FUNCTION(substr, 2, 0, 0, substrFunc ), - FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(printf, -1, 0, 0, printfFunc ), FUNCTION(unicode, 1, 0, 0, unicodeFunc ), FUNCTION(char, -1, 0, 0, charFunc ), @@ -101282,40 +108364,22 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), - FUNCTION(coalesce, 1, 0, 0, 0 ), - FUNCTION(coalesce, 0, 0, 0, 0 ), - FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), FUNCTION(hex, 1, 0, 0, hexFunc ), FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), - FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), -#if SQLITE_USER_AUTHENTICATION - FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), -#endif -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS - DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), - DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), -#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ FUNCTION(quote, 1, 0, 0, quoteFunc ), VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), VFUNCTION(changes, 0, 0, 0, changes ), VFUNCTION(total_changes, 0, 0, 0, total_changes ), FUNCTION(replace, 3, 0, 0, replaceFunc ), FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), - #ifdef SQLITE_SOUNDEX - FUNCTION(soundex, 1, 0, 0, soundexFunc ), - #endif - #ifndef SQLITE_OMIT_LOAD_EXTENSION - VFUNCTION(load_extension, 1, 0, 0, loadExt ), - VFUNCTION(load_extension, 2, 0, 0, loadExt ), - #endif + FUNCTION(substr, 2, 0, 0, substrFunc ), + FUNCTION(substr, 3, 0, 0, substrFunc ), AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), @@ -101326,28 +108390,43 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){ AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), - #ifdef SQLITE_CASE_SENSITIVE_LIKE +#ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), - #else +#else LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), - #endif +#endif +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + FUNCTION(unknown, -1, 0, 0, unknownFunc ), +#endif + FUNCTION(coalesce, 1, 0, 0, 0 ), + FUNCTION(coalesce, 0, 0, 0, 0 ), + FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), }; - - int i; - FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); - FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc); - - for(i=0; iu.pHash){ + int n = sqlite3Strlen30(p->zName); + int h = p->zName[0] + n; + printf(" %s(%d)", p->zName, h); + } + printf("\n"); + } + } #endif } @@ -101574,13 +108653,13 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( } }else if( paiCol ){ assert( nCol>1 ); - aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int)); + aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int)); if( !aiCol ) return 1; *paiCol = aiCol; } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){ + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ @@ -101939,7 +109018,7 @@ static void fkScanChildren( assert( iCol>=0 ); zCol = pFKey->pFrom->aCol[iCol].zName; pRight = sqlite3Expr(db, TK_ID, zCol); - pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0); + pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pWhere = sqlite3ExprAnd(db, pWhere, pEq); } @@ -101961,7 +109040,7 @@ static void fkScanChildren( if( HasRowid(pTab) ){ pLeft = exprTableRegister(pParse, pTab, regData, -1); pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1); - pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0); + pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight); }else{ Expr *pEq, *pAll = 0; Index *pPk = sqlite3PrimaryKeyIndex(pTab); @@ -101971,10 +109050,10 @@ static void fkScanChildren( 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, 0); + pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pAll = sqlite3ExprAnd(db, pAll, pEq); } - pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0); + pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } pWhere = sqlite3ExprAnd(db, pWhere, pNe); } @@ -101988,10 +109067,12 @@ static void fkScanChildren( /* Create VDBE to loop through the entries in pSrc that match the WHERE ** clause. For each row found, increment either the deferred or immediate ** foreign key constraint counter. */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); - sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); - if( pWInfo ){ - sqlite3WhereEnd(pWInfo); + if( pParse->nErr==0 ){ + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); + if( pWInfo ){ + sqlite3WhereEnd(pWInfo); + } } /* Clean up the WHERE clause constructed above. */ @@ -102226,7 +109307,7 @@ SQLITE_PRIVATE void sqlite3FkCheck( if( (db->flags&SQLITE_ForeignKeys)==0 ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ @@ -102362,7 +109443,7 @@ SQLITE_PRIVATE void sqlite3FkCheck( struct SrcList_item *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; - pItem->pTab->nRef++; + pItem->pTab->nTabRef++; pItem->iCursor = pParse->nTab++; if( regNew!=0 ){ @@ -102442,8 +109523,16 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask( ** UPDATE statement modifies the rowid fields of the table. ** ** If any foreign key processing will be required, this function returns -** true. If there is no foreign key related processing, this function -** returns false. +** non-zero. If there is no foreign key related processing, this function +** returns zero. +** +** For an UPDATE, this function returns 2 if: +** +** * There are any FKs for which pTab is the child and the parent table, or +** * the UPDATE modifies one or more parent keys for which the action is +** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL). +** +** Or, assuming some other foreign key processing is required, 1. */ SQLITE_PRIVATE int sqlite3FkRequired( Parse *pParse, /* Parse context */ @@ -102451,12 +109540,13 @@ SQLITE_PRIVATE int sqlite3FkRequired( int *aChange, /* Non-NULL for UPDATE operations */ int chngRowid /* True for UPDATE that affects rowid */ ){ + int eRet = 0; if( pParse->db->flags&SQLITE_ForeignKeys ){ if( !aChange ){ /* A DELETE operation. Foreign key processing is required if the ** table in question is either the child or parent table for any ** foreign key constraint. */ - return (sqlite3FkReferences(pTab) || pTab->pFKey); + eRet = (sqlite3FkReferences(pTab) || pTab->pFKey); }else{ /* This is an UPDATE. Foreign key processing is only required if the ** operation modifies one or more child or parent key columns. */ @@ -102464,16 +109554,22 @@ SQLITE_PRIVATE int sqlite3FkRequired( /* Check if any child key columns are being modified. */ for(p=pTab->pFKey; p; p=p->pNextFrom){ - if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1; + if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2; + if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ + eRet = 1; + } } /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ - if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1; + if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ + if( p->aAction[1]!=OE_None ) return 2; + eRet = 1; + } } } } - return 0; + return eRet; } /* @@ -102517,10 +109613,12 @@ static Trigger *fkActionTrigger( int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */ action = pFKey->aAction[iAction]; + if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){ + return 0; + } pTrigger = pFKey->apTrigger[iAction]; if( action!=OE_None && !pTrigger ){ - u8 enableLookaside; /* Copy of db->lookaside.bEnabled */ char const *zFrom; /* Name of child table */ int nFrom; /* Length in bytes of zFrom */ Index *pIdx = 0; /* Parent key index for this FK */ @@ -102547,11 +109645,9 @@ static Trigger *fkActionTrigger( assert( iFromCol>=0 ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKeynCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); - tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName; - tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName; - - tToCol.n = sqlite3Strlen30(tToCol.z); - tFromCol.n = sqlite3Strlen30(tFromCol.z); + sqlite3TokenInit(&tToCol, + pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName); + sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName); /* Create the expression "OLD.zToCol = zFromCol". It is important ** that the "OLD.zToCol" term is on the LHS of the = operator, so @@ -102560,10 +109656,9 @@ static Trigger *fkActionTrigger( pEq = sqlite3PExpr(pParse, TK_EQ, sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), - sqlite3ExprAlloc(db, TK_ID, &tToCol, 0) - , 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) - , 0); + ); pWhere = sqlite3ExprAnd(db, pWhere, pEq); /* For ON UPDATE, construct the next term of the WHEN clause. @@ -102575,13 +109670,11 @@ static Trigger *fkActionTrigger( pEq = sqlite3PExpr(pParse, TK_IS, sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), - sqlite3ExprAlloc(db, TK_ID, &tToCol, 0), - 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), - sqlite3ExprAlloc(db, TK_ID, &tToCol, 0), - 0), - 0); + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) + ); pWhen = sqlite3ExprAnd(db, pWhen, pEq); } @@ -102590,17 +109683,16 @@ static Trigger *fkActionTrigger( if( action==OE_Cascade ){ pNew = sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), - sqlite3ExprAlloc(db, TK_ID, &tToCol, 0) - , 0); + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)); }else if( action==OE_SetDflt ){ Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt; if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); }else{ - pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0); + pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } }else{ - pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0); + pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } pList = sqlite3ExprListAppend(pParse, pList, pNew); sqlite3ExprListSetName(pParse, pList, &tFromCol, 0); @@ -102631,8 +109723,7 @@ static Trigger *fkActionTrigger( } /* Disable lookaside memory allocation */ - enableLookaside = db->lookaside.bEnabled; - db->lookaside.bEnabled = 0; + db->lookaside.bDisable++; pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ @@ -102648,13 +109739,13 @@ static Trigger *fkActionTrigger( pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); if( pWhen ){ - pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0); + pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0); pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } } /* Re-enable the lookaside buffer, if it was disabled earlier. */ - db->lookaside.bEnabled = enableLookaside; + db->lookaside.bDisable--; sqlite3ExprDelete(db, pWhere); sqlite3ExprDelete(db, pWhen); @@ -102728,7 +109819,8 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ - assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); + assert( db==0 || IsVirtual(pTab) + || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ @@ -102849,7 +109941,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ Table *pTab = pIdx->pTable; pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); if( !pIdx->zColAff ){ - db->mallocFailed = 1; + sqlite3OomFault(db); return 0; } for(n=0; nnColumn; n++){ @@ -102900,7 +109992,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ sqlite3 *db = sqlite3VdbeDb(v); zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); if( !zColAff ){ - db->mallocFailed = 1; + sqlite3OomFault(db); return; } @@ -102966,7 +110058,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){ /* ** Locate or create an AutoincInfo structure associated with table pTab ** which is in database iDb. Return the register number for the register -** that holds the maximum rowid. +** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT +** table. (Also return zero when doing a VACUUM since we do not want to +** update the AUTOINCREMENT counters during a VACUUM.) ** ** There is at most one AutoincInfo structure per table even if the ** same table is autoincremented multiple times due to inserts within @@ -102989,14 +110083,16 @@ static int autoIncBegin( Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ - if( pTab->tabFlags & TF_Autoincrement ){ + if( (pTab->tabFlags & TF_Autoincrement)!=0 + && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 + ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ - pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo)); + pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); if( pInfo==0 ) return 0; pInfo->pNext = pToplevel->pAinc; pToplevel->pAinc = pInfo; @@ -103020,7 +110116,6 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* Database only autoinc table */ int memId; /* Register holding max rowid */ - int addr; /* A VDBE address */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ /* This routine is never called during trigger-generation. It is @@ -103030,33 +110125,46 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ assert( v ); /* We failed long ago if this is not so */ for(p = pParse->pAinc; p; p = p->pNext){ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList autoInc[] = { + /* 0 */ {OP_Null, 0, 0, 0}, + /* 1 */ {OP_Rewind, 0, 9, 0}, + /* 2 */ {OP_Column, 0, 0, 0}, + /* 3 */ {OP_Ne, 0, 7, 0}, + /* 4 */ {OP_Rowid, 0, 0, 0}, + /* 5 */ {OP_Column, 0, 1, 0}, + /* 6 */ {OP_Goto, 0, 9, 0}, + /* 7 */ {OP_Next, 0, 2, 0}, + /* 8 */ {OP_Integer, 0, 0, 0}, + /* 9 */ {OP_Close, 0, 0, 0} + }; + VdbeOp *aOp; pDb = &db->aDb[p->iDb]; memId = p->regCtr; assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); - sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1); - addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeLoadString(v, memId-1, p->pTab->zName); - sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId); - sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v); - sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); - sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1); - sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId); - sqlite3VdbeGoto(v, addr+9); - sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Integer, 0, memId); - sqlite3VdbeAddOp0(v, OP_Close); + aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn); + if( aOp==0 ) break; + aOp[0].p2 = memId; + aOp[0].p3 = memId+1; + aOp[2].p3 = memId; + aOp[3].p1 = memId-1; + aOp[3].p3 = memId; + aOp[3].p5 = SQLITE_JUMPIFNULL; + aOp[4].p2 = memId+1; + aOp[5].p3 = memId; + aOp[8].p2 = memId; } } /* ** Update the maximum rowid for an autoincrement calculation. ** -** This routine should be called when the top of the stack holds a +** This routine should be called when the regRowid register holds a ** new rowid that is about to be inserted. If that new rowid is ** larger than the maximum rowid in the memId memory cell, then the -** memory cell is updated. The stack is unchanged. +** memory cell is updated. */ static void autoIncStep(Parse *pParse, int memId, int regRowid){ if( memId>0 ){ @@ -103071,31 +110179,44 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){ ** table (either directly or through triggers) needs to call this ** routine just before the "exit" code. */ -SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ +static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){ AutoincInfo *p; Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; assert( v ); for(p = pParse->pAinc; p; p = p->pNext){ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList autoIncEnd[] = { + /* 0 */ {OP_NotNull, 0, 2, 0}, + /* 1 */ {OP_NewRowid, 0, 0, 0}, + /* 2 */ {OP_MakeRecord, 0, 2, 0}, + /* 3 */ {OP_Insert, 0, 0, 0}, + /* 4 */ {OP_Close, 0, 0, 0} + }; + VdbeOp *aOp; Db *pDb = &db->aDb[p->iDb]; - int addr1; int iRec; int memId = p->regCtr; iRec = sqlite3GetTempReg(pParse); assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); - addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1); - sqlite3VdbeJumpHere(v, addr1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec); - sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1); - sqlite3VdbeChangeP5(v, OPFLAG_APPEND); - sqlite3VdbeAddOp0(v, OP_Close); + aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn); + if( aOp==0 ) break; + aOp[0].p1 = memId+1; + aOp[1].p2 = memId+1; + aOp[2].p1 = memId-1; + aOp[2].p3 = iRec; + aOp[3].p2 = iRec; + aOp[3].p3 = memId+1; + aOp[3].p5 = OPFLAG_APPEND; sqlite3ReleaseTempReg(pParse, iRec); } } +SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ + if( pParse->pAinc ) autoIncrementEnd(pParse); +} #else /* ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines @@ -103221,9 +110342,7 @@ SQLITE_PRIVATE void sqlite3Insert( ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ - char *zTab; /* Name of the table into which we are inserting */ - const char *zDb; /* Name of the database holding this table */ - int i, j, idx; /* Loop counters */ + int i, j; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ int nColumn; /* Number of columns in the data */ @@ -103237,7 +110356,6 @@ SQLITE_PRIVATE void sqlite3Insert( int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ - Db *pDb; /* The database containing table being inserted into */ u8 useTempTable = 0; /* Store SELECT results in intermediate table */ u8 appendFlag = 0; /* True if the insert is likely to be an append */ u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ @@ -103260,10 +110378,10 @@ SQLITE_PRIVATE void sqlite3Insert( #endif db = pParse->db; - memset(&dest, 0, sizeof(dest)); if( pParse->nErr || db->mallocFailed ){ goto insert_cleanup; } + dest.iSDParm = 0; /* Suppress a harmless compiler warning */ /* If the Select object is really just a simple VALUES() list with a ** single row (the common case) then keep that one row of values @@ -103279,17 +110397,14 @@ SQLITE_PRIVATE void sqlite3Insert( /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); - zTab = pTabList->a[0].zName; - if( NEVER(zTab==0) ) goto insert_cleanup; pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); - pDb = &db->aDb[iDb]; - zDb = pDb->zName; - if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, + db->aDb[iDb].zDbSName) ){ goto insert_cleanup; } withoutRowid = !HasRowid(pTab); @@ -103426,7 +110541,7 @@ SQLITE_PRIVATE void sqlite3Insert( rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); + sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; @@ -103528,12 +110643,14 @@ SQLITE_PRIVATE void sqlite3Insert( int nIdx; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); - aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1)); + aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1)); if( aRegIdx==0 ){ goto insert_cleanup; } - for(i=0; ipIndex; ipNext, i++){ + assert( pIdx ); aRegIdx[i] = ++pParse->nMem; + pParse->nMem += pIdx->nColumn; } } @@ -103735,12 +110852,26 @@ SQLITE_PRIVATE void sqlite3Insert( #endif { int isReplace; /* Set to true if constraints may cause a replace */ + int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, - regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0 ); sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); + + /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE + ** constraints or (b) there are no triggers and this table is not a + ** parent table in a foreign key constraint. It is safe to set the + ** flag in the second case as if any REPLACE constraint is hit, an + ** OP_Delete or OP_IdxDelete instruction will be executed on each + ** cursor that is disturbed. And these instructions both clear the + ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT + ** functionality. */ + bUseSeek = (isReplace==0 || (pTrigger==0 && + ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0) + )); sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, - regIns, aRegIdx, 0, appendFlag, isReplace==0); + regIns, aRegIdx, 0, appendFlag, bUseSeek + ); } } @@ -103769,14 +110900,6 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3VdbeJumpHere(v, addrInsTop); } - if( !IsVirtual(pTab) && !isView ){ - /* Close all tables opened */ - if( iDataCurpIndex; pIdx; pIdx=pIdx->pNext, idx++){ - sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur); - } - } - insert_end: /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into @@ -103818,6 +110941,59 @@ insert_cleanup: #undef tmask #endif +/* +** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged() +*/ +#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 +** columns that are being modifed by an UPDATE statement. +*/ +static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN ){ + assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 ); + if( pExpr->iColumn>=0 ){ + if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){ + pWalker->eCode |= CKCNSTRNT_COLUMN; + } + }else{ + pWalker->eCode |= CKCNSTRNT_ROWID; + } + } + return WRC_Continue; +} + +/* +** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The +** 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 +** changing columns (or the rowid if it is changing). In other words, +** return true if this CHECK constraint can be skipped when validating +** the new row in the UPDATE statement. +*/ +static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 0; + w.xExprCallback = checkConstraintExprNode; + w.u.aiCol = aiChng; + sqlite3WalkExpr(&w, pExpr); + if( !chngRowid ){ + testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 ); + w.eCode &= ~CKCNSTRNT_ROWID; + } + testcase( w.eCode==0 ); + testcase( w.eCode==CKCNSTRNT_COLUMN ); + testcase( w.eCode==CKCNSTRNT_ROWID ); + testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); + return !w.eCode; +} + /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE ** on table pTab. @@ -103912,7 +111088,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */ u8 overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ - int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */ + int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ + int *aiChng /* column i is unchanged if aiChng[i]<0 */ ){ Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ @@ -103929,7 +111106,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int ipkBottom = 0; /* Bottom of the rowid change constraint check */ u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ - int regRowid = -1; /* Register holding ROWID value */ isUpdate = regOldData!=0; db = pParse->db; @@ -103958,10 +111134,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( */ for(i=0; iiPKey ){ + continue; /* ROWID is never NULL */ + } + if( aiChng && aiChng[i]<0 ){ + /* Don't bother checking for NOT NULL on columns that do not change */ continue; } onError = pTab->aCol[i].notNull; - if( onError==OE_None ) continue; + if( onError==OE_None ) continue; /* This column is allowed to be NULL */ if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ @@ -103980,8 +111160,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( case OE_Fail: { char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pTab->aCol[i].zName); - sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, - regNewData+1+i, zMsg, P4_DYNAMIC); + sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, + regNewData+1+i); + sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); VdbeCoverage(v); break; @@ -104007,11 +111188,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; inExpr; i++){ - int allOk = sqlite3VdbeMakeLabel(v); - sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL); + int allOk; + Expr *pExpr = pCheck->a[i].pExpr; + if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue; + allOk = sqlite3VdbeMakeLabel(v); + sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); }else{ @@ -104024,6 +111208,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } sqlite3VdbeResolveLabel(v, allOk); } + pParse->iSelfTab = 0; } #endif /* !defined(SQLITE_OMIT_CHECK) */ @@ -104042,7 +111227,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } if( isUpdate ){ - /* pkChng!=0 does not mean that the rowid has change, only that + /* pkChng!=0 does not mean that the rowid has changed, only that ** it might have changed. Skip the conflict logic below if the rowid ** is unchanged. */ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); @@ -104111,9 +111296,18 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, - regNewData, 1, 0, OE_Replace, - ONEPASS_SINGLE, -1); + regNewData, 1, 0, OE_Replace, 1, -1); }else{ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( HasRowid(pTab) ){ + /* This OP_Delete opcode fires the pre-update-hook only. It does + ** not modify the b-tree. It is more efficient to let the coming + ** OP_Insert replace the existing entry than it is to delete the + ** existing entry and then insert a new one. */ + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ if( pTab->pIndex ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1); @@ -104159,29 +111353,27 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, SQLITE_JUMPIFNULL); - pParse->ckBase = 0; + pParse->iSelfTab = 0; } /* Create a record for this index entry as it should appear after ** the insert or update. Store that record in the aRegIdx[ix] register */ - regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); + regIdx = aRegIdx[ix]+1; for(i=0; inColumn; i++){ int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); - pParse->ckBase = 0; + pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); }else{ if( iField==XN_ROWID || iField==pTab->iPKey ){ - if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ x = regNewData; - regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; }else{ x = iField + regNewData + 1; } @@ -104191,7 +111383,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); - sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn); +#ifdef SQLITE_ENABLE_NULL_TRIM + if( pIdx->idxType==2 ) sqlite3SetMakeRecordP5(v, pIdx->pTable); +#endif /* In an UPDATE operation, if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table and there has been no change the @@ -104205,7 +111399,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Find out what action to take in case there is a uniqueness conflict */ onError = pIdx->onError; if( onError==OE_None ){ - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn); sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; /* pIdx is not a UNIQUE index */ } @@ -104214,7 +111407,26 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( }else if( onError==OE_Default ){ onError = OE_Abort; } - + + /* Collision detection may be omitted if all of the following are true: + ** (1) The conflict resolution algorithm is REPLACE + ** (2) The table is a WITHOUT ROWID table + ** (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. + */ + if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ + && pPk==pIdx /* Condition 2 */ + && onError==OE_Replace /* Condition 1 */ + && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ + 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) + && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ + (0==pTab->pFKey && 0==sqlite3FkReferences(pTab))) + ){ + sqlite3VdbeResolveLabel(v, addrUniqueOk); + continue; + } + /* Check to see if the new index entry will be unique */ sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); VdbeCoverage(v); @@ -104298,13 +111510,12 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, - (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1); + (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); seenReplace = 1; break; } } sqlite3VdbeResolveLabel(v, addrUniqueOk); - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); } if( ipkTop ){ @@ -104316,6 +111527,28 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } +#ifdef SQLITE_ENABLE_NULL_TRIM +/* +** Change the P5 operand on the last opcode (which should be an OP_MakeRecord) +** to be the number of columns in table pTab that must not be NULL-trimmed. +** +** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero. +*/ +SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){ + u16 i; + + /* Records with omitted columns are only allowed for schema format + ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */ + if( pTab->pSchema->file_format<2 ) return; + + for(i=pTab->nCol-1; i>0; i--){ + if( pTab->aCol[i].pDflt!=0 ) break; + if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; + } + sqlite3VdbeChangeP5(v, i+1); +} +#endif + /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. @@ -104332,7 +111565,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( int iIdxCur, /* First index cursor */ int regNewData, /* Range of content */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ - int isUpdate, /* True for UPDATE, False for INSERT */ + int update_flags, /* True for UPDATE, False for INSERT */ int appendBias, /* True if this is likely to be an append */ int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ ){ @@ -104344,6 +111577,11 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( int i; /* Loop counter */ u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ + assert( update_flags==0 + || update_flags==OPFLAG_ISUPDATE + || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) + ); + v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ @@ -104354,26 +111592,39 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); } - sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]); - pik_flags = 0; - if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT; + pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; + 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 + ); + sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); + } +#endif } - if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i], + aRegIdx[i]+1, + pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn); + sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; regData = regNewData + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); - if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0); - sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); + sqlite3SetMakeRecordP5(v, pTab); + if( !bAffinityDone ){ + sqlite3TableAffinity(v, pTab, 0); + sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); + } if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; - pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID); + pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID); } if( appendBias ){ pik_flags |= OPFLAG_APPEND; @@ -104383,7 +111634,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( } sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData); if( !pParse->nested ){ - sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } sqlite3VdbeChangeP5(v, pik_flags); } @@ -104413,7 +111664,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ Table *pTab, /* Table to be opened */ int op, /* OP_OpenRead or OP_OpenWrite */ - u8 p5, /* P5 value for OP_Open* instructions */ + u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */ int iBase, /* Use this for the table cursor, if there is one */ u8 *aToOpen, /* If not NULL: boolean for each table and index */ int *piDataCur, /* Write the database source cursor number here */ @@ -104448,8 +111699,9 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ int iIdxCur = iBase++; assert( pIdx->pSchema==pTab->pSchema ); - if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){ - *piDataCur = iIdxCur; + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ + if( piDataCur ) *piDataCur = iIdxCur; + p5 = 0; } if( aToOpen==0 || aToOpen[i+1] ){ sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb); @@ -104502,7 +111754,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ } if( pSrc->aiColumn[i]==XN_EXPR ){ assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); - if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, + if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr, pDest->aColExpr->a[i].pExpr, -1)!=0 ){ return 0; /* Different expressions in the index */ } @@ -104514,7 +111766,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ return 0; /* Different collating sequences */ } } - if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ + if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ return 0; /* Different WHERE clauses */ } @@ -104583,7 +111835,7 @@ static int xferOptimization( return 0; /* tab1 must not have triggers */ } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pDest->tabFlags & TF_Virtual ){ + if( IsVirtual(pDest) ){ return 0; /* tab1 must not be a virtual table */ } #endif @@ -104645,7 +111897,7 @@ static int xferOptimization( return 0; /* source and destination must both be WITHOUT ROWID or not */ } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pSrc->tabFlags & TF_Virtual ){ + if( IsVirtual(pSrc) ){ return 0; /* tab2 must not be a virtual table */ } #endif @@ -104662,7 +111914,7 @@ static int xferOptimization( Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS - if( (db->flags & SQLITE_Vacuum)==0 + if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN ){ return 0; /* Neither table may have __hidden__ columns */ @@ -104678,11 +111930,15 @@ static int xferOptimization( return 0; /* tab2 must be NOT NULL if tab1 is */ } /* Default values for second and subsequent columns need to match. */ - if( i>0 - && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0) - || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0)) - ){ - return 0; /* Default values must be the same for all columns */ + if( i>0 ){ + assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); + assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); + if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) + || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken, + pSrcCol->pDflt->u.zToken)!=0) + ){ + return 0; /* Default values must be the same for all columns */ + } } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ @@ -104734,15 +111990,15 @@ static int xferOptimization( regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); - if( (db->flags & SQLITE_Vacuum)==0 && ( + if( (db->mDbFlags & DBFLAG_Vacuum)==0 && ( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ )){ /* In some circumstances, we are able to run the xfer optimization ** only if the destination table is initially empty. Unless the - ** SQLITE_Vacuum flag is set, this block generates code to make - ** that determination. If SQLITE_Vacuum is set, then the destination + ** DBFLAG_Vacuum flag is set, this block generates code to make + ** that determination. If DBFLAG_Vacuum is set, then the destination ** table is always empty. ** ** Conditions under which the destination must be empty: @@ -104761,6 +112017,7 @@ static int xferOptimization( sqlite3VdbeJumpHere(v, addr1); } if( HasRowid(pSrc) ){ + u8 insFlags; sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ @@ -104776,10 +112033,17 @@ static int xferOptimization( addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } - sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData); - sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid); - sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND); - sqlite3VdbeChangeP4(v, -1, pDest->zName, 0); + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); + if( db->mDbFlags & DBFLAG_Vacuum ){ + sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID| + OPFLAG_APPEND|OPFLAG_USESEEKRESULT; + }else{ + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; + } + sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, + (char*)pDest, P4_TABLE); + sqlite3VdbeChangeP5(v, insFlags); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); @@ -104801,14 +112065,14 @@ static int xferOptimization( sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData); - if( db->flags & SQLITE_Vacuum ){ + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); + if( db->mDbFlags & DBFLAG_Vacuum ){ /* This INSERT command is part of a VACUUM operation, which guarantees ** that the destination table is empty. If all indexed columns use ** collation sequence BINARY, then it can also be assumed that the ** index will be populated by inserting keys in strictly sorted ** order. In this case, instead of seeking within the b-tree as part - ** of every OP_IdxInsert opcode, an OP_Last is added before the + ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the ** OP_IdxInsert to seek to the point within the b-tree where each key ** should be inserted. This is faster. ** @@ -104819,20 +112083,18 @@ static int xferOptimization( ** sorted order. */ for(i=0; inColumn; i++){ const char *zColl = pSrcIdx->azColl[i]; - assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0 - || sqlite3StrBINARY==zColl ); if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break; } if( i==pSrcIdx->nColumn ){ idxInsFlags = OPFLAG_USESEEKRESULT; - sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); } } if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){ idxInsFlags |= OPFLAG_NCHANGE; } - sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1); - sqlite3VdbeChangeP5(v, idxInsFlags); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); + sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); @@ -104842,6 +112104,7 @@ static int xferOptimization( sqlite3ReleaseTempReg(pParse, regRowid); sqlite3ReleaseTempReg(pParse, regData); if( emptyDestTest ){ + sqlite3AutoincrementEnd(pParse); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0); sqlite3VdbeJumpHere(v, emptyDestTest); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); @@ -104883,7 +112146,7 @@ static int xferOptimization( ** argument to xCallback(). If xCallback=NULL then no callback ** is invoked, even for queries. */ -SQLITE_API int SQLITE_STDCALL sqlite3_exec( +SQLITE_API int sqlite3_exec( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ sqlite3_callback xCallback, /* Invoke this callback routine */ @@ -104929,7 +112192,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( (SQLITE_DONE==rc && !callbackIsInit && db->flags&SQLITE_NullCallback)) ){ if( !callbackIsInit ){ - azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1); + azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*)); if( azCols==0 ){ goto exec_out; } @@ -104946,10 +112209,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( for(i=0; imallocFailed = 1; + sqlite3OomFault(db); goto exec_out; } } + azVals[i] = 0; } if( xCallback(pArg, nCol, azVals, azCols) ){ /* EVIDENCE-OF: R-38229-40159 If the callback function to @@ -104982,12 +112246,9 @@ exec_out: rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && pzErrMsg ){ - int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); - *pzErrMsg = sqlite3Malloc(nErrMsg); - if( *pzErrMsg ){ - memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); - }else{ - rc = SQLITE_NOMEM; + *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db)); + if( *pzErrMsg==0 ){ + rc = SQLITE_NOMEM_BKPT; sqlite3Error(db, SQLITE_NOMEM); } }else if( pzErrMsg ){ @@ -105038,12 +112299,10 @@ exec_out: ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ -#ifndef _SQLITE3EXT_H_ -#define _SQLITE3EXT_H_ +#ifndef SQLITE3EXT_H +#define SQLITE3EXT_H /* #include "sqlite3.h" */ -typedef struct sqlite3_api_routines sqlite3_api_routines; - /* ** The following structure holds pointers to all of the SQLite API ** routines. @@ -105159,7 +112418,7 @@ struct sqlite3_api_routines { int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*snprintf)(int,char*,const char*,...); + char * (*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -105271,7 +112530,7 @@ struct sqlite3_api_routines { int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); - char *(*vsnprintf)(int,char*,const char*,va_list); + char *(*xvsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); /* Version 3.8.7 and later */ int (*auto_extension)(void(*)(void)); @@ -105302,8 +112561,33 @@ struct sqlite3_api_routines { int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); int (*strlike)(const char*,const char*,unsigned int); int (*db_cacheflush)(sqlite3*); + /* Version 3.12.0 and later */ + int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); }; +/* +** This is the function signature used for all extension entry points. It +** is also defined in the file "loadext.c". +*/ +typedef int (*sqlite3_loadext_entry)( + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ +); + /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. @@ -105418,7 +112702,7 @@ struct sqlite3_api_routines { #define sqlite3_rollback_hook sqlite3_api->rollback_hook #define sqlite3_set_authorizer sqlite3_api->set_authorizer #define sqlite3_set_auxdata sqlite3_api->set_auxdata -#define sqlite3_snprintf sqlite3_api->snprintf +#define sqlite3_snprintf sqlite3_api->xsnprintf #define sqlite3_step sqlite3_api->step #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup @@ -105442,7 +112726,7 @@ struct sqlite3_api_routines { #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf -#define sqlite3_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 @@ -105518,7 +112802,7 @@ struct sqlite3_api_routines { #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 /* Version 3.8.7 and later */ #define sqlite3_auto_extension sqlite3_api->auto_extension @@ -105545,6 +112829,19 @@ struct sqlite3_api_routines { #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush +/* Version 3.12.0 and later */ +#define sqlite3_system_errno sqlite3_api->system_errno +/* Version 3.14.0 and later */ +#define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql +/* Version 3.18.0 and later */ +#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +/* Version 3.20.0 and later */ +#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 +#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 +#define sqlite3_bind_pointer sqlite3_api->bind_pointer +#define sqlite3_result_pointer sqlite3_api->result_pointer +#define sqlite3_value_pointer sqlite3_api->value_pointer #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -105562,15 +112859,13 @@ struct sqlite3_api_routines { # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif -#endif /* _SQLITE3EXT_H_ */ +#endif /* SQLITE3EXT_H */ /************** End of sqlite3ext.h ******************************************/ /************** Continuing where we left off in loadext.c ********************/ /* #include "sqliteInt.h" */ -/* #include */ #ifndef SQLITE_OMIT_LOAD_EXTENSION - /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer @@ -105602,6 +112897,7 @@ struct sqlite3_api_routines { # define sqlite3_open16 0 # define sqlite3_prepare16 0 # define sqlite3_prepare16_v2 0 +# define sqlite3_prepare16_v3 0 # define sqlite3_result_error16 0 # define sqlite3_result_text16 0 # define sqlite3_result_text16be 0 @@ -105640,7 +112936,7 @@ struct sqlite3_api_routines { # define sqlite3_enable_shared_cache 0 #endif -#ifdef SQLITE_OMIT_TRACE +#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED) # define sqlite3_profile 0 # define sqlite3_trace 0 #endif @@ -105660,6 +112956,10 @@ struct sqlite3_api_routines { #define sqlite3_blob_reopen 0 #endif +#if defined(SQLITE_OMIT_TRACE) +# define sqlite3_trace_v2 0 +#endif + /* ** The following structure contains pointers to all SQLite API routines. ** A pointer to this structure is passed into extensions when they are @@ -105963,7 +113263,20 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.10.0 and later */ sqlite3_status64, sqlite3_strlike, - sqlite3_db_cacheflush + sqlite3_db_cacheflush, + /* Version 3.12.0 and later */ + sqlite3_system_errno, + /* Version 3.14.0 and later */ + sqlite3_trace_v2, + sqlite3_expanded_sql, + /* Version 3.18.0 and later */ + sqlite3_set_last_insert_rowid, + /* Version 3.20.0 and later */ + sqlite3_prepare_v3, + sqlite3_prepare16_v3, + sqlite3_bind_pointer, + sqlite3_result_pointer, + sqlite3_value_pointer }; /* @@ -105986,13 +113299,14 @@ static int sqlite3LoadExtension( ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; - int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); + sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = 300 + sqlite3Strlen30(zFile); int ii; + int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { @@ -106011,8 +113325,9 @@ static int sqlite3LoadExtension( /* Ticket #1863. To avoid a creating security problems for older ** applications that relink against newer versions of SQLite, the ** ability to run load_extension is turned off by default. One - ** must call sqlite3_enable_load_extension() to turn on extension - ** loading. Otherwise you get the following error. + ** must call either sqlite3_enable_load_extension(db) or + ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0) + ** to turn on extension loading. */ if( (db->flags & SQLITE_LoadExtension)==0 ){ if( pzErrMsg ){ @@ -106027,7 +113342,7 @@ static int sqlite3LoadExtension( #if SQLITE_OS_UNIX || SQLITE_OS_WIN for(ii=0; ii=0 && zFile[iFile]!='/'; iFile--){} @@ -106076,8 +113390,7 @@ static int sqlite3LoadExtension( } memcpy(zAltEntry+iEntry, "_init", 6); zEntry = zAltEntry; - xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) - sqlite3OsDlSym(pVfs, handle, zEntry); + xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); } if( xInit==0 ){ if( pzErrMsg ){ @@ -106094,7 +113407,9 @@ static int sqlite3LoadExtension( return SQLITE_ERROR; } sqlite3_free(zAltEntry); - if( xInit(db, &zErrmsg, &sqlite3Apis) ){ + rc = xInit(db, &zErrmsg, &sqlite3Apis); + if( rc ){ + if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK; if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } @@ -106106,7 +113421,7 @@ static int sqlite3LoadExtension( /* Append the new shared library handle to the db->aExtension array. */ aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1)); if( aHandle==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } if( db->nExtension>0 ){ memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension); @@ -106117,7 +113432,7 @@ static int sqlite3LoadExtension( db->aExtension[db->nExtension++] = handle; return SQLITE_OK; } -SQLITE_API int SQLITE_STDCALL sqlite3_load_extension( +SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ @@ -106148,29 +113463,18 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){ ** Enable or disable extension loading. Extension loading is disabled by ** default so as not to open security holes in older applications. */ -SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){ +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ sqlite3_mutex_enter(db->mutex); if( onoff ){ - db->flags |= SQLITE_LoadExtension; + db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; }else{ - db->flags &= ~SQLITE_LoadExtension; + db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc); } sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } -#endif /* SQLITE_OMIT_LOAD_EXTENSION */ - -/* -** The auto-extension code added regardless of whether or not extension -** loading is supported. We need a dummy sqlite3Apis pointer for that -** code if regular extension loading is not available. This is that -** dummy pointer. -*/ -#ifdef SQLITE_OMIT_LOAD_EXTENSION -static const sqlite3_api_routines sqlite3Apis = { 0 }; -#endif - +#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */ /* ** The following object holds the list of automatically loaded @@ -106205,7 +113509,9 @@ static SQLITE_WSD struct sqlite3AutoExtList { ** Register a statically linked extension that is automatically ** loaded by every new database connection. */ -SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){ +SQLITE_API int sqlite3_auto_extension( + void (*xInit)(void) +){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); @@ -106228,7 +113534,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){ void (**aNew)(void); aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte); if( aNew==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; }else{ wsdAutoext.aExt = aNew; wsdAutoext.aExt[wsdAutoext.nExt] = xInit; @@ -106250,7 +113556,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){ ** Return 1 if xInit was found on the list and removed. Return 0 if xInit ** was not on the list. */ -SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){ +SQLITE_API int sqlite3_cancel_auto_extension( + void (*xInit)(void) +){ #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif @@ -106273,7 +113581,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)) /* ** Reset the automatic extension loading mechanism. */ -SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){ +SQLITE_API void sqlite3_reset_auto_extension(void){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize()==SQLITE_OK ) #endif @@ -106299,7 +113607,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ u32 i; int go = 1; int rc; - int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); + sqlite3_loadext_entry xInit; wsdAutoextInit; if( wsdAutoext.nExt==0 ){ @@ -106310,18 +113618,22 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ char *zErrmsg; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif +#ifdef SQLITE_OMIT_LOAD_EXTENSION + const sqlite3_api_routines *pThunk = 0; +#else + const sqlite3_api_routines *pThunk = &sqlite3Apis; #endif sqlite3_mutex_enter(mutex); if( i>=wsdAutoext.nExt ){ xInit = 0; go = 0; }else{ - xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) - wsdAutoext.aExt[i]; + xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i]; } sqlite3_mutex_leave(mutex); zErrmsg = 0; - if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){ + if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){ sqlite3ErrorWithMsg(db, rc, "automatic extension loading failed: %s", zErrmsg); go = 0; @@ -106369,6 +113681,8 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ ** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit ** that script and rerun it. */ + +/* The various pragma types */ #define PragTyp_HEADER_VALUE 0 #define PragTyp_AUTO_VACUUM 1 #define PragTyp_FLAG 2 @@ -106384,458 +113698,641 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_ENCODING 12 #define PragTyp_FOREIGN_KEY_CHECK 13 #define PragTyp_FOREIGN_KEY_LIST 14 -#define PragTyp_INCREMENTAL_VACUUM 15 -#define PragTyp_INDEX_INFO 16 -#define PragTyp_INDEX_LIST 17 -#define PragTyp_INTEGRITY_CHECK 18 -#define PragTyp_JOURNAL_MODE 19 -#define PragTyp_JOURNAL_SIZE_LIMIT 20 -#define PragTyp_LOCK_PROXY_FILE 21 -#define PragTyp_LOCKING_MODE 22 -#define PragTyp_PAGE_COUNT 23 -#define PragTyp_MMAP_SIZE 24 -#define PragTyp_PAGE_SIZE 25 -#define PragTyp_SECURE_DELETE 26 -#define PragTyp_SHRINK_MEMORY 27 -#define PragTyp_SOFT_HEAP_LIMIT 28 -#define PragTyp_STATS 29 -#define PragTyp_SYNCHRONOUS 30 -#define PragTyp_TABLE_INFO 31 -#define PragTyp_TEMP_STORE 32 -#define PragTyp_TEMP_STORE_DIRECTORY 33 -#define PragTyp_THREADS 34 -#define PragTyp_WAL_AUTOCHECKPOINT 35 -#define PragTyp_WAL_CHECKPOINT 36 -#define PragTyp_ACTIVATE_EXTENSIONS 37 -#define PragTyp_HEXKEY 38 -#define PragTyp_KEY 39 -#define PragTyp_REKEY 40 -#define PragTyp_LOCK_STATUS 41 -#define PragTyp_PARSER_TRACE 42 -#define PragFlag_NeedSchema 0x01 -#define PragFlag_ReadOnly 0x02 -static const struct sPragmaNames { - const char *const zName; /* Name of pragma */ - u8 ePragTyp; /* PragTyp_XXX value */ - u8 mPragFlag; /* Zero or more PragFlag_XXX values */ - u32 iArg; /* Extra argument */ -} aPragmaNames[] = { +#define PragTyp_FUNCTION_LIST 15 +#define PragTyp_INCREMENTAL_VACUUM 16 +#define PragTyp_INDEX_INFO 17 +#define PragTyp_INDEX_LIST 18 +#define PragTyp_INTEGRITY_CHECK 19 +#define PragTyp_JOURNAL_MODE 20 +#define PragTyp_JOURNAL_SIZE_LIMIT 21 +#define PragTyp_LOCK_PROXY_FILE 22 +#define PragTyp_LOCKING_MODE 23 +#define PragTyp_PAGE_COUNT 24 +#define PragTyp_MMAP_SIZE 25 +#define PragTyp_MODULE_LIST 26 +#define PragTyp_OPTIMIZE 27 +#define PragTyp_PAGE_SIZE 28 +#define PragTyp_PRAGMA_LIST 29 +#define PragTyp_SECURE_DELETE 30 +#define PragTyp_SHRINK_MEMORY 31 +#define PragTyp_SOFT_HEAP_LIMIT 32 +#define PragTyp_SYNCHRONOUS 33 +#define PragTyp_TABLE_INFO 34 +#define PragTyp_TEMP_STORE 35 +#define PragTyp_TEMP_STORE_DIRECTORY 36 +#define PragTyp_THREADS 37 +#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 + +/* Property flags associated with various pragma. */ +#define PragFlg_NeedSchema 0x01 /* Force schema load before running */ +#define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ +#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ +#define PragFlg_ReadOnly 0x08 /* Read-only HEADER_VALUE */ +#define PragFlg_Result0 0x10 /* Acts as query when no argument */ +#define PragFlg_Result1 0x20 /* Acts as query when has one argument */ +#define PragFlg_SchemaOpt 0x40 /* Schema restricts name search if present */ +#define PragFlg_SchemaReq 0x80 /* Schema required - "main" is default */ + +/* Names of columns for pragmas that return multi-column result +** or that return single-column results where the name of the +** 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", + /* 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 */ + /* 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", +}; + +/* Definitions of all built-in pragmas */ +typedef struct PragmaName { + const char *const zName; /* Name of pragma */ + u8 ePragTyp; /* PragTyp_XXX value */ + 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 */ +} PragmaName; +static const PragmaName aPragmaName[] = { #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) - { /* zName: */ "activate_extensions", - /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "activate_extensions", + /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "application_id", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ BTREE_APPLICATION_ID }, + {/* zName: */ "application_id", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_APPLICATION_ID }, #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) - { /* zName: */ "auto_vacuum", - /* ePragTyp: */ PragTyp_AUTO_VACUUM, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "auto_vacuum", + /* ePragTyp: */ PragTyp_AUTO_VACUUM, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX) - { /* zName: */ "automatic_index", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_AutoIndex }, + {/* zName: */ "automatic_index", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_AutoIndex }, #endif #endif - { /* zName: */ "busy_timeout", - /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "busy_timeout", + /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 49, 1, + /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "cache_size", - /* ePragTyp: */ PragTyp_CACHE_SIZE, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "cache_size", + /* ePragTyp: */ PragTyp_CACHE_SIZE, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "cache_spill", - /* ePragTyp: */ PragTyp_CACHE_SPILL, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "cache_spill", + /* ePragTyp: */ PragTyp_CACHE_SPILL, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif - { /* zName: */ "case_sensitive_like", - /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "cell_size_check", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CellSizeCk }, + {/* zName: */ "case_sensitive_like", + /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, + /* ePragFlg: */ PragFlg_NoColumns, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "cell_size_check", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_CellSizeCk }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "checkpoint_fullfsync", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CkptFullFSync }, + {/* zName: */ "checkpoint_fullfsync", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_CkptFullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "collation_list", - /* ePragTyp: */ PragTyp_COLLATION_LIST, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "collation_list", + /* ePragTyp: */ PragTyp_COLLATION_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 32, 2, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) - { /* zName: */ "compile_options", - /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "compile_options", + /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "count_changes", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CountRows }, + {/* zName: */ "count_changes", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_CountRows }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN - { /* zName: */ "data_store_directory", - /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "data_store_directory", + /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "data_version", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ PragFlag_ReadOnly, - /* iArg: */ BTREE_DATA_VERSION }, + {/* zName: */ "data_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_DATA_VERSION }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "database_list", - /* ePragTyp: */ PragTyp_DATABASE_LIST, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "database_list", + /* ePragTyp: */ PragTyp_DATABASE_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, + /* ColNames: */ 26, 3, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) - { /* zName: */ "default_cache_size", - /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "default_cache_size", + /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 1, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { /* zName: */ "defer_foreign_keys", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_DeferFKs }, + {/* zName: */ "defer_foreign_keys", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_DeferFKs }, #endif #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "empty_result_callbacks", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_NullCallback }, + {/* zName: */ "empty_result_callbacks", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_NullCallback }, #endif #if !defined(SQLITE_OMIT_UTF16) - { /* zName: */ "encoding", - /* ePragTyp: */ PragTyp_ENCODING, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "encoding", + /* ePragTyp: */ PragTyp_ENCODING, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { /* zName: */ "foreign_key_check", - /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "foreign_key_check", + /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, + /* ColNames: */ 42, 4, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) - { /* zName: */ "foreign_key_list", - /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "foreign_key_list", + /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 34, 8, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - { /* zName: */ "foreign_keys", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ForeignKeys }, + {/* zName: */ "foreign_keys", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ForeignKeys }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "freelist_count", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ PragFlag_ReadOnly, - /* iArg: */ BTREE_FREE_PAGE_COUNT }, + {/* zName: */ "freelist_count", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_FREE_PAGE_COUNT }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "full_column_names", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_FullColNames }, - { /* zName: */ "fullfsync", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_FullFSync }, + {/* zName: */ "full_column_names", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_FullColNames }, + {/* zName: */ "fullfsync", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_FullFSync }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if defined(SQLITE_INTROSPECTION_PRAGMAS) + {/* zName: */ "function_list", + /* ePragTyp: */ PragTyp_FUNCTION_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 29, 2, + /* iArg: */ 0 }, +#endif #endif #if defined(SQLITE_HAS_CODEC) - { /* zName: */ "hexkey", - /* ePragTyp: */ PragTyp_HEXKEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "hexrekey", - /* ePragTyp: */ PragTyp_HEXKEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "hexkey", + /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "hexrekey", + /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) - { /* zName: */ "ignore_check_constraints", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_IgnoreChecks }, + {/* zName: */ "ignore_check_constraints", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_IgnoreChecks }, #endif #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) - { /* zName: */ "incremental_vacuum", - /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "incremental_vacuum", + /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "index_info", - /* ePragTyp: */ PragTyp_INDEX_INFO, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "index_list", - /* ePragTyp: */ PragTyp_INDEX_LIST, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "index_xinfo", - /* ePragTyp: */ PragTyp_INDEX_INFO, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 1 }, + {/* zName: */ "index_info", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 12, 3, + /* iArg: */ 0 }, + {/* zName: */ "index_list", + /* ePragTyp: */ PragTyp_INDEX_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 21, 5, + /* iArg: */ 0 }, + {/* zName: */ "index_xinfo", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 15, 6, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) - { /* zName: */ "integrity_check", - /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "integrity_check", + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "journal_mode", - /* ePragTyp: */ PragTyp_JOURNAL_MODE, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "journal_size_limit", - /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "journal_mode", + /* ePragTyp: */ PragTyp_JOURNAL_MODE, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "journal_size_limit", + /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if defined(SQLITE_HAS_CODEC) - { /* zName: */ "key", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "key", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "legacy_file_format", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_LegacyFileFmt }, + {/* zName: */ "legacy_file_format", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_LegacyFileFmt }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE - { /* zName: */ "lock_proxy_file", - /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "lock_proxy_file", + /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - { /* zName: */ "lock_status", - /* ePragTyp: */ PragTyp_LOCK_STATUS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "lock_status", + /* ePragTyp: */ PragTyp_LOCK_STATUS, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 50, 2, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "locking_mode", - /* ePragTyp: */ PragTyp_LOCKING_MODE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "max_page_count", - /* ePragTyp: */ PragTyp_PAGE_COUNT, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "mmap_size", - /* ePragTyp: */ PragTyp_MMAP_SIZE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "page_count", - /* ePragTyp: */ PragTyp_PAGE_COUNT, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, - { /* zName: */ "page_size", - /* ePragTyp: */ PragTyp_PAGE_SIZE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "locking_mode", + /* ePragTyp: */ PragTyp_LOCKING_MODE, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "max_page_count", + /* ePragTyp: */ PragTyp_PAGE_COUNT, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "mmap_size", + /* ePragTyp: */ PragTyp_MMAP_SIZE, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if !defined(SQLITE_OMIT_VIRTUALTABLE) +#if defined(SQLITE_INTROSPECTION_PRAGMAS) + {/* zName: */ "module_list", + /* ePragTyp: */ PragTyp_MODULE_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 31, 1, + /* iArg: */ 0 }, +#endif +#endif +#endif + {/* zName: */ "optimize", + /* ePragTyp: */ PragTyp_OPTIMIZE, + /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "page_count", + /* ePragTyp: */ PragTyp_PAGE_COUNT, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "page_size", + /* ePragTyp: */ PragTyp_PAGE_SIZE, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE) - { /* zName: */ "parser_trace", - /* ePragTyp: */ PragTyp_PARSER_TRACE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "parser_trace", + /* ePragTyp: */ PragTyp_PARSER_TRACE, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_INTROSPECTION_PRAGMAS) + {/* zName: */ "pragma_list", + /* ePragTyp: */ PragTyp_PRAGMA_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 31, 1, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "query_only", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_QueryOnly }, + {/* zName: */ "query_only", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_QueryOnly }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) - { /* zName: */ "quick_check", - /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "quick_check", + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "read_uncommitted", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ReadUncommitted }, - { /* zName: */ "recursive_triggers", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_RecTriggers }, + {/* zName: */ "read_uncommitted", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ReadUncommit }, + {/* zName: */ "recursive_triggers", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_RecTriggers }, #endif #if defined(SQLITE_HAS_CODEC) - { /* zName: */ "rekey", - /* ePragTyp: */ PragTyp_REKEY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "rekey", + /* ePragTyp: */ PragTyp_REKEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "reverse_unordered_selects", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ReverseOrder }, + {/* zName: */ "reverse_unordered_selects", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ReverseOrder }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "schema_version", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ BTREE_SCHEMA_VERSION }, + {/* zName: */ "schema_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_SCHEMA_VERSION }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "secure_delete", - /* ePragTyp: */ PragTyp_SECURE_DELETE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "secure_delete", + /* ePragTyp: */ PragTyp_SECURE_DELETE, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "short_column_names", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_ShortColNames }, + {/* zName: */ "short_column_names", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ShortColNames }, #endif - { /* zName: */ "shrink_memory", - /* ePragTyp: */ PragTyp_SHRINK_MEMORY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "soft_heap_limit", - /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "shrink_memory", + /* ePragTyp: */ PragTyp_SHRINK_MEMORY, + /* ePragFlg: */ PragFlg_NoColumns, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "soft_heap_limit", + /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) - { /* zName: */ "sql_trace", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_SqlTrace }, + {/* zName: */ "sql_trace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_SqlTrace }, #endif #endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "stats", - /* ePragTyp: */ PragTyp_STATS, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) + {/* zName: */ "stats", + /* ePragTyp: */ PragTyp_STATS, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 7, 5, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "synchronous", - /* ePragTyp: */ PragTyp_SYNCHRONOUS, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "synchronous", + /* ePragTyp: */ PragTyp_SYNCHRONOUS, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - { /* zName: */ "table_info", - /* ePragTyp: */ PragTyp_TABLE_INFO, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "table_info", + /* ePragTyp: */ PragTyp_TABLE_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 1, 6, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) - { /* zName: */ "temp_store", - /* ePragTyp: */ PragTyp_TEMP_STORE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "temp_store_directory", - /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "temp_store", + /* ePragTyp: */ PragTyp_TEMP_STORE, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "temp_store_directory", + /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #endif - { /* zName: */ "threads", - /* ePragTyp: */ PragTyp_THREADS, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + {/* zName: */ "threads", + /* ePragTyp: */ PragTyp_THREADS, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) - { /* zName: */ "user_version", - /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ BTREE_USER_VERSION }, + {/* zName: */ "user_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_USER_VERSION }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) - { /* zName: */ "vdbe_addoptrace", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeAddopTrace }, - { /* zName: */ "vdbe_debug", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, - { /* zName: */ "vdbe_eqp", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeEQP }, - { /* zName: */ "vdbe_listing", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeListing }, - { /* zName: */ "vdbe_trace", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_VdbeTrace }, + {/* zName: */ "vdbe_addoptrace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeAddopTrace }, + {/* zName: */ "vdbe_debug", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, + {/* zName: */ "vdbe_eqp", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeEQP }, + {/* zName: */ "vdbe_listing", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeListing }, + {/* zName: */ "vdbe_trace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeTrace }, #endif #endif #if !defined(SQLITE_OMIT_WAL) - { /* zName: */ "wal_autocheckpoint", - /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, - { /* zName: */ "wal_checkpoint", - /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, - /* ePragFlag: */ PragFlag_NeedSchema, - /* iArg: */ 0 }, + {/* zName: */ "wal_autocheckpoint", + /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "wal_checkpoint", + /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, + /* ePragFlg: */ PragFlg_NeedSchema, + /* ColNames: */ 46, 3, + /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - { /* zName: */ "writable_schema", - /* ePragTyp: */ PragTyp_FLAG, - /* ePragFlag: */ 0, - /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, + {/* zName: */ "writable_schema", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_WriteSchema }, #endif }; -/* Number of pragmas: 60 on by default, 73 total. */ +/* Number of pragmas: 60 on by default, 77 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ /* ** Interpret the given string as a safety level. Return 0 for OFF, -** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or -** unrecognized string argument. The FULL option is disallowed +** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or +** unrecognized string argument. The FULL and EXTRA option is disallowed ** if the omitFull parameter it 1. ** ** Note that the values returned are one less that the values that @@ -106844,18 +114341,21 @@ static const struct sPragmaNames { ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){ - /* 123456789 123456789 */ - static const char zText[] = "onoffalseyestruefull"; - static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16}; - static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4}; - static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2}; + /* 123456789 123456789 123 */ + static const char zText[] = "onoffalseyestruextrafull"; + static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 15, 20}; + static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 5, 4}; + static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 3, 2}; + /* on no off false yes true extra full */ int i, n; if( sqlite3Isdigit(*z) ){ return (u8)sqlite3Atoi(z); } n = sqlite3Strlen30(z); - for(i=0; inPragCName; + sqlite3VdbeSetNumCols(v, n==0 ? 1 : n); + if( n==0 ){ + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC); + }else{ + int i, j; + for(i=0, j=pPragma->iPragCName; iupr ? 0 : &aPragmaName[mid]; +} + +/* +** Helper subroutine for PRAGMA integrity_check: +** +** Generate code to output a single-column result row with a value of the +** string held in register 3. Decrement the result count in register 1 +** and halt if the maximum number of result rows have been issued. +*/ +static int integrityCheckResultRow(Vdbe *v){ + int addr; + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); + addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1); + VdbeCoverage(v); + sqlite3VdbeAddOp0(v, OP_Halt); + return addr; +} + /* ** Process a pragma statement. ** @@ -107104,12 +114638,11 @@ SQLITE_PRIVATE void sqlite3Pragma( Token *pId; /* Pointer to token */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ int iDb; /* Database index for */ - int lwr, upr, mid = 0; /* Binary search bounds */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ - const struct sPragmaNames *pPragma; + const PragmaName *pPragma; /* The pragma */ if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); @@ -107137,7 +114670,7 @@ SQLITE_PRIVATE void sqlite3Pragma( } assert( pId2 ); - zDb = pId2->n>0 ? pDb->zName : 0; + zDb = pId2->n>0 ? pDb->zDbSName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; } @@ -107164,7 +114697,9 @@ SQLITE_PRIVATE void sqlite3Pragma( db->busyHandler.nBusy = 0; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); if( rc==SQLITE_OK ){ - returnSingleText(v, "result", aFcntl[0]); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT); + returnSingleText(v, aFcntl[0]); sqlite3_free(aFcntl[0]); goto pragma_out; } @@ -107179,26 +114714,21 @@ SQLITE_PRIVATE void sqlite3Pragma( } /* Locate the pragma in the lookup table */ - lwr = 0; - upr = ArraySize(aPragmaNames)-1; - while( lwr<=upr ){ - mid = (lwr+upr)/2; - rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName); - if( rc==0 ) break; - if( rc<0 ){ - upr = mid - 1; - }else{ - lwr = mid + 1; - } - } - if( lwr>upr ) goto pragma_out; - pPragma = &aPragmaNames[mid]; + pPragma = pragmaLocate(zLeft); + if( pPragma==0 ) goto pragma_out; /* Make sure the database schema is loaded if the pragma requires that */ - if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){ + if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } + /* Register the result column names for pragmas that return results */ + if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 + && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0) + ){ + setPragmaResultColumnNames(v, pPragma); + } + /* Jump to the appropriate pragma handler */ switch( pPragma->ePragTyp ){ @@ -107232,20 +114762,20 @@ SQLITE_PRIVATE void sqlite3Pragma( { OP_Noop, 0, 0, 0}, { OP_ResultRow, 1, 1, 0}, }; - int addr; + VdbeOp *aOp; sqlite3VdbeUsesBtree(v, iDb); if( !zRight ){ - setOneColumnName(v, "cache_size"); pParse->nMem += 2; - addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn); - sqlite3VdbeChangeP1(v, addr, iDb); - sqlite3VdbeChangeP1(v, addr+1, iDb); - sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE); + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE; }else{ int size = sqlite3AbsInt32(sqlite3Atoi(zRight)); sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3VdbeAddOp2(v, OP_Integer, size, 1); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); @@ -107269,14 +114799,14 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( pBt!=0 ); if( !zRight ){ int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0; - returnSingleInt(v, "page_size", size); + returnSingleInt(v, size); }else{ /* Malloc may fail when setting the page-size, as there is an internal ** buffer that the pager module resizes using sqlite3_realloc(). */ db->nextPagesize = sqlite3Atoi(zRight); if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } } break; @@ -107284,18 +114814,22 @@ SQLITE_PRIVATE void sqlite3Pragma( /* ** PRAGMA [schema.]secure_delete - ** PRAGMA [schema.]secure_delete=ON/OFF + ** PRAGMA [schema.]secure_delete=ON/OFF/FAST ** ** The first form reports the current setting for the ** secure_delete flag. The second form changes the secure_delete - ** flag setting and reports thenew value. + ** flag setting and reports the new value. */ case PragTyp_SECURE_DELETE: { Btree *pBt = pDb->pBt; int b = -1; assert( pBt!=0 ); if( zRight ){ - b = sqlite3GetBoolean(zRight, 0); + if( sqlite3_stricmp(zRight, "fast")==0 ){ + b = 2; + }else{ + b = sqlite3GetBoolean(zRight, 0); + } } if( pId2->n==0 && b>=0 ){ int ii; @@ -107304,7 +114838,7 @@ SQLITE_PRIVATE void sqlite3Pragma( } } b = sqlite3BtreeSecureDelete(pBt, b); - returnSingleInt(v, "secure_delete", b); + returnSingleInt(v, b); break; } @@ -107336,8 +114870,6 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3AbsInt32(sqlite3Atoi(zRight))); } sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); break; } @@ -107383,7 +114915,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){ zRet = "exclusive"; } - returnSingleText(v, "locking_mode", zRet); + returnSingleText(v, zRet); break; } @@ -107396,7 +114928,6 @@ SQLITE_PRIVATE void sqlite3Pragma( int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */ int ii; /* Loop counter */ - setOneColumnName(v, "journal_mode"); if( zRight==0 ){ /* If there is no "=MODE" part of the pragma, do a query for the ** current mode */ @@ -107442,7 +114973,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( iLimit<-1 ) iLimit = -1; } iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); - returnSingleInt(v, "journal_size_limit", iLimit); + returnSingleInt(v, iLimit); break; } @@ -107460,7 +114991,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Btree *pBt = pDb->pBt; assert( pBt!=0 ); if( !zRight ){ - returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt)); + returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt)); }else{ int eAuto = getAutoVacuum(zRight); assert( eAuto>=0 && eAuto<=2 ); @@ -107483,16 +115014,18 @@ SQLITE_PRIVATE void sqlite3Pragma( { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE}, { OP_If, 1, 0, 0}, /* 2 */ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ - { OP_Integer, 0, 1, 0}, /* 4 */ - { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */ + { OP_SetCookie, 0, BTREE_INCR_VACUUM, 0}, /* 4 */ }; - int iAddr; - iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); - sqlite3VdbeChangeP1(v, iAddr, iDb); - sqlite3VdbeChangeP1(v, iAddr+1, iDb); - sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); - sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); - sqlite3VdbeChangeP1(v, iAddr+5, iDb); + VdbeOp *aOp; + int iAddr = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[2].p2 = iAddr+4; + aOp[4].p1 = iDb; + aOp[4].p3 = eAuto - 1; sqlite3VdbeUsesBtree(v, iDb); } } @@ -107537,7 +115070,7 @@ SQLITE_PRIVATE void sqlite3Pragma( case PragTyp_CACHE_SIZE: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ - returnSingleInt(v, "cache_size", pDb->pSchema->cache_size); + returnSingleInt(v, pDb->pSchema->cache_size); }else{ int size = sqlite3Atoi(zRight); pDb->pSchema->cache_size = size; @@ -107571,7 +115104,7 @@ SQLITE_PRIVATE void sqlite3Pragma( case PragTyp_CACHE_SPILL: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ - returnSingleInt(v, "cache_spill", + returnSingleInt(v, (db->flags & SQLITE_CacheSpill)==0 ? 0 : sqlite3BtreeSetSpillSize(pDb->pBt,0)); }else{ @@ -107625,7 +115158,7 @@ SQLITE_PRIVATE void sqlite3Pragma( rc = SQLITE_OK; #endif if( rc==SQLITE_OK ){ - returnSingleInt(v, "mmap_size", sz); + returnSingleInt(v, sz); }else if( rc!=SQLITE_NOTFOUND ){ pParse->nErr++; pParse->rc = rc; @@ -107646,7 +115179,7 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_TEMP_STORE: { if( !zRight ){ - returnSingleInt(v, "temp_store", db->temp_store); + returnSingleInt(v, db->temp_store); }else{ changeTempStorage(pParse, zRight); } @@ -107665,7 +115198,7 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_TEMP_STORE_DIRECTORY: { if( !zRight ){ - returnSingleText(v, "temp_store_directory", sqlite3_temp_directory); + returnSingleText(v, sqlite3_temp_directory); }else{ #ifndef SQLITE_OMIT_WSD if( zRight[0] ){ @@ -107709,7 +115242,7 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_DATA_STORE_DIRECTORY: { if( !zRight ){ - returnSingleText(v, "data_store_directory", sqlite3_data_directory); + returnSingleText(v, sqlite3_data_directory); }else{ #ifndef SQLITE_OMIT_WSD if( zRight[0] ){ @@ -107748,7 +115281,7 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3_file *pFile = sqlite3PagerFile(pPager); sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, &proxy_file_path); - returnSingleText(v, "lock_proxy_file", proxy_file_path); + returnSingleText(v, proxy_file_path); }else{ Pager *pPager = sqlite3BtreePager(pDb->pBt); sqlite3_file *pFile = sqlite3PagerFile(pPager); @@ -107771,7 +115304,7 @@ SQLITE_PRIVATE void sqlite3Pragma( /* ** PRAGMA [schema.]synchronous - ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL + ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA ** ** Return or set the local value of the synchronous flag. Changing ** the local value does not make changes to the disk file and the @@ -107780,15 +115313,16 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_SYNCHRONOUS: { if( !zRight ){ - returnSingleInt(v, "synchronous", pDb->safety_level-1); + returnSingleInt(v, pDb->safety_level-1); }else{ if( !db->autoCommit ){ sqlite3ErrorMsg(pParse, "Safety level may not be changed inside a transaction"); - }else{ + }else if( iDb!=1 ){ int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK; if( iLevel==0 ) iLevel = 1; pDb->safety_level = iLevel; + pDb->bSyncSet = 1; setAllPagerFlags(db); } } @@ -107799,7 +115333,8 @@ SQLITE_PRIVATE void sqlite3Pragma( #ifndef SQLITE_OMIT_FLAG_PRAGMAS case PragTyp_FLAG: { if( zRight==0 ){ - returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 ); + setPragmaResultColumnNames(v, pPragma); + returnSingleInt(v, (db->flags & pPragma->iArg)!=0 ); }else{ int mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ @@ -107825,7 +115360,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ - sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); + sqlite3VdbeAddOp0(v, OP_Expire); setAllPagerFlags(db); } break; @@ -107847,18 +115382,14 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; - pTab = sqlite3FindTable(db, zRight, zDb); + pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ - static const char *azCol[] = { - "cid", "name", "type", "notnull", "dflt_value", "pk" - }; int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); pParse->nMem = 6; sqlite3CodeVerifySchema(pParse, iDb); - setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) ); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ if( IsHiddenColumn(pCol) ){ @@ -107872,54 +115403,51 @@ SQLITE_PRIVATE void sqlite3Pragma( }else{ 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", i-nHidden, pCol->zName, - pCol->zType ? pCol->zType : "", + sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, - pCol->zDflt, + pCol->pDflt ? pCol->pDflt->u.zToken : 0, k); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } } break; +#ifdef SQLITE_DEBUG case PragTyp_STATS: { - static const char *azCol[] = { "table", "index", "width", "height" }; Index *pIdx; HashElem *i; - v = sqlite3GetVdbe(pParse); - pParse->nMem = 4; + pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); - setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) ); for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); - sqlite3VdbeMultiLoad(v, 1, "ssii", + sqlite3VdbeMultiLoad(v, 1, "ssiii", pTab->zName, 0, - (int)sqlite3LogEstToInt(pTab->szTabRow), - (int)sqlite3LogEstToInt(pTab->nRowLogEst)); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); + pTab->szTabRow, + pTab->nRowLogEst, + pTab->tabFlags); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqlite3VdbeMultiLoad(v, 2, "sii", + sqlite3VdbeMultiLoad(v, 2, "siiiX", pIdx->zName, - (int)sqlite3LogEstToInt(pIdx->szIdxRow), - (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0])); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); + pIdx->szIdxRow, + pIdx->aiRowLogEst[0], + pIdx->hasStat1); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } break; +#endif case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ - static const char *azCol[] = { - "seqno", "cid", "name", "desc", "coll", "key" - }; int i; int mx; if( pPragma->iArg ){ @@ -107933,14 +115461,13 @@ SQLITE_PRIVATE void sqlite3Pragma( } pTab = pIdx->pTable; sqlite3CodeVerifySchema(pParse, iDb); - assert( pParse->nMem<=ArraySize(azCol) ); - setAllColumnNames(v, pParse->nMem, azCol); + assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; iaiColumn[i]; - sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum, + sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, cnum<0 ? 0 : pTab->aCol[cnum].zName); if( pPragma->iArg ){ - sqlite3VdbeMultiLoad(v, 4, "isi", + sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], pIdx->azColl[i], inKeyCol); @@ -107957,13 +115484,8 @@ SQLITE_PRIVATE void sqlite3Pragma( int i; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ - static const char *azCol[] = { - "seq", "name", "unique", "origin", "partial" - }; - v = sqlite3GetVdbe(pParse); pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); - setAllColumnNames(v, 5, azCol); assert( 5==ArraySize(azCol) ); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeMultiLoad(v, 1, "isisi", @@ -107972,42 +115494,75 @@ SQLITE_PRIVATE void sqlite3Pragma( IsUniqueIndex(pIdx), azOrigin[pIdx->idxType], pIdx->pPartIdxWhere!=0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } break; case PragTyp_DATABASE_LIST: { - static const char *azCol[] = { "seq", "name", "file" }; int i; pParse->nMem = 3; - setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) ); for(i=0; inDb; i++){ if( db->aDb[i].pBt==0 ) continue; - assert( db->aDb[i].zName!=0 ); + assert( db->aDb[i].zDbSName!=0 ); sqlite3VdbeMultiLoad(v, 1, "iss", i, - db->aDb[i].zName, + db->aDb[i].zDbSName, sqlite3BtreeGetFilename(db->aDb[i].pBt)); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } break; case PragTyp_COLLATION_LIST: { - static const char *azCol[] = { "seq", "name" }; int i = 0; HashElem *p; pParse->nMem = 2; - setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) ); for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } } break; + +#ifdef SQLITE_INTROSPECTION_PRAGMAS + case PragTyp_FUNCTION_LIST: { + int i; + HashElem *j; + FuncDef *p; + pParse->nMem = 2; + for(i=0; iu.pHash ){ + sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1); + } + } + for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ + p = (FuncDef*)sqliteHashData(j); + sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0); + } + } + break; + +#ifndef SQLITE_OMIT_VIRTUALTABLE + case PragTyp_MODULE_LIST: { + HashElem *j; + pParse->nMem = 1; + for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){ + Module *pMod = (Module*)sqliteHashData(j); + sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName); + } + } + break; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + case PragTyp_PRAGMA_LIST: { + int i; + for(i=0; ipFKey; if( pFK ){ - static const char *azCol[] = { - "id", "seq", "table", "from", "to", "on_update", "on_delete", - "match" - }; int i = 0; pParse->nMem = 8; sqlite3CodeVerifySchema(pParse, iDb); - setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) ); while(pFK){ int j; for(j=0; jnCol; j++){ @@ -108039,7 +115588,6 @@ SQLITE_PRIVATE void sqlite3Pragma( actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ "NONE"); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8); } ++i; pFK = pFK->pNextFrom; @@ -108067,14 +115615,11 @@ SQLITE_PRIVATE void sqlite3Pragma( int addrTop; /* Top of a loop checking foreign keys */ int addrOk; /* Jump here if the key is OK */ int *aiCols; /* child to parent column mapping */ - static const char *azCol[] = { "table", "rowid", "parent", "fkid" }; regResult = pParse->nMem+1; pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; - v = sqlite3GetVdbe(pParse); - setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) ); sqlite3CodeVerifySchema(pParse, iDb); k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ @@ -108121,36 +115666,38 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( x==0 ); } addrOk = sqlite3VdbeMakeLabel(v); - if( pParent && pIdx==0 ){ - int iKey = pFK->aCol[0].iFrom; - assert( iKey>=0 && iKeynCol ); - if( iKey!=pTab->iPKey ){ - sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); - sqlite3ColumnDefault(v, pTab, iKey, regRow); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, - sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v); - }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); - } - sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v); - sqlite3VdbeGoto(v, addrOk); - sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); - }else{ - for(j=0; jnCol; j++){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, - aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); - } - if( pParent ){ - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, - sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); - sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); - VdbeCoverage(v); - } + + /* Generate code to read the child key values into registers + ** regRow..regRow+n. If any of the child key values are NULL, this + ** row cannot cause an FK violation. Jump directly to addrOk in + ** this case. */ + for(j=0; jnCol; j++){ + int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; + sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); + sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); - sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1); + + /* Generate code to query the parent index for a matching parent + ** key. If a match is found, jump to addrOk. */ + if( pIdx ){ + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, + sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); + sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); + VdbeCoverage(v); + }else if( pParent ){ + int jmp = sqlite3VdbeCurrentAddr(v)+2; + sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v); + sqlite3VdbeGoto(v, addrOk); + assert( pFK->nCol==1 ); + } + + /* Generate code to report an FK violation to the caller. */ + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1); + } + sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1); sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); sqlite3VdbeResolveLabel(v, addrOk); sqlite3DbFree(db, aiCols); @@ -108191,25 +115738,21 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif #ifndef SQLITE_OMIT_INTEGRITY_CHECK - /* Pragma "quick_check" is reduced version of + /* PRAGMA integrity_check + ** PRAGMA integrity_check(N) + ** PRAGMA quick_check + ** PRAGMA quick_check(N) + ** + ** Verify the integrity of the database. + ** + ** The "quick_check" is reduced version of ** integrity_check designed to detect most database corruption - ** without most of the overhead of a full integrity-check. + ** without the overhead of cross-checking indexes. Quick_check + ** is linear time wherease integrity_check is O(NlogN). */ case PragTyp_INTEGRITY_CHECK: { int i, j, addr, mxErr; - /* Code that appears at the end of the integrity check. If no error - ** messages have been generated, output OK. Otherwise output the - ** error message - */ - static const int iLn = VDBE_OFFSET_LINENO(2); - static const VdbeOpList endCode[] = { - { OP_AddImm, 1, 0, 0}, /* 0 */ - { OP_If, 1, 0, 0}, /* 1 */ - { OP_String8, 0, 3, 0}, /* 2 */ - { OP_ResultRow, 3, 1, 0}, - }; - int isQuick = (sqlite3Tolower(zLeft[0])=='q'); /* If the PRAGMA command was of the form "PRAGMA .integrity_check", @@ -108227,7 +115770,6 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Initialize the VDBE program */ pParse->nMem = 6; - setOneColumnName(v, "integrity_check"); /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; @@ -108237,63 +115779,66 @@ SQLITE_PRIVATE void sqlite3Pragma( mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; } } - sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */ + sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */ /* Do an integrity check on each database file */ for(i=0; inDb; i++){ - HashElem *x; - Hash *pTbls; - int cnt = 0; + HashElem *x; /* For looping over tables in the schema */ + Hash *pTbls; /* Set of all tables in the schema */ + int *aRoot; /* Array of root page numbers of all btrees */ + int cnt = 0; /* Number of entries in aRoot[] */ + int mxIdx = 0; /* Maximum number of indexes for any table */ if( OMIT_TEMPDB && i==1 ) continue; if( iDb>=0 && i!=iDb ) continue; sqlite3CodeVerifySchema(pParse, i); - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */ - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeJumpHere(v, addr); /* Do an integrity check of the B-Tree ** - ** Begin by filling registers 2, 3, ... with the root pages numbers + ** Begin by finding the root pages numbers ** for all tables and indices in the database. */ assert( sqlite3SchemaMutexHeld(db, i, 0) ); pTbls = &db->aDb[i].pSchema->tblHash; - for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + Table *pTab = sqliteHashData(x); /* Current table */ + Index *pIdx; /* An index on pTab */ + int nIdx; /* Number of indexes on pTab */ + if( HasRowid(pTab) ) cnt++; + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } + if( nIdx>mxIdx ) mxIdx = nIdx; + } + aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); + if( aRoot==0 ) break; + for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; - if( HasRowid(pTab) ){ - sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt); - VdbeComment((v, "%s", pTab->zName)); - cnt++; - } + if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt); - VdbeComment((v, "%s", pIdx->zName)); - cnt++; + aRoot[++cnt] = pIdx->tnum; } } + aRoot[0] = cnt; /* Make sure sufficient number of registers have been allocated */ - pParse->nMem = MAX( pParse->nMem, cnt+8 ); + pParse->nMem = MAX( pParse->nMem, 8+mxIdx ); + sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ - sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1); + sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, - sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), + sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); - sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); + sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3); + integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. */ - for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){ + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; Index *pPrior = 0; @@ -108301,115 +115846,156 @@ SQLITE_PRIVATE void sqlite3Pragma( int iDataCur, iIdxCur; int r1 = -1; - if( pTab->pIndex==0 ) continue; + if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */ - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeJumpHere(v, addr); sqlite3ExprCacheClear(pParse); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); + /* reg[7] counts the number of entries in the table. + ** reg[8+i] counts the number of entries in the i-th index + */ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */ } - pParse->nMem = MAX(pParse->nMem, 8+j); + assert( pParse->nMem>=8+j ); + assert( sqlite3NoTempsInRange(pParse,1,7+j) ); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); /* Verify that all NOT NULL columns really are NOT NULL */ for(j=0; jnCol; j++){ char *zErr; - int jmp2, jmp3; + int jmp2; if( j==pTab->iPKey ) continue; if( pTab->aCol[j].notNull==0 ) continue; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pTab->aCol[j].zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); - jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); - sqlite3VdbeAddOp0(v, OP_Halt); + integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, jmp2); - sqlite3VdbeJumpHere(v, jmp3); } - /* 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); - if( pPk==pIdx ) continue; - r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, - pPrior, r1); - pPrior = pIdx; - sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ - /* Verify that an index entry exists for the current table row */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, - pIdx->nColumn); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ - sqlite3VdbeLoadString(v, 3, "row "); - sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeLoadString(v, 4, " missing from index "); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); - jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); - sqlite3VdbeAddOp0(v, OP_Halt); - sqlite3VdbeJumpHere(v, jmp2); - /* For UNIQUE indexes, verify that only one entry exists with the - ** 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 jmp6; - int kk; - for(kk=0; kknKeyCol; kk++){ - int iCol = pIdx->aiColumn[kk]; - assert( iCol!=XN_ROWID && iColnCol ); - if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; - sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); - VdbeCoverage(v); + /* Verify CHECK constraints */ + 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); + char *zErr; + int k; + pParse->iSelfTab = iDataCur + 1; + sqlite3ExprCachePush(pParse); + for(k=pCheck->nExpr-1; k>0; k--){ + sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); } - jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); - sqlite3VdbeGoto(v, uniqOk); - sqlite3VdbeJumpHere(v, jmp6); - sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, - pIdx->nKeyCol); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ - sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); - sqlite3VdbeGoto(v, jmp5); - sqlite3VdbeResolveLabel(v, uniqOk); + sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, + SQLITE_JUMPIFNULL); + sqlite3VdbeResolveLabel(v, addrCkFault); + pParse->iSelfTab = 0; + zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", + pTab->zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v); + sqlite3VdbeResolveLabel(v, addrCkOk); + sqlite3ExprCachePop(pParse); + } + sqlite3ExprListDelete(db, pCheck); + } + if( !isQuick ){ /* Omit the remaining tests for quick_check */ + /* Sanity check on record header decoding */ + sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + /* 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); + if( pPk==pIdx ) continue; + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, + pPrior, r1); + pPrior = pIdx; + sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ + /* Verify that an index entry exists for the current table row */ + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, + pIdx->nColumn); VdbeCoverage(v); + sqlite3VdbeLoadString(v, 3, "row "); + sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); + sqlite3VdbeLoadString(v, 4, " missing from index "); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); + jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); + jmp4 = integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, jmp2); + /* For UNIQUE indexes, verify that only one entry exists with the + ** 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 jmp6; + int kk; + for(kk=0; kknKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol!=XN_ROWID && iColnCol ); + if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); + VdbeCoverage(v); + } + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); + sqlite3VdbeGoto(v, uniqOk); + sqlite3VdbeJumpHere(v, jmp6); + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, + pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); + sqlite3VdbeGoto(v, jmp5); + sqlite3VdbeResolveLabel(v, uniqOk); + } + sqlite3VdbeJumpHere(v, jmp4); + sqlite3ResolvePartIdxLabel(pParse, jmp3); } - sqlite3VdbeJumpHere(v, jmp4); - sqlite3ResolvePartIdxLabel(pParse, jmp3); } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); #ifndef SQLITE_OMIT_BTREECOUNT - sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); - for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - if( pPk==pIdx ) continue; - addr = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); - sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); - sqlite3VdbeLoadString(v, 3, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); - sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); + if( !isQuick ){ + sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( pPk==pIdx ) continue; + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); + addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, addr); + } } #endif /* SQLITE_OMIT_BTREECOUNT */ } } - addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); - sqlite3VdbeChangeP2(v, addr, -mxErr); - sqlite3VdbeJumpHere(v, addr+1); - sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); + { + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList endCode[] = { + { OP_AddImm, 1, 0, 0}, /* 0 */ + { OP_IfNotZero, 1, 4, 0}, /* 1 */ + { OP_String8, 0, 3, 0}, /* 2 */ + { OP_ResultRow, 3, 1, 0}, /* 3 */ + { OP_Halt, 0, 0, 0}, /* 4 */ + { OP_String8, 0, 3, 0}, /* 5 */ + { OP_Goto, 0, 3, 0}, /* 6 */ + }; + VdbeOp *aOp; + + aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); + if( aOp ){ + aOp[0].p2 = 1-mxErr; + aOp[2].p4type = P4_STATIC; + aOp[2].p4.z = "ok"; + aOp[5].p4type = P4_STATIC; + aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT); + } + sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2); + } } break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -108458,7 +116044,7 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 ); assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE ); assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE ); - returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName); + returnSingleText(v, encnames[ENC(pParse->db)].zName); }else{ /* "PRAGMA encoding = XXX" */ /* Only change the value of sqlite.enc if the database handle is not ** initialized. If the main database exists, the new sqlite.enc value @@ -108493,7 +116079,9 @@ SQLITE_PRIVATE void sqlite3Pragma( ** PRAGMA [schema.]user_version ** PRAGMA [schema.]user_version = ** - ** PRAGMA [schema.]freelist_count = + ** PRAGMA [schema.]freelist_count + ** + ** PRAGMA [schema.]data_version ** ** PRAGMA [schema.]application_id ** PRAGMA [schema.]application_id = @@ -108519,18 +116107,20 @@ SQLITE_PRIVATE void sqlite3Pragma( case PragTyp_HEADER_VALUE: { int iCookie = pPragma->iArg; /* Which cookie to read or write */ sqlite3VdbeUsesBtree(v, iDb); - if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){ + if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ - { OP_Integer, 0, 1, 0}, /* 1 */ - { OP_SetCookie, 0, 0, 1}, /* 2 */ + { OP_SetCookie, 0, 0, 0}, /* 1 */ }; - int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); - sqlite3VdbeChangeP1(v, addr, iDb); - sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight)); - sqlite3VdbeChangeP1(v, addr+2, iDb); - sqlite3VdbeChangeP2(v, addr+2, iCookie); + VdbeOp *aOp; + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[1].p2 = iCookie; + aOp[1].p3 = sqlite3Atoi(zRight); }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { @@ -108538,12 +116128,14 @@ SQLITE_PRIVATE void sqlite3Pragma( { OP_ReadCookie, 0, 1, 0}, /* 1 */ { OP_ResultRow, 1, 1, 0} }; - int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0); - sqlite3VdbeChangeP1(v, addr, iDb); - sqlite3VdbeChangeP1(v, addr+1, iDb); - sqlite3VdbeChangeP3(v, addr+1, iCookie); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); + VdbeOp *aOp; + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[1].p3 = iCookie; + sqlite3VdbeReusable(v); } } break; @@ -108560,11 +116152,11 @@ SQLITE_PRIVATE void sqlite3Pragma( int i = 0; const char *zOpt; pParse->nMem = 1; - setOneColumnName(v, "compile_option"); while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){ sqlite3VdbeLoadString(v, 1, zOpt); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); } + sqlite3VdbeReusable(v); } break; #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ @@ -108576,7 +116168,6 @@ SQLITE_PRIVATE void sqlite3Pragma( ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { - static const char *azCol[] = { "busy", "log", "checkpointed" }; int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED); int eMode = SQLITE_CHECKPOINT_PASSIVE; if( zRight ){ @@ -108588,7 +116179,6 @@ SQLITE_PRIVATE void sqlite3Pragma( eMode = SQLITE_CHECKPOINT_TRUNCATE; } } - setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) ); pParse->nMem = 3; sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); @@ -108607,7 +116197,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( zRight ){ sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight)); } - returnSingleInt(v, "wal_autocheckpoint", + returnSingleInt(v, db->xWalCallback==sqlite3WalDefaultHook ? SQLITE_PTR_TO_INT(db->pWalArg) : 0); } @@ -108626,6 +116216,119 @@ SQLITE_PRIVATE void sqlite3Pragma( break; } + /* + ** PRAGMA optimize + ** PRAGMA optimize(MASK) + ** PRAGMA schema.optimize + ** PRAGMA schema.optimize(MASK) + ** + ** Attempt to optimize the database. All schemas are optimized in the first + ** two forms, and only the specified schema is optimized in the latter two. + ** + ** The details of optimizations performed by this pragma are expected + ** to change and improve over time. Applications should anticipate that + ** this pragma will perform new optimizations in future releases. + ** + ** The optional argument is a bitmask of optimizations to perform: + ** + ** 0x0001 Debugging mode. Do not actually perform any optimizations + ** but instead return one line of text for each optimization + ** that would have been done. Off by default. + ** + ** 0x0002 Run ANALYZE on tables that might benefit. On by default. + ** See below for additional information. + ** + ** 0x0004 (Not yet implemented) Record usage and performance + ** information from the current session in the + ** database file so that it will be available to "optimize" + ** pragmas run by future database connections. + ** + ** 0x0008 (Not yet implemented) Create indexes that might have + ** been helpful to recent queries + ** + ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all + ** of the optimizations listed above except Debug Mode, including new + ** optimizations that have not yet been invented. If new optimizations are + ** ever added that should be off by default, those off-by-default + ** optimizations will have bitmasks of 0x10000 or larger. + ** + ** DETERMINATION OF WHEN TO RUN ANALYZE + ** + ** In the current implementation, a table is analyzed if only if all of + ** the following are true: + ** + ** (1) MASK bit 0x02 is set. + ** + ** (2) The query planner used sqlite_stat1-style statistics for one or + ** more indexes of the table at some point during the lifetime of + ** the current connection. + ** + ** (3) One or more indexes of the table are currently unanalyzed OR + ** the number of rows in the table has increased by 25 times or more + ** since the last time ANALYZE was run. + ** + ** The rules for when tables are analyzed are likely to change in + ** future releases. + */ + case PragTyp_OPTIMIZE: { + int iDbLast; /* Loop termination point for the schema loop */ + int iTabCur; /* Cursor for a table whose size needs checking */ + HashElem *k; /* Loop over tables of a schema */ + Schema *pSchema; /* The current schema */ + Table *pTab; /* A table in the schema */ + Index *pIdx; /* An index of the table */ + LogEst szThreshold; /* Size threshold above which reanalysis is needd */ + char *zSubSql; /* SQL statement for the OP_SqlExec opcode */ + u32 opMask; /* Mask of operations to perform */ + + if( zRight ){ + opMask = (u32)sqlite3Atoi(zRight); + if( (opMask & 0x02)==0 ) break; + }else{ + opMask = 0xfffe; + } + iTabCur = pParse->nTab++; + for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ + if( iDb==1 ) continue; + sqlite3CodeVerifySchema(pParse, iDb); + pSchema = db->aDb[iDb].pSchema; + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + + /* If table pTab has not been used in a way that would benefit from + ** having analysis statistics during the current session, then skip it. + ** This also has the effect of skipping virtual tables and views */ + if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue; + + /* Reanalyze if the table is 25 times larger than the last analysis */ + szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( !pIdx->hasStat1 ){ + szThreshold = 0; /* Always analyze if any index lacks statistics */ + break; + } + } + if( szThreshold ){ + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, + sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold); + VdbeCoverage(v); + } + zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", + db->aDb[iDb].zDbSName, pTab->zName); + if( opMask & 0x01 ){ + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1); + }else{ + sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); + } + } + } + sqlite3VdbeAddOp0(v, OP_Expire); + break; + } + /* ** PRAGMA busy_timeout ** PRAGMA busy_timeout = N @@ -108640,7 +116343,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( zRight ){ sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); } - returnSingleInt(v, "timeout", db->busyTimeout); + returnSingleInt(v, db->busyTimeout); break; } @@ -108660,7 +116363,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } - returnSingleInt(v, "soft_heap_limit", sqlite3_soft_heap_limit64(-1)); + returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); break; } @@ -108679,8 +116382,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ){ sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); } - returnSingleInt(v, "threads", - sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); + returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); break; } @@ -108692,24 +116394,21 @@ SQLITE_PRIVATE void sqlite3Pragma( static const char *const azLockName[] = { "unlocked", "shared", "reserved", "pending", "exclusive" }; - static const char *azCol[] = { "database", "status" }; int i; - setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) ); pParse->nMem = 2; for(i=0; inDb; i++){ Btree *pBt; const char *zState = "unknown"; int j; - if( db->aDb[i].zName==0 ) continue; + if( db->aDb[i].zDbSName==0 ) continue; pBt = db->aDb[i].pBt; if( pBt==0 || sqlite3BtreePager(pBt)==0 ){ zState = "closed"; - }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, + }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ zState = azLockName[j]; } - sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); + sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); } break; } @@ -108760,10 +116459,329 @@ SQLITE_PRIVATE void sqlite3Pragma( } /* End of the PRAGMA switch */ + /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only + ** purpose is to execute assert() statements to verify that if the + ** PragFlg_NoColumns1 flag is set and the caller specified an argument + ** to the PRAGMA, the implementation has not added any OP_ResultRow + ** instructions to the VM. */ + if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){ + sqlite3VdbeVerifyNoResultRow(v); + } + pragma_out: sqlite3DbFree(db, zLeft); sqlite3DbFree(db, zRight); } +#ifndef SQLITE_OMIT_VIRTUALTABLE +/***************************************************************************** +** Implementation of an eponymous virtual table that runs a pragma. +** +*/ +typedef struct PragmaVtab PragmaVtab; +typedef struct PragmaVtabCursor PragmaVtabCursor; +struct PragmaVtab { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* The database connection to which it belongs */ + const PragmaName *pName; /* Name of the pragma */ + u8 nHidden; /* Number of hidden columns */ + u8 iHidden; /* Index of the first hidden column */ +}; +struct PragmaVtabCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + sqlite3_stmt *pPragma; /* The pragma statement to run */ + sqlite_int64 iRowid; /* Current rowid */ + char *azArg[2]; /* Value of the argument and schema */ +}; + +/* +** Pragma virtual table module xConnect method. +*/ +static int pragmaVtabConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + const PragmaName *pPragma = (const PragmaName*)pAux; + PragmaVtab *pTab = 0; + int rc; + int i, j; + char cSep = '('; + StrAccum acc; + char zBuf[200]; + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x"); + for(i=0, j=pPragma->iPragCName; inPragCName; i++, j++){ + sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]); + cSep = ','; + } + if( i==0 ){ + sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName); + cSep = ','; + i++; + } + j = 0; + if( pPragma->mPragFlg & PragFlg_Result1 ){ + sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN"); + j++; + } + if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){ + sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN"); + j++; + } + sqlite3StrAccumAppend(&acc, ")", 1); + sqlite3StrAccumFinish(&acc); + assert( strlen(zBuf) < sizeof(zBuf)-1 ); + rc = sqlite3_declare_vtab(db, zBuf); + if( rc==SQLITE_OK ){ + pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab)); + if( pTab==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pTab, 0, sizeof(PragmaVtab)); + pTab->pName = pPragma; + pTab->db = db; + pTab->iHidden = i; + pTab->nHidden = j; + } + }else{ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** Pragma virtual table module xDisconnect method. +*/ +static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){ + PragmaVtab *pTab = (PragmaVtab*)pVtab; + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* Figure out the best index to use to search a pragma virtual table. +** +** There are not really any index choices. But we want to encourage the +** query planner to give == constraints on as many hidden parameters as +** possible, and especially on the first hidden parameter. So return a +** high cost if hidden parameters are unconstrained. +*/ +static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + PragmaVtab *pTab = (PragmaVtab*)tab; + const struct sqlite3_index_constraint *pConstraint; + int i, j; + int seen[2]; + + pIdxInfo->estimatedCost = (double)1; + if( pTab->nHidden==0 ){ return SQLITE_OK; } + pConstraint = pIdxInfo->aConstraint; + seen[0] = 0; + seen[1] = 0; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->usable==0 ) continue; + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + if( pConstraint->iColumn < pTab->iHidden ) continue; + j = pConstraint->iColumn - pTab->iHidden; + assert( j < 2 ); + seen[j] = i+1; + } + if( seen[0]==0 ){ + pIdxInfo->estimatedCost = (double)2147483647; + pIdxInfo->estimatedRows = 2147483647; + return SQLITE_OK; + } + j = seen[0]-1; + pIdxInfo->aConstraintUsage[j].argvIndex = 1; + pIdxInfo->aConstraintUsage[j].omit = 1; + if( seen[1]==0 ) return SQLITE_OK; + pIdxInfo->estimatedCost = (double)20; + pIdxInfo->estimatedRows = 20; + j = seen[1]-1; + pIdxInfo->aConstraintUsage[j].argvIndex = 2; + pIdxInfo->aConstraintUsage[j].omit = 1; + return SQLITE_OK; +} + +/* Create a new cursor for the pragma virtual table */ +static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){ + PragmaVtabCursor *pCsr; + pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr)); + if( pCsr==0 ) return SQLITE_NOMEM; + memset(pCsr, 0, sizeof(PragmaVtabCursor)); + pCsr->base.pVtab = pVtab; + *ppCursor = &pCsr->base; + return SQLITE_OK; +} + +/* Clear all content from pragma virtual table cursor. */ +static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){ + int i; + sqlite3_finalize(pCsr->pPragma); + pCsr->pPragma = 0; + for(i=0; iazArg); i++){ + sqlite3_free(pCsr->azArg[i]); + pCsr->azArg[i] = 0; + } +} + +/* Close a pragma virtual table cursor */ +static int pragmaVtabClose(sqlite3_vtab_cursor *cur){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur; + pragmaVtabCursorClear(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* Advance the pragma virtual table cursor to the next row */ +static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + int rc = SQLITE_OK; + + /* Increment the xRowid value */ + pCsr->iRowid++; + assert( pCsr->pPragma ); + if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){ + rc = sqlite3_finalize(pCsr->pPragma); + pCsr->pPragma = 0; + pragmaVtabCursorClear(pCsr); + } + return rc; +} + +/* +** Pragma virtual table module xFilter method. +*/ +static int pragmaVtabFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab); + int rc; + int i, j; + StrAccum acc; + char *zSql; + + UNUSED_PARAMETER(idxNum); + UNUSED_PARAMETER(idxStr); + pragmaVtabCursorClear(pCsr); + j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1; + for(i=0; iazArg) ); + assert( pCsr->azArg[j]==0 ); + if( zText ){ + pCsr->azArg[j] = sqlite3_mprintf("%s", zText); + if( pCsr->azArg[j]==0 ){ + return SQLITE_NOMEM; + } + } + } + sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]); + sqlite3StrAccumAppendAll(&acc, "PRAGMA "); + if( pCsr->azArg[1] ){ + sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]); + } + sqlite3StrAccumAppendAll(&acc, pTab->pName->zName); + if( pCsr->azArg[0] ){ + sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]); + } + zSql = sqlite3StrAccumFinish(&acc); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0); + sqlite3_free(zSql); + if( rc!=SQLITE_OK ){ + pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); + return rc; + } + return pragmaVtabNext(pVtabCursor); +} + +/* +** Pragma virtual table module xEof method. +*/ +static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + return (pCsr->pPragma==0); +} + +/* The xColumn method simply returns the corresponding column from +** the PRAGMA. +*/ +static int pragmaVtabColumn( + sqlite3_vtab_cursor *pVtabCursor, + sqlite3_context *ctx, + int i +){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab); + if( iiHidden ){ + sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i)); + }else{ + sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT); + } + return SQLITE_OK; +} + +/* +** Pragma virtual table module xRowid method. +*/ +static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + *p = pCsr->iRowid; + return SQLITE_OK; +} + +/* The pragma virtual table object */ +static const sqlite3_module pragmaVtabModule = { + 0, /* iVersion */ + 0, /* xCreate - create a table */ + pragmaVtabConnect, /* xConnect - connect to an existing table */ + pragmaVtabBestIndex, /* xBestIndex - Determine search strategy */ + pragmaVtabDisconnect, /* xDisconnect - Disconnect from a table */ + 0, /* xDestroy - Drop a table */ + pragmaVtabOpen, /* xOpen - open a cursor */ + pragmaVtabClose, /* xClose - close a cursor */ + pragmaVtabFilter, /* xFilter - configure scan constraints */ + pragmaVtabNext, /* xNext - advance a cursor */ + pragmaVtabEof, /* xEof */ + pragmaVtabColumn, /* xColumn - read data */ + pragmaVtabRowid, /* xRowid - read data */ + 0, /* xUpdate - write data */ + 0, /* xBegin - begin transaction */ + 0, /* xSync - sync transaction */ + 0, /* xCommit - commit transaction */ + 0, /* xRollback - rollback transaction */ + 0, /* xFindFunction - function overloading */ + 0, /* xRename - rename the table */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ +}; + +/* +** Check to see if zTabName is really the name of a pragma. If it is, +** then register an eponymous virtual table for that pragma and return +** a pointer to the Module object for the new virtual table. +*/ +SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){ + const PragmaName *pName; + assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 ); + pName = pragmaLocate(zName+7); + if( pName==0 ) return 0; + if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0; + assert( sqlite3HashFind(&db->aModule, zName)==0 ); + return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0); +} + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_PRAGMA */ @@ -108796,16 +116814,15 @@ static void corruptSchema( const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; - if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){ + if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){ char *z; if( zObj==0 ) zObj = "?"; - z = sqlite3_mprintf("malformed database schema (%s)", zObj); - if( z && zExtra ) z = sqlite3_mprintf("%z - %s", z, zExtra); + z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); + if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); sqlite3DbFree(db, *pData->pzErrMsg); *pData->pzErrMsg = z; - if( z==0 ) db->mallocFailed = 1; } - pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT; + pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT; } /* @@ -108845,6 +116862,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char ** structures that describe the table, index, or view. */ int rc; + u8 saved_iDb = db->init.iDb; sqlite3_stmt *pStmt; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ @@ -108855,14 +116873,15 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); - db->init.iDb = 0; + db->init.iDb = saved_iDb; + assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ pData->rc = rc; if( rc==SQLITE_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ corruptSchema(pData, argv[0], sqlite3_errmsg(db)); } @@ -108879,7 +116898,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char ** to do here is record the root page number for that index. */ Index *pIndex; - pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName); + 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 @@ -108908,61 +116927,29 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ #ifndef SQLITE_OMIT_DEPRECATED int size; #endif - Table *pTab; Db *pDb; char const *azArg[4]; int meta[5]; InitData initData; - char const *zMasterSchema; - char const *zMasterName; + const char *zMasterName; int openedTransaction = 0; - /* - ** The master database table has a structure like this - */ - static const char master_schema[] = - "CREATE TABLE sqlite_master(\n" - " type text,\n" - " name text,\n" - " tbl_name text,\n" - " rootpage integer,\n" - " sql text\n" - ")" - ; -#ifndef SQLITE_OMIT_TEMPDB - static const char temp_master_schema[] = - "CREATE TEMP TABLE sqlite_temp_master(\n" - " type text,\n" - " name text,\n" - " tbl_name text,\n" - " rootpage integer,\n" - " sql text\n" - ")" - ; -#else - #define temp_master_schema 0 -#endif - assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); - /* zMasterSchema and zInitScript are set to point at the master schema - ** and initialisation script appropriate for the database being - ** initialized. zMasterName is the name of the master table. - */ - if( !OMIT_TEMPDB && iDb==1 ){ - zMasterSchema = temp_master_schema; - }else{ - zMasterSchema = master_schema; - } - zMasterName = SCHEMA_TABLE(iDb); + db->init.busy = 1; - /* Construct the schema tables. */ - azArg[0] = zMasterName; + /* Construct the in-memory representation schema tables (sqlite_master or + ** sqlite_temp_master) by invoking the parser directly. The appropriate + ** table name will be inserted automatically by the parser so we can just + ** use the abbreviation "x" here. The parser will also automatically tag + ** the schema table as read-only. */ + azArg[0] = zMasterName = SCHEMA_TABLE(iDb); azArg[1] = "1"; - azArg[2] = zMasterSchema; + azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," + "rootpage int,sql text)"; azArg[3] = 0; initData.db = db; initData.iDb = iDb; @@ -108973,19 +116960,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = initData.rc; goto error_out; } - pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); - if( ALWAYS(pTab) ){ - pTab->tabFlags |= TF_Readonly; - } /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ - if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){ - DbSetProperty(db, 1, DB_SchemaLoaded); - } - return SQLITE_OK; + assert( iDb==1 ); + DbSetProperty(db, 1, DB_SchemaLoaded); + rc = SQLITE_OK; + goto error_out; } /* If there is not already a read-only (or read-write) transaction opened @@ -109095,8 +117078,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ { char *zSql; zSql = sqlite3MPrintf(db, - "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid", - db->aDb[iDb].zName, zMasterName); + "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", + db->aDb[iDb].zDbSName, zMasterName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; @@ -109117,11 +117100,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ #endif } if( db->mallocFailed ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } - if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ - /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider + if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){ + /* Black magic: If the SQLITE_WriteSchema 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 @@ -109144,9 +117127,13 @@ initone_error_out: sqlite3BtreeLeave(pDb->pBt); error_out: - if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ - db->mallocFailed = 1; + if( rc ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + } + sqlite3ResetOneSchema(db, iDb); } + db->init.busy = 0; return rc; } @@ -109162,42 +117149,29 @@ error_out: */ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int i, rc; - int commit_internal = !(db->flags&SQLITE_InternChanges); + int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); - rc = SQLITE_OK; - db->init.busy = 1; ENC(db) = SCHEMA_ENC(db); - for(i=0; rc==SQLITE_OK && inDb; i++){ - if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; - rc = sqlite3InitOne(db, i, pzErrMsg); - if( rc ){ - sqlite3ResetOneSchema(db, i); + assert( db->nDb>0 ); + /* Do the main schema first */ + if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, 0, pzErrMsg); + if( rc ) return rc; + } + /* All other schemas after the main schema. The "temp" schema must be last */ + for(i=db->nDb-1; i>0; i--){ + if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, i, pzErrMsg); + if( rc ) return rc; } } - - /* Once all the other databases have been initialized, load the schema - ** for the TEMP database. This is loaded last, as the TEMP database - ** schema may contain references to objects in other databases. - */ -#ifndef SQLITE_OMIT_TEMPDB - assert( db->nDb>1 ); - if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, 1, pzErrMsg); - if( rc ){ - sqlite3ResetOneSchema(db, 1); - } - } -#endif - - db->init.busy = 0; - if( rc==SQLITE_OK && commit_internal ){ + if( commit_internal ){ sqlite3CommitInternalChanges(db); } - - return rc; + return SQLITE_OK; } /* @@ -109243,7 +117217,7 @@ static void schemaIsValid(Parse *pParse){ if( !sqlite3BtreeIsInReadTrans(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } if( rc!=SQLITE_OK ) return; openedTransaction = 1; @@ -109302,11 +117276,14 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ ** Free all memory allocations in the pParse object */ SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){ - if( pParse ){ - sqlite3 *db = pParse->db; - sqlite3DbFree(db, pParse->aLabel); - sqlite3ExprListDelete(db, pParse->pConstExpr); + sqlite3 *db = pParse->db; + sqlite3DbFree(db, pParse->aLabel); + sqlite3ExprListDelete(db, pParse->pConstExpr); + if( db ){ + assert( db->lookaside.bDisable >= pParse->disableLookaside ); + db->lookaside.bDisable -= pParse->disableLookaside; } + pParse->disableLookaside = 0; } /* @@ -109316,27 +117293,31 @@ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ - Parse *pParse; /* Parsing context */ char *zErrMsg = 0; /* Error message */ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ + Parse sParse; /* Parsing context */ - /* Allocate the parsing context */ - pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); - if( pParse==0 ){ - rc = SQLITE_NOMEM; - goto end_prepare; - } - pParse->pReprepare = pReprepare; + memset(&sParse, 0, PARSE_HDR_SZ); + memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); + sParse.pReprepare = pReprepare; assert( ppStmt && *ppStmt==0 ); - assert( !db->mallocFailed ); + /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ assert( sqlite3_mutex_held(db->mutex) ); + /* For a long-term use prepared statement avoid the use of + ** lookaside memory. + */ + if( prepFlags & SQLITE_PREPARE_PERSISTENT ){ + sParse.disableLookaside++; + db->lookaside.bDisable++; + } + /* 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 ** some other database connection is holding a write-lock, which in @@ -109366,9 +117347,9 @@ static int sqlite3Prepare( assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ - const char *zDb = db->aDb[i].zName; + const char *zDb = db->aDb[i].zDbSName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); - testcase( db->flags & SQLITE_ReadUncommitted ); + testcase( db->flags & SQLITE_ReadUncommit ); goto end_prepare; } } @@ -109376,8 +117357,7 @@ static int sqlite3Prepare( sqlite3VtabUnlockList(db); - pParse->db = db; - pParse->nQueryLoop = 0; /* Logarithmic, so 0 really means 1 */ + sParse.db = db; if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -109390,64 +117370,60 @@ static int sqlite3Prepare( } zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ - sqlite3RunParser(pParse, zSqlCopy, &zErrMsg); + sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); + sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sqlite3DbFree(db, zSqlCopy); - pParse->zTail = &zSql[pParse->zTail-zSqlCopy]; }else{ - pParse->zTail = &zSql[nBytes]; + sParse.zTail = &zSql[nBytes]; } }else{ - sqlite3RunParser(pParse, zSql, &zErrMsg); + sqlite3RunParser(&sParse, zSql, &zErrMsg); } - assert( 0==pParse->nQueryLoop ); + assert( 0==sParse.nQueryLoop ); - if( db->mallocFailed ){ - pParse->rc = SQLITE_NOMEM; - } - if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK; - if( pParse->checkSchema ){ - schemaIsValid(pParse); + if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; + if( sParse.checkSchema ){ + schemaIsValid(&sParse); } if( db->mallocFailed ){ - pParse->rc = SQLITE_NOMEM; + sParse.rc = SQLITE_NOMEM_BKPT; } if( pzTail ){ - *pzTail = pParse->zTail; + *pzTail = sParse.zTail; } - rc = pParse->rc; + rc = sParse.rc; #ifndef SQLITE_OMIT_EXPLAIN - if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){ + if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ static const char * const azColName[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", "selectid", "order", "from", "detail" }; int iFirst, mx; - if( pParse->explain==2 ){ - sqlite3VdbeSetNumCols(pParse->pVdbe, 4); + if( sParse.explain==2 ){ + sqlite3VdbeSetNumCols(sParse.pVdbe, 4); iFirst = 8; mx = 12; }else{ - sqlite3VdbeSetNumCols(pParse->pVdbe, 8); + sqlite3VdbeSetNumCols(sParse.pVdbe, 8); iFirst = 0; mx = 8; } for(i=iFirst; ipVdbe, i-iFirst, COLNAME_NAME, + sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME, azColName[i], SQLITE_STATIC); } } #endif if( db->init.busy==0 ){ - Vdbe *pVdbe = pParse->pVdbe; - sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag); + sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); } - if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ - sqlite3VdbeFinalize(pParse->pVdbe); + if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ + sqlite3VdbeFinalize(sParse.pVdbe); assert(!(*ppStmt)); }else{ - *ppStmt = (sqlite3_stmt*)pParse->pVdbe; + *ppStmt = (sqlite3_stmt*)sParse.pVdbe; } if( zErrMsg ){ @@ -109458,16 +117434,15 @@ static int sqlite3Prepare( } /* Delete any TriggerPrg structures allocated while parsing this statement. */ - while( pParse->pTriggerPrg ){ - TriggerPrg *pT = pParse->pTriggerPrg; - pParse->pTriggerPrg = pT->pNext; + while( sParse.pTriggerPrg ){ + TriggerPrg *pT = sParse.pTriggerPrg; + sParse.pTriggerPrg = pT->pNext; sqlite3DbFree(db, pT); } end_prepare: - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); + sqlite3ParserReset(&sParse); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); return rc; @@ -109476,7 +117451,7 @@ static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ @@ -109492,10 +117467,11 @@ static int sqlite3LockAndPrepare( } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); - rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); + rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); if( rc==SQLITE_SCHEMA ){ + sqlite3ResetOneSchema(db, -1); sqlite3_finalize(*ppStmt); - rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); + rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); @@ -109516,16 +117492,18 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ sqlite3_stmt *pNew; const char *zSql; sqlite3 *db; + u8 prepFlags; assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3_sql((sqlite3_stmt *)p); assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ db = sqlite3VdbeDb(p); assert( sqlite3_mutex_held(db->mutex) ); - rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0); + prepFlags = sqlite3VdbePrepareFlags(p); + rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0); if( rc ){ if( rc==SQLITE_NOMEM ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } assert( pNew==0 ); return rc; @@ -109548,7 +117526,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ ** and the statement is automatically recompiled if an schema change ** occurs. */ -SQLITE_API int SQLITE_STDCALL sqlite3_prepare( +SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ @@ -109560,7 +117538,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare( assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2( +SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ @@ -109568,8 +117546,36 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2( const char **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail); - assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works + ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags + ** parameter. + ** + ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */ + rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0, + ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); + return rc; +} +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from + ** sqlite3_prepare_v2() only in having the extra prepFlags parameter, + ** which is a bit array consisting of zero or more of the + ** SQLITE_PREPARE_* flags. + ** + ** Proof by comparison to the implementation of sqlite3_prepare_v2() + ** directly above. */ + rc = sqlite3LockAndPrepare(db,zSql,nBytes, + SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), + 0,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); return rc; } @@ -109582,7 +117588,7 @@ static int sqlite3Prepare16( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ @@ -109610,7 +117616,7 @@ static int sqlite3Prepare16( sqlite3_mutex_enter(db->mutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ - rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8); + rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8); } if( zTail8 && pzTail ){ @@ -109636,7 +117642,7 @@ static int sqlite3Prepare16( ** and the statement is automatically recompiled if an schema change ** occurs. */ -SQLITE_API int SQLITE_STDCALL sqlite3_prepare16( +SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ @@ -109648,7 +117654,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16( assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } -SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2( +SQLITE_API int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ @@ -109656,7 +117662,22 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2( const void **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail); + rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-16 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3Prepare16(db,zSql,nBytes, + SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), + ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } @@ -109723,6 +117744,7 @@ struct SortCtx { int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ + u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ @@ -109741,8 +117763,8 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pLimit); sqlite3ExprDelete(db, p->pOffset); - sqlite3WithDelete(db, p->pWith); - if( bFree ) sqlite3DbFree(db, p); + if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); + if( bFree ) sqlite3DbFreeNN(db, p); p = pPrior; bFree = 1; } @@ -109754,7 +117776,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ pDest->eDest = (u8)eDest; pDest->iSDParm = iParm; - pDest->affSdst = 0; + pDest->zAffSdst = 0; pDest->iSdst = 0; pDest->nSdst = 0; } @@ -109772,38 +117794,47 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ - u16 selFlags, /* Flag parameters, such as SF_Distinct */ + u32 selFlags, /* Flag parameters, such as SF_Distinct */ Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pOffset /* OFFSET value. NULL means no offset */ ){ Select *pNew; Select standin; - sqlite3 *db = pParse->db; - pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); + pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); if( pNew==0 ){ - assert( db->mallocFailed ); + assert( pParse->db->mallocFailed ); pNew = &standin; - memset(pNew, 0, sizeof(*pNew)); } if( pEList==0 ){ - pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0)); + pEList = sqlite3ExprListAppend(pParse, 0, + sqlite3Expr(pParse->db,TK_ASTERISK,0)); } pNew->pEList = pEList; - if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); + pNew->op = TK_SELECT; + pNew->selFlags = selFlags; + pNew->iLimit = 0; + pNew->iOffset = 0; +#if SELECTTRACE_ENABLED + pNew->zSelName[0] = 0; +#endif + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->nSelectRow = 0; + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; - pNew->selFlags = selFlags; - pNew->op = TK_SELECT; + pNew->pPrior = 0; + pNew->pNext = 0; pNew->pLimit = pLimit; pNew->pOffset = pOffset; - assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; - if( db->mallocFailed ) { - clearSelect(db, pNew, pNew!=&standin); + pNew->pWith = 0; + assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 + || pParse->db->mallocFailed!=0 ); + if( pParse->db->mallocFailed ) { + clearSelect(pParse->db, pNew, pNew!=&standin); pNew = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); @@ -109828,7 +117859,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){ ** Delete the given Select structure and all of its substructures. */ SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ - clearSelect(db, p, 1); + if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } /* @@ -109992,7 +118023,7 @@ static void addWhereTerm( pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft); pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); - pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0); + pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); @@ -110069,11 +118100,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; inSrc-1; i++, pRight++, pLeft++){ - Table *pLeftTab = pLeft->pTab; Table *pRightTab = pRight->pTab; int isOuter; - if( NEVER(pLeftTab==0 || pRightTab==0) ) continue; + if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; isOuter = (pRight->fg.jointype & JT_OUTER)!=0; /* When the NATURAL keyword is present, add WHERE clause terms for @@ -110179,7 +118209,7 @@ static void pushOntoSorter( int iLimit; /* LIMIT counter */ assert( bSeq==0 || bSeq==1 ); - assert( nData==1 || regData==regOrigData ); + assert( nData==1 || regData==regOrigData || regOrigData==0 ); if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); regBase = regData - nExpr - bSeq; @@ -110191,11 +118221,11 @@ static void pushOntoSorter( iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; pSort->labelDone = sqlite3VdbeMakeLabel(v); sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, - SQLITE_ECEL_DUP|SQLITE_ECEL_REF); + SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0)); if( bSeq ){ sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); } - if( nPrefixReg==0 ){ + if( nPrefixReg==0 && nData>0 ){ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); @@ -110221,11 +118251,11 @@ static void pushOntoSorter( if( pParse->db->mallocFailed ) return; pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; - memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ + memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); - testcase( pKI->nXField>2 ); + testcase( pKI->nAllField > pKI->nKeyField+2 ); pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, - pKI->nXField-1); + pKI->nAllField-pKI->nKeyField-1); addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); pSort->labelBkOut = sqlite3VdbeMakeLabel(v); @@ -110245,12 +118275,34 @@ static void pushOntoSorter( }else{ op = OP_IdxInsert; } - sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); + sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, + regBase+nOBSat, nBase-nOBSat); if( iLimit ){ int addr; - addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); + int r1 = 0; + /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit + ** register is initialized with value of LIMIT+OFFSET.) After the sorter + ** fills up, delete the least entry in the sorter after each insert. + ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ + addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + r1 = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); + VdbeComment((v, "seq")); + } sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + /* If the inner loop is driven by an index such that values from + ** the same iteration of the inner loop are in sorted order, then + ** immediately jump to the next iteration of an inner loop if the + ** entry from the current iteration does not fit into the top + ** LIMIT+OFFSET entries of the sorter. */ + int iBrk = sqlite3VdbeCurrentAddr(v) + 2; + sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } sqlite3VdbeJumpHere(v, addr); } } @@ -110292,48 +118344,24 @@ static void codeDistinct( r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, r1); } -#ifndef SQLITE_OMIT_SUBQUERY -/* -** Generate an error message when a SELECT is used within a subexpression -** (example: "a IN (SELECT * FROM table)") but it has more than 1 result -** column. We do this in a subroutine because the error used to occur -** in multiple places. (The error only occurs in one place now, but we -** retain the subroutine to minimize code disruption.) -*/ -static int checkForMultiColumnSelectError( - Parse *pParse, /* Parse context. */ - SelectDest *pDest, /* Destination of SELECT results */ - int nExpr /* Number of result columns returned by SELECT */ -){ - int eDest = pDest->eDest; - if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){ - sqlite3ErrorMsg(pParse, "only a single result allowed for " - "a SELECT that is part of an expression"); - return 1; - }else{ - return 0; - } -} -#endif - /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** -** If srcTab is negative, then the pEList expressions +** If srcTab is negative, then the p->pEList expressions ** are evaluated in order to get the data for this row. If srcTab is -** zero or more, then data is pulled from srcTab and pEList is used only -** to get number columns and the datatype for each column. +** zero or more, then data is pulled from srcTab and p->pEList is used only +** to get the number of columns and the collation sequence for each column. */ static void selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ - ExprList *pEList, /* List of values being extracted */ - int srcTab, /* Pull data from this table */ + int srcTab, /* Pull data from this table if non-negative */ SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ @@ -110342,15 +118370,22 @@ static void selectInnerLoop( ){ Vdbe *v = pParse->pVdbe; int i; - int hasDistinct; /* True if the DISTINCT keyword is present */ - int regResult; /* Start of memory holding result set */ + int hasDistinct; /* True if the DISTINCT keyword is present */ int eDest = pDest->eDest; /* How to dispose of results */ int iParm = pDest->iSDParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ int nPrefixReg = 0; /* Number of extra registers before regResult */ + /* Usually, regResult is the first cell in an array of memory cells + ** containing the current result row. In this case regOrig is set to the + ** same value. However, if the results are being sent to the sorter, the + ** values for any expressions that are also part of the sort-key are omitted + ** from this array. In this case regOrig is set to zero. */ + int regResult; /* Start of memory holding current results */ + int regOrig; /* Start of memory holding full result (or 0) */ + assert( v ); - assert( pEList!=0 ); + assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; if( pSort==0 && !hasDistinct ){ @@ -110360,7 +118395,7 @@ static void selectInnerLoop( /* Pull the requested columns. */ - nResultCol = pEList->nExpr; + nResultCol = p->pEList->nExpr; if( pDest->iSdst==0 ){ if( pSort ){ @@ -110379,11 +118414,11 @@ static void selectInnerLoop( pParse->nMem += nResultCol; } pDest->nSdst = nResultCol; - regResult = pDest->iSdst; + regOrig = regResult = pDest->iSdst; if( srcTab>=0 ){ for(i=0; ia[i].zName)); + VdbeComment((v, "%s", p->pEList->a[i].zName)); } }else if( eDest!=SRT_Exists ){ /* If the destination is an EXISTS(...) expression, the actual @@ -110395,7 +118430,26 @@ static void selectInnerLoop( }else{ ecelFlags = 0; } - sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags); + if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){ + /* For each expression in p->pEList that is a copy of an expression in + ** the ORDER BY clause (pSort->pOrderBy), set the associated + ** iOrderByCol value to one more than the index of the ORDER BY + ** expression within the sort-key that pushOntoSorter() will generate. + ** This allows the p->pEList field to be omitted from the sorted record, + ** saving space and CPU cycles. */ + ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF); + for(i=pSort->nOBSat; ipOrderBy->nExpr; i++){ + int j; + if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){ + p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; + } + } + regOrig = 0; + assert( eDest==SRT_Set || eDest==SRT_Mem + || eDest==SRT_Coroutine || eDest==SRT_Output ); + } + nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult, + 0,ecelFlags); } /* If the DISTINCT keyword was present on the SELECT statement @@ -110427,7 +118481,7 @@ static void selectInnerLoop( iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for(i=0; ia[i].pExpr); + CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr); if( iaffSdst = - sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); if( pSort ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg); + pushOntoSorter( + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); - sqlite3ExprCacheAffinityChange(pParse, regResult, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); + assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, + r1, pDest->zAffSdst, nResultCol); + sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; @@ -110557,14 +118611,16 @@ static void selectInnerLoop( } /* If this is a scalar select that is part of an expression, then - ** store the results in the appropriate memory cell and break out - ** of the scan loop. + ** store the results in the appropriate memory cell or array of + ** memory cells and break out of the scan loop. */ case SRT_Mem: { - assert( nResultCol==1 ); if( pSort ){ - pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg); + assert( nResultCol<=pDest->nSdst ); + pushOntoSorter( + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ + assert( nResultCol==pDest->nSdst ); assert( regResult==iParm ); /* The LIMIT clause will jump out of the loop for us */ } @@ -110577,7 +118633,7 @@ static void selectInnerLoop( testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); if( pSort ){ - pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol, + pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); @@ -110627,7 +118683,7 @@ static void selectInnerLoop( } sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey); sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2); if( addrTest ) sqlite3VdbeJumpHere(v, addrTest); sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempRange(pParse, r2, nKey+2); @@ -110664,17 +118720,18 @@ static void selectInnerLoop( ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ - KeyInfo *p = sqlite3DbMallocZero(0, - sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1)); + int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); + KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortOrder = (u8*)&p->aColl[N+X]; - p->nField = (u16)N; - p->nXField = (u16)X; + p->nKeyField = (u16)N; + p->nAllField = (u16)(N+X); p->enc = ENC(db); p->db = db; p->nRef = 1; + memset(&p[1], 0, nExtra); }else{ - db->mallocFailed = 1; + sqlite3OomFault(db); } return p; } @@ -110686,7 +118743,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; - if( p->nRef==0 ) sqlite3DbFree(0, p); + if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p); } } @@ -110742,10 +118799,7 @@ static KeyInfo *keyInfoFromExprList( if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; ipExpr); - if( !pColl ) pColl = db->pDfltColl; - pInfo->aColl[i-iStart] = pColl; + pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); pInfo->aSortOrder[i-iStart] = pItem->sortOrder; } } @@ -110861,14 +118915,13 @@ static void generateSortTail( int iParm = pDest->iSDParm; int regRow; int regRowid; + int iCol; int nKey; int iSortTab; /* Sorter cursor to read from */ int nSortData; /* Trailing values to read from sorter */ int i; int bSeq; /* True if sorter record includes seq. no. */ -#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS struct ExprList_item *aOutEx = p->pEList->a; -#endif assert( addrBreak<0 ); if( pSort->labelBkOut ){ @@ -110877,21 +118930,21 @@ static void generateSortTail( sqlite3VdbeResolveLabel(v, pSort->labelBkOut); } iTab = pSort->iECursor; - if( eDest==SRT_Output || eDest==SRT_Coroutine ){ + if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ regRowid = 0; regRow = pDest->iSdst; nSortData = nColumn; }else{ regRowid = sqlite3GetTempReg(pParse); - regRow = sqlite3GetTempReg(pParse); - nSortData = 1; + regRow = sqlite3GetTempRange(pParse, nColumn); + nSortData = nColumn; } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; iSortTab = pParse->nTab++; if( pSort->labelBkOut ){ - addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); @@ -110906,11 +118959,18 @@ static void generateSortTail( iSortTab = iTab; bSeq = 1; } - for(i=0; iaffSdst, 1); - sqlite3ExprCacheAffinityChange(pParse, regRow, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid); + assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, + pDest->zAffSdst, nColumn); + sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); break; } case SRT_Mem: { - assert( nColumn==1 ); - sqlite3ExprCodeMove(pParse, regRow, iParm, 1); /* The LIMIT clause will terminate the loop for us */ break; } @@ -110947,7 +119005,11 @@ static void generateSortTail( } } if( regRowid ){ - sqlite3ReleaseTempReg(pParse, regRow); + if( eDest==SRT_Set ){ + sqlite3ReleaseTempRange(pParse, regRow, nColumn); + }else{ + sqlite3ReleaseTempReg(pParse, regRow); + } sqlite3ReleaseTempReg(pParse, regRowid); } /* The bottom of the loop @@ -110987,23 +119049,23 @@ static void generateSortTail( ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used. */ #ifdef SQLITE_ENABLE_COLUMN_METADATA -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F) +# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E) #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F) +# define columnType(A,B,C,D,E) columnTypeImpl(A,B) #endif static const char *columnTypeImpl( NameContext *pNC, +#ifndef SQLITE_ENABLE_COLUMN_METADATA + Expr *pExpr +#else Expr *pExpr, -#ifdef SQLITE_ENABLE_COLUMN_METADATA const char **pzOrigDb, const char **pzOrigTab, - const char **pzOrigCol, + const char **pzOrigCol #endif - u8 *pEstWidth ){ char const *zType = 0; int j; - u8 estWidth = 1; #ifdef SQLITE_ENABLE_COLUMN_METADATA char const *zOrigDb = 0; char const *zOrigTab = 0; @@ -111062,46 +119124,42 @@ static const char *columnTypeImpl( ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ - if( iCol>=0 && ALWAYS(iColpEList->nExpr) ){ + if( iCol>=0 && iColpEList->nExpr ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. - ** - ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been - ** caught already by name resolution. */ NameContext sNC; Expr *p = pS->pEList->a[iCol].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; - zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth); + zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol); } - }else if( pTab->pSchema ){ - /* A real table */ + }else{ + /* A real table or a CTE table */ assert( !pS ); - if( iCol<0 ) iCol = pTab->iPKey; - assert( iCol==-1 || (iCol>=0 && iColnCol) ); #ifdef SQLITE_ENABLE_COLUMN_METADATA + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==XN_ROWID || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; zOrigCol = "rowid"; }else{ - zType = pTab->aCol[iCol].zType; zOrigCol = pTab->aCol[iCol].zName; - estWidth = pTab->aCol[iCol].szEst; + zType = sqlite3ColumnType(&pTab->aCol[iCol],0); } zOrigTab = pTab->zName; - if( pNC->pParse ){ + if( pNC->pParse && pTab->pSchema ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); - zOrigDb = pNC->pParse->db->aDb[iDb].zName; + zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; } #else + assert( iCol==XN_ROWID || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; }else{ - zType = pTab->aCol[iCol].zType; - estWidth = pTab->aCol[iCol].szEst; + zType = sqlite3ColumnType(&pTab->aCol[iCol],0); } #endif } @@ -111120,7 +119178,7 @@ static const char *columnTypeImpl( sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; - zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth); + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); break; } #endif @@ -111134,7 +119192,6 @@ static const char *columnTypeImpl( *pzOrigCol = zOrigCol; } #endif - if( pEstWidth ) *pEstWidth = estWidth; return zType; } @@ -111153,6 +119210,7 @@ static void generateColumnTypes( NameContext sNC; sNC.pSrcList = pTabList; sNC.pParse = pParse; + sNC.pNext = 0; for(i=0; inExpr; i++){ Expr *p = pEList->a[i].pExpr; const char *zType; @@ -111160,7 +119218,7 @@ static void generateColumnTypes( const char *zOrigDb = 0; const char *zOrigTab = 0; const char *zOrigCol = 0; - zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0); + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); /* The vdbe must make its own copy of the column-type and other ** column specific strings, in case the schema is reset before this @@ -111170,27 +119228,56 @@ static void generateColumnTypes( sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT); sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT); #else - zType = columnType(&sNC, p, 0, 0, 0, 0); + zType = columnType(&sNC, p, 0, 0, 0); #endif sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT); } #endif /* !defined(SQLITE_OMIT_DECLTYPE) */ } + /* -** Generate code that will tell the VDBE the names of columns -** in the result set. This information is used to provide the -** azCol[] values in the callback. +** Compute the column names for a SELECT statement. +** +** The only guarantee that SQLite makes about column names is that if the +** column has an AS clause assigning it a name, that will be the name used. +** That is the only documented guarantee. However, countless applications +** developed over the years have made baseless assumptions about column names +** and will break if those assumptions changes. Hence, use extreme caution +** when modifying this routine to avoid breaking legacy. +** +** See Also: sqlite3ColumnsFromExprList() +** +** The PRAGMA short_column_names and PRAGMA full_column_names settings are +** deprecated. The default setting is short=ON, full=OFF. 99.9% of all +** applications should operate this way. Nevertheless, we need to support the +** other modes for legacy: +** +** short=OFF, full=OFF: Column name is the text of the expression has it +** originally appears in the SELECT statement. In +** other words, the zSpan of the result expression. +** +** short=ON, full=OFF: (This is the default setting). If the result +** refers directly to a table column, then the +** result column name is just the table column +** name: COLUMN. Otherwise use zSpan. +** +** full=ON, short=ANY: If the result refers directly to a table column, +** then the result column name with the table name +** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ static void generateColumnNames( Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ + Select *pSelect /* Generate column names for this SELECT statement */ ){ Vdbe *v = pParse->pVdbe; - int i, j; + int i; + Table *pTab; + SrcList *pTabList; + ExprList *pEList; sqlite3 *db = pParse->db; - int fullNames, shortNames; + int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */ + int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */ #ifndef SQLITE_OMIT_EXPLAIN /* If this is an EXPLAIN, skip this step */ @@ -111200,28 +119287,31 @@ static void generateColumnNames( #endif if( pParse->colNamesSet || db->mallocFailed ) return; + /* Column names are determined by the left-most term of a compound select */ + while( pSelect->pPrior ) pSelect = pSelect->pPrior; + pTabList = pSelect->pSrc; + pEList = pSelect->pEList; assert( v!=0 ); assert( pTabList!=0 ); pParse->colNamesSet = 1; - fullNames = (db->flags & SQLITE_FullColNames)!=0; - shortNames = (db->flags & SQLITE_ShortColNames)!=0; + fullName = (db->flags & SQLITE_FullColNames)!=0; + srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; inExpr; i++){ - Expr *p; - p = pEList->a[i].pExpr; - if( NEVER(p==0) ) continue; + Expr *p = pEList->a[i].pExpr; + + 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 */ if( pEList->a[i].zName ){ + /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); - }else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){ - Table *pTab; + }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; - for(j=0; ALWAYS(jnSrc); j++){ - if( pTabList->a[j].iCursor==p->iTable ) break; - } - assert( jnSrc ); - pTab = pTabList->a[j].pTab; + pTab = p->pTab; + assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iColnCol) ); if( iCol<0 ){ @@ -111229,10 +119319,7 @@ static void generateColumnNames( }else{ zCol = pTab->aCol[iCol].zName; } - if( !shortNames && !fullNames ){ - sqlite3VdbeSetColName(v, i, COLNAME_NAME, - sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC); - }else if( fullNames ){ + if( fullName ){ char *zName = 0; zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol); sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); @@ -111260,6 +119347,15 @@ static void generateColumnNames( ** ** Return SQLITE_OK on success. If a memory allocation error occurs, ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. +** +** The only guarantee that SQLite makes about column names is that if the +** column has an AS clause assigning it a name, that will be the name used. +** That is the only documented guarantee. However, countless applications +** developed over the years have made baseless assumptions about column names +** and will break if those assumptions changes. Hence, use extreme caution +** when modifying this routine to avoid breaking legacy. +** +** See Also: generateColumnNames() */ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ @@ -111272,7 +119368,6 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( u32 cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ - Expr *p; /* Expression for a single result column */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ Hash ht; /* Hash table of column names */ @@ -111282,6 +119377,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); testcase( aCol==0 ); + if( nCol>32767 ) nCol = 32767; }else{ nCol = 0; aCol = 0; @@ -111293,20 +119389,20 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( for(i=0, pCol=aCol; imallocFailed; i++, pCol++){ /* Get an appropriate name for the column */ - p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS " phrase, use as the name */ }else{ - Expr *pColExpr = p; /* The expression that is the result column name */ - Table *pTab; /* Table associated with this expression */ + Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr); while( pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } - if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){ + if( (pColExpr->op==TK_COLUMN || pColExpr->op==TK_AGG_COLUMN) + && pColExpr->pTab!=0 + ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; - pTab = pColExpr->pTab; + Table *pTab = pColExpr->pTab; if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; }else if( pColExpr->op==TK_ID ){ @@ -111317,7 +119413,11 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( zName = pEList->a[i].zSpan; } } - zName = sqlite3MPrintf(db, "%s", zName); + if( zName ){ + zName = sqlite3DbStrDup(db, zName); + }else{ + zName = sqlite3MPrintf(db,"column%d",i+1); + } /* Make sure the column name is unique. If the name is not unique, ** append an integer to the name so that it becomes unique. @@ -111335,7 +119435,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( pCol->zName = zName; sqlite3ColumnPropertiesFromName(0, pCol); if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){ - db->mallocFailed = 1; + sqlite3OomFault(db); } } sqlite3HashClear(&ht); @@ -111346,7 +119446,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( sqlite3DbFree(db, aCol); *paCol = 0; *pnCol = 0; - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } return SQLITE_OK; } @@ -111362,7 +119462,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( ** This routine requires that all identifiers in the SELECT ** statement be resolved. */ -static void selectAddColumnTypeAndCollation( +SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ Select *pSelect /* SELECT used to determine types and collations */ @@ -111374,7 +119474,6 @@ static void selectAddColumnTypeAndCollation( int i; Expr *p; struct ExprList_item *a; - u64 szAll = 0; assert( pSelect!=0 ); assert( (pSelect->selFlags & SF_Resolved)!=0 ); @@ -111384,20 +119483,28 @@ static void selectAddColumnTypeAndCollation( sNC.pSrcList = pSelect->pSrc; a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ + const char *zType; + int n, m; p = a[i].pExpr; - if( pCol->zType==0 ){ - pCol->zType = sqlite3DbStrDup(db, - columnType(&sNC, p,0,0,0, &pCol->szEst)); - } - szAll += pCol->szEst; + zType = columnType(&sNC, p, 0, 0, 0); + /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); + if( zType ){ + m = sqlite3Strlen30(zType); + n = sqlite3Strlen30(pCol->zName); + pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); + if( pCol->zName ){ + memcpy(&pCol->zName[n+1], zType, m+1); + pCol->colFlags |= COLFLAG_HASTYPE; + } + } if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB; pColl = sqlite3ExprCollSeq(pParse, p); if( pColl && pCol->zColl==0 ){ pCol->zColl = sqlite3DbStrDup(db, pColl->zName); } } - pTab->szTabRow = sqlite3LogEst(szAll*4); + pTab->szTabRow = 1; /* Any non-zero value works */ } /* @@ -111422,12 +119529,12 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ } /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside ** is disabled */ - assert( db->lookaside.bEnabled==0 ); - pTab->nRef = 1; + assert( db->lookaside.bDisable ); + pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); - selectAddColumnTypeAndCollation(pParse, pTab, pSelect); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); @@ -111441,18 +119548,15 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ ** If an error occurs, return NULL and leave a message in pParse. */ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ - Vdbe *v = pParse->pVdbe; - if( v==0 ){ - v = pParse->pVdbe = sqlite3VdbeCreate(pParse); - if( v ) sqlite3VdbeAddOp0(v, OP_Init); - if( pParse->pToplevel==0 - && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) - ){ - pParse->okConstFactor = 1; - } - + if( pParse->pVdbe ){ + return pParse->pVdbe; } - return v; + if( pParse->pToplevel==0 + && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) + ){ + pParse->okConstFactor = 1; + } + return sqlite3VdbeCreate(pParse); } @@ -111503,8 +119607,9 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ VdbeComment((v, "LIMIT counter")); if( n==0 ){ sqlite3VdbeGoto(v, iBreak); - }else if( n>=0 && p->nSelectRow>(u64)n ){ - p->nSelectRow = n; + }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){ + p->nSelectRow = sqlite3LogEst((u64)n); + p->selFlags |= SF_FixedLimit; } }else{ sqlite3ExprCode(pParse, p->pLimit, iLimit); @@ -111518,10 +119623,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ sqlite3ExprCode(pParse, p->pOffset, iOffset); sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); VdbeComment((v, "OFFSET counter")); - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0); - sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1); + sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset); VdbeComment((v, "LIMIT+OFFSET")); - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1); } } } @@ -111655,6 +119758,7 @@ static void generateWithRecursiveQuery( /* Process the LIMIT and OFFSET clauses, if they exist */ addrBreak = sqlite3VdbeMakeLabel(v); + p->nSelectRow = 320; /* 4 billion rows */ computeLimitRegisters(pParse, p, addrBreak); pLimit = p->pLimit; pOffset = p->pOffset; @@ -111725,7 +119829,7 @@ static void generateWithRecursiveQuery( /* Output the single row in Current */ addrCont = sqlite3VdbeMakeLabel(v); codeOffset(v, regOffset, addrCont); - selectInnerLoop(pParse, p, p->pEList, iCurrent, + selectInnerLoop(pParse, p, iCurrent, 0, 0, pDest, addrCont, addrBreak); if( regLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); @@ -111863,15 +119967,9 @@ static int multiSelect( db = pParse->db; pPrior = p->pPrior; dest = *pDest; - if( pPrior->pOrderBy ){ - sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before", - selectOpName(p->op)); - rc = 1; - goto multi_select_end; - } - if( pPrior->pLimit ){ - sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before", - selectOpName(p->op)); + if( pPrior->pOrderBy || pPrior->pLimit ){ + sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", + pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op)); rc = 1; goto multi_select_end; } @@ -111884,7 +119982,6 @@ static int multiSelect( if( dest.eDest==SRT_EphemTab ){ assert( p->pEList ); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr); - sqlite3VdbeChangeP5(v, BTREE_UNORDERED); dest.eDest = SRT_Table; } @@ -111938,9 +120035,8 @@ static int multiSelect( addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); if( p->iOffset ){ - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0); - sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1); - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1); + sqlite3VdbeAddOp3(v, OP_OffsetLimit, + p->iLimit, p->iOffset+1, p->iOffset); } } explainSetInteger(iSub2, pParse->iNextSelectId); @@ -111948,12 +120044,12 @@ static int multiSelect( testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; - p->nSelectRow += pPrior->nSelectRow; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( pPrior->pLimit && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit) - && nLimit>0 && p->nSelectRow > (u64)nLimit + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ - p->nSelectRow = nLimit; + p->nSelectRow = sqlite3LogEst((u64)nLimit); } if( addr ){ sqlite3VdbeJumpHere(v, addr); @@ -112025,7 +120121,9 @@ static int multiSelect( pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; - if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow; + if( p->op==TK_UNION ){ + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; @@ -112039,17 +120137,12 @@ static int multiSelect( if( dest.eDest!=priorOp ){ int iCont, iBreak, iStart; assert( p->pEList ); - if( dest.eDest==SRT_Output ){ - Select *pFirst = p; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); - selectInnerLoop(pParse, p, p->pEList, unionTab, + selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); @@ -112114,20 +120207,15 @@ static int multiSelect( ** tables. */ assert( p->pEList ); - if( dest.eDest==SRT_Output ){ - Select *pFirst = p; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); r1 = sqlite3GetTempReg(pParse); - iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1); + iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r1); - selectInnerLoop(pParse, p, p->pEList, tab1, + selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); @@ -112160,7 +120248,7 @@ static int multiSelect( nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto multi_select_end; } for(i=0, apColl=pKeyInfo->aColl; inSdst==1 || pParse->nErr>0 ); - pDest->affSdst = - sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst); + testcase( pIn->nSdst>1 ); r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1); - sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, + r1, pDest->zAffSdst, pIn->nSdst); + sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, + pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); break; } @@ -112515,10 +120601,10 @@ static int multiSelectOrderBy( } if( j==nOrderBy ){ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); - if( pNew==0 ) return SQLITE_NOMEM; + if( pNew==0 ) return SQLITE_NOMEM_BKPT; pNew->flags |= EP_IntValue; pNew->u.iValue = i; - pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); + p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; } } @@ -112531,10 +120617,11 @@ static int multiSelectOrderBy( ** to the right and the left are evaluated, they use the correct ** collation. */ - aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy); + aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; - for(i=0, pItem=pOrderBy->a; ia; i<=nOrderBy; i++, pItem++){ assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; @@ -112612,7 +120699,7 @@ static int multiSelectOrderBy( pPrior->iLimit = regLimitA; explainSetInteger(iSub1, pParse->iNextSelectId); sqlite3Select(pParse, pPrior, &destA); - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA); + sqlite3VdbeEndCoroutine(v, regAddrA); sqlite3VdbeJumpHere(v, addr1); /* Generate a coroutine to evaluate the SELECT statement on @@ -112629,7 +120716,7 @@ static int multiSelectOrderBy( sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB); + sqlite3VdbeEndCoroutine(v, regAddrB); /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. @@ -112661,7 +120748,7 @@ static int multiSelectOrderBy( addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); VdbeCoverage(v); sqlite3VdbeGoto(v, addrEofA); - p->nSelectRow += pPrior->nSelectRow; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } /* Generate a subroutine to run when the results from select B @@ -112727,14 +120814,6 @@ static int multiSelectOrderBy( */ sqlite3VdbeResolveLabel(v, labelEnd); - /* Set the number of output columns - */ - if( pDest->eDest==SRT_Output ){ - Select *pFirst = pPrior; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } - /* Reassembly the compound query so that it will be freed correctly ** by the calling function */ if( p->pPrior ){ @@ -112751,9 +120830,24 @@ static int multiSelectOrderBy( #endif #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + +/* An instance of the SubstContext object describes an substitution edit +** to be performed on a parse tree. +** +** All references to columns in table iTable are to be replaced by corresponding +** expressions in pEList. +*/ +typedef struct SubstContext { + Parse *pParse; /* The parsing context */ + int iTable; /* Replace references to this table */ + int iNewTable; /* New table number */ + int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ + ExprList *pEList; /* Replacement expressions */ +} SubstContext; + /* Forward Declarations */ -static void substExprList(sqlite3*, ExprList*, int, ExprList*); -static void substSelect(sqlite3*, Select *, int, ExprList*, int); +static void substExprList(SubstContext*, ExprList*); +static void substSelect(SubstContext*, Select*, int); /* ** Scan through the expression pExpr. Replace every reference to @@ -112764,74 +120858,97 @@ static void substSelect(sqlite3*, Select *, int, ExprList*, int); ** This routine is part of the flattening procedure. A subquery ** whose result set is defined by pEList appears as entry in the ** FROM clause of a SELECT such that the VDBE cursor assigned to that -** FORM clause entry is iTable. This routine make the necessary +** FORM clause entry is iTable. This routine makes the necessary ** changes to pExpr so that it refers directly to the source table ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( - sqlite3 *db, /* Report malloc errors to this connection */ - Expr *pExpr, /* Expr in which substitution occurs */ - int iTable, /* Table to be substituted */ - ExprList *pEList /* Substitute expressions */ + SubstContext *pSubst, /* Description of the substitution */ + Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; - if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){ + if( ExprHasProperty(pExpr, EP_FromJoin) + && pExpr->iRightJoinTable==pSubst->iTable + ){ + pExpr->iRightJoinTable = pSubst->iNewTable; + } + if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){ if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; - assert( pEList!=0 && pExpr->iColumnnExpr ); + Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; + Expr ifNullRow; + assert( pSubst->pEList!=0 && pExpr->iColumnpEList->nExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 ); - pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0); - sqlite3ExprDelete(db, pExpr); - pExpr = pNew; + if( sqlite3ExprIsVector(pCopy) ){ + sqlite3VectorErrorMsg(pSubst->pParse, pCopy); + }else{ + sqlite3 *db = pSubst->pParse->db; + if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){ + memset(&ifNullRow, 0, sizeof(ifNullRow)); + ifNullRow.op = TK_IF_NULL_ROW; + ifNullRow.pLeft = pCopy; + ifNullRow.iTable = pSubst->iNewTable; + pCopy = &ifNullRow; + } + pNew = sqlite3ExprDup(db, pCopy, 0); + if( pNew && pSubst->isLeftJoin ){ + ExprSetProperty(pNew, EP_CanBeNull); + } + if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){ + pNew->iRightJoinTable = pExpr->iRightJoinTable; + ExprSetProperty(pNew, EP_FromJoin); + } + sqlite3ExprDelete(db, pExpr); + pExpr = pNew; + } } }else{ - pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList); - pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList); + if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){ + pExpr->iTable = pSubst->iNewTable; + } + pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); + pExpr->pRight = substExpr(pSubst, pExpr->pRight); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - substSelect(db, pExpr->x.pSelect, iTable, pEList, 1); + substSelect(pSubst, pExpr->x.pSelect, 1); }else{ - substExprList(db, pExpr->x.pList, iTable, pEList); + substExprList(pSubst, pExpr->x.pList); } } return pExpr; } static void substExprList( - sqlite3 *db, /* Report malloc errors here */ - ExprList *pList, /* List to scan and in which to make substitutes */ - int iTable, /* Table to be substituted */ - ExprList *pEList /* Substitute values */ + SubstContext *pSubst, /* Description of the substitution */ + ExprList *pList /* List to scan and in which to make substitutes */ ){ int i; if( pList==0 ) return; for(i=0; inExpr; i++){ - pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList); + pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr); } } static void substSelect( - sqlite3 *db, /* Report malloc errors here */ - Select *p, /* SELECT statement in which to make substitutions */ - int iTable, /* Table to be replaced */ - ExprList *pEList, /* Substitute values */ - int doPrior /* Do substitutes on p->pPrior too */ + SubstContext *pSubst, /* Description of the substitution */ + Select *p, /* SELECT statement in which to make substitutions */ + int doPrior /* Do substitutes on p->pPrior too */ ){ SrcList *pSrc; struct SrcList_item *pItem; int i; if( !p ) return; do{ - substExprList(db, p->pEList, iTable, pEList); - substExprList(db, p->pGroupBy, iTable, pEList); - substExprList(db, p->pOrderBy, iTable, pEList); - p->pHaving = substExpr(db, p->pHaving, iTable, pEList); - p->pWhere = substExpr(db, p->pWhere, iTable, pEList); + substExprList(pSubst, p->pEList); + substExprList(pSubst, p->pGroupBy); + substExprList(pSubst, p->pOrderBy); + p->pHaving = substExpr(pSubst, p->pHaving); + p->pWhere = substExpr(pSubst, p->pWhere); pSrc = p->pSrc; assert( pSrc!=0 ); for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - substSelect(db, pItem->pSelect, iTable, pEList, 1); + substSelect(pSubst, pItem->pSelect, 1); if( pItem->fg.isTabFunc ){ - substExprList(db, pItem->u1.pFuncArg, iTable, pEList); + substExprList(pSubst, pItem->u1.pFuncArg); } } }while( doPrior && (p = p->pPrior)!=0 ); @@ -112865,66 +120982,74 @@ static void substSelect( ** exist on the table t1, a complete scan of the data might be ** avoided. ** -** Flattening is only attempted if all of the following are true: +** Flattening is subject to the following constraints: ** -** (1) The subquery and the outer query do not both use aggregates. +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** The subquery and the outer query cannot both be aggregates. ** -** (2) The subquery is not an aggregate or (2a) the outer query is not a join -** and (2b) the outer query does not use subqueries other than the one -** FROM-clause subquery that is a candidate for flattening. (2b is -** due to ticket [2f7170d73bf9abf80] from 2015-02-09.) +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** (2) If the subquery is an aggregate then +** (2a) the outer query must not be a join and +** (2b) the outer query must not use subqueries +** other than the one FROM-clause subquery that is a candidate +** for flattening. (This is due to ticket [2f7170d73bf9abf80] +** from 2015-02-09.) ** -** (3) The subquery is not the right operand of a left outer join -** (Originally ticket #306. Strengthened by ticket #3300) +** (3) If the subquery is the right operand of a LEFT JOIN then +** (3a) the subquery may not be a join and +** (3b) the FROM clause of the subquery may not contain a virtual +** table and +** (3c) the outer query may not be an aggregate. ** -** (4) The subquery is not DISTINCT. +** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** -** (6) The subquery does not use aggregates or the outer query is not -** DISTINCT. +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** If the subquery is aggregate, the outer query may not be DISTINCT. ** -** (7) The subquery has a FROM clause. TODO: For subqueries without -** A FROM clause, consider adding a FROM close with the special +** (7) The subquery must have a FROM clause. TODO: For subqueries without +** A FROM clause, consider adding a FROM clause with the special ** table sqlite_once that consists of a single row containing a ** single NULL. ** -** (8) The subquery does not use LIMIT or the outer query is not a join. +** (8) If the subquery uses LIMIT then the outer query may not be a join. ** -** (9) The subquery does not use LIMIT or the outer query does not use -** aggregates. +** (9) If the subquery uses LIMIT then the outer query may not be aggregate. ** ** (**) Restriction (10) was removed from the code on 2005-02-05 but we ** accidently carried the comment forward until 2014-09-15. Original -** text: "The subquery does not use aggregates or the outer query -** does not use LIMIT." +** constraint: "If the subquery is aggregate then the outer query +** may not use LIMIT." ** -** (11) The subquery and the outer query do not both have ORDER BY clauses. +** (11) The subquery and the outer query may not both have ORDER BY clauses. ** ** (**) Not implemented. Subsumed into restriction (3). Was previously ** a separate restriction deriving from ticket #350. ** -** (13) The subquery and outer query do not both use LIMIT. +** (13) The subquery and outer query may not both use LIMIT. ** -** (14) The subquery does not use OFFSET. +** (14) The subquery may not use OFFSET. ** -** (15) The outer query is not part of a compound select or the -** subquery does not have a LIMIT clause. +** (15) If the outer query is part of a compound select, then the +** subquery may not use LIMIT. ** (See ticket #2339 and ticket [02a8e81d44]). ** -** (16) The outer query is not an aggregate or the subquery does -** not contain ORDER BY. (Ticket #2942) This used to not matter +** (16) If the outer query is aggregate, then the subquery may not +** use ORDER BY. (Ticket #2942) This used to not matter ** until we introduced the group_concat() function. ** -** (17) The sub-query is not a compound select, or it is a UNION ALL -** compound clause made up entirely of non-aggregate queries, and -** the parent query: -** -** * is not itself part of a compound select, -** * is not an aggregate or DISTINCT query, and -** * is not a join +** (17) If the subquery is a compound select, then +** (17a) all compound operators must be a UNION ALL, and +** (17b) no terms within the subquery compound may be aggregate +** or DISTINCT, and +** (17c) every term within the subquery compound must have a FROM clause +** (17d) the outer query may not be +** (17d1) aggregate, or +** (17d2) DISTINCT, or +** (17d3) a join. ** ** The parent and sub-query may contain WHERE clauses. Subject to ** rules (11), (13) and (14), they may also contain ORDER BY, @@ -112940,29 +121065,32 @@ static void substSelect( ** syntax error and return a detailed message. ** ** (18) If the sub-query is a compound select, then all terms of the -** ORDER by clause of the parent must be simple references to +** ORDER BY clause of the parent must be simple references to ** columns of the sub-query. ** -** (19) The subquery does not use LIMIT or the outer query does not +** (19) If the subquery uses LIMIT then the outer query may not ** have a WHERE clause. ** -** (20) If the sub-query is a compound select, then it must not use -** an ORDER BY clause. Ticket #3773. We could relax this constraint -** somewhat by saying that the terms of the ORDER BY clause must -** appear as unmodified result columns in the outer query. But we -** have other optimizations in mind to deal with that case. +** (**) Subsumed into (17d3). Was: If the sub-query is a compound select, +** then it must not use an ORDER BY clause - Ticket #3773. Because +** of (17d3), then only way to have a compound subquery is if it is +** the only term in the FROM clause of the outer query. But if the +** only term in the FROM clause has an ORDER BY, then it will be +** implemented as a co-routine and the flattener will never be called. ** -** (21) The subquery does not use LIMIT or the outer query is not +** (21) If the subquery uses LIMIT then the outer query may not be ** DISTINCT. (See ticket [752e1646fc]). ** -** (22) The subquery is not a recursive CTE. +** (22) The subquery may not be a recursive CTE. ** -** (23) The parent is not a recursive CTE, or the sub-query is not a -** compound query. This restriction is because transforming the +** (**) Subsumed into restriction (17d3). Was: If the outer query is +** a recursive CTE, then the sub-query may not be a compound query. +** This restriction is because transforming the ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** -** (24) The subquery is not an aggregate that uses the built-in min() or +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** The subquery may not be an aggregate that uses the built-in min() or ** or max() functions. (Without this restriction, a query like: ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily ** return the value X for which Y was maximal.) @@ -112970,7 +121098,7 @@ static void substSelect( ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query -** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. +** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. @@ -112982,8 +121110,7 @@ static int flattenSubquery( Parse *pParse, /* Parsing context */ Select *p, /* The parent or outer SELECT statement */ int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ - int isAgg, /* True if outer SELECT uses aggregate functions */ - int subqueryIsAgg /* True if the subquery uses aggregate functions */ + int isAgg /* True if outer SELECT uses aggregate functions */ ){ const char *zSavedAuthContext = pParse->zAuthContext; Select *pParent; /* Current UNION ALL term of the other query */ @@ -112991,8 +121118,9 @@ static int flattenSubquery( Select *pSub1; /* Pointer to the rightmost select in sub-query */ SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ - ExprList *pList; /* The result set of the outer query */ int iParent; /* VDBE cursor number of the pSub result set temp table */ + int iNewParent = -1;/* Replacement table for iParent */ + int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ struct SrcList_item *pSubitem; /* The subquery */ @@ -113001,7 +121129,7 @@ static int flattenSubquery( /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); - assert( p->pPrior==0 ); /* Unable to flatten compound queries */ + assert( p->pPrior==0 ); if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFromnSrc ); @@ -113009,17 +121137,7 @@ static int flattenSubquery( iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); - if( subqueryIsAgg ){ - if( isAgg ) return 0; /* Restriction (1) */ - if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */ - if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery)) - || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0 - || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0 - ){ - return 0; /* Restriction (2b) */ - } - } - + pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, @@ -113033,13 +121151,10 @@ static int flattenSubquery( return 0; /* Restriction (15) */ } if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ - if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */ + if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */ if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){ return 0; /* Restrictions (8)(9) */ } - if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){ - return 0; /* Restriction (6) */ - } if( p->pOrderBy && pSub->pOrderBy ){ return 0; /* Restriction (11) */ } @@ -113048,19 +121163,14 @@ static int flattenSubquery( if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } - testcase( pSub->selFlags & SF_Recursive ); - testcase( pSub->selFlags & SF_MinMaxAgg ); - if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){ - return 0; /* Restrictions (22) and (24) */ - } - if( (p->selFlags & SF_Recursive) && pSub->pPrior ){ - return 0; /* Restriction (23) */ + if( pSub->selFlags & (SF_Recursive) ){ + return 0; /* Restrictions (22) */ } - /* OBSOLETE COMMENT 1: - ** Restriction 3: If the subquery is a join, make sure the subquery is - ** not used as the right operand of an outer join. Examples of why this - ** is not allowed: + /* + ** If the subquery is the right operand of a LEFT JOIN, then the + ** subquery may not be a join itself (3a). Example of why this is not + ** allowed: ** ** t1 LEFT OUTER JOIN (t2 JOIN t3) ** @@ -113070,56 +121180,54 @@ static int flattenSubquery( ** ** which is not at all the same thing. ** - ** OBSOLETE COMMENT 2: - ** Restriction 12: If the subquery is the right operand of a left outer - ** join, make sure the subquery has no WHERE clause. - ** An examples of why this is not allowed: + ** If the subquery is the right operand of a LEFT JOIN, then the outer + ** query cannot be an aggregate. (3c) This is an artifact of the way + ** aggregates are processed - there is no mechanism to determine if + ** the LEFT JOIN table should be all-NULL. ** - ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0) - ** - ** If we flatten the above, we would get - ** - ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0 - ** - ** But the t2.x>0 test will always fail on a NULL row of t2, which - ** effectively converts the OUTER JOIN into an INNER JOIN. - ** - ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE: - ** Ticket #3300 shows that flattening the right term of a LEFT JOIN - ** is fraught with danger. Best to avoid the whole thing. If the - ** subquery is the right term of a LEFT JOIN, then do not flatten. + ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ - return 0; + isLeftJoin = 1; + if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){ + /* (3a) (3c) (3b) */ + return 0; + } } +#ifdef SQLITE_EXTRA_IFNULLROW + else if( iFrom>0 && !isAgg ){ + /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for + ** every reference to any result column from subquery in a join, even + ** though they are not necessary. This will stress-test the OP_IfNullRow + ** opcode. */ + isLeftJoin = -1; + } +#endif - /* Restriction 17: If the sub-query is a compound SELECT, then it must + /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ - if( pSub->pOrderBy ){ - return 0; /* Restriction 20 */ - } if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){ - return 0; + return 0; /* (17d1), (17d2), or (17d3) */ } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); assert( pSub->pSrc!=0 ); assert( pSub->pEList->nExpr==pSub1->pEList->nExpr ); - if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 - || (pSub1->pPrior && pSub1->op!=TK_ALL) - || pSub1->pSrc->nSrc<1 + if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */ + || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */ + || pSub1->pSrc->nSrc<1 /* (17c) */ ){ return 0; } testcase( pSub1->pSrc->nSrc>1 ); } - /* Restriction 18. */ + /* Restriction (18). */ if( p->pOrderBy ){ int ii; for(ii=0; iipOrderBy->nExpr; ii++){ @@ -113128,6 +121236,23 @@ static int flattenSubquery( } } + /* Ex-restriction (23): + ** The only way that the recursive part of a CTE can contain a compound + ** subquery is for the subquery to be one term of a join. But if the + ** subquery is a join, then the flattening has already been stopped by + ** restriction (17d3) + */ + assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 ); + + /* Ex-restriction (20): + ** A compound subquery must be the only term in the FROM clause of the + ** outer query by restriction (17d3). But if that term also has an + ** ORDER BY clause, then the subquery will be implemented by co-routine + ** and so the flattener will never be invoked. Hence, it is not possible + ** for the subquery to be a compound and have an ORDER BY clause. + */ + assert( pSub->pPrior==0 || pSub->pOrderBy==0 ); + /***** If we reach this point, flattening is permitted. *****/ SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", pSub->zSelName, pSub, iFrom)); @@ -113228,12 +121353,12 @@ static int flattenSubquery( */ if( ALWAYS(pSubitem->pTab!=0) ){ Table *pTabToDel = pSubitem->pTab; - if( pTabToDel->nRef==1 ){ + if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); pTabToDel->pNextZombie = pToplevel->pZombieTab; pToplevel->pZombieTab = pTabToDel; }else{ - pTabToDel->nRef--; + pTabToDel->nTabRef--; } pSubitem->pTab = 0; } @@ -113299,6 +121424,7 @@ static int flattenSubquery( sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing); assert( pSrc->a[i+iFrom].fg.isTabFunc==0 ); pSrc->a[i+iFrom] = pSubSrc->a[i]; + iNewParent = pSubSrc->a[i].iCursor; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } pSrc->a[iFrom].fg.jointype = jointype; @@ -113315,14 +121441,6 @@ static int flattenSubquery( ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ - pList = pParent->pEList; - for(i=0; inExpr; i++){ - if( pList->a[i].zName==0 ){ - char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan); - sqlite3Dequote(zName); - pList->a[i].zName = zName; - } - } if( pSub->pOrderBy ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th @@ -113344,18 +121462,19 @@ static int flattenSubquery( pSub->pOrderBy = 0; } pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); - if( subqueryIsAgg ){ - assert( pParent->pHaving==0 ); - pParent->pHaving = pParent->pWhere; - pParent->pWhere = pWhere; - pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving, - sqlite3ExprDup(db, pSub->pHaving, 0)); - assert( pParent->pGroupBy==0 ); - pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0); - }else{ - pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere); + if( isLeftJoin>0 ){ + setJoinExpr(pWhere, iNewParent); + } + pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); + if( db->mallocFailed==0 ){ + SubstContext x; + x.pParse = pParse; + x.iTable = iParent; + x.iNewTable = iNewParent; + x.isLeftJoin = isLeftJoin; + x.pEList = pSub->pEList; + substSelect(&x, pParent, 0); } - substSelect(db, pParent, iParent, pSub->pEList, 0); /* The flattened query is distinct if either the inner or the ** outer query is distinct. @@ -113409,9 +121528,13 @@ static int flattenSubquery( ** ** Do not attempt this optimization if: ** -** (1) The inner query is an aggregate. (In that case, we'd really want -** to copy the outer WHERE-clause terms onto the HAVING clause of the -** inner query. But they probably won't help there so do not bother.) +** (1) (** This restriction was removed on 2017-09-29. We used to +** disallow this optimization for aggregate subqueries, but now +** it is allowed by putting the extra terms on the HAVING clause. +** The added HAVING clause is pointless if the subquery lacks +** a GROUP BY clause. But such a HAVING clause is also harmless +** so there does not appear to be any reason to add extra logic +** to suppress it. **) ** ** (2) The inner query is the recursive part of a common table expression. ** @@ -113429,7 +121552,7 @@ static int flattenSubquery( ** terms are duplicated into the subquery. */ static int pushDownWhereTerms( - sqlite3 *db, /* The database connection (for malloc()) */ + Parse *pParse, /* Parse context (for malloc() and error reporting) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ Expr *pWhere, /* The WHERE clause of the outer query */ int iCursor /* Cursor number of the subquery */ @@ -113437,23 +121560,45 @@ static int pushDownWhereTerms( Expr *pNew; int nChng = 0; if( pWhere==0 ) return 0; - if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){ - return 0; /* restrictions (1) and (2) */ + if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */ + +#ifdef SQLITE_DEBUG + /* Only the first term of a compound can have a WITH clause. But make + ** sure no other terms are marked SF_Recursive in case something changes + ** in the future. + */ + { + Select *pX; + for(pX=pSubq; pX; pX=pX->pPrior){ + assert( (pX->selFlags & (SF_Recursive))==0 ); + } } +#endif + if( pSubq->pLimit!=0 ){ - return 0; /* restriction (3) */ + return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ - nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor); + nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor); pWhere = pWhere->pLeft; } - if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */ + if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */ if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; while( pSubq ){ - pNew = sqlite3ExprDup(db, pWhere, 0); - pNew = substExpr(db, pNew, iCursor, pSubq->pEList); - pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew); + SubstContext x; + pNew = sqlite3ExprDup(pParse->db, pWhere, 0); + x.pParse = pParse; + x.iTable = iCursor; + x.iNewTable = iCursor; + x.isLeftJoin = 0; + x.pEList = pSubq->pEList; + pNew = substExpr(&x, pNew); + if( pSubq->selFlags & SF_Aggregate ){ + pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew); + }else{ + pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + } pSubq = pSubq->pPrior; } } @@ -113745,13 +121890,13 @@ static int withExpand( assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; - pTab->nRef = 1; + pTab->nTabRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); - if( db->mallocFailed ) return SQLITE_NOMEM; + if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; assert( pFrom->pSelect ); /* Check if this is a recursive CTE. */ @@ -113768,25 +121913,34 @@ static int withExpand( ){ pItem->pTab = pTab; pItem->fg.isRecursive = 1; - pTab->nRef++; + pTab->nTabRef++; pSel->selFlags |= SF_Recursive; } } } /* Only one recursive reference is permitted. */ - if( pTab->nRef>2 ){ + if( pTab->nTabRef>2 ){ sqlite3ErrorMsg( pParse, "multiple references to recursive table: %s", pCte->zName ); return SQLITE_ERROR; } - assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 )); + assert( pTab->nTabRef==1 || + ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; - sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel); + if( bMayRecursive ){ + Select *pPrior = pSel->pPrior; + assert( pPrior->pWith==0 ); + pPrior->pWith = pSel->pWith; + sqlite3WalkSelect(pWalker, pPrior); + pPrior->pWith = 0; + }else{ + sqlite3WalkSelect(pWalker, pSel); + } pParse->pWith = pWith; for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); @@ -113830,10 +121984,12 @@ static int withExpand( */ static void selectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; - With *pWith = findRightmost(p)->pWith; - if( pWith!=0 ){ - assert( pParse->pWith==pWith ); - pParse->pWith = pWith->pOuter; + if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){ + With *pWith = findRightmost(p)->pWith; + if( pWith!=0 ){ + assert( pParse->pWith==pWith ); + pParse->pWith = pWith->pOuter; + } } } #else @@ -113883,8 +122039,8 @@ static int selectExpander(Walker *pWalker, Select *p){ } pTabList = p->pSrc; pEList = p->pEList; - if( pWalker->xSelectCallback2==selectPopWith ){ - sqlite3WithPush(pParse, findRightmost(p)->pWith, 0); + if( OK_IF_ALWAYS_TRUE(p->pWith) ){ + sqlite3WithPush(pParse, p->pWith, 0); } /* Make sure cursor numbers have been assigned to all entries in @@ -113914,8 +122070,12 @@ static int selectExpander(Walker *pWalker, Select *p){ if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; - pTab->nRef = 1; - pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); + pTab->nTabRef = 1; + if( pFrom->zAlias ){ + pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias); + }else{ + pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab); + } while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; @@ -113927,13 +122087,13 @@ static int selectExpander(Walker *pWalker, Select *p){ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; - if( pTab->nRef==0xffff ){ + if( pTab->nTabRef>=0xffff ){ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", pTab->zName); pFrom->pTab = 0; return WRC_Abort; } - pTab->nRef++; + pTab->nTabRef++; if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){ return WRC_Abort; } @@ -114037,7 +122197,7 @@ static int selectExpander(Walker *pWalker, Select *p){ continue; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*"; + zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } for(j=0; jnCol; j++){ char *zName = pTab->aCol[j].zName; @@ -114083,10 +122243,10 @@ static int selectExpander(Walker *pWalker, Select *p){ if( longNames || pTabList->nSrc>1 ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); - pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); if( zSchemaName ){ pLeft = sqlite3Expr(db, TK_ID, zSchemaName); - pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0); + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr); } if( longNames ){ zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); @@ -114096,8 +122256,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pExpr = pRight; } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); - sColname.z = zColname; - sColname.n = sqlite3Strlen30(zColname); + sqlite3TokenInit(&sColname, zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; @@ -114126,12 +122285,10 @@ static int selectExpander(Walker *pWalker, Select *p){ sqlite3ExprListDelete(db, pEList); p->pEList = pNew; } -#if SQLITE_MAX_COLUMN if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns in result set"); return WRC_Abort; } -#endif return WRC_Continue; } @@ -114149,6 +122306,25 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ return WRC_Continue; } +/* +** No-op routine for the parse-tree walker for SELECT statements. +** subquery in the parser tree. +*/ +SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return WRC_Continue; +} + +#if SQLITE_DEBUG +/* +** Always assert. This xSelectCallback2 implementation proves that the +** xSelectCallback2 is never invoked. +*/ +SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + assert( 0 ); +} +#endif /* ** This routine "expands" a SELECT statement and all of its subqueries. ** For additional information on what it means to "expand" a SELECT @@ -114164,17 +122340,15 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; - memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; - if( pParse->hasCompound ){ + if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; + w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - if( (pSelect->selFlags & SF_MultiValue)==0 ){ - w.xSelectCallback2 = selectPopWith; - } + w.xSelectCallback2 = selectPopWith; sqlite3WalkSelect(&w, pSelect); } @@ -114212,7 +122386,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Select *pSel = pFrom->pSelect; if( pSel ){ while( pSel->pPrior ) pSel = pSel->pPrior; - selectAddColumnTypeAndCollation(pParse, pTab, pSel); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel); } } } @@ -114230,7 +122404,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; - memset(&w, 0, sizeof(w)); + w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = selectAddSubqueryTypeInfo; w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; @@ -114256,15 +122430,13 @@ SQLITE_PRIVATE void sqlite3SelectPrep( Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ - sqlite3 *db; - if( NEVER(p==0) ) return; - db = pParse->db; - if( db->mallocFailed ) return; + assert( p!=0 || pParse->db->mallocFailed ); + if( pParse->db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); - if( pParse->nErr || db->mallocFailed ) return; + if( pParse->nErr || pParse->db->mallocFailed ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); - if( pParse->nErr || db->mallocFailed ) return; + if( pParse->nErr || pParse->db->mallocFailed ) return; sqlite3SelectAddTypeInfo(pParse, p); } @@ -114324,8 +122496,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ ExprList *pList = pF->pExpr->x.pList; assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); - sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0, - (void*)pF->pFunc, P4_FUNCDEF); + sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } } @@ -114376,8 +122548,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem, - (void*)pF->pFunc, P4_FUNCDEF); + sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); @@ -114437,6 +122609,187 @@ static void explainSimpleCount( # define explainSimpleCount(a,b,c) #endif +/* +** Context object for havingToWhereExprCb(). +*/ +struct HavingToWhereCtx { + Expr **ppWhere; + ExprList *pGroupBy; +}; + +/* +** sqlite3WalkExpr() callback used by havingToWhere(). +** +** If the node passed to the callback is a TK_AND node, return +** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes. +** +** Otherwise, return WRC_Prune. In this case, also check if the +** sub-expression matches the criteria for being moved to the WHERE +** clause. If so, add it to the WHERE clause and replace the sub-expression +** within the HAVING expression with a constant "1". +*/ +static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op!=TK_AND ){ + struct HavingToWhereCtx *p = pWalker->u.pHavingCtx; + if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){ + sqlite3 *db = pWalker->pParse->db; + Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0); + if( pNew ){ + Expr *pWhere = *(p->ppWhere); + SWAP(Expr, *pNew, *pExpr); + pNew = sqlite3ExprAnd(db, pWhere, pNew); + *(p->ppWhere) = pNew; + } + } + return WRC_Prune; + } + return WRC_Continue; +} + +/* +** Transfer eligible terms from the HAVING clause of a query, which is +** processed after grouping, to the WHERE clause, which is processed before +** grouping. For example, the query: +** +** SELECT * FROM WHERE a=? GROUP BY b HAVING b=? AND c=? +** +** can be rewritten as: +** +** SELECT * FROM WHERE a=? AND b=? GROUP BY b HAVING c=? +** +** A term of the HAVING expression is eligible for transfer if it consists +** entirely of constants and expressions that are also GROUP BY terms that +** use the "BINARY" collation sequence. +*/ +static void havingToWhere( + Parse *pParse, + ExprList *pGroupBy, + Expr *pHaving, + Expr **ppWhere +){ + struct HavingToWhereCtx sCtx; + Walker sWalker; + + sCtx.ppWhere = ppWhere; + sCtx.pGroupBy = pGroupBy; + + memset(&sWalker, 0, sizeof(sWalker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = havingToWhereExprCb; + sWalker.u.pHavingCtx = &sCtx; + sqlite3WalkExpr(&sWalker, pHaving); +} + +/* +** Check to see if the pThis entry of pTabList is a self-join of a prior view. +** If it is, then return the SrcList_item for the prior view. If it is not, +** then return 0. +*/ +static struct SrcList_item *isSelfJoinView( + SrcList *pTabList, /* Search for self-joins in this FROM clause */ + struct SrcList_item *pThis /* Search for prior reference to this subquery */ +){ + 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; + if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; + if( sqlite3ExprCompare(0, + pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) + ){ + /* The view was modified by some other optimization such as + ** pushDownWhereTerms() */ + continue; + } + return pItem; + } + return 0; +} + +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION +/* +** Attempt to transform a query of the form +** +** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2) +** +** Into this: +** +** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) +** +** The transformation only works if all of the following are true: +** +** * The subquery is a UNION ALL of two or more terms +** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries +** * The outer query is a simple count(*) +** +** Return TRUE if the optimization is undertaken. +*/ +static int countOfViewOptimization(Parse *pParse, Select *p){ + Select *pSub, *pPrior; + Expr *pExpr; + Expr *pCount; + sqlite3 *db; + if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ + if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ + 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() */ + if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ + if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ + pSub = p->pSrc->a[0].pSelect; + if( pSub==0 ) return 0; /* The FROM is a subquery */ + if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ + do{ + if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ + if( pSub->pWhere ) return 0; /* No WHERE clause */ + if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ + pSub = pSub->pPrior; /* Repeat over compound */ + }while( pSub ); + + /* If we reach this point then it is OK to perform the transformation */ + + db = pParse->db; + pCount = pExpr; + pExpr = 0; + pSub = p->pSrc->a[0].pSelect; + p->pSrc->a[0].pSelect = 0; + sqlite3SrcListDelete(db, p->pSrc); + p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); + while( pSub ){ + Expr *pTerm; + pPrior = pSub->pPrior; + pSub->pPrior = 0; + pSub->pNext = 0; + pSub->selFlags |= SF_Aggregate; + pSub->selFlags &= ~SF_Compound; + pSub->nSelectRow = 0; + sqlite3ExprListDelete(db, pSub->pEList); + pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; + pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); + pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, pTerm, pSub); + if( pExpr==0 ){ + pExpr = pTerm; + }else{ + pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); + } + pSub = pPrior; + } + p->pEList->a[0].pExpr = pExpr; + p->selFlags &= ~SF_Aggregate; + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + return 1; +} +#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */ + /* ** Generate code for the SELECT statement given in the p argument. ** @@ -114521,15 +122874,13 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - - /* If writing to memory or generating a set - ** only a single column may be output. - */ -#ifndef SQLITE_OMIT_SUBQUERY - if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){ - goto select_end; + /* Get a pointer the VDBE under construction, allocating a new VDBE if one + ** does not already exist */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto select_end; + if( pDest->eDest==SRT_Output ){ + generateColumnNames(pParse, p); } -#endif /* Try to flatten subqueries in the FROM clause up into the main query */ @@ -114537,7 +122888,6 @@ SQLITE_PRIVATE int sqlite3Select( for(i=0; !p->pPrior && inSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; - int isAggSub; Table *pTab = pItem->pTab; if( pSub==0 ) continue; @@ -114549,13 +122899,36 @@ SQLITE_PRIVATE int sqlite3Select( goto select_end; } - isAggSub = (pSub->selFlags & SF_Aggregate)!=0; - if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* Do not try to flatten an aggregate subquery. + ** + ** Flattening an aggregate subquery is only possible if the outer query + ** is not a join. But if the outer query is not a join, then the subquery + ** will be implemented as a co-routine and there is no advantage to + ** flattening in that case. + */ + if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; + assert( pSub->pGroupBy==0 ); + + /* If the subquery contains an ORDER BY clause and if + ** it will be implemented as a co-routine, then do not flatten. This + ** restriction allows SQL constructs like this: + ** + ** SELECT expensive_function(x) + ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10); + ** + ** The expensive_function() is only computed on the 10 rows that + ** are output, rather than every row of the table. + */ + if( pSub->pOrderBy!=0 + && i==0 + && (pTabList->nSrc==1 + || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) + ){ + continue; + } + + if( flattenSubquery(pParse, p, i, isAgg) ){ /* This subquery can be absorbed into its parent. */ - if( isAggSub ){ - isAgg = 1; - p->selFlags |= SF_Aggregate; - } i = -1; } pTabList = p->pSrc; @@ -114566,11 +122939,6 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* Get a pointer the VDBE under construction, allocating a new VDBE if one - ** does not already exist */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto select_end; - #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() ** procedure. @@ -114586,13 +122954,42 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* Generate code for all sub-queries in the FROM clause + /* For each term in the FROM clause, do two things: + ** (1) Authorized unreferenced tables + ** (2) Generate code for all sub-queries */ -#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; inSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; - Select *pSub = pItem->pSelect; + Select *pSub; +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + const char *zSavedAuthContext; +#endif + + /* Issue SQLITE_READ authorizations with a fake column name for any + ** tables that are referenced but from which no values are extracted. + ** Examples of where these kinds of null SQLITE_READ authorizations + ** would occur: + ** + ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" + ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2."" + ** + ** The fake column name is an empty string. It is possible for a table to + ** have a column named by the empty string, in which case there is no way to + ** distinguish between an unreferenced table and an actual reference to the + ** "" column. The original design was for the fake column name to be a NULL, + ** which would be unambiguous. But legacy authorization callbacks might + ** assume the column name is non-NULL and segfault. The use of an empty + ** string for the fake column name seems safer. + */ + if( pItem->colUsed==0 ){ + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); + } + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + /* Generate code for all sub-queries in the FROM clause + */ + pSub = pItem->pSelect; if( pSub==0 ) continue; /* Sometimes the code for a subquery will be generated more than @@ -114603,6 +123000,10 @@ SQLITE_PRIVATE int sqlite3Select( ** 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; @@ -114621,7 +123022,7 @@ SQLITE_PRIVATE int sqlite3Select( ** inside the subquery. This can help the subquery to run more efficiently. */ if( (pItem->fg.jointype & JT_OUTER)==0 - && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor) + && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ @@ -114631,16 +123032,27 @@ SQLITE_PRIVATE int sqlite3Select( #endif } + zSavedAuthContext = pParse->zAuthContext; + pParse->zAuthContext = pItem->zName; + /* Generate code to implement the subquery + ** + ** The subquery is implemented as a co-routine if the subquery is + ** guaranteed to be the outer loop (so that it does not need to be + ** computed more than once) + ** + ** TODO: Are there other reasons beside (1) to use a co-routine + ** implementation? */ - if( pTabList->nSrc==1 - && (p->selFlags & SF_All)==0 - && OptimizationEnabled(db, SQLITE_SubqCoroutine) + if( i==0 + && (pTabList->nSrc==1 + || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; + pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); @@ -114648,10 +123060,10 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); + pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); + sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else{ @@ -114663,6 +123075,8 @@ SQLITE_PRIVATE int sqlite3Select( int topAddr; int onceAddr = 0; int retAddr; + struct SrcList_item *pPrior; + assert( pItem->addrFillSub==0 ); pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); @@ -114671,15 +123085,23 @@ SQLITE_PRIVATE int sqlite3Select( /* If the subquery is not correlated and if we are not inside of ** a trigger, then we only need to compute the value of the subquery ** once. */ - onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); }else{ VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); } - sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); - sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); + pPrior = isSelfJoinView(pTabList, pItem); + if( pPrior ){ + sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); + explainSetInteger(pItem->iSelectId, pPrior->iSelectId); + assert( pPrior->pSelect!=0 ); + pSub->nSelectRow = pPrior->pSelect->nSelectRow; + }else{ + sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + } + pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); @@ -114688,8 +123110,9 @@ SQLITE_PRIVATE int sqlite3Select( } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); - } + pParse->zAuthContext = zSavedAuthContext; #endif + } /* Various elements of the SELECT copied into local variables for ** convenience */ @@ -114706,6 +123129,16 @@ SQLITE_PRIVATE int sqlite3Select( } #endif +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION + if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) + && countOfViewOptimization(pParse, p) + ){ + if( db->mallocFailed ) goto select_end; + pEList = p->pEList; + pTabList = p->pSrc; + } +#endif + /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: @@ -114730,6 +123163,13 @@ SQLITE_PRIVATE int sqlite3Select( ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ assert( sDistinct.isTnct ); + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif } /* If there is an ORDER BY clause, then create an ephemeral index to @@ -114762,7 +123202,9 @@ SQLITE_PRIVATE int sqlite3Select( /* Set the limiter. */ iEnd = sqlite3VdbeMakeLabel(v); - p->nSelectRow = LARGEST_INT64; + if( (p->selFlags & SF_FixedLimit)==0 ){ + p->nSelectRow = 320; /* 4 billion rows */ + } computeLimitRegisters(pParse, p, iEnd); if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen); @@ -114786,10 +123228,12 @@ SQLITE_PRIVATE int sqlite3Select( if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); + assert( WHERE_USE_LIMIT==SF_FixedLimit ); + wctrlFlags |= p->selFlags & SF_FixedLimit; /* Begin the database scan. */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, - p->pEList, wctrlFlags, 0); + p->pEList, wctrlFlags, p->nSelectRow); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); @@ -114799,6 +123243,7 @@ SQLITE_PRIVATE int sqlite3Select( } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); + sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } @@ -114813,7 +123258,8 @@ SQLITE_PRIVATE int sqlite3Select( } /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, + assert( p->pEList==pEList ); + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); @@ -114849,9 +123295,11 @@ SQLITE_PRIVATE int sqlite3Select( for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){ pItem->u.x.iAlias = 0; } - if( p->nSelectRow>100 ) p->nSelectRow = 100; + assert( 66==sqlite3LogEst(100) ); + if( p->nSelectRow>66 ) p->nSelectRow = 66; }else{ - p->nSelectRow = 1; + assert( 0==sqlite3LogEst(1) ); + p->nSelectRow = 0; } /* If there is both a GROUP BY and an ORDER BY clause and they are @@ -114883,6 +123331,11 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); if( pHaving ){ + if( pGroupBy ){ + assert( pWhere==p->pWhere ); + havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere); + pWhere = p->pWhere; + } sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } sAggInfo.nAccumulator = sAggInfo.nColumn; @@ -115109,7 +123562,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, &sSort, + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); @@ -115223,7 +123676,8 @@ SQLITE_PRIVATE int sqlite3Select( if( flag ){ pMinMax = sqlite3ExprListDup(db, pMinMax, 0); pDel = pMinMax; - if( pMinMax && !db->mallocFailed ){ + assert( db->mallocFailed || pMinMax!=0 ); + if( !db->mallocFailed ){ pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; pMinMax->a[0].pExpr->op = TK_COLUMN; } @@ -115234,7 +123688,7 @@ SQLITE_PRIVATE int sqlite3Select( ** of output. */ resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax, 0,flag,0); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDel); goto select_end; @@ -115252,7 +123706,7 @@ SQLITE_PRIVATE int sqlite3Select( sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, + selectInnerLoop(pParse, p, -1, 0, 0, pDest, addrEnd, addrEnd); sqlite3ExprListDelete(db, pDel); } @@ -115287,12 +123741,6 @@ SQLITE_PRIVATE int sqlite3Select( select_end: explainSetInteger(pParse->iSelectId, iRestoreSelectId); - /* Identify column names if results of the SELECT are to be output. - */ - if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){ - generateColumnNames(pParse, pTabList, pEList); - } - sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); #if SELECTTRACE_ENABLED @@ -115323,8 +123771,6 @@ select_end: ** if they are not used. */ /* #include "sqliteInt.h" */ -/* #include */ -/* #include */ #ifndef SQLITE_OMIT_GET_TABLE @@ -115407,7 +123853,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ return 0; malloc_failed: - p->rc = SQLITE_NOMEM; + p->rc = SQLITE_NOMEM_BKPT; return 1; } @@ -115421,7 +123867,7 @@ malloc_failed: ** Instead, the entire table should be passed to sqlite3_free_table() when ** the calling procedure is finished using it. */ -SQLITE_API int SQLITE_STDCALL sqlite3_get_table( +SQLITE_API int sqlite3_get_table( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ char ***pazResult, /* Write the result table here */ @@ -115448,7 +123894,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table( res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc ); if( res.azResult==0 ){ db->errCode = SQLITE_NOMEM; - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } res.azResult[0] = 0; rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); @@ -115477,7 +123923,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table( if( azNew==0 ){ sqlite3_free_table(&res.azResult[1]); db->errCode = SQLITE_NOMEM; - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } res.azResult = azNew; } @@ -115490,7 +123936,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table( /* ** This routine frees the space the sqlite3_get_table() malloced. */ -SQLITE_API void SQLITE_STDCALL sqlite3_free_table( +SQLITE_API void sqlite3_free_table( char **azResult /* Result returned from sqlite3_get_table() */ ){ if( azResult ){ @@ -115605,7 +124051,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( int iDb; /* The database to store the trigger in */ Token *pName; /* The unqualified db name */ DbFixer sFix; /* State vector for the DB fixer */ - int iTabDb; /* Index of the database holding pTab */ assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ assert( pName2!=0 ); @@ -115718,13 +124163,13 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( " trigger on table: %S", pTableName, 0); goto trigger_cleanup; } - iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int code = SQLITE_CREATE_TRIGGER; - const char *zDb = db->aDb[iTabDb].zName; - const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; + const char *zDb = db->aDb[iTabDb].zDbSName; + const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; @@ -115796,8 +124241,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } - nameToken.z = pTrig->zName; - nameToken.n = sqlite3Strlen30(nameToken.z); + sqlite3TokenInit(&nameToken, pTrig->zName); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) || sqlite3FixExpr(&sFix, pTrig->pWhen) @@ -115817,9 +124261,10 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); + testcase( z==0 ); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, + db->aDb[iDb].zDbSName, MASTER_NAME, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); @@ -115833,7 +124278,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pTrig = sqlite3HashInsert(pHash, zName, pTrig); if( pTrig ){ - db->mallocFailed = 1; + sqlite3OomFault(db); }else if( pLink->pSchema==pLink->pTabSchema ){ Table *pTab; pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); @@ -116008,7 +124453,7 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; + if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; @@ -116054,7 +124499,7 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; - const char *zDb = db->aDb[iDb].zName; + const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || @@ -116070,7 +124515,7 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrigger->zName + db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); @@ -116095,7 +124540,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch *pp = (*pp)->pNext; } sqlite3DeleteTrigger(db, pTrigger); - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } } @@ -116173,8 +124618,10 @@ static SrcList *targetSrcList( pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); if( iDb==0 || iDb>=2 ){ + const char *zDb; assert( iDbnDb ); - pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); + zDb = db->aDb[iDb].zDbSName; + pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); } } return pSrc; @@ -116388,7 +124835,6 @@ static TriggerPrg *codeRowTrigger( } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; - pProgram->nOnce = pSubParse->nOnce; pProgram->token = (void *)pTrigger; pPrg->aColmask[0] = pSubParse->oldmask; pPrg->aColmask[1] = pSubParse->newmask; @@ -116461,8 +124907,8 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( if( pPrg ){ int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); - sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem); - sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM); + sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem, + (const char *)pPrg->pProgram, P4_SUBPROGRAM); VdbeComment( (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); @@ -116681,14 +125127,14 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, pCol->affinity, &pValue); if( pValue ){ - sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM); + sqlite3VdbeAppendP4(v, pValue, P4_MEM); } -#ifndef SQLITE_OMIT_FLOATING_POINT - if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ - sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); - } -#endif } +#ifndef SQLITE_OMIT_FLOATING_POINT + if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); + } +#endif } /* @@ -116717,7 +125163,7 @@ SQLITE_PRIVATE void sqlite3Update( int iDataCur; /* Cursor for the canonical data btree */ int iIdxCur; /* Cursor for the first index */ sqlite3 *db; /* The database structure */ - int *aRegIdx = 0; /* One register assigned to each index to be updated */ + int *aRegIdx = 0; /* First register in array assigned to each index */ 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. */ @@ -116729,10 +125175,11 @@ SQLITE_PRIVATE void sqlite3Update( AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ - int okOnePass; /* True for one-pass algorithm without the FIFO */ + int eOnePass; /* ONEPASS_XXX value from where.c */ int hasFK; /* True if foreign key processing is required */ int labelBreak; /* Jump here to break out of UPDATE loop */ int labelContinue; /* Jump here to continue next step of UPDATE loop */ + int flags; /* Flags for sqlite3WhereBegin() */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True when updating a view (INSTEAD OF trigger) */ @@ -116743,6 +125190,10 @@ SQLITE_PRIVATE void sqlite3Update( int iEph = 0; /* Ephemeral table holding all primary key values */ int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ + int addrOpen = 0; /* Address of OP_OpenEphemeral */ + int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */ + i16 nPk = 0; /* Number of components of the PRIMARY KEY */ + int bReplace = 0; /* True if REPLACE conflict resolution might happen */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ @@ -116809,7 +125260,7 @@ SQLITE_PRIVATE void sqlite3Update( /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ - aXRef = sqlite3DbMallocRaw(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 ); + aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; aToOpen = (u8*)(aRegIdx+nIdx); @@ -116861,7 +125312,7 @@ SQLITE_PRIVATE void sqlite3Update( int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, j<0 ? "ROWID" : pTab->aCol[j].zName, - db->aDb[iDb].zName); + db->aDb[iDb].zDbSName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ @@ -116880,7 +125331,7 @@ SQLITE_PRIVATE void sqlite3Update( ** case, set all bits of the colUsed mask (to ensure that the virtual ** table implementation makes all columns available). */ - pTabList->a[0].colUsed = IsVirtual(pTab) ? (Bitmask)-1 : 0; + pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); @@ -116892,14 +125343,21 @@ SQLITE_PRIVATE void sqlite3Update( */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; - if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){ + if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){ 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 ){ reg = ++pParse->nMem; + pParse->nMem += pIdx->nColumn; + if( (onError==OE_Replace) + || (onError==OE_Default && pIdx->onError==OE_Replace) + ){ + bReplace = 1; + } break; } } @@ -116907,6 +125365,11 @@ SQLITE_PRIVATE void sqlite3Update( if( reg==0 ) aToOpen[j+1] = 0; aRegIdx[j] = reg; } + if( bReplace ){ + /* If REPLACE conflict resolution might be invoked, open cursors on all + ** indexes in case they are needed to delete records. */ + memset(aToOpen, 1, nIdx+1); + } /* Begin generating code. */ v = sqlite3GetVdbe(pParse); @@ -116959,109 +125422,130 @@ SQLITE_PRIVATE void sqlite3Update( } #endif - /* Begin the database scan - */ + /* Initialize the count of updated rows */ + if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){ + regRowCount = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); + } + if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); - pWInfo = sqlite3WhereBegin( - pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur - ); - if( pWInfo==0 ) goto update_cleanup; - okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); - - /* Remember the rowid of every item to be updated. - */ - sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); - if( !okOnePass ){ - sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); - } - - /* End the database scan loop. - */ - sqlite3WhereEnd(pWInfo); }else{ - int iPk; /* First of nPk memory cells holding PRIMARY KEY value */ - i16 nPk; /* Number of components of the PRIMARY KEY */ - int addrOpen; /* Address of the OpenEphemeral instruction */ - assert( pPk!=0 ); nPk = pPk->nKeyCol; iPk = pParse->nMem+1; pParse->nMem += nPk; regKey = ++pParse->nMem; iEph = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_Null, 0, iPk); addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, - WHERE_ONEPASS_DESIRED, iIdxCur); - if( pWInfo==0 ) goto update_cleanup; - okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); + } + + /* Begin the database scan. + ** + ** Do not consider a single-pass strategy for a multi-row update if + ** there are any triggers or foreign keys to process, or rows may + ** be deleted as a result of REPLACE conflict handling. Any of these + ** things might disturb a cursor being used to scan through the table + ** or index, causing a single-pass approach to malfunction. */ + flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE; + if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ + flags |= WHERE_ONEPASS_MULTIROW; + } + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur); + if( pWInfo==0 ) goto update_cleanup; + + /* A one-pass strategy that might update more than one row may not + ** be used if any column of the index used for the scan is being + ** updated. Otherwise, if there is an index on "b", statements like + ** the following could create an infinite loop: + ** + ** UPDATE t1 SET b=b+1 WHERE b>? + ** + ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI + ** strategy that uses an index for which one or more columns are being + ** updated. */ + eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); + if( eOnePass==ONEPASS_MULTI ){ + int iCur = aiCurOnePass[1]; + if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ + eOnePass = ONEPASS_OFF; + } + assert( iCur!=iDataCur || !HasRowid(pTab) ); + } + + if( HasRowid(pTab) ){ + /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF + ** mode, write the rowid into the FIFO. In either of the one-pass modes, + ** leave it in register regOldRowid. */ + sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); + if( eOnePass==ONEPASS_OFF ){ + sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); + } + }else{ + /* Read the PK of the current row into an array of registers. In + ** ONEPASS_OFF mode, serialize the array into a record and store it in + ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change + ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table + ** is not required) and leave the PK fields in the array of registers. */ for(i=0; iaiColumn[i]>=0 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], - iPk+i); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i); } - if( okOnePass ){ + if( eOnePass ){ sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, sqlite3IndexAffinityStr(db, pPk), nPk); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk); } - sqlite3WhereEnd(pWInfo); } - /* Initialize the count of updated rows - */ - if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){ - regRowCount = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); + if( eOnePass!=ONEPASS_MULTI ){ + sqlite3WhereEnd(pWInfo); } labelBreak = sqlite3VdbeMakeLabel(v); if( !isView ){ - /* - ** Open every index that needs updating. Note that if any - ** index could potentially invoke a REPLACE conflict resolution - ** action, then we need to open all indices because we might need - ** to be deleting some records. - */ - if( onError==OE_Replace ){ - memset(aToOpen, 1, nIdx+1); - }else{ - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_Replace ){ - memset(aToOpen, 1, nIdx+1); - break; - } - } - } - if( okOnePass ){ + int addrOnce = 0; + + /* Open every index that needs updating. */ + if( eOnePass!=ONEPASS_OFF ){ if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; } + + if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, 0, 0); + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); } /* Top of the update loop */ - if( okOnePass ){ - if( aToOpen[iDataCur-iBaseCur] && !isView ){ + if( eOnePass!=ONEPASS_OFF ){ + if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); VdbeCoverageNeverTaken(v); } - labelContinue = labelBreak; + if( eOnePass==ONEPASS_SINGLE ){ + labelContinue = labelBreak; + }else{ + labelContinue = sqlite3VdbeMakeLabel(v); + } sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); VdbeCoverageIf(v, pPk==0); VdbeCoverageIf(v, pPk!=0); }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); - addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey); + addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); VdbeCoverage(v); }else{ @@ -117179,12 +125663,12 @@ SQLITE_PRIVATE void sqlite3Update( if( !isView ){ int addr1 = 0; /* Address of jump instruction */ - int bReplace = 0; /* True if REPLACE conflict resolution might happen */ /* Do constraint checks. */ assert( regOldRowid>0 ); sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, - regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace); + regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, + aXRef); /* Do FK constraint checks. */ if( hasFK ){ @@ -117201,11 +125685,34 @@ SQLITE_PRIVATE void sqlite3Update( VdbeCoverageNeverTaken(v); } sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1); - - /* If changing the record number, delete the old record. */ - if( hasFK || chngKey || pPk!=0 ){ + + /* If changing the rowid value, or if there are foreign key constraints + ** to process, delete the old record. Otherwise, add a noop OP_Delete + ** to invoke the pre-update hook. + ** + ** That (regNew==regnewRowid+1) is true is also important for the + ** pre-update hook. If the caller invokes preupdate_new(), the returned + ** value is copied from memory cell (regNewRowid+1+iCol), where iCol + ** is the column index supplied by the user. + */ + assert( regNew==regNewRowid+1 ); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + sqlite3VdbeAddOp3(v, OP_Delete, iDataCur, + OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP), + regNewRowid + ); + if( eOnePass==ONEPASS_MULTI ){ + assert( hasFK==0 && chngKey==0 ); + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); + } + if( !pParse->nested ){ + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } +#else + if( hasFK>1 || chngKey ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } +#endif if( bReplace || chngKey ){ sqlite3VdbeJumpHere(v, addr1); } @@ -117215,8 +125722,11 @@ SQLITE_PRIVATE void sqlite3Update( } /* Insert the new index entries and the new record. */ - sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, - regNewRowid, aRegIdx, 1, 0, 0); + sqlite3CompleteInsertion( + pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, + OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), + 0, 0 + ); /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key @@ -117238,8 +125748,11 @@ SQLITE_PRIVATE void sqlite3Update( /* Repeat the above with the next record to be updated, until ** all record selected by the WHERE clause have been updated. */ - if( okOnePass ){ + if( eOnePass==ONEPASS_SINGLE ){ /* Nothing to do at end-of-loop for a single-pass */ + }else if( eOnePass==ONEPASS_MULTI ){ + sqlite3VdbeResolveLabel(v, labelContinue); + sqlite3WhereEnd(pWInfo); }else if( pPk ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); @@ -117248,15 +125761,6 @@ SQLITE_PRIVATE void sqlite3Update( } sqlite3VdbeResolveLabel(v, labelBreak); - /* Close all tables */ - for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ - assert( aRegIdx ); - if( aToOpen[i+1] ){ - sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0); - } - } - if( iDataCurnCol; i++){ if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); @@ -117370,6 +125868,23 @@ static void updateVirtualTable( sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); } } + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); + if( pRowid ){ + sqlite3ExprCode(pParse, pRowid, regArg+1); + }else{ + sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); + } + }else{ + Index *pPk; /* PRIMARY KEY index */ + i16 iPk; /* PRIMARY KEY column */ + pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + assert( pPk->nKeyCol==1 ); + iPk = pPk->aiColumn[0]; + sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); + sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); + } bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); @@ -117442,57 +125957,52 @@ static void updateVirtualTable( /* #include "vdbeInt.h" */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* -** Finalize a prepared statement. If there was an error, store the -** text of the error message in *pzErrMsg. Return the result code. -*/ -static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){ - int rc; - rc = sqlite3VdbeFinalize((Vdbe*)pStmt); - if( rc ){ - sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); - } - return rc; -} /* -** Execute zSql on database db. Return an error code. +** Execute zSql on database db. +** +** If zSql returns rows, then each row will have exactly one +** column. (This will only happen if zSql begins with "SELECT".) +** Take each row of result and call execSql() again recursively. +** +** The execSqlF() routine does the same thing, except it accepts +** a format string as its third argument */ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ - sqlite3_stmt *pStmt; - VVA_ONLY( int rc; ) - if( !zSql ){ - return SQLITE_NOMEM; - } - if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ - sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); - return sqlite3_errcode(db); - } - VVA_ONLY( rc = ) sqlite3_step(pStmt); - assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) ); - return vacuumFinalize(db, pStmt, pzErrMsg); -} - -/* -** Execute zSql on database db. The statement returns exactly -** one column. Execute this as SQL on the same database. -*/ -static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ sqlite3_stmt *pStmt; int rc; - rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + /* printf("SQL: [%s]\n", zSql); fflush(stdout); */ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; - - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0)); - if( rc!=SQLITE_OK ){ - vacuumFinalize(db, pStmt, pzErrMsg); - return rc; + while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ + const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); + assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); + if( zSubSql ){ + assert( zSubSql[0]!='S' ); + rc = execSql(db, pzErrMsg, zSubSql); + if( rc!=SQLITE_OK ) break; } } - - return vacuumFinalize(db, pStmt, pzErrMsg); + assert( rc!=SQLITE_ROW ); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + if( rc ){ + sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); + } + (void)sqlite3_finalize(pStmt); + return rc; +} +static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){ + char *z; + va_list ap; + int rc; + va_start(ap, zSql); + z = sqlite3VMPrintf(db, zSql, ap); + va_end(ap); + if( z==0 ) return SQLITE_NOMEM; + rc = execSql(db, pzErrMsg, z); + sqlite3DbFree(db, z); + return rc; } /* @@ -117525,11 +126035,29 @@ static int execExecSql(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){ +SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){ Vdbe *v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0); - sqlite3VdbeUsesBtree(v, 0); + int iDb = 0; + if( v==0 ) return; + 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; +#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 + ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). + ** The buggy behavior is required for binary compatibility with some + ** legacy applications. */ + iDb = sqlite3FindDb(pParse->db, pNm); + if( iDb<0 ) iDb = 0; +#endif + } + if( iDb!=1 ){ + sqlite3VdbeAddOp1(v, OP_Vacuum, iDb); + sqlite3VdbeUsesBtree(v, iDb); } return; } @@ -117537,19 +126065,20 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){ /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ -SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ +SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ - char *zSql = 0; /* SQL statements */ - int saved_flags; /* Saved value of the db->flags */ + u16 saved_mDbFlags; /* Saved value of db->mDbFlags */ + u32 saved_flags; /* Saved value of db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ - void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */ + 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 */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); @@ -117564,14 +126093,17 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; + saved_mDbFlags = db->mDbFlags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; - saved_xTrace = db->xTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin; - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); - db->xTrace = 0; + 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->mTrace = 0; - pMain = db->aDb[0].pBt; + zDbMain = db->aDb[iDb].zDbSName; + pMain = db->aDb[iDb].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); /* Attach the temporary database as 'vacuum_db'. The synchronous pragma @@ -117589,18 +126121,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ ** to write the journal header file. */ nDb = db->nDb; - if( sqlite3TempInMemory(db) ){ - zSql = "ATTACH ':memory:' AS vacuum_db;"; - }else{ - zSql = "ATTACH '' AS vacuum_db;"; - } - rc = execSql(db, pzErrMsg, zSql); - if( db->nDb>nDb ){ - pDb = &db->aDb[db->nDb-1]; - assert( strcmp(pDb->zName,"vacuum_db")==0 ); - } + rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); if( rc!=SQLITE_OK ) goto end_of_vacuum; - pTemp = db->aDb[db->nDb-1].pBt; + 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 @@ -117616,19 +126142,20 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif - rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); - if( rc!=SQLITE_OK ) goto end_of_vacuum; + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); + sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); + sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL); /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ - rc = execSql(db, pzErrMsg, "BEGIN;"); + rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = sqlite3BtreeBeginTrans(pMain, 2); if( rc!=SQLITE_OK ) goto end_of_vacuum; @@ -117643,7 +126170,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) || NEVER(db->mallocFailed) ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; goto end_of_vacuum; } @@ -117655,64 +126182,48 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ - rc = execExecSql(db, pzErrMsg, - "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " - " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" - " AND coalesce(rootpage,1)>0" + db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='table'AND name<>'sqlite_sequence'" + " AND coalesce(rootpage,1)>0", + zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" - " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " - " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='index' AND length(sql)>10", + zDbMain + ); if( rc!=SQLITE_OK ) goto end_of_vacuum; + db->init.iDb = 0; /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ - assert( (db->flags & SQLITE_Vacuum)==0 ); - db->flags |= SQLITE_Vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'INSERT INTO vacuum_db.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) || ';'" - "FROM main.sqlite_master " - "WHERE type = 'table' AND name!='sqlite_sequence' " - " AND coalesce(rootpage,1)>0" + rc = execSqlF(db, pzErrMsg, + "SELECT'INSERT INTO vacuum_db.'||quote(name)" + "||' SELECT*FROM\"%w\".'||quote(name)" + "FROM vacuum_db.sqlite_master " + "WHERE type='table'AND coalesce(rootpage,1)>0", + zDbMain ); - assert( (db->flags & SQLITE_Vacuum)!=0 ); - db->flags &= ~SQLITE_Vacuum; + assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); + db->mDbFlags &= ~DBFLAG_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; - /* Copy over the sequence table - */ - rc = execExecSql(db, pzErrMsg, - "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " - "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' " - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'INSERT INTO vacuum_db.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) || ';' " - "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';" - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - - /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the SQLITE_MASTER table. */ - rc = execSql(db, pzErrMsg, - "INSERT INTO vacuum_db.sqlite_master " - " SELECT type, name, tbl_name, rootpage, sql" - " FROM main.sqlite_master" - " WHERE type='view' OR type='trigger'" - " OR (type='table' AND rootpage=0)" + rc = execSqlF(db, pzErrMsg, + "INSERT INTO vacuum_db.sqlite_master" + " SELECT*FROM \"%w\".sqlite_master" + " WHERE type IN('view','trigger')" + " OR(type='table'AND rootpage=0)", + zDbMain ); if( rc ) goto end_of_vacuum; @@ -117766,10 +126277,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ end_of_vacuum: /* Restore the original value of db->flags */ + db->init.iDb = 0; + db->mDbFlags = saved_mDbFlags; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; - db->xTrace = saved_xTrace; + db->mTrace = saved_mTrace; sqlite3BtreeSetPageSize(pMain, -1, -1, 1); /* Currently there is an SQL level transaction open on the vacuum @@ -117828,6 +126341,43 @@ struct VtabCtx { int bDeclared; /* True after sqlite3_declare_vtab() is called */ }; +/* +** Construct and install a Module object for a virtual table. When this +** routine is called, it is guaranteed that all appropriate locks are held +** and the module is not already part of the connection. +*/ +SQLITE_PRIVATE Module *sqlite3VtabCreateModule( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux, /* Context pointer for xCreate/xConnect */ + void (*xDestroy)(void *) /* Module destructor function */ +){ + Module *pMod; + int nName = sqlite3Strlen30(zName); + pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); + if( pMod==0 ){ + sqlite3OomFault(db); + }else{ + Module *pDel; + char *zCopy = (char *)(&pMod[1]); + memcpy(zCopy, zName, nName+1); + pMod->zName = zCopy; + pMod->pModule = pModule; + pMod->pAux = pAux; + pMod->xDestroy = xDestroy; + pMod->pEpoTab = 0; + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); + assert( pDel==0 || pDel==pMod ); + if( pDel ){ + sqlite3OomFault(db); + sqlite3DbFree(db, pDel); + pMod = 0; + } + } + return pMod; +} + /* ** The actual function that does the work of creating a new module. ** This function implements the sqlite3_create_module() and @@ -117841,35 +126391,15 @@ static int createModule( void (*xDestroy)(void *) /* Module destructor function */ ){ int rc = SQLITE_OK; - int nName; sqlite3_mutex_enter(db->mutex); - nName = sqlite3Strlen30(zName); if( sqlite3HashFind(&db->aModule, zName) ){ rc = SQLITE_MISUSE_BKPT; }else{ - Module *pMod; - pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); - if( pMod ){ - Module *pDel; - char *zCopy = (char *)(&pMod[1]); - memcpy(zCopy, zName, nName+1); - pMod->zName = zCopy; - pMod->pModule = pModule; - pMod->pAux = pAux; - pMod->xDestroy = xDestroy; - pMod->pEpoTab = 0; - pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); - assert( pDel==0 || pDel==pMod ); - if( pDel ){ - db->mallocFailed = 1; - sqlite3DbFree(db, pDel); - } - } + (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); } rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); - sqlite3_mutex_leave(db->mutex); return rc; } @@ -117878,7 +126408,7 @@ static int createModule( /* ** External API function used to create a new virtual-table module. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_module( +SQLITE_API int sqlite3_create_module( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ @@ -117893,7 +126423,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_module( /* ** External API function used to create a new virtual-table module. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2( +SQLITE_API int sqlite3_create_module_v2( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ @@ -118124,8 +126654,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); - pTable->tabFlags |= TF_Virtual; - pTable->nModuleArg = 0; + assert( pTable->nModuleArg==0 ); addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(db, pTable, 0); addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); @@ -118144,7 +126673,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( */ if( pTable->azModuleArg ){ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, - pTable->azModuleArg[0], pParse->db->aDb[iDb].zName); + pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } @@ -118208,7 +126737,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zDbSName, MASTER_NAME, pTab->zName, pTab->zName, zStmt, @@ -118218,7 +126747,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); - sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); + sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); @@ -118239,7 +126768,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ - db->mallocFailed = 1; + sqlite3OomFault(db); assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } @@ -118304,21 +126833,22 @@ static int vtabCallConstructor( } } - zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); + zModuleName = sqlite3DbStrDup(db, pTab->zName); if( !zModuleName ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } - pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); + pVTable = sqlite3MallocZero(sizeof(VTable)); if( !pVTable ){ + sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - pTab->azModuleArg[1] = db->aDb[iDb].zName; + pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); @@ -118330,7 +126860,7 @@ static int vtabCallConstructor( db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); db->pVtabCtx = sCtx.pPrior; - if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); assert( sCtx.pTab==pTab ); if( SQLITE_OK!=rc ){ @@ -118364,22 +126894,16 @@ static int vtabCallConstructor( pTab->pVTable = pVTable; for(iCol=0; iColnCol; iCol++){ - char *zType = pTab->aCol[iCol].zType; + char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); int nType; int i = 0; - if( !zType ){ - pTab->tabFlags |= oooHidden; - continue; - } nType = sqlite3Strlen30(zType); - if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){ - for(i=0; itabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){ + if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } @@ -118436,6 +126960,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); + pParse->rc = rc; } sqlite3DbFree(db, zErr); } @@ -118455,7 +126980,7 @@ static int growVTrans(sqlite3 *db){ int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); db->aVTrans = aVTrans; @@ -118478,7 +127003,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){ ** This function is invoked by the vdbe to call the xCreate method ** of the virtual table named zTab in database iDb. ** -** If an error occurs, *pzErr is set to point an an English language +** If an error occurs, *pzErr is set to point to an English language ** description of the error and an SQLITE_XXX error code is returned. ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr. */ @@ -118488,8 +127013,8 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, Module *pMod; const char *zMod; - pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); - assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable ); + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + assert( pTab && IsVirtual(pTab) && !pTab->pVTable ); /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; @@ -118523,12 +127048,12 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, ** valid to call this function from within the xCreate() or xConnect() of a ** virtual table module. */ -SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ +SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; - Parse *pParse; int rc = SQLITE_OK; Table *pTab; char *zErr = 0; + Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ @@ -118543,43 +127068,57 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCre return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; - assert( (pTab->tabFlags & TF_Virtual)!=0 ); + assert( IsVirtual(pTab) ); - pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); - if( pParse==0 ){ - rc = SQLITE_NOMEM; - }else{ - pParse->declareVtab = 1; - pParse->db = db; - pParse->nQueryLoop = 1; - - if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) - && pParse->pNewTable - && !db->mallocFailed - && !pParse->pNewTable->pSelect - && (pParse->pNewTable->tabFlags & TF_Virtual)==0 - ){ - if( !pTab->aCol ){ - pTab->aCol = pParse->pNewTable->aCol; - pTab->nCol = pParse->pNewTable->nCol; - pParse->pNewTable->nCol = 0; - pParse->pNewTable->aCol = 0; + memset(&sParse, 0, sizeof(sParse)); + sParse.declareVtab = 1; + sParse.db = db; + sParse.nQueryLoop = 1; + if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) + && sParse.pNewTable + && !db->mallocFailed + && !sParse.pNewTable->pSelect + && !IsVirtual(sParse.pNewTable) + ){ + if( !pTab->aCol ){ + Table *pNew = sParse.pNewTable; + Index *pIdx; + pTab->aCol = pNew->aCol; + pTab->nCol = pNew->nCol; + pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); + pNew->nCol = 0; + pNew->aCol = 0; + assert( pTab->pIndex==0 ); + assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 ); + if( !HasRowid(pNew) + && pCtx->pVTable->pMod->pModule->xUpdate!=0 + && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1 + ){ + /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0) + ** or else must have a single-column PRIMARY KEY */ + rc = SQLITE_ERROR; + } + pIdx = pNew->pIndex; + if( pIdx ){ + assert( pIdx->pNext==0 ); + pTab->pIndex = pIdx; + pNew->pIndex = 0; + pIdx->pTable = pTab; } - pCtx->bDeclared = 1; - }else{ - sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); - sqlite3DbFree(db, zErr); - rc = SQLITE_ERROR; } - pParse->declareVtab = 0; - - if( pParse->pVdbe ){ - sqlite3VdbeFinalize(pParse->pVdbe); - } - sqlite3DeleteTable(db, pParse->pNewTable); - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); + pCtx->bDeclared = 1; + }else{ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); + sqlite3DbFree(db, zErr); + rc = SQLITE_ERROR; } + sParse.declareVtab = 0; + + if( sParse.pVdbe ){ + sqlite3VdbeFinalize(sParse.pVdbe); + } + sqlite3DeleteTable(db, sParse.pNewTable); + sqlite3ParserReset(&sParse); assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); @@ -118598,8 +127137,8 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab int rc = SQLITE_OK; Table *pTab; - pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); - if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->pVTable; p; p=p->pNext){ @@ -118739,7 +127278,10 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ if( rc==SQLITE_OK ){ int iSvpt = db->nStatement + db->nSavepoint; addToVTrans(db, pVTab); - if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1); + if( iSvpt && pModule->xSavepoint ){ + pVTab->iSavepoint = iSvpt; + rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1); + } } } } @@ -118816,7 +127358,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( Table *pTab; sqlite3_vtab *pVtab; sqlite3_module *pMod; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0; + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0; void *pArg = 0; FuncDef *pNew; int rc = 0; @@ -118828,8 +127370,8 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->pTab; - if( NEVER(pTab==0) ) return pDef; - if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef; + if( pTab==0 ) return pDef; + if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); @@ -118844,7 +127386,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( for(z=(unsigned char*)zLowerName; *z; z++){ *z = sqlite3UpperToLower[*z]; } - rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg); + rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg); sqlite3DbFree(db, zLowerName); } if( rc==0 ){ @@ -118859,9 +127401,9 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( return pDef; } *pNew = *pDef; - pNew->zName = (char *)&pNew[1]; - memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1); - pNew->xFunc = xFunc; + pNew->zName = (const char*)&pNew[1]; + memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1); + pNew->xSFunc = xSFunc; pNew->pUserData = pArg; pNew->funcFlags |= SQLITE_FUNC_EPHEM; return pNew; @@ -118888,12 +127430,12 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ - pToplevel->db->mallocFailed = 1; + sqlite3OomFault(pToplevel->db); } } /* -** Check to see if virtual tale module pMod can be have an eponymous +** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if the eponymous virtual table instance exists ** when this routine returns, and return zero if it does not exist. @@ -118910,21 +127452,21 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ const sqlite3_module *pModule = pMod->pModule; Table *pTab; char *zErr = 0; - int nName; int rc; sqlite3 *db = pParse->db; if( pMod->pEpoTab ) return 1; if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; - nName = sqlite3Strlen30(pMod->zName) + 1; - pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName); + pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 0; + pTab->zName = sqlite3DbStrDup(db, pMod->zName); + if( pTab->zName==0 ){ + sqlite3DbFree(db, pTab); + return 0; + } pMod->pEpoTab = pTab; - pTab->zName = (char*)&pTab[1]; - memcpy(pTab->zName, pMod->zName, nName); - pTab->nRef = 1; + pTab->nTabRef = 1; pTab->pSchema = db->aDb[0].pSchema; - pTab->tabFlags |= TF_Virtual; - pTab->nModuleArg = 0; + assert( pTab->nModuleArg==0 ); pTab->iPKey = -1; addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(db, pTab, 0); @@ -118946,9 +127488,11 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ - sqlite3DeleteColumnNames(db, pTab); - sqlite3VtabClear(db, pTab); - sqlite3DbFree(db, pTab); + /* Mark the table as Ephemeral prior to deleting it, so that the + ** sqlite3DeleteTable() routine will know that it is not stored in + ** the schema. */ + pTab->tabFlags |= TF_Ephemeral; + sqlite3DeleteTable(db, pTab); pMod->pEpoTab = 0; } } @@ -118960,7 +127504,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ ** The results of this routine are undefined unless it is called from ** within an xUpdate method. */ -SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){ +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ static const unsigned char aMap[] = { SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE }; @@ -118978,7 +127522,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){ ** the SQLite core with additional information about the behavior ** of the virtual table being implemented. */ -SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){ +SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; @@ -118993,7 +127537,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){ if( !p ){ rc = SQLITE_MISUSE_BKPT; }else{ - assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 ); + assert( p->pTab==0 || IsVirtual(p->pTab) ); p->pVTable->bConstraint = (u8)va_arg(ap, int); } break; @@ -119107,7 +127651,7 @@ struct WhereLevel { int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS - int iLikeRepCntr; /* LIKE range processing counter register */ + u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif u8 iFrom; /* Which entry in the FROM clause */ @@ -119159,6 +127703,9 @@ struct WhereLoop { union { struct { /* Information for internal btree tables */ u16 nEq; /* Number of equality constraints */ + u16 nBtm; /* Size of BTM vector */ + u16 nTop; /* Size of TOP vector */ + u16 nIdxCol; /* Index column used for ORDER BY */ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ @@ -119281,19 +127828,20 @@ struct WherePath { */ struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ + WhereClause *pWC; /* The clause this term is part of */ + LogEst truthProb; /* Probability of truth for this expression */ + u16 wtFlags; /* TERM_xxx bit flags. See below */ + u16 eOperator; /* A WO_xx value describing */ + u8 nChild; /* Number of children that must disable us */ + u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X " */ + int iField; /* Field in (?,?,?) IN (SELECT...) vector */ union { int leftColumn; /* Column number of X in "X " */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; - LogEst truthProb; /* Probability of truth for this expression */ - u16 eOperator; /* A WO_xx value describing */ - u16 wtFlags; /* TERM_xxx bit flags. See below */ - u8 nChild; /* Number of children that must disable us */ - u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ - WhereClause *pWC; /* The clause this term is part of */ Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ }; @@ -119317,6 +127865,7 @@ struct WhereTerm { #define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ #define TERM_LIKE 0x400 /* The original LIKE operator */ #define TERM_IS 0x800 /* Term.pExpr is an IS operator */ +#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */ /* ** An instance of the WhereScan object is used as an iterator for locating @@ -119406,6 +127955,7 @@ struct WhereAndInfo { ** no gaps. */ struct WhereMaskSet { + int bVarSelect; /* Used by sqlite3WhereExprUsage() */ int n; /* Number of assigned cursor values */ int ix[BMS]; /* Cursor assigned to each bit */ }; @@ -119429,8 +127979,13 @@ struct WhereLoopBuilder { UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif + unsigned int bldFlags; /* SQLITE_BLDF_* flags */ }; +/* 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 WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second @@ -119445,24 +128000,27 @@ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ - ExprList *pResultSet; /* Result set. DISTINCT operates on these */ - WhereLoop *pLoops; /* List of all WhereLoop objects */ - Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ - LogEst nRowOut; /* Estimated number of output rows */ + ExprList *pResultSet; /* Result set of the query */ + Expr *pWhere; /* The complete WHERE clause */ + LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ + int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ + int iContinue; /* Jump here to continue with next record */ + int iBreak; /* Jump here to break out of the loop */ + int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + u8 nLevel; /* Number of nested loop */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ - u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ - u8 nLevel; /* Number of nested loop */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ + u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ int iTop; /* The very beginning of the WHERE loop */ - int iContinue; /* Jump here to continue with next record */ - int iBreak; /* Jump here to break out of the loop */ - int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ - int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ - WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ + WhereLoop *pLoops; /* List of all WhereLoop objects */ + Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ + LogEst nRowOut; /* Estimated number of output rows */ WhereClause sWC; /* Decomposition of the WHERE clause */ + WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; @@ -119472,6 +128030,9 @@ struct WhereInfo { ** where.c: */ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); +#ifdef WHERETRACE_ENABLED +SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); +#endif SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ @@ -119528,6 +128089,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC ** operators that are of interest to the query planner. An ** OR-ed combination of these values can be used when searching for ** particular WhereTerms within a WhereClause. +** +** Value constraints: +** WO_EQ == SQLITE_INDEX_CONSTRAINT_EQ +** WO_LT == SQLITE_INDEX_CONSTRAINT_LT +** WO_LE == SQLITE_INDEX_CONSTRAINT_LE +** WO_GT == SQLITE_INDEX_CONSTRAINT_GT +** WO_GE == SQLITE_INDEX_CONSTRAINT_GE */ #define WO_IN 0x0001 #define WO_EQ 0x0002 @@ -119535,7 +128103,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) -#define WO_MATCH 0x0040 +#define WO_AUX 0x0040 /* Op useful to virtual tables only */ #define WO_IS 0x0080 #define WO_ISNULL 0x0100 #define WO_OR 0x0200 /* Two or more OR-connected terms */ @@ -119575,6 +128143,17 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC /************** Continuing where we left off in wherecode.c ******************/ #ifndef SQLITE_OMIT_EXPLAIN + +/* +** Return the name of the i-th column of the pIdx index. +*/ +static const char *explainIndexColumnName(Index *pIdx, int i){ + i = pIdx->aiColumn[i]; + if( i==XN_EXPR ) return ""; + if( i==XN_ROWID ) return "rowid"; + return pIdx->pTable->aCol[i].zName; +} + /* ** This routine is a helper for explainIndexRange() below ** @@ -119585,24 +128164,32 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC */ static void explainAppendTerm( StrAccum *pStr, /* The text expression being built */ - int iTerm, /* Index of this term. First is zero */ - const char *zColumn, /* Name of the column */ + Index *pIdx, /* Index to read column names from */ + int nTerm, /* Number of terms */ + int iTerm, /* Zero-based index of first term. */ + int bAnd, /* Non-zero to append " AND " */ const char *zOp /* Name of the operator */ ){ - if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5); - sqlite3StrAccumAppendAll(pStr, zColumn); - sqlite3StrAccumAppend(pStr, zOp, 1); - sqlite3StrAccumAppend(pStr, "?", 1); -} + int i; -/* -** Return the name of the i-th column of the pIdx index. -*/ -static const char *explainIndexColumnName(Index *pIdx, int i){ - i = pIdx->aiColumn[i]; - if( i==XN_EXPR ) return ""; - if( i==XN_ROWID ) return "rowid"; - return pIdx->pTable->aCol[i].zName; + assert( nTerm>=1 ); + if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5); + + if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); + + sqlite3StrAccumAppend(pStr, zOp, 1); + + if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); } /* @@ -119630,17 +128217,16 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ for(i=0; i=nSkip ? "%s=?" : "ANY(%s)", z); + sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z); } j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ - const char *z = explainIndexColumnName(pIndex, i); - explainAppendTerm(pStr, i++, z, ">"); + explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">"); + i = 1; } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ - const char *z = explainIndexColumnName(pIndex, j); - explainAppendTerm(pStr, i, z, "<"); + explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<"); } sqlite3StrAccumAppend(pStr, ")", 1); } @@ -119680,7 +128266,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) @@ -119689,13 +128275,13 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ - sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); + sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId); }else{ - sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); + sqlite3XPrintf(&str, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ - sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); + sqlite3XPrintf(&str, " AS %s", pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; @@ -119719,7 +128305,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( } if( zFmt ){ sqlite3StrAccumAppend(&str, " USING ", 7); - sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); + sqlite3XPrintf(&str, zFmt, pIdx->zName); explainIndexRange(&str, pLoop); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ @@ -119734,17 +128320,17 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( assert( flags&WHERE_TOP_LIMIT); zRangeOp = "<"; } - sqlite3XPrintf(&str, 0, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); + sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ - sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s", + sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ - sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3StrAccumAppend(&str, " (~1 row)", 9); } @@ -119830,7 +128416,7 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; - while( pTerm + while( ALWAYS(pTerm!=0) && (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (pLevel->notReady & pTerm->prereqAll)==0 @@ -119881,22 +128467,50 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ - sqlite3VdbeAddOp2(v, OP_Affinity, base, n); - sqlite3VdbeChangeP4(v, -1, zAff, n); + sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); sqlite3ExprCacheAffinityChange(pParse, base, n); } } +/* +** Expression pRight, which is the RHS of a comparison operation, is +** either a vector of n elements or, if n==1, a scalar expression. +** Before the comparison operation, affinity zAff is to be applied +** to the pRight values. This function modifies characters within the +** affinity string to SQLITE_AFF_BLOB if either: +** +** * the comparison will be performed with no affinity, or +** * the affinity change in zAff is guaranteed not to change the value. +*/ +static void updateRangeAffinityStr( + Expr *pRight, /* RHS of comparison */ + int n, /* Number of vector elements in comparison */ + char *zAff /* Affinity string to modify */ +){ + int i; + for(i=0; ipVdbe; int iReg; /* Register holding results */ + assert( pLevel->pWLoop->aLTerm[iEq]==pTerm ); assert( iTarget>0 ); if( pX->op==TK_EQ || pX->op==TK_IS ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); @@ -119919,10 +128534,13 @@ static int codeEqualityTerm( sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ - int eType; + int eType = IN_INDEX_NOOP; int iTab; struct InLoop *pIn; WhereLoop *pLoop = pLevel->pWLoop; + int i; + int nEq = 0; + int *aiMap = 0; if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 @@ -119934,7 +128552,78 @@ static int codeEqualityTerm( } assert( pX->op==TK_IN ); iReg = iTarget; - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0); + + for(i=0; iaLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){ + disableTerm(pLevel, pTerm); + return iTarget; + } + } + for(i=iEq;inLTerm; i++){ + if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++; + } + + if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0); + }else{ + Select *pSelect = pX->x.pSelect; + sqlite3 *db = pParse->db; + u16 savedDbOptFlags = db->dbOptFlags; + ExprList *pOrigRhs = pSelect->pEList; + ExprList *pOrigLhs = pX->pLeft->x.pList; + ExprList *pRhs = 0; /* New Select.pEList for RHS */ + ExprList *pLhs = 0; /* New pX->pLeft vector */ + + for(i=iEq;inLTerm; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + int iField = pLoop->aLTerm[i]->iField - 1; + Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0); + Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0); + + pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs); + pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs); + } + } + if( !db->mallocFailed ){ + Expr *pLeft = pX->pLeft; + + if( pSelect->pOrderBy ){ + /* If the SELECT statement has an ORDER BY clause, zero the + ** iOrderByCol variables. These are set to non-zero when an + ** ORDER BY term exactly matches one of the terms of the + ** result-set. Since the result-set of the SELECT statement may + ** have been modified or reordered, these variables are no longer + ** set correctly. Since setting them is just an optimization, + ** it's easiest just to zero them here. */ + ExprList *pOrderBy = pSelect->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } + } + + /* Take care here not to generate a TK_VECTOR containing only a + ** single value. Since the parser never creates such a vector, some + ** of the subroutines do not handle this case. */ + if( pLhs->nExpr==1 ){ + pX->pLeft = pLhs->a[0].pExpr; + }else{ + pLeft->x.pList = pLhs; + aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq); + testcase( aiMap==0 ); + } + pSelect->pEList = pRhs; + db->dbOptFlags |= SQLITE_QueryFlattener; + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap); + db->dbOptFlags = savedDbOptFlags; + testcase( aiMap!=0 && aiMap[0]!=0 ); + pSelect->pEList = pOrigRhs; + pLeft->x.pList = pOrigLhs; + pX->pLeft = pLeft; + } + sqlite3ExprListDelete(pParse->db, pLhs); + sqlite3ExprListDelete(pParse->db, pRhs); + } + if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; @@ -119944,28 +128633,45 @@ static int codeEqualityTerm( VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } - pLevel->u.in.nIn++; + + i = pLevel->u.in.nIn; + pLevel->u.in.nIn += nEq; pLevel->u.in.aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); pIn = pLevel->u.in.aInLoop; if( pIn ){ - pIn += pLevel->u.in.nIn - 1; - pIn->iCur = iTab; - if( eType==IN_INDEX_ROWID ){ - pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); - }else{ - pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); + int iMap = 0; /* Index in aiMap[] */ + pIn += i; + for(i=iEq;inLTerm; i++){ + 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; + pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut); + } + sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); + if( i==iEq ){ + pIn->iCur = iTab; + pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; + }else{ + pIn->eEndLoopOp = OP_Noop; + } + pIn++; + } } - pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; - sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v); }else{ pLevel->u.in.nIn = 0; } + sqlite3DbFree(pParse->db, aiMap); #endif } disableTerm(pLevel, pTerm); @@ -120050,9 +128756,7 @@ static int codeAllEqualityTerms( pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); - if( !zAff ){ - pParse->db->mallocFailed = 1; - } + assert( zAff!=0 || pParse->db->mallocFailed ); if( nSkip ){ int iIdxCur = pLevel->iIdxCur; @@ -120093,9 +128797,15 @@ static int codeAllEqualityTerms( sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); } } - testcase( pTerm->eOperator & WO_ISNULL ); - testcase( pTerm->eOperator & WO_IN ); - if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ + if( pTerm->eOperator & WO_IN ){ + if( pTerm->pExpr->flags & EP_xIsSelect ){ + /* No affinity ever needs to be (or should be) applied to a value + ** from the RHS of an "? IN (SELECT ...)" expression. The + ** sqlite3FindInIndex() routine has already ensured that the + ** affinity of the comparison has been applied to the value. */ + if( zAff ) zAff[j] = SQLITE_AFF_BLOB; + } + }else if( (pTerm->eOperator & WO_ISNULL)==0 ){ Expr *pRight = pTerm->pExpr->pRight; if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); @@ -120117,15 +128827,16 @@ static int codeAllEqualityTerms( #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS /* -** If the most recently coded instruction is a constant range contraint -** that originated from the LIKE optimization, then change the P3 to be -** pLoop->iLikeRepCntr and set P5. +** If the most recently coded instruction is a constant range constraint +** (a string literal) that originated from the LIKE optimization, then +** set P3 and P5 on the OP_String opcode so that the string will be cast +** to a BLOB at appropriate times. ** ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range ** expression: "x>='ABC' AND x<'abd'". But this requires that the range ** scan loop run twice, once for strings and a second time for BLOBs. ** The OP_String opcodes on the second pass convert the upper and lower -** bound string contants to blobs. This routine makes the necessary changes +** bound string constants to blobs. This routine makes the necessary changes ** to the OP_String opcodes for that to happen. ** ** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then @@ -120144,8 +128855,8 @@ static void whereLikeOptimizationStringFixup( assert( pOp!=0 ); assert( pOp->opcode==OP_String8 || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); - pOp->p3 = pLevel->iLikeRepCntr; - pOp->p5 = 1; + pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ + pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ } } #else @@ -120182,6 +128893,38 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } +/* +** Test whether or not expression pExpr, which was part of a WHERE clause, +** should be included in the cursor-hint for a table that is on the rhs +** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the +** expression is not suitable. +** +** An expression is unsuitable if it might evaluate to non NULL even if +** a TK_COLUMN node that does affect the value of the expression is set +** to NULL. For example: +** +** col IS NULL +** col IS NOT NULL +** coalesce(col, 1) +** CASE WHEN col THEN 0 ELSE 1 END +*/ +static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_IS + || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT + || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE + ){ + pWalker->eCode = 1; + }else if( pExpr->op==TK_FUNCTION ){ + int d1; + char d2[4]; + if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ + pWalker->eCode = 1; + } + } + + return WRC_Continue; +} + /* ** This function is called on every node of an expression tree used as an @@ -120234,6 +128977,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( + struct SrcList_item *pTabItem, /* FROM clause item */ WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ @@ -120264,7 +129008,42 @@ static void codeCursorHint( pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + + /* Any terms specified as part of the ON(...) clause for any LEFT + ** JOIN for which the current table is not the rhs are omitted + ** from the cursor-hint. + ** + ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms + ** that were specified as part of the WHERE clause must be excluded. + ** This is to address the following: + ** + ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; + ** + ** Say there is a single row in t2 that matches (t1.a=t2.b), but its + ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is + ** pushed down to the cursor, this row is filtered out, causing + ** SQLite to synthesize a row of NULL values. Which does match the + ** WHERE clause, and so the query returns a row. Which is incorrect. + ** + ** For the same reason, WHERE terms such as: + ** + ** WHERE 1 = (t2.c IS NULL) + ** + ** are also excluded. See codeCursorHintIsOrFunction() for details. + */ + if( pTabItem->fg.jointype & JT_LEFT ){ + Expr *pExpr = pTerm->pExpr; + if( !ExprHasProperty(pExpr, EP_FromJoin) + || pExpr->iRightJoinTable!=pTabItem->iCursor + ){ + sWalker.eCode = 0; + sWalker.xExprCallback = codeCursorHintIsOrFunction; + sqlite3WalkExpr(&sWalker, pTerm->pExpr); + if( sWalker.eCode ) continue; + } + }else{ + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + } /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize ** the cursor. These terms are not needed as hints for a pure range @@ -120298,9 +129077,153 @@ static void codeCursorHint( } } #else -# define codeCursorHint(A,B,C) /* No-op */ +# define codeCursorHint(A,B,C,D) /* No-op */ #endif /* SQLITE_ENABLE_CURSOR_HINTS */ +/* +** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains +** a rowid value just read from cursor iIdxCur, open on index pIdx. This +** function generates code to do a deferred seek of cursor iCur to the +** rowid stored in register iRowid. +** +** Normally, this is just: +** +** OP_DeferredSeek $iCur $iRowid +** +** However, if the scan currently being coded is a branch of an OR-loop and +** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek +** is set to iIdxCur and P4 is set to point to an array of integers +** containing one entry for each column of the table cursor iCur is open +** on. For each table column, if the column is the i'th column of the +** index, then the corresponding array entry is set to (i+1). If the column +** does not appear in the index at all, the array entry is set to 0. +*/ +static void codeDeferredSeek( + WhereInfo *pWInfo, /* Where clause context */ + Index *pIdx, /* Index scan is using */ + int iCur, /* Cursor for IPK b-tree */ + int iIdxCur /* Index cursor */ +){ + Parse *pParse = pWInfo->pParse; /* Parse context */ + Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ + + assert( iIdxCur>0 ); + assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); + + sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); + if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) + && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) + ){ + int i; + Table *pTab = pIdx->pTable; + int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); + if( ai ){ + ai[0] = pTab->nCol; + for(i=0; inColumn-1; i++){ + assert( pIdx->aiColumn[i]nCol ); + if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1; + } + sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); + } + } +} + +/* +** If the expression passed as the second argument is a vector, generate +** code to write the first nReg elements of the vector into an array +** of registers starting with iReg. +** +** If the expression is not a vector, then nReg must be passed 1. In +** this case, generate code to evaluate the expression and leave the +** result in register iReg. +*/ +static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ + assert( nReg>0 ); + if( p && sqlite3ExprIsVector(p) ){ +#ifndef SQLITE_OMIT_SUBQUERY + if( (p->flags & EP_xIsSelect) ){ + Vdbe *v = pParse->pVdbe; + int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0); + sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); + }else +#endif + { + int i; + ExprList *pList = p->x.pList; + assert( nReg<=pList->nExpr ); + for(i=0; ia[i].pExpr, iReg+i); + } + } + }else{ + assert( nReg==1 ); + sqlite3ExprCode(pParse, p, iReg); + } +} + +/* An instance of the IdxExprTrans object carries information about a +** mapping from an expression on table columns into a column in an index +** down through the Walker. +*/ +typedef struct IdxExprTrans { + Expr *pIdxExpr; /* The index expression */ + int iTabCur; /* The cursor of the corresponding table */ + int iIdxCur; /* The cursor for the index */ + int iIdxCol; /* The column for the index */ +} IdxExprTrans; + +/* The walker node callback used to transform matching expressions into +** a reference to an index column for an index on an expression. +** +** If pExpr matches, then transform it into a reference to the index column +** that contains the value of pExpr. +*/ +static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ + IdxExprTrans *pX = p->u.pIdxTrans; + if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ + pExpr->op = TK_COLUMN; + pExpr->iTable = pX->iIdxCur; + pExpr->iColumn = pX->iIdxCol; + pExpr->pTab = 0; + return WRC_Prune; + }else{ + return WRC_Continue; + } +} + +/* +** For an indexes on expression X, locate every instance of expression X +** in pExpr and change that subexpression into a reference to the appropriate +** column of the index. +*/ +static void whereIndexExprTrans( + Index *pIdx, /* The Index */ + int iTabCur, /* Cursor of the table that is being indexed */ + int iIdxCur, /* Cursor of the index itself */ + WhereInfo *pWInfo /* Transform expressions in this WHERE clause */ +){ + int iIdxCol; /* Column number of the index */ + ExprList *aColExpr; /* Expressions that are indexed */ + Walker w; + IdxExprTrans x; + aColExpr = pIdx->aColExpr; + if( aColExpr==0 ) return; /* Not an index on expressions */ + memset(&w, 0, sizeof(w)); + w.xExprCallback = whereIndexExprTransNode; + w.u.pIdxTrans = &x; + x.iTabCur = iTabCur; + x.iIdxCur = iIdxCur; + for(iIdxCol=0; iIdxColnExpr; iIdxCol++){ + if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue; + assert( aColExpr->a[iIdxCol].pExpr!=0 ); + x.iIdxCol = iIdxCol; + x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; + sqlite3WalkExpr(&w, pWInfo->pWhere); + sqlite3WalkExprList(&w, pWInfo->pOrderBy); + sqlite3WalkExprList(&w, pWInfo->pResultSet); + } +} + /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. @@ -120324,9 +129247,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( 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 */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ + Index *pIdx = 0; /* Index used by loop (if any) */ + int iLoop; /* Iteration of constraint generator loop */ pParse = pWInfo->pParse; v = pParse->pVdbe; @@ -120339,7 +129265,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==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 @@ -120365,6 +129291,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeComment((v, "init LEFT JOIN no-match flag")); } + /* Compute a safe address to jump to if we discover that the table for + ** this loop is empty and can never contribute content. */ + for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){} + addrHalt = pWInfo->a[j].addrBrk; + /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; @@ -120383,6 +129314,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; int nConstraint = pLoop->nLTerm; + int iIn; /* Counter for IN constraints */ sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); @@ -120390,30 +129322,73 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( for(j=0; jaLTerm[j]; - if( pTerm==0 ) continue; + if( NEVER(pTerm==0) ) continue; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; }else{ - sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); + Expr *pRight = pTerm->pExpr->pRight; + codeExprOrVector(pParse, pRight, iTarget, 1); } } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, - pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); + pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); VdbeCoverage(v); pLoop->u.vtab.needFree = 0; - for(j=0; ju.vtab.omitMask>>j)&1 ){ - disableTerm(pLevel, pLoop->aLTerm[j]); - } - } pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); - sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + iIn = pLevel->u.in.nIn; + for(j=nConstraint-1; j>=0; j--){ + pTerm = pLoop->aLTerm[j]; + if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ + disableTerm(pLevel, pTerm); + }else if( (pTerm->eOperator & WO_IN)!=0 ){ + Expr *pCompare; /* The comparison operator */ + Expr *pRight; /* RHS of the comparison */ + VdbeOp *pOp; /* Opcode to access the value of the IN constraint */ + + /* Reload the constraint value into reg[iReg+j+2]. The same value + ** was loaded into the same register prior to the OP_VFilter, but + ** the xFilter implementation might have changed the datatype or + ** encoding of the value in the register, so it *must* be reloaded. */ + assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed ); + if( !db->mallocFailed ){ + assert( iIn>0 ); + pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop); + assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid ); + assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 ); + assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 ); + testcase( pOp->opcode==OP_Rowid ); + sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); + } + + /* Generate code that will continue to the next row if + ** the IN constraint is not satisfied */ + pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0); + assert( pCompare!=0 || db->mallocFailed ); + if( pCompare ){ + pCompare->pLeft = pTerm->pExpr->pLeft; + pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0); + if( pRight ){ + pRight->iTable = iReg+j+2; + sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0); + } + pCompare->pLeft = 0; + sqlite3ExprDelete(db, pCompare); + } + } + } + /* These registers need to be preserved in case there is an IN operator + ** loop. So we could deallocate the registers here (and potentially + ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems + ** simpler and safer to simply not reuse the registers. + ** + ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + */ sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -120436,8 +129411,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; - sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); @@ -120464,10 +129438,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pStart = pEnd; pEnd = pTerm; } - codeCursorHint(pWInfo, pLevel, pEnd); + codeCursorHint(pTabItem, pWInfo, pLevel, pEnd); if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ + int op; /* Cursor seek operation */ /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx @@ -120487,8 +129462,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pX = pStart->pExpr; assert( pX!=0 ); testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ - r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); - sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); + if( sqlite3ExprIsVector(pX->pRight) ){ + r1 = rTemp = sqlite3GetTempReg(pParse); + codeExprOrVector(pParse, pX->pRight, r1, 1); + op = aMoveOp[(pX->op - TK_GT) | 0x0001]; + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); + disableTerm(pLevel, pStart); + op = aMoveOp[(pX->op - TK_GT)]; + } + sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); VdbeComment((v, "pk")); VdbeCoverageIf(v, pX->op==TK_GT); VdbeCoverageIf(v, pX->op==TK_LE); @@ -120496,9 +129479,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverageIf(v, pX->op==TK_GE); sqlite3ExprCacheAffinityChange(pParse, r1, 1); sqlite3ReleaseTempReg(pParse, rTemp); - disableTerm(pLevel, pStart); }else{ - sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk); + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); } @@ -120510,13 +129492,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ testcase( pEnd->wtFlags & TERM_VIRTUAL ); memEndValue = ++pParse->nMem; - sqlite3ExprCode(pParse, pX->pRight, memEndValue); - if( pX->op==TK_LT || pX->op==TK_GT ){ + codeExprOrVector(pParse, pX->pRight, memEndValue, 1); + if( 0==sqlite3ExprIsVector(pX->pRight) + && (pX->op==TK_LT || pX->op==TK_GT) + ){ testOp = bRev ? OP_Le : OP_Ge; }else{ testOp = bRev ? OP_Lt : OP_Gt; } - disableTerm(pLevel, pEnd); + if( 0==sqlite3ExprIsVector(pX->pRight) ){ + disableTerm(pLevel, pEnd); + } } start = sqlite3VdbeCurrentAddr(v); pLevel->op = bRev ? OP_Prev : OP_Next; @@ -120583,6 +129569,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */ }; u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ + u16 nBtm = pLoop->u.btree.nBtm; /* Length of BTM vector */ + u16 nTop = pLoop->u.btree.nTop; /* Length of TOP vector */ int regBase; /* Base register holding constraint values */ WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */ @@ -120590,12 +129578,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int endEq; /* True if range end uses ==, >= or <= */ int start_constraints; /* Start of range is constrained */ int nConstraint; /* Number of constraint terms */ - Index *pIdx; /* The index we will be using */ int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ char *zStartAff; /* Affinity for start of range constraint */ - char cEndAff = 0; /* Affinity for end of range constraint */ + 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 */ @@ -120629,33 +129616,36 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( j = nEq; if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ pRangeStart = pLoop->aLTerm[j++]; - nExtraReg = 1; + nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm); /* Like optimization range constraints always occur in pairs */ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 ); } if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = pLoop->aLTerm[j++]; - nExtraReg = 1; + nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop); #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ assert( pRangeStart!=0 ); /* LIKE opt constraints */ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ - pLevel->iLikeRepCntr = ++pParse->nMem; - testcase( bRev ); - testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); - sqlite3VdbeAddOp2(v, OP_Integer, - bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), - pLevel->iLikeRepCntr); + pLevel->iLikeRepCntr = (u32)++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr); VdbeComment((v, "LIKE loop counter")); pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); + /* iLikeRepCntr actually stores 2x the counter register number. The + ** bottom bit indicates whether the search order is ASC or DESC. */ + testcase( bRev ); + testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); + assert( (bRev & ~1)==0 ); + pLevel->iLikeRepCntr <<=1; + pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC); } #endif - if( pRangeStart==0 - && (j = pIdx->aiColumn[nEq])>=0 - && pIdx->pTable->aCol[j].notNull==0 - ){ - bSeekPastNull = 1; + if( pRangeStart==0 ){ + j = pIdx->aiColumn[nEq]; + if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ + bSeekPastNull = 1; + } } } assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); @@ -120669,16 +129659,19 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); + SWAP(u8, nBtm, nTop); } /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ - codeCursorHint(pWInfo, pLevel, pRangeEnd); + codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); - if( zStartAff ) cEndAff = zStartAff[nEq]; + if( zStartAff && nTop ){ + zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); + } addrNxt = pLevel->addrNxt; testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); @@ -120693,7 +129686,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; - sqlite3ExprCode(pParse, pRight, regBase+nEq); + codeExprOrVector(pParse, pRight, regBase+nEq, nBtm); whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); if( (pRangeStart->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) @@ -120702,18 +129695,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverage(v); } if( zStartAff ){ - if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){ - /* Since the comparison is to be performed with no conversions - ** applied to the operands, set the affinity to apply to pRight to - ** SQLITE_AFF_BLOB. */ - zStartAff[nEq] = SQLITE_AFF_BLOB; - } - if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ - zStartAff[nEq] = SQLITE_AFF_BLOB; - } + updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]); } - nConstraint++; + nConstraint += nBtm; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); + if( sqlite3ExprIsVector(pRight)==0 ){ + disableTerm(pLevel, pRangeStart); + }else{ + startEq = 1; + } + bSeekPastNull = 0; }else if( bSeekPastNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; @@ -120721,16 +129712,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( start_constraints = 1; } codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); - op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; - assert( op!=0 ); - sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); - VdbeCoverage(v); - VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); - VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); - VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); - VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); - VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); - VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); + if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ + /* The skip-scan logic inside the call to codeAllEqualityConstraints() + ** above has already left the cursor sitting on the correct row, + ** so no further seeking is needed */ + }else{ + op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; + assert( op!=0 ); + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); + VdbeCoverage(v); + VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); + VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); + VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); + VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); + VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); + VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); + } /* Load the value for the inequality constraint at the end of the ** range (if any). @@ -120739,7 +129736,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); - sqlite3ExprCode(pParse, pRight, regBase+nEq); + codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) @@ -120747,19 +129744,27 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); VdbeCoverage(v); } - if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB - && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff) - ){ - codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff); + if( zEndAff ){ + updateRangeAffinityStr(pRight, nTop, zEndAff); + codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff); + }else{ + assert( pParse->db->mallocFailed ); } - nConstraint++; + nConstraint += nTop; testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); + + if( sqlite3ExprIsVector(pRight)==0 ){ + disableTerm(pLevel, pRangeEnd); + }else{ + endEq = 1; + } }else if( bStopAtNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); endEq = 0; nConstraint++; } sqlite3DbFree(db, zStartAff); + sqlite3DbFree(db, zEndAff); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); @@ -120775,19 +129780,20 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } /* Seek the table cursor, if required */ - disableTerm(pLevel, pRangeStart); - disableTerm(pLevel, pRangeEnd); if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ - iRowidReg = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - if( pWInfo->eOnePass!=ONEPASS_OFF ){ + if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || ( + (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) + && (pWInfo->eOnePass==ONEPASS_SINGLE) + )){ + iRowidReg = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); VdbeCoverage(v); }else{ - sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ + codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); } }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); @@ -120800,9 +129806,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( iRowidReg, pPk->nKeyCol); VdbeCoverage(v); } - /* Record the instruction used to terminate the loop. Disable - ** WHERE clause terms made redundant by the index range scan. + /* If pIdx is an index on one or more expressions, then look through + ** all the expressions in pWInfo and try to transform matching expressions + ** into reference to index columns. */ + whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); + + + /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; }else if( bRev ){ @@ -120817,6 +129828,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( }else{ assert( pLevel->p5==0 ); } + if( omitTable ) pIdx = 0; }else #ifndef SQLITE_OMIT_OR_OPTIMIZATION @@ -120879,7 +129891,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( u16 wctrlFlags; /* Flags for sub-WHERE clause */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Table *pTab = pTabItem->pTab; - + pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); @@ -120956,14 +129968,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( Expr *pExpr = pWC->a[iTerm].pExpr; if( &pWC->a[iTerm] == pTerm ) continue; if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; - if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue; + testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); + testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); + if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; 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); } if( pAndExpr ){ - pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr, 0); + pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr); } } @@ -120971,10 +129985,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OMIT_OPEN_CLOSE - | WHERE_FORCE_TABLE - | WHERE_ONETABLE_ONLY - | WHERE_NO_AUTOINDEX; + wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ @@ -121039,7 +130050,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } if( iSet>=0 ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); - sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid, + r, nPk); if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); } @@ -121082,7 +130094,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; - wctrlFlags |= WHERE_REOPEN_IDX; }else{ pCov = 0; } @@ -121119,10 +130130,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ - codeCursorHint(pWInfo, pLevel, 0); + codeCursorHint(pTabItem, pWInfo, pLevel, 0); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; - pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); + pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; @@ -121135,37 +130146,75 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. + ** + ** This loop may run between one and three times, depending on the + ** constraints to be generated. The value of stack variable iLoop + ** determines the constraints coded by each iteration, as follows: + ** + ** iLoop==1: Code only expressions that are entirely covered by pIdx. + ** iLoop==2: Code remaining expressions that do not contain correlated + ** sub-queries. + ** iLoop==3: Code all remaining expressions. + ** + ** An effort is made to skip unnecessary iterations of the loop. */ - for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ - Expr *pE; - int skipLikeAddr = 0; - testcase( pTerm->wtFlags & TERM_VIRTUAL ); - testcase( pTerm->wtFlags & TERM_CODED ); - if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ - testcase( pWInfo->untestedTerms==0 - && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); - pWInfo->untestedTerms = 1; - continue; - } - pE = pTerm->pExpr; - assert( pE!=0 ); - if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ - continue; - } - if( pTerm->wtFlags & TERM_LIKECOND ){ + iLoop = (pIdx ? 1 : 2); + do{ + int iNext = 0; /* Next value for iLoop */ + for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ + Expr *pE; + int skipLikeAddr = 0; + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + testcase( pTerm->wtFlags & TERM_CODED ); + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + testcase( pWInfo->untestedTerms==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); + pWInfo->untestedTerms = 1; + continue; + } + pE = pTerm->pExpr; + assert( pE!=0 ); + if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ + continue; + } + + if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ + iNext = 2; + continue; + } + if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){ + if( iNext==0 ) iNext = 3; + continue; + } + + if( pTerm->wtFlags & TERM_LIKECOND ){ + /* If the TERM_LIKECOND flag is set, that means that the range search + ** is sufficient to guarantee that the LIKE operator is true, so we + ** can skip the call to the like(A,B) function. But this only works + ** for strings. So do not skip the call to the function on the pass + ** that compares BLOBs. */ #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS - continue; + continue; #else - assert( pLevel->iLikeRepCntr>0 ); - skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); - VdbeCoverage(v); + u32 x = pLevel->iLikeRepCntr; + assert( x>0 ); + skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1)); + VdbeCoverage(v); #endif + } +#ifdef WHERETRACE_ENABLED /* 0xffff */ + if( sqlite3WhereTrace ){ + VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d", + pWC->nTerm-j, pTerm, iLoop)); + } +#endif + sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); + if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); + pTerm->wtFlags |= TERM_CODED; } - sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); - if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); - pTerm->wtFlags |= TERM_CODED; - } + iLoop = iNext; + }while( iLoop>0 ); /* Insert code to test for implied constraints based on transitivity ** of the "==" operator. @@ -121176,7 +130225,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** the implied "t1.a=123" constraint. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ - Expr *pE, *pEAlt; + Expr *pE, sEAlt; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; @@ -121194,13 +130243,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( testcase( pAlt->eOperator & WO_IS ); testcase( pAlt->eOperator & WO_IN ); VdbeModuleComment((v, "begin transitive constraint")); - pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt)); - if( pEAlt ){ - *pEAlt = *pAlt->pExpr; - pEAlt->pLeft = pE->pLeft; - sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL); - sqlite3StackFree(db, pEAlt); - } + sEAlt = *pAlt->pExpr; + sEAlt.pLeft = pE->pLeft; + sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); } /* For a LEFT OUTER JOIN, generate code that will record the fact that @@ -121296,7 +130341,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ if( pWC->nTerm>=pWC->nSlot ){ WhereTerm *pOld = pWC->a; sqlite3 *db = pWC->pWInfo->pParse->db; - pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); + pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); if( pWC->a==0 ){ if( wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, p); @@ -121309,7 +130354,6 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ sqlite3DbFree(db, pOld); } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); - memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm)); } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ @@ -121321,13 +130365,15 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; + memset(&pTerm->eOperator, 0, + sizeof(WhereTerm) - offsetof(WhereTerm,eOperator)); return idx; } /* ** Return TRUE if the given operator is one of the operators that is ** allowed for an indexable WHERE clause term. The allowed operators are -** "=", "<", ">", "<=", ">=", "IN", and "IS NULL" +** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL" */ static int allowedOp(int op){ assert( TK_GT>TK_EQ && TK_GTdb; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ + int rc; /* Result code to return */ if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ return 0; @@ -121443,41 +130490,75 @@ static int isLikeOrGlob( #endif pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; - if( pLeft->op!=TK_COLUMN - || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->pTab) /* Value might be numeric */ - ){ - /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must - ** be the name of an indexed column with TEXT affinity. */ - return 0; - } - assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */ pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; - if( op==TK_VARIABLE ){ + if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ - z = (char *)sqlite3_value_text(pVal); + z = sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ - z = pRight->u.zToken; + z = (u8*)pRight->u.zToken; } if( z ){ + + /* 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( sqlite3Isdigit(z[0]) || z[0]=='-' ){ + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || IsVirtual(pLeft->pTab) /* Value might be numeric */ + ){ + sqlite3ValueFree(pVal); + return 0; + } + } + + /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; + if( c==wc[3] && z[cnt]!=0 ) cnt++; } + + /* The optimization is possible only if (1) the pattern does not begin + ** with a wildcard and if (2) the non-wildcard prefix does not end with + ** an (illegal 0xff) character. The second condition is necessary so + ** that we can increment the prefix key to find an upper bound for the + ** range search. + */ if( cnt!=0 && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; + + /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; - pPrefix = sqlite3Expr(db, TK_STRING, z); - if( pPrefix ) pPrefix->u.zToken[cnt] = 0; + + /* Get the pattern prefix. Remove all escapes from the prefix. */ + pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); + if( pPrefix ){ + int iFrom, iTo; + char *zNew = pPrefix->u.zToken; + zNew[cnt] = 0; + for(iFrom=iTo=0; iFrompVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); @@ -121499,56 +130580,93 @@ static int isLikeOrGlob( } } + rc = (z!=0); sqlite3ValueFree(pVal); - return (z!=0); + return rc; } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* -** Check to see if the given expression is of the form +** Check to see if the pExpr expression is a form that needs to be passed +** to the xBestIndex method of virtual tables. Forms of interest include: ** -** column OP expr +** Expression Virtual Table Operator +** ----------------------- --------------------------------- +** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH +** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB +** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE +** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP +** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE +** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE +** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT +** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT +** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL ** -** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a -** column of a virtual table. +** In every case, "column" must be a column of a virtual table. If there +** is a match, set *ppLeft to the "column" expression, set *ppRight to the +** "expr" expression (even though in forms (6) and (8) the column is on the +** right and the expression is on the left). Also set *peOp2 to the +** appropriate virtual table operator. The return value is 1 or 2 if there +** is a match. The usual return is 1, but if the RHS is also a column +** of virtual table in forms (5) or (7) then return 2. ** -** If it is then return TRUE. If not, return FALSE. +** If the expression matches none of the patterns above, return 0. */ -static int isMatchOfColumn( +static int isAuxiliaryVtabOperator( Expr *pExpr, /* Test this expression */ - unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ + unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ + Expr **ppLeft, /* Column expression to left of MATCH/op2 */ + Expr **ppRight /* Expression to left of MATCH/op2 */ ){ - struct Op2 { - const char *zOp; - unsigned char eOp2; - } aOp[] = { - { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, - { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, - { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, - { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } - }; - ExprList *pList; - Expr *pCol; /* Column reference */ - int i; + if( pExpr->op==TK_FUNCTION ){ + static const struct Op2 { + const char *zOp; + unsigned char eOp2; + } aOp[] = { + { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, + { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, + { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, + { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } + }; + ExprList *pList; + Expr *pCol; /* Column reference */ + int i; - if( pExpr->op!=TK_FUNCTION ){ - return 0; - } - pList = pExpr->x.pList; - if( pList==0 || pList->nExpr!=2 ){ - return 0; - } - pCol = pList->a[1].pExpr; - if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ - return 0; - } - for(i=0; iu.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - return 1; + pList = pExpr->x.pList; + if( pList==0 || pList->nExpr!=2 ){ + return 0; } + pCol = pList->a[1].pExpr; + if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ + return 0; + } + for(i=0; iu.zToken, aOp[i].zOp)==0 ){ + *peOp2 = aOp[i].eOp2; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; + } + } + }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ + int res = 0; + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; + if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){ + res++; + } + if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){ + res++; + SWAP(Expr*, pLeft, pRight); + } + *ppLeft = pLeft; + *ppRight = pRight; + if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE; + if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT; + if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL; + return res; } return 0; } @@ -121627,8 +130745,8 @@ static void whereCombineDisjuncts( && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); - if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; - if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return; + if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; + if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return; /* If we reach this point, it means the two subterms can be combined */ if( (eOp & (eOp-1))!=0 ){ if( eOp & (WO_LT|WO_LE) ){ @@ -121763,6 +130881,7 @@ static void exprAnalyzeOrTerm( if( pOrInfo==0 ) return; pTerm->wtFlags |= TERM_ORINFO; pOrWc = &pOrInfo->wc; + memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic)); sqlite3WhereClauseInit(pOrWc, pWInfo); sqlite3WhereSplit(pOrWc, pExpr, TK_OR); sqlite3WhereExprAnalyze(pSrc, pOrWc); @@ -121779,7 +130898,7 @@ static void exprAnalyzeOrTerm( WhereAndInfo *pAndInfo; assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); chngToIN = 0; - pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo)); + pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo)); if( pAndInfo ){ WhereClause *pAndWC; WhereTerm *pAndTerm; @@ -121789,15 +130908,17 @@ static void exprAnalyzeOrTerm( pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; pAndWC = &pAndInfo->wc; + memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; - testcase( db->mallocFailed ); if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); - if( allowedOp(pAndTerm->pExpr->op) ){ + if( allowedOp(pAndTerm->pExpr->op) + || pAndTerm->eOperator==WO_AUX + ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } @@ -121960,7 +131081,7 @@ static void exprAnalyzeOrTerm( } assert( pLeft!=0 ); pDup = sqlite3ExprDup(db, pLeft, 0); - pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0); + pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); @@ -121998,7 +131119,6 @@ static void exprAnalyzeOrTerm( static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; - const char *zColl1, *zColl2; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; @@ -122011,13 +131131,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - /* Since pLeft and pRight are both a column references, their collating - ** sequence should always be defined. */ - zColl1 = ALWAYS(pColl) ? pColl->zName : 0; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); - zColl2 = ALWAYS(pColl) ? pColl->zName : 0; - return sqlite3StrICmp(zColl1, zColl2)==0; + return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } /* @@ -122050,46 +131164,65 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ ** Expression pExpr is one operand of a comparison operator that might ** be useful for indexing. This routine checks to see if pExpr appears ** in any index. Return TRUE (1) if pExpr is an indexed term and return -** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor -** number of the table that is indexed and *piColumn to the column number -** of the column that is indexed, or -2 if an expression is being indexed. +** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor +** number of the table that is indexed and aiCurCol[1] to the column number +** of the column that is indexed, or XN_EXPR (-2) if an expression is being +** indexed. ** ** If pExpr is a TK_COLUMN column reference, then this routine always returns ** true even if that particular column is not indexed, because the column ** might be added to an automatic index later. */ -static int exprMightBeIndexed( +static SQLITE_NOINLINE int exprMightBeIndexed2( SrcList *pFrom, /* The FROM clause */ Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ - Expr *pExpr, /* An operand of a comparison operator */ - int *piCur, /* Write the referenced table cursor number here */ - int *piColumn /* Write the referenced table column number here */ + int *aiCurCol, /* Write the referenced table cursor and column here */ + Expr *pExpr /* An operand of a comparison operator */ ){ Index *pIdx; int i; int iCur; - if( pExpr->op==TK_COLUMN ){ - *piCur = pExpr->iTable; - *piColumn = pExpr->iColumn; - return 1; - } - if( mPrereq==0 ) return 0; /* No table references */ - if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ for(i=0; mPrereq>1; i++, mPrereq>>=1){} iCur = pFrom->a[i].iCursor; for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr==0 ) continue; for(i=0; inKeyCol; i++){ - if( pIdx->aiColumn[i]!=(-2) ) continue; - if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ - *piCur = iCur; - *piColumn = -2; + if( pIdx->aiColumn[i]!=XN_EXPR ) continue; + if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ + aiCurCol[0] = iCur; + aiCurCol[1] = XN_EXPR; return 1; } } } return 0; } +static int exprMightBeIndexed( + SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ + int *aiCurCol, /* Write the referenced table cursor & column here */ + Expr *pExpr, /* An operand of a comparison operator */ + int op /* The specific comparison operator */ +){ + /* If this expression is a vector to the left or right of a + ** inequality constraint (>, <, >= or <=), perform the processing + ** on the first element of the vector. */ + assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); + assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ + pExpr = pExpr->x.pList->a[0].pExpr; + } + + if( pExpr->op==TK_COLUMN ){ + aiCurCol[0] = pExpr->iTable; + aiCurCol[1] = pExpr->iColumn; + return 1; + } + if( mPrereq==0 ) return 0; /* No table references */ + if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ + return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); +} /* ** The input to this routine is an WhereTerm structure with only the @@ -122128,6 +131261,7 @@ static void exprAnalyze( Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */ + int nLeft; /* Number of elements on left side vector */ if( db->mallocFailed ){ return; @@ -122140,6 +131274,7 @@ static void exprAnalyze( op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); + if( sqlite3ExprCheckIN(pParse, pExpr) ) return; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); }else{ @@ -122150,34 +131285,48 @@ static void exprAnalyze( }else{ pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); } + pMaskSet->bVarSelect = 0; prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr); + if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT; if( ExprHasProperty(pExpr, EP_FromJoin) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ + if( (prereqAll>>1)>=x ){ + sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); + return; + } } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ - int iCur, iColumn; + int aiCurCol[2]; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; - if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){ - pTerm->leftCursor = iCur; - pTerm->u.leftColumn = iColumn; + + if( pTerm->iField>0 ){ + assert( op==TK_IN ); + assert( pLeft->op==TK_VECTOR ); + pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr; + } + + if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ + pTerm->leftCursor = aiCurCol[0]; + pTerm->u.leftColumn = aiCurCol[1]; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight - && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn) + && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ + assert( pTerm->iField==0 ); if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); @@ -122202,8 +131351,8 @@ static void exprAnalyze( pNew = pTerm; } exprCommute(pParse, pDup); - pNew->leftCursor = iCur; - pNew->u.leftColumn = iColumn; + pNew->leftCursor = aiCurCol[0]; + pNew->u.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; @@ -122238,7 +131387,7 @@ static void exprAnalyze( int idxNew; pNewExpr = sqlite3PExpr(pParse, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0), - sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0); + sqlite3ExprDup(db, pList->a[i].pExpr, 0)); transferJoinMarkings(pNewExpr, pExpr); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); @@ -122323,7 +131472,7 @@ static void exprAnalyze( pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), - pStr1, 0); + pStr1); transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); @@ -122331,7 +131480,7 @@ static void exprAnalyze( pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), - pStr2, 0); + pStr2); transferJoinMarkings(pNewExpr2, pExpr); idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); @@ -122345,42 +131494,103 @@ static void exprAnalyze( #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE - /* Add a WO_MATCH auxiliary term to the constraint set if the - ** current expression is of the form: column MATCH expr. + /* Add a WO_AUX auxiliary term to the constraint set if the + ** current expression is of the form "column OP expr" where OP + ** is an operator that gets passed into virtual tables but which is + ** not normally optimized for ordinary tables. In other words, OP + ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ - if( isMatchOfColumn(pExpr, &eOp2) ){ - int idxNew; + if( pWC->op==TK_AND ){ Expr *pRight, *pLeft; - WhereTerm *pNewTerm; - Bitmask prereqColumn, prereqExpr; + int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight); + while( res-- > 0 ){ + int idxNew; + WhereTerm *pNewTerm; + Bitmask prereqColumn, prereqExpr; - pRight = pExpr->x.pList->a[0].pExpr; - pLeft = pExpr->x.pList->a[1].pExpr; - prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); - prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); - if( (prereqExpr & prereqColumn)==0 ){ - Expr *pNewExpr; - pNewExpr = sqlite3PExpr(pParse, TK_MATCH, - 0, sqlite3ExprDup(db, pRight, 0), 0); - idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); - testcase( idxNew==0 ); - pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = prereqExpr; - pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; - pNewTerm->eOperator = WO_MATCH; - pNewTerm->eMatchOp = eOp2; - markTermAsChild(pWC, idxNew, idxTerm); - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - pNewTerm->prereqAll = pTerm->prereqAll; + prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); + prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); + if( (prereqExpr & prereqColumn)==0 ){ + Expr *pNewExpr; + pNewExpr = sqlite3PExpr(pParse, TK_MATCH, + 0, sqlite3ExprDup(db, pRight, 0)); + if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){ + ExprSetProperty(pNewExpr, EP_FromJoin); + } + idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = prereqExpr; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_AUX; + pNewTerm->eMatchOp = eOp2; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + SWAP(Expr*, pLeft, pRight); } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ + /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create + ** new terms for each component comparison - "a = ?" and "b = ?". The + ** new terms completely replace the original vector comparison, which is + ** no longer used. + ** + ** This is only required if at least one side of the comparison operation + ** is not a sub-select. */ + if( pWC->op==TK_AND + && (pExpr->op==TK_EQ || pExpr->op==TK_IS) + && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 + && sqlite3ExprVectorSize(pExpr->pRight)==nLeft + && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 + || (pExpr->pRight->flags & EP_xIsSelect)==0) + ){ + int i; + for(i=0; ipLeft, i); + Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i); + + pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); + transferJoinMarkings(pNew, pExpr); + idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); + exprAnalyze(pSrc, pWC, idxNew); + } + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */ + pTerm->eOperator = 0; + } + + /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create + ** a virtual term for each vector component. The expression object + ** used by each such virtual term is pExpr (the full vector IN(...) + ** expression). The WhereTerm.iField variable identifies the index within + ** the vector on the LHS that the virtual term represents. + ** + ** This only works if the RHS is a simple SELECT, not a compound + */ + if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0 + && pExpr->pLeft->op==TK_VECTOR + && pExpr->x.pSelect->pPrior==0 + ){ + int i; + for(i=0; ipLeft); i++){ + int idxNew; + idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL); + pWC->a[idxNew].iField = i+1; + exprAnalyze(pSrc, pWC, idxNew); + markTermAsChild(pWC, idxNew, idxTerm); + } + } + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* When sqlite_stat3 histogram data is available an operator of the ** form "x IS NOT NULL" can sometimes be evaluated more efficiently @@ -122401,7 +131611,7 @@ static void exprAnalyze( pNewExpr = sqlite3PExpr(pParse, TK_GT, sqlite3ExprDup(db, pLeft, 0), - sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0); + sqlite3ExprAlloc(db, TK_NULL, 0, 0)); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); @@ -122422,6 +131632,8 @@ static void exprAnalyze( /* Prevent ON clause terms of a LEFT JOIN from being used to drive ** an index for tables to the left of the join. */ + testcase( pTerm!=&pWC->a[idxTerm] ); + pTerm = &pWC->a[idxTerm]; pTerm->prereqRight |= extraRight; } @@ -122504,17 +131716,21 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){ ** tree. */ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ - Bitmask mask = 0; + Bitmask mask; if( p==0 ) return 0; if( p->op==TK_COLUMN ){ - mask = sqlite3WhereGetMask(pMaskSet, p->iTable); - return mask; + return sqlite3WhereGetMask(pMaskSet, p->iTable); } - mask = sqlite3WhereExprUsage(pMaskSet, p->pRight); - mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); - if( ExprHasProperty(p, EP_xIsSelect) ){ + mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; + assert( !ExprHasProperty(p, EP_TokenOnly) ); + if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); + if( p->pRight ){ + mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight); + assert( p->x.pList==0 ); + }else if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); - }else{ + }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } return mask; @@ -122578,13 +131794,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( pTab->zName, j); return; } - pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); + pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); 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), 0); + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } @@ -122624,8 +131840,8 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int); /* ** Return the estimated number of output rows from a WHERE clause */ -SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ - return sqlite3LogEstToInt(pWInfo->nRowOut); +SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ + return pWInfo->nRowOut; } /* @@ -122644,6 +131860,18 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } +/* +** Return TRUE if the innermost loop of the WHERE clause implementation +** returns rows in ORDER BY order for complete run of the inner loop. +** +** Across multiple iterations of outer loops, the output rows need not be +** sorted. As long as rows are sorted for just the innermost loop, this +** routine can return TRUE. +*/ +SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ + return pWInfo->bOrderedInnerLoop; +} + /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. @@ -122779,16 +132007,19 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ - while( pScan->iEquiv<=pScan->nEquiv ){ - iCur = pScan->aiCur[pScan->iEquiv-1]; + assert( pScan->iEquiv<=pScan->nEquiv ); + pWC = pScan->pWC; + while(1){ iColumn = pScan->aiColumn[pScan->iEquiv-1]; - if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0; - while( (pWC = pScan->pWC)!=0 ){ + iCur = pScan->aiCur[pScan->iEquiv-1]; + assert( pWC!=0 ); + do{ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn && (iColumn!=XN_EXPR - || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0) + || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, + pScan->pIdxExpr,iCur)==0) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 @@ -122833,15 +132064,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ testcase( pTerm->eOperator & WO_IS ); continue; } + pScan->pWC = pWC; pScan->k = k+1; return pTerm; } } } - pScan->pWC = pScan->pWC->pOuter; + pWC = pWC->pOuter; k = 0; - } - pScan->pWC = pScan->pOrigWC; + }while( pWC!=0 ); + if( pScan->iEquiv>=pScan->nEquiv ) break; + pWC = pScan->pOrigWC; k = 0; pScan->iEquiv++; } @@ -122854,7 +132087,10 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ ** ** The scanner will be searching the WHERE clause pWC. It will look ** for terms of the form "X " where X is column iColumn of table -** iCur. The must be one of the operators described by opMask. +** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx +** must be one of the indexes of table iCur. +** +** The must be one of the operators described by opMask. ** ** If the search is for X and the WHERE clause contains terms of the ** form X=Y then this routine might also return terms of the form @@ -122872,23 +132108,25 @@ static WhereTerm *whereScanInit( u32 opMask, /* Operator(s) to scan for */ Index *pIdx /* Must be compatible with this index */ ){ - int j = 0; - - /* memset(pScan, 0, sizeof(*pScan)); */ pScan->pOrigWC = pWC; pScan->pWC = pWC; pScan->pIdxExpr = 0; + pScan->idxaff = 0; + pScan->zCollName = 0; if( pIdx ){ - j = iColumn; + int j = iColumn; iColumn = pIdx->aiColumn[j]; - if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; - } - if( pIdx && iColumn>=0 ){ - pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; - pScan->zCollName = pIdx->azColl[j]; - }else{ - pScan->idxaff = 0; - pScan->zCollName = 0; + if( iColumn==XN_EXPR ){ + pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; + pScan->zCollName = pIdx->azColl[j]; + }else if( iColumn==pIdx->pTable->iPKey ){ + iColumn = XN_ROWID; + }else if( iColumn>=0 ){ + pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; + pScan->zCollName = pIdx->azColl[j]; + } + }else if( iColumn==XN_EXPR ){ + return 0; } pScan->opMask = opMask; pScan->k = 0; @@ -122901,11 +132139,12 @@ static WhereTerm *whereScanInit( /* ** Search for a term in the WHERE clause that is of the form "X " -** where X is a reference to the iColumn of table iCur and is one of -** the WO_xx operator codes specified by the op parameter. -** Return a pointer to the term. Return 0 if not found. +** where X is a reference to the iColumn of table iCur or of index pIdx +** if pIdx!=0 and is one of the WO_xx operator codes specified by +** the op parameter. Return a pointer to the term. Return 0 if not found. ** -** If pIdx!=0 then search for terms matching the iColumn-th column of pIdx +** If pIdx!=0 then it must be one of the indexes of table iCur. +** Search for terms matching the iColumn-th column of pIdx ** rather than the iColumn-th column of table iCur. ** ** The term returned might by Y= if there is another constraint in @@ -122973,8 +132212,8 @@ static int findIndexCol( && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); - if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){ + CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr); + if( 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } @@ -123087,14 +132326,16 @@ static LogEst estLog(LogEst N){ ** value stored in its output register. */ static void translateColumnToCopy( - Vdbe *v, /* The VDBE containing code to translate */ + 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) */ ){ + Vdbe *v = pParse->pVdbe; VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); int iEnd = sqlite3VdbeCurrentAddr(v); + if( pParse->db->mallocFailed ) return; for(; iStartp1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ @@ -123176,6 +132417,15 @@ static int termCanDriveIndex( char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; + if( (pSrc->fg.jointype & JT_LEFT) + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (pTerm->eOperator & WO_IS) + ){ + /* Cannot use an IS term from the WHERE clause as an index driver for + ** the RHS of a LEFT JOIN. Such a term can only be used if it is from + ** the ON clause. */ + return 0; + } if( (pTerm->prereqRight & notReady)!=0 ) return 0; if( pTerm->u.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; @@ -123227,7 +132477,7 @@ static void constructAutomaticIndex( ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); - addrInit = sqlite3CodeOnce(pParse); VdbeCoverage(v); + addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ @@ -123372,7 +132622,9 @@ static void constructAutomaticIndex( if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pTabItem->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); - translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1); + testcase( pParse->db->mallocFailed ); + translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, + pTabItem->regResult, 1); sqlite3VdbeGoto(v, addrTop); pTabItem->fg.viaCoroutine = 0; }else{ @@ -123402,7 +132654,8 @@ static sqlite3_index_info *allocateIndexInfo( WhereClause *pWC, Bitmask mUnusable, /* Ignore terms with these prereqs */ struct SrcList_item *pSrc, - ExprList *pOrderBy + ExprList *pOrderBy, + u16 *pmNoOmit /* Mask of terms not to omit */ ){ int i, j; int nTerm; @@ -123412,6 +132665,7 @@ static sqlite3_index_info *allocateIndexInfo( WhereTerm *pTerm; int nOrderBy; sqlite3_index_info *pIdxInfo; + u16 mNoOmit = 0; /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ @@ -123423,7 +132677,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; + if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( pTerm->u.leftColumn>=(-1) ); nTerm++; @@ -123471,7 +132725,7 @@ static sqlite3_index_info *allocateIndexInfo( pUsage; for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - u8 op; + u16 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); @@ -123479,27 +132733,42 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; + if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; - op = (u8)pTerm->eOperator & WO_ALL; + op = pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; - if( op==WO_MATCH ){ - op = pTerm->eMatchOp; + if( op==WO_AUX ){ + pIdxCons[j].op = pTerm->eMatchOp; + }else if( op & (WO_ISNULL|WO_IS) ){ + if( op==WO_ISNULL ){ + pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL; + }else{ + pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS; + } + }else{ + pIdxCons[j].op = (u8)op; + /* The direct assignment in the previous line is possible only because + ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The + ** following asserts verify this fact. */ + assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); + assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); + assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); + assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); + assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); + assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) ); + + if( op & (WO_LT|WO_LE|WO_GT|WO_GE) + && sqlite3ExprIsVector(pTerm->pExpr->pRight) + ){ + if( i<16 ) mNoOmit |= (1 << i); + if( op==WO_LT ) pIdxCons[j].op = WO_LE; + if( op==WO_GT ) pIdxCons[j].op = WO_GE; + } } - pIdxCons[j].op = op; - /* The direct assignment in the previous line is possible only because - ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The - ** following asserts verify this fact. */ - assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); - assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); - assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); - assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); - assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); - assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); - assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); + j++; } for(i=0; ia[i].sortOrder; } + *pmNoOmit = mNoOmit; return pIdxInfo; } @@ -123527,7 +132797,6 @@ static sqlite3_index_info *allocateIndexInfo( */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; - int i; int rc; TRACE_IDX_INPUTS(p); @@ -123536,7 +132805,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ){ - pParse->db->mallocFailed = 1; + sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ @@ -123546,12 +132815,16 @@ 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; } @@ -123743,7 +133016,7 @@ static int whereKeyStats( iGap = iGap/3; } aStat[0] = iLower + iGap; - aStat[1] = pIdx->aAvgEq[iCol]; + aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ @@ -123780,7 +133053,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ /* ** Return the affinity for a single column of an index. */ -static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ +SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ assert( iCol>=0 && iColnColumn ); if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; @@ -123957,7 +133230,8 @@ static int whereRangeScanEst( if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; - u8 aff; + int nBtm = pLoop->u.btree.nBtm; + int nTop = pLoop->u.btree.nTop; /* Variable iLower will be set to the estimate of the number of rows in ** the index that are less than the lower bound of the range query. The @@ -123987,8 +133261,6 @@ static int whereRangeScanEst( testcase( pRec->nField!=pBuilder->nRecValid ); pRec->nField = pBuilder->nRecValid; } - aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq); - assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER ); /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; @@ -124007,17 +133279,20 @@ static int whereRangeScanEst( if( p->aSortOrder[nEq] ){ /* The roles of pLower and pUpper are swapped for a DESC index */ SWAP(WhereTerm*, pLower, pUpper); + SWAP(int, nBtm, nTop); } /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ - int bOk; /* True if value is extracted from pExpr */ + int n; /* Values extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n); + if( rc==SQLITE_OK && n ){ tRowcnt iNew; + u16 mask = WO_GT|WO_LE; + if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); - iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); + iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; pLower = 0; @@ -124026,13 +133301,15 @@ static int whereRangeScanEst( /* If possible, improve on the iUpper estimate using ($P:$U). */ if( pUpper ){ - int bOk; /* True if value is extracted from pExpr */ + int n; /* Values extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n); + if( rc==SQLITE_OK && n ){ tRowcnt iNew; + u16 mask = WO_GT|WO_LE; + if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); - iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); + iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0); if( iNewpNew->u.btree.pIndex; int nEq = pBuilder->pNew->u.btree.nEq; UnpackedRecord *pRec = pBuilder->pRec; - u8 aff; /* Column affinity */ int rc; /* Subfunction return code */ tRowcnt a[2]; /* Statistics */ int bOk; @@ -124146,15 +133422,15 @@ static int whereEqualScanEst( return SQLITE_OK; } - aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1); - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk); + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk); pBuilder->pRec = pRec; if( rc!=SQLITE_OK ) return rc; if( bOk==0 ) return SQLITE_NOTFOUND; pBuilder->nRecValid = nEq; whereKeyStats(pParse, p, pRec, 0, a); - WHERETRACE(0x10,("equality scan regions: %d\n", (int)a[1])); + WHERETRACE(0x10,("equality scan regions %s(%d): %d\n", + p->zName, nEq-1, (int)a[1])); *pnRow = a[1]; return rc; @@ -124220,30 +133496,58 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; + char zLeft[50]; memcpy(zType, "...", 4); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + if( pTerm->eOperator & WO_SINGLE ){ + sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", + pTerm->leftCursor, pTerm->u.leftColumn); + }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ + sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", + pTerm->u.pOrInfo->indexable); + }else{ + sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); + } sqlite3DebugPrintf( - "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n", - iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x", + iTerm, pTerm, zType, zLeft, pTerm->truthProb, pTerm->eOperator, pTerm->wtFlags); + if( pTerm->iField ){ + sqlite3DebugPrintf(" iField=%d\n", pTerm->iField); + }else{ + sqlite3DebugPrintf("\n"); + } sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } #endif +#ifdef WHERETRACE_ENABLED +/* +** Show the complete content of a WhereClause +*/ +SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ + int i; + for(i=0; inTerm; i++){ + whereTermPrint(&pWC->a[i], i); + } +} +#endif + #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes */ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ WhereInfo *pWInfo = pWC->pWInfo; - int nb = 1+(pWInfo->pTabList->nSrc+7)/8; + int nb = 1+(pWInfo->pTabList->nSrc+3)/4; struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab; Table *pTab = pItem->pTab; + Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, - p->iTab, nb, p->maskSelf, nb, p->prereq); + p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ @@ -124306,7 +133610,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); - sqlite3DbFree(db, p->u.btree.pIndex); + sqlite3DbFreeNN(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } @@ -124316,7 +133620,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ ** Deallocate internal memory used by a WhereLoop object */ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ - if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); whereLoopClearUnion(db, p); whereLoopInit(p); } @@ -124328,10 +133632,10 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ WhereTerm **paNew; if( p->nLSlot>=n ) return SQLITE_OK; n = (n+7)&~7; - paNew = sqlite3DbMallocRaw(db, sizeof(p->aLTerm[0])*n); - if( paNew==0 ) return SQLITE_NOMEM; + paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n); + if( paNew==0 ) return SQLITE_NOMEM_BKPT; memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot); - if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); p->aLTerm = paNew; p->nLSlot = n; return SQLITE_OK; @@ -124344,7 +133648,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); if( whereLoopResize(db, pTo, pFrom->nLTerm) ){ memset(&pTo->u, 0, sizeof(pTo->u)); - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); @@ -124361,7 +133665,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ */ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ whereLoopClear(db, p); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } /* @@ -124382,7 +133686,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } - sqlite3DbFree(db, pWInfo); + sqlite3DbFreeNN(db, pWInfo); } } @@ -124390,18 +133694,19 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** Return TRUE if all of the following are true: ** ** (1) X has the same or lower cost that Y -** (2) X is a proper subset of Y -** (3) X skips at least as many columns as Y -** -** By "proper subset" we mean that X uses fewer WHERE clause terms -** than Y and that every WHERE clause term used by X is also used -** by Y. +** (2) X uses fewer WHERE clause terms than Y +** (3) Every WHERE clause term used by X is also used by Y +** (4) X skips at least as many columns as Y +** (5) If X is a covering index, than Y is too ** +** Conditions (2) and (3) mean that X is a "proper subset" of Y. ** If X is a proper subset of Y then Y is a better choice and ought ** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. The third rule +** relationship is inverted and needs to be adjusted. Constraint (4) ** was added because if X uses skip-scan less than Y it still might -** deserve a lower cost even if it is a proper subset of Y. +** deserve a lower cost even if it is a proper subset of Y. Constraint (5) +** was added because a covering index probably deserves to have a lower cost +** than a non-covering index even if it is a proper subset. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ @@ -124423,6 +133728,10 @@ static int whereLoopCheaperProperSubset( } if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } + if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 + && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ + return 0; /* Constraint (5) */ + } return 1; /* All conditions meet */ } @@ -124465,16 +133774,17 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ /* ** Search the list of WhereLoops in *ppPrev looking for one that can be -** supplanted by pTemplate. +** replaced by pTemplate. ** -** Return NULL if the WhereLoop list contains an entry that can supplant -** pTemplate, in other words if pTemplate does not belong on the list. +** Return NULL if pTemplate does not belong on the WhereLoop list. +** In other words if pTemplate ought to be dropped from further consideration. ** -** If pX is a WhereLoop that pTemplate can supplant, then return the +** If pX is a WhereLoop that pTemplate can replace, then return the ** link that points to pX. ** -** If pTemplate cannot supplant any existing element of the list but needs -** to be added to the list, then return a pointer to the tail of the list. +** If pTemplate cannot replace any existing element of the list but needs +** to be added to the list as a new entry, then return a pointer to the +** tail of the list. */ static WhereLoop **whereLoopFindLesser( WhereLoop **ppPrev, @@ -124568,6 +133878,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; + int rc; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. @@ -124618,15 +133929,17 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ if( p!=0 ){ sqlite3DebugPrintf("replace: "); whereLoopPrint(p, pBuilder->pWC); + sqlite3DebugPrintf(" with: "); + }else{ + sqlite3DebugPrintf(" add: "); } - sqlite3DebugPrintf(" add: "); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif if( p==0 ){ /* Allocate a new WhereLoop to add to the end of the list */ - *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop)); - if( p==0 ) return SQLITE_NOMEM; + *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop)); + if( p==0 ) return SQLITE_NOMEM_BKPT; whereLoopInit(p); p->pNextLoop = 0; }else{ @@ -124650,14 +133963,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ whereLoopDelete(db, pToDel); } } - whereLoopXfer(db, p, pTemplate); + rc = whereLoopXfer(db, p, pTemplate); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->tnum==0 ){ p->u.btree.pIndex = 0; } } - return SQLITE_OK; + return rc; } /* @@ -124735,6 +134048,72 @@ static void whereLoopOutputAdjust( if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce; } +/* +** Term pTerm is a vector range comparison operation. The first comparison +** in the vector can be optimized using column nEq of the index. This +** function returns the total number of vector elements that can be used +** as part of the range comparison. +** +** For example, if the query is: +** +** WHERE a = ? AND (b, c, d) > (?, ?, ?) +** +** and the index: +** +** CREATE INDEX ... ON (a, b, c, d, e) +** +** then this function would be invoked with nEq=1. The value returned in +** this case is 3. +*/ +static int whereRangeVectorLen( + Parse *pParse, /* Parsing context */ + int iCur, /* Cursor open on pIdx */ + Index *pIdx, /* The index to be used for a inequality constraint */ + int nEq, /* Number of prior equality constraints on same index */ + WhereTerm *pTerm /* The vector inequality constraint */ +){ + int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft); + int i; + + nCmp = MIN(nCmp, (pIdx->nColumn - nEq)); + for(i=1; ipExpr->pLeft->x.pList->a[i].pExpr; + Expr *pRhs = pTerm->pExpr->pRight; + if( pRhs->flags & EP_xIsSelect ){ + pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; + }else{ + pRhs = pRhs->x.pList->a[i].pExpr; + } + + /* Check that the LHS of the comparison is a column reference to + ** the right column of the right source table. And that the sort + ** order of the index column is the same as the sort order of the + ** leftmost index column. */ + if( pLhs->op!=TK_COLUMN + || pLhs->iTable!=iCur + || pLhs->iColumn!=pIdx->aiColumn[i+nEq] + || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq] + ){ + break; + } + + testcase( pLhs->iColumn==XN_ROWID ); + aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs)); + idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); + if( aff!=idxaff ) break; + + pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + if( pColl==0 ) break; + if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; + } + return i; +} + /* ** Adjust the cost C by the costMult facter T. This only occurs if ** compiled with -DSQLITE_ENABLE_COSTMULT @@ -124773,6 +134152,8 @@ static int whereLoopAddBtreeIndex( Bitmask saved_prereq; /* Original value of pNew->prereq */ u16 saved_nLTerm; /* Original value of pNew->nLTerm */ u16 saved_nEq; /* Original value of pNew->u.btree.nEq */ + u16 saved_nBtm; /* Original value of pNew->u.btree.nBtm */ + u16 saved_nTop; /* Original value of pNew->u.btree.nTop */ u16 saved_nSkip; /* Original value of pNew->nSkip */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */ LogEst saved_nOut; /* Original value of pNew->nOut */ @@ -124782,15 +134163,16 @@ static int whereLoopAddBtreeIndex( WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; - if( db->mallocFailed ) return SQLITE_NOMEM; + if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; + WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n", + pProbe->zName, pNew->u.btree.nEq)); assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; - }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){ - opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE; }else{ + assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); @@ -124798,6 +134180,8 @@ static int whereLoopAddBtreeIndex( assert( pNew->u.btree.nEqnColumn ); saved_nEq = pNew->u.btree.nEq; + saved_nBtm = pNew->u.btree.nBtm; + saved_nTop = pNew->u.btree.nTop; saved_nSkip = pNew->nSkip; saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; @@ -124827,8 +134211,27 @@ static int whereLoopAddBtreeIndex( ** to mix with a lower range bound from some other source */ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; + /* Do not allow IS constraints from the WHERE clause to be used by the + ** right table of a LEFT JOIN. Only constraints in the ON clause are + ** allowed */ + if( (pSrc->fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (eOp & (WO_IS|WO_ISNULL))!=0 + ){ + testcase( eOp & WO_IS ); + testcase( eOp & WO_ISNULL ); + continue; + } + + if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){ + pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE; + }else{ + pBuilder->bldFlags |= SQLITE_BLDF_INDEXED; + } pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; + pNew->u.btree.nBtm = saved_nBtm; + pNew->u.btree.nTop = saved_nTop; pNew->nLTerm = saved_nLTerm; if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTerm; @@ -124845,14 +134248,23 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ + int i; nIn = 46; assert( 46==sqlite3LogEst(25) ); + + /* The expression may actually be of the form (x, y) IN (SELECT...). + ** In this case there is a separate term for each of (x) and (y). + ** However, the nIn multiplier should only be applied once, not once + ** for each such term. The following loop checks that pTerm is the + ** first such term in use, and sets nIn back to 0 if it is not. */ + for(i=0; inLTerm-1; i++){ + if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; + } }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); + assert( nIn>0 ); /* RHS always has 2 or more terms... The parser + ** changes "x IN (?)" into "x=?". */ } - assert( nIn>0 ); /* RHS always has 2 or more terms... The parser - ** changes "x IN (?)" into "x=?". */ - }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; @@ -124872,6 +134284,9 @@ static int whereLoopAddBtreeIndex( testcase( eOp & WO_GT ); testcase( eOp & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; + pNew->u.btree.nBtm = whereRangeVectorLen( + pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm + ); pBtm = pTerm; pTop = 0; if( pTerm->wtFlags & TERM_LIKEOPT ){ @@ -124884,12 +134299,16 @@ static int whereLoopAddBtreeIndex( if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTop; pNew->wsFlags |= WHERE_TOP_LIMIT; + pNew->u.btree.nTop = 1; } }else{ assert( eOp & (WO_LT|WO_LE) ); testcase( eOp & WO_LT ); testcase( eOp & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; + pNew->u.btree.nTop = whereRangeVectorLen( + pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm + ); pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aLTerm[pNew->nLTerm-2] : 0; @@ -124989,6 +134408,8 @@ static int whereLoopAddBtreeIndex( } pNew->prereq = saved_prereq; pNew->u.btree.nEq = saved_nEq; + pNew->u.btree.nBtm = saved_nBtm; + pNew->u.btree.nTop = saved_nTop; pNew->nSkip = saved_nSkip; pNew->wsFlags = saved_wsFlags; pNew->nOut = saved_nOut; @@ -125028,6 +134449,8 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags = saved_wsFlags; } + WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n", + pProbe->zName, saved_nEq, rc)); return rc; } @@ -125060,7 +134483,7 @@ static int indexMightHelpWithOrderBy( }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jjnKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; - if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ + if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } @@ -125093,14 +134516,16 @@ static Bitmask columnsInIndex(Index *pIdx){ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ int i; WhereTerm *pTerm; + Parse *pParse = pWC->pWInfo->pParse; while( pWhere->op==TK_AND ){ if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0; pWhere = pWhere->pRight; } + if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0; for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ Expr *pExpr = pTerm->pExpr; - if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) - && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) + if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) + && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) ){ return 1; } @@ -125110,7 +134535,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ /* ** Add all WhereLoop objects for a single table of the join where the table -** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be +** is identified by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. ** ** The costs (WhereLoop.rRun) of the b-tree loops added by this function @@ -125146,7 +134571,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ */ static int whereLoopAddBtree( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mExtra /* Extra prerequesites for using this table */ + Bitmask mPrereq /* Extra prerequesites for using this table */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ @@ -125207,7 +134632,7 @@ static int whereLoopAddBtree( #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ - && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ @@ -125239,6 +134664,7 @@ static int whereLoopAddBtree( pNew->rSetup += 24; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); + if( pNew->rSetup<0 ) pNew->rSetup = 0; /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would @@ -125246,7 +134672,7 @@ static int whereLoopAddBtree( pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; - pNew->prereq = mExtra | pTerm->prereqRight; + pNew->prereq = mPrereq | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); } } @@ -125263,11 +134689,13 @@ static int whereLoopAddBtree( } rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; + pNew->u.btree.nBtm = 0; + pNew->u.btree.nTop = 0; pNew->nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; - pNew->prereq = mExtra; + pNew->prereq = mPrereq; pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); @@ -125299,6 +134727,7 @@ static int whereLoopAddBtree( /* Full scan via index */ if( b || !HasRowid(pTab) + || pProbe->pPartIdxWhere!=0 || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRowszTabRow) @@ -125311,11 +134740,34 @@ static int whereLoopAddBtree( /* The cost of visiting the index rows is N*K, where K is ** between 1.1 and 3.0, depending on the relative sizes of the - ** index and table rows. If this is a non-covering index scan, - ** also add the cost of visiting table rows (N*3.0). */ + ** index and table rows. */ pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; if( m!=0 ){ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); + /* If this is a non-covering index scan, add in the cost of + ** doing table lookups. The cost will be 3x the number of + ** lookups. Take into account WHERE clause terms that can be + ** satisfied using just the index, and that do not require a + ** table lookup. */ + LogEst nLookup = rSize + 16; /* Base cost: N*3 */ + int ii; + int iCur = pSrc->iCursor; + WhereClause *pWC2 = &pWInfo->sWC; + for(ii=0; iinTerm; ii++){ + WhereTerm *pTerm = &pWC2->a[ii]; + if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){ + break; + } + /* pTerm can be evaluated using just the index. So reduce + ** the expected number of table lookups accordingly */ + if( pTerm->truthProb<=0 ){ + nLookup += pTerm->truthProb; + }else{ + nLookup--; + if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19; + } + } + + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); @@ -125325,7 +134777,15 @@ static int whereLoopAddBtree( } } + pBuilder->bldFlags = 0; rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); + if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){ + /* If a non-unique index is used, or if a prefix of the key for + ** unique index is used (making the index functionally non-unique) + ** then the sqlite_stat1 data becomes important for scoring the + ** plan */ + pTab->tabFlags |= TF_StatsUsed; + } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; @@ -125340,12 +134800,162 @@ static int whereLoopAddBtree( } #ifndef SQLITE_OMIT_VIRTUALTABLE + +/* +** Argument pIdxInfo is already populated with all constraints that may +** be used by the virtual table identified by pBuilder->pNew->iTab. This +** function marks a subset of those constraints usable, invokes the +** xBestIndex method and adds the returned plan to pBuilder. +** +** A constraint is marked usable if: +** +** * Argument mUsable indicates that its prerequisites are available, and +** +** * It is not one of the operators specified in the mExclude mask passed +** as the fourth argument (which in practice is either WO_IN or 0). +** +** Argument mPrereq is a mask of tables that must be scanned before the +** virtual table in question. These are added to the plans prerequisites +** before it is added to pBuilder. +** +** Output parameter *pbIn is set to true if the plan added to pBuilder +** uses one or more WO_IN terms, or false otherwise. +*/ +static int whereLoopAddVirtualOne( + WhereLoopBuilder *pBuilder, + Bitmask mPrereq, /* Mask of tables that must be used. */ + Bitmask mUsable, /* Mask of usable tables */ + u16 mExclude, /* Exclude terms using these operators */ + sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ + u16 mNoOmit, /* Do not omit these constraints */ + int *pbIn /* OUT: True if plan uses an IN(...) op */ +){ + WhereClause *pWC = pBuilder->pWC; + struct sqlite3_index_constraint *pIdxCons; + struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage; + int i; + int mxTerm; + int rc = SQLITE_OK; + WhereLoop *pNew = pBuilder->pNew; + Parse *pParse = pBuilder->pWInfo->pParse; + struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; + int nConstraint = pIdxInfo->nConstraint; + + assert( (mUsable & mPrereq)==mPrereq ); + *pbIn = 0; + pNew->prereq = mPrereq; + + /* Set the usable flag on the subset of constraints identified by + ** arguments mUsable and mExclude. */ + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; ia[pIdxCons->iTermOffset]; + pIdxCons->usable = 0; + if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight + && (pTerm->eOperator & mExclude)==0 + ){ + pIdxCons->usable = 1; + } + } + + /* Initialize the output fields of the sqlite3_index_info structure */ + memset(pUsage, 0, sizeof(pUsage[0])*nConstraint); + assert( pIdxInfo->needToFreeIdxStr==0 ); + pIdxInfo->idxStr = 0; + pIdxInfo->idxNum = 0; + pIdxInfo->orderByConsumed = 0; + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; + pIdxInfo->estimatedRows = 25; + pIdxInfo->idxFlags = 0; + pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; + + /* Invoke the virtual table xBestIndex() method */ + rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); + if( rc ) return rc; + + mxTerm = -1; + assert( pNew->nLSlot>=nConstraint ); + for(i=0; iaLTerm[i] = 0; + pNew->u.vtab.omitMask = 0; + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; i=0 ){ + WhereTerm *pTerm; + int j = pIdxCons->iTermOffset; + if( iTerm>=nConstraint + || j<0 + || j>=pWC->nTerm + || pNew->aLTerm[iTerm]!=0 + || pIdxCons->usable==0 + ){ + rc = SQLITE_ERROR; + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); + return rc; + } + testcase( iTerm==nConstraint-1 ); + testcase( j==0 ); + testcase( j==pWC->nTerm-1 ); + pTerm = &pWC->a[j]; + pNew->prereq |= pTerm->prereqRight; + assert( iTermnLSlot ); + pNew->aLTerm[iTerm] = pTerm; + if( iTerm>mxTerm ) mxTerm = iTerm; + testcase( iTerm==15 ); + testcase( iTerm==16 ); + if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ + /* A virtual table that is constrained by an IN clause may not + ** consume the ORDER BY clause because (1) the order of IN terms + ** is not necessarily related to the order of output terms and + ** (2) Multiple outputs from a single IN value will not merge + ** together. */ + pIdxInfo->orderByConsumed = 0; + pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; + *pbIn = 1; assert( (mExclude & WO_IN)==0 ); + } + } + } + pNew->u.vtab.omitMask &= ~mNoOmit; + + pNew->nLTerm = mxTerm+1; + assert( pNew->nLTerm<=pNew->nLSlot ); + pNew->u.vtab.idxNum = pIdxInfo->idxNum; + pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; + pIdxInfo->needToFreeIdxStr = 0; + pNew->u.vtab.idxStr = pIdxInfo->idxStr; + pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? + pIdxInfo->nOrderBy : 0); + pNew->rSetup = 0; + pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); + pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); + + /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated + ** that the scan will visit at most one row. Clear it otherwise. */ + if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){ + pNew->wsFlags |= WHERE_ONEROW; + }else{ + pNew->wsFlags &= ~WHERE_ONEROW; + } + rc = whereLoopInsert(pBuilder, pNew); + if( pNew->u.vtab.needFree ){ + sqlite3_free(pNew->u.vtab.idxStr); + pNew->u.vtab.needFree = 0; + } + WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n", + *pbIn, (sqlite3_uint64)mPrereq, + (sqlite3_uint64)(pNew->prereq & ~mPrereq))); + + return rc; +} + + /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. ** -** If there are no LEFT or CROSS JOIN joins in the query, both mExtra and -** mUnusable are set to 0. Otherwise, mExtra is a mask of all FROM clause +** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and +** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause ** entries that occur before the virtual table in the FROM clause and are ** separated from it by at least one LEFT or CROSS JOIN. Similarly, the ** mUnusable mask contains all FROM clause entries that occur after the @@ -125356,188 +134966,128 @@ static int whereLoopAddBtree( ** ** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6; ** -** then mExtra corresponds to (t1, t2) and mUnusable to (t5, t6). +** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6). ** -** All the tables in mExtra must be scanned before the current virtual +** All the tables in mPrereq must be scanned before the current virtual ** table. So any terms for which all prerequisites are satisfied by -** mExtra may be specified as "usable" in all calls to xBestIndex. +** mPrereq may be specified as "usable" in all calls to xBestIndex. ** Conversely, all tables in mUnusable must be scanned after the current ** virtual table, so any terms for which the prerequisites overlap with ** mUnusable should always be configured as "not-usable" for xBestIndex. */ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mExtra, /* Tables that must be scanned before this one */ + Bitmask mPrereq, /* Tables that must be scanned before this one */ Bitmask mUnusable /* Tables that must be scanned after this one */ ){ + int rc = SQLITE_OK; /* Return code */ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ WhereClause *pWC; /* The WHERE clause */ struct SrcList_item *pSrc; /* The FROM clause term to search */ - Table *pTab; - sqlite3 *db; - sqlite3_index_info *pIdxInfo; - struct sqlite3_index_constraint *pIdxCons; - struct sqlite3_index_constraint_usage *pUsage; - WhereTerm *pTerm; - int i, j; - int iTerm, mxTerm; - int nConstraint; - int seenIn = 0; /* True if an IN operator is seen */ - int seenVar = 0; /* True if a non-constant constraint is seen */ - int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */ + sqlite3_index_info *p; /* Object to pass to xBestIndex() */ + int nConstraint; /* Number of constraints in p */ + int bIn; /* True if plan uses IN(...) operator */ WhereLoop *pNew; - int rc = SQLITE_OK; + Bitmask mBest; /* Tables used by best possible plan */ + u16 mNoOmit; - assert( (mExtra & mUnusable)==0 ); + assert( (mPrereq & mUnusable)==0 ); pWInfo = pBuilder->pWInfo; pParse = pWInfo->pParse; - db = pParse->db; pWC = pBuilder->pWC; pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; - pTab = pSrc->pTab; - assert( IsVirtual(pTab) ); - pIdxInfo = allocateIndexInfo(pParse, pWC, mUnusable, pSrc,pBuilder->pOrderBy); - if( pIdxInfo==0 ) return SQLITE_NOMEM; - pNew->prereq = 0; + assert( IsVirtual(pSrc->pTab) ); + p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, + &mNoOmit); + if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; pNew->nLTerm = 0; pNew->u.vtab.needFree = 0; - pUsage = pIdxInfo->aConstraintUsage; - nConstraint = pIdxInfo->nConstraint; - if( whereLoopResize(db, pNew, nConstraint) ){ - sqlite3DbFree(db, pIdxInfo); - return SQLITE_NOMEM; + nConstraint = p->nConstraint; + if( whereLoopResize(pParse->db, pNew, nConstraint) ){ + sqlite3DbFree(pParse->db, p); + return SQLITE_NOMEM_BKPT; } - for(iPhase=0; iPhase<=3; iPhase++){ - if( !seenIn && (iPhase&1)!=0 ){ - iPhase++; - if( iPhase>3 ) break; - } - if( !seenVar && iPhase>1 ) break; - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pIdxCons++){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - switch( iPhase ){ - case 0: /* Constants without IN operator */ - pIdxCons->usable = 0; - if( (pTerm->eOperator & WO_IN)!=0 ){ - seenIn = 1; - } - if( (pTerm->prereqRight & ~mExtra)!=0 ){ - seenVar = 1; - }else if( (pTerm->eOperator & WO_IN)==0 ){ - pIdxCons->usable = 1; - } - break; - case 1: /* Constants with IN operators */ - assert( seenIn ); - pIdxCons->usable = (pTerm->prereqRight & ~mExtra)==0; - break; - case 2: /* Variables without IN */ - assert( seenVar ); - pIdxCons->usable = (pTerm->eOperator & WO_IN)==0; - break; - default: /* Variables with IN */ - assert( seenVar && seenIn ); - pIdxCons->usable = 1; - break; - } - } - memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); - if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr); - pIdxInfo->idxStr = 0; - pIdxInfo->idxNum = 0; - pIdxInfo->needToFreeIdxStr = 0; - pIdxInfo->orderByConsumed = 0; - pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; - pIdxInfo->estimatedRows = 25; - pIdxInfo->idxFlags = 0; - pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; - rc = vtabBestIndex(pParse, pTab, pIdxInfo); - if( rc ) goto whereLoopAddVtab_exit; - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - pNew->prereq = mExtra; - mxTerm = -1; - assert( pNew->nLSlot>=nConstraint ); - for(i=0; iaLTerm[i] = 0; - pNew->u.vtab.omitMask = 0; - for(i=0; i=0 ){ - j = pIdxCons->iTermOffset; - if( iTerm>=nConstraint - || j<0 - || j>=pWC->nTerm - || pNew->aLTerm[iTerm]!=0 - ){ - rc = SQLITE_ERROR; - sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName); - goto whereLoopAddVtab_exit; - } - testcase( iTerm==nConstraint-1 ); - testcase( j==0 ); - testcase( j==pWC->nTerm-1 ); - pTerm = &pWC->a[j]; - pNew->prereq |= pTerm->prereqRight; - assert( iTermnLSlot ); - pNew->aLTerm[iTerm] = pTerm; - if( iTerm>mxTerm ) mxTerm = iTerm; - testcase( iTerm==15 ); - testcase( iTerm==16 ); - if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ - if( pUsage[i].omit==0 ){ - /* Do not attempt to use an IN constraint if the virtual table - ** says that the equivalent EQ constraint cannot be safely omitted. - ** If we do attempt to use such a constraint, some rows might be - ** repeated in the output. */ - break; - } - /* A virtual table that is constrained by an IN clause may not - ** consume the ORDER BY clause because (1) the order of IN terms - ** is not necessarily related to the order of output terms and - ** (2) Multiple outputs from a single IN value will not merge - ** together. */ - pIdxInfo->orderByConsumed = 0; - pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; - } - } - } - if( i>=nConstraint ){ - pNew->nLTerm = mxTerm+1; - assert( pNew->nLTerm<=pNew->nLSlot ); - pNew->u.vtab.idxNum = pIdxInfo->idxNum; - pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; - pIdxInfo->needToFreeIdxStr = 0; - pNew->u.vtab.idxStr = pIdxInfo->idxStr; - pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? - pIdxInfo->nOrderBy : 0); - pNew->rSetup = 0; - pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); - pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); + /* First call xBestIndex() with all constraints usable. */ + WHERETRACE(0x40, (" VirtualOne: all usable\n")); + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); - /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated - ** that the scan will visit at most one row. Clear it otherwise. */ - if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){ - pNew->wsFlags |= WHERE_ONEROW; - }else{ - pNew->wsFlags &= ~WHERE_ONEROW; - } - whereLoopInsert(pBuilder, pNew); - if( pNew->u.vtab.needFree ){ - sqlite3_free(pNew->u.vtab.idxStr); - pNew->u.vtab.needFree = 0; + /* 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 ){ + 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; + Bitmask mBestNoIn = 0; + + /* If the plan produced by the earlier call uses an IN(...) term, call + ** xBestIndex again, this time with IN(...) terms disabled. */ + if( bIn ){ + WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n")); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn); + assert( bIn==0 ); + mBestNoIn = pNew->prereq & ~mPrereq; + if( mBestNoIn==0 ){ + seenZero = 1; + seenZeroNoIN = 1; } } - } -whereLoopAddVtab_exit: - if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr); - sqlite3DbFree(db, pIdxInfo); + /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) + ** in the set of terms that apply to the current virtual table. */ + while( rc==SQLITE_OK ){ + int i; + Bitmask mNext = ALLBITS; + assert( mNext>0 ); + for(i=0; ia[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq + ); + if( mThis>mPrev && mThisprereq==mPrereq ){ + seenZero = 1; + if( bIn==0 ) seenZeroNoIN = 1; + } + } + + /* If the calls to xBestIndex() in the above loop did not find a plan + ** that requires no source tables at all (i.e. one guaranteed to be + ** usable), make a call here with all source tables disabled */ + if( rc==SQLITE_OK && seenZero==0 ){ + WHERETRACE(0x40, (" VirtualOne: all disabled\n")); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn); + if( bIn==0 ) seenZeroNoIN = 1; + } + + /* If the calls to xBestIndex() have so far failed to find a plan + ** that requires no source tables at all and does not use an IN(...) + ** operator, make a final call to obtain one here. */ + if( rc==SQLITE_OK && seenZeroNoIN==0 ){ + WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n")); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn); + } + } + + if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); + sqlite3DbFreeNN(pParse->db, p); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -125548,7 +135098,7 @@ whereLoopAddVtab_exit: */ static int whereLoopAddOr( WhereLoopBuilder *pBuilder, - Bitmask mExtra, + Bitmask mPrereq, Bitmask mUnusable ){ WhereInfo *pWInfo = pBuilder->pWInfo; @@ -125602,21 +135152,19 @@ static int whereLoopAddOr( WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ - for(i=0; inTerm; i++){ - whereTermPrint(&sSubBuild.pWC->a[i], i); - } + sqlite3WhereClausePrint(sSubBuild.pWC); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ - rc = whereLoopAddVirtual(&sSubBuild, mExtra, mUnusable); + rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif { - rc = whereLoopAddBtree(&sSubBuild, mExtra); + rc = whereLoopAddBtree(&sSubBuild, mPrereq); } if( rc==SQLITE_OK ){ - rc = whereLoopAddOr(&sSubBuild, mExtra, mUnusable); + rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ @@ -125673,7 +135221,7 @@ static int whereLoopAddOr( */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; - Bitmask mExtra = 0; + Bitmask mPrereq = 0; Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; @@ -125694,9 +135242,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ - mExtra = mPrior; + mPrereq = mPrior; } priorJointype = pItem->fg.jointype; +#ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; psMaskSet, p->iCursor); } } - rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable); - }else{ - rc = whereLoopAddBtree(pBuilder, mExtra); + rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); + }else +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + { + rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK ){ - rc = whereLoopAddOr(pBuilder, mExtra, mUnusable); + rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; @@ -125720,7 +135271,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ } /* -** Examine a WherePath (with the addition of the extra WhereLoop of the 5th +** Examine a WherePath (with the addition of the extra WhereLoop of the 6th ** parameters) to see if it outputs rows in the requested ORDER BY ** (or GROUP BY) without requiring a separate sort operation. Return N: ** @@ -125740,7 +135291,7 @@ static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ - u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ + u16 wctrlFlags, /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ @@ -125751,6 +135302,7 @@ static i8 wherePathSatisfiesOrderBy( u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */ u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */ u8 isMatch; /* iColumn matches a term of the ORDER BY clause */ + u16 eqOpMask; /* Allowed equality operators */ u16 nKeyCol; /* Number of key columns in pIndex */ u16 nColumn; /* Total number of ordered columns in the index */ u16 nOrderBy; /* Number terms in the ORDER BY clause */ @@ -125801,12 +135353,21 @@ static i8 wherePathSatisfiesOrderBy( obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; + eqOpMask = WO_EQ | WO_IS | WO_ISNULL; + if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN; for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; - pLoop = iLoopaLoop[iLoop] : pLast; + if( iLoopaLoop[iLoop]; + if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue; + }else{ + pLoop = pLast; + } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ if( pLoop->u.vtab.isOrdered ) obSat = obDone; break; + }else{ + pLoop->u.btree.nIdxCol = 0; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; @@ -125821,17 +135382,21 @@ static i8 wherePathSatisfiesOrderBy( if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, - ~ready, WO_EQ|WO_ISNULL|WO_IS, 0); + ~ready, eqOpMask, 0); if( pTerm==0 ) continue; + if( pTerm->eOperator==WO_IN ){ + /* IN terms are only valid for sorting in the ORDER BY LIMIT + ** optimization, and then only if they are actually used + ** by the query plan */ + assert( wctrlFlags & WHERE_ORDERBY_LIMIT ); + for(j=0; jnLTerm && pTerm!=pLoop->aLTerm[j]; j++){} + if( j>=pLoop->nLTerm ) continue; + } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ - const char *z1, *z2; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); - if( !pColl ) pColl = db->pDfltColl; - z1 = pColl->zName; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); - if( !pColl ) pColl = db->pDfltColl; - z2 = pColl->zName; - if( sqlite3StrICmp(z1, z2)!=0 ) continue; + if( sqlite3ExprCollSeqMatch(pWInfo->pParse, + pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){ + continue; + } testcase( pTerm->pExpr->op==TK_IS ); } obSat |= MASKBIT(i); @@ -125859,18 +135424,42 @@ static i8 wherePathSatisfiesOrderBy( rev = revSet = 0; distinctColumns = 0; for(j=0; ju.btree.nEq - && pLoop->nSkip==0 - && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0 - ){ - if( i & WO_ISNULL ){ - testcase( isOrderDistinct ); - isOrderDistinct = 0; + assert( j>=pLoop->u.btree.nEq + || (pLoop->aLTerm[j]==0)==(jnSkip) + ); + if( ju.btree.nEq && j>=pLoop->nSkip ){ + u16 eOp = pLoop->aLTerm[j]->eOperator; + + /* Skip over == and IS and ISNULL terms. (Also skip IN terms when + ** doing WHERE_ORDERBY_LIMIT processing). + ** + ** If the current term is a column of an ((?,?) IN (SELECT...)) + ** expression for which the SELECT returns more than one column, + ** check that it is the only column used by this loop. Otherwise, + ** if it is one of two or more, none of the columns can be + ** considered to match an ORDER BY term. */ + if( (eOp & eqOpMask)!=0 ){ + if( eOp & WO_ISNULL ){ + testcase( isOrderDistinct ); + isOrderDistinct = 0; + } + continue; + }else if( ALWAYS(eOp & WO_IN) ){ + /* ALWAYS() justification: eOp is an equality operator due to the + ** ju.btree.nEq constraint above. Any equality other + ** than WO_IN is captured by the previous "if". So this one + ** always has to be WO_IN. */ + Expr *pX = pLoop->aLTerm[j]->pExpr; + for(i=j+1; iu.btree.nEq; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + assert( (pLoop->aLTerm[i]->eOperator & WO_IN) ); + bOnce = 0; + break; + } + } } - continue; } /* Get the column number in the table (iColumn) and sort order @@ -125879,7 +135468,7 @@ static i8 wherePathSatisfiesOrderBy( if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j]; - if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; + if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID; }else{ iColumn = XN_ROWID; revIdx = 0; @@ -125899,7 +135488,6 @@ static i8 wherePathSatisfiesOrderBy( /* Find the ORDER BY term that corresponds to the j-th column ** of the index and mark that ORDER BY term off */ - bOnce = 1; isMatch = 0; for(i=0; bOnce && i=(-1) ){ + if( iColumn>=XN_ROWID ){ if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ - if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){ + Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr; + if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){ continue; } } - if( iColumn>=0 ){ - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); - if( !pColl ) pColl = db->pDfltColl; + if( iColumn!=XN_ROWID ){ + pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } + pLoop->u.btree.nIdxCol = j+1; isMatch = 1; break; } @@ -125936,7 +135525,7 @@ static i8 wherePathSatisfiesOrderBy( } } if( isMatch ){ - if( iColumn<0 ){ + if( iColumn==XN_ROWID ){ testcase( distinctColumns==0 ); distinctColumns = 1; } @@ -126052,15 +135641,14 @@ static LogEst whereSortingCost( LogEst rScale, rSortCost; assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; - rSortCost = nRow + estLog(nRow) + rScale + 16; + rSortCost = nRow + rScale + 16; - /* TUNING: The cost of implementing DISTINCT using a B-TREE is - ** similar but with a larger constant of proportionality. - ** Multiply by an additional factor of 3.0. */ - if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ - rSortCost += 16; + /* Multiple by log(M) where M is the number of output rows. + ** Use the LIMIT for M if it is smaller */ + if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimitiLimit; } - + rSortCost += estLog(nRow); return rSortCost; } @@ -126122,8 +135710,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; nSpace += sizeof(LogEst) * nOrderBy; - pSpace = sqlite3DbMallocRaw(db, nSpace); - if( pSpace==0 ) return SQLITE_NOMEM; + pSpace = sqlite3DbMallocRawNN(db, nSpace); + if( pSpace==0 ) return SQLITE_NOMEM_BKPT; aTo = (WherePath*)pSpace; aFrom = aTo+mxChoice; memset(aFrom, 0, sizeof(aFrom[0])); @@ -126178,6 +135766,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; + if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){ + /* Do not use an automatic index if the this loop is expected + ** to run less than 2 times. */ + assert( 10==sqlite3LogEst(2) ); + continue; + } /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); @@ -126205,6 +135799,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ rUnsorted, rCost)); }else{ rCost = rUnsorted; + rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ } /* Check to see if pWLoop should be added to the set of @@ -126236,8 +135831,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** this candidate as not viable. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif @@ -126255,26 +135850,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif }else{ /* Control reaches here if best-so-far path pTo=aTo[jj] covers the - ** same set of loops and has the sam isOrdered setting as the + ** same set of loops and has the same isOrdered setting as the ** candidate path. Check to see if the candidate should replace - ** pTo or if the candidate should be skipped */ - if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){ + ** pTo or if the candidate should be skipped. + ** + ** The conditional is an expanded vector comparison equivalent to: + ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted) + */ + if( pTo->rCostrCost==rCost + && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted) + ) + ) + ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Skip %s cost=%-3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + "Skip %s cost=%-3d,%3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); - sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", + sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif /* Discard the candidate path from further consideration */ @@ -126287,12 +135892,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Update %s cost=%-3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + "Update %s cost=%-3d,%3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); - sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", + sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } @@ -126347,7 +135952,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( nFrom==0 ){ sqlite3ErrorMsg(pParse, "no query solution"); - sqlite3DbFree(db, pSpace); + sqlite3DbFreeNN(db, pSpace); return SQLITE_ERROR; } @@ -126383,8 +135988,26 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ } }else{ pWInfo->nOBSat = pFrom->isOrdered; - if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; pWInfo->revMask = pFrom->revLoop; + if( pWInfo->nOBSat<=0 ){ + pWInfo->nOBSat = 0; + if( nLoop>0 ){ + u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags; + if( (wsFlags & WHERE_ONEROW)==0 + && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN) + ){ + Bitmask m = 0; + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, + WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); + testcase( wsFlags & WHERE_IPK ); + testcase( wsFlags & WHERE_COLUMN_IN ); + if( rc==pWInfo->pOrderBy->nExpr ){ + pWInfo->bOrderedInnerLoop = 1; + pWInfo->revMask = m; + } + } + } + } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 @@ -126405,7 +136028,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ - sqlite3DbFree(db, pSpace); + sqlite3DbFreeNN(db, pSpace); return SQLITE_OK; } @@ -126430,9 +136053,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ int j; Table *pTab; Index *pIdx; - + pWInfo = pBuilder->pWInfo; - if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0; + if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; @@ -126483,7 +136106,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pLoop->wsFlags ){ pLoop->nOut = (LogEst)1; pWInfo->a[0].pWLoop = pLoop; - pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); + assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] ); + pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; @@ -126498,6 +136122,32 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ return 0; } +/* +** Helper function for exprIsDeterministic(). +*/ +static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){ + pWalker->eCode = 0; + return WRC_Abort; + } + return WRC_Continue; +} + +/* +** Return true if the expression contains no non-deterministic SQL +** functions. Do not consider non-deterministic SQL functions that are +** part of sub-select statements. +*/ +static int exprIsDeterministic(Expr *p){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 1; + w.xExprCallback = exprNodeIsDeterministic; + w.xSelectCallback = sqlite3SelectWalkFail; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains @@ -126579,7 +136229,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** ** The iIdxCur parameter is the cursor number of an index. If -** WHERE_ONETABLE_ONLY is set, iIdxCur is the cursor number of an index +** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index ** to use for OR clause processing. The WHERE clause should use this ** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is ** the first cursor in an array of cursors for all indices. iIdxCur should @@ -126587,13 +136237,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ** used. */ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( - Parse *pParse, /* The parser context */ - SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ - Expr *pWhere, /* The WHERE clause */ - ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ - ExprList *pResultSet, /* Result set of the query */ - u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ - int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ + Expr *pWhere, /* The WHERE clause */ + ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ + ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */ + u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ + int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number + ** If WHERE_USE_LIMIT, then the limit amount */ ){ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ @@ -126607,13 +136258,17 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ - u8 bFordelete = 0; + u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */ assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 - && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 )); + /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */ + assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + || (wctrlFlags & WHERE_USE_LIMIT)==0 ); + /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); @@ -126639,11 +136294,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } /* This function normally generates a nested loop for all tables in - ** pTabList. But if the WHERE_ONETABLE_ONLY flag is set, then we should + ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should ** only generate code for the first table in pTabList and assume that ** any cursors associated with subsequent tables are uninitialized. */ - nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc; + nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc; /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo @@ -126653,21 +136308,26 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** some architectures. Hence the ROUND8() below. */ nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); - pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop)); + pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); pWInfo = 0; goto whereBeginError; } - pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; - pWInfo->nLevel = nTabList; pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; + pWInfo->pWhere = pWhere; pWInfo->pResultSet = pResultSet; + pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; + pWInfo->nLevel = nTabList; pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); pWInfo->wctrlFlags = wctrlFlags; + pWInfo->iLimit = iAuxArg; pWInfo->savedNQueryLoop = pParse->nQueryLoop; + memset(&pWInfo->nOBSat, 0, + offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat)); + memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel)); assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */ pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; @@ -126686,17 +136346,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); - /* Special case: a WHERE clause that is constant. Evaluate the - ** expression and either jump over all of the code or fall thru. - */ - for(ii=0; iinTerm; ii++){ - if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){ - sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak, - SQLITE_JUMPIFNULL); - sWLB.pWC->a[ii].wtFlags |= TERM_CODED; - } - } - /* Special case: No FROM clause */ if( nTabList==0 ){ @@ -126704,37 +136353,61 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + }else{ + /* Assign a bit from the bitmask to every term in the FROM clause. + ** + ** The N-th term of the FROM clause is assigned a bitmask of 1<nSrc tables in + ** pTabList, not just the first nTabList tables. nTabList is normally + ** equal to pTabList->nSrc but might be shortened to 1 if the + ** WHERE_OR_SUBCLAUSE flag is set. + */ + ii = 0; + do{ + createMask(pMaskSet, pTabList->a[ii].iCursor); + sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); + }while( (++ii)nSrc ); + #ifdef SQLITE_DEBUG + { + Bitmask mx = 0; + for(ii=0; iinSrc; ii++){ + Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); + assert( m>=mx ); + mx = m; + } + } + #endif } - - /* Assign a bit from the bitmask to every term in the FROM clause. - ** - ** The N-th term of the FROM clause is assigned a bitmask of 1<nSrc tables in - ** pTabList, not just the first nTabList tables. nTabList is normally - ** equal to pTabList->nSrc but might be shortened to 1 if the - ** WHERE_ONETABLE_ONLY flag is set. - */ - for(ii=0; iinSrc; ii++){ - createMask(pMaskSet, pTabList->a[ii].iCursor); - sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); - } -#ifdef SQLITE_DEBUG - for(ii=0; iinSrc; ii++){ - Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); - assert( m==MASKBIT(ii) ); - } -#endif - + /* Analyze all of the subexpressions. */ sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); if( db->mallocFailed ) goto whereBeginError; + /* Special case: WHERE terms that do not refer to any tables in the join + ** (constant expressions). Evaluate each such term, and jump over all the + ** generated code if the result is not true. + ** + ** Do not do this if the expression contains non-deterministic functions + ** that are not within a sub-select. This is not strictly required, but + ** preserves SQLite's legacy behaviour in the following two cases: + ** + ** FROM ... WHERE random()>0; -- eval random() once per row + ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall + */ + for(ii=0; iinTerm; ii++){ + WhereTerm *pT = &sWLB.pWC->a[ii]; + if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ + sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); + pT->wtFlags |= TERM_CODED; + } + } + if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ @@ -126747,14 +136420,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } /* Construct the WhereLoop objects */ - WHERETRACE(0xffff,("*** Optimizer Start *** (wctrlFlags: 0x%x)\n", - wctrlFlags)); #if defined(WHERETRACE_ENABLED) - if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ - int i; - for(i=0; inTerm; i++){ - whereTermPrint(&sWLB.pWC->a[i], i); + if( sqlite3WhereTrace & 0xffff ){ + sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); + if( wctrlFlags & WHERE_USE_LIMIT ){ + sqlite3DebugPrintf(", limit: %d", iAuxArg); } + sqlite3DebugPrintf(")\n"); + } + if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ + sqlite3WhereClausePrint(sWLB.pWC); } #endif @@ -126769,7 +136444,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ - p->cId = zLabel[i%sizeof(zLabel)]; + p->cId = zLabel[i%(sizeof(zLabel)-1)]; whereLoopPrint(p, sWLB.pWC); } } @@ -126783,7 +136458,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } } if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ - pWInfo->revMask = (Bitmask)(-1); + pWInfo->revMask = ALLBITS; } if( pParse->nErr || NEVER(db->mallocFailed) ){ goto whereBeginError; @@ -126852,16 +136527,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. - ** The one-pass algorithm only works if the WHERE clause constrains - ** the statement to update or delete a single row. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; - if( bOnerow || ( (wctrlFlags & WHERE_ONEPASS_MULTIROW) - && 0==(wsFlags & WHERE_VIRTUALTABLE) - )){ + if( bOnerow + || ((wctrlFlags & WHERE_ONEPASS_MULTIROW)!=0 + && 0==(wsFlags & WHERE_VIRTUALTABLE)) + ){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ @@ -126897,7 +136571,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( }else #endif if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int op = OP_OpenRead; if( pWInfo->eOnePass!=ONEPASS_OFF ){ op = OP_OpenWrite; @@ -126911,8 +136585,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Bitmask b = pTabItem->colUsed; int n = 0; for(; b; b=b>>1, n++){} - sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, - SQLITE_INT_TO_PTR(n), P4_INT32); + sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -126934,10 +136607,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; - /* iIdxCur is always set if to a positive value if ONEPASS is possible */ - assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); + /* iAuxArg is always set to a positive value if ONEPASS is possible */ + assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) - && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ /* This is one term of an OR-optimization using the PRIMARY KEY of a ** WITHOUT ROWID table. No need for a separate index */ @@ -126945,7 +136618,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( op = 0; }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ Index *pJ = pTabItem->pTab->pIndex; - iIndexCur = iIdxCur; + iIndexCur = iAuxArg; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); while( ALWAYS(pJ) && pJ!=pIx ){ iIndexCur++; @@ -126953,9 +136626,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } op = OP_OpenWrite; pWInfo->aiCurOnePass[1] = iIndexCur; - }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){ - iIndexCur = iIdxCur; - if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx; + }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ + iIndexCur = iAuxArg; + op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; } @@ -126968,6 +136641,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 + && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ } @@ -127017,7 +136691,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; - if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ + if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); } } @@ -127056,14 +136730,43 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ int addr; pLevel = &pWInfo->a[i]; pLoop = pLevel->pWLoop; - sqlite3VdbeResolveLabel(v, pLevel->addrCont); if( pLevel->op!=OP_Noop ){ +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + int addrSeek = 0; + Index *pIdx; + int n; + if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED + && (pLoop->wsFlags & WHERE_INDEXED)!=0 + && (pIdx = pLoop->u.btree.pIndex)->hasStat1 + && (n = pLoop->u.btree.nIdxCol)>0 + && pIdx->aiRowLogEst[n]>=36 + ){ + int r1 = pParse->nMem+1; + int j, op; + for(j=0; jiIdxCur, j, r1+j); + } + pParse->nMem += n+1; + op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT; + addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n); + VdbeCoverageIf(v, op==OP_SeekLT); + VdbeCoverageIf(v, op==OP_SeekGT); + sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); + } +#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ + /* The common case: Advance to the next row */ + sqlite3VdbeResolveLabel(v, pLevel->addrCont); sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); +#endif + }else{ + sqlite3VdbeResolveLabel(v, pLevel->addrCont); } if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; @@ -127071,10 +136774,12 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); - sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); - VdbeCoverage(v); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); + if( pIn->eEndLoopOp!=OP_Noop ){ + sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); + VdbeCoverage(v); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); + } sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } } @@ -127087,24 +136792,21 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( pLevel->addrLikeRep ){ - int op; - if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){ - op = OP_DecrJumpZero; - }else{ - op = OP_JumpZeroIncr; - } - sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1), + pLevel->addrLikeRep); VdbeCoverage(v); } #endif if( pLevel->iLeftJoin ){ + int ws = pLoop->wsFlags; addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); - if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){ + assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); + if( (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor); } - if( pLoop->wsFlags & WHERE_INDEXED ){ + if( (ws & WHERE_INDEXED) + || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) + ){ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ @@ -127137,33 +136839,13 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ - if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){ - translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur, + if( pTabItem->fg.viaCoroutine ){ + testcase( pParse->db->mallocFailed ); + translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } - /* Close all of the cursors that were opened by sqlite3WhereBegin. - ** Except, do not close cursors that will be reused by the OR optimization - ** (WHERE_OMIT_OPEN_CLOSE). 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_OMIT_OPEN_CLOSE)==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); - } - } - /* 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 @@ -127202,10 +136884,13 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; } - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 ); + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 + || pWInfo->eOnePass ); }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; + }else if( pOp->opcode==OP_IfNullRow ){ + pOp->p1 = pLevel->iIdxCur; } } } @@ -127266,6 +136951,19 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ */ #define YYPARSEFREENEVERNULL 1 +/* +** In the amalgamation, the parse.c file generated by lemon and the +** tokenize.c file are concatenated. In that case, sqlite3RunParser() +** has access to the the size of the yyParser object and so the parser +** engine can be allocated from stack. In that case, only the +** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked +** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be +** omitted. +*/ +#ifdef SQLITE_AMALGAMATION +# define sqlite3Parser_ENGINEALWAYSONSTACK 1 +#endif + /* ** Alternative datatype for the argument to the malloc() routine passed ** into sqlite3ParserAlloc(). The default is size_t. @@ -127281,15 +136979,6 @@ struct LimitVal { Expr *pOffset; /* The OFFSET expression. NULL if there is none */ }; -/* -** An instance of this structure is used to store the LIKE, -** GLOB, NOT LIKE, and NOT GLOB operators. -*/ -struct LikeOp { - Token eOperator; /* "like" or "glob" or "regexp" */ - int bNot; /* True if the NOT keyword is present */ -}; - /* ** An instance of the following structure describes the event of a ** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, @@ -127302,9 +136991,13 @@ struct LikeOp { struct TrigEvent { int a; IdList * b; }; /* -** An instance of this structure holds the ATTACH key and the key type. +** Disable lookaside memory allocation for objects that might be +** shared across database connections. */ -struct AttachKey { int type; Token key; }; +static void disableLookaside(Parse *pParse){ + pParse->disableLookaside++; + pParse->db->lookaside.bDisable++; +} /* @@ -127342,53 +137035,68 @@ struct AttachKey { int type; Token key; }; ** new Expr to populate pOut. Set the span of pOut to be the identifier ** that created the expression. */ - static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){ - pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue); - pOut->zStart = pValue->z; - pOut->zEnd = &pValue->z[pValue->n]; + static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){ + Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = (u8)op; + p->flags = EP_Leaf; + p->iAgg = -1; + 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); + } +#if SQLITE_MAX_EXPR_DEPTH>0 + p->nHeight = 1; +#endif + } + pOut->pExpr = p; + pOut->zStart = t.z; + pOut->zEnd = &t.z[t.n]; } /* This routine constructs a binary expression node out of two ExprSpan ** objects and uses the result to populate a new ExprSpan object. */ static void spanBinaryExpr( - ExprSpan *pOut, /* Write the result here */ Parse *pParse, /* The parsing context. Errors accumulate here */ int op, /* The binary operation */ - ExprSpan *pLeft, /* The left operand */ + ExprSpan *pLeft, /* The left operand, and output */ ExprSpan *pRight /* The right operand */ ){ - pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0); - pOut->zStart = pLeft->zStart; - pOut->zEnd = pRight->zEnd; + pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr); + pLeft->zEnd = pRight->zEnd; } /* If doNot is true, then add a TK_NOT Expr-node wrapper around the ** outside of *ppExpr. */ - static void exprNot(Parse *pParse, int doNot, Expr **ppExpr){ - if( doNot ) *ppExpr = sqlite3PExpr(pParse, TK_NOT, *ppExpr, 0, 0); + static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){ + if( doNot ){ + pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0); + } } /* Construct an expression node for a unary postfix operator */ static void spanUnaryPostfix( - ExprSpan *pOut, /* Write the new expression node here */ Parse *pParse, /* Parsing context to record errors */ int op, /* The operator */ - ExprSpan *pOperand, /* The operand */ + ExprSpan *pOperand, /* The operand, and output */ Token *pPostOp /* The operand token for setting the span */ ){ - pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); - pOut->zStart = pOperand->zStart; - pOut->zEnd = &pPostOp->z[pPostOp->n]; + pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); + pOperand->zEnd = &pPostOp->z[pPostOp->n]; } /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; - if( pY && pA && pY->op==TK_NULL ){ + if( pA && pY && pY->op==TK_NULL ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; @@ -127404,8 +137112,8 @@ struct AttachKey { int type; Token key; }; ExprSpan *pOperand, /* The operand */ Token *pPreOp /* The operand token for setting the span */ ){ - pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); pOut->zStart = pPreOp->z; + pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); pOut->zEnd = pOperand->zEnd; } @@ -127480,7 +137188,8 @@ struct AttachKey { int type; Token key; }; ** YY_MAX_SHIFT Maximum value for shift actions ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** YY_MIN_REDUCE Maximum value for reduce actions +** YY_MIN_REDUCE Minimum value for reduce actions +** YY_MAX_REDUCE Maximum value for reduce actions ** YY_ERROR_ACTION The yy_action[] code for syntax error ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op @@ -127490,26 +137199,25 @@ struct AttachKey { int type; Token key; }; #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned char -#define YYNOCODE 253 +#define YYNOCODE 252 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 70 +#define YYWILDCARD 83 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - int yy4; - struct TrigEvent yy90; - ExprSpan yy118; - TriggerStep* yy203; - struct {int value; int mask;} yy215; - SrcList* yy259; - struct LimitVal yy292; - Expr* yy314; - ExprList* yy322; - struct LikeOp yy342; - IdList* yy384; - Select* yy387; - With* yy451; + Expr* yy72; + TriggerStep* yy145; + ExprList* yy148; + SrcList* yy185; + ExprSpan yy190; + int yy194; + Select* yy243; + IdList* yy254; + With* yy285; + struct TrigEvent yy332; + struct LimitVal yy354; + struct {int value; int mask;} yy497; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -127519,22 +137227,18 @@ typedef union { #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse #define sqlite3ParserARG_STORE yypParser->pParse = pParse #define YYFALLBACK 1 -#define YYNSTATE 436 -#define YYNRULE 328 -#define YY_MAX_SHIFT 435 -#define YY_MIN_SHIFTREDUCE 649 -#define YY_MAX_SHIFTREDUCE 976 -#define YY_MIN_REDUCE 977 -#define YY_MAX_REDUCE 1304 -#define YY_ERROR_ACTION 1305 -#define YY_ACCEPT_ACTION 1306 -#define YY_NO_ACTION 1307 +#define YYNSTATE 455 +#define YYNRULE 329 +#define YY_MAX_SHIFT 454 +#define YY_MIN_SHIFTREDUCE 664 +#define YY_MAX_SHIFTREDUCE 992 +#define YY_MIN_REDUCE 993 +#define YY_MAX_REDUCE 1321 +#define YY_ERROR_ACTION 1322 +#define YY_ACCEPT_ACTION 1323 +#define YY_NO_ACTION 1324 /************* End control #defines *******************************************/ -/* The yyzerominor constant is used to initialize instances of -** YYMINORTYPE objects to zero. */ -static const YYMINORTYPE yyzerominor = { 0 }; - /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. ** @@ -127564,7 +137268,7 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE - +** ** N == YY_ERROR_ACTION A syntax error has occurred. ** ** N == YY_ACCEPT_ACTION The parser accepts its input. @@ -127573,16 +137277,20 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as +** Given state S and lookahead X, the action is computed as either: ** -** yy_action[ yy_shift_ofst[S] + X ] +** (A) N = yy_action[ yy_shift_ofst[S] + X ] +** (B) N = yy_default[S] ** -** If the index value yy_shift_ofst[S]+X is out of range or if the value -** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] -** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. +** The (A) formula is preferred. The B formula is used instead if: +** (1) The yy_shift_ofst[S]+X value is out of range, or +** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or +** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. +** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that +** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) ** -** The formula above is for computing the action when the lookahead is +** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of @@ -127600,446 +137308,463 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (1501) +#define YY_ACTTAB_COUNT (1566) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 311, 1306, 145, 651, 2, 192, 652, 338, 780, 92, - /* 10 */ 92, 92, 92, 85, 90, 90, 90, 90, 89, 89, - /* 20 */ 88, 88, 88, 87, 335, 88, 88, 88, 87, 335, - /* 30 */ 327, 856, 856, 92, 92, 92, 92, 697, 90, 90, - /* 40 */ 90, 90, 89, 89, 88, 88, 88, 87, 335, 76, - /* 50 */ 807, 74, 93, 94, 84, 868, 871, 860, 860, 91, - /* 60 */ 91, 92, 92, 92, 92, 335, 90, 90, 90, 90, - /* 70 */ 89, 89, 88, 88, 88, 87, 335, 311, 780, 90, - /* 80 */ 90, 90, 90, 89, 89, 88, 88, 88, 87, 335, - /* 90 */ 356, 808, 776, 701, 689, 689, 86, 83, 166, 257, - /* 100 */ 809, 715, 430, 86, 83, 166, 324, 697, 856, 856, - /* 110 */ 201, 158, 276, 387, 271, 386, 188, 689, 689, 828, - /* 120 */ 86, 83, 166, 269, 833, 49, 123, 87, 335, 93, - /* 130 */ 94, 84, 868, 871, 860, 860, 91, 91, 92, 92, - /* 140 */ 92, 92, 239, 90, 90, 90, 90, 89, 89, 88, - /* 150 */ 88, 88, 87, 335, 311, 763, 333, 332, 216, 408, - /* 160 */ 394, 69, 231, 393, 690, 691, 396, 910, 251, 354, - /* 170 */ 250, 288, 315, 430, 908, 430, 909, 89, 89, 88, - /* 180 */ 88, 88, 87, 335, 391, 856, 856, 690, 691, 183, - /* 190 */ 95, 123, 384, 381, 380, 833, 31, 833, 49, 912, - /* 200 */ 912, 751, 752, 379, 123, 311, 93, 94, 84, 868, - /* 210 */ 871, 860, 860, 91, 91, 92, 92, 92, 92, 114, - /* 220 */ 90, 90, 90, 90, 89, 89, 88, 88, 88, 87, - /* 230 */ 335, 430, 408, 399, 435, 657, 856, 856, 346, 57, - /* 240 */ 232, 828, 109, 704, 366, 689, 689, 363, 825, 760, - /* 250 */ 97, 749, 752, 833, 49, 708, 708, 93, 94, 84, - /* 260 */ 868, 871, 860, 860, 91, 91, 92, 92, 92, 92, - /* 270 */ 423, 90, 90, 90, 90, 89, 89, 88, 88, 88, - /* 280 */ 87, 335, 311, 114, 22, 361, 688, 58, 408, 390, - /* 290 */ 251, 349, 240, 213, 762, 689, 689, 847, 685, 115, - /* 300 */ 361, 231, 393, 689, 689, 396, 183, 689, 689, 384, - /* 310 */ 381, 380, 361, 856, 856, 690, 691, 160, 159, 223, - /* 320 */ 379, 738, 25, 806, 707, 841, 143, 689, 689, 835, - /* 330 */ 392, 339, 766, 766, 93, 94, 84, 868, 871, 860, - /* 340 */ 860, 91, 91, 92, 92, 92, 92, 914, 90, 90, - /* 350 */ 90, 90, 89, 89, 88, 88, 88, 87, 335, 311, - /* 360 */ 840, 840, 840, 266, 257, 690, 691, 778, 706, 86, - /* 370 */ 83, 166, 219, 690, 691, 737, 1, 690, 691, 689, - /* 380 */ 689, 689, 689, 430, 86, 83, 166, 249, 688, 937, - /* 390 */ 856, 856, 427, 699, 700, 828, 298, 690, 691, 221, - /* 400 */ 686, 115, 123, 944, 795, 833, 48, 342, 305, 970, - /* 410 */ 847, 93, 94, 84, 868, 871, 860, 860, 91, 91, - /* 420 */ 92, 92, 92, 92, 114, 90, 90, 90, 90, 89, - /* 430 */ 89, 88, 88, 88, 87, 335, 311, 940, 841, 679, - /* 440 */ 713, 429, 835, 430, 251, 354, 250, 355, 288, 690, - /* 450 */ 691, 690, 691, 285, 941, 340, 971, 287, 210, 23, - /* 460 */ 174, 793, 832, 430, 353, 833, 10, 856, 856, 24, - /* 470 */ 942, 151, 753, 840, 840, 840, 794, 968, 1290, 321, - /* 480 */ 398, 1290, 356, 352, 754, 833, 49, 935, 93, 94, - /* 490 */ 84, 868, 871, 860, 860, 91, 91, 92, 92, 92, - /* 500 */ 92, 430, 90, 90, 90, 90, 89, 89, 88, 88, - /* 510 */ 88, 87, 335, 311, 376, 114, 907, 705, 430, 907, - /* 520 */ 328, 890, 114, 833, 10, 966, 430, 857, 857, 320, - /* 530 */ 189, 163, 832, 165, 430, 906, 344, 323, 906, 904, - /* 540 */ 833, 10, 965, 306, 856, 856, 187, 419, 833, 10, - /* 550 */ 220, 869, 872, 832, 222, 403, 833, 49, 1219, 793, - /* 560 */ 68, 937, 406, 245, 66, 93, 94, 84, 868, 871, - /* 570 */ 860, 860, 91, 91, 92, 92, 92, 92, 861, 90, - /* 580 */ 90, 90, 90, 89, 89, 88, 88, 88, 87, 335, - /* 590 */ 311, 404, 213, 762, 834, 345, 114, 940, 902, 368, - /* 600 */ 727, 5, 316, 192, 396, 772, 780, 269, 230, 242, - /* 610 */ 771, 244, 397, 164, 941, 385, 123, 347, 55, 355, - /* 620 */ 329, 856, 856, 728, 333, 332, 688, 968, 1291, 724, - /* 630 */ 942, 1291, 413, 214, 833, 9, 362, 286, 955, 115, - /* 640 */ 718, 311, 93, 94, 84, 868, 871, 860, 860, 91, - /* 650 */ 91, 92, 92, 92, 92, 430, 90, 90, 90, 90, - /* 660 */ 89, 89, 88, 88, 88, 87, 335, 912, 912, 1300, - /* 670 */ 1300, 758, 856, 856, 325, 966, 780, 833, 35, 747, - /* 680 */ 720, 334, 699, 700, 977, 652, 338, 243, 745, 920, - /* 690 */ 920, 369, 187, 93, 94, 84, 868, 871, 860, 860, - /* 700 */ 91, 91, 92, 92, 92, 92, 114, 90, 90, 90, - /* 710 */ 90, 89, 89, 88, 88, 88, 87, 335, 311, 430, - /* 720 */ 954, 430, 112, 310, 430, 693, 317, 698, 400, 430, - /* 730 */ 793, 359, 430, 1017, 430, 192, 430, 401, 780, 430, - /* 740 */ 360, 833, 36, 833, 12, 430, 833, 27, 316, 856, - /* 750 */ 856, 833, 37, 20, 833, 38, 833, 39, 833, 28, - /* 760 */ 72, 833, 29, 663, 664, 665, 264, 833, 40, 234, - /* 770 */ 93, 94, 84, 868, 871, 860, 860, 91, 91, 92, - /* 780 */ 92, 92, 92, 430, 90, 90, 90, 90, 89, 89, - /* 790 */ 88, 88, 88, 87, 335, 311, 430, 698, 430, 917, - /* 800 */ 147, 430, 165, 916, 275, 833, 41, 430, 780, 430, - /* 810 */ 21, 430, 259, 430, 262, 274, 430, 367, 833, 42, - /* 820 */ 833, 11, 430, 833, 43, 235, 856, 856, 793, 833, - /* 830 */ 99, 833, 44, 833, 45, 833, 32, 75, 833, 46, - /* 840 */ 305, 967, 257, 257, 833, 47, 311, 93, 94, 84, - /* 850 */ 868, 871, 860, 860, 91, 91, 92, 92, 92, 92, - /* 860 */ 430, 90, 90, 90, 90, 89, 89, 88, 88, 88, - /* 870 */ 87, 335, 430, 186, 185, 184, 238, 856, 856, 650, - /* 880 */ 2, 1064, 833, 33, 739, 217, 218, 257, 971, 257, - /* 890 */ 426, 317, 257, 774, 833, 117, 257, 311, 93, 94, - /* 900 */ 84, 868, 871, 860, 860, 91, 91, 92, 92, 92, - /* 910 */ 92, 430, 90, 90, 90, 90, 89, 89, 88, 88, - /* 920 */ 88, 87, 335, 430, 318, 124, 212, 163, 856, 856, - /* 930 */ 943, 900, 898, 833, 118, 759, 726, 725, 257, 755, - /* 940 */ 289, 289, 733, 734, 961, 833, 119, 682, 311, 93, - /* 950 */ 82, 84, 868, 871, 860, 860, 91, 91, 92, 92, - /* 960 */ 92, 92, 430, 90, 90, 90, 90, 89, 89, 88, - /* 970 */ 88, 88, 87, 335, 430, 716, 246, 322, 331, 856, - /* 980 */ 856, 256, 114, 357, 833, 53, 808, 913, 913, 932, - /* 990 */ 156, 416, 420, 424, 930, 809, 833, 34, 364, 311, - /* 1000 */ 253, 94, 84, 868, 871, 860, 860, 91, 91, 92, - /* 1010 */ 92, 92, 92, 430, 90, 90, 90, 90, 89, 89, - /* 1020 */ 88, 88, 88, 87, 335, 430, 114, 114, 114, 960, - /* 1030 */ 856, 856, 307, 258, 830, 833, 100, 191, 252, 377, - /* 1040 */ 267, 68, 197, 68, 261, 716, 769, 833, 50, 71, - /* 1050 */ 911, 911, 263, 84, 868, 871, 860, 860, 91, 91, - /* 1060 */ 92, 92, 92, 92, 430, 90, 90, 90, 90, 89, - /* 1070 */ 89, 88, 88, 88, 87, 335, 80, 425, 802, 3, - /* 1080 */ 1214, 191, 430, 265, 336, 336, 833, 101, 741, 80, - /* 1090 */ 425, 897, 3, 723, 722, 428, 721, 336, 336, 430, - /* 1100 */ 893, 270, 430, 197, 833, 102, 430, 800, 428, 430, - /* 1110 */ 695, 430, 843, 111, 414, 430, 784, 409, 430, 831, - /* 1120 */ 430, 833, 98, 123, 833, 116, 847, 414, 833, 49, - /* 1130 */ 779, 833, 113, 833, 106, 226, 123, 833, 105, 847, - /* 1140 */ 833, 103, 833, 104, 791, 411, 77, 78, 290, 412, - /* 1150 */ 430, 291, 114, 79, 432, 431, 389, 430, 835, 77, - /* 1160 */ 78, 897, 839, 408, 410, 430, 79, 432, 431, 372, - /* 1170 */ 703, 835, 833, 52, 430, 80, 425, 430, 3, 833, - /* 1180 */ 54, 772, 843, 336, 336, 684, 771, 833, 51, 840, - /* 1190 */ 840, 840, 842, 19, 428, 672, 833, 26, 671, 833, - /* 1200 */ 30, 673, 840, 840, 840, 842, 19, 207, 661, 278, - /* 1210 */ 304, 148, 280, 414, 282, 248, 358, 822, 382, 6, - /* 1220 */ 348, 161, 273, 80, 425, 847, 3, 934, 895, 720, - /* 1230 */ 894, 336, 336, 296, 157, 415, 241, 284, 674, 958, - /* 1240 */ 194, 953, 428, 951, 948, 77, 78, 777, 319, 56, - /* 1250 */ 59, 135, 79, 432, 431, 121, 66, 835, 146, 128, - /* 1260 */ 350, 414, 819, 130, 351, 131, 132, 133, 375, 173, - /* 1270 */ 107, 138, 149, 847, 365, 178, 62, 70, 425, 936, - /* 1280 */ 3, 827, 889, 371, 255, 336, 336, 792, 840, 840, - /* 1290 */ 840, 842, 19, 77, 78, 915, 428, 208, 179, 144, - /* 1300 */ 79, 432, 431, 373, 260, 835, 180, 326, 675, 181, - /* 1310 */ 308, 744, 388, 743, 731, 414, 718, 742, 730, 712, - /* 1320 */ 402, 309, 711, 272, 788, 65, 710, 847, 709, 277, - /* 1330 */ 193, 789, 787, 279, 876, 73, 840, 840, 840, 842, - /* 1340 */ 19, 786, 281, 418, 283, 422, 227, 77, 78, 330, - /* 1350 */ 228, 229, 96, 767, 79, 432, 431, 407, 67, 835, - /* 1360 */ 215, 292, 293, 405, 294, 303, 302, 301, 204, 299, - /* 1370 */ 295, 202, 676, 681, 7, 433, 669, 203, 205, 206, - /* 1380 */ 125, 110, 313, 434, 667, 666, 658, 168, 224, 237, - /* 1390 */ 840, 840, 840, 842, 19, 120, 656, 337, 236, 155, - /* 1400 */ 167, 341, 233, 314, 108, 905, 903, 826, 127, 126, - /* 1410 */ 756, 170, 129, 172, 247, 928, 134, 136, 171, 60, - /* 1420 */ 61, 123, 169, 137, 933, 175, 176, 927, 8, 13, - /* 1430 */ 177, 254, 918, 139, 191, 924, 140, 370, 678, 150, - /* 1440 */ 374, 182, 274, 268, 141, 122, 63, 14, 378, 15, - /* 1450 */ 383, 64, 225, 846, 845, 874, 16, 4, 729, 765, - /* 1460 */ 770, 162, 395, 209, 211, 142, 801, 878, 796, 312, - /* 1470 */ 71, 68, 875, 873, 939, 190, 417, 938, 17, 195, - /* 1480 */ 196, 152, 18, 975, 199, 976, 153, 198, 154, 421, - /* 1490 */ 877, 844, 696, 81, 200, 297, 343, 1019, 1018, 300, - /* 1500 */ 653, + /* 0 */ 324, 1323, 155, 155, 2, 203, 94, 94, 94, 93, + /* 10 */ 350, 98, 98, 98, 98, 91, 95, 95, 94, 94, + /* 20 */ 94, 93, 350, 268, 99, 100, 90, 971, 971, 847, + /* 30 */ 850, 839, 839, 97, 97, 98, 98, 98, 98, 350, + /* 40 */ 969, 96, 96, 96, 96, 95, 95, 94, 94, 94, + /* 50 */ 93, 350, 950, 96, 96, 96, 96, 95, 95, 94, + /* 60 */ 94, 94, 93, 350, 250, 96, 96, 96, 96, 95, + /* 70 */ 95, 94, 94, 94, 93, 350, 224, 224, 969, 132, + /* 80 */ 888, 348, 347, 415, 172, 324, 1286, 449, 414, 950, + /* 90 */ 951, 952, 808, 977, 1032, 950, 300, 786, 428, 132, + /* 100 */ 975, 362, 976, 9, 9, 787, 132, 52, 52, 99, + /* 110 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97, + /* 120 */ 98, 98, 98, 98, 372, 978, 241, 978, 262, 369, + /* 130 */ 261, 120, 950, 951, 952, 194, 58, 324, 401, 398, + /* 140 */ 397, 808, 427, 429, 75, 808, 1260, 1260, 132, 396, + /* 150 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 160 */ 350, 99, 100, 90, 971, 971, 847, 850, 839, 839, + /* 170 */ 97, 97, 98, 98, 98, 98, 786, 262, 369, 261, + /* 180 */ 826, 262, 364, 251, 787, 1084, 101, 1114, 72, 324, + /* 190 */ 227, 1113, 242, 411, 442, 819, 92, 89, 178, 818, + /* 200 */ 1022, 268, 96, 96, 96, 96, 95, 95, 94, 94, + /* 210 */ 94, 93, 350, 99, 100, 90, 971, 971, 847, 850, + /* 220 */ 839, 839, 97, 97, 98, 98, 98, 98, 449, 372, + /* 230 */ 818, 818, 820, 92, 89, 178, 60, 92, 89, 178, + /* 240 */ 1025, 324, 357, 930, 1316, 300, 61, 1316, 52, 52, + /* 250 */ 836, 836, 848, 851, 96, 96, 96, 96, 95, 95, + /* 260 */ 94, 94, 94, 93, 350, 99, 100, 90, 971, 971, + /* 270 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98, + /* 280 */ 92, 89, 178, 427, 412, 198, 930, 1317, 454, 995, + /* 290 */ 1317, 355, 1024, 324, 243, 231, 114, 277, 348, 347, + /* 300 */ 1242, 950, 416, 1071, 928, 840, 96, 96, 96, 96, + /* 310 */ 95, 95, 94, 94, 94, 93, 350, 99, 100, 90, + /* 320 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98, + /* 330 */ 98, 98, 449, 328, 449, 120, 23, 256, 950, 951, + /* 340 */ 952, 968, 978, 438, 978, 324, 329, 928, 954, 701, + /* 350 */ 200, 175, 52, 52, 52, 52, 939, 353, 96, 96, + /* 360 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 99, + /* 370 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97, + /* 380 */ 98, 98, 98, 98, 354, 449, 954, 427, 417, 427, + /* 390 */ 426, 1290, 92, 89, 178, 268, 253, 324, 255, 1058, + /* 400 */ 1037, 694, 93, 350, 383, 52, 52, 380, 1058, 374, + /* 410 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 420 */ 350, 99, 100, 90, 971, 971, 847, 850, 839, 839, + /* 430 */ 97, 97, 98, 98, 98, 98, 228, 449, 167, 449, + /* 440 */ 427, 407, 157, 446, 446, 446, 349, 349, 349, 324, + /* 450 */ 310, 316, 991, 827, 320, 242, 411, 51, 51, 36, + /* 460 */ 36, 254, 96, 96, 96, 96, 95, 95, 94, 94, + /* 470 */ 94, 93, 350, 99, 100, 90, 971, 971, 847, 850, + /* 480 */ 839, 839, 97, 97, 98, 98, 98, 98, 194, 316, + /* 490 */ 929, 401, 398, 397, 224, 224, 1265, 939, 353, 1318, + /* 500 */ 317, 324, 396, 1063, 1063, 813, 414, 1061, 1061, 950, + /* 510 */ 299, 448, 992, 268, 96, 96, 96, 96, 95, 95, + /* 520 */ 94, 94, 94, 93, 350, 99, 100, 90, 971, 971, + /* 530 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98, + /* 540 */ 757, 1041, 449, 893, 893, 386, 950, 951, 952, 410, + /* 550 */ 992, 747, 747, 324, 229, 268, 221, 296, 268, 771, + /* 560 */ 890, 378, 52, 52, 890, 421, 96, 96, 96, 96, + /* 570 */ 95, 95, 94, 94, 94, 93, 350, 99, 100, 90, + /* 580 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98, + /* 590 */ 98, 98, 103, 449, 275, 384, 1241, 343, 157, 1207, + /* 600 */ 909, 669, 670, 671, 176, 197, 196, 195, 324, 298, + /* 610 */ 319, 1266, 2, 37, 37, 910, 1134, 1040, 96, 96, + /* 620 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 697, + /* 630 */ 911, 177, 99, 100, 90, 971, 971, 847, 850, 839, + /* 640 */ 839, 97, 97, 98, 98, 98, 98, 230, 146, 120, + /* 650 */ 735, 1235, 826, 270, 1141, 273, 1141, 771, 171, 170, + /* 660 */ 736, 1141, 82, 324, 80, 268, 697, 819, 158, 268, + /* 670 */ 378, 818, 78, 96, 96, 96, 96, 95, 95, 94, + /* 680 */ 94, 94, 93, 350, 120, 950, 393, 99, 100, 90, + /* 690 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98, + /* 700 */ 98, 98, 818, 818, 820, 1141, 1070, 370, 331, 133, + /* 710 */ 1066, 1141, 1250, 198, 268, 324, 1016, 330, 245, 333, + /* 720 */ 24, 334, 950, 951, 952, 368, 335, 81, 96, 96, + /* 730 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 99, + /* 740 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97, + /* 750 */ 98, 98, 98, 98, 132, 267, 260, 445, 330, 223, + /* 760 */ 175, 1289, 925, 752, 724, 318, 1073, 324, 751, 246, + /* 770 */ 385, 301, 301, 378, 329, 361, 344, 414, 1233, 280, + /* 780 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, + /* 790 */ 350, 99, 88, 90, 971, 971, 847, 850, 839, 839, + /* 800 */ 97, 97, 98, 98, 98, 98, 337, 346, 721, 722, + /* 810 */ 449, 120, 118, 887, 162, 887, 810, 371, 324, 202, + /* 820 */ 202, 373, 249, 263, 202, 394, 74, 704, 208, 1069, + /* 830 */ 12, 12, 96, 96, 96, 96, 95, 95, 94, 94, + /* 840 */ 94, 93, 350, 100, 90, 971, 971, 847, 850, 839, + /* 850 */ 839, 97, 97, 98, 98, 98, 98, 449, 771, 232, + /* 860 */ 449, 278, 120, 286, 74, 704, 714, 713, 324, 342, + /* 870 */ 749, 877, 1209, 77, 285, 1255, 780, 52, 52, 202, + /* 880 */ 27, 27, 418, 96, 96, 96, 96, 95, 95, 94, + /* 890 */ 94, 94, 93, 350, 90, 971, 971, 847, 850, 839, + /* 900 */ 839, 97, 97, 98, 98, 98, 98, 86, 444, 877, + /* 910 */ 3, 1193, 422, 1013, 873, 435, 886, 208, 886, 689, + /* 920 */ 1091, 257, 116, 822, 447, 1230, 117, 1229, 86, 444, + /* 930 */ 177, 3, 381, 96, 96, 96, 96, 95, 95, 94, + /* 940 */ 94, 94, 93, 350, 339, 447, 120, 351, 120, 212, + /* 950 */ 169, 287, 404, 282, 403, 199, 771, 950, 433, 419, + /* 960 */ 439, 822, 280, 691, 1039, 264, 269, 132, 351, 153, + /* 970 */ 826, 376, 74, 272, 274, 276, 83, 84, 1054, 433, + /* 980 */ 147, 1038, 443, 85, 351, 451, 450, 281, 132, 818, + /* 990 */ 25, 826, 449, 120, 950, 951, 952, 83, 84, 86, + /* 1000 */ 444, 691, 3, 408, 85, 351, 451, 450, 449, 5, + /* 1010 */ 818, 203, 32, 32, 1107, 120, 447, 950, 225, 1140, + /* 1020 */ 818, 818, 820, 821, 19, 203, 226, 950, 38, 38, + /* 1030 */ 1087, 314, 314, 313, 215, 311, 120, 449, 678, 351, + /* 1040 */ 237, 818, 818, 820, 821, 19, 969, 409, 377, 1, + /* 1050 */ 433, 180, 706, 248, 950, 951, 952, 10, 10, 449, + /* 1060 */ 969, 247, 826, 1098, 950, 951, 952, 430, 83, 84, + /* 1070 */ 756, 336, 950, 20, 431, 85, 351, 451, 450, 10, + /* 1080 */ 10, 818, 86, 444, 969, 3, 950, 449, 302, 303, + /* 1090 */ 182, 950, 1146, 338, 1021, 1015, 1004, 183, 969, 447, + /* 1100 */ 132, 181, 76, 444, 21, 3, 449, 10, 10, 950, + /* 1110 */ 951, 952, 818, 818, 820, 821, 19, 715, 1279, 447, + /* 1120 */ 389, 233, 351, 950, 951, 952, 10, 10, 950, 951, + /* 1130 */ 952, 1003, 218, 433, 1005, 325, 1273, 773, 289, 291, + /* 1140 */ 424, 293, 351, 7, 159, 826, 363, 402, 315, 360, + /* 1150 */ 1129, 83, 84, 433, 1232, 716, 772, 259, 85, 351, + /* 1160 */ 451, 450, 358, 375, 818, 826, 360, 359, 399, 1211, + /* 1170 */ 157, 83, 84, 681, 98, 98, 98, 98, 85, 351, + /* 1180 */ 451, 450, 323, 252, 818, 295, 1211, 1213, 1235, 173, + /* 1190 */ 1037, 284, 434, 340, 1204, 818, 818, 820, 821, 19, + /* 1200 */ 308, 234, 449, 234, 96, 96, 96, 96, 95, 95, + /* 1210 */ 94, 94, 94, 93, 350, 818, 818, 820, 821, 19, + /* 1220 */ 909, 120, 39, 39, 1203, 449, 168, 360, 449, 1276, + /* 1230 */ 367, 449, 135, 449, 986, 910, 449, 1249, 449, 1247, + /* 1240 */ 449, 205, 983, 449, 370, 40, 40, 1211, 41, 41, + /* 1250 */ 911, 42, 42, 28, 28, 870, 29, 29, 31, 31, + /* 1260 */ 43, 43, 379, 44, 44, 449, 59, 449, 332, 449, + /* 1270 */ 432, 62, 144, 156, 449, 130, 449, 72, 449, 137, + /* 1280 */ 449, 365, 449, 392, 139, 45, 45, 11, 11, 46, + /* 1290 */ 46, 140, 1200, 449, 105, 105, 47, 47, 48, 48, + /* 1300 */ 33, 33, 49, 49, 1126, 449, 141, 366, 449, 185, + /* 1310 */ 142, 449, 1234, 50, 50, 449, 160, 449, 148, 449, + /* 1320 */ 1136, 382, 449, 67, 449, 34, 34, 449, 122, 122, + /* 1330 */ 449, 123, 123, 449, 1198, 124, 124, 56, 56, 35, + /* 1340 */ 35, 449, 106, 106, 53, 53, 449, 107, 107, 449, + /* 1350 */ 108, 108, 449, 104, 104, 449, 406, 449, 388, 449, + /* 1360 */ 189, 121, 121, 449, 190, 449, 119, 119, 449, 112, + /* 1370 */ 112, 449, 111, 111, 1218, 109, 109, 110, 110, 55, + /* 1380 */ 55, 266, 752, 57, 57, 54, 54, 751, 26, 26, + /* 1390 */ 1099, 30, 30, 219, 154, 390, 271, 191, 321, 1006, + /* 1400 */ 192, 405, 1057, 1056, 1055, 341, 1048, 706, 1047, 1029, + /* 1410 */ 322, 420, 1028, 71, 1095, 283, 288, 1027, 1288, 204, + /* 1420 */ 6, 297, 79, 1184, 437, 1096, 1094, 290, 345, 292, + /* 1430 */ 441, 1093, 294, 102, 425, 73, 423, 213, 1012, 22, + /* 1440 */ 452, 945, 214, 1077, 216, 217, 238, 453, 306, 304, + /* 1450 */ 307, 239, 240, 1001, 305, 125, 996, 126, 115, 235, + /* 1460 */ 127, 665, 352, 166, 244, 179, 356, 113, 885, 883, + /* 1470 */ 806, 136, 128, 738, 326, 138, 327, 258, 184, 899, + /* 1480 */ 143, 129, 145, 63, 64, 65, 66, 902, 186, 187, + /* 1490 */ 898, 8, 13, 188, 134, 265, 891, 202, 980, 387, + /* 1500 */ 150, 149, 680, 161, 391, 193, 285, 279, 395, 151, + /* 1510 */ 68, 717, 14, 15, 400, 69, 16, 131, 236, 825, + /* 1520 */ 824, 853, 746, 750, 4, 70, 174, 413, 220, 222, + /* 1530 */ 152, 779, 774, 77, 868, 74, 854, 201, 17, 852, + /* 1540 */ 908, 206, 907, 207, 18, 857, 934, 163, 436, 210, + /* 1550 */ 935, 164, 209, 165, 440, 856, 823, 312, 690, 87, + /* 1560 */ 211, 309, 1281, 940, 995, 1280, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 19, 144, 145, 146, 147, 24, 1, 2, 27, 80, - /* 10 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - /* 20 */ 91, 92, 93, 94, 95, 91, 92, 93, 94, 95, - /* 30 */ 19, 50, 51, 80, 81, 82, 83, 27, 85, 86, - /* 40 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 137, - /* 50 */ 177, 139, 71, 72, 73, 74, 75, 76, 77, 78, - /* 60 */ 79, 80, 81, 82, 83, 95, 85, 86, 87, 88, - /* 70 */ 89, 90, 91, 92, 93, 94, 95, 19, 97, 85, - /* 80 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - /* 90 */ 152, 33, 212, 173, 27, 28, 223, 224, 225, 152, - /* 100 */ 42, 181, 152, 223, 224, 225, 95, 97, 50, 51, - /* 110 */ 99, 100, 101, 102, 103, 104, 105, 27, 28, 59, - /* 120 */ 223, 224, 225, 112, 174, 175, 66, 94, 95, 71, - /* 130 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - /* 140 */ 82, 83, 195, 85, 86, 87, 88, 89, 90, 91, - /* 150 */ 92, 93, 94, 95, 19, 197, 89, 90, 220, 209, - /* 160 */ 210, 26, 119, 120, 97, 98, 208, 100, 108, 109, - /* 170 */ 110, 152, 157, 152, 107, 152, 109, 89, 90, 91, - /* 180 */ 92, 93, 94, 95, 163, 50, 51, 97, 98, 99, - /* 190 */ 55, 66, 102, 103, 104, 174, 175, 174, 175, 132, - /* 200 */ 133, 192, 193, 113, 66, 19, 71, 72, 73, 74, - /* 210 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 198, - /* 220 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - /* 230 */ 95, 152, 209, 210, 148, 149, 50, 51, 100, 53, - /* 240 */ 154, 59, 156, 174, 229, 27, 28, 232, 163, 163, - /* 250 */ 22, 192, 193, 174, 175, 27, 28, 71, 72, 73, - /* 260 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - /* 270 */ 251, 85, 86, 87, 88, 89, 90, 91, 92, 93, - /* 280 */ 94, 95, 19, 198, 198, 152, 152, 24, 209, 210, - /* 290 */ 108, 109, 110, 196, 197, 27, 28, 69, 164, 165, - /* 300 */ 152, 119, 120, 27, 28, 208, 99, 27, 28, 102, - /* 310 */ 103, 104, 152, 50, 51, 97, 98, 89, 90, 185, - /* 320 */ 113, 187, 22, 177, 174, 97, 58, 27, 28, 101, - /* 330 */ 115, 245, 117, 118, 71, 72, 73, 74, 75, 76, - /* 340 */ 77, 78, 79, 80, 81, 82, 83, 11, 85, 86, - /* 350 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 19, - /* 360 */ 132, 133, 134, 23, 152, 97, 98, 91, 174, 223, - /* 370 */ 224, 225, 239, 97, 98, 187, 22, 97, 98, 27, - /* 380 */ 28, 27, 28, 152, 223, 224, 225, 239, 152, 163, - /* 390 */ 50, 51, 170, 171, 172, 59, 160, 97, 98, 239, - /* 400 */ 164, 165, 66, 242, 124, 174, 175, 195, 22, 23, - /* 410 */ 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, - /* 420 */ 80, 81, 82, 83, 198, 85, 86, 87, 88, 89, - /* 430 */ 90, 91, 92, 93, 94, 95, 19, 12, 97, 21, - /* 440 */ 23, 152, 101, 152, 108, 109, 110, 221, 152, 97, - /* 450 */ 98, 97, 98, 152, 29, 243, 70, 226, 23, 233, - /* 460 */ 26, 26, 152, 152, 238, 174, 175, 50, 51, 22, - /* 470 */ 45, 24, 47, 132, 133, 134, 124, 22, 23, 188, - /* 480 */ 163, 26, 152, 65, 59, 174, 175, 163, 71, 72, - /* 490 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - /* 500 */ 83, 152, 85, 86, 87, 88, 89, 90, 91, 92, - /* 510 */ 93, 94, 95, 19, 19, 198, 152, 23, 152, 152, - /* 520 */ 209, 103, 198, 174, 175, 70, 152, 50, 51, 219, - /* 530 */ 213, 214, 152, 98, 152, 171, 172, 188, 171, 172, - /* 540 */ 174, 175, 248, 249, 50, 51, 51, 251, 174, 175, - /* 550 */ 220, 74, 75, 152, 188, 152, 174, 175, 140, 124, - /* 560 */ 26, 163, 188, 16, 130, 71, 72, 73, 74, 75, - /* 570 */ 76, 77, 78, 79, 80, 81, 82, 83, 101, 85, - /* 580 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - /* 590 */ 19, 209, 196, 197, 23, 231, 198, 12, 231, 219, - /* 600 */ 37, 22, 107, 24, 208, 116, 27, 112, 201, 62, - /* 610 */ 121, 64, 152, 152, 29, 52, 66, 221, 211, 221, - /* 620 */ 219, 50, 51, 60, 89, 90, 152, 22, 23, 183, - /* 630 */ 45, 26, 47, 22, 174, 175, 238, 152, 164, 165, - /* 640 */ 106, 19, 71, 72, 73, 74, 75, 76, 77, 78, - /* 650 */ 79, 80, 81, 82, 83, 152, 85, 86, 87, 88, - /* 660 */ 89, 90, 91, 92, 93, 94, 95, 132, 133, 119, - /* 670 */ 120, 163, 50, 51, 111, 70, 97, 174, 175, 181, - /* 680 */ 182, 170, 171, 172, 0, 1, 2, 140, 190, 108, - /* 690 */ 109, 110, 51, 71, 72, 73, 74, 75, 76, 77, - /* 700 */ 78, 79, 80, 81, 82, 83, 198, 85, 86, 87, - /* 710 */ 88, 89, 90, 91, 92, 93, 94, 95, 19, 152, - /* 720 */ 152, 152, 22, 166, 152, 168, 169, 27, 19, 152, - /* 730 */ 26, 19, 152, 122, 152, 24, 152, 28, 27, 152, - /* 740 */ 28, 174, 175, 174, 175, 152, 174, 175, 107, 50, - /* 750 */ 51, 174, 175, 22, 174, 175, 174, 175, 174, 175, - /* 760 */ 138, 174, 175, 7, 8, 9, 16, 174, 175, 152, - /* 770 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - /* 780 */ 81, 82, 83, 152, 85, 86, 87, 88, 89, 90, - /* 790 */ 91, 92, 93, 94, 95, 19, 152, 97, 152, 31, - /* 800 */ 24, 152, 98, 35, 101, 174, 175, 152, 97, 152, - /* 810 */ 79, 152, 62, 152, 64, 112, 152, 49, 174, 175, - /* 820 */ 174, 175, 152, 174, 175, 152, 50, 51, 124, 174, - /* 830 */ 175, 174, 175, 174, 175, 174, 175, 138, 174, 175, - /* 840 */ 22, 23, 152, 152, 174, 175, 19, 71, 72, 73, - /* 850 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - /* 860 */ 152, 85, 86, 87, 88, 89, 90, 91, 92, 93, - /* 870 */ 94, 95, 152, 108, 109, 110, 152, 50, 51, 146, - /* 880 */ 147, 23, 174, 175, 26, 195, 195, 152, 70, 152, - /* 890 */ 168, 169, 152, 26, 174, 175, 152, 19, 71, 72, - /* 900 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - /* 910 */ 83, 152, 85, 86, 87, 88, 89, 90, 91, 92, - /* 920 */ 93, 94, 95, 152, 246, 247, 213, 214, 50, 51, - /* 930 */ 195, 152, 195, 174, 175, 195, 100, 101, 152, 195, - /* 940 */ 152, 152, 7, 8, 152, 174, 175, 163, 19, 71, - /* 950 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - /* 960 */ 82, 83, 152, 85, 86, 87, 88, 89, 90, 91, - /* 970 */ 92, 93, 94, 95, 152, 27, 152, 189, 189, 50, - /* 980 */ 51, 195, 198, 152, 174, 175, 33, 132, 133, 152, - /* 990 */ 123, 163, 163, 163, 152, 42, 174, 175, 152, 19, - /* 1000 */ 152, 72, 73, 74, 75, 76, 77, 78, 79, 80, - /* 1010 */ 81, 82, 83, 152, 85, 86, 87, 88, 89, 90, - /* 1020 */ 91, 92, 93, 94, 95, 152, 198, 198, 198, 23, - /* 1030 */ 50, 51, 26, 152, 23, 174, 175, 26, 23, 23, - /* 1040 */ 23, 26, 26, 26, 152, 97, 23, 174, 175, 26, - /* 1050 */ 132, 133, 152, 73, 74, 75, 76, 77, 78, 79, - /* 1060 */ 80, 81, 82, 83, 152, 85, 86, 87, 88, 89, - /* 1070 */ 90, 91, 92, 93, 94, 95, 19, 20, 23, 22, - /* 1080 */ 23, 26, 152, 152, 27, 28, 174, 175, 152, 19, - /* 1090 */ 20, 27, 22, 183, 183, 38, 152, 27, 28, 152, - /* 1100 */ 23, 152, 152, 26, 174, 175, 152, 152, 38, 152, - /* 1110 */ 23, 152, 27, 26, 57, 152, 215, 163, 152, 152, - /* 1120 */ 152, 174, 175, 66, 174, 175, 69, 57, 174, 175, - /* 1130 */ 152, 174, 175, 174, 175, 212, 66, 174, 175, 69, - /* 1140 */ 174, 175, 174, 175, 152, 152, 89, 90, 152, 193, - /* 1150 */ 152, 152, 198, 96, 97, 98, 91, 152, 101, 89, - /* 1160 */ 90, 97, 152, 209, 210, 152, 96, 97, 98, 235, - /* 1170 */ 152, 101, 174, 175, 152, 19, 20, 152, 22, 174, - /* 1180 */ 175, 116, 97, 27, 28, 152, 121, 174, 175, 132, - /* 1190 */ 133, 134, 135, 136, 38, 152, 174, 175, 152, 174, - /* 1200 */ 175, 152, 132, 133, 134, 135, 136, 234, 152, 212, - /* 1210 */ 150, 199, 212, 57, 212, 240, 240, 203, 178, 200, - /* 1220 */ 216, 186, 177, 19, 20, 69, 22, 203, 177, 182, - /* 1230 */ 177, 27, 28, 202, 200, 228, 216, 216, 155, 39, - /* 1240 */ 122, 159, 38, 159, 41, 89, 90, 91, 159, 241, - /* 1250 */ 241, 22, 96, 97, 98, 71, 130, 101, 222, 191, - /* 1260 */ 18, 57, 203, 194, 159, 194, 194, 194, 18, 158, - /* 1270 */ 244, 191, 222, 69, 159, 158, 137, 19, 20, 203, - /* 1280 */ 22, 191, 203, 46, 236, 27, 28, 159, 132, 133, - /* 1290 */ 134, 135, 136, 89, 90, 237, 38, 159, 158, 22, - /* 1300 */ 96, 97, 98, 179, 159, 101, 158, 48, 159, 158, - /* 1310 */ 179, 176, 107, 176, 184, 57, 106, 176, 184, 176, - /* 1320 */ 125, 179, 178, 176, 218, 107, 176, 69, 176, 217, - /* 1330 */ 159, 218, 218, 217, 159, 137, 132, 133, 134, 135, - /* 1340 */ 136, 218, 217, 179, 217, 179, 227, 89, 90, 95, - /* 1350 */ 230, 230, 129, 207, 96, 97, 98, 126, 128, 101, - /* 1360 */ 5, 206, 205, 127, 204, 10, 11, 12, 13, 14, - /* 1370 */ 203, 25, 17, 162, 26, 161, 13, 153, 153, 6, - /* 1380 */ 247, 180, 250, 151, 151, 151, 151, 32, 180, 34, - /* 1390 */ 132, 133, 134, 135, 136, 167, 4, 3, 43, 22, - /* 1400 */ 15, 68, 142, 250, 16, 23, 23, 120, 111, 131, - /* 1410 */ 20, 56, 123, 125, 16, 1, 123, 131, 63, 79, - /* 1420 */ 79, 66, 67, 111, 28, 36, 122, 1, 5, 22, - /* 1430 */ 107, 140, 54, 54, 26, 61, 107, 44, 20, 24, - /* 1440 */ 19, 105, 112, 23, 22, 40, 22, 22, 53, 22, - /* 1450 */ 53, 22, 53, 23, 23, 23, 22, 22, 30, 116, - /* 1460 */ 23, 122, 26, 23, 23, 22, 28, 11, 124, 114, - /* 1470 */ 26, 26, 23, 23, 23, 36, 24, 23, 36, 26, - /* 1480 */ 22, 22, 36, 23, 122, 23, 22, 26, 22, 24, - /* 1490 */ 23, 23, 23, 22, 122, 23, 141, 122, 122, 15, - /* 1500 */ 1, + /* 0 */ 19, 144, 145, 146, 147, 24, 90, 91, 92, 93, + /* 10 */ 94, 54, 55, 56, 57, 58, 88, 89, 90, 91, + /* 20 */ 92, 93, 94, 152, 43, 44, 45, 46, 47, 48, + /* 30 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 94, + /* 40 */ 59, 84, 85, 86, 87, 88, 89, 90, 91, 92, + /* 50 */ 93, 94, 59, 84, 85, 86, 87, 88, 89, 90, + /* 60 */ 91, 92, 93, 94, 193, 84, 85, 86, 87, 88, + /* 70 */ 89, 90, 91, 92, 93, 94, 194, 195, 97, 79, + /* 80 */ 11, 88, 89, 152, 26, 19, 171, 152, 206, 96, + /* 90 */ 97, 98, 72, 100, 179, 59, 152, 31, 163, 79, + /* 100 */ 107, 219, 109, 172, 173, 39, 79, 172, 173, 43, + /* 110 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 120 */ 54, 55, 56, 57, 152, 132, 199, 134, 108, 109, + /* 130 */ 110, 196, 96, 97, 98, 99, 209, 19, 102, 103, + /* 140 */ 104, 72, 207, 208, 26, 72, 119, 120, 79, 113, + /* 150 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 160 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 170 */ 52, 53, 54, 55, 56, 57, 31, 108, 109, 110, + /* 180 */ 82, 108, 109, 110, 39, 210, 68, 175, 130, 19, + /* 190 */ 218, 175, 119, 120, 250, 97, 221, 222, 223, 101, + /* 200 */ 172, 152, 84, 85, 86, 87, 88, 89, 90, 91, + /* 210 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49, + /* 220 */ 50, 51, 52, 53, 54, 55, 56, 57, 152, 152, + /* 230 */ 132, 133, 134, 221, 222, 223, 66, 221, 222, 223, + /* 240 */ 172, 19, 193, 22, 23, 152, 24, 26, 172, 173, + /* 250 */ 46, 47, 48, 49, 84, 85, 86, 87, 88, 89, + /* 260 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, + /* 270 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 280 */ 221, 222, 223, 207, 208, 46, 22, 23, 148, 149, + /* 290 */ 26, 242, 172, 19, 154, 218, 156, 23, 88, 89, + /* 300 */ 241, 59, 163, 163, 83, 101, 84, 85, 86, 87, + /* 310 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45, + /* 320 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 330 */ 56, 57, 152, 157, 152, 196, 196, 16, 96, 97, + /* 340 */ 98, 26, 132, 250, 134, 19, 107, 83, 59, 23, + /* 350 */ 211, 212, 172, 173, 172, 173, 1, 2, 84, 85, + /* 360 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43, + /* 370 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 380 */ 54, 55, 56, 57, 244, 152, 97, 207, 208, 207, + /* 390 */ 208, 185, 221, 222, 223, 152, 75, 19, 77, 179, + /* 400 */ 180, 23, 93, 94, 228, 172, 173, 231, 188, 152, + /* 410 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 420 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 430 */ 52, 53, 54, 55, 56, 57, 193, 152, 123, 152, + /* 440 */ 207, 208, 152, 168, 169, 170, 168, 169, 170, 19, + /* 450 */ 160, 22, 23, 23, 164, 119, 120, 172, 173, 172, + /* 460 */ 173, 140, 84, 85, 86, 87, 88, 89, 90, 91, + /* 470 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49, + /* 480 */ 50, 51, 52, 53, 54, 55, 56, 57, 99, 22, + /* 490 */ 23, 102, 103, 104, 194, 195, 0, 1, 2, 247, + /* 500 */ 248, 19, 113, 190, 191, 23, 206, 190, 191, 59, + /* 510 */ 225, 152, 83, 152, 84, 85, 86, 87, 88, 89, + /* 520 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, + /* 530 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 540 */ 90, 181, 152, 108, 109, 110, 96, 97, 98, 115, + /* 550 */ 83, 117, 118, 19, 193, 152, 23, 152, 152, 26, + /* 560 */ 29, 152, 172, 173, 33, 152, 84, 85, 86, 87, + /* 570 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45, + /* 580 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 590 */ 56, 57, 22, 152, 16, 64, 193, 207, 152, 193, + /* 600 */ 12, 7, 8, 9, 152, 108, 109, 110, 19, 152, + /* 610 */ 164, 146, 147, 172, 173, 27, 163, 181, 84, 85, + /* 620 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 59, + /* 630 */ 42, 98, 43, 44, 45, 46, 47, 48, 49, 50, + /* 640 */ 51, 52, 53, 54, 55, 56, 57, 238, 22, 196, + /* 650 */ 62, 163, 82, 75, 152, 77, 152, 124, 88, 89, + /* 660 */ 72, 152, 137, 19, 139, 152, 96, 97, 24, 152, + /* 670 */ 152, 101, 138, 84, 85, 86, 87, 88, 89, 90, + /* 680 */ 91, 92, 93, 94, 196, 59, 19, 43, 44, 45, + /* 690 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 700 */ 56, 57, 132, 133, 134, 152, 193, 219, 245, 246, + /* 710 */ 193, 152, 152, 46, 152, 19, 166, 167, 152, 217, + /* 720 */ 232, 217, 96, 97, 98, 237, 217, 138, 84, 85, + /* 730 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43, + /* 740 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 750 */ 54, 55, 56, 57, 79, 193, 238, 166, 167, 211, + /* 760 */ 212, 23, 23, 116, 26, 26, 195, 19, 121, 152, + /* 770 */ 217, 152, 152, 152, 107, 100, 217, 206, 163, 112, + /* 780 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + /* 790 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 800 */ 52, 53, 54, 55, 56, 57, 187, 187, 7, 8, + /* 810 */ 152, 196, 22, 132, 24, 134, 23, 23, 19, 26, + /* 820 */ 26, 23, 152, 23, 26, 23, 26, 59, 26, 163, + /* 830 */ 172, 173, 84, 85, 86, 87, 88, 89, 90, 91, + /* 840 */ 92, 93, 94, 44, 45, 46, 47, 48, 49, 50, + /* 850 */ 51, 52, 53, 54, 55, 56, 57, 152, 26, 238, + /* 860 */ 152, 23, 196, 101, 26, 97, 100, 101, 19, 19, + /* 870 */ 23, 59, 152, 26, 112, 152, 23, 172, 173, 26, + /* 880 */ 172, 173, 19, 84, 85, 86, 87, 88, 89, 90, + /* 890 */ 91, 92, 93, 94, 45, 46, 47, 48, 49, 50, + /* 900 */ 51, 52, 53, 54, 55, 56, 57, 19, 20, 97, + /* 910 */ 22, 23, 207, 163, 23, 163, 132, 26, 134, 23, + /* 920 */ 213, 152, 26, 59, 36, 152, 22, 152, 19, 20, + /* 930 */ 98, 22, 152, 84, 85, 86, 87, 88, 89, 90, + /* 940 */ 91, 92, 93, 94, 94, 36, 196, 59, 196, 99, + /* 950 */ 100, 101, 102, 103, 104, 105, 124, 59, 70, 96, + /* 960 */ 163, 97, 112, 59, 181, 152, 152, 79, 59, 71, + /* 970 */ 82, 19, 26, 152, 152, 152, 88, 89, 152, 70, + /* 980 */ 22, 152, 163, 95, 96, 97, 98, 152, 79, 101, + /* 990 */ 22, 82, 152, 196, 96, 97, 98, 88, 89, 19, + /* 1000 */ 20, 97, 22, 163, 95, 96, 97, 98, 152, 22, + /* 1010 */ 101, 24, 172, 173, 152, 196, 36, 59, 22, 152, + /* 1020 */ 132, 133, 134, 135, 136, 24, 5, 59, 172, 173, + /* 1030 */ 152, 10, 11, 12, 13, 14, 196, 152, 17, 59, + /* 1040 */ 210, 132, 133, 134, 135, 136, 59, 207, 96, 22, + /* 1050 */ 70, 30, 106, 32, 96, 97, 98, 172, 173, 152, + /* 1060 */ 59, 40, 82, 152, 96, 97, 98, 152, 88, 89, + /* 1070 */ 90, 186, 59, 22, 191, 95, 96, 97, 98, 172, + /* 1080 */ 173, 101, 19, 20, 97, 22, 59, 152, 152, 152, + /* 1090 */ 69, 59, 152, 186, 152, 152, 152, 76, 97, 36, + /* 1100 */ 79, 80, 19, 20, 53, 22, 152, 172, 173, 96, + /* 1110 */ 97, 98, 132, 133, 134, 135, 136, 35, 122, 36, + /* 1120 */ 234, 186, 59, 96, 97, 98, 172, 173, 96, 97, + /* 1130 */ 98, 152, 233, 70, 152, 114, 152, 124, 210, 210, + /* 1140 */ 186, 210, 59, 198, 197, 82, 214, 65, 150, 152, + /* 1150 */ 201, 88, 89, 70, 201, 73, 124, 239, 95, 96, + /* 1160 */ 97, 98, 141, 239, 101, 82, 169, 170, 176, 152, + /* 1170 */ 152, 88, 89, 21, 54, 55, 56, 57, 95, 96, + /* 1180 */ 97, 98, 164, 214, 101, 214, 169, 170, 163, 184, + /* 1190 */ 180, 175, 227, 111, 175, 132, 133, 134, 135, 136, + /* 1200 */ 200, 183, 152, 185, 84, 85, 86, 87, 88, 89, + /* 1210 */ 90, 91, 92, 93, 94, 132, 133, 134, 135, 136, + /* 1220 */ 12, 196, 172, 173, 175, 152, 198, 230, 152, 155, + /* 1230 */ 78, 152, 243, 152, 60, 27, 152, 159, 152, 159, + /* 1240 */ 152, 122, 38, 152, 219, 172, 173, 230, 172, 173, + /* 1250 */ 42, 172, 173, 172, 173, 103, 172, 173, 172, 173, + /* 1260 */ 172, 173, 237, 172, 173, 152, 240, 152, 159, 152, + /* 1270 */ 62, 240, 22, 220, 152, 43, 152, 130, 152, 189, + /* 1280 */ 152, 18, 152, 18, 192, 172, 173, 172, 173, 172, + /* 1290 */ 173, 192, 140, 152, 172, 173, 172, 173, 172, 173, + /* 1300 */ 172, 173, 172, 173, 201, 152, 192, 159, 152, 158, + /* 1310 */ 192, 152, 201, 172, 173, 152, 220, 152, 189, 152, + /* 1320 */ 189, 159, 152, 137, 152, 172, 173, 152, 172, 173, + /* 1330 */ 152, 172, 173, 152, 201, 172, 173, 172, 173, 172, + /* 1340 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152, + /* 1350 */ 172, 173, 152, 172, 173, 152, 90, 152, 61, 152, + /* 1360 */ 158, 172, 173, 152, 158, 152, 172, 173, 152, 172, + /* 1370 */ 173, 152, 172, 173, 236, 172, 173, 172, 173, 172, + /* 1380 */ 173, 235, 116, 172, 173, 172, 173, 121, 172, 173, + /* 1390 */ 159, 172, 173, 159, 22, 177, 159, 158, 177, 159, + /* 1400 */ 158, 107, 174, 174, 174, 63, 182, 106, 182, 174, + /* 1410 */ 177, 125, 176, 107, 216, 174, 215, 174, 174, 159, + /* 1420 */ 22, 159, 137, 224, 177, 216, 216, 215, 94, 215, + /* 1430 */ 177, 216, 215, 129, 126, 128, 127, 25, 162, 26, + /* 1440 */ 161, 13, 153, 205, 153, 6, 226, 151, 202, 204, + /* 1450 */ 201, 229, 229, 151, 203, 165, 151, 165, 178, 178, + /* 1460 */ 165, 4, 3, 22, 142, 15, 81, 16, 23, 23, + /* 1470 */ 120, 131, 111, 20, 249, 123, 249, 16, 125, 1, + /* 1480 */ 123, 111, 131, 53, 53, 53, 53, 96, 34, 122, + /* 1490 */ 1, 5, 22, 107, 246, 140, 67, 26, 74, 41, + /* 1500 */ 107, 67, 20, 24, 19, 105, 112, 23, 66, 22, + /* 1510 */ 22, 28, 22, 22, 66, 22, 22, 37, 66, 23, + /* 1520 */ 23, 23, 116, 23, 22, 26, 122, 26, 23, 23, + /* 1530 */ 22, 96, 124, 26, 23, 26, 23, 34, 34, 23, + /* 1540 */ 23, 26, 23, 22, 34, 11, 23, 22, 24, 122, + /* 1550 */ 23, 22, 26, 22, 24, 23, 23, 15, 23, 22, + /* 1560 */ 122, 23, 122, 1, 251, 122, }; -#define YY_SHIFT_USE_DFLT (-89) -#define YY_SHIFT_COUNT (435) -#define YY_SHIFT_MIN (-88) -#define YY_SHIFT_MAX (1499) +#define YY_SHIFT_USE_DFLT (1566) +#define YY_SHIFT_COUNT (454) +#define YY_SHIFT_MIN (-84) +#define YY_SHIFT_MAX (1562) static const short yy_shift_ofst[] = { - /* 0 */ 5, 1057, 1355, 1070, 1204, 1204, 1204, 90, 60, -19, - /* 10 */ 58, 58, 186, 1204, 1204, 1204, 1204, 1204, 1204, 1204, - /* 20 */ 67, 67, 182, 336, 218, 550, 135, 263, 340, 417, - /* 30 */ 494, 571, 622, 699, 776, 827, 827, 827, 827, 827, - /* 40 */ 827, 827, 827, 827, 827, 827, 827, 827, 827, 827, - /* 50 */ 878, 827, 929, 980, 980, 1156, 1204, 1204, 1204, 1204, - /* 60 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, - /* 70 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, - /* 80 */ 1204, 1204, 1204, 1204, 1258, 1204, 1204, 1204, 1204, 1204, - /* 90 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, -71, -47, - /* 100 */ -47, -47, -47, -47, -6, 88, -66, 218, 218, 418, - /* 110 */ 495, 535, 535, 33, 43, 10, -30, -89, -89, -89, - /* 120 */ 11, 425, 425, 268, 455, 605, 218, 218, 218, 218, - /* 130 */ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, - /* 140 */ 218, 218, 218, 218, 218, 684, 138, 10, 43, 125, - /* 150 */ 125, 125, 125, 125, 125, -89, -89, -89, 228, 341, - /* 160 */ 341, 207, 276, 300, 280, 352, 354, 218, 218, 218, - /* 170 */ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, - /* 180 */ 218, 218, 218, 218, 563, 563, 563, 218, 218, 435, - /* 190 */ 218, 218, 218, 579, 218, 218, 585, 218, 218, 218, - /* 200 */ 218, 218, 218, 218, 218, 218, 218, 581, 768, 711, - /* 210 */ 711, 711, 704, 215, 1065, 756, 434, 709, 709, 712, - /* 220 */ 434, 712, 534, 858, 641, 953, 709, -88, 953, 953, - /* 230 */ 867, 489, 447, 1200, 1118, 1118, 1203, 1203, 1118, 1229, - /* 240 */ 1184, 1126, 1242, 1242, 1242, 1242, 1118, 1250, 1126, 1229, - /* 250 */ 1184, 1184, 1126, 1118, 1250, 1139, 1237, 1118, 1118, 1250, - /* 260 */ 1277, 1118, 1250, 1118, 1250, 1277, 1205, 1205, 1205, 1259, - /* 270 */ 1277, 1205, 1210, 1205, 1259, 1205, 1205, 1195, 1218, 1195, - /* 280 */ 1218, 1195, 1218, 1195, 1218, 1118, 1118, 1198, 1277, 1254, - /* 290 */ 1254, 1277, 1223, 1231, 1230, 1236, 1126, 1346, 1348, 1363, - /* 300 */ 1363, 1373, 1373, 1373, 1373, -89, -89, -89, -89, -89, - /* 310 */ -89, 477, 547, 386, 818, 750, 765, 700, 1006, 731, - /* 320 */ 1011, 1015, 1016, 1017, 948, 836, 935, 703, 1023, 1055, - /* 330 */ 1064, 1077, 855, 918, 1087, 1085, 611, 1392, 1394, 1377, - /* 340 */ 1260, 1385, 1333, 1388, 1382, 1383, 1287, 1278, 1297, 1289, - /* 350 */ 1390, 1288, 1398, 1414, 1293, 1286, 1340, 1341, 1312, 1396, - /* 360 */ 1389, 1304, 1426, 1423, 1407, 1323, 1291, 1378, 1408, 1379, - /* 370 */ 1374, 1393, 1329, 1415, 1418, 1421, 1330, 1336, 1422, 1395, - /* 380 */ 1424, 1425, 1420, 1427, 1397, 1428, 1429, 1399, 1405, 1430, - /* 390 */ 1431, 1432, 1343, 1434, 1437, 1435, 1436, 1339, 1440, 1441, - /* 400 */ 1438, 1439, 1443, 1344, 1444, 1442, 1445, 1446, 1444, 1449, - /* 410 */ 1450, 1451, 1453, 1454, 1458, 1456, 1460, 1459, 1452, 1461, - /* 420 */ 1462, 1464, 1465, 1461, 1467, 1466, 1468, 1469, 1471, 1362, - /* 430 */ 1372, 1375, 1376, 1472, 1484, 1499, + /* 0 */ 355, 888, 1021, 909, 1063, 1063, 1063, 1063, 20, -19, + /* 10 */ 66, 66, 170, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 20 */ -7, -7, 36, 73, 69, 27, 118, 222, 274, 326, + /* 30 */ 378, 430, 482, 534, 589, 644, 696, 696, 696, 696, + /* 40 */ 696, 696, 696, 696, 696, 696, 696, 696, 696, 696, + /* 50 */ 696, 696, 696, 748, 696, 799, 849, 849, 980, 1063, + /* 60 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 70 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 80 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 90 */ 1083, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 100 */ 1063, 1063, 1063, 1063, -43, 1120, 1120, 1120, 1120, 1120, + /* 110 */ -31, -72, -84, 242, 1152, 667, 210, 210, 242, 309, + /* 120 */ 336, -55, 1566, 1566, 1566, 850, 850, 850, 626, 626, + /* 130 */ 588, 588, 898, 221, 264, 242, 242, 242, 242, 242, + /* 140 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + /* 150 */ 242, 242, 242, 242, 242, 496, 675, 289, 289, 336, + /* 160 */ 0, 0, 0, 0, 0, 0, 1566, 1566, 1566, 570, + /* 170 */ 98, 98, 958, 389, 450, 968, 1013, 1032, 1027, 242, + /* 180 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + /* 190 */ 242, 242, 242, 242, 242, 1082, 1082, 1082, 242, 242, + /* 200 */ 533, 242, 242, 242, 987, 242, 242, 1208, 242, 242, + /* 210 */ 242, 242, 242, 242, 242, 242, 242, 242, 435, 531, + /* 220 */ 1001, 1001, 1001, 832, 434, 1266, 594, 58, 863, 863, + /* 230 */ 952, 58, 952, 946, 738, 239, 145, 863, 525, 145, + /* 240 */ 145, 315, 647, 790, 1174, 1119, 1119, 1204, 1204, 1119, + /* 250 */ 1250, 1232, 1147, 1263, 1263, 1263, 1263, 1119, 1265, 1147, + /* 260 */ 1250, 1232, 1232, 1147, 1119, 1265, 1186, 1297, 1119, 1119, + /* 270 */ 1265, 1372, 1119, 1265, 1119, 1265, 1372, 1294, 1294, 1294, + /* 280 */ 1342, 1372, 1294, 1301, 1294, 1342, 1294, 1294, 1286, 1306, + /* 290 */ 1286, 1306, 1286, 1306, 1286, 1306, 1119, 1398, 1119, 1285, + /* 300 */ 1372, 1334, 1334, 1372, 1304, 1308, 1307, 1309, 1147, 1412, + /* 310 */ 1413, 1428, 1428, 1439, 1439, 1439, 1566, 1566, 1566, 1566, + /* 320 */ 1566, 1566, 1566, 1566, 204, 321, 429, 467, 578, 497, + /* 330 */ 904, 739, 1051, 793, 794, 798, 800, 802, 838, 768, + /* 340 */ 766, 801, 762, 847, 853, 812, 891, 681, 784, 896, + /* 350 */ 864, 996, 1457, 1459, 1441, 1322, 1450, 1385, 1451, 1445, + /* 360 */ 1446, 1350, 1340, 1361, 1352, 1453, 1353, 1461, 1478, 1357, + /* 370 */ 1351, 1430, 1431, 1432, 1433, 1370, 1391, 1454, 1367, 1489, + /* 380 */ 1486, 1470, 1386, 1355, 1429, 1471, 1434, 1424, 1458, 1393, + /* 390 */ 1479, 1482, 1485, 1394, 1400, 1487, 1442, 1488, 1490, 1484, + /* 400 */ 1491, 1448, 1483, 1493, 1452, 1480, 1496, 1497, 1498, 1499, + /* 410 */ 1406, 1494, 1500, 1502, 1501, 1404, 1505, 1506, 1435, 1503, + /* 420 */ 1508, 1408, 1507, 1504, 1509, 1510, 1511, 1507, 1513, 1516, + /* 430 */ 1517, 1515, 1519, 1521, 1534, 1523, 1525, 1524, 1526, 1527, + /* 440 */ 1529, 1530, 1526, 1532, 1531, 1533, 1535, 1537, 1427, 1438, + /* 450 */ 1440, 1443, 1538, 1542, 1562, }; #define YY_REDUCE_USE_DFLT (-144) -#define YY_REDUCE_COUNT (310) +#define YY_REDUCE_COUNT (323) #define YY_REDUCE_MIN (-143) -#define YY_REDUCE_MAX (1235) +#define YY_REDUCE_MAX (1305) static const short yy_reduce_ofst[] = { - /* 0 */ -143, 954, 86, 21, -50, 23, 79, 134, 226, -120, - /* 10 */ -127, 146, 161, 291, 349, 366, 311, 382, 374, 231, - /* 20 */ 364, 367, 396, 398, 236, 317, -103, -103, -103, -103, - /* 30 */ -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - /* 40 */ -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, - /* 50 */ -103, -103, -103, -103, -103, 460, 503, 567, 569, 572, - /* 60 */ 577, 580, 582, 584, 587, 593, 631, 644, 646, 649, - /* 70 */ 655, 657, 659, 661, 664, 670, 708, 720, 759, 771, - /* 80 */ 810, 822, 861, 873, 912, 930, 947, 950, 957, 959, - /* 90 */ 963, 966, 968, 998, 1005, 1013, 1022, 1025, -103, -103, - /* 100 */ -103, -103, -103, -103, -103, -103, -103, 474, 212, 15, - /* 110 */ 498, 222, 511, -103, 97, 557, -103, -103, -103, -103, - /* 120 */ -80, 9, 59, 19, 294, 294, -53, -62, 690, 691, - /* 130 */ 735, 737, 740, 744, 133, 310, 148, 330, 160, 380, - /* 140 */ 786, 788, 401, 296, 789, 733, 85, 722, -42, 324, - /* 150 */ 508, 784, 828, 829, 830, 678, 713, 407, 69, 150, - /* 160 */ 194, 188, 289, 301, 403, 461, 485, 568, 617, 673, - /* 170 */ 724, 779, 792, 824, 831, 837, 842, 846, 848, 881, - /* 180 */ 892, 900, 931, 936, 446, 910, 911, 944, 949, 901, - /* 190 */ 955, 967, 978, 923, 992, 993, 956, 996, 999, 1010, - /* 200 */ 289, 1018, 1033, 1043, 1046, 1049, 1056, 934, 973, 997, - /* 210 */ 1000, 1002, 901, 1012, 1019, 1060, 1014, 1004, 1020, 975, - /* 220 */ 1024, 976, 1040, 1035, 1047, 1045, 1021, 1007, 1051, 1053, - /* 230 */ 1031, 1034, 1083, 1026, 1082, 1084, 1008, 1009, 1089, 1036, - /* 240 */ 1068, 1059, 1069, 1071, 1072, 1073, 1105, 1111, 1076, 1050, - /* 250 */ 1080, 1090, 1079, 1115, 1117, 1058, 1048, 1128, 1138, 1140, - /* 260 */ 1124, 1145, 1148, 1149, 1151, 1131, 1135, 1137, 1141, 1130, - /* 270 */ 1142, 1143, 1144, 1147, 1134, 1150, 1152, 1106, 1112, 1113, - /* 280 */ 1116, 1114, 1125, 1123, 1127, 1171, 1175, 1119, 1164, 1120, - /* 290 */ 1121, 1166, 1146, 1155, 1157, 1160, 1167, 1211, 1214, 1224, - /* 300 */ 1225, 1232, 1233, 1234, 1235, 1132, 1153, 1133, 1201, 1208, - /* 310 */ 1228, + /* 0 */ -143, -65, 140, 840, 76, 180, 182, 233, 488, -25, + /* 10 */ 12, 16, 59, 885, 907, 935, 390, 705, 954, 285, + /* 20 */ 997, 1017, 1018, -118, 1025, 139, 171, 171, 171, 171, + /* 30 */ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + /* 40 */ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + /* 50 */ 171, 171, 171, 171, 171, 171, 171, 171, -69, 287, + /* 60 */ 441, 658, 708, 856, 1050, 1073, 1076, 1079, 1081, 1084, + /* 70 */ 1086, 1088, 1091, 1113, 1115, 1117, 1122, 1124, 1126, 1128, + /* 80 */ 1130, 1141, 1153, 1156, 1159, 1163, 1165, 1167, 1170, 1172, + /* 90 */ 1175, 1178, 1181, 1189, 1194, 1197, 1200, 1203, 1205, 1207, + /* 100 */ 1211, 1213, 1216, 1219, 171, 171, 171, 171, 171, 171, + /* 110 */ 171, 171, 171, 49, 176, 220, 275, 278, 290, 171, + /* 120 */ 300, 171, 171, 171, 171, -85, -85, -85, -28, 77, + /* 130 */ 313, 317, -56, 252, 252, 446, -129, 243, 361, 403, + /* 140 */ 406, 513, 517, 409, 502, 518, 504, 509, 621, 553, + /* 150 */ 562, 619, 559, 93, 620, 465, 453, 550, 591, 571, + /* 160 */ 615, 666, 750, 752, 797, 819, 463, 548, -73, 28, + /* 170 */ 68, 120, 257, 206, 359, 405, 413, 452, 457, 560, + /* 180 */ 566, 617, 670, 720, 723, 769, 773, 775, 780, 813, + /* 190 */ 814, 821, 822, 823, 826, 360, 436, 783, 829, 835, + /* 200 */ 707, 862, 867, 878, 830, 911, 915, 883, 936, 937, + /* 210 */ 940, 359, 942, 943, 944, 979, 982, 984, 886, 899, + /* 220 */ 928, 929, 931, 707, 947, 945, 998, 949, 932, 969, + /* 230 */ 918, 953, 924, 992, 1005, 1010, 1016, 971, 965, 1019, + /* 240 */ 1049, 1000, 1028, 1074, 989, 1078, 1080, 1026, 1031, 1109, + /* 250 */ 1053, 1090, 1103, 1092, 1099, 1114, 1118, 1148, 1151, 1111, + /* 260 */ 1096, 1129, 1131, 1133, 1162, 1202, 1138, 1146, 1231, 1234, + /* 270 */ 1206, 1218, 1237, 1239, 1240, 1242, 1221, 1228, 1229, 1230, + /* 280 */ 1224, 1233, 1235, 1236, 1241, 1226, 1243, 1244, 1198, 1201, + /* 290 */ 1209, 1212, 1210, 1214, 1215, 1217, 1260, 1199, 1262, 1220, + /* 300 */ 1247, 1222, 1223, 1253, 1238, 1245, 1251, 1246, 1249, 1276, + /* 310 */ 1279, 1289, 1291, 1296, 1302, 1305, 1225, 1227, 1248, 1290, + /* 320 */ 1292, 1280, 1281, 1295, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 982, 1300, 1300, 1300, 1214, 1214, 1214, 1305, 1300, 1109, - /* 10 */ 1138, 1138, 1274, 1305, 1305, 1305, 1305, 1305, 1305, 1212, - /* 20 */ 1305, 1305, 1305, 1300, 1305, 1113, 1144, 1305, 1305, 1305, - /* 30 */ 1305, 1305, 1305, 1305, 1305, 1273, 1275, 1152, 1151, 1254, - /* 40 */ 1125, 1149, 1142, 1146, 1215, 1208, 1209, 1207, 1211, 1216, - /* 50 */ 1305, 1145, 1177, 1192, 1176, 1305, 1305, 1305, 1305, 1305, - /* 60 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 70 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 80 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 90 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1186, 1191, - /* 100 */ 1198, 1190, 1187, 1179, 1178, 1180, 1181, 1305, 1305, 1008, - /* 110 */ 1074, 1305, 1305, 1182, 1305, 1020, 1183, 1195, 1194, 1193, - /* 120 */ 1015, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 130 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 140 */ 1305, 1305, 1305, 1305, 1305, 982, 1300, 1305, 1305, 1300, - /* 150 */ 1300, 1300, 1300, 1300, 1300, 1292, 1113, 1103, 1305, 1305, - /* 160 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1280, 1278, - /* 170 */ 1305, 1227, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 180 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 190 */ 1305, 1305, 1305, 1109, 1305, 1305, 1305, 1305, 1305, 1305, - /* 200 */ 1305, 1305, 1305, 1305, 1305, 1305, 988, 1305, 1247, 1109, - /* 210 */ 1109, 1109, 1111, 1089, 1101, 990, 1148, 1127, 1127, 1259, - /* 220 */ 1148, 1259, 1045, 1068, 1042, 1138, 1127, 1210, 1138, 1138, - /* 230 */ 1110, 1101, 1305, 1285, 1118, 1118, 1277, 1277, 1118, 1157, - /* 240 */ 1078, 1148, 1085, 1085, 1085, 1085, 1118, 1005, 1148, 1157, - /* 250 */ 1078, 1078, 1148, 1118, 1005, 1253, 1251, 1118, 1118, 1005, - /* 260 */ 1220, 1118, 1005, 1118, 1005, 1220, 1076, 1076, 1076, 1060, - /* 270 */ 1220, 1076, 1045, 1076, 1060, 1076, 1076, 1131, 1126, 1131, - /* 280 */ 1126, 1131, 1126, 1131, 1126, 1118, 1118, 1305, 1220, 1224, - /* 290 */ 1224, 1220, 1143, 1132, 1141, 1139, 1148, 1011, 1063, 998, - /* 300 */ 998, 987, 987, 987, 987, 1297, 1297, 1292, 1047, 1047, - /* 310 */ 1030, 1305, 1305, 1305, 1305, 1305, 1305, 1022, 1305, 1229, - /* 320 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 330 */ 1305, 1305, 1305, 1305, 1305, 1305, 1164, 1305, 983, 1287, - /* 340 */ 1305, 1305, 1284, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 350 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 360 */ 1305, 1257, 1305, 1305, 1305, 1305, 1305, 1305, 1250, 1249, - /* 370 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 380 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, - /* 390 */ 1305, 1305, 1092, 1305, 1305, 1305, 1096, 1305, 1305, 1305, - /* 400 */ 1305, 1305, 1305, 1305, 1140, 1305, 1133, 1305, 1213, 1305, - /* 410 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1302, - /* 420 */ 1305, 1305, 1305, 1301, 1305, 1305, 1305, 1305, 1305, 1166, - /* 430 */ 1305, 1165, 1169, 1305, 996, 1305, + /* 0 */ 1270, 1260, 1260, 1260, 1193, 1193, 1193, 1193, 1260, 1088, + /* 10 */ 1117, 1117, 1244, 1322, 1322, 1322, 1322, 1322, 1322, 1192, + /* 20 */ 1322, 1322, 1322, 1322, 1260, 1092, 1123, 1322, 1322, 1322, + /* 30 */ 1322, 1194, 1195, 1322, 1322, 1322, 1243, 1245, 1133, 1132, + /* 40 */ 1131, 1130, 1226, 1104, 1128, 1121, 1125, 1194, 1188, 1189, + /* 50 */ 1187, 1191, 1195, 1322, 1124, 1158, 1172, 1157, 1322, 1322, + /* 60 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 70 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 80 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 90 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 100 */ 1322, 1322, 1322, 1322, 1166, 1171, 1178, 1170, 1167, 1160, + /* 110 */ 1159, 1161, 1162, 1322, 1011, 1059, 1322, 1322, 1322, 1163, + /* 120 */ 1322, 1164, 1175, 1174, 1173, 1251, 1278, 1277, 1322, 1322, + /* 130 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 140 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 150 */ 1322, 1322, 1322, 1322, 1322, 1270, 1260, 1017, 1017, 1322, + /* 160 */ 1260, 1260, 1260, 1260, 1260, 1260, 1256, 1092, 1083, 1322, + /* 170 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 180 */ 1248, 1246, 1322, 1208, 1322, 1322, 1322, 1322, 1322, 1322, + /* 190 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 200 */ 1322, 1322, 1322, 1322, 1088, 1322, 1322, 1322, 1322, 1322, + /* 210 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1272, 1322, 1221, + /* 220 */ 1088, 1088, 1088, 1090, 1072, 1082, 997, 1127, 1106, 1106, + /* 230 */ 1311, 1127, 1311, 1034, 1292, 1031, 1117, 1106, 1190, 1117, + /* 240 */ 1117, 1089, 1082, 1322, 1314, 1097, 1097, 1313, 1313, 1097, + /* 250 */ 1138, 1062, 1127, 1068, 1068, 1068, 1068, 1097, 1008, 1127, + /* 260 */ 1138, 1062, 1062, 1127, 1097, 1008, 1225, 1308, 1097, 1097, + /* 270 */ 1008, 1201, 1097, 1008, 1097, 1008, 1201, 1060, 1060, 1060, + /* 280 */ 1049, 1201, 1060, 1034, 1060, 1049, 1060, 1060, 1110, 1105, + /* 290 */ 1110, 1105, 1110, 1105, 1110, 1105, 1097, 1196, 1097, 1322, + /* 300 */ 1201, 1205, 1205, 1201, 1122, 1111, 1120, 1118, 1127, 1014, + /* 310 */ 1052, 1275, 1275, 1271, 1271, 1271, 1319, 1319, 1256, 1287, + /* 320 */ 1287, 1036, 1036, 1287, 1322, 1322, 1322, 1322, 1322, 1322, + /* 330 */ 1282, 1322, 1210, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 340 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 350 */ 1322, 1143, 1322, 993, 1253, 1322, 1322, 1252, 1322, 1322, + /* 360 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 370 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1310, 1322, + /* 380 */ 1322, 1322, 1322, 1322, 1322, 1224, 1223, 1322, 1322, 1322, + /* 390 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 400 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, + /* 410 */ 1074, 1322, 1322, 1322, 1296, 1322, 1322, 1322, 1322, 1322, + /* 420 */ 1322, 1322, 1119, 1322, 1112, 1322, 1322, 1301, 1322, 1322, + /* 430 */ 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1262, 1322, + /* 440 */ 1322, 1322, 1261, 1322, 1322, 1322, 1322, 1322, 1145, 1322, + /* 450 */ 1144, 1148, 1322, 1002, 1322, }; /********** End of lemon-generated parsing tables *****************************/ @@ -128061,74 +137786,87 @@ static const YYACTIONTYPE yy_default[] = { static const YYCODETYPE yyFallback[] = { 0, /* $ => nothing */ 0, /* SEMI => nothing */ - 27, /* EXPLAIN => ID */ - 27, /* QUERY => ID */ - 27, /* PLAN => ID */ - 27, /* BEGIN => ID */ + 59, /* EXPLAIN => ID */ + 59, /* QUERY => ID */ + 59, /* PLAN => ID */ + 59, /* BEGIN => ID */ 0, /* TRANSACTION => nothing */ - 27, /* DEFERRED => ID */ - 27, /* IMMEDIATE => ID */ - 27, /* EXCLUSIVE => ID */ + 59, /* DEFERRED => ID */ + 59, /* IMMEDIATE => ID */ + 59, /* EXCLUSIVE => ID */ 0, /* COMMIT => nothing */ - 27, /* END => ID */ - 27, /* ROLLBACK => ID */ - 27, /* SAVEPOINT => ID */ - 27, /* RELEASE => ID */ + 59, /* END => ID */ + 59, /* ROLLBACK => ID */ + 59, /* SAVEPOINT => ID */ + 59, /* RELEASE => ID */ 0, /* TO => nothing */ 0, /* TABLE => nothing */ 0, /* CREATE => nothing */ - 27, /* IF => ID */ + 59, /* IF => ID */ 0, /* NOT => nothing */ 0, /* EXISTS => nothing */ - 27, /* TEMP => ID */ + 59, /* TEMP => ID */ 0, /* LP => nothing */ 0, /* RP => nothing */ 0, /* AS => nothing */ - 27, /* WITHOUT => ID */ + 59, /* WITHOUT => ID */ 0, /* COMMA => nothing */ + 59, /* ABORT => ID */ + 59, /* ACTION => ID */ + 59, /* AFTER => ID */ + 59, /* ANALYZE => ID */ + 59, /* ASC => ID */ + 59, /* ATTACH => ID */ + 59, /* BEFORE => ID */ + 59, /* BY => ID */ + 59, /* CASCADE => ID */ + 59, /* CAST => ID */ + 59, /* CONFLICT => ID */ + 59, /* DATABASE => ID */ + 59, /* DESC => ID */ + 59, /* DETACH => ID */ + 59, /* EACH => ID */ + 59, /* FAIL => ID */ + 0, /* OR => nothing */ + 0, /* AND => nothing */ + 0, /* IS => nothing */ + 59, /* MATCH => ID */ + 59, /* LIKE_KW => ID */ + 0, /* BETWEEN => nothing */ + 0, /* IN => nothing */ + 0, /* ISNULL => nothing */ + 0, /* NOTNULL => nothing */ + 0, /* NE => nothing */ + 0, /* EQ => nothing */ + 0, /* GT => nothing */ + 0, /* LE => nothing */ + 0, /* LT => nothing */ + 0, /* GE => nothing */ + 0, /* ESCAPE => nothing */ 0, /* ID => nothing */ - 0, /* INDEXED => nothing */ - 27, /* ABORT => ID */ - 27, /* ACTION => ID */ - 27, /* AFTER => ID */ - 27, /* ANALYZE => ID */ - 27, /* ASC => ID */ - 27, /* ATTACH => ID */ - 27, /* BEFORE => ID */ - 27, /* BY => ID */ - 27, /* CASCADE => ID */ - 27, /* CAST => ID */ - 27, /* COLUMNKW => ID */ - 27, /* CONFLICT => ID */ - 27, /* DATABASE => ID */ - 27, /* DESC => ID */ - 27, /* DETACH => ID */ - 27, /* EACH => ID */ - 27, /* FAIL => ID */ - 27, /* FOR => ID */ - 27, /* IGNORE => ID */ - 27, /* INITIALLY => ID */ - 27, /* INSTEAD => ID */ - 27, /* LIKE_KW => ID */ - 27, /* MATCH => ID */ - 27, /* NO => ID */ - 27, /* KEY => ID */ - 27, /* OF => ID */ - 27, /* OFFSET => ID */ - 27, /* PRAGMA => ID */ - 27, /* RAISE => ID */ - 27, /* RECURSIVE => ID */ - 27, /* REPLACE => ID */ - 27, /* RESTRICT => ID */ - 27, /* ROW => ID */ - 27, /* TRIGGER => ID */ - 27, /* VACUUM => ID */ - 27, /* VIEW => ID */ - 27, /* VIRTUAL => ID */ - 27, /* WITH => ID */ - 27, /* REINDEX => ID */ - 27, /* RENAME => ID */ - 27, /* CTIME_KW => ID */ + 59, /* COLUMNKW => ID */ + 59, /* FOR => ID */ + 59, /* IGNORE => ID */ + 59, /* INITIALLY => ID */ + 59, /* INSTEAD => ID */ + 59, /* NO => ID */ + 59, /* KEY => ID */ + 59, /* OF => ID */ + 59, /* OFFSET => ID */ + 59, /* PRAGMA => ID */ + 59, /* RAISE => ID */ + 59, /* RECURSIVE => ID */ + 59, /* REPLACE => ID */ + 59, /* RESTRICT => ID */ + 59, /* ROW => ID */ + 59, /* TRIGGER => ID */ + 59, /* VACUUM => ID */ + 59, /* VIEW => ID */ + 59, /* VIRTUAL => ID */ + 59, /* WITH => ID */ + 59, /* REINDEX => ID */ + 59, /* RENAME => ID */ + 59, /* CTIME_KW => ID */ }; #endif /* YYFALLBACK */ @@ -128160,17 +137898,21 @@ typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { - int yyidx; /* Index of top element in stack */ + yyStackEntry *yytos; /* Pointer to top element of the stack */ #ifdef YYTRACKMAXSTACKDEPTH - int yyidxMax; /* Maximum value of yyidx */ + int yyhwm; /* High-water mark of the stack */ #endif +#ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ +#endif sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ + yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; @@ -128217,25 +137959,25 @@ static const char *const yyTokenName[] = { "ROLLBACK", "SAVEPOINT", "RELEASE", "TO", "TABLE", "CREATE", "IF", "NOT", "EXISTS", "TEMP", "LP", "RP", - "AS", "WITHOUT", "COMMA", "ID", - "INDEXED", "ABORT", "ACTION", "AFTER", - "ANALYZE", "ASC", "ATTACH", "BEFORE", - "BY", "CASCADE", "CAST", "COLUMNKW", - "CONFLICT", "DATABASE", "DESC", "DETACH", - "EACH", "FAIL", "FOR", "IGNORE", - "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH", - "NO", "KEY", "OF", "OFFSET", - "PRAGMA", "RAISE", "RECURSIVE", "REPLACE", - "RESTRICT", "ROW", "TRIGGER", "VACUUM", - "VIEW", "VIRTUAL", "WITH", "REINDEX", - "RENAME", "CTIME_KW", "ANY", "OR", - "AND", "IS", "BETWEEN", "IN", - "ISNULL", "NOTNULL", "NE", "EQ", - "GT", "LE", "LT", "GE", - "ESCAPE", "BITAND", "BITOR", "LSHIFT", - "RSHIFT", "PLUS", "MINUS", "STAR", - "SLASH", "REM", "CONCAT", "COLLATE", - "BITNOT", "STRING", "JOIN_KW", "CONSTRAINT", + "AS", "WITHOUT", "COMMA", "ABORT", + "ACTION", "AFTER", "ANALYZE", "ASC", + "ATTACH", "BEFORE", "BY", "CASCADE", + "CAST", "CONFLICT", "DATABASE", "DESC", + "DETACH", "EACH", "FAIL", "OR", + "AND", "IS", "MATCH", "LIKE_KW", + "BETWEEN", "IN", "ISNULL", "NOTNULL", + "NE", "EQ", "GT", "LE", + "LT", "GE", "ESCAPE", "ID", + "COLUMNKW", "FOR", "IGNORE", "INITIALLY", + "INSTEAD", "NO", "KEY", "OF", + "OFFSET", "PRAGMA", "RAISE", "RECURSIVE", + "REPLACE", "RESTRICT", "ROW", "TRIGGER", + "VACUUM", "VIEW", "VIRTUAL", "WITH", + "REINDEX", "RENAME", "CTIME_KW", "ANY", + "BITAND", "BITOR", "LSHIFT", "RSHIFT", + "PLUS", "MINUS", "STAR", "SLASH", + "REM", "CONCAT", "COLLATE", "BITNOT", + "INDEXED", "STRING", "JOIN_KW", "CONSTRAINT", "DEFAULT", "NULL", "PRIMARY", "UNIQUE", "CHECK", "REFERENCES", "AUTOINCR", "ON", "INSERT", "DELETE", "UPDATE", "SET", @@ -128244,7 +137986,7 @@ static const char *const yyTokenName[] = { "VALUES", "DISTINCT", "DOT", "FROM", "JOIN", "USING", "ORDER", "GROUP", "HAVING", "LIMIT", "WHERE", "INTO", - "INTEGER", "FLOAT", "BLOB", "VARIABLE", + "FLOAT", "BLOB", "INTEGER", "VARIABLE", "CASE", "WHEN", "THEN", "ELSE", "INDEX", "ALTER", "ADD", "error", "input", "cmdlist", "ecmd", "explain", @@ -128252,28 +137994,28 @@ static const char *const yyTokenName[] = { "nm", "savepoint_opt", "create_table", "create_table_args", "createkw", "temp", "ifnotexists", "dbnm", "columnlist", "conslist_opt", "table_options", "select", - "column", "columnid", "type", "carglist", - "typetoken", "typename", "signed", "plus_num", - "minus_num", "ccons", "term", "expr", - "onconf", "sortorder", "autoinc", "eidlist_opt", - "refargs", "defer_subclause", "refarg", "refact", - "init_deferred_pred_opt", "conslist", "tconscomma", "tcons", - "sortlist", "eidlist", "defer_subclause_opt", "orconf", - "resolvetype", "raisetype", "ifexists", "fullname", - "selectnowith", "oneselect", "with", "multiselect_op", - "distinct", "selcollist", "from", "where_opt", - "groupby_opt", "having_opt", "orderby_opt", "limit_opt", - "values", "nexprlist", "exprlist", "sclp", - "as", "seltablist", "stl_prefix", "joinop", - "indexed_opt", "on_opt", "using_opt", "idlist", - "setlist", "insert_cmd", "idlist_opt", "likeop", - "between_op", "in_op", "case_operand", "case_exprlist", - "case_else", "uniqueflag", "collate", "nmnum", - "trigger_decl", "trigger_cmd_list", "trigger_time", "trigger_event", - "foreach_clause", "when_clause", "trigger_cmd", "trnm", - "tridxby", "database_kw_opt", "key_opt", "add_column_fullname", - "kwcolumn_opt", "create_vtab", "vtabarglist", "vtabarg", - "vtabargtoken", "lp", "anylist", "wqlist", + "columnname", "carglist", "typetoken", "typename", + "signed", "plus_num", "minus_num", "ccons", + "term", "expr", "onconf", "sortorder", + "autoinc", "eidlist_opt", "refargs", "defer_subclause", + "refarg", "refact", "init_deferred_pred_opt", "conslist", + "tconscomma", "tcons", "sortlist", "eidlist", + "defer_subclause_opt", "orconf", "resolvetype", "raisetype", + "ifexists", "fullname", "selectnowith", "oneselect", + "with", "multiselect_op", "distinct", "selcollist", + "from", "where_opt", "groupby_opt", "having_opt", + "orderby_opt", "limit_opt", "values", "nexprlist", + "exprlist", "sclp", "as", "seltablist", + "stl_prefix", "joinop", "indexed_opt", "on_opt", + "using_opt", "idlist", "setlist", "insert_cmd", + "idlist_opt", "likeop", "between_op", "in_op", + "paren_exprlist", "case_operand", "case_exprlist", "case_else", + "uniqueflag", "collate", "nmnum", "trigger_decl", + "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause", + "when_clause", "trigger_cmd", "trnm", "tridxby", + "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt", + "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken", + "lp", "anylist", "wqlist", }; #endif /* NDEBUG */ @@ -128281,358 +138023,369 @@ static const char *const yyTokenName[] = { /* For tracing reduce actions, the names of all rules are required. */ static const char *const yyRuleName[] = { - /* 0 */ "input ::= cmdlist", - /* 1 */ "cmdlist ::= cmdlist ecmd", - /* 2 */ "cmdlist ::= ecmd", - /* 3 */ "ecmd ::= SEMI", - /* 4 */ "ecmd ::= explain cmdx SEMI", - /* 5 */ "explain ::=", - /* 6 */ "explain ::= EXPLAIN", - /* 7 */ "explain ::= EXPLAIN QUERY PLAN", - /* 8 */ "cmdx ::= cmd", - /* 9 */ "cmd ::= BEGIN transtype trans_opt", - /* 10 */ "trans_opt ::=", - /* 11 */ "trans_opt ::= TRANSACTION", - /* 12 */ "trans_opt ::= TRANSACTION nm", - /* 13 */ "transtype ::=", - /* 14 */ "transtype ::= DEFERRED", - /* 15 */ "transtype ::= IMMEDIATE", - /* 16 */ "transtype ::= EXCLUSIVE", - /* 17 */ "cmd ::= COMMIT trans_opt", - /* 18 */ "cmd ::= END trans_opt", - /* 19 */ "cmd ::= ROLLBACK trans_opt", - /* 20 */ "savepoint_opt ::= SAVEPOINT", - /* 21 */ "savepoint_opt ::=", - /* 22 */ "cmd ::= SAVEPOINT nm", - /* 23 */ "cmd ::= RELEASE savepoint_opt nm", - /* 24 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", - /* 25 */ "cmd ::= create_table create_table_args", - /* 26 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", - /* 27 */ "createkw ::= CREATE", - /* 28 */ "ifnotexists ::=", - /* 29 */ "ifnotexists ::= IF NOT EXISTS", - /* 30 */ "temp ::= TEMP", - /* 31 */ "temp ::=", - /* 32 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", - /* 33 */ "create_table_args ::= AS select", - /* 34 */ "table_options ::=", - /* 35 */ "table_options ::= WITHOUT nm", - /* 36 */ "columnlist ::= columnlist COMMA column", - /* 37 */ "columnlist ::= column", - /* 38 */ "column ::= columnid type carglist", - /* 39 */ "columnid ::= nm", - /* 40 */ "nm ::= ID|INDEXED", - /* 41 */ "nm ::= STRING", - /* 42 */ "nm ::= JOIN_KW", - /* 43 */ "type ::=", - /* 44 */ "type ::= typetoken", - /* 45 */ "typetoken ::= typename", - /* 46 */ "typetoken ::= typename LP signed RP", - /* 47 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 48 */ "typename ::= ID|STRING", - /* 49 */ "typename ::= typename ID|STRING", - /* 50 */ "signed ::= plus_num", - /* 51 */ "signed ::= minus_num", - /* 52 */ "carglist ::= carglist ccons", - /* 53 */ "carglist ::=", - /* 54 */ "ccons ::= CONSTRAINT nm", - /* 55 */ "ccons ::= DEFAULT term", - /* 56 */ "ccons ::= DEFAULT LP expr RP", - /* 57 */ "ccons ::= DEFAULT PLUS term", - /* 58 */ "ccons ::= DEFAULT MINUS term", - /* 59 */ "ccons ::= DEFAULT ID|INDEXED", - /* 60 */ "ccons ::= NULL onconf", - /* 61 */ "ccons ::= NOT NULL onconf", - /* 62 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 63 */ "ccons ::= UNIQUE onconf", - /* 64 */ "ccons ::= CHECK LP expr RP", - /* 65 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 66 */ "ccons ::= defer_subclause", - /* 67 */ "ccons ::= COLLATE ID|STRING", - /* 68 */ "autoinc ::=", - /* 69 */ "autoinc ::= AUTOINCR", - /* 70 */ "refargs ::=", - /* 71 */ "refargs ::= refargs refarg", - /* 72 */ "refarg ::= MATCH nm", - /* 73 */ "refarg ::= ON INSERT refact", - /* 74 */ "refarg ::= ON DELETE refact", - /* 75 */ "refarg ::= ON UPDATE refact", - /* 76 */ "refact ::= SET NULL", - /* 77 */ "refact ::= SET DEFAULT", - /* 78 */ "refact ::= CASCADE", - /* 79 */ "refact ::= RESTRICT", - /* 80 */ "refact ::= NO ACTION", - /* 81 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 82 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 83 */ "init_deferred_pred_opt ::=", - /* 84 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 85 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 86 */ "conslist_opt ::=", - /* 87 */ "conslist_opt ::= COMMA conslist", - /* 88 */ "conslist ::= conslist tconscomma tcons", - /* 89 */ "conslist ::= tcons", - /* 90 */ "tconscomma ::= COMMA", - /* 91 */ "tconscomma ::=", - /* 92 */ "tcons ::= CONSTRAINT nm", - /* 93 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 94 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 95 */ "tcons ::= CHECK LP expr RP onconf", - /* 96 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 97 */ "defer_subclause_opt ::=", - /* 98 */ "defer_subclause_opt ::= defer_subclause", - /* 99 */ "onconf ::=", - /* 100 */ "onconf ::= ON CONFLICT resolvetype", - /* 101 */ "orconf ::=", - /* 102 */ "orconf ::= OR resolvetype", - /* 103 */ "resolvetype ::= raisetype", - /* 104 */ "resolvetype ::= IGNORE", - /* 105 */ "resolvetype ::= REPLACE", - /* 106 */ "cmd ::= DROP TABLE ifexists fullname", - /* 107 */ "ifexists ::= IF EXISTS", - /* 108 */ "ifexists ::=", - /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 110 */ "cmd ::= DROP VIEW ifexists fullname", - /* 111 */ "cmd ::= select", - /* 112 */ "select ::= with selectnowith", - /* 113 */ "selectnowith ::= oneselect", - /* 114 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 115 */ "multiselect_op ::= UNION", - /* 116 */ "multiselect_op ::= UNION ALL", - /* 117 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 118 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 119 */ "oneselect ::= values", - /* 120 */ "values ::= VALUES LP nexprlist RP", - /* 121 */ "values ::= values COMMA LP exprlist RP", - /* 122 */ "distinct ::= DISTINCT", - /* 123 */ "distinct ::= ALL", - /* 124 */ "distinct ::=", - /* 125 */ "sclp ::= selcollist COMMA", - /* 126 */ "sclp ::=", - /* 127 */ "selcollist ::= sclp expr as", - /* 128 */ "selcollist ::= sclp STAR", - /* 129 */ "selcollist ::= sclp nm DOT STAR", - /* 130 */ "as ::= AS nm", - /* 131 */ "as ::= ID|STRING", - /* 132 */ "as ::=", - /* 133 */ "from ::=", - /* 134 */ "from ::= FROM seltablist", - /* 135 */ "stl_prefix ::= seltablist joinop", - /* 136 */ "stl_prefix ::=", - /* 137 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", - /* 138 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", - /* 139 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", - /* 140 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", - /* 141 */ "dbnm ::=", - /* 142 */ "dbnm ::= DOT nm", - /* 143 */ "fullname ::= nm dbnm", - /* 144 */ "joinop ::= COMMA|JOIN", - /* 145 */ "joinop ::= JOIN_KW JOIN", - /* 146 */ "joinop ::= JOIN_KW nm JOIN", - /* 147 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 148 */ "on_opt ::= ON expr", - /* 149 */ "on_opt ::=", - /* 150 */ "indexed_opt ::=", - /* 151 */ "indexed_opt ::= INDEXED BY nm", - /* 152 */ "indexed_opt ::= NOT INDEXED", - /* 153 */ "using_opt ::= USING LP idlist RP", - /* 154 */ "using_opt ::=", - /* 155 */ "orderby_opt ::=", - /* 156 */ "orderby_opt ::= ORDER BY sortlist", - /* 157 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 158 */ "sortlist ::= expr sortorder", - /* 159 */ "sortorder ::= ASC", - /* 160 */ "sortorder ::= DESC", - /* 161 */ "sortorder ::=", - /* 162 */ "groupby_opt ::=", - /* 163 */ "groupby_opt ::= GROUP BY nexprlist", - /* 164 */ "having_opt ::=", - /* 165 */ "having_opt ::= HAVING expr", - /* 166 */ "limit_opt ::=", - /* 167 */ "limit_opt ::= LIMIT expr", - /* 168 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 169 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 170 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", - /* 171 */ "where_opt ::=", - /* 172 */ "where_opt ::= WHERE expr", - /* 173 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", - /* 174 */ "setlist ::= setlist COMMA nm EQ expr", - /* 175 */ "setlist ::= nm EQ expr", - /* 176 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", - /* 177 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", - /* 178 */ "insert_cmd ::= INSERT orconf", - /* 179 */ "insert_cmd ::= REPLACE", - /* 180 */ "idlist_opt ::=", - /* 181 */ "idlist_opt ::= LP idlist RP", - /* 182 */ "idlist ::= idlist COMMA nm", - /* 183 */ "idlist ::= nm", - /* 184 */ "expr ::= term", - /* 185 */ "expr ::= LP expr RP", - /* 186 */ "term ::= NULL", - /* 187 */ "expr ::= ID|INDEXED", - /* 188 */ "expr ::= JOIN_KW", - /* 189 */ "expr ::= nm DOT nm", - /* 190 */ "expr ::= nm DOT nm DOT nm", - /* 191 */ "term ::= INTEGER|FLOAT|BLOB", - /* 192 */ "term ::= STRING", - /* 193 */ "expr ::= VARIABLE", - /* 194 */ "expr ::= expr COLLATE ID|STRING", - /* 195 */ "expr ::= CAST LP expr AS typetoken RP", - /* 196 */ "expr ::= ID|INDEXED LP distinct exprlist RP", - /* 197 */ "expr ::= ID|INDEXED LP STAR RP", - /* 198 */ "term ::= CTIME_KW", - /* 199 */ "expr ::= expr AND expr", - /* 200 */ "expr ::= expr OR expr", - /* 201 */ "expr ::= expr LT|GT|GE|LE expr", - /* 202 */ "expr ::= expr EQ|NE expr", - /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 204 */ "expr ::= expr PLUS|MINUS expr", - /* 205 */ "expr ::= expr STAR|SLASH|REM expr", - /* 206 */ "expr ::= expr CONCAT expr", - /* 207 */ "likeop ::= LIKE_KW|MATCH", - /* 208 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 209 */ "expr ::= expr likeop expr", - /* 210 */ "expr ::= expr likeop expr ESCAPE expr", - /* 211 */ "expr ::= expr ISNULL|NOTNULL", - /* 212 */ "expr ::= expr NOT NULL", - /* 213 */ "expr ::= expr IS expr", - /* 214 */ "expr ::= expr IS NOT expr", - /* 215 */ "expr ::= NOT expr", - /* 216 */ "expr ::= BITNOT expr", - /* 217 */ "expr ::= MINUS expr", - /* 218 */ "expr ::= PLUS expr", - /* 219 */ "between_op ::= BETWEEN", - /* 220 */ "between_op ::= NOT BETWEEN", - /* 221 */ "expr ::= expr between_op expr AND expr", - /* 222 */ "in_op ::= IN", - /* 223 */ "in_op ::= NOT IN", - /* 224 */ "expr ::= expr in_op LP exprlist RP", - /* 225 */ "expr ::= LP select RP", - /* 226 */ "expr ::= expr in_op LP select RP", - /* 227 */ "expr ::= expr in_op nm dbnm", - /* 228 */ "expr ::= EXISTS LP select RP", - /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 231 */ "case_exprlist ::= WHEN expr THEN expr", - /* 232 */ "case_else ::= ELSE expr", - /* 233 */ "case_else ::=", - /* 234 */ "case_operand ::= expr", - /* 235 */ "case_operand ::=", - /* 236 */ "exprlist ::= nexprlist", - /* 237 */ "exprlist ::=", - /* 238 */ "nexprlist ::= nexprlist COMMA expr", - /* 239 */ "nexprlist ::= expr", - /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 241 */ "uniqueflag ::= UNIQUE", - /* 242 */ "uniqueflag ::=", - /* 243 */ "eidlist_opt ::=", - /* 244 */ "eidlist_opt ::= LP eidlist RP", - /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 246 */ "eidlist ::= nm collate sortorder", - /* 247 */ "collate ::=", - /* 248 */ "collate ::= COLLATE ID|STRING", - /* 249 */ "cmd ::= DROP INDEX ifexists fullname", - /* 250 */ "cmd ::= VACUUM", - /* 251 */ "cmd ::= VACUUM nm", - /* 252 */ "cmd ::= PRAGMA nm dbnm", - /* 253 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 254 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 255 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 256 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 257 */ "nmnum ::= plus_num", - /* 258 */ "nmnum ::= nm", - /* 259 */ "nmnum ::= ON", - /* 260 */ "nmnum ::= DELETE", - /* 261 */ "nmnum ::= DEFAULT", - /* 262 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 263 */ "plus_num ::= INTEGER|FLOAT", - /* 264 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 265 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 266 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 267 */ "trigger_time ::= BEFORE", - /* 268 */ "trigger_time ::= AFTER", - /* 269 */ "trigger_time ::= INSTEAD OF", - /* 270 */ "trigger_time ::=", - /* 271 */ "trigger_event ::= DELETE|INSERT", - /* 272 */ "trigger_event ::= UPDATE", - /* 273 */ "trigger_event ::= UPDATE OF idlist", - /* 274 */ "foreach_clause ::=", - /* 275 */ "foreach_clause ::= FOR EACH ROW", - /* 276 */ "when_clause ::=", - /* 277 */ "when_clause ::= WHEN expr", - /* 278 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 279 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 280 */ "trnm ::= nm", - /* 281 */ "trnm ::= nm DOT nm", - /* 282 */ "tridxby ::=", - /* 283 */ "tridxby ::= INDEXED BY nm", - /* 284 */ "tridxby ::= NOT INDEXED", - /* 285 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", - /* 286 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", - /* 287 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", - /* 288 */ "trigger_cmd ::= select", - /* 289 */ "expr ::= RAISE LP IGNORE RP", - /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 291 */ "raisetype ::= ROLLBACK", - /* 292 */ "raisetype ::= ABORT", - /* 293 */ "raisetype ::= FAIL", - /* 294 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 295 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 296 */ "cmd ::= DETACH database_kw_opt expr", - /* 297 */ "key_opt ::=", - /* 298 */ "key_opt ::= KEY expr", - /* 299 */ "database_kw_opt ::= DATABASE", - /* 300 */ "database_kw_opt ::=", - /* 301 */ "cmd ::= REINDEX", - /* 302 */ "cmd ::= REINDEX nm dbnm", - /* 303 */ "cmd ::= ANALYZE", - /* 304 */ "cmd ::= ANALYZE nm dbnm", - /* 305 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 306 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", - /* 307 */ "add_column_fullname ::= fullname", - /* 308 */ "kwcolumn_opt ::=", - /* 309 */ "kwcolumn_opt ::= COLUMNKW", - /* 310 */ "cmd ::= create_vtab", - /* 311 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 312 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 313 */ "vtabarglist ::= vtabarg", - /* 314 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 315 */ "vtabarg ::=", - /* 316 */ "vtabarg ::= vtabarg vtabargtoken", - /* 317 */ "vtabargtoken ::= ANY", - /* 318 */ "vtabargtoken ::= lp anylist RP", - /* 319 */ "lp ::= LP", - /* 320 */ "anylist ::=", - /* 321 */ "anylist ::= anylist LP anylist RP", - /* 322 */ "anylist ::= anylist ANY", - /* 323 */ "with ::=", - /* 324 */ "with ::= WITH wqlist", - /* 325 */ "with ::= WITH RECURSIVE wqlist", - /* 326 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 327 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 0 */ "explain ::= EXPLAIN", + /* 1 */ "explain ::= EXPLAIN QUERY PLAN", + /* 2 */ "cmdx ::= cmd", + /* 3 */ "cmd ::= BEGIN transtype trans_opt", + /* 4 */ "transtype ::=", + /* 5 */ "transtype ::= DEFERRED", + /* 6 */ "transtype ::= IMMEDIATE", + /* 7 */ "transtype ::= EXCLUSIVE", + /* 8 */ "cmd ::= COMMIT|END trans_opt", + /* 9 */ "cmd ::= ROLLBACK trans_opt", + /* 10 */ "cmd ::= SAVEPOINT nm", + /* 11 */ "cmd ::= RELEASE savepoint_opt nm", + /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 14 */ "createkw ::= CREATE", + /* 15 */ "ifnotexists ::=", + /* 16 */ "ifnotexists ::= IF NOT EXISTS", + /* 17 */ "temp ::= TEMP", + /* 18 */ "temp ::=", + /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", + /* 20 */ "create_table_args ::= AS select", + /* 21 */ "table_options ::=", + /* 22 */ "table_options ::= WITHOUT nm", + /* 23 */ "columnname ::= nm typetoken", + /* 24 */ "typetoken ::=", + /* 25 */ "typetoken ::= typename LP signed RP", + /* 26 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 27 */ "typename ::= typename ID|STRING", + /* 28 */ "ccons ::= CONSTRAINT nm", + /* 29 */ "ccons ::= DEFAULT term", + /* 30 */ "ccons ::= DEFAULT LP expr RP", + /* 31 */ "ccons ::= DEFAULT PLUS term", + /* 32 */ "ccons ::= DEFAULT MINUS term", + /* 33 */ "ccons ::= DEFAULT ID|INDEXED", + /* 34 */ "ccons ::= NOT NULL onconf", + /* 35 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 36 */ "ccons ::= UNIQUE onconf", + /* 37 */ "ccons ::= CHECK LP expr RP", + /* 38 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 39 */ "ccons ::= defer_subclause", + /* 40 */ "ccons ::= COLLATE ID|STRING", + /* 41 */ "autoinc ::=", + /* 42 */ "autoinc ::= AUTOINCR", + /* 43 */ "refargs ::=", + /* 44 */ "refargs ::= refargs refarg", + /* 45 */ "refarg ::= MATCH nm", + /* 46 */ "refarg ::= ON INSERT refact", + /* 47 */ "refarg ::= ON DELETE refact", + /* 48 */ "refarg ::= ON UPDATE refact", + /* 49 */ "refact ::= SET NULL", + /* 50 */ "refact ::= SET DEFAULT", + /* 51 */ "refact ::= CASCADE", + /* 52 */ "refact ::= RESTRICT", + /* 53 */ "refact ::= NO ACTION", + /* 54 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 55 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 56 */ "init_deferred_pred_opt ::=", + /* 57 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 58 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 59 */ "conslist_opt ::=", + /* 60 */ "tconscomma ::= COMMA", + /* 61 */ "tcons ::= CONSTRAINT nm", + /* 62 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 63 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 64 */ "tcons ::= CHECK LP expr RP onconf", + /* 65 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 66 */ "defer_subclause_opt ::=", + /* 67 */ "onconf ::=", + /* 68 */ "onconf ::= ON CONFLICT resolvetype", + /* 69 */ "orconf ::=", + /* 70 */ "orconf ::= OR resolvetype", + /* 71 */ "resolvetype ::= IGNORE", + /* 72 */ "resolvetype ::= REPLACE", + /* 73 */ "cmd ::= DROP TABLE ifexists fullname", + /* 74 */ "ifexists ::= IF EXISTS", + /* 75 */ "ifexists ::=", + /* 76 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 77 */ "cmd ::= DROP VIEW ifexists fullname", + /* 78 */ "cmd ::= select", + /* 79 */ "select ::= with selectnowith", + /* 80 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 81 */ "multiselect_op ::= UNION", + /* 82 */ "multiselect_op ::= UNION ALL", + /* 83 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 84 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 85 */ "values ::= VALUES LP nexprlist RP", + /* 86 */ "values ::= values COMMA LP exprlist RP", + /* 87 */ "distinct ::= DISTINCT", + /* 88 */ "distinct ::= ALL", + /* 89 */ "distinct ::=", + /* 90 */ "sclp ::=", + /* 91 */ "selcollist ::= sclp expr as", + /* 92 */ "selcollist ::= sclp STAR", + /* 93 */ "selcollist ::= sclp nm DOT STAR", + /* 94 */ "as ::= AS nm", + /* 95 */ "as ::=", + /* 96 */ "from ::=", + /* 97 */ "from ::= FROM seltablist", + /* 98 */ "stl_prefix ::= seltablist joinop", + /* 99 */ "stl_prefix ::=", + /* 100 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 101 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 102 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 103 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 104 */ "dbnm ::=", + /* 105 */ "dbnm ::= DOT nm", + /* 106 */ "fullname ::= nm dbnm", + /* 107 */ "joinop ::= COMMA|JOIN", + /* 108 */ "joinop ::= JOIN_KW JOIN", + /* 109 */ "joinop ::= JOIN_KW nm JOIN", + /* 110 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 111 */ "on_opt ::= ON expr", + /* 112 */ "on_opt ::=", + /* 113 */ "indexed_opt ::=", + /* 114 */ "indexed_opt ::= INDEXED BY nm", + /* 115 */ "indexed_opt ::= NOT INDEXED", + /* 116 */ "using_opt ::= USING LP idlist RP", + /* 117 */ "using_opt ::=", + /* 118 */ "orderby_opt ::=", + /* 119 */ "orderby_opt ::= ORDER BY sortlist", + /* 120 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 121 */ "sortlist ::= expr sortorder", + /* 122 */ "sortorder ::= ASC", + /* 123 */ "sortorder ::= DESC", + /* 124 */ "sortorder ::=", + /* 125 */ "groupby_opt ::=", + /* 126 */ "groupby_opt ::= GROUP BY nexprlist", + /* 127 */ "having_opt ::=", + /* 128 */ "having_opt ::= HAVING expr", + /* 129 */ "limit_opt ::=", + /* 130 */ "limit_opt ::= LIMIT expr", + /* 131 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 132 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 133 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", + /* 134 */ "where_opt ::=", + /* 135 */ "where_opt ::= WHERE expr", + /* 136 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", + /* 137 */ "setlist ::= setlist COMMA nm EQ expr", + /* 138 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 139 */ "setlist ::= nm EQ expr", + /* 140 */ "setlist ::= LP idlist RP EQ expr", + /* 141 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", + /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", + /* 143 */ "insert_cmd ::= INSERT orconf", + /* 144 */ "insert_cmd ::= REPLACE", + /* 145 */ "idlist_opt ::=", + /* 146 */ "idlist_opt ::= LP idlist RP", + /* 147 */ "idlist ::= idlist COMMA nm", + /* 148 */ "idlist ::= nm", + /* 149 */ "expr ::= LP expr RP", + /* 150 */ "expr ::= ID|INDEXED", + /* 151 */ "expr ::= JOIN_KW", + /* 152 */ "expr ::= nm DOT nm", + /* 153 */ "expr ::= nm DOT nm DOT nm", + /* 154 */ "term ::= NULL|FLOAT|BLOB", + /* 155 */ "term ::= STRING", + /* 156 */ "term ::= INTEGER", + /* 157 */ "expr ::= VARIABLE", + /* 158 */ "expr ::= expr COLLATE ID|STRING", + /* 159 */ "expr ::= CAST LP expr AS typetoken RP", + /* 160 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 161 */ "expr ::= ID|INDEXED LP STAR RP", + /* 162 */ "term ::= CTIME_KW", + /* 163 */ "expr ::= LP nexprlist COMMA expr RP", + /* 164 */ "expr ::= expr AND expr", + /* 165 */ "expr ::= expr OR expr", + /* 166 */ "expr ::= expr LT|GT|GE|LE expr", + /* 167 */ "expr ::= expr EQ|NE expr", + /* 168 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 169 */ "expr ::= expr PLUS|MINUS expr", + /* 170 */ "expr ::= expr STAR|SLASH|REM expr", + /* 171 */ "expr ::= expr CONCAT expr", + /* 172 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 173 */ "expr ::= expr likeop expr", + /* 174 */ "expr ::= expr likeop expr ESCAPE expr", + /* 175 */ "expr ::= expr ISNULL|NOTNULL", + /* 176 */ "expr ::= expr NOT NULL", + /* 177 */ "expr ::= expr IS expr", + /* 178 */ "expr ::= expr IS NOT expr", + /* 179 */ "expr ::= NOT expr", + /* 180 */ "expr ::= BITNOT expr", + /* 181 */ "expr ::= MINUS expr", + /* 182 */ "expr ::= PLUS expr", + /* 183 */ "between_op ::= BETWEEN", + /* 184 */ "between_op ::= NOT BETWEEN", + /* 185 */ "expr ::= expr between_op expr AND expr", + /* 186 */ "in_op ::= IN", + /* 187 */ "in_op ::= NOT IN", + /* 188 */ "expr ::= expr in_op LP exprlist RP", + /* 189 */ "expr ::= LP select RP", + /* 190 */ "expr ::= expr in_op LP select RP", + /* 191 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 192 */ "expr ::= EXISTS LP select RP", + /* 193 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 194 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 195 */ "case_exprlist ::= WHEN expr THEN expr", + /* 196 */ "case_else ::= ELSE expr", + /* 197 */ "case_else ::=", + /* 198 */ "case_operand ::= expr", + /* 199 */ "case_operand ::=", + /* 200 */ "exprlist ::=", + /* 201 */ "nexprlist ::= nexprlist COMMA expr", + /* 202 */ "nexprlist ::= expr", + /* 203 */ "paren_exprlist ::=", + /* 204 */ "paren_exprlist ::= LP exprlist RP", + /* 205 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 206 */ "uniqueflag ::= UNIQUE", + /* 207 */ "uniqueflag ::=", + /* 208 */ "eidlist_opt ::=", + /* 209 */ "eidlist_opt ::= LP eidlist RP", + /* 210 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 211 */ "eidlist ::= nm collate sortorder", + /* 212 */ "collate ::=", + /* 213 */ "collate ::= COLLATE ID|STRING", + /* 214 */ "cmd ::= DROP INDEX ifexists fullname", + /* 215 */ "cmd ::= VACUUM", + /* 216 */ "cmd ::= VACUUM nm", + /* 217 */ "cmd ::= PRAGMA nm dbnm", + /* 218 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 219 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 220 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 221 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 222 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 223 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 224 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 225 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 226 */ "trigger_time ::= BEFORE|AFTER", + /* 227 */ "trigger_time ::= INSTEAD OF", + /* 228 */ "trigger_time ::=", + /* 229 */ "trigger_event ::= DELETE|INSERT", + /* 230 */ "trigger_event ::= UPDATE", + /* 231 */ "trigger_event ::= UPDATE OF idlist", + /* 232 */ "when_clause ::=", + /* 233 */ "when_clause ::= WHEN expr", + /* 234 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 235 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 236 */ "trnm ::= nm DOT nm", + /* 237 */ "tridxby ::= INDEXED BY nm", + /* 238 */ "tridxby ::= NOT INDEXED", + /* 239 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", + /* 240 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", + /* 241 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", + /* 242 */ "trigger_cmd ::= select", + /* 243 */ "expr ::= RAISE LP IGNORE RP", + /* 244 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 245 */ "raisetype ::= ROLLBACK", + /* 246 */ "raisetype ::= ABORT", + /* 247 */ "raisetype ::= FAIL", + /* 248 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 249 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 250 */ "cmd ::= DETACH database_kw_opt expr", + /* 251 */ "key_opt ::=", + /* 252 */ "key_opt ::= KEY expr", + /* 253 */ "cmd ::= REINDEX", + /* 254 */ "cmd ::= REINDEX nm dbnm", + /* 255 */ "cmd ::= ANALYZE", + /* 256 */ "cmd ::= ANALYZE nm dbnm", + /* 257 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 258 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 259 */ "add_column_fullname ::= fullname", + /* 260 */ "cmd ::= create_vtab", + /* 261 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 262 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 263 */ "vtabarg ::=", + /* 264 */ "vtabargtoken ::= ANY", + /* 265 */ "vtabargtoken ::= lp anylist RP", + /* 266 */ "lp ::= LP", + /* 267 */ "with ::=", + /* 268 */ "with ::= WITH wqlist", + /* 269 */ "with ::= WITH RECURSIVE wqlist", + /* 270 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 271 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 272 */ "input ::= cmdlist", + /* 273 */ "cmdlist ::= cmdlist ecmd", + /* 274 */ "cmdlist ::= ecmd", + /* 275 */ "ecmd ::= SEMI", + /* 276 */ "ecmd ::= explain cmdx SEMI", + /* 277 */ "explain ::=", + /* 278 */ "trans_opt ::=", + /* 279 */ "trans_opt ::= TRANSACTION", + /* 280 */ "trans_opt ::= TRANSACTION nm", + /* 281 */ "savepoint_opt ::= SAVEPOINT", + /* 282 */ "savepoint_opt ::=", + /* 283 */ "cmd ::= create_table create_table_args", + /* 284 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 285 */ "columnlist ::= columnname carglist", + /* 286 */ "nm ::= ID|INDEXED", + /* 287 */ "nm ::= STRING", + /* 288 */ "nm ::= JOIN_KW", + /* 289 */ "typetoken ::= typename", + /* 290 */ "typename ::= ID|STRING", + /* 291 */ "signed ::= plus_num", + /* 292 */ "signed ::= minus_num", + /* 293 */ "carglist ::= carglist ccons", + /* 294 */ "carglist ::=", + /* 295 */ "ccons ::= NULL onconf", + /* 296 */ "conslist_opt ::= COMMA conslist", + /* 297 */ "conslist ::= conslist tconscomma tcons", + /* 298 */ "conslist ::= tcons", + /* 299 */ "tconscomma ::=", + /* 300 */ "defer_subclause_opt ::= defer_subclause", + /* 301 */ "resolvetype ::= raisetype", + /* 302 */ "selectnowith ::= oneselect", + /* 303 */ "oneselect ::= values", + /* 304 */ "sclp ::= selcollist COMMA", + /* 305 */ "as ::= ID|STRING", + /* 306 */ "expr ::= term", + /* 307 */ "likeop ::= LIKE_KW|MATCH", + /* 308 */ "exprlist ::= nexprlist", + /* 309 */ "nmnum ::= plus_num", + /* 310 */ "nmnum ::= nm", + /* 311 */ "nmnum ::= ON", + /* 312 */ "nmnum ::= DELETE", + /* 313 */ "nmnum ::= DEFAULT", + /* 314 */ "plus_num ::= INTEGER|FLOAT", + /* 315 */ "foreach_clause ::=", + /* 316 */ "foreach_clause ::= FOR EACH ROW", + /* 317 */ "trnm ::= nm", + /* 318 */ "tridxby ::=", + /* 319 */ "database_kw_opt ::= DATABASE", + /* 320 */ "database_kw_opt ::=", + /* 321 */ "kwcolumn_opt ::=", + /* 322 */ "kwcolumn_opt ::= COLUMNKW", + /* 323 */ "vtabarglist ::= vtabarg", + /* 324 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 325 */ "vtabarg ::= vtabarg vtabargtoken", + /* 326 */ "anylist ::=", + /* 327 */ "anylist ::= anylist LP anylist RP", + /* 328 */ "anylist ::= anylist ANY", }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* -** Try to increase the size of the parser stack. +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. */ -static void yyGrowStack(yyParser *p){ +static int yyGrowStack(yyParser *p){ int newSize; + int idx; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; + }else{ + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + } if( pNew ){ p->yystack = pNew; - p->yystksz = newSize; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", - yyTracePrompt, p->yystksz); + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); } #endif + p->yystksz = newSize; } + return pNew==0; } #endif @@ -128645,6 +138398,34 @@ static void yyGrowStack(yyParser *p){ # define YYMALLOCARGTYPE size_t #endif +/* Initialize a new parser that has already been allocated. +*/ +SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){ + yyParser *pParser = (yyParser*)yypParser; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyhwm = 0; +#endif +#if YYSTACKDEPTH<=0 + pParser->yytos = NULL; + pParser->yystack = NULL; + pParser->yystksz = 0; + if( yyGrowStack(pParser) ){ + pParser->yystack = &pParser->yystk0; + pParser->yystksz = 1; + } +#endif +#ifndef YYNOERRORRECOVERY + pParser->yyerrcnt = -1; +#endif + pParser->yytos = pParser->yystack; + pParser->yystack[0].stateno = 0; + pParser->yystack[0].major = 0; +#if YYSTACKDEPTH>0 + pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1]; +#endif +} + +#ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like @@ -128660,19 +138441,11 @@ static void yyGrowStack(yyParser *p){ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); - if( pParser ){ - pParser->yyidx = -1; -#ifdef YYTRACKMAXSTACKDEPTH - pParser->yyidxMax = 0; -#endif -#if YYSTACKDEPTH<=0 - pParser->yystack = NULL; - pParser->yystksz = 0; - yyGrowStack(pParser); -#endif - } + if( pParser ) sqlite3ParserInit(pParser); return pParser; } +#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ + /* The following function deletes the "minor type" or semantic value ** associated with a symbol. The symbol can be either a terminal @@ -128700,75 +138473,76 @@ static void yy_destructor( */ /********* Begin destructor definitions ***************************************/ case 163: /* select */ - case 196: /* selectnowith */ - case 197: /* oneselect */ - case 208: /* values */ + case 194: /* selectnowith */ + case 195: /* oneselect */ + case 206: /* values */ { -sqlite3SelectDelete(pParse->db, (yypminor->yy387)); +sqlite3SelectDelete(pParse->db, (yypminor->yy243)); } break; - case 174: /* term */ - case 175: /* expr */ + case 172: /* term */ + case 173: /* expr */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy118).pExpr); +sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr); } break; - case 179: /* eidlist_opt */ - case 188: /* sortlist */ - case 189: /* eidlist */ - case 201: /* selcollist */ - case 204: /* groupby_opt */ - case 206: /* orderby_opt */ - case 209: /* nexprlist */ - case 210: /* exprlist */ - case 211: /* sclp */ - case 220: /* setlist */ - case 227: /* case_exprlist */ + case 177: /* eidlist_opt */ + case 186: /* sortlist */ + case 187: /* eidlist */ + case 199: /* selcollist */ + case 202: /* groupby_opt */ + case 204: /* orderby_opt */ + case 207: /* nexprlist */ + case 208: /* exprlist */ + case 209: /* sclp */ + case 218: /* setlist */ + case 224: /* paren_exprlist */ + case 226: /* case_exprlist */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy322)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy148)); } break; - case 195: /* fullname */ - case 202: /* from */ - case 213: /* seltablist */ - case 214: /* stl_prefix */ + case 193: /* fullname */ + case 200: /* from */ + case 211: /* seltablist */ + case 212: /* stl_prefix */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy259)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy185)); } break; - case 198: /* with */ - case 251: /* wqlist */ + case 196: /* with */ + case 250: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy451)); +sqlite3WithDelete(pParse->db, (yypminor->yy285)); } break; - case 203: /* where_opt */ - case 205: /* having_opt */ - case 217: /* on_opt */ - case 226: /* case_operand */ - case 228: /* case_else */ - case 237: /* when_clause */ - case 242: /* key_opt */ + case 201: /* where_opt */ + case 203: /* having_opt */ + case 215: /* on_opt */ + case 225: /* case_operand */ + case 227: /* case_else */ + case 236: /* when_clause */ + case 241: /* key_opt */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy314)); +sqlite3ExprDelete(pParse->db, (yypminor->yy72)); } break; - case 218: /* using_opt */ - case 219: /* idlist */ - case 222: /* idlist_opt */ + case 216: /* using_opt */ + case 217: /* idlist */ + case 220: /* idlist_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy384)); +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); } break; - case 233: /* trigger_cmd_list */ - case 238: /* trigger_cmd */ + case 232: /* trigger_cmd_list */ + case 237: /* trigger_cmd */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203)); +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145)); } break; - case 235: /* trigger_event */ + case 234: /* trigger_event */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy90).b); +sqlite3IdListDelete(pParse->db, (yypminor->yy332).b); } break; /********* End destructor definitions *****************************************/ @@ -128784,8 +138558,9 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy90).b); */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; - assert( pParser->yyidx>=0 ); - yytos = &pParser->yystack[pParser->yyidx--]; + assert( pParser->yytos!=0 ); + assert( pParser->yytos > pParser->yystack ); + yytos = pParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", @@ -128796,6 +138571,18 @@ static void yy_pop_parser_stack(yyParser *pParser){ yy_destructor(pParser, yytos->major, &yytos->minor); } +/* +** Clear all secondary memory allocations from the parser +*/ +SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ + yyParser *pParser = (yyParser*)p; + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); +#endif +} + +#ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* ** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. @@ -128808,16 +138595,13 @@ SQLITE_PRIVATE void sqlite3ParserFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ - yyParser *pParser = (yyParser*)p; #ifndef YYPARSEFREENEVERNULL - if( pParser==0 ) return; + if( p==0 ) return; #endif - while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); -#if YYSTACKDEPTH<=0 - free(pParser->yystack); -#endif - (*freeProc)((void*)pParser); + sqlite3ParserFinalize(p); + (*freeProc)(p); } +#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ /* ** Return the peak depth of the stack for a parser. @@ -128825,7 +138609,7 @@ SQLITE_PRIVATE void sqlite3ParserFree( #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ yyParser *pParser = (yyParser*)p; - return pParser->yyidxMax; + return pParser->yyhwm; } #endif @@ -128833,61 +138617,58 @@ SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. */ -static int yy_find_shift_action( +static unsigned int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; - int stateno = pParser->yystack[pParser->yyidx].stateno; + int stateno = pParser->yytos->stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); do{ i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } #endif #ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( + { + int j = i - iLookAhead + YYWILDCARD; + if( #if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && + j>=0 && #endif #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j0 + ){ #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], - yyTokenName[YYWILDCARD]); - } -#endif /* NDEBUG */ - return yy_action[j]; + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); } +#endif /* NDEBUG */ + return yy_action[j]; } -#endif /* YYWILDCARD */ } +#endif /* YYWILDCARD */ return yy_default[stateno]; }else{ return yy_action[i]; @@ -128929,20 +138710,18 @@ static int yy_find_reduce_action( /* ** The following routine is called if the stack overflows. */ -static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ +static void yyStackOverflow(yyParser *yypParser){ sqlite3ParserARG_FETCH; - yypParser->yyidx--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ - UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */ sqlite3ErrorMsg(pParse, "parser stack overflow"); /******** End %stack_overflow code ********************************************/ sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ @@ -128956,11 +138735,11 @@ static void yyTraceShift(yyParser *yypParser, int yyNewState){ if( yyTraceFILE ){ if( yyNewStateyystack[yypParser->yyidx].major], + yyTracePrompt,yyTokenName[yypParser->yytos->major], yyNewState); }else{ fprintf(yyTraceFILE,"%sShift '%s'\n", - yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]); + yyTracePrompt,yyTokenName[yypParser->yytos->major]); } } } @@ -128975,33 +138754,38 @@ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ - YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ + sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; - yypParser->yyidx++; + yypParser->yytos++; #ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif #if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH ){ - yyStackOverflow(yypParser, yypMinor); + if( yypParser->yytos>yypParser->yystackEnd ){ + yypParser->yytos--; + yyStackOverflow(yypParser); return; } #else - if( yypParser->yyidx>=yypParser->yystksz ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz ){ - yyStackOverflow(yypParser, yypMinor); + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ + if( yyGrowStack(yypParser) ){ + yypParser->yytos--; + yyStackOverflow(yypParser); return; } } #endif - yytos = &yypParser->yystack[yypParser->yyidx]; + if( yyNewState > YY_MAX_SHIFT ){ + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yytos = yypParser->yytos; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; - yytos->minor = *yypMinor; + yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState); } @@ -129009,337 +138793,338 @@ static void yy_shift( ** is used during the reduce. */ static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ + 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[] = { - { 144, 1 }, - { 145, 2 }, - { 145, 1 }, - { 146, 1 }, - { 146, 3 }, - { 147, 0 }, - { 147, 1 }, - { 147, 3 }, - { 148, 1 }, - { 149, 3 }, - { 151, 0 }, - { 151, 1 }, - { 151, 2 }, + { 147, -1 }, + { 147, -3 }, + { 148, -1 }, + { 149, -3 }, { 150, 0 }, - { 150, 1 }, - { 150, 1 }, - { 150, 1 }, - { 149, 2 }, - { 149, 2 }, - { 149, 2 }, - { 153, 1 }, - { 153, 0 }, - { 149, 2 }, - { 149, 3 }, - { 149, 5 }, - { 149, 2 }, - { 154, 6 }, - { 156, 1 }, + { 150, -1 }, + { 150, -1 }, + { 150, -1 }, + { 149, -2 }, + { 149, -2 }, + { 149, -2 }, + { 149, -3 }, + { 149, -5 }, + { 154, -6 }, + { 156, -1 }, { 158, 0 }, - { 158, 3 }, - { 157, 1 }, + { 158, -3 }, + { 157, -1 }, { 157, 0 }, - { 155, 5 }, - { 155, 2 }, + { 155, -5 }, + { 155, -2 }, { 162, 0 }, - { 162, 2 }, - { 160, 3 }, - { 160, 1 }, - { 164, 3 }, - { 165, 1 }, - { 152, 1 }, - { 152, 1 }, - { 152, 1 }, + { 162, -2 }, + { 164, -2 }, { 166, 0 }, - { 166, 1 }, - { 168, 1 }, - { 168, 4 }, - { 168, 6 }, - { 169, 1 }, - { 169, 2 }, - { 170, 1 }, - { 170, 1 }, - { 167, 2 }, - { 167, 0 }, - { 173, 2 }, - { 173, 2 }, - { 173, 4 }, - { 173, 3 }, - { 173, 3 }, - { 173, 2 }, - { 173, 2 }, - { 173, 3 }, - { 173, 5 }, - { 173, 2 }, - { 173, 4 }, - { 173, 4 }, - { 173, 1 }, - { 173, 2 }, - { 178, 0 }, - { 178, 1 }, - { 180, 0 }, - { 180, 2 }, - { 182, 2 }, - { 182, 3 }, - { 182, 3 }, - { 182, 3 }, - { 183, 2 }, - { 183, 2 }, - { 183, 1 }, - { 183, 1 }, - { 183, 2 }, - { 181, 3 }, - { 181, 2 }, - { 184, 0 }, - { 184, 2 }, - { 184, 2 }, - { 161, 0 }, - { 161, 2 }, - { 185, 3 }, - { 185, 1 }, - { 186, 1 }, - { 186, 0 }, - { 187, 2 }, - { 187, 7 }, - { 187, 5 }, - { 187, 5 }, - { 187, 10 }, - { 190, 0 }, - { 190, 1 }, + { 166, -4 }, + { 166, -6 }, + { 167, -2 }, + { 171, -2 }, + { 171, -2 }, + { 171, -4 }, + { 171, -3 }, + { 171, -3 }, + { 171, -2 }, + { 171, -3 }, + { 171, -5 }, + { 171, -2 }, + { 171, -4 }, + { 171, -4 }, + { 171, -1 }, + { 171, -2 }, { 176, 0 }, - { 176, 3 }, - { 191, 0 }, - { 191, 2 }, - { 192, 1 }, - { 192, 1 }, - { 192, 1 }, - { 149, 4 }, - { 194, 2 }, - { 194, 0 }, - { 149, 9 }, - { 149, 4 }, - { 149, 1 }, - { 163, 2 }, - { 196, 1 }, - { 196, 3 }, - { 199, 1 }, - { 199, 2 }, - { 199, 1 }, - { 197, 9 }, - { 197, 1 }, - { 208, 4 }, - { 208, 5 }, - { 200, 1 }, - { 200, 1 }, - { 200, 0 }, - { 211, 2 }, - { 211, 0 }, - { 201, 3 }, - { 201, 2 }, - { 201, 4 }, - { 212, 2 }, - { 212, 1 }, - { 212, 0 }, - { 202, 0 }, - { 202, 2 }, - { 214, 2 }, - { 214, 0 }, - { 213, 7 }, - { 213, 9 }, - { 213, 7 }, - { 213, 7 }, - { 159, 0 }, - { 159, 2 }, - { 195, 2 }, - { 215, 1 }, - { 215, 2 }, - { 215, 3 }, - { 215, 4 }, - { 217, 2 }, - { 217, 0 }, - { 216, 0 }, - { 216, 3 }, - { 216, 2 }, - { 218, 4 }, - { 218, 0 }, - { 206, 0 }, - { 206, 3 }, - { 188, 4 }, - { 188, 2 }, - { 177, 1 }, - { 177, 1 }, - { 177, 0 }, - { 204, 0 }, - { 204, 3 }, - { 205, 0 }, - { 205, 2 }, - { 207, 0 }, - { 207, 2 }, - { 207, 4 }, - { 207, 4 }, - { 149, 6 }, - { 203, 0 }, - { 203, 2 }, - { 149, 8 }, - { 220, 5 }, - { 220, 3 }, - { 149, 6 }, - { 149, 7 }, - { 221, 2 }, - { 221, 1 }, - { 222, 0 }, - { 222, 3 }, - { 219, 3 }, - { 219, 1 }, - { 175, 1 }, - { 175, 3 }, - { 174, 1 }, - { 175, 1 }, - { 175, 1 }, - { 175, 3 }, - { 175, 5 }, - { 174, 1 }, - { 174, 1 }, - { 175, 1 }, - { 175, 3 }, - { 175, 6 }, - { 175, 5 }, - { 175, 4 }, - { 174, 1 }, - { 175, 3 }, - { 175, 3 }, - { 175, 3 }, - { 175, 3 }, - { 175, 3 }, - { 175, 3 }, - { 175, 3 }, - { 175, 3 }, - { 223, 1 }, - { 223, 2 }, - { 175, 3 }, - { 175, 5 }, - { 175, 2 }, - { 175, 3 }, - { 175, 3 }, - { 175, 4 }, - { 175, 2 }, - { 175, 2 }, - { 175, 2 }, - { 175, 2 }, - { 224, 1 }, - { 224, 2 }, - { 175, 5 }, - { 225, 1 }, - { 225, 2 }, - { 175, 5 }, - { 175, 3 }, - { 175, 5 }, - { 175, 4 }, - { 175, 4 }, - { 175, 5 }, - { 227, 5 }, - { 227, 4 }, - { 228, 2 }, - { 228, 0 }, - { 226, 1 }, - { 226, 0 }, - { 210, 1 }, - { 210, 0 }, - { 209, 3 }, - { 209, 1 }, - { 149, 12 }, - { 229, 1 }, - { 229, 0 }, - { 179, 0 }, - { 179, 3 }, - { 189, 5 }, - { 189, 3 }, - { 230, 0 }, - { 230, 2 }, - { 149, 4 }, - { 149, 1 }, - { 149, 2 }, - { 149, 3 }, - { 149, 5 }, - { 149, 6 }, - { 149, 5 }, - { 149, 6 }, - { 231, 1 }, - { 231, 1 }, - { 231, 1 }, - { 231, 1 }, - { 231, 1 }, - { 171, 2 }, - { 171, 1 }, - { 172, 2 }, - { 149, 5 }, - { 232, 11 }, - { 234, 1 }, - { 234, 1 }, - { 234, 2 }, - { 234, 0 }, - { 235, 1 }, - { 235, 1 }, - { 235, 3 }, - { 236, 0 }, - { 236, 3 }, - { 237, 0 }, - { 237, 2 }, - { 233, 3 }, - { 233, 2 }, - { 239, 1 }, - { 239, 3 }, - { 240, 0 }, - { 240, 3 }, - { 240, 2 }, - { 238, 7 }, - { 238, 5 }, - { 238, 5 }, - { 238, 1 }, - { 175, 4 }, - { 175, 6 }, - { 193, 1 }, - { 193, 1 }, - { 193, 1 }, - { 149, 4 }, - { 149, 6 }, - { 149, 3 }, - { 242, 0 }, - { 242, 2 }, - { 241, 1 }, - { 241, 0 }, - { 149, 1 }, - { 149, 3 }, - { 149, 1 }, - { 149, 3 }, - { 149, 6 }, - { 149, 6 }, - { 243, 1 }, - { 244, 0 }, - { 244, 1 }, - { 149, 1 }, - { 149, 4 }, - { 245, 8 }, - { 246, 1 }, - { 246, 3 }, - { 247, 0 }, - { 247, 2 }, - { 248, 1 }, - { 248, 3 }, - { 249, 1 }, - { 250, 0 }, - { 250, 4 }, - { 250, 2 }, + { 176, -1 }, + { 178, 0 }, + { 178, -2 }, + { 180, -2 }, + { 180, -3 }, + { 180, -3 }, + { 180, -3 }, + { 181, -2 }, + { 181, -2 }, + { 181, -1 }, + { 181, -1 }, + { 181, -2 }, + { 179, -3 }, + { 179, -2 }, + { 182, 0 }, + { 182, -2 }, + { 182, -2 }, + { 161, 0 }, + { 184, -1 }, + { 185, -2 }, + { 185, -7 }, + { 185, -5 }, + { 185, -5 }, + { 185, -10 }, + { 188, 0 }, + { 174, 0 }, + { 174, -3 }, + { 189, 0 }, + { 189, -2 }, + { 190, -1 }, + { 190, -1 }, + { 149, -4 }, + { 192, -2 }, + { 192, 0 }, + { 149, -9 }, + { 149, -4 }, + { 149, -1 }, + { 163, -2 }, + { 194, -3 }, + { 197, -1 }, + { 197, -2 }, + { 197, -1 }, + { 195, -9 }, + { 206, -4 }, + { 206, -5 }, + { 198, -1 }, + { 198, -1 }, { 198, 0 }, - { 198, 2 }, - { 198, 3 }, - { 251, 6 }, - { 251, 8 }, + { 209, 0 }, + { 199, -3 }, + { 199, -2 }, + { 199, -4 }, + { 210, -2 }, + { 210, 0 }, + { 200, 0 }, + { 200, -2 }, + { 212, -2 }, + { 212, 0 }, + { 211, -7 }, + { 211, -9 }, + { 211, -7 }, + { 211, -7 }, + { 159, 0 }, + { 159, -2 }, + { 193, -2 }, + { 213, -1 }, + { 213, -2 }, + { 213, -3 }, + { 213, -4 }, + { 215, -2 }, + { 215, 0 }, + { 214, 0 }, + { 214, -3 }, + { 214, -2 }, + { 216, -4 }, + { 216, 0 }, + { 204, 0 }, + { 204, -3 }, + { 186, -4 }, + { 186, -2 }, + { 175, -1 }, + { 175, -1 }, + { 175, 0 }, + { 202, 0 }, + { 202, -3 }, + { 203, 0 }, + { 203, -2 }, + { 205, 0 }, + { 205, -2 }, + { 205, -4 }, + { 205, -4 }, + { 149, -6 }, + { 201, 0 }, + { 201, -2 }, + { 149, -8 }, + { 218, -5 }, + { 218, -7 }, + { 218, -3 }, + { 218, -5 }, + { 149, -6 }, + { 149, -7 }, + { 219, -2 }, + { 219, -1 }, + { 220, 0 }, + { 220, -3 }, + { 217, -3 }, + { 217, -1 }, + { 173, -3 }, + { 173, -1 }, + { 173, -1 }, + { 173, -3 }, + { 173, -5 }, + { 172, -1 }, + { 172, -1 }, + { 172, -1 }, + { 173, -1 }, + { 173, -3 }, + { 173, -6 }, + { 173, -5 }, + { 173, -4 }, + { 172, -1 }, + { 173, -5 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 173, -3 }, + { 221, -2 }, + { 173, -3 }, + { 173, -5 }, + { 173, -2 }, + { 173, -3 }, + { 173, -3 }, + { 173, -4 }, + { 173, -2 }, + { 173, -2 }, + { 173, -2 }, + { 173, -2 }, + { 222, -1 }, + { 222, -2 }, + { 173, -5 }, + { 223, -1 }, + { 223, -2 }, + { 173, -5 }, + { 173, -3 }, + { 173, -5 }, + { 173, -5 }, + { 173, -4 }, + { 173, -5 }, + { 226, -5 }, + { 226, -4 }, + { 227, -2 }, + { 227, 0 }, + { 225, -1 }, + { 225, 0 }, + { 208, 0 }, + { 207, -3 }, + { 207, -1 }, + { 224, 0 }, + { 224, -3 }, + { 149, -12 }, + { 228, -1 }, + { 228, 0 }, + { 177, 0 }, + { 177, -3 }, + { 187, -5 }, + { 187, -3 }, + { 229, 0 }, + { 229, -2 }, + { 149, -4 }, + { 149, -1 }, + { 149, -2 }, + { 149, -3 }, + { 149, -5 }, + { 149, -6 }, + { 149, -5 }, + { 149, -6 }, + { 169, -2 }, + { 170, -2 }, + { 149, -5 }, + { 231, -11 }, + { 233, -1 }, + { 233, -2 }, + { 233, 0 }, + { 234, -1 }, + { 234, -1 }, + { 234, -3 }, + { 236, 0 }, + { 236, -2 }, + { 232, -3 }, + { 232, -2 }, + { 238, -3 }, + { 239, -3 }, + { 239, -2 }, + { 237, -7 }, + { 237, -5 }, + { 237, -5 }, + { 237, -1 }, + { 173, -4 }, + { 173, -6 }, + { 191, -1 }, + { 191, -1 }, + { 191, -1 }, + { 149, -4 }, + { 149, -6 }, + { 149, -3 }, + { 241, 0 }, + { 241, -2 }, + { 149, -1 }, + { 149, -3 }, + { 149, -1 }, + { 149, -3 }, + { 149, -6 }, + { 149, -7 }, + { 242, -1 }, + { 149, -1 }, + { 149, -4 }, + { 244, -8 }, + { 246, 0 }, + { 247, -1 }, + { 247, -3 }, + { 248, -1 }, + { 196, 0 }, + { 196, -2 }, + { 196, -3 }, + { 250, -6 }, + { 250, -8 }, + { 144, -1 }, + { 145, -2 }, + { 145, -1 }, + { 146, -1 }, + { 146, -3 }, + { 147, 0 }, + { 151, 0 }, + { 151, -1 }, + { 151, -2 }, + { 153, -1 }, + { 153, 0 }, + { 149, -2 }, + { 160, -4 }, + { 160, -2 }, + { 152, -1 }, + { 152, -1 }, + { 152, -1 }, + { 166, -1 }, + { 167, -1 }, + { 168, -1 }, + { 168, -1 }, + { 165, -2 }, + { 165, 0 }, + { 171, -2 }, + { 161, -2 }, + { 183, -3 }, + { 183, -1 }, + { 184, 0 }, + { 188, -1 }, + { 190, -1 }, + { 194, -1 }, + { 195, -1 }, + { 209, -2 }, + { 210, -1 }, + { 173, -1 }, + { 221, -1 }, + { 208, -1 }, + { 230, -1 }, + { 230, -1 }, + { 230, -1 }, + { 230, -1 }, + { 230, -1 }, + { 169, -1 }, + { 235, 0 }, + { 235, -3 }, + { 238, -1 }, + { 239, 0 }, + { 240, -1 }, + { 240, 0 }, + { 243, 0 }, + { 243, -1 }, + { 245, -1 }, + { 245, -3 }, + { 246, -2 }, + { 249, 0 }, + { 249, -4 }, + { 249, -2 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -129350,24 +139135,47 @@ static void yy_accept(yyParser*); /* Forward Declaration */ */ static void yy_reduce( yyParser *yypParser, /* The parser */ - int yyruleno /* Number of the rule by which to reduce */ + unsigned int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ - YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ sqlite3ParserARG_FETCH; - yymsp = &yypParser->yystack[yypParser->yyidx]; + yymsp = yypParser->yytos; #ifndef NDEBUG - if( yyTraceFILE && yyruleno>=0 - && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, - yyRuleName[yyruleno], yymsp[-yysize].stateno); + yyRuleName[yyruleno], yymsp[yysize].stateno); } #endif /* NDEBUG */ - yygotominor = yyzerominor; + + /* 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 ){ +#ifdef YYTRACKMAXSTACKDEPTH + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=yypParser->yystackEnd ){ + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ + if( yyGrowStack(yypParser) ){ + yyStackOverflow(yypParser); + return; + } + yymsp = yypParser->yytos; + } +#endif + } switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example @@ -129379,325 +139187,285 @@ static void yy_reduce( ** break; */ /********** Begin reduce actions **********************************************/ - case 5: /* explain ::= */ -{ sqlite3BeginParse(pParse, 0); } + YYMINORTYPE yylhsminor; + case 0: /* explain ::= EXPLAIN */ +{ pParse->explain = 1; } break; - case 6: /* explain ::= EXPLAIN */ -{ sqlite3BeginParse(pParse, 1); } + case 1: /* explain ::= EXPLAIN QUERY PLAN */ +{ pParse->explain = 2; } break; - case 7: /* explain ::= EXPLAIN QUERY PLAN */ -{ sqlite3BeginParse(pParse, 2); } - break; - case 8: /* cmdx ::= cmd */ + case 2: /* cmdx ::= cmd */ { sqlite3FinishCoding(pParse); } break; - case 9: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);} + case 3: /* cmd ::= BEGIN transtype trans_opt */ +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);} break; - case 13: /* transtype ::= */ -{yygotominor.yy4 = TK_DEFERRED;} + case 4: /* transtype ::= */ +{yymsp[1].minor.yy194 = TK_DEFERRED;} break; - case 14: /* transtype ::= DEFERRED */ - case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15); - case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16); - case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115); - case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117); -{yygotominor.yy4 = yymsp[0].major;} + case 5: /* transtype ::= DEFERRED */ + case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); + case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/} break; - case 17: /* cmd ::= COMMIT trans_opt */ - case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18); -{sqlite3CommitTransaction(pParse);} + case 8: /* cmd ::= COMMIT|END trans_opt */ + case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); +{sqlite3EndTransaction(pParse,yymsp[-1].major);} break; - case 19: /* cmd ::= ROLLBACK trans_opt */ -{sqlite3RollbackTransaction(pParse);} - break; - case 22: /* cmd ::= SAVEPOINT nm */ + case 10: /* cmd ::= SAVEPOINT nm */ { sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); } break; - case 23: /* cmd ::= RELEASE savepoint_opt nm */ + case 11: /* cmd ::= RELEASE savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); } break; - case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ { sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; - case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194); } break; - case 27: /* createkw ::= CREATE */ + case 14: /* createkw ::= CREATE */ +{disableLookaside(pParse);} + break; + case 15: /* ifnotexists ::= */ + case 18: /* temp ::= */ yytestcase(yyruleno==18); + case 21: /* table_options ::= */ yytestcase(yyruleno==21); + case 41: /* autoinc ::= */ yytestcase(yyruleno==41); + case 56: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==56); + case 66: /* defer_subclause_opt ::= */ yytestcase(yyruleno==66); + case 75: /* ifexists ::= */ yytestcase(yyruleno==75); + case 89: /* distinct ::= */ yytestcase(yyruleno==89); + case 212: /* collate ::= */ yytestcase(yyruleno==212); +{yymsp[1].minor.yy194 = 0;} + break; + case 16: /* ifnotexists ::= IF NOT EXISTS */ +{yymsp[-2].minor.yy194 = 1;} + break; + case 17: /* temp ::= TEMP */ + case 42: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==42); +{yymsp[0].minor.yy194 = 1;} + break; + case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ { - pParse->db->lookaside.bEnabled = 0; - yygotominor.yy0 = yymsp[0].minor.yy0; + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0); } break; - case 28: /* ifnotexists ::= */ - case 31: /* temp ::= */ yytestcase(yyruleno==31); - case 34: /* table_options ::= */ yytestcase(yyruleno==34); - case 68: /* autoinc ::= */ yytestcase(yyruleno==68); - case 81: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==81); - case 83: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==83); - case 85: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==85); - case 97: /* defer_subclause_opt ::= */ yytestcase(yyruleno==97); - case 108: /* ifexists ::= */ yytestcase(yyruleno==108); - case 124: /* distinct ::= */ yytestcase(yyruleno==124); - case 219: /* between_op ::= BETWEEN */ yytestcase(yyruleno==219); - case 222: /* in_op ::= IN */ yytestcase(yyruleno==222); - case 247: /* collate ::= */ yytestcase(yyruleno==247); -{yygotominor.yy4 = 0;} - break; - case 29: /* ifnotexists ::= IF NOT EXISTS */ - case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30); - case 69: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==69); - case 84: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==84); - case 107: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==107); - case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220); - case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223); - case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248); -{yygotominor.yy4 = 1;} - break; - case 32: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ + case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy4,0); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); } break; - case 33: /* create_table_args ::= AS select */ -{ - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy387); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387); -} - break; - case 35: /* table_options ::= WITHOUT nm */ + case 22: /* table_options ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yygotominor.yy4 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yygotominor.yy4 = 0; + yymsp[-1].minor.yy194 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } break; - case 38: /* column ::= columnid type carglist */ + case 23: /* columnname ::= nm typetoken */ +{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} + break; + case 24: /* typetoken ::= */ + case 59: /* conslist_opt ::= */ yytestcase(yyruleno==59); + case 95: /* as ::= */ yytestcase(yyruleno==95); +{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} + break; + case 25: /* typetoken ::= typename LP signed RP */ { - yygotominor.yy0.z = yymsp[-2].minor.yy0.z; - yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n; + yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); } break; - case 39: /* columnid ::= nm */ + case 26: /* typetoken ::= typename LP signed COMMA signed RP */ { - sqlite3AddColumn(pParse,&yymsp[0].minor.yy0); - yygotominor.yy0 = yymsp[0].minor.yy0; - pParse->constraintName.n = 0; + yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); } break; - case 40: /* nm ::= ID|INDEXED */ - case 41: /* nm ::= STRING */ yytestcase(yyruleno==41); - case 42: /* nm ::= JOIN_KW */ yytestcase(yyruleno==42); - case 45: /* typetoken ::= typename */ yytestcase(yyruleno==45); - case 48: /* typename ::= ID|STRING */ yytestcase(yyruleno==48); - case 130: /* as ::= AS nm */ yytestcase(yyruleno==130); - case 131: /* as ::= ID|STRING */ yytestcase(yyruleno==131); - case 142: /* dbnm ::= DOT nm */ yytestcase(yyruleno==142); - case 151: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==151); - case 257: /* nmnum ::= plus_num */ yytestcase(yyruleno==257); - case 258: /* nmnum ::= nm */ yytestcase(yyruleno==258); - case 259: /* nmnum ::= ON */ yytestcase(yyruleno==259); - case 260: /* nmnum ::= DELETE */ yytestcase(yyruleno==260); - case 261: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==261); - case 262: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==262); - case 263: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==263); - case 264: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==264); - case 280: /* trnm ::= nm */ yytestcase(yyruleno==280); -{yygotominor.yy0 = yymsp[0].minor.yy0;} + case 27: /* typename ::= typename ID|STRING */ +{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} break; - case 44: /* type ::= typetoken */ -{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);} - break; - case 46: /* typetoken ::= typename LP signed RP */ -{ - yygotominor.yy0.z = yymsp[-3].minor.yy0.z; - yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); -} - break; - case 47: /* typetoken ::= typename LP signed COMMA signed RP */ -{ - yygotominor.yy0.z = yymsp[-5].minor.yy0.z; - yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); -} - break; - case 49: /* typename ::= typename ID|STRING */ -{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} - break; - case 54: /* ccons ::= CONSTRAINT nm */ - case 92: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==92); + case 28: /* ccons ::= CONSTRAINT nm */ + case 61: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==61); {pParse->constraintName = yymsp[0].minor.yy0;} break; - case 55: /* ccons ::= DEFAULT term */ - case 57: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==57); -{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy118);} + case 29: /* ccons ::= DEFAULT term */ + case 31: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==31); +{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);} break; - case 56: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy118);} + case 30: /* ccons ::= DEFAULT LP expr RP */ +{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);} break; - case 58: /* ccons ::= DEFAULT MINUS term */ + case 32: /* ccons ::= DEFAULT MINUS term */ { ExprSpan v; - v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy118.pExpr, 0, 0); + v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0); v.zStart = yymsp[-1].minor.yy0.z; - v.zEnd = yymsp[0].minor.yy118.zEnd; + v.zEnd = yymsp[0].minor.yy190.zEnd; sqlite3AddDefaultValue(pParse,&v); } break; - case 59: /* ccons ::= DEFAULT ID|INDEXED */ + case 33: /* ccons ::= DEFAULT ID|INDEXED */ { ExprSpan v; - spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0); + spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0); sqlite3AddDefaultValue(pParse,&v); } break; - case 61: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);} + case 34: /* ccons ::= NOT NULL onconf */ +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);} break; - case 62: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);} + case 35: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);} break; - case 63: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0);} + case 36: /* ccons ::= UNIQUE onconf */ +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} break; - case 64: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy118.pExpr);} + case 37: /* ccons ::= CHECK LP expr RP */ +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);} break; - case 65: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);} + case 38: /* ccons ::= REFERENCES nm eidlist_opt refargs */ +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);} break; - case 66: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);} + case 39: /* ccons ::= defer_subclause */ +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);} break; - case 67: /* ccons ::= COLLATE ID|STRING */ + case 40: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; - case 70: /* refargs ::= */ -{ yygotominor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */} + case 43: /* refargs ::= */ +{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */} break; - case 71: /* refargs ::= refargs refarg */ -{ yygotominor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; } + case 44: /* refargs ::= refargs refarg */ +{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; } break; - case 72: /* refarg ::= MATCH nm */ - case 73: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==73); -{ yygotominor.yy215.value = 0; yygotominor.yy215.mask = 0x000000; } + case 45: /* refarg ::= MATCH nm */ +{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; } break; - case 74: /* refarg ::= ON DELETE refact */ -{ yygotominor.yy215.value = yymsp[0].minor.yy4; yygotominor.yy215.mask = 0x0000ff; } + case 46: /* refarg ::= ON INSERT refact */ +{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; } break; - case 75: /* refarg ::= ON UPDATE refact */ -{ yygotominor.yy215.value = yymsp[0].minor.yy4<<8; yygotominor.yy215.mask = 0x00ff00; } + case 47: /* refarg ::= ON DELETE refact */ +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; } break; - case 76: /* refact ::= SET NULL */ -{ yygotominor.yy4 = OE_SetNull; /* EV: R-33326-45252 */} + case 48: /* refarg ::= ON UPDATE refact */ +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; } break; - case 77: /* refact ::= SET DEFAULT */ -{ yygotominor.yy4 = OE_SetDflt; /* EV: R-33326-45252 */} + case 49: /* refact ::= SET NULL */ +{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */} break; - case 78: /* refact ::= CASCADE */ -{ yygotominor.yy4 = OE_Cascade; /* EV: R-33326-45252 */} + case 50: /* refact ::= SET DEFAULT */ +{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */} break; - case 79: /* refact ::= RESTRICT */ -{ yygotominor.yy4 = OE_Restrict; /* EV: R-33326-45252 */} + case 51: /* refact ::= CASCADE */ +{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */} break; - case 80: /* refact ::= NO ACTION */ -{ yygotominor.yy4 = OE_None; /* EV: R-33326-45252 */} + case 52: /* refact ::= RESTRICT */ +{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */} break; - case 82: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 98: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==98); - case 100: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==100); - case 102: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==102); - case 103: /* resolvetype ::= raisetype */ yytestcase(yyruleno==103); - case 178: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==178); -{yygotominor.yy4 = yymsp[0].minor.yy4;} + case 53: /* refact ::= NO ACTION */ +{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */} break; - case 86: /* conslist_opt ::= */ -{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;} + case 54: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ +{yymsp[-2].minor.yy194 = 0;} break; - case 87: /* conslist_opt ::= COMMA conslist */ -{yygotominor.yy0 = yymsp[-1].minor.yy0;} + case 55: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 70: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==70); + case 143: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==143); +{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;} break; - case 90: /* tconscomma ::= COMMA */ + case 57: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 74: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==74); + case 184: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==184); + case 187: /* in_op ::= NOT IN */ yytestcase(yyruleno==187); + case 213: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==213); +{yymsp[-1].minor.yy194 = 1;} + break; + case 58: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ +{yymsp[-1].minor.yy194 = 0;} + break; + case 60: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; - case 93: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);} + case 62: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);} break; - case 94: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0);} + case 63: /* tcons ::= UNIQUE LP sortlist RP onconf */ +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} break; - case 95: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy118.pExpr);} + case 64: /* tcons ::= CHECK LP expr RP onconf */ +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);} break; - case 96: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + case 65: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194); } break; - case 99: /* onconf ::= */ - case 101: /* orconf ::= */ yytestcase(yyruleno==101); -{yygotominor.yy4 = OE_Default;} + case 67: /* onconf ::= */ + case 69: /* orconf ::= */ yytestcase(yyruleno==69); +{yymsp[1].minor.yy194 = OE_Default;} break; - case 104: /* resolvetype ::= IGNORE */ -{yygotominor.yy4 = OE_Ignore;} + case 68: /* onconf ::= ON CONFLICT resolvetype */ +{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;} break; - case 105: /* resolvetype ::= REPLACE */ - case 179: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==179); -{yygotominor.yy4 = OE_Replace;} + case 71: /* resolvetype ::= IGNORE */ +{yymsp[0].minor.yy194 = OE_Ignore;} break; - case 106: /* cmd ::= DROP TABLE ifexists fullname */ + case 72: /* resolvetype ::= REPLACE */ + case 144: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==144); +{yymsp[0].minor.yy194 = OE_Replace;} + break; + case 73: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4); + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194); } break; - case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + case 76: /* 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.yy322, yymsp[0].minor.yy387, yymsp[-7].minor.yy4, yymsp[-5].minor.yy4); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194); } break; - case 110: /* cmd ::= DROP VIEW ifexists fullname */ + case 77: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4); + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194); } break; - case 111: /* cmd ::= select */ + case 78: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy387, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387); + sqlite3Select(pParse, yymsp[0].minor.yy243, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); } break; - case 112: /* select ::= with selectnowith */ + case 79: /* select ::= with selectnowith */ { - Select *p = yymsp[0].minor.yy387; + Select *p = yymsp[0].minor.yy243; if( p ){ - p->pWith = yymsp[-1].minor.yy451; + p->pWith = yymsp[-1].minor.yy285; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy451); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285); } - yygotominor.yy387 = p; + yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/ } break; - case 113: /* selectnowith ::= oneselect */ - case 119: /* oneselect ::= values */ yytestcase(yyruleno==119); -{yygotominor.yy387 = yymsp[0].minor.yy387;} - break; - case 114: /* selectnowith ::= selectnowith multiselect_op oneselect */ + case 80: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy387; - Select *pLhs = yymsp[-2].minor.yy387; + Select *pRhs = yymsp[0].minor.yy243; + Select *pLhs = yymsp[-2].minor.yy243; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -129707,23 +139475,30 @@ static void yy_reduce( pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy4; + pRhs->op = (u8)yymsp[-1].minor.yy194; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy4!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yygotominor.yy387 = pRhs; + yymsp[-2].minor.yy243 = pRhs; } break; - case 116: /* multiselect_op ::= UNION ALL */ -{yygotominor.yy4 = TK_ALL;} + case 81: /* multiselect_op ::= UNION */ + case 83: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==83); +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/} break; - case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 82: /* multiselect_op ::= UNION ALL */ +{yymsp[-1].minor.yy194 = TK_ALL;} + break; + case 84: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yygotominor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy292.pLimit,yymsp[0].minor.yy292.pOffset); +#if SELECTTRACE_ENABLED + Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ +#endif + yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset); #if SELECTTRACE_ENABLED /* Populate the Select.zSelName[] string that is used to help with ** query planner debugging, to differentiate between multiple Select @@ -129734,446 +139509,483 @@ static void yy_reduce( ** comment to be the zSelName value. Otherwise, the label is #N where ** is an integer that is incremented with each SELECT statement seen. */ - if( yygotominor.yy387!=0 ){ - const char *z = yymsp[-8].minor.yy0.z+6; + if( yymsp[-8].minor.yy243!=0 ){ + const char *z = s.z+6; int i; - sqlite3_snprintf(sizeof(yygotominor.yy387->zSelName), yygotominor.yy387->zSelName, "#%d", + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d", ++pParse->nSelect); while( z[0]==' ' ) z++; if( z[0]=='/' && z[1]=='*' ){ z += 2; while( z[0]==' ' ) z++; for(i=0; sqlite3Isalnum(z[i]); i++){} - sqlite3_snprintf(sizeof(yygotominor.yy387->zSelName), yygotominor.yy387->zSelName, "%.*s", i, z); + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z); } } #endif /* SELECTRACE_ENABLED */ } break; - case 120: /* values ::= VALUES LP nexprlist RP */ + case 85: /* values ::= VALUES LP nexprlist RP */ { - yygotominor.yy387 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0,0); + yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0); } break; - case 121: /* values ::= values COMMA LP exprlist RP */ + case 86: /* values ::= values COMMA LP exprlist RP */ { - Select *pRight, *pLeft = yymsp[-4].minor.yy387; - pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); + Select *pRight, *pLeft = yymsp[-4].minor.yy243; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; - pLeft = yymsp[-4].minor.yy387; pRight->pPrior = pLeft; - yygotominor.yy387 = pRight; + yymsp[-4].minor.yy243 = pRight; }else{ - yygotominor.yy387 = pLeft; + yymsp[-4].minor.yy243 = pLeft; } } break; - case 122: /* distinct ::= DISTINCT */ -{yygotominor.yy4 = SF_Distinct;} + case 87: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy194 = SF_Distinct;} break; - case 123: /* distinct ::= ALL */ -{yygotominor.yy4 = SF_All;} + case 88: /* distinct ::= ALL */ +{yymsp[0].minor.yy194 = SF_All;} break; - case 125: /* sclp ::= selcollist COMMA */ - case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244); -{yygotominor.yy322 = yymsp[-1].minor.yy322;} + case 90: /* sclp ::= */ + case 118: /* orderby_opt ::= */ yytestcase(yyruleno==118); + case 125: /* groupby_opt ::= */ yytestcase(yyruleno==125); + case 200: /* exprlist ::= */ yytestcase(yyruleno==200); + case 203: /* paren_exprlist ::= */ yytestcase(yyruleno==203); + case 208: /* eidlist_opt ::= */ yytestcase(yyruleno==208); +{yymsp[1].minor.yy148 = 0;} break; - case 126: /* sclp ::= */ - case 155: /* orderby_opt ::= */ yytestcase(yyruleno==155); - case 162: /* groupby_opt ::= */ yytestcase(yyruleno==162); - case 237: /* exprlist ::= */ yytestcase(yyruleno==237); - case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243); -{yygotominor.yy322 = 0;} - break; - case 127: /* selcollist ::= sclp expr as */ + case 91: /* selcollist ::= sclp expr as */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, yymsp[-1].minor.yy118.pExpr); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yygotominor.yy322,&yymsp[-1].minor.yy118); + yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190); } break; - case 128: /* selcollist ::= sclp STAR */ + case 92: /* selcollist ::= sclp STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy322, p); + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p); } break; - case 129: /* selcollist ::= sclp nm DOT STAR */ + case 93: /* selcollist ::= sclp nm DOT STAR */ { - Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &yymsp[0].minor.yy0); - Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); - Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); - yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, pDot); + 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[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot); } break; - case 132: /* as ::= */ -{yygotominor.yy0.n = 0;} + case 94: /* as ::= AS nm */ + case 105: /* dbnm ::= DOT nm */ yytestcase(yyruleno==105); + case 222: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==222); + case 223: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==223); +{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 133: /* from ::= */ -{yygotominor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy259));} + case 96: /* from ::= */ +{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));} break; - case 134: /* from ::= FROM seltablist */ + case 97: /* from ::= FROM seltablist */ { - yygotominor.yy259 = yymsp[0].minor.yy259; - sqlite3SrcListShiftJoinType(yygotominor.yy259); + yymsp[-1].minor.yy185 = yymsp[0].minor.yy185; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185); } break; - case 135: /* stl_prefix ::= seltablist joinop */ + case 98: /* stl_prefix ::= seltablist joinop */ { - yygotominor.yy259 = yymsp[-1].minor.yy259; - if( ALWAYS(yygotominor.yy259 && yygotominor.yy259->nSrc>0) ) yygotominor.yy259->a[yygotominor.yy259->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy4; + if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194; } break; - case 136: /* stl_prefix ::= */ -{yygotominor.yy259 = 0;} + case 99: /* stl_prefix ::= */ +{yymsp[1].minor.yy185 = 0;} break; - case 137: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + case 100: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ { - yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); - sqlite3SrcListIndexedBy(pParse, yygotominor.yy259, &yymsp[-2].minor.yy0); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0); } break; - case 138: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + case 101: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ { - yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy259,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); - sqlite3SrcListFuncArgs(pParse, yygotominor.yy259, yymsp[-4].minor.yy322); + yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148); } break; - case 139: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + case 102: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ { - yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); } break; - case 140: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + case 103: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { - if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){ - yygotominor.yy259 = yymsp[-4].minor.yy259; - }else if( yymsp[-4].minor.yy259->nSrc==1 ){ - yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); - if( yygotominor.yy259 ){ - struct SrcList_item *pNew = &yygotominor.yy259->a[yygotominor.yy259->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy259->a; + if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){ + yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185; + }else if( yymsp[-4].minor.yy185->nSrc==1 ){ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + if( yymsp[-6].minor.yy185 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy185->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy259); + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,SF_NestedFrom,0,0); - yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); } } break; - case 141: /* dbnm ::= */ - case 150: /* indexed_opt ::= */ yytestcase(yyruleno==150); -{yygotominor.yy0.z=0; yygotominor.yy0.n=0;} + case 104: /* dbnm ::= */ + case 113: /* indexed_opt ::= */ yytestcase(yyruleno==113); +{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 143: /* fullname ::= nm dbnm */ -{yygotominor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} + case 106: /* fullname ::= nm dbnm */ +{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 144: /* joinop ::= COMMA|JOIN */ -{ yygotominor.yy4 = JT_INNER; } + case 107: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy194 = JT_INNER; } break; - case 145: /* joinop ::= JOIN_KW JOIN */ -{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } + case 108: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 146: /* joinop ::= JOIN_KW nm JOIN */ -{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); } + case 109: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 147: /* joinop ::= JOIN_KW nm nm JOIN */ -{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); } + case 110: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 148: /* on_opt ::= ON expr */ - case 165: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==165); - case 172: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==172); - case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232); - case 234: /* case_operand ::= expr */ yytestcase(yyruleno==234); -{yygotominor.yy314 = yymsp[0].minor.yy118.pExpr;} + case 111: /* on_opt ::= ON expr */ + case 128: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==128); + case 135: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==135); + case 196: /* case_else ::= ELSE expr */ yytestcase(yyruleno==196); +{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;} break; - case 149: /* on_opt ::= */ - case 164: /* having_opt ::= */ yytestcase(yyruleno==164); - case 171: /* where_opt ::= */ yytestcase(yyruleno==171); - case 233: /* case_else ::= */ yytestcase(yyruleno==233); - case 235: /* case_operand ::= */ yytestcase(yyruleno==235); -{yygotominor.yy314 = 0;} + case 112: /* on_opt ::= */ + case 127: /* having_opt ::= */ yytestcase(yyruleno==127); + case 134: /* where_opt ::= */ yytestcase(yyruleno==134); + case 197: /* case_else ::= */ yytestcase(yyruleno==197); + case 199: /* case_operand ::= */ yytestcase(yyruleno==199); +{yymsp[1].minor.yy72 = 0;} break; - case 152: /* indexed_opt ::= NOT INDEXED */ -{yygotominor.yy0.z=0; yygotominor.yy0.n=1;} + case 114: /* indexed_opt ::= INDEXED BY nm */ +{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 153: /* using_opt ::= USING LP idlist RP */ - case 181: /* idlist_opt ::= LP idlist RP */ yytestcase(yyruleno==181); -{yygotominor.yy384 = yymsp[-1].minor.yy384;} + case 115: /* indexed_opt ::= NOT INDEXED */ +{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 154: /* using_opt ::= */ - case 180: /* idlist_opt ::= */ yytestcase(yyruleno==180); -{yygotominor.yy384 = 0;} + case 116: /* using_opt ::= USING LP idlist RP */ +{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} break; - case 156: /* orderby_opt ::= ORDER BY sortlist */ - case 163: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==163); - case 236: /* exprlist ::= nexprlist */ yytestcase(yyruleno==236); -{yygotominor.yy322 = yymsp[0].minor.yy322;} + case 117: /* using_opt ::= */ + case 145: /* idlist_opt ::= */ yytestcase(yyruleno==145); +{yymsp[1].minor.yy254 = 0;} break; - case 157: /* sortlist ::= sortlist COMMA expr sortorder */ + case 119: /* orderby_opt ::= ORDER BY sortlist */ + case 126: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==126); +{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;} + break; + case 120: /* sortlist ::= sortlist COMMA expr sortorder */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy118.pExpr); - sqlite3ExprListSetSortOrder(yygotominor.yy322,yymsp[0].minor.yy4); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194); } break; - case 158: /* sortlist ::= expr sortorder */ + case 121: /* sortlist ::= expr sortorder */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy118.pExpr); - sqlite3ExprListSetSortOrder(yygotominor.yy322,yymsp[0].minor.yy4); + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194); } break; - case 159: /* sortorder ::= ASC */ -{yygotominor.yy4 = SQLITE_SO_ASC;} + case 122: /* sortorder ::= ASC */ +{yymsp[0].minor.yy194 = SQLITE_SO_ASC;} break; - case 160: /* sortorder ::= DESC */ -{yygotominor.yy4 = SQLITE_SO_DESC;} + case 123: /* sortorder ::= DESC */ +{yymsp[0].minor.yy194 = SQLITE_SO_DESC;} break; - case 161: /* sortorder ::= */ -{yygotominor.yy4 = SQLITE_SO_UNDEFINED;} + case 124: /* sortorder ::= */ +{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;} break; - case 166: /* limit_opt ::= */ -{yygotominor.yy292.pLimit = 0; yygotominor.yy292.pOffset = 0;} + case 129: /* limit_opt ::= */ +{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;} break; - case 167: /* limit_opt ::= LIMIT expr */ -{yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr; yygotominor.yy292.pOffset = 0;} + case 130: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;} break; - case 168: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yygotominor.yy292.pLimit = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pOffset = yymsp[0].minor.yy118.pExpr;} + case 131: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;} break; - case 169: /* limit_opt ::= LIMIT expr COMMA expr */ -{yygotominor.yy292.pOffset = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr;} + case 132: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;} break; - case 170: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ + case 133: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ { - sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1); - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314); + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72); } break; - case 173: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ + case 136: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ { - sqlite3WithPush(pParse, yymsp[-7].minor.yy451, 1); - sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy259, &yymsp[-3].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy322,"set list"); - sqlite3Update(pParse,yymsp[-4].minor.yy259,yymsp[-1].minor.yy322,yymsp[0].minor.yy314,yymsp[-5].minor.yy4); + sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy148,"set list"); + sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194); } break; - case 174: /* setlist ::= setlist COMMA nm EQ expr */ + case 137: /* setlist ::= setlist COMMA nm EQ expr */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy118.pExpr); - sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1); } break; - case 175: /* setlist ::= nm EQ expr */ + case 138: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy118.pExpr); - sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1); + yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); } break; - case 176: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ + case 139: /* setlist ::= nm EQ expr */ { - sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1); - sqlite3Insert(pParse, yymsp[-2].minor.yy259, yymsp[0].minor.yy387, yymsp[-1].minor.yy384, yymsp[-4].minor.yy4); + yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1); +} + yymsp[-2].minor.yy148 = yylhsminor.yy148; + break; + case 140: /* setlist ::= LP idlist RP EQ expr */ +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); } break; - case 177: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ + case 141: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ { - sqlite3WithPush(pParse, yymsp[-6].minor.yy451, 1); - sqlite3Insert(pParse, yymsp[-3].minor.yy259, 0, yymsp[-2].minor.yy384, yymsp[-5].minor.yy4); + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194); } break; - case 182: /* idlist ::= idlist COMMA nm */ -{yygotominor.yy384 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy384,&yymsp[0].minor.yy0);} - break; - case 183: /* idlist ::= nm */ -{yygotominor.yy384 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);} - break; - case 184: /* expr ::= term */ -{yygotominor.yy118 = yymsp[0].minor.yy118;} - break; - case 185: /* expr ::= LP expr RP */ -{yygotominor.yy118.pExpr = yymsp[-1].minor.yy118.pExpr; spanSet(&yygotominor.yy118,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);} - break; - case 186: /* term ::= NULL */ - case 191: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==191); - case 192: /* term ::= STRING */ yytestcase(yyruleno==192); -{spanExpr(&yygotominor.yy118, pParse, yymsp[0].major, &yymsp[0].minor.yy0);} - break; - case 187: /* expr ::= ID|INDEXED */ - case 188: /* expr ::= JOIN_KW */ yytestcase(yyruleno==188); -{spanExpr(&yygotominor.yy118, pParse, TK_ID, &yymsp[0].minor.yy0);} - break; - case 189: /* expr ::= nm DOT nm */ + case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ { - Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); - Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0); - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); - spanSet(&yygotominor.yy118,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194); } break; - case 190: /* expr ::= nm DOT nm DOT nm */ + case 146: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} + break; + case 147: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} + break; + case 148: /* idlist ::= nm */ +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + break; + case 149: /* expr ::= LP expr RP */ +{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;} + break; + case 150: /* expr ::= ID|INDEXED */ + case 151: /* expr ::= JOIN_KW */ yytestcase(yyruleno==151); +{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 152: /* expr ::= nm DOT nm */ { - Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0); - Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); - Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0); - Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0); - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); - spanSet(&yygotominor.yy118,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); + Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } break; - case 193: /* expr ::= VARIABLE */ + case 153: /* expr ::= nm DOT nm DOT nm */ { - if( yymsp[0].minor.yy0.n>=2 && yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1]) ){ + Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); + Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); + Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); +} + break; + case 154: /* term ::= NULL|FLOAT|BLOB */ + case 155: /* term ::= STRING */ yytestcase(yyruleno==155); +{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 156: /* term ::= INTEGER */ +{ + yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z; + yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n; +} + yymsp[0].minor.yy190 = yylhsminor.yy190; + break; + case 157: /* expr ::= VARIABLE */ +{ + if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ + u32 n = yymsp[0].minor.yy0.n; + spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr, 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 ** in the virtual machine. #N is the N-th register. */ + Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ + assert( t.n>=2 ); + spanSet(&yymsp[0].minor.yy190, &t, &t); if( pParse->nested==0 ){ - sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0); - yygotominor.yy118.pExpr = 0; + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); + yymsp[0].minor.yy190.pExpr = 0; }else{ - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0); - if( yygotominor.yy118.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy118.pExpr->iTable); + yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable); } - }else{ - spanExpr(&yygotominor.yy118, pParse, TK_VARIABLE, &yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yygotominor.yy118.pExpr); } - spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); } break; - case 194: /* expr ::= expr COLLATE ID|STRING */ + case 158: /* expr ::= expr COLLATE ID|STRING */ { - yygotominor.yy118.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy118.pExpr, &yymsp[0].minor.yy0, 1); - yygotominor.yy118.zStart = yymsp[-2].minor.yy118.zStart; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 195: /* expr ::= CAST LP expr AS typetoken RP */ + case 159: /* expr ::= CAST LP expr AS typetoken RP */ { - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy118.pExpr, 0, &yymsp[-1].minor.yy0); - spanSet(&yygotominor.yy118,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, 0); } break; - case 196: /* expr ::= ID|INDEXED LP distinct exprlist RP */ + case 160: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { - if( yymsp[-1].minor.yy322 && yymsp[-1].minor.yy322->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); } - yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); - spanSet(&yygotominor.yy118,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy4==SF_Distinct && yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->flags |= EP_Distinct; + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); + if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->flags |= EP_Distinct; } } + yymsp[-4].minor.yy190 = yylhsminor.yy190; break; - case 197: /* expr ::= ID|INDEXED LP STAR RP */ + case 161: /* expr ::= ID|INDEXED LP STAR RP */ { - yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); - spanSet(&yygotominor.yy118,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); } + yymsp[-3].minor.yy190 = yylhsminor.yy190; break; - case 198: /* term ::= CTIME_KW */ + case 162: /* term ::= CTIME_KW */ { - yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); - spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); + spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); } + yymsp[0].minor.yy190 = yylhsminor.yy190; break; - case 199: /* expr ::= expr AND expr */ - case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200); - case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201); - case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202); - case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203); - case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204); - case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205); - case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206); -{spanBinaryExpr(&yygotominor.yy118,pParse,yymsp[-1].major,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy118);} + case 163: /* expr ::= LP nexprlist COMMA expr RP */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr); + yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->x.pList = pList; + spanSet(&yylhsminor.yy190, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } +} + yymsp[-4].minor.yy190 = yylhsminor.yy190; break; - case 207: /* likeop ::= LIKE_KW|MATCH */ -{yygotominor.yy342.eOperator = yymsp[0].minor.yy0; yygotominor.yy342.bNot = 0;} + case 164: /* expr ::= expr AND expr */ + case 165: /* expr ::= expr OR expr */ yytestcase(yyruleno==165); + case 166: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==166); + case 167: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==167); + case 168: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==168); + case 169: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==169); + case 170: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==170); + case 171: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==171); +{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);} break; - case 208: /* likeop ::= NOT LIKE_KW|MATCH */ -{yygotominor.yy342.eOperator = yymsp[0].minor.yy0; yygotominor.yy342.bNot = 1;} + case 172: /* 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 209: /* expr ::= expr likeop expr */ + case 173: /* expr ::= expr likeop expr */ { ExprList *pList; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy118.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy118.pExpr); - yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy342.eOperator); - exprNot(pParse, yymsp[-1].minor.yy342.bNot, &yygotominor.yy118.pExpr); - yygotominor.yy118.zStart = yymsp[-2].minor.yy118.zStart; - yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd; - if( yygotominor.yy118.pExpr ) yygotominor.yy118.pExpr->flags |= EP_InfixFunc; + int bNot = yymsp[-1].minor.yy0.n & 0x80000000; + yymsp[-1].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr); + yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0); + exprNot(pParse, bNot, &yymsp[-2].minor.yy190); + yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc; } break; - case 210: /* expr ::= expr likeop expr ESCAPE expr */ + case 174: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy118.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy118.pExpr); - yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy342.eOperator); - exprNot(pParse, yymsp[-3].minor.yy342.bNot, &yygotominor.yy118.pExpr); - yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart; - yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd; - if( yygotominor.yy118.pExpr ) yygotominor.yy118.pExpr->flags |= EP_InfixFunc; + int bNot = yymsp[-3].minor.yy0.n & 0x80000000; + yymsp[-3].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0); + exprNot(pParse, bNot, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc; } break; - case 211: /* expr ::= expr ISNULL|NOTNULL */ -{spanUnaryPostfix(&yygotominor.yy118,pParse,yymsp[0].major,&yymsp[-1].minor.yy118,&yymsp[0].minor.yy0);} + case 175: /* expr ::= expr ISNULL|NOTNULL */ +{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);} break; - case 212: /* expr ::= expr NOT NULL */ -{spanUnaryPostfix(&yygotominor.yy118,pParse,TK_NOTNULL,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy0);} + case 176: /* expr ::= expr NOT NULL */ +{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);} break; - case 213: /* expr ::= expr IS expr */ + case 177: /* expr ::= expr IS expr */ { - spanBinaryExpr(&yygotominor.yy118,pParse,TK_IS,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy118); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy118.pExpr, yygotominor.yy118.pExpr, TK_ISNULL); + spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL); } break; - case 214: /* expr ::= expr IS NOT expr */ + case 178: /* expr ::= expr IS NOT expr */ { - spanBinaryExpr(&yygotominor.yy118,pParse,TK_ISNOT,&yymsp[-3].minor.yy118,&yymsp[0].minor.yy118); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy118.pExpr, yygotominor.yy118.pExpr, TK_NOTNULL); + spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL); } break; - case 215: /* expr ::= NOT expr */ - case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216); -{spanUnaryPrefix(&yygotominor.yy118,pParse,yymsp[-1].major,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);} + case 179: /* expr ::= NOT expr */ + case 180: /* expr ::= BITNOT expr */ yytestcase(yyruleno==180); +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; - case 217: /* expr ::= MINUS expr */ -{spanUnaryPrefix(&yygotominor.yy118,pParse,TK_UMINUS,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);} + case 181: /* expr ::= MINUS expr */ +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; - case 218: /* expr ::= PLUS expr */ -{spanUnaryPrefix(&yygotominor.yy118,pParse,TK_UPLUS,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);} + case 182: /* expr ::= PLUS expr */ +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; - case 221: /* expr ::= expr between_op expr AND expr */ + case 183: /* between_op ::= BETWEEN */ + case 186: /* in_op ::= IN */ yytestcase(yyruleno==186); +{yymsp[0].minor.yy194 = 0;} + break; + case 185: /* expr ::= expr between_op expr AND expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy118.pExpr); - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy118.pExpr, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - exprNot(pParse, yymsp[-3].minor.yy4, &yygotominor.yy118.pExpr); - yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart; - yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd; + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; } break; - case 224: /* expr ::= expr in_op LP exprlist RP */ + case 188: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy322==0 ){ + if( yymsp[-1].minor.yy148==0 ){ /* Expressions of the form ** ** expr1 IN () @@ -130182,9 +139994,9 @@ static void yy_reduce( ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy4]); - sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy118.pExpr); - }else if( yymsp[-1].minor.yy322->nExpr==1 ){ + sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy194],1); + }else if( yymsp[-1].minor.yy148->nExpr==1 ){ /* Expressions of the form: ** ** expr1 IN (?1) @@ -130201,423 +140013,422 @@ static void 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.yy322->a[0].pExpr; - yymsp[-1].minor.yy322->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr; + yymsp[-1].minor.yy148->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); /* 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; } - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy4 ? TK_NE : TK_EQ, yymsp[-4].minor.yy118.pExpr, pRHS, 0); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS); }else{ - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy118.pExpr, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->x.pList = yymsp[-1].minor.yy322; - sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); } - exprNot(pParse, yymsp[-3].minor.yy4, &yygotominor.yy118.pExpr); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); } - yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 225: /* expr ::= LP select RP */ + case 189: /* expr ::= LP select RP */ { - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->x.pSelect = yymsp[-1].minor.yy387; - ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect|EP_Subquery); - sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr); - }else{ - sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387); - } - yygotominor.yy118.zStart = yymsp[-2].minor.yy0.z; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243); } break; - case 226: /* expr ::= expr in_op LP select RP */ + case 190: /* expr ::= expr in_op LP select RP */ { - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy118.pExpr, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->x.pSelect = yymsp[-1].minor.yy387; - ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect|EP_Subquery); - sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr); - }else{ - sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387); - } - exprNot(pParse, yymsp[-3].minor.yy4, &yygotominor.yy118.pExpr); - yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 227: /* expr ::= expr in_op nm dbnm */ + case 191: /* expr ::= expr in_op nm dbnm paren_exprlist */ { - SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy118.pExpr, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); - ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect|EP_Subquery); - sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr); - }else{ - sqlite3SrcListDelete(pParse->db, pSrc); - } - exprNot(pParse, yymsp[-2].minor.yy4, &yygotominor.yy118.pExpr); - yygotominor.yy118.zStart = yymsp[-3].minor.yy118.zStart; - yygotominor.yy118.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]; + SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); + Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); + if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; } break; - case 228: /* expr ::= EXISTS LP select RP */ + case 192: /* expr ::= EXISTS LP select RP */ { - Expr *p = yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); - if( p ){ - p->x.pSelect = yymsp[-1].minor.yy387; - ExprSetProperty(p, EP_xIsSelect|EP_Subquery); - sqlite3ExprSetHeightAndFlags(pParse, p); - }else{ - sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387); - } - yygotominor.yy118.zStart = yymsp[-3].minor.yy0.z; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + Expr *p; + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243); } break; - case 229: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 193: /* expr ::= CASE case_operand case_exprlist case_else END */ { - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy314, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->x.pList = yymsp[-1].minor.yy314 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy314) : yymsp[-2].minor.yy322; - sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr); + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy314); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72); } - yygotominor.yy118.zStart = yymsp[-4].minor.yy0.z; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 194: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy118.pExpr); - yygotominor.yy322 = sqlite3ExprListAppend(pParse,yygotominor.yy322, yymsp[0].minor.yy118.pExpr); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); } break; - case 231: /* case_exprlist ::= WHEN expr THEN expr */ + case 195: /* case_exprlist ::= WHEN expr THEN expr */ { - yygotominor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr); - yygotominor.yy322 = sqlite3ExprListAppend(pParse,yygotominor.yy322, yymsp[0].minor.yy118.pExpr); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr); } break; - case 238: /* nexprlist ::= nexprlist COMMA expr */ -{yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy118.pExpr);} + case 198: /* case_operand ::= expr */ +{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/} break; - case 239: /* nexprlist ::= expr */ -{yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy118.pExpr);} + case 201: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);} break; - case 240: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 202: /* nexprlist ::= expr */ +{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/} + break; + case 204: /* paren_exprlist ::= LP exprlist RP */ + case 209: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==209); +{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;} + break; + case 205: /* 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.yy322, yymsp[-10].minor.yy4, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy314, SQLITE_SO_ASC, yymsp[-8].minor.yy4); + sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF); } break; - case 241: /* uniqueflag ::= UNIQUE */ - case 292: /* raisetype ::= ABORT */ yytestcase(yyruleno==292); -{yygotominor.yy4 = OE_Abort;} + case 206: /* uniqueflag ::= UNIQUE */ + case 246: /* raisetype ::= ABORT */ yytestcase(yyruleno==246); +{yymsp[0].minor.yy194 = OE_Abort;} break; - case 242: /* uniqueflag ::= */ -{yygotominor.yy4 = OE_None;} + case 207: /* uniqueflag ::= */ +{yymsp[1].minor.yy194 = OE_None;} break; - case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 210: /* eidlist ::= eidlist COMMA nm collate sortorder */ { - yygotominor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4); + yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); } break; - case 246: /* eidlist ::= nm collate sortorder */ + case 211: /* eidlist ::= nm collate sortorder */ { - yygotominor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4); + yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/ } break; - case 249: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy259, yymsp[-1].minor.yy4);} + case 214: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);} break; - case 250: /* cmd ::= VACUUM */ - case 251: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==251); -{sqlite3Vacuum(pParse);} + case 215: /* cmd ::= VACUUM */ +{sqlite3Vacuum(pParse,0);} break; - case 252: /* cmd ::= PRAGMA nm dbnm */ + case 216: /* cmd ::= VACUUM nm */ +{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} + break; + case 217: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 253: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 218: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 254: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 219: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 255: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 220: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 256: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 221: /* 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 265: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 224: /* 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.yy203, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all); } break; - case 266: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 225: /* 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.yy4, yymsp[-4].minor.yy90.a, yymsp[-4].minor.yy90.b, yymsp[-2].minor.yy259, yymsp[0].minor.yy314, yymsp[-10].minor.yy4, yymsp[-8].minor.yy4); - yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194); + yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 267: /* trigger_time ::= BEFORE */ - case 270: /* trigger_time ::= */ yytestcase(yyruleno==270); -{ yygotominor.yy4 = TK_BEFORE; } + case 226: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 268: /* trigger_time ::= AFTER */ -{ yygotominor.yy4 = TK_AFTER; } + case 227: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy194 = TK_INSTEAD;} break; - case 269: /* trigger_time ::= INSTEAD OF */ -{ yygotominor.yy4 = TK_INSTEAD;} + case 228: /* trigger_time ::= */ +{ yymsp[1].minor.yy194 = TK_BEFORE; } break; - case 271: /* trigger_event ::= DELETE|INSERT */ - case 272: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==272); -{yygotominor.yy90.a = yymsp[0].major; yygotominor.yy90.b = 0;} + case 229: /* trigger_event ::= DELETE|INSERT */ + case 230: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==230); +{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;} break; - case 273: /* trigger_event ::= UPDATE OF idlist */ -{yygotominor.yy90.a = TK_UPDATE; yygotominor.yy90.b = yymsp[0].minor.yy384;} + case 231: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;} break; - case 276: /* when_clause ::= */ - case 297: /* key_opt ::= */ yytestcase(yyruleno==297); -{ yygotominor.yy314 = 0; } + case 232: /* when_clause ::= */ + case 251: /* key_opt ::= */ yytestcase(yyruleno==251); +{ yymsp[1].minor.yy72 = 0; } break; - case 277: /* when_clause ::= WHEN expr */ - case 298: /* key_opt ::= KEY expr */ yytestcase(yyruleno==298); -{ yygotominor.yy314 = yymsp[0].minor.yy118.pExpr; } + case 233: /* when_clause ::= WHEN expr */ + case 252: /* key_opt ::= KEY expr */ yytestcase(yyruleno==252); +{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; } break; - case 278: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 234: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - assert( yymsp[-2].minor.yy203!=0 ); - yymsp[-2].minor.yy203->pLast->pNext = yymsp[-1].minor.yy203; - yymsp[-2].minor.yy203->pLast = yymsp[-1].minor.yy203; - yygotominor.yy203 = yymsp[-2].minor.yy203; + assert( yymsp[-2].minor.yy145!=0 ); + yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145; + yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145; } break; - case 279: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 235: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy203!=0 ); - yymsp[-1].minor.yy203->pLast = yymsp[-1].minor.yy203; - yygotominor.yy203 = yymsp[-1].minor.yy203; + assert( yymsp[-1].minor.yy145!=0 ); + yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145; } break; - case 281: /* trnm ::= nm DOT nm */ + case 236: /* trnm ::= nm DOT nm */ { - yygotominor.yy0 = yymsp[0].minor.yy0; + yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } break; - case 283: /* tridxby ::= INDEXED BY nm */ + case 237: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 284: /* tridxby ::= NOT INDEXED */ + case 238: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 285: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ -{ yygotominor.yy203 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy322, yymsp[0].minor.yy314, yymsp[-5].minor.yy4); } + case 239: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ +{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);} break; - case 286: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ -{yygotominor.yy203 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy384, yymsp[0].minor.yy387, yymsp[-4].minor.yy4);} + case 240: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ +{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/} break; - case 287: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ -{yygotominor.yy203 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy314);} + case 241: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ +{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);} break; - case 288: /* trigger_cmd ::= select */ -{yygotominor.yy203 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy387); } + case 242: /* trigger_cmd ::= select */ +{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/} break; - case 289: /* expr ::= RAISE LP IGNORE RP */ + case 243: /* expr ::= RAISE LP IGNORE RP */ { - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); - if( yygotominor.yy118.pExpr ){ - yygotominor.yy118.pExpr->affinity = OE_Ignore; + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy190.pExpr ){ + yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore; } - yygotominor.yy118.zStart = yymsp[-3].minor.yy0.z; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 290: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 244: /* expr ::= RAISE LP raisetype COMMA nm RP */ { - yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); - if( yygotominor.yy118.pExpr ) { - yygotominor.yy118.pExpr->affinity = (char)yymsp[-3].minor.yy4; + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy190.pExpr ) { + yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194; } - yygotominor.yy118.zStart = yymsp[-5].minor.yy0.z; - yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; - case 291: /* raisetype ::= ROLLBACK */ -{yygotominor.yy4 = OE_Rollback;} + case 245: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy194 = OE_Rollback;} break; - case 293: /* raisetype ::= FAIL */ -{yygotominor.yy4 = OE_Fail;} + case 247: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy194 = OE_Fail;} break; - case 294: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 248: /* cmd ::= DROP TRIGGER ifexists fullname */ { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy259,yymsp[-1].minor.yy4); + sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194); } break; - case 295: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 249: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - sqlite3Attach(pParse, yymsp[-3].minor.yy118.pExpr, yymsp[-1].minor.yy118.pExpr, yymsp[0].minor.yy314); + sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72); } break; - case 296: /* cmd ::= DETACH database_kw_opt expr */ + case 250: /* cmd ::= DETACH database_kw_opt expr */ { - sqlite3Detach(pParse, yymsp[0].minor.yy118.pExpr); + sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr); } break; - case 301: /* cmd ::= REINDEX */ + case 253: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 302: /* cmd ::= REINDEX nm dbnm */ + case 254: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 303: /* cmd ::= ANALYZE */ + case 255: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 304: /* cmd ::= ANALYZE nm dbnm */ + case 256: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 305: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 257: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy259,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0); } break; - case 306: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */ + case 258: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { - sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0); + 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 307: /* add_column_fullname ::= fullname */ + case 259: /* add_column_fullname ::= fullname */ { - pParse->db->lookaside.bEnabled = 0; - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy259); + disableLookaside(pParse); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185); } break; - case 310: /* cmd ::= create_vtab */ + case 260: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 311: /* cmd ::= create_vtab LP vtabarglist RP */ + case 261: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 312: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 262: /* 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.yy4); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194); } break; - case 315: /* vtabarg ::= */ + case 263: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 317: /* vtabargtoken ::= ANY */ - case 318: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==318); - case 319: /* lp ::= LP */ yytestcase(yyruleno==319); + case 264: /* vtabargtoken ::= ANY */ + case 265: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==265); + case 266: /* lp ::= LP */ yytestcase(yyruleno==266); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 323: /* with ::= */ -{yygotominor.yy451 = 0;} + case 267: /* with ::= */ +{yymsp[1].minor.yy285 = 0;} break; - case 324: /* with ::= WITH wqlist */ - case 325: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==325); -{ yygotominor.yy451 = yymsp[0].minor.yy451; } + case 268: /* with ::= WITH wqlist */ +{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; } break; - case 326: /* wqlist ::= nm eidlist_opt AS LP select RP */ + case 269: /* with ::= WITH RECURSIVE wqlist */ +{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; } + break; + case 270: /* wqlist ::= nm eidlist_opt AS LP select RP */ { - yygotominor.yy451 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387); + yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/ } break; - case 327: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + case 271: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ { - yygotominor.yy451 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy451, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387); + yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); } break; default: - /* (0) input ::= cmdlist */ yytestcase(yyruleno==0); - /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1); - /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2); - /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3); - /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4); - /* (10) trans_opt ::= */ yytestcase(yyruleno==10); - /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11); - /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12); - /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20); - /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21); - /* (25) cmd ::= create_table create_table_args */ yytestcase(yyruleno==25); - /* (36) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==36); - /* (37) columnlist ::= column */ yytestcase(yyruleno==37); - /* (43) type ::= */ yytestcase(yyruleno==43); - /* (50) signed ::= plus_num */ yytestcase(yyruleno==50); - /* (51) signed ::= minus_num */ yytestcase(yyruleno==51); - /* (52) carglist ::= carglist ccons */ yytestcase(yyruleno==52); - /* (53) carglist ::= */ yytestcase(yyruleno==53); - /* (60) ccons ::= NULL onconf */ yytestcase(yyruleno==60); - /* (88) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==88); - /* (89) conslist ::= tcons */ yytestcase(yyruleno==89); - /* (91) tconscomma ::= */ yytestcase(yyruleno==91); - /* (274) foreach_clause ::= */ yytestcase(yyruleno==274); - /* (275) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==275); - /* (282) tridxby ::= */ yytestcase(yyruleno==282); - /* (299) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==299); - /* (300) database_kw_opt ::= */ yytestcase(yyruleno==300); - /* (308) kwcolumn_opt ::= */ yytestcase(yyruleno==308); - /* (309) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==309); - /* (313) vtabarglist ::= vtabarg */ yytestcase(yyruleno==313); - /* (314) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==314); - /* (316) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==316); - /* (320) anylist ::= */ yytestcase(yyruleno==320); - /* (321) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==321); - /* (322) anylist ::= anylist ANY */ yytestcase(yyruleno==322); + /* (272) input ::= cmdlist */ yytestcase(yyruleno==272); + /* (273) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==273); + /* (274) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=274); + /* (275) ecmd ::= SEMI */ yytestcase(yyruleno==275); + /* (276) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==276); + /* (277) explain ::= */ yytestcase(yyruleno==277); + /* (278) trans_opt ::= */ yytestcase(yyruleno==278); + /* (279) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==279); + /* (280) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==280); + /* (281) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==281); + /* (282) savepoint_opt ::= */ yytestcase(yyruleno==282); + /* (283) cmd ::= create_table create_table_args */ yytestcase(yyruleno==283); + /* (284) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==284); + /* (285) columnlist ::= columnname carglist */ yytestcase(yyruleno==285); + /* (286) nm ::= ID|INDEXED */ yytestcase(yyruleno==286); + /* (287) nm ::= STRING */ yytestcase(yyruleno==287); + /* (288) nm ::= JOIN_KW */ yytestcase(yyruleno==288); + /* (289) typetoken ::= typename */ yytestcase(yyruleno==289); + /* (290) typename ::= ID|STRING */ yytestcase(yyruleno==290); + /* (291) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=291); + /* (292) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=292); + /* (293) carglist ::= carglist ccons */ yytestcase(yyruleno==293); + /* (294) carglist ::= */ yytestcase(yyruleno==294); + /* (295) ccons ::= NULL onconf */ yytestcase(yyruleno==295); + /* (296) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==296); + /* (297) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==297); + /* (298) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=298); + /* (299) tconscomma ::= */ yytestcase(yyruleno==299); + /* (300) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=300); + /* (301) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=301); + /* (302) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=302); + /* (303) oneselect ::= values */ yytestcase(yyruleno==303); + /* (304) sclp ::= selcollist COMMA */ yytestcase(yyruleno==304); + /* (305) as ::= ID|STRING */ yytestcase(yyruleno==305); + /* (306) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=306); + /* (307) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==307); + /* (308) exprlist ::= nexprlist */ yytestcase(yyruleno==308); + /* (309) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=309); + /* (310) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=310); + /* (311) nmnum ::= ON */ yytestcase(yyruleno==311); + /* (312) nmnum ::= DELETE */ yytestcase(yyruleno==312); + /* (313) nmnum ::= DEFAULT */ yytestcase(yyruleno==313); + /* (314) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==314); + /* (315) foreach_clause ::= */ yytestcase(yyruleno==315); + /* (316) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==316); + /* (317) trnm ::= nm */ yytestcase(yyruleno==317); + /* (318) tridxby ::= */ yytestcase(yyruleno==318); + /* (319) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==319); + /* (320) database_kw_opt ::= */ yytestcase(yyruleno==320); + /* (321) kwcolumn_opt ::= */ yytestcase(yyruleno==321); + /* (322) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==322); + /* (323) vtabarglist ::= vtabarg */ yytestcase(yyruleno==323); + /* (324) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==324); + /* (325) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==325); + /* (326) anylist ::= */ yytestcase(yyruleno==326); + /* (327) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==327); + /* (328) anylist ::= anylist ANY */ yytestcase(yyruleno==328); break; /********** End reduce actions ************************************************/ }; - assert( yyruleno>=0 && yyrulenoyyidx -= yysize; - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - /* If the reduce action popped at least - ** one element off the stack, then we can push the new element back - ** onto the stack here, and skip the stack overflow test in yy_shift(). - ** That gives a significant speed improvement. */ - if( yysize ){ - yypParser->yyidx++; - yymsp -= yysize-1; - yymsp->stateno = (YYACTIONTYPE)yyact; - yymsp->major = (YYCODETYPE)yygoto; - yymsp->minor = yygotominor; - yyTraceShift(yypParser, yyact); - }else{ - yy_shift(yypParser,yyact,yygoto,&yygotominor); - } - }else{ - assert( yyact == YY_ACCEPT_ACTION ); + yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto); + + /* There are no SHIFTREDUCE actions on nonterminals because the table + ** generator has simplified them to pure REDUCE actions. */ + assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( yyact!=YY_ERROR_ACTION ); + + if( yyact==YY_ACCEPT_ACTION ){ + yypParser->yytos += yysize; yy_accept(yypParser); + }else{ + yymsp += yysize+1; + yypParser->yytos = yymsp; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yyTraceShift(yypParser, yyact); } } @@ -130634,7 +140445,7 @@ static void yy_parse_failed( fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ @@ -130649,10 +140460,10 @@ static void yy_parse_failed( static void yy_syntax_error( yyParser *yypParser, /* The parser */ int yymajor, /* The major type of the error token */ - YYMINORTYPE yyminor /* The minor type of the error token */ + sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ ){ sqlite3ParserARG_FETCH; -#define TOKEN (yyminor.yy0) +#define TOKEN yyminor /************ Begin %syntax_error code ****************************************/ UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ @@ -130674,7 +140485,10 @@ static void yy_accept( fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + assert( yypParser->yytos==yypParser->yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ @@ -130708,7 +140522,7 @@ SQLITE_PRIVATE void sqlite3Parser( sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ ){ YYMINORTYPE yyminorunion; - int yyact; /* The parser action. */ + unsigned int yyact; /* The parser action. */ #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) int yyendofinput; /* True if we are at the end of input */ #endif @@ -130717,29 +140531,8 @@ SQLITE_PRIVATE void sqlite3Parser( #endif yyParser *yypParser; /* The parser */ - /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; - if( yypParser->yyidx<0 ){ -#if YYSTACKDEPTH<=0 - if( yypParser->yystksz <=0 ){ - /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ - yyminorunion = yyzerominor; - yyStackOverflow(yypParser, &yyminorunion); - return; - } -#endif - yypParser->yyidx = 0; - yypParser->yyerrcnt = -1; - yypParser->yystack[0].stateno = 0; - yypParser->yystack[0].major = 0; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n", - yyTracePrompt); - } -#endif - } - yyminorunion.yy0 = yyminor; + assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif @@ -130754,14 +140547,16 @@ SQLITE_PRIVATE void sqlite3Parser( do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - yy_shift(yypParser,yyact,yymajor,&yyminorunion); + yy_shift(yypParser,yyact,yymajor,yyminor); +#ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; +#endif yymajor = YYNOCODE; }else if( yyact <= YY_MAX_REDUCE ){ yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ assert( yyact == YY_ERROR_ACTION ); + yyminorunion.yy0 = yyminor; #ifdef YYERRORSYMBOL int yymx; #endif @@ -130791,9 +140586,9 @@ SQLITE_PRIVATE void sqlite3Parser( ** */ if( yypParser->yyerrcnt<0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_syntax_error(yypParser,yymajor,yyminor); } - yymx = yypParser->yystack[yypParser->yyidx].major; + yymx = yypParser->yytos->major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ @@ -130801,26 +140596,26 @@ SQLITE_PRIVATE void sqlite3Parser( yyTracePrompt,yyTokenName[yymajor]); } #endif - yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); + yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ - while( - yypParser->yyidx >= 0 && - yymx != YYERRORSYMBOL && - (yyact = yy_find_reduce_action( - yypParser->yystack[yypParser->yyidx].stateno, + while( yypParser->yytos >= yypParser->yystack + && yymx != YYERRORSYMBOL + && (yyact = yy_find_reduce_action( + yypParser->yytos->stateno, YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } - if( yypParser->yyidx < 0 || yymajor==0 ){ + if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ - YYMINORTYPE u2; - u2.YYERRSYMDT = 0; - yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); + yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); } } yypParser->yyerrcnt = 3; @@ -130833,7 +140628,7 @@ SQLITE_PRIVATE void sqlite3Parser( ** Applications can set this macro (for example inside %include) if ** they intend to abandon the parse upon the first syntax error seen. */ - yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_syntax_error(yypParser,yymajor, yyminor); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yymajor = YYNOCODE; @@ -130848,24 +140643,29 @@ SQLITE_PRIVATE void sqlite3Parser( ** three input tokens have been successfully shifted. */ if( yypParser->yyerrcnt<=0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_syntax_error(yypParser,yymajor, yyminor); } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif } yymajor = YYNOCODE; #endif } - }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); #ifndef NDEBUG if( yyTraceFILE ){ - int i; + yyStackEntry *i; + char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ', - yyTokenName[yypParser->yystack[i].major]); + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); + cDiv = ' '; + } fprintf(yyTraceFILE,"]\n"); } #endif @@ -130894,12 +140694,92 @@ SQLITE_PRIVATE void sqlite3Parser( /* #include "sqliteInt.h" */ /* #include */ +/* Character classes for tokenizing +** +** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented +** using a lookup table, whereas a switch() directly on c uses a binary search. +** The lookup table is much faster. To maximize speed, and to ensure that +** a lookup table is used, all of the classes need to be small integers and +** all of them need to be used within the switch. +*/ +#define CC_X 0 /* The letter 'x', or start of BLOB literal */ +#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */ +#define CC_ID 2 /* unicode characters usable in IDs */ +#define CC_DIGIT 3 /* Digits */ +#define CC_DOLLAR 4 /* '$' */ +#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ +#define CC_VARNUM 6 /* '?'. Numeric SQL variables */ +#define CC_SPACE 7 /* Space characters */ +#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ +#define CC_QUOTE2 9 /* '['. [...] style quoted ids */ +#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */ +#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */ +#define CC_LT 12 /* '<'. Part of < or <= or <> */ +#define CC_GT 13 /* '>'. Part of > or >= */ +#define CC_EQ 14 /* '='. Part of = or == */ +#define CC_BANG 15 /* '!'. Part of != */ +#define CC_SLASH 16 /* '/'. / or c-style comment */ +#define CC_LP 17 /* '(' */ +#define CC_RP 18 /* ')' */ +#define CC_SEMI 19 /* ';' */ +#define CC_PLUS 20 /* '+' */ +#define CC_STAR 21 /* '*' */ +#define CC_PERCENT 22 /* '%' */ +#define CC_COMMA 23 /* ',' */ +#define CC_AND 24 /* '&' */ +#define CC_TILDA 25 /* '~' */ +#define CC_DOT 26 /* '.' */ +#define CC_ILLEGAL 27 /* Illegal character */ + +static const unsigned char aiClass[] = { +#ifdef SQLITE_ASCII +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ +/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, +/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, +/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, +/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1, +/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27, +/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +#endif +#ifdef SQLITE_EBCDIC +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ +/* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27, +/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10, +/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27, +/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6, +/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8, +/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, +/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27, +/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, +/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27, +#endif +}; + /* -** The charMap() macro maps alphabetic characters into their +** The charMap() macro maps alphabetic characters (only) into their ** lower-case ASCII equivalent. On ASCII machines, this is just ** an upper-to-lower case map. On EBCDIC machines we also need -** to adjust the encoding. Only alphabetic characters and underscores -** need to be translated. +** to adjust the encoding. The mapping is only valid for alphabetics +** which are the only characters for which this feature is used. +** +** Used by keywordhash.h */ #ifdef SQLITE_ASCII # define charMap(X) sqlite3UpperToLower[(unsigned char)X] @@ -130933,7 +140813,7 @@ const unsigned char ebcdicToAscii[] = { ** returned. If the input is not a keyword, TK_ID is returned. ** ** The implementation of this routine was generated by a program, -** mkkeywordhash.h, located in the tool subdirectory of the distribution. +** mkkeywordhash.c, located in the tool subdirectory of the distribution. ** The output of the mkkeywordhash.c program is written into a file ** named keywordhash.h and then included into this source file by ** the #include below. @@ -130954,258 +140834,278 @@ const unsigned char ebcdicToAscii[] = { ** on platforms with limited memory. */ /* Hash score: 182 */ +/* zKWText[] encodes 834 bytes of keyword text in 554 bytes */ +/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ +/* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ +/* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ +/* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ +/* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ +/* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ +/* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ +/* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ +/* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ +/* VACUUMVIEWINITIALLY */ +static const char zKWText[553] = { + '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','E','C','U','R','S','I','V','E', + 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','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','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','W','H', + 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','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','R','I','M','A', + 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', + 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', + 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', + 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', + 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', + 'V','I','E','W','I','N','I','T','I','A','L','L','Y', +}; +/* aKWHash[i] is the hash value for the i-th keyword */ +static const unsigned char aKWHash[127] = { + 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, + 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, + 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, + 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, + 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, + 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, + 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, + 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, + 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, + 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, +}; +/* 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[124] = { + 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, 0, 0, 30, 0, 58, 0, 38, + 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, + 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, + 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, + 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, + 73, 83, 0, 35, 68, 0, 0, +}; +/* aKWLen[i] is the length (in bytes) of the i-th keyword */ +static const unsigned char aKWLen[124] = { + 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, 9, 7, 7, 3, 2, 4, 4, + 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, + 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, + 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, + 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, + 3, 5, 5, 6, 4, 9, 3, +}; +/* aKWOffset[i] is the index into zKWText[] of the start of +** the text for the i-th keyword. */ +static const unsigned short int aKWOffset[124] = { + 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, 234, 240, 240, 240, 243, 246, + 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, + 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, + 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, + 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, + 521, 524, 529, 534, 540, 544, 549, +}; +/* aKWCode[i] is the parser symbol code for the i-th keyword */ +static const unsigned char aKWCode[124] = { + 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_RECURSIVE, TK_BETWEEN, + TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, + TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, + TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, + TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, + TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, + TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, 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_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, + TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, + TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, + TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, + TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, +}; +/* 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 +** return the integer n (the length of the token). */ static int keywordCode(const char *z, int n, int *pType){ - /* zText[] encodes 834 bytes of keywords in 554 bytes */ - /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ - /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ - /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ - /* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ - /* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ - /* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ - /* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ - /* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ - /* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ - /* VACUUMVIEWINITIALLY */ - static const char zText[553] = { - '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','E','C','U','R','S','I','V','E', - 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','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','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','W','H', - 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','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','R','I','M','A', - 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', - 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', - 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', - 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', - 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', - 'V','I','E','W','I','N','I','T','I','A','L','L','Y', - }; - static const unsigned char aHash[127] = { - 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, - 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, - 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, - 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, - 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, - 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, - 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, - 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, - 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, - 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, - }; - static const unsigned char aNext[124] = { - 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, 0, 0, 30, 0, 58, 0, 38, - 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, - 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, - 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, - 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, - 73, 83, 0, 35, 68, 0, 0, - }; - static const unsigned char aLen[124] = { - 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, 9, 7, 7, 3, 2, 4, 4, - 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, - 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, - 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, - 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, - 3, 5, 5, 6, 4, 9, 3, - }; - static const unsigned short int aOffset[124] = { - 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, 234, 240, 240, 240, 243, 246, - 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, - 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, - 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, - 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, - 521, 524, 529, 534, 540, 544, 549, - }; - static const unsigned char aCode[124] = { - 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_RECURSIVE, TK_BETWEEN, - TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, - TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, - TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, - TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, - TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, - TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, 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_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, - TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, - TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, - TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, - TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, - }; - int h, i; + int i, j; + const char *zKW; if( n>=2 ){ - h = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127; - for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){ - if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){ - testcase( i==0 ); /* REINDEX */ - testcase( i==1 ); /* INDEXED */ - testcase( i==2 ); /* INDEX */ - testcase( i==3 ); /* DESC */ - testcase( i==4 ); /* ESCAPE */ - testcase( i==5 ); /* EACH */ - testcase( i==6 ); /* CHECK */ - testcase( i==7 ); /* KEY */ - testcase( i==8 ); /* BEFORE */ - testcase( i==9 ); /* FOREIGN */ - testcase( i==10 ); /* FOR */ - testcase( i==11 ); /* IGNORE */ - testcase( i==12 ); /* REGEXP */ - testcase( i==13 ); /* EXPLAIN */ - testcase( i==14 ); /* INSTEAD */ - testcase( i==15 ); /* ADD */ - testcase( i==16 ); /* DATABASE */ - testcase( i==17 ); /* AS */ - testcase( i==18 ); /* SELECT */ - testcase( i==19 ); /* TABLE */ - testcase( i==20 ); /* LEFT */ - testcase( i==21 ); /* THEN */ - 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 ); /* RECURSIVE */ - testcase( i==59 ); /* BETWEEN */ - testcase( i==60 ); /* NOTNULL */ - testcase( i==61 ); /* NOT */ - testcase( i==62 ); /* NO */ - testcase( i==63 ); /* NULL */ - testcase( i==64 ); /* LIKE */ - testcase( i==65 ); /* CASCADE */ - testcase( i==66 ); /* ASC */ - testcase( i==67 ); /* DELETE */ - testcase( i==68 ); /* CASE */ - testcase( i==69 ); /* COLLATE */ - testcase( i==70 ); /* CREATE */ - testcase( i==71 ); /* CURRENT_DATE */ - testcase( i==72 ); /* DETACH */ - testcase( i==73 ); /* IMMEDIATE */ - testcase( i==74 ); /* JOIN */ - testcase( i==75 ); /* INSERT */ - testcase( i==76 ); /* MATCH */ - testcase( i==77 ); /* PLAN */ - testcase( i==78 ); /* ANALYZE */ - testcase( i==79 ); /* PRAGMA */ - testcase( i==80 ); /* ABORT */ - testcase( i==81 ); /* VALUES */ - testcase( i==82 ); /* VIRTUAL */ - testcase( i==83 ); /* LIMIT */ - testcase( i==84 ); /* WHEN */ - testcase( i==85 ); /* WHERE */ - testcase( i==86 ); /* RENAME */ - testcase( i==87 ); /* AFTER */ - testcase( i==88 ); /* REPLACE */ - testcase( i==89 ); /* AND */ - testcase( i==90 ); /* DEFAULT */ - testcase( i==91 ); /* AUTOINCREMENT */ - testcase( i==92 ); /* TO */ - testcase( i==93 ); /* IN */ - testcase( i==94 ); /* CAST */ - testcase( i==95 ); /* COLUMN */ - testcase( i==96 ); /* COMMIT */ - testcase( i==97 ); /* CONFLICT */ - testcase( i==98 ); /* CROSS */ - testcase( i==99 ); /* CURRENT_TIMESTAMP */ - testcase( i==100 ); /* CURRENT_TIME */ - testcase( i==101 ); /* PRIMARY */ - testcase( i==102 ); /* DEFERRED */ - testcase( i==103 ); /* DISTINCT */ - testcase( i==104 ); /* IS */ - testcase( i==105 ); /* DROP */ - testcase( i==106 ); /* FAIL */ - testcase( i==107 ); /* FROM */ - testcase( i==108 ); /* FULL */ - testcase( i==109 ); /* GLOB */ - testcase( i==110 ); /* BY */ - testcase( i==111 ); /* IF */ - testcase( i==112 ); /* ISNULL */ - testcase( i==113 ); /* ORDER */ - testcase( i==114 ); /* RESTRICT */ - testcase( i==115 ); /* RIGHT */ - testcase( i==116 ); /* ROLLBACK */ - testcase( i==117 ); /* ROW */ - testcase( i==118 ); /* UNION */ - testcase( i==119 ); /* USING */ - testcase( i==120 ); /* VACUUM */ - testcase( i==121 ); /* VIEW */ - testcase( i==122 ); /* INITIALLY */ - testcase( i==123 ); /* ALL */ - *pType = aCode[i]; - break; - } + i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127; + for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){ + if( aKWLen[i]!=n ) continue; + j = 0; + zKW = &zKWText[aKWOffset[i]]; +#ifdef SQLITE_ASCII + while( j': { + case CC_GT: { if( (c=z[1])=='=' ){ *tokenType = TK_GE; return 2; @@ -131356,16 +141258,16 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ return 1; } } - case '!': { + case CC_BANG: { if( z[1]!='=' ){ *tokenType = TK_ILLEGAL; - return 2; + return 1; }else{ *tokenType = TK_NE; return 2; } } - case '|': { + case CC_PIPE: { if( z[1]!='|' ){ *tokenType = TK_BITOR; return 1; @@ -131374,21 +141276,19 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ return 2; } } - case ',': { + case CC_COMMA: { *tokenType = TK_COMMA; return 1; } - case '&': { + case CC_AND: { *tokenType = TK_BITAND; return 1; } - case '~': { + case CC_TILDA: { *tokenType = TK_BITNOT; return 1; } - case '`': - case '\'': - case '"': { + case CC_QUOTE: { int delim = z[0]; testcase( delim=='`' ); testcase( delim=='\'' ); @@ -131413,7 +141313,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ return i; } } - case '.': { + case CC_DOT: { #ifndef SQLITE_OMIT_FLOATING_POINT if( !sqlite3Isdigit(z[1]) ) #endif @@ -131424,8 +141324,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { + case CC_DIGIT: { testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); @@ -131460,22 +141359,18 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ } return i; } - case '[': { + case CC_QUOTE2: { for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} *tokenType = c==']' ? TK_ID : TK_ILLEGAL; return i; } - case '?': { + case CC_VARNUM: { *tokenType = TK_VARIABLE; for(i=1; sqlite3Isdigit(z[i]); i++){} return i; } -#ifndef SQLITE_OMIT_TCL_VARIABLE - case '$': -#endif - case '@': /* For compatibility with MS SQL Server */ - case '#': - case ':': { + case CC_DOLLAR: + case CC_VARALPHA: { int n = 0; testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' ); testcase( z[0]=='#' ); @@ -131504,8 +141399,20 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ if( n==0 ) *tokenType = TK_ILLEGAL; return i; } + case CC_KYWD: { + for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} + if( IdChar(z[i]) ){ + /* This token started out using characters that can appear in keywords, + ** but z[i] is a character not allowed within keywords, so this must + ** be an identifier instead */ + i++; + break; + } + *tokenType = TK_ID; + return keywordCode((char*)z, i, tokenType); + } + case CC_X: { #ifndef SQLITE_OMIT_BLOB_LITERAL - case 'x': case 'X': { testcase( z[0]=='x' ); testcase( z[0]=='X' ); if( z[1]=='\'' ){ *tokenType = TK_BLOB; @@ -131517,20 +141424,22 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ if( z[i] ) i++; return i; } - /* Otherwise fall through to the next case */ - } #endif + /* If it is not a BLOB literal, then it must be an ID, since no + ** SQL keywords start with the letter 'x'. Fall through */ + } + case CC_ID: { + i = 1; + break; + } default: { - if( !IdChar(*z) ){ - break; - } - for(i=1; IdChar(z[i]); i++){} - *tokenType = TK_ID; - return keywordCode((char*)z, i, tokenType); + *tokenType = TK_ILLEGAL; + return 1; } } - *tokenType = TK_ILLEGAL; - return 1; + while( IdChar(z[i]) ){ i++; } + *tokenType = TK_ID; + return i; } /* @@ -131542,13 +141451,15 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ */ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ int nErr = 0; /* Number of errors encountered */ - int i; /* Loop counter */ void *pEngine; /* The LEMON-generated LALR(1) parser */ + int n = 0; /* Length of the next token token */ int tokenType; /* type of the next token */ int lastTokenParsed = -1; /* type of the previous token */ - u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */ sqlite3 *db = pParse->db; /* The database connection */ int mxSqlLen; /* Max length of an SQL string */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ +#endif assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -131557,60 +141468,64 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr } pParse->rc = SQLITE_OK; pParse->zTail = zSql; - i = 0; assert( pzErrMsg!=0 ); /* sqlite3ParserTrace(stdout, "parser: "); */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + pEngine = &sEngine; + sqlite3ParserInit(pEngine); +#else pEngine = sqlite3ParserAlloc(sqlite3Malloc); if( pEngine==0 ){ - db->mallocFailed = 1; - return SQLITE_NOMEM; + sqlite3OomFault(db); + return SQLITE_NOMEM_BKPT; } +#endif assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); - assert( pParse->nzVar==0 ); - assert( pParse->azVar==0 ); - enableLookaside = db->lookaside.bEnabled; - if( db->lookaside.pStart ) db->lookaside.bEnabled = 1; - while( zSql[i]!=0 ){ - assert( i>=0 ); - pParse->sLastToken.z = &zSql[i]; - pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType); - i += pParse->sLastToken.n; - if( i>mxSqlLen ){ - pParse->rc = SQLITE_TOOBIG; - break; + assert( pParse->pVList==0 ); + while( 1 ){ + if( zSql[0]!=0 ){ + n = sqlite3GetToken((u8*)zSql, &tokenType); + mxSqlLen -= n; + if( mxSqlLen<0 ){ + pParse->rc = SQLITE_TOOBIG; + break; + } + }else{ + /* Upon reaching the end of input, call the parser two more times + ** with tokens TK_SEMI and 0, in that order. */ + if( lastTokenParsed==TK_SEMI ){ + tokenType = 0; + }else if( lastTokenParsed==0 ){ + break; + }else{ + tokenType = TK_SEMI; + } + zSql -= n; } if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); if( db->u1.isInterrupted ){ - sqlite3ErrorMsg(pParse, "interrupt"); pParse->rc = SQLITE_INTERRUPT; break; } if( tokenType==TK_ILLEGAL ){ - sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", - &pParse->sLastToken); + sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql); break; } + zSql += n; }else{ - if( tokenType==TK_SEMI ) pParse->zTail = &zSql[i]; + pParse->sLastToken.z = zSql; + pParse->sLastToken.n = n; sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); lastTokenParsed = tokenType; + zSql += n; if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } } assert( nErr==0 ); - if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ - assert( zSql[i]==0 ); - if( lastTokenParsed!=TK_SEMI ){ - sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); - pParse->zTail = &zSql[i]; - } - if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ - sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); - } - } + pParse->zTail = zSql; #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, @@ -131618,10 +141533,13 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr ); sqlite3_mutex_leave(sqlite3MallocMutex()); #endif /* YYDEBUG */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + sqlite3ParserFinalize(pEngine); +#else sqlite3ParserFree(pEngine, sqlite3_free); - db->lookaside.bEnabled = enableLookaside; +#endif if( db->mallocFailed ){ - pParse->rc = SQLITE_NOMEM; + pParse->rc = SQLITE_NOMEM_BKPT; } if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); @@ -131656,14 +141574,13 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr sqlite3DeleteTable(db, pParse->pNewTable); } - sqlite3WithDelete(db, pParse->pWithToFree); + if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); sqlite3DeleteTrigger(db, pParse->pNewTrigger); - for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]); - sqlite3DbFree(db, pParse->azVar); + sqlite3DbFree(db, pParse->pVList); while( pParse->pAinc ){ AutoincInfo *p = pParse->pAinc; pParse->pAinc = p->pNext; - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } while( pParse->pZombieTab ){ Table *p = pParse->pZombieTab; @@ -131779,7 +141696,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; ** to recognize the end of a trigger can be omitted. All we have to do ** is look for a semicolon that is not part of an string or comment. */ -SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){ +SQLITE_API int sqlite3_complete(const char *zSql){ u8 state = 0; /* Current state, using numbers defined in header comment */ u8 token; /* Value of the next token */ @@ -131944,7 +141861,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){ ** above, except that the parameter is required to be UTF-16 encoded, not ** UTF-8. */ -SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){ +SQLITE_API int sqlite3_complete16(const void *zSql){ sqlite3_value *pVal; char const *zSql8; int rc; @@ -131959,7 +141876,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){ if( zSql8 ){ rc = sqlite3_complete(zSql8); }else{ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } sqlite3ValueFree(pVal); return rc & 0xff; @@ -132090,6 +142007,9 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); #ifdef SQLITE_ENABLE_JSON1 SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*); #endif +#ifdef SQLITE_ENABLE_STMTVTAB +SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*); +#endif #ifdef SQLITE_ENABLE_FTS5 SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); #endif @@ -132104,24 +142024,26 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; /* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns ** a pointer to the to the sqlite3_version[] string constant. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void){ return sqlite3_version; } +SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } -/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a +/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a ** pointer to a string constant whose value is the same as the -** SQLITE_SOURCE_ID C preprocessor macro. +** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using +** an edited copy of the amalgamation, then the last four characters of +** the hash might be different from SQLITE_SOURCE_ID. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */ /* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function ** returns an integer equal to SQLITE_VERSION_NUMBER. */ -SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } +SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } /* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns ** zero if and only if SQLite was compiled with mutexing code omitted due to ** the SQLITE_THREADSAFE compile-time option being set to 0. */ -SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } +SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } /* ** When compiling the test fixture or with debugging enabled (on Win32), @@ -132194,7 +142116,7 @@ SQLITE_API char *sqlite3_data_directory = 0; ** * Recursive calls to this routine from thread X return immediately ** without blocking. */ -SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){ +SQLITE_API int sqlite3_initialize(void){ MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ int rc; /* Result code */ #ifdef SQLITE_EXTRA_INIT @@ -132249,7 +142171,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){ sqlite3GlobalConfig.pInitMutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } } } @@ -132280,7 +142202,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){ */ sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex); if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ - FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); sqlite3GlobalConfig.inProgress = 1; #ifdef SQLITE_ENABLE_SQLLOG { @@ -132288,8 +142209,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){ sqlite3_init_sqllog(); } #endif - memset(pHash, 0, sizeof(sqlite3GlobalFunctions)); - sqlite3RegisterGlobalFunctions(); + memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions)); + sqlite3RegisterBuiltinFunctions(); if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } @@ -132361,7 +142282,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){ ** on when SQLite is already shut down. If SQLite is already shut down ** when this routine is invoked, then this routine is a harmless no-op. */ -SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){ +SQLITE_API int sqlite3_shutdown(void){ #ifdef SQLITE_OMIT_WSD int rc = sqlite3_wsd_init(4096, 24); if( rc!=SQLITE_OK ){ @@ -132415,7 +142336,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){ ** threadsafe. Failure to heed these warnings can lead to unpredictable ** behavior. */ -SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){ +SQLITE_API int sqlite3_config(int op, ...){ va_list ap; int rc = SQLITE_OK; @@ -132496,14 +142417,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){ sqlite3GlobalConfig.bMemstat = va_arg(ap, int); break; } - case SQLITE_CONFIG_SCRATCH: { - /* EVIDENCE-OF: R-08404-60887 There are three arguments to - ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from - ** which the scratch allocations will be drawn, the size of each scratch - ** allocation (sz), and the maximum number of scratch allocations (N). */ - sqlite3GlobalConfig.pScratch = va_arg(ap, void*); - sqlite3GlobalConfig.szScratch = va_arg(ap, int); - sqlite3GlobalConfig.nScratch = va_arg(ap, int); + case SQLITE_CONFIG_SMALL_MALLOC: { + sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int); break; } case SQLITE_CONFIG_PAGECACHE: { @@ -132696,6 +142611,11 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){ break; } + case SQLITE_CONFIG_STMTJRNL_SPILL: { + sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int); + break; + } + default: { rc = SQLITE_ERROR; break; @@ -132719,7 +142639,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ #ifndef SQLITE_OMIT_LOOKASIDE void *pStart; - if( db->lookaside.nOut ){ + + if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; } /* Free any existing lookaside buffer for this handle before @@ -132747,26 +142668,29 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ pStart = pBuf; } db->lookaside.pStart = pStart; + db->lookaside.pInit = 0; db->lookaside.pFree = 0; db->lookaside.sz = (u16)sz; if( pStart ){ int i; LookasideSlot *p; assert( sz > (int)sizeof(LookasideSlot*) ); + db->lookaside.nSlot = cnt; p = (LookasideSlot*)pStart; for(i=cnt-1; i>=0; i--){ - p->pNext = db->lookaside.pFree; - db->lookaside.pFree = p; + p->pNext = db->lookaside.pInit; + db->lookaside.pInit = p; p = (LookasideSlot*)&((u8*)p)[sz]; } db->lookaside.pEnd = p; - db->lookaside.bEnabled = 1; + db->lookaside.bDisable = 0; db->lookaside.bMalloced = pBuf==0 ?1:0; }else{ db->lookaside.pStart = db; db->lookaside.pEnd = db; - db->lookaside.bEnabled = 0; + db->lookaside.bDisable = 1; db->lookaside.bMalloced = 0; + db->lookaside.nSlot = 0; } #endif /* SQLITE_OMIT_LOOKASIDE */ return SQLITE_OK; @@ -132775,7 +142699,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ /* ** Return the mutex associated with a database connection. */ -SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){ +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -132789,7 +142713,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){ ** Free up as much memory as we can from the given database ** connection. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){ +SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){ int i; #ifdef SQLITE_ENABLE_API_ARMOR @@ -132813,7 +142737,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){ ** Flush any dirty pages in the pager-cache for any attached database ** to disk. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3 *db){ +SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ int i; int rc = SQLITE_OK; int bSeenBusy = 0; @@ -132842,11 +142766,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3 *db){ /* ** Configuration settings for an individual database connection */ -SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){ +SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; va_start(ap, op); switch( op ){ + case SQLITE_DBCONFIG_MAINDBNAME: { + /* IMP: R-06824-28531 */ + /* IMP: R-36257-52125 */ + db->aDb[0].zDbSName = va_arg(ap,char*); + rc = SQLITE_OK; + break; + } case SQLITE_DBCONFIG_LOOKASIDE: { void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ @@ -132859,8 +142790,12 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){ int op; /* The opcode */ u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ } aFlagOp[] = { - { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, - { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, + { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, + { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, + { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, + { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, + { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, + { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -132868,7 +142803,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){ if( aFlagOp[i].op==op ){ int onoff = va_arg(ap, int); int *pRes = va_arg(ap, int*); - int oldFlags = db->flags; + u32 oldFlags = db->flags; if( onoff>0 ){ db->flags |= aFlagOp[i].mask; }else if( onoff==0 ){ @@ -132917,6 +142852,7 @@ static int binCollFunc( /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares ** strings byte by byte using the memcmp() function from the standard C ** library. */ + assert( pKey1 && pKey2 ); rc = memcmp(pKey1, pKey2, n); if( rc==0 ){ if( padFlag @@ -132961,7 +142897,7 @@ static int nocaseCollatingFunc( /* ** Return the ROWID of the most recent insert */ -SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){ +SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -132971,10 +142907,25 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){ return db->lastRowid; } +/* +** Set the value returned by the sqlite3_last_insert_rowid() API function. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + sqlite3_mutex_enter(db->mutex); + db->lastRowid = iRowid; + sqlite3_mutex_leave(db->mutex); +} + /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){ +SQLITE_API int sqlite3_changes(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -132987,7 +142938,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){ /* ** Return the number of changes since the database handle was opened. */ -SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3 *db){ +SQLITE_API int sqlite3_total_changes(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -133020,7 +142971,7 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){ ** with SQLITE_ANY as the encoding. */ static void functionDestroy(sqlite3 *db, FuncDef *p){ - FuncDestructor *pDestructor = p->pDestructor; + FuncDestructor *pDestructor = p->u.pDestructor; if( pDestructor ){ pDestructor->nRef--; if( pDestructor->nRef==0 ){ @@ -133089,6 +143040,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); + if( db->mTrace & SQLITE_TRACE_CLOSE ){ + db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); + } /* Force xDisconnect calls on all virtual tables */ disconnectAllVtab(db); @@ -133135,8 +143089,8 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ ** unclosed resources, and arranges for deallocation when the last ** prepare statement or sqlite3_backup closes. */ -SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } -SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } +SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } +SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } /* @@ -133202,18 +143156,17 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ */ sqlite3ConnectionClosed(db); - for(j=0; jaFunc.a); j++){ - FuncDef *pNext, *pHash, *p; - for(p=db->aFunc.a[j]; p; p=pHash){ - pHash = p->pHash; - while( p ){ - functionDestroy(db, p); - pNext = p->pNext; - sqlite3DbFree(db, p); - p = pNext; - } - } + for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ + FuncDef *pNext, *p; + p = sqliteHashData(i); + do{ + functionDestroy(db, p); + pNext = p->pNext; + sqlite3DbFree(db, p); + p = pNext; + }while( p ); } + sqlite3HashClear(&db->aFunc); for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ CollSeq *pColl = (CollSeq *)sqliteHashData(i); /* Invoke any destructors registered for collation sequence user data. */ @@ -133257,7 +143210,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3_mutex_leave(db->mutex); db->magic = SQLITE_MAGIC_CLOSED; sqlite3_mutex_free(db->mutex); - assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */ + assert( sqlite3LookasideUsed(db,0)==0 ); if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } @@ -133285,7 +143238,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** the database rollback and schema reset, which can cause false ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); - schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; + schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0; for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; @@ -133299,7 +143252,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); - if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ + if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); } @@ -133432,10 +143385,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ static const char* const aMsg[] = { /* SQLITE_OK */ "not an error", - /* SQLITE_ERROR */ "SQL logic error or missing database", + /* SQLITE_ERROR */ "SQL logic error", /* SQLITE_INTERNAL */ 0, /* SQLITE_PERM */ "access permission denied", - /* SQLITE_ABORT */ "callback requested query abort", + /* SQLITE_ABORT */ "query aborted", /* SQLITE_BUSY */ "database is locked", /* SQLITE_LOCKED */ "database table is locked", /* SQLITE_NOMEM */ "out of memory", @@ -133447,17 +143400,21 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ /* SQLITE_FULL */ "database or disk is full", /* SQLITE_CANTOPEN */ "unable to open database file", /* SQLITE_PROTOCOL */ "locking protocol", - /* SQLITE_EMPTY */ "table contains no data", + /* SQLITE_EMPTY */ 0, /* SQLITE_SCHEMA */ "database schema has changed", /* SQLITE_TOOBIG */ "string or blob too big", /* SQLITE_CONSTRAINT */ "constraint failed", /* SQLITE_MISMATCH */ "datatype mismatch", - /* SQLITE_MISUSE */ "library routine called out of sequence", + /* SQLITE_MISUSE */ "bad parameter or other API misuse", +#ifdef SQLITE_DISABLE_LFS /* SQLITE_NOLFS */ "large file support is disabled", +#else + /* SQLITE_NOLFS */ 0, +#endif /* SQLITE_AUTH */ "authorization denied", - /* SQLITE_FORMAT */ "auxiliary database format error", - /* SQLITE_RANGE */ "bind or column index out of range", - /* SQLITE_NOTADB */ "file is encrypted or is not a database", + /* SQLITE_FORMAT */ 0, + /* SQLITE_RANGE */ "column index out of range", + /* SQLITE_NOTADB */ "file is not a database", }; const char *zErr = "unknown error"; switch( rc ){ @@ -133544,7 +143501,7 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){ ** This routine sets the busy callback for an Sqlite database to the ** given callback function with the given argument. */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler( +SQLITE_API int sqlite3_busy_handler( sqlite3 *db, int (*xBusy)(void*,int), void *pArg @@ -133567,7 +143524,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler( ** given callback function with the given argument. The progress callback will ** be invoked every nOps opcodes. */ -SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler( +SQLITE_API void sqlite3_progress_handler( sqlite3 *db, int nOps, int (*xProgress)(void*), @@ -133598,7 +143555,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler( ** This routine installs a default busy handler that waits for the ** specified number of milliseconds before returning 0. */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){ +SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif @@ -133614,9 +143571,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){ /* ** Cause any pending operation to stop at its earliest opportunity. */ -SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3 *db){ +SQLITE_API void sqlite3_interrupt(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ + if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return; } @@ -133637,7 +143594,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc( int nArg, int enc, void *pUserData, - void (*xFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), FuncDestructor *pDestructor @@ -133648,9 +143605,9 @@ SQLITE_PRIVATE int sqlite3CreateFunc( assert( sqlite3_mutex_held(db->mutex) ); if( zFunctionName==0 || - (xFunc && (xFinal || xStep)) || - (!xFunc && (xFinal && !xStep)) || - (!xFunc && (!xFinal && xStep)) || + (xSFunc && (xFinal || xStep)) || + (!xSFunc && (xFinal && !xStep)) || + (!xSFunc && (!xFinal && xStep)) || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || (255<(nName = sqlite3Strlen30( zFunctionName))) ){ return SQLITE_MISUSE_BKPT; @@ -133673,10 +143630,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc( }else if( enc==SQLITE_ANY ){ int rc; rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags, - pUserData, xFunc, xStep, xFinal, pDestructor); + pUserData, xSFunc, xStep, xFinal, pDestructor); if( rc==SQLITE_OK ){ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags, - pUserData, xFunc, xStep, xFinal, pDestructor); + pUserData, xSFunc, xStep, xFinal, pDestructor); } if( rc!=SQLITE_OK ){ return rc; @@ -133692,7 +143649,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc( ** is being overridden/deleted but there are no active VMs, allow the ** operation to continue but invalidate all precompiled statements. */ - p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0); + p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0); if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, @@ -133704,10 +143661,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc( } } - p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1); + p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); assert(p || db->mallocFailed); if( !p ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } /* If an older version of the function with a configured destructor is @@ -133717,11 +143674,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc( if( pDestructor ){ pDestructor->nRef++; } - p->pDestructor = pDestructor; + p->u.pDestructor = pDestructor; p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; testcase( p->funcFlags & SQLITE_DETERMINISTIC ); - p->xFunc = xFunc; - p->xStep = xStep; + p->xSFunc = xSFunc ? xSFunc : xStep; p->xFinalize = xFinal; p->pUserData = pUserData; p->nArg = (u16)nArg; @@ -133731,27 +143687,27 @@ SQLITE_PRIVATE int sqlite3CreateFunc( /* ** Create new user functions. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_function( +SQLITE_API int sqlite3_create_function( sqlite3 *db, const char *zFunc, int nArg, int enc, void *p, - void (*xFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*) ){ - return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep, + return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, 0); } -SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( +SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunc, int nArg, int enc, void *p, - void (*xFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), void (*xDestroy)(void *) @@ -133774,7 +143730,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( pArg->xDestroy = xDestroy; pArg->pUserData = p; } - rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg); + rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg); if( pArg && pArg->nRef==0 ){ assert( rc!=SQLITE_OK ); xDestroy(p); @@ -133788,13 +143744,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( } #ifndef SQLITE_OMIT_UTF16 -SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( +SQLITE_API int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, int eTextRep, void *p, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ){ @@ -133807,7 +143763,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); - rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0); + rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0); sqlite3DbFree(db, zFunc8); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -133828,12 +143784,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( ** A global function must exist in order for name resolution to work ** properly. */ -SQLITE_API int SQLITE_STDCALL sqlite3_overload_function( +SQLITE_API int sqlite3_overload_function( sqlite3 *db, const char *zName, int nArg ){ - int nName = sqlite3Strlen30(zName); int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_API_ARMOR @@ -133842,7 +143797,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function( } #endif sqlite3_mutex_enter(db->mutex); - if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){ + if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){ rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, 0, sqlite3InvalidFunction, 0, 0, 0); } @@ -133860,7 +143815,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function( ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR @@ -133871,11 +143827,38 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*, #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; - db->xTrace = xTrace; + db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; + db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } +#endif /* SQLITE_OMIT_DEPRECATED */ + +/* Register a trace callback using the version-2 interface. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3 *db, /* Trace this connection */ + unsigned mTrace, /* Mask of events to be traced */ + int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ + void *pArg /* Context */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( mTrace==0 ) xTrace = 0; + if( xTrace==0 ) mTrace = 0; + db->mTrace = mTrace; + db->xTrace = xTrace; + db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_DEPRECATED /* ** Register a profile function. The pArg from the previously registered ** profile function is returned. @@ -133884,7 +143867,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*, ** profile is a pointer to a function that is invoked at the conclusion of ** each SQL statement that is run. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_profile( +SQLITE_API void *sqlite3_profile( sqlite3 *db, void (*xProfile)(void*,const char*,sqlite_uint64), void *pArg @@ -133904,6 +143887,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile( sqlite3_mutex_leave(db->mutex); return pOld; } +#endif /* SQLITE_OMIT_DEPRECATED */ #endif /* SQLITE_OMIT_TRACE */ /* @@ -133911,7 +143895,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile( ** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook( +SQLITE_API void *sqlite3_commit_hook( sqlite3 *db, /* Attach the hook to this database */ int (*xCallback)(void*), /* Function to invoke on each commit */ void *pArg /* Argument to the function */ @@ -133936,7 +143920,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook( ** Register a callback to be invoked each time a row is updated, ** inserted or deleted using this database connection. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( +SQLITE_API void *sqlite3_update_hook( sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), void *pArg /* Argument to the function */ @@ -133961,7 +143945,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( ** Register a callback to be invoked each time a transaction is rolled ** back by this database connection. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook( +SQLITE_API void *sqlite3_rollback_hook( sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*), /* Callback function */ void *pArg /* Argument to the function */ @@ -133982,6 +143966,27 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook( return pRet; } +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Register a callback to be invoked each time a row is updated, +** inserted or deleted using this database connection. +*/ +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, /* Attach the hook to this database */ + void(*xCallback)( /* Callback function */ + void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64), + void *pArg /* First callback argument */ +){ + void *pRet; + sqlite3_mutex_enter(db->mutex); + pRet = db->pPreUpdateArg; + db->xPreUpdateCallback = xCallback; + db->pPreUpdateArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). @@ -134015,7 +144020,7 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook( ** using sqlite3_wal_hook() disables the automatic checkpoint mechanism ** configured by this function. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ #ifdef SQLITE_OMIT_WAL UNUSED_PARAMETER(db); UNUSED_PARAMETER(nFrame); @@ -134036,7 +144041,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame ** Register a callback to be invoked each time a transaction is written ** into the write-ahead-log by this database connection. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook( +SQLITE_API void *sqlite3_wal_hook( sqlite3 *db, /* Attach the hook to this db handle */ int(*xCallback)(void *, sqlite3*, const char*, int), void *pArg /* First argument passed to xCallback() */ @@ -134063,7 +144068,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook( /* ** Checkpoint database zDb. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( +SQLITE_API int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of attached database (or NULL) */ int eMode, /* SQLITE_CHECKPOINT_* value */ @@ -134107,6 +144112,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( sqlite3Error(db, rc); } rc = sqlite3ApiExit(db, rc); + + /* If there are no active statements, clear the interrupt flag at this + ** point. */ + if( db->nVdbeActive==0 ){ + db->u1.isInterrupted = 0; + } + sqlite3_mutex_leave(db->mutex); return rc; #endif @@ -134118,7 +144130,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( ** to contains a zero-length string, all attached databases are ** checkpointed. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */ return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0); @@ -134142,7 +144154,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD ** checkpointed. If an error is encountered it is returned immediately - ** no attempt is made to checkpoint any remaining databases. ** -** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART +** or TRUNCATE. */ SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; /* Return code */ @@ -134209,17 +144222,17 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){ ** Return UTF-8 encoded English language explanation of the most recent ** error. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){ +SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ const char *z; if( !db ){ - return sqlite3ErrStr(SQLITE_NOMEM); + return sqlite3ErrStr(SQLITE_NOMEM_BKPT); } if( !sqlite3SafetyCheckSickOrOk(db) ){ return sqlite3ErrStr(SQLITE_MISUSE_BKPT); } sqlite3_mutex_enter(db->mutex); if( db->mallocFailed ){ - z = sqlite3ErrStr(SQLITE_NOMEM); + z = sqlite3ErrStr(SQLITE_NOMEM_BKPT); }else{ testcase( db->pErr==0 ); z = (char*)sqlite3_value_text(db->pErr); @@ -134237,17 +144250,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){ ** Return UTF-16 encoded English language explanation of the most recent ** error. */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){ +SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ static const u16 outOfMem[] = { 'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0 }; static const u16 misuse[] = { - 'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ', - 'r', 'o', 'u', 't', 'i', 'n', 'e', ' ', - 'c', 'a', 'l', 'l', 'e', 'd', ' ', - 'o', 'u', 't', ' ', - 'o', 'f', ' ', - 's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0 + 'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ', + 'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ', + 'm', 'i', 's', 'u', 's', 'e', 0 }; const void *z; @@ -134271,7 +144281,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){ ** be cleared before returning. Do this directly, instead of via ** sqlite3ApiExit(), to avoid setting the database handle error message. */ - db->mallocFailed = 0; + sqlite3OomClear(db); } sqlite3_mutex_leave(db->mutex); return z; @@ -134282,31 +144292,34 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){ ** Return the most recent error code generated by an SQLite routine. If NULL is ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ -SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){ +SQLITE_API int sqlite3_errcode(sqlite3 *db){ if( db && !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } if( !db || db->mallocFailed ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } return db->errCode & db->errMask; } -SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){ +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ if( db && !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } if( !db || db->mallocFailed ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; } return db->errCode; } +SQLITE_API int sqlite3_system_errno(sqlite3 *db){ + return db ? db->iSysErrno : 0; +} /* ** Return a string that describes the kind of error specified in the ** argument. For now, this simply calls the internal sqlite3ErrStr() ** function. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int rc){ +SQLITE_API const char *sqlite3_errstr(int rc){ return sqlite3ErrStr(rc); } @@ -134376,7 +144389,7 @@ static int createCollation( } pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1); - if( pColl==0 ) return SQLITE_NOMEM; + if( pColl==0 ) return SQLITE_NOMEM_BKPT; pColl->xCmp = xCompare; pColl->pUser = pCtx; pColl->xDel = xDel; @@ -134424,8 +144437,8 @@ static const int aHardLimit[] = { #if SQLITE_MAX_VDBE_OP<40 # error SQLITE_MAX_VDBE_OP must be at least 40 #endif -#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000 -# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000 +#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127 +# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127 #endif #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 # error SQLITE_MAX_ATTACHED must be between 0 and 125 @@ -134454,7 +144467,7 @@ static const int aHardLimit[] = { ** It merely prevents new constructs that exceed the limit ** from forming. */ -SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ +SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ int oldLimit; #ifdef SQLITE_ENABLE_API_ARMOR @@ -134555,7 +144568,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( for(iIn=0; iIn=0 && octet<256 ); if( octet==0 ){ +#ifndef SQLITE_ENABLE_URI_00_ERROR /* This branch is taken when "%00" appears within the URI. In this ** case we ignore all text in the remainder of the path, name or ** value currently being parsed. So ignore the current character @@ -134618,6 +144632,12 @@ SQLITE_PRIVATE int sqlite3ParseUri( iIn++; } continue; +#else + /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */ + *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri"); + rc = SQLITE_ERROR; + goto parse_uri_out; +#endif } c = octet; }else if( eState==1 && (c=='&' || c=='=') ){ @@ -134721,8 +144741,10 @@ SQLITE_PRIVATE int sqlite3ParseUri( }else{ zFile = sqlite3_malloc64(nUri+2); - if( !zFile ) return SQLITE_NOMEM; - memcpy(zFile, zUri, nUri); + if( !zFile ) return SQLITE_NOMEM_BKPT; + if( nUri ){ + memcpy(zFile, zUri, nUri); + } zFile[nUri] = '\0'; zFile[nUri+1] = '\0'; flags &= ~SQLITE_OPEN_URI; @@ -134770,26 +144792,6 @@ static int openDatabase( if( rc ) return rc; #endif - /* Only allow sensible combinations of bits in the flags argument. - ** Throw an error if any non-sense combination is used. If we - ** do not block illegal combinations here, it could trigger - ** assert() statements in deeper layers. Sensible combinations - ** are: - ** - ** 1: SQLITE_OPEN_READONLY - ** 2: SQLITE_OPEN_READWRITE - ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE - */ - assert( SQLITE_OPEN_READONLY == 0x01 ); - assert( SQLITE_OPEN_READWRITE == 0x02 ); - assert( SQLITE_OPEN_CREATE == 0x04 ); - testcase( (1<<(flags&7))==0x02 ); /* READONLY */ - testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ - testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ - if( ((1<<(flags&7)) & 0x46)==0 ){ - return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ - } - if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_NOMUTEX ){ @@ -134877,6 +144879,12 @@ static int openDatabase( #endif #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) | SQLITE_CellSizeCk +#endif +#if defined(SQLITE_ENABLE_FTS3_TOKENIZER) + | SQLITE_Fts3Tokenizer +#endif +#if defined(SQLITE_ENABLE_QPSG) + | SQLITE_EnableQPSG #endif ; sqlite3HashInit(&db->aCollSeq); @@ -134905,11 +144913,32 @@ static int openDatabase( db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0); assert( db->pDfltColl!=0 ); - /* Parse the filename/URI argument. */ + /* Parse the filename/URI argument + ** + ** Only allow sensible combinations of bits in the flags argument. + ** Throw an error if any non-sense combination is used. If we + ** do not block illegal combinations here, it could trigger + ** assert() statements in deeper layers. Sensible combinations + ** are: + ** + ** 1: SQLITE_OPEN_READONLY + ** 2: SQLITE_OPEN_READWRITE + ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE + */ db->openFlags = flags; - rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + assert( SQLITE_OPEN_READONLY == 0x01 ); + assert( SQLITE_OPEN_READWRITE == 0x02 ); + assert( SQLITE_OPEN_CREATE == 0x04 ); + testcase( (1<<(flags&7))==0x02 ); /* READONLY */ + testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ + testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ + if( ((1<<(flags&7)) & 0x46)==0 ){ + rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ + }else{ + rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + } if( rc!=SQLITE_OK ){ - if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); sqlite3_free(zErrMsg); goto opendb_out; @@ -134920,7 +144949,7 @@ static int openDatabase( flags | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ if( rc==SQLITE_IOERR_NOMEM ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM_BKPT; } sqlite3Error(db, rc); goto opendb_out; @@ -134931,13 +144960,13 @@ static int openDatabase( sqlite3BtreeLeave(db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); - /* The default safety_level for the main database is 'full'; for the temp - ** database it is 'NONE'. This matches the pager layer defaults. + /* The default safety_level for the main database is FULL; for the temp + ** database it is OFF. This matches the pager layer defaults. */ - db->aDb[0].zName = "main"; - db->aDb[0].safety_level = 3; - db->aDb[1].zName = "temp"; - db->aDb[1].safety_level = 1; + db->aDb[0].zDbSName = "main"; + db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + db->aDb[1].zDbSName = "temp"; + db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; db->magic = SQLITE_MAGIC_OPEN; if( db->mallocFailed ){ @@ -134949,12 +144978,21 @@ static int openDatabase( ** is accessed. */ sqlite3Error(db, SQLITE_OK); - sqlite3RegisterBuiltinFunctions(db); + sqlite3RegisterPerConnectionBuiltinFunctions(db); + rc = sqlite3_errcode(db); + +#ifdef SQLITE_ENABLE_FTS5 + /* Register any built-in FTS5 module before loading the automatic + ** extensions. This allows automatic extensions to register FTS5 + ** tokenizers and auxiliary functions. */ + if( !db->mallocFailed && rc==SQLITE_OK ){ + rc = sqlite3Fts5Init(db); + } +#endif /* Load automatic extensions - extensions that have been registered ** using the sqlite3_automatic_extension() API. */ - rc = sqlite3_errcode(db); if( rc==SQLITE_OK ){ sqlite3AutoLoadExtensions(db); rc = sqlite3_errcode(db); @@ -134983,12 +145021,6 @@ static int openDatabase( } #endif -#ifdef SQLITE_ENABLE_FTS5 - if( !db->mallocFailed && rc==SQLITE_OK ){ - rc = sqlite3Fts5Init(db); - } -#endif - #ifdef SQLITE_ENABLE_ICU if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3IcuInit(db); @@ -135001,6 +145033,12 @@ static int openDatabase( } #endif +#ifdef SQLITE_ENABLE_DBPAGE_VTAB + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3DbpageRegister(db); + } +#endif + #ifdef SQLITE_ENABLE_DBSTAT_VTAB if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3DbstatRegister(db); @@ -135013,6 +145051,12 @@ static int openDatabase( } #endif +#ifdef SQLITE_ENABLE_STMTVTAB + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3StmtVtabInit(db); + } +#endif + /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. @@ -135055,16 +145099,18 @@ opendb_out: #endif #if defined(SQLITE_HAS_CODEC) if( rc==SQLITE_OK ){ - const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey"); - if( zHexKey && zHexKey[0] ){ + const char *zKey; + if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){ u8 iByte; int i; - char zKey[40]; - for(i=0, iByte=0; izType; + zDataType = sqlite3ColumnType(pCol,0); zCollSeq = pCol->zColl; notnull = pCol->notNull!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; @@ -135434,7 +145491,7 @@ error_out: /* ** Sleep for a little while. Return the amount of time slept. */ -SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){ +SQLITE_API int sqlite3_sleep(int ms){ sqlite3_vfs *pVfs; int rc; pVfs = sqlite3_vfs_find(0); @@ -135450,7 +145507,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){ /* ** Enable or disable the extended result codes. */ -SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int onoff){ +SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif @@ -135463,7 +145520,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int ono /* ** Invoke the xFileControl method on a particular database. */ -SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ +SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ int rc = SQLITE_ERROR; Btree *pBtree; @@ -135503,9 +145560,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN /* ** Interface to the testing logic. */ -SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ +SQLITE_API int sqlite3_test_control(int op, ...){ int rc = 0; -#ifdef SQLITE_OMIT_BUILTIN_TEST +#ifdef SQLITE_UNTESTABLE UNUSED_PARAMETER(op); #else va_list ap; @@ -135629,7 +145686,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ */ case SQLITE_TESTCTRL_ASSERT: { volatile int x = 0; - assert( (x = va_arg(ap,int))!=0 ); + assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); rc = x; break; } @@ -135641,7 +145698,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ ** This action provides a run-time test to see how the ALWAYS and ** NEVER macros were defined at compile-time. ** - ** The return value is ALWAYS(X). + ** The return value is ALWAYS(X) if X is true, or 0 if X is false. ** ** The recommended test is X==2. If the return value is 2, that means ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the @@ -135664,7 +145721,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ */ case SQLITE_TESTCTRL_ALWAYS: { int x = va_arg(ap,int); - rc = ALWAYS(x); + rc = x ? ALWAYS(x) : 0; break; } @@ -135731,22 +145788,6 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ } #endif - /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree); - ** - ** Pass pFree into sqlite3ScratchFree(). - ** If sz>0 then allocate a scratch buffer into pNew. - */ - case SQLITE_TESTCTRL_SCRATCHMALLOC: { - void *pFree, **ppNew; - int sz; - sz = va_arg(ap, int); - ppNew = va_arg(ap, void**); - pFree = va_arg(ap, void*); - if( sz ) *ppNew = sqlite3ScratchMalloc(sz); - sqlite3ScratchFree(pFree); - break; - } - /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); ** ** If parameter onoff is non-zero, configure the wrappers so that all @@ -135771,6 +145812,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ break; } + /* Set the threshold at which OP_Once counters reset back to zero. + ** By default this is 0x7ffffffe (over 2 billion), but that value is + ** too big to test in a reasonable amount of time, so this control is + ** provided to set a small and easily reachable reset value. + */ + case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: { + sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int); + break; + } /* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr); ** @@ -135833,7 +145883,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ } } va_end(ap); -#endif /* SQLITE_OMIT_BUILTIN_TEST */ +#endif /* SQLITE_UNTESTABLE */ return rc; } @@ -135848,7 +145898,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){ ** parameter if it exists. If the parameter does not exist, this routine ** returns a NULL pointer. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam){ +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ if( zFilename==0 || zParam==0 ) return 0; zFilename += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] ){ @@ -135863,7 +145913,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilenam /* ** Return a boolean value for a query parameter. */ -SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ +SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ const char *z = sqlite3_uri_parameter(zFilename, zParam); bDflt = bDflt!=0; return z ? sqlite3GetBoolean(z, bDflt) : bDflt; @@ -135872,14 +145922,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const c /* ** Return a 64-bit integer value for a query parameter. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64( +SQLITE_API sqlite3_int64 sqlite3_uri_int64( const char *zFilename, /* Filename as passed to xOpen */ const char *zParam, /* URI parameter sought */ sqlite3_int64 bDflt /* return if parameter is missing */ ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; - if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ + if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; @@ -135889,22 +145939,15 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64( ** Return the Btree pointer identified by zDbName. Return NULL if not found. */ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ - int i; - for(i=0; inDb; i++){ - if( db->aDb[i].pBt - && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0) - ){ - return db->aDb[i].pBt; - } - } - return 0; + int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; + return iDb<0 ? 0 : db->aDb[iDb].pBt; } /* ** Return the filename of the database associated with a database ** connection. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName){ +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ Btree *pBt; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ @@ -135920,7 +145963,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha ** Return 1 if database is read-only or 0 if read/write. Return -1 if ** no such database exists. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ Btree *pBt; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ @@ -135937,14 +145980,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa ** Obtain a snapshot handle for the snapshot of database zDb currently ** being read by handle db. */ -SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get( +SQLITE_API int sqlite3_snapshot_get( sqlite3 *db, const char *zDb, sqlite3_snapshot **ppSnapshot ){ int rc = SQLITE_ERROR; #ifndef SQLITE_OMIT_WAL - int iDb; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ @@ -135953,13 +145995,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get( #endif sqlite3_mutex_enter(db->mutex); - iDb = sqlite3FindDbName(db, zDb); - if( iDb==0 || iDb>1 ){ - Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); + if( db->autoCommit==0 ){ + int iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( 0==sqlite3BtreeIsInTrans(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); + } } } } @@ -135972,7 +146016,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get( /* ** Open a read-transaction on the snapshot idendified by pSnapshot. */ -SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_open( +SQLITE_API int sqlite3_snapshot_open( sqlite3 *db, const char *zDb, sqlite3_snapshot *pSnapshot @@ -136006,14 +146050,98 @@ SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_open( return rc; } +/* +** Recover as many snapshots as possible from the wal file associated with +** schema zDb of database db. +*/ +SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ + int rc = SQLITE_ERROR; + int iDb; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + + sqlite3_mutex_enter(db->mutex); + iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); + sqlite3BtreeCommit(pBt); + } + } + } + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + /* ** Free a snapshot handle obtained from sqlite3_snapshot_get(). */ -SQLITE_API void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ +SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ sqlite3_free(pSnapshot); } #endif /* SQLITE_ENABLE_SNAPSHOT */ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +/* +** Given the name of a compile-time option, return true if that option +** was used and false if not. +** +** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix +** is not required for a match. +*/ +SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ + int i, n; + int nOpt; + const char **azCompileOpt; + +#if SQLITE_ENABLE_API_ARMOR + if( zOptName==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + azCompileOpt = sqlite3CompileOptions(&nOpt); + + if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; + n = sqlite3Strlen30(zOptName); + + /* Since nOpt is normally in single digits, a linear search is + ** adequate. No need for a binary search. */ + for(i=0; i=0 && N=0 ); return 5; } @@ -137741,6 +147880,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ assert( p->pSegments==0 ); /* Free any prepared statements held */ + sqlite3_finalize(p->pSeekStmt); for(i=0; iaStmt); i++){ sqlite3_finalize(p->aStmt[i]); } @@ -138466,65 +148606,66 @@ static int fts3InitVtab( break; } } - if( iOpt==SizeofArray(aFts4Opt) ){ - sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); - rc = SQLITE_ERROR; - }else{ - switch( iOpt ){ - case 0: /* MATCHINFO */ - if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ - sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); - rc = SQLITE_ERROR; - } - bNoDocsize = 1; - break; + switch( iOpt ){ + case 0: /* MATCHINFO */ + if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); + rc = SQLITE_ERROR; + } + bNoDocsize = 1; + break; - case 1: /* PREFIX */ - sqlite3_free(zPrefix); - zPrefix = zVal; - zVal = 0; - break; + case 1: /* PREFIX */ + sqlite3_free(zPrefix); + zPrefix = zVal; + zVal = 0; + break; - case 2: /* COMPRESS */ - sqlite3_free(zCompress); - zCompress = zVal; - zVal = 0; - break; + case 2: /* COMPRESS */ + sqlite3_free(zCompress); + zCompress = zVal; + zVal = 0; + break; - case 3: /* UNCOMPRESS */ - sqlite3_free(zUncompress); - zUncompress = zVal; - zVal = 0; - break; + case 3: /* UNCOMPRESS */ + sqlite3_free(zUncompress); + zUncompress = zVal; + zVal = 0; + break; - case 4: /* ORDER */ - if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) - && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) - ){ - sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); - rc = SQLITE_ERROR; - } - bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); - break; + case 4: /* ORDER */ + if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) + && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) + ){ + sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); + rc = SQLITE_ERROR; + } + bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); + break; - case 5: /* CONTENT */ - sqlite3_free(zContent); - zContent = zVal; - zVal = 0; - break; + case 5: /* CONTENT */ + sqlite3_free(zContent); + zContent = zVal; + zVal = 0; + break; - case 6: /* LANGUAGEID */ - assert( iOpt==6 ); - sqlite3_free(zLanguageid); - zLanguageid = zVal; - zVal = 0; - break; + case 6: /* LANGUAGEID */ + assert( iOpt==6 ); + sqlite3_free(zLanguageid); + zLanguageid = zVal; + zVal = 0; + break; - case 7: /* NOTINDEXED */ - azNotindexed[nNotindexed++] = zVal; - zVal = 0; - break; - } + case 7: /* NOTINDEXED */ + azNotindexed[nNotindexed++] = zVal; + zVal = 0; + break; + + default: + assert( iOpt==SizeofArray(aFts4Opt) ); + sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); + rc = SQLITE_ERROR; + break; } sqlite3_free(zVal); } @@ -138612,9 +148753,9 @@ static int fts3InitVtab( p->pTokenizer = pTokenizer; p->nMaxPendingData = FTS3_MAX_PENDING_DATA; p->bHasDocsize = (isFts4 && bNoDocsize==0); - p->bHasStat = isFts4; - p->bFts4 = isFts4; - p->bDescIdx = bDescIdx; + p->bHasStat = (u8)isFts4; + p->bFts4 = (u8)isFts4; + p->bDescIdx = (u8)bDescIdx; p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ p->zContentTbl = zContent; p->zLanguageid = zLanguageid; @@ -138645,7 +148786,9 @@ static int fts3InitVtab( char *z; int n = 0; z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n); - memcpy(zCsr, z, n); + if( n>0 ){ + memcpy(zCsr, z, n); + } zCsr[n] = '\0'; sqlite3Fts3Dequote(zCsr); p->azColumn[iCol] = zCsr; @@ -138929,6 +149072,39 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ return SQLITE_OK; } +/* +** Finalize the statement handle at pCsr->pStmt. +** +** Or, if that statement handle is one created by fts3CursorSeekStmt(), +** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement +** pointer there instead of finalizing it. +*/ +static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){ + if( pCsr->bSeekStmt ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + if( p->pSeekStmt==0 ){ + p->pSeekStmt = pCsr->pStmt; + sqlite3_reset(pCsr->pStmt); + pCsr->pStmt = 0; + } + pCsr->bSeekStmt = 0; + } + sqlite3_finalize(pCsr->pStmt); +} + +/* +** Free all resources currently held by the cursor passed as the only +** argument. +*/ +static void fts3ClearCursor(Fts3Cursor *pCsr){ + fts3CursorFinalizeStmt(pCsr); + sqlite3Fts3FreeDeferredTokens(pCsr); + sqlite3_free(pCsr->aDoclist); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + sqlite3Fts3ExprFree(pCsr->pExpr); + memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); +} + /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. @@ -138936,11 +149112,7 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); - sqlite3_finalize(pCsr->pStmt); - sqlite3Fts3ExprFree(pCsr->pExpr); - sqlite3Fts3FreeDeferredTokens(pCsr); - sqlite3_free(pCsr->aDoclist); - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + fts3ClearCursor(pCsr); assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); sqlite3_free(pCsr); return SQLITE_OK; @@ -138954,20 +149126,23 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ ** ** (or the equivalent for a content=xxx table) and set pCsr->pStmt to ** it. If an error occurs, return an SQLite error code. -** -** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK. */ -static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){ +static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ int rc = SQLITE_OK; if( pCsr->pStmt==0 ){ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; char *zSql; - zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); - if( !zSql ) return SQLITE_NOMEM; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); - sqlite3_free(zSql); + if( p->pSeekStmt ){ + pCsr->pStmt = p->pSeekStmt; + p->pSeekStmt = 0; + }else{ + zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); + if( !zSql ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0); + sqlite3_free(zSql); + } + if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; } - *ppStmt = pCsr->pStmt; return rc; } @@ -138979,9 +149154,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ int rc = SQLITE_OK; if( pCsr->isRequireSeek ){ - sqlite3_stmt *pStmt = 0; - - rc = fts3CursorSeekStmt(pCsr, &pStmt); + rc = fts3CursorSeekStmt(pCsr); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); pCsr->isRequireSeek = 0; @@ -139070,7 +149243,8 @@ static int fts3ScanInteriorNode( isFirstTerm = 0; zCsr += fts3GetVarint32(zCsr, &nSuffix); - if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){ + assert( nPrefix>=0 && nSuffix>=0 ); + if( &zCsr[nSuffix]>zEnd ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } @@ -139880,7 +150054,7 @@ SQLITE_PRIVATE int sqlite3Fts3FirstFilter( fts3ColumnlistCopy(0, &p); } - while( ppStmt); - sqlite3_free(pCsr->aDoclist); - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); - sqlite3Fts3ExprFree(pCsr->pExpr); - memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); + fts3ClearCursor(pCsr); /* Set the lower and upper bounds on docids to return */ pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); @@ -140501,13 +150671,13 @@ static int fts3FilterMethod( ); } if( zSql ){ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0); sqlite3_free(zSql); }else{ rc = SQLITE_NOMEM; } }else if( eSearch==FTS3_DOCID_SEARCH ){ - rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt); + rc = fts3CursorSeekStmt(pCsr); if( rc==SQLITE_OK ){ rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons); } @@ -140522,7 +150692,12 @@ static int fts3FilterMethod( ** routine to find out if it has reached the end of a result set. */ static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){ - return ((Fts3Cursor *)pCursor)->isEof; + Fts3Cursor *pCsr = (Fts3Cursor*)pCursor; + if( pCsr->isEof ){ + fts3ClearCursor(pCsr); + pCsr->isEof = 1; + } + return pCsr->isEof; } /* @@ -140560,33 +150735,37 @@ static int fts3ColumnMethod( /* The column value supplied by SQLite must be in range. */ assert( iCol>=0 && iCol<=p->nColumn+2 ); - if( iCol==p->nColumn+1 ){ - /* This call is a request for the "docid" column. Since "docid" is an - ** alias for "rowid", use the xRowid() method to obtain the value. - */ - sqlite3_result_int64(pCtx, pCsr->iPrevId); - }else if( iCol==p->nColumn ){ - /* The extra column whose name is the same as the table. - ** Return a blob which is a pointer to the cursor. */ - sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT); - }else if( iCol==p->nColumn+2 && pCsr->pExpr ){ - sqlite3_result_int64(pCtx, pCsr->iLangid); - }else{ - /* The requested column is either a user column (one that contains - ** indexed data), or the language-id column. */ - rc = fts3CursorSeek(0, pCsr); + switch( iCol-p->nColumn ){ + case 0: + /* The special 'table-name' column */ + sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0); + break; - if( rc==SQLITE_OK ){ - if( iCol==p->nColumn+2 ){ - int iLangid = 0; - if( p->zLanguageid ){ - iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1); - } - sqlite3_result_int(pCtx, iLangid); - }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){ + case 1: + /* The docid column */ + sqlite3_result_int64(pCtx, pCsr->iPrevId); + break; + + case 2: + if( pCsr->pExpr ){ + sqlite3_result_int64(pCtx, pCsr->iLangid); + break; + }else if( p->zLanguageid==0 ){ + sqlite3_result_int(pCtx, 0); + break; + }else{ + iCol = p->nColumn; + /* fall-through */ + } + + default: + /* A user column. Or, if this is a full-table scan, possibly the + ** language-id column. Seek the cursor. */ + rc = fts3CursorSeek(0, pCsr); + if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } - } + break; } assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); @@ -140635,8 +150814,10 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */ Fts3Table *p = (Fts3Table*)pVtab; - int rc = sqlite3Fts3PendingTermsFlush(p); + int rc; + i64 iLastRowid = sqlite3_last_insert_rowid(p->db); + rc = sqlite3Fts3PendingTermsFlush(p); if( rc==SQLITE_OK && p->nLeafAdd>(nMinMerge/16) && p->nAutoincrmerge && p->nAutoincrmerge!=0xff @@ -140651,6 +150832,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); } sqlite3Fts3SegmentsClose(p); + sqlite3_set_last_insert_rowid(p->db, iLastRowid); return rc; } @@ -140663,17 +150845,11 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){ static int fts3SetHasStat(Fts3Table *p){ int rc = SQLITE_OK; if( p->bHasStat==2 ){ - const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'"; - char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName); - if( zSql ){ - sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - if( rc==SQLITE_OK ){ - int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW); - rc = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) p->bHasStat = bHasStat; - } - sqlite3_free(zSql); + char *zTbl = sqlite3_mprintf("%s_stat", p->zName); + if( zTbl ){ + int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0); + sqlite3_free(zTbl); + p->bHasStat = (res==SQLITE_OK); }else{ rc = SQLITE_NOMEM; } @@ -140780,18 +150956,17 @@ static int fts3FunctionArg( sqlite3_value *pVal, /* argv[0] passed to function */ Fts3Cursor **ppCsr /* OUT: Store cursor handle here */ ){ - Fts3Cursor *pRet; - if( sqlite3_value_type(pVal)!=SQLITE_BLOB - || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *) - ){ + int rc; + *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor"); + if( (*ppCsr)!=0 ){ + rc = SQLITE_OK; + }else{ char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); sqlite3_result_error(pContext, zErr, -1); sqlite3_free(zErr); - return SQLITE_ERROR; + rc = SQLITE_ERROR; } - memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *)); - *ppCsr = pRet; - return SQLITE_OK; + return rc; } /* @@ -141178,7 +151353,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ #endif /* Create the virtual table wrapper around the hash-table and overload - ** the two scalar functions. If this is successful, register the + ** the four scalar functions. If this is successful, register the ** module with sqlite. */ if( SQLITE_OK==rc @@ -141761,7 +151936,7 @@ static int fts3EvalIncrPhraseNext( ** one incremental token. In which case the bIncr flag is set. */ assert( p->bIncr==1 ); - if( p->nToken==1 && p->bIncr ){ + if( p->nToken==1 ){ rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, &pDL->iDocid, &pDL->pList, &pDL->nList ); @@ -141994,6 +152169,7 @@ static void fts3EvalTokenCosts( ** the number of overflow pages consumed by a record B bytes in size. */ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ + int rc = SQLITE_OK; if( pCsr->nRowAvg==0 ){ /* The average document size, which is required to calculate the cost ** of each doclist, has not yet been determined. Read the required @@ -142006,7 +152182,6 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ ** data stored in all rows of each column of the table, from left ** to right. */ - int rc; Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; sqlite3_stmt *pStmt; sqlite3_int64 nDoc = 0; @@ -142033,11 +152208,10 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz); assert( pCsr->nRowAvg>0 ); rc = sqlite3_reset(pStmt); - if( rc!=SQLITE_OK ) return rc; } *pnPage = pCsr->nRowAvg; - return SQLITE_OK; + return rc; } /* @@ -142387,7 +152561,8 @@ static void fts3EvalNextRow( pExpr->iDocid = pLeft->iDocid; pExpr->bEof = (pLeft->bEof || pRight->bEof); if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){ - if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){ + assert( pRight->eType==FTSQUERY_PHRASE ); + if( pRight->pPhrase->doclist.aAll ){ Fts3Doclist *pDl = &pRight->pPhrase->doclist; while( *pRc==SQLITE_OK && pRight->bEof==0 ){ memset(pDl->pList, 0, pDl->nList); @@ -142416,7 +152591,7 @@ static void fts3EvalNextRow( if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ fts3EvalNextRow(pCsr, pLeft, pRc); - }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){ + }else if( pLeft->bEof || iCmp>0 ){ fts3EvalNextRow(pCsr, pRight, pRc); }else{ fts3EvalNextRow(pCsr, pLeft, pRc); @@ -142508,7 +152683,6 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ */ if( *pRc==SQLITE_OK && pExpr->eType==FTSQUERY_NEAR - && pExpr->bEof==0 && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) ){ Fts3Expr *p; @@ -142517,42 +152691,39 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ /* Allocate temporary working space. */ for(p=pExpr; p->pLeft; p=p->pLeft){ + assert( p->pRight->pPhrase->doclist.nList>0 ); nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; - if( nTmp==0 ){ + aTmp = sqlite3_malloc(nTmp*2); + if( !aTmp ){ + *pRc = SQLITE_NOMEM; res = 0; }else{ - aTmp = sqlite3_malloc(nTmp*2); - if( !aTmp ){ - *pRc = SQLITE_NOMEM; - res = 0; - }else{ - char *aPoslist = p->pPhrase->doclist.pList; - int nToken = p->pPhrase->nToken; + char *aPoslist = p->pPhrase->doclist.pList; + int nToken = p->pPhrase->nToken; - for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ - Fts3Phrase *pPhrase = p->pRight->pPhrase; - int nNear = p->nNear; - res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); - } - - aPoslist = pExpr->pRight->pPhrase->doclist.pList; - nToken = pExpr->pRight->pPhrase->nToken; - for(p=pExpr->pLeft; p && res; p=p->pLeft){ - int nNear; - Fts3Phrase *pPhrase; - assert( p->pParent && p->pParent->pLeft==p ); - nNear = p->pParent->nNear; - pPhrase = ( - p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase - ); - res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); - } + for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ + Fts3Phrase *pPhrase = p->pRight->pPhrase; + int nNear = p->nNear; + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); } - sqlite3_free(aTmp); + aPoslist = pExpr->pRight->pPhrase->doclist.pList; + nToken = pExpr->pRight->pPhrase->nToken; + for(p=pExpr->pLeft; p && res; p=p->pLeft){ + int nNear; + Fts3Phrase *pPhrase; + assert( p->pParent && p->pParent->pLeft==p ); + nNear = p->pParent->nNear; + pPhrase = ( + p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase + ); + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } } + + sqlite3_free(aTmp); } return res; @@ -143160,7 +153331,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ #ifdef _WIN32 __declspec(dllexport) #endif -SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init( +SQLITE_API int sqlite3_fts3_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -146121,6 +156292,18 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule( /* #include */ /* #include */ +/* +** Return true if the two-argument version of fts3_tokenizer() +** has been activated via a prior call to sqlite3_db_config(db, +** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0); +*/ +static int fts3TokenizerEnabled(sqlite3_context *context){ + sqlite3 *db = sqlite3_context_db_handle(context); + int isEnabled = 0; + sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled); + return isEnabled; +} + /* ** Implementation of the SQL scalar function for accessing the underlying ** hash table. This function may be called as follows: @@ -146141,7 +156324,7 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule( ** is a blob containing the pointer stored as the hash data corresponding ** to string (after the hash-table is updated, if applicable). */ -static void scalarFunc( +static void fts3TokenizerFunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -146159,16 +156342,20 @@ static void scalarFunc( nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ - void *pOld; - int n = sqlite3_value_bytes(argv[1]); - if( zName==0 || n!=sizeof(pPtr) ){ - sqlite3_result_error(context, "argument type mismatch", -1); - return; - } - pPtr = *(void **)sqlite3_value_blob(argv[1]); - pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); - if( pOld==pPtr ){ - sqlite3_result_error(context, "out of memory", -1); + if( fts3TokenizerEnabled(context) ){ + void *pOld; + int n = sqlite3_value_bytes(argv[1]); + if( zName==0 || n!=sizeof(pPtr) ){ + sqlite3_result_error(context, "argument type mismatch", -1); + return; + } + pPtr = *(void **)sqlite3_value_blob(argv[1]); + pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); + if( pOld==pPtr ){ + sqlite3_result_error(context, "out of memory", -1); + } + }else{ + sqlite3_result_error(context, "fts3tokenize disabled", -1); return; } }else{ @@ -146182,7 +156369,6 @@ static void scalarFunc( return; } } - sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); } @@ -146301,7 +156487,11 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( #ifdef SQLITE_TEST -#include +#if defined(INCLUDE_SQLITE_TCL_H) +# include "sqlite_tcl.h" +#else +# include "tcl.h" +#endif /* #include */ /* @@ -146442,6 +156632,7 @@ int registerTokenizer( return sqlite3_finalize(pStmt); } + static int queryTokenizer( sqlite3 *db, @@ -146512,11 +156703,13 @@ static void intTestFunc( assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); /* Test the storage function */ - rc = registerTokenizer(db, "nosuchtokenizer", p1); - assert( rc==SQLITE_OK ); - rc = queryTokenizer(db, "nosuchtokenizer", &p2); - assert( rc==SQLITE_OK ); - assert( p2==p1 ); + if( fts3TokenizerEnabled(context) ){ + rc = registerTokenizer(db, "nosuchtokenizer", p1); + assert( rc==SQLITE_OK ); + rc = queryTokenizer(db, "nosuchtokenizer", &p2); + assert( rc==SQLITE_OK ); + assert( p2==p1 ); + } sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); } @@ -146532,7 +156725,7 @@ static void intTestFunc( ** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); ** ** This function adds a scalar function (see header comment above -** scalarFunc() in this file for details) and, if ENABLE_TABLE is +** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is ** defined at compilation time, a temporary virtual table (see header ** comment above struct HashTableVtab) to the database schema. Both ** provide read/write access to the contents of *pHash. @@ -146561,10 +156754,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable( #endif if( SQLITE_OK==rc ){ - rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0); + rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0); } if( SQLITE_OK==rc ){ - rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0); + rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0); } #ifdef SQLITE_TEST if( SQLITE_OK==rc ){ @@ -147616,7 +157809,8 @@ static int fts3SqlStmt( ** of the oldest level in the db that contains at least ? segments. Or, ** if no level in the FTS index contains more than ? segments, the statement ** returns zero rows. */ -/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?" +/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " + " GROUP BY level HAVING cnt>=?" " ORDER BY (level %% 1024) ASC LIMIT 1", /* Estimate the upper limit on the number of leaf nodes in a new segment @@ -147689,7 +157883,8 @@ static int fts3SqlStmt( if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL); + rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT, + &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; @@ -150477,7 +160672,7 @@ static int fts3SegmentMerge( ** segment. The level of the new segment is equal to the numerically ** greatest segment level currently present in the database for this ** index. The idx of the new segment is always 0. */ - if( csr.nSegment==1 ){ + if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){ rc = SQLITE_DONE; goto finished; } @@ -152119,10 +162314,11 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ ** set nSeg to -1. */ rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0); - sqlite3_bind_int(pFindLevel, 1, nMin); + sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin)); if( sqlite3_step(pFindLevel)==SQLITE_ROW ){ iAbsLevel = sqlite3_column_int64(pFindLevel, 0); - nSeg = nMin; + nSeg = sqlite3_column_int(pFindLevel, 1); + assert( nSeg>=2 ); }else{ nSeg = -1; } @@ -152237,11 +162433,14 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ ** Convert the text beginning at *pz into an integer and return ** its value. Advance *pz to point to the first character past ** the integer. +** +** This function used for parameters to merge= and incrmerge= +** commands. */ static int fts3Getint(const char **pz){ const char *z = *pz; int i = 0; - while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0'; + while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0'; *pz = z; return i; } @@ -154807,16 +165006,16 @@ static int unicodeAddExceptions( ){ const unsigned char *z = (const unsigned char *)zIn; const unsigned char *zTerm = &z[nIn]; - int iCode; + unsigned int iCode; int nEntry = 0; assert( bAlnum==0 || bAlnum==1 ); while( zi; j--) aNew[j] = aNew[j-1]; - aNew[i] = iCode; + aNew[i] = (int)iCode; nNew++; } } @@ -154989,7 +165188,7 @@ static int unicodeNext( ){ unicode_cursor *pCsr = (unicode_cursor *)pC; unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); - int iCode = 0; + unsigned int iCode = 0; char *zOut; const unsigned char *z = &pCsr->aInput[pCsr->iOff]; const unsigned char *zStart = z; @@ -155001,7 +165200,7 @@ static int unicodeNext( ** the input. */ while( z=zTerm ) return SQLITE_DONE; @@ -155021,7 +165220,7 @@ static int unicodeNext( /* Write the folded case of the last character read to the output */ zEnd = z; - iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic); + iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic); if( iOut ){ WRITE_UTF8(zOut, iOut); } @@ -155029,8 +165228,8 @@ static int unicodeNext( /* If the cursor is not at EOF, read the next character */ if( z>=zTerm ) break; READ_UTF8(z, zTerm, iCode); - }while( unicodeIsAlnum(p, iCode) - || sqlite3FtsUnicodeIsdiacritic(iCode) + }while( unicodeIsAlnum(p, (int)iCode) + || sqlite3FtsUnicodeIsdiacritic((int)iCode) ); /* Set the output variables and return. */ @@ -155194,9 +165393,9 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, }; - if( c<128 ){ - return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); - }else if( c<(1<<22) ){ + if( (unsigned int)c<128 ){ + return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 ); + }else if( (unsigned int)c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; @@ -155389,16 +165588,17 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ int ret = c; - assert( c>=0 ); assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); if( c<128 ){ if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); }else if( c<65536 ){ + const struct TableEntry *p; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; int iLo = 0; int iRes = -1; + assert( c>aEntry[0].iCode ); while( iHi>=iLo ){ int iTest = (iHi + iLo) / 2; int cmp = (c - aEntry[iTest].iCode); @@ -155409,14 +165609,12 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ iHi = iTest-1; } } - assert( iRes<0 || c>=aEntry[iRes].iCode ); - if( iRes>=0 ){ - const struct TableEntry *p = &aEntry[iRes]; - if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ - ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; - assert( ret>0 ); - } + assert( iRes>=0 && c>=aEntry[iRes].iCode ); + p = &aEntry[iRes]; + if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ + ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; + assert( ret>0 ); } if( bRemoveDiacritic ) ret = remove_diacritic(ret); @@ -155503,6 +165701,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; @@ -155551,13 +165750,16 @@ struct Rtree { sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ + u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ + u8 inWrTrans; /* True if inside write transaction */ 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 */ - int nBusy; /* Current number of users of this structure */ + u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ + u32 nCursor; /* Number of open cursors */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - @@ -155567,8 +165769,10 @@ struct Rtree { RtreeNode *pDeleted; int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */ + /* Blob I/O on xxx_node */ + sqlite3_blob *pNodeBlob; + /* Statements to read/write/delete a record from xxx_node */ - sqlite3_stmt *pReadNode; sqlite3_stmt *pWriteNode; sqlite3_stmt *pDeleteNode; @@ -155768,14 +165972,6 @@ struct RtreeGeomCallback { void *pContext; }; - -/* -** Value for the first field of every RtreeMatchArg object. The MATCH -** operator tests that the first field of a blob operand matches this -** value to avoid operating on invalid blobs (which could cause a segfault). -*/ -#define RTREE_GEOMETRY_MAGIC 0x891245AB - /* ** An instance of this structure (in the form of a BLOB) is returned by ** the SQL functions that sqlite3_rtree_geometry_callback() and @@ -155783,7 +165979,7 @@ struct RtreeGeomCallback { ** operand to the MATCH operator of an R-Tree. */ struct RtreeMatchArg { - u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ + u32 iSize; /* Size of this object */ RtreeGeomCallback cb; /* Info about the callback functions */ int nParam; /* Number of parameters to the SQL function */ sqlite3_value **apSqlParam; /* Original SQL parameter values */ @@ -155797,6 +165993,58 @@ struct RtreeMatchArg { # define MIN(x,y) ((x) > (y) ? (y) : (x)) #endif +/* What version of GCC is being used. 0 means GCC is not being used . +** Note that the GCC_VERSION macro will also be set correctly when using +** clang, since clang works hard to be gcc compatible. So the gcc +** optimizations will also work when compiling with clang. +*/ +#ifndef GCC_VERSION +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) +#else +# define GCC_VERSION 0 +#endif +#endif + +/* The testcase() macro should already be defined in the amalgamation. If +** it is not, make it a no-op. +*/ +#ifndef SQLITE_AMALGAMATION +# define testcase(X) +#endif + +/* +** Macros to determine whether the machine is big or little endian, +** and whether or not that determination is run-time or compile-time. +** +** For best performance, an attempt is made to guess at the byte-order +** using C-preprocessor macros. If that is unsuccessful, or if +** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** 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__) +# define SQLITE_BYTEORDER 1234 +#elif defined(sparc) || defined(__ppc__) +# define SQLITE_BYTEORDER 4321 +#else +# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ +#endif +#endif + + +/* What version of MSVC is being used. 0 means MSVC is not being used */ +#ifndef MSVC_VERSION +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif +#endif + /* ** Functions to deserialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The deserialized value is returned. @@ -155805,24 +166053,47 @@ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + pCoord->u = _byteswap_ulong(*(u32*)p); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + pCoord->u = __builtin_bswap32(*(u32*)p); +#elif SQLITE_BYTEORDER==4321 + pCoord->u = *(u32*)p; +#else pCoord->u = ( (((u32)p[0]) << 24) + (((u32)p[1]) << 16) + (((u32)p[2]) << 8) + (((u32)p[3]) << 0) ); +#endif } static i64 readInt64(u8 *p){ - return ( - (((i64)p[0]) << 56) + - (((i64)p[1]) << 48) + - (((i64)p[2]) << 40) + - (((i64)p[3]) << 32) + - (((i64)p[4]) << 24) + - (((i64)p[5]) << 16) + - (((i64)p[6]) << 8) + - (((i64)p[7]) << 0) +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u64 x; + memcpy(&x, p, 8); + return (i64)_byteswap_uint64(x); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u64 x; + memcpy(&x, p, 8); + return (i64)__builtin_bswap64(x); +#elif SQLITE_BYTEORDER==4321 + i64 x; + memcpy(&x, p, 8); + return x; +#else + return (i64)( + (((u64)p[0]) << 56) + + (((u64)p[1]) << 48) + + (((u64)p[2]) << 40) + + (((u64)p[3]) << 32) + + (((u64)p[4]) << 24) + + (((u64)p[5]) << 16) + + (((u64)p[6]) << 8) + + (((u64)p[7]) << 0) ); +#endif } /* @@ -155830,23 +166101,43 @@ static i64 readInt64(u8 *p){ ** 64 bit integer. The value returned is the number of bytes written ** to the argument buffer (always 2, 4 and 8 respectively). */ -static int writeInt16(u8 *p, int i){ +static void writeInt16(u8 *p, int i){ p[0] = (i>> 8)&0xFF; p[1] = (i>> 0)&0xFF; - return 2; } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ assert( sizeof(RtreeCoord)==4 ); assert( sizeof(u32)==4 ); +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + i = __builtin_bswap32(pCoord->u); + memcpy(p, &i, 4); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + i = _byteswap_ulong(pCoord->u); + memcpy(p, &i, 4); +#elif SQLITE_BYTEORDER==4321 + i = pCoord->u; + memcpy(p, &i, 4); +#else i = pCoord->u; p[0] = (i>>24)&0xFF; p[1] = (i>>16)&0xFF; p[2] = (i>> 8)&0xFF; p[3] = (i>> 0)&0xFF; +#endif return 4; } static int writeInt64(u8 *p, i64 i){ +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + i = (i64)__builtin_bswap64((u64)i); + memcpy(p, &i, 8); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + i = (i64)_byteswap_uint64((u64)i); + memcpy(p, &i, 8); +#elif SQLITE_BYTEORDER==4321 + memcpy(p, &i, 8); +#else p[0] = (i>>56)&0xFF; p[1] = (i>>48)&0xFF; p[2] = (i>>40)&0xFF; @@ -155855,6 +166146,7 @@ static int writeInt64(u8 *p, i64 i){ p[5] = (i>>16)&0xFF; p[6] = (i>> 8)&0xFF; p[7] = (i>> 0)&0xFF; +#endif return 8; } @@ -155937,6 +166229,17 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ return pNode; } +/* +** Clear the Rtree.pNodeBlob object +*/ +static void nodeBlobReset(Rtree *pRtree){ + if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + sqlite3_blob_close(pBlob); + } +} + /* ** Obtain a reference to an r-tree node. */ @@ -155946,9 +166249,8 @@ static int nodeAcquire( RtreeNode *pParent, /* Either the parent node or NULL */ RtreeNode **ppNode /* OUT: Acquired node */ ){ - int rc; - int rc2 = SQLITE_OK; - RtreeNode *pNode; + int rc = SQLITE_OK; + RtreeNode *pNode = 0; /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. @@ -155964,28 +166266,45 @@ static int nodeAcquire( return SQLITE_OK; } - sqlite3_bind_int64(pRtree->pReadNode, 1, iNode); - rc = sqlite3_step(pRtree->pReadNode); - if( rc==SQLITE_ROW ){ - const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0); - if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){ - pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); - if( !pNode ){ - rc2 = SQLITE_NOMEM; - }else{ - pNode->pParent = pParent; - pNode->zData = (u8 *)&pNode[1]; - pNode->nRef = 1; - pNode->iNode = iNode; - pNode->isDirty = 0; - pNode->pNext = 0; - memcpy(pNode->zData, zBlob, pRtree->iNodeSize); - nodeReference(pParent); - } + if( pRtree->pNodeBlob ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + rc = sqlite3_blob_reopen(pBlob, iNode); + pRtree->pNodeBlob = pBlob; + if( rc ){ + nodeBlobReset(pRtree); + if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM; + } + } + if( pRtree->pNodeBlob==0 ){ + char *zTab = sqlite3_mprintf("%s_node", pRtree->zName); + if( zTab==0 ) return SQLITE_NOMEM; + rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0, + &pRtree->pNodeBlob); + sqlite3_free(zTab); + } + if( rc ){ + nodeBlobReset(pRtree); + *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; + }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ + pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); + if( !pNode ){ + rc = SQLITE_NOMEM; + }else{ + pNode->pParent = pParent; + pNode->zData = (u8 *)&pNode[1]; + pNode->nRef = 1; + pNode->iNode = iNode; + pNode->isDirty = 0; + pNode->pNext = 0; + rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, + pRtree->iNodeSize, 0); + nodeReference(pParent); } } - rc = sqlite3_reset(pRtree->pReadNode); - if( rc==SQLITE_OK ) rc = rc2; /* If the root node was just loaded, set pRtree->iDepth to the height ** of the r-tree structure. A height of zero means all data is stored on @@ -156037,7 +166356,7 @@ static void nodeOverwriteCell( int ii; u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; p += writeInt64(p, pCell->iRowid); - for(ii=0; ii<(pRtree->nDim*2); ii++){ + for(ii=0; iinDim2; ii++){ p += writeCoord(p, &pCell->aCoord[ii]); } pNode->isDirty = 1; @@ -156171,13 +166490,16 @@ static void nodeGetCell( ){ u8 *pData; RtreeCoord *pCoord; - int ii; + int ii = 0; pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); pCoord = pCell->aCoord; - for(ii=0; iinDim*2; ii++){ - readCoord(&pData[ii*4], &pCoord[ii]); - } + do{ + readCoord(pData, &pCoord[ii]); + readCoord(pData+4, &pCoord[ii+1]); + pData += 8; + ii += 2; + }while( iinDim2 ); } @@ -156228,7 +166550,9 @@ static void rtreeReference(Rtree *pRtree){ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ - sqlite3_finalize(pRtree->pReadNode); + pRtree->inWrTrans = 0; + pRtree->nCursor = 0; + nodeBlobReset(pRtree); sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); @@ -156266,6 +166590,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){ if( !zCreate ){ rc = SQLITE_NOMEM; }else{ + nodeBlobReset(pRtree); rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0); sqlite3_free(zCreate); } @@ -156281,6 +166606,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){ */ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; + Rtree *pRtree = (Rtree *)pVTab; RtreeCursor *pCsr; pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor)); @@ -156288,6 +166614,7 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = pVTab; rc = SQLITE_OK; + pRtree->nCursor++; } *ppCursor = (sqlite3_vtab_cursor *)pCsr; @@ -156320,10 +166647,13 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); int ii; RtreeCursor *pCsr = (RtreeCursor *)cur; + assert( pRtree->nCursor>0 ); freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); for(ii=0; iiaNode[ii]); sqlite3_free(pCsr); + pRtree->nCursor--; + nodeBlobReset(pRtree); return SQLITE_OK; } @@ -156346,15 +166676,22 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){ ** false. a[] is the four bytes of the on-disk record to be decoded. ** Store the results in "r". ** -** There are three versions of this macro, one each for little-endian and -** big-endian processors and a third generic implementation. The endian- -** specific implementations are much faster and are preferred if the -** processor endianness is known at compile-time. The SQLITE_BYTEORDER -** macro is part of sqliteInt.h and hence the endian-specific -** implementation will only be used if this module is compiled as part -** of the amalgamation. +** There are five versions of this macro. The last one is generic. The +** other four are various architectures-specific optimizations. */ -#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234 +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = _byteswap_ulong(*(u32*)a); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = __builtin_bswap32(*(u32*)a); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==1234 #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ memcpy(&c.u,a,4); \ @@ -156362,7 +166699,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){ ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ } -#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321 +#elif SQLITE_BYTEORDER==4321 #define RTREE_DECODE_COORD(eInt, a, r) { \ RtreeCoord c; /* Coordinate decoded */ \ memcpy(&c.u,a,4); \ @@ -156389,10 +166726,10 @@ static int rtreeCallbackConstraint( sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ int *peWithin /* OUT: visibility of the cell */ ){ - int i; /* Loop counter */ sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ int nCoord = pInfo->nCoord; /* No. of coordinates */ int rc; /* Callback return code */ + RtreeCoord c; /* Translator union */ sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); @@ -156402,13 +166739,41 @@ static int rtreeCallbackConstraint( pInfo->iRowid = readInt64(pCellData); } pCellData += 8; - for(i=0; iop==RTREE_MATCH ){ + int eWithin = 0; rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, - nCoord, aCoord, &i); - if( i==0 ) *peWithin = NOT_WITHIN; + nCoord, aCoord, &eWithin); + if( eWithin==0 ) *peWithin = NOT_WITHIN; *prScore = RTREE_ZERO; }else{ pInfo->aCoord = aCoord; @@ -156444,6 +166809,7 @@ static void rtreeNonleafConstraint( assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ ); + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ switch( p->op ){ case RTREE_LE: case RTREE_LT: @@ -156484,6 +166850,7 @@ static void rtreeLeafConstraint( assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ ); pCellData += 8 + p->iCoord*4; + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ RTREE_DECODE_COORD(eInt, pCellData, xN); switch( p->op ){ case RTREE_LE: if( xN <= p->u.rValue ) return; break; @@ -156552,7 +166919,7 @@ static int rtreeSearchPointCompare( } /* -** Interchange to search points in a cursor. +** Interchange two search points in a cursor. */ static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ RtreeSearchPoint t = p->aPoint[i]; @@ -156800,7 +167167,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){ if( rScoreeWithin = eWithin; + p->eWithin = (u8)eWithin; p->id = x.id; p->iCell = x.iCell; RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); @@ -156859,7 +167226,6 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else{ - if( rc ) return rc; nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ @@ -156908,33 +167274,17 @@ static int findLeafNode( ** operator. */ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ - RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ + RtreeMatchArg *pBlob, *pSrc; /* BLOB returned by geometry function */ sqlite3_rtree_query_info *pInfo; /* Callback information */ - int nBlob; /* Size of the geometry function blob */ - int nExpected; /* Expected size of the BLOB */ - /* Check that value is actually a blob. */ - if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; - - /* Check that the blob is roughly the right size. */ - nBlob = sqlite3_value_bytes(pValue); - if( nBlob<(int)sizeof(RtreeMatchArg) ){ - return SQLITE_ERROR; - } - - pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); + pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg"); + if( pSrc==0 ) return SQLITE_ERROR; + pInfo = (sqlite3_rtree_query_info*) + sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize ); if( !pInfo ) return SQLITE_NOMEM; memset(pInfo, 0, sizeof(*pInfo)); pBlob = (RtreeMatchArg*)&pInfo[1]; - - memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); - nExpected = (int)(sizeof(RtreeMatchArg) + - pBlob->nParam*sizeof(sqlite3_value*) + - (pBlob->nParam-1)*sizeof(RtreeDValue)); - if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ - sqlite3_free(pInfo); - return SQLITE_ERROR; - } + memcpy(pBlob, pSrc, pSrc->iSize); pInfo->pContext = pBlob->cb.pContext; pInfo->nParam = pBlob->nParam; pInfo->aParam = pBlob->aParam; @@ -156977,7 +167327,7 @@ static int rtreeFilter( if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ - RtreeSearchPoint *p; /* Search point for the the leaf */ + RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); @@ -156988,7 +167338,7 @@ static int rtreeFilter( p->id = iNode; p->eWithin = PARTLY_WITHIN; rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); - p->iCell = iCell; + p->iCell = (u8)iCell; RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); }else{ pCsr->atEOF = 1; @@ -157021,7 +167371,7 @@ static int rtreeFilter( if( rc!=SQLITE_OK ){ break; } - p->pInfo->nCoord = pRtree->nDim*2; + p->pInfo->nCoord = pRtree->nDim2; p->pInfo->anQueue = pCsr->anQueue; p->pInfo->mxLevel = pRtree->iDepth + 1; }else{ @@ -157036,7 +167386,7 @@ static int rtreeFilter( } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; - pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1); + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); if( pNew==0 ) return SQLITE_NOMEM; pNew->id = 1; pNew->iCell = 0; @@ -157054,19 +167404,6 @@ static int rtreeFilter( return rc; } -/* -** Set the pIdxInfo->estimatedRows variable to nRow. Unless this -** extension is currently being used by a version of SQLite too old to -** support estimatedRows. In that case this function is a no-op. -*/ -static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ -#if SQLITE_VERSION_NUMBER>=3008002 - if( sqlite3_libversion_number()>=3008002 ){ - pIdxInfo->estimatedRows = nRow; - } -#endif -} - /* ** Rtree virtual table module xBestIndex method. There are three ** table scan strategies to choose from (in order from most to @@ -157146,7 +167483,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ** a single row. */ pIdxInfo->estimatedCost = 30.0; - setEstimatedRows(pIdxInfo, 1); + pIdxInfo->estimatedRows = 1; return SQLITE_OK; } @@ -157164,7 +167501,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ break; } zIdxStr[iIdx++] = op; - zIdxStr[iIdx++] = p->iColumn - 1 + '0'; + zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = 1; } @@ -157176,9 +167513,9 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ return SQLITE_NOMEM; } - nRow = pRtree->nRowEst / (iIdx + 1); + nRow = pRtree->nRowEst >> (iIdx/2); pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; - setEstimatedRows(pIdxInfo, nRow); + pIdxInfo->estimatedRows = nRow; return rc; } @@ -157188,9 +167525,26 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ */ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ RtreeDValue area = (RtreeDValue)1; - int ii; - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ - area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]))); + assert( pRtree->nDim>=1 && pRtree->nDim<=5 ); +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + switch( pRtree->nDim ){ + case 5: area = p->aCoord[9].f - p->aCoord[8].f; + case 4: area *= p->aCoord[7].f - p->aCoord[6].f; + case 3: area *= p->aCoord[5].f - p->aCoord[4].f; + case 2: area *= p->aCoord[3].f - p->aCoord[2].f; + default: area *= p->aCoord[1].f - p->aCoord[0].f; + } + }else +#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; + } } return area; } @@ -157200,11 +167554,12 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ ** of the objects size in each dimension. */ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ - RtreeDValue margin = (RtreeDValue)0; - int ii; - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ + RtreeDValue margin = 0; + int ii = pRtree->nDim2 - 2; + do{ margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); - } + ii -= 2; + }while( ii>=0 ); return margin; } @@ -157212,17 +167567,19 @@ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ ** Store the union of cells p1 and p2 in p1. */ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ - int ii; + int ii = 0; if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ + do{ p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f); p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f); - } + ii += 2; + }while( iinDim2 ); }else{ - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ + do{ p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i); p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i); - } + ii += 2; + }while( iinDim2 ); } } @@ -157233,7 +167590,7 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ int ii; int isInt = (pRtree->eCoordType==RTREE_COORD_INT32); - for(ii=0; ii<(pRtree->nDim*2); ii+=2){ + for(ii=0; iinDim2; ii+=2){ RtreeCoord *a1 = &p1->aCoord[ii]; RtreeCoord *a2 = &p2->aCoord[ii]; if( (!isInt && (a2[0].fa1[1].f)) @@ -157268,7 +167625,7 @@ static RtreeDValue cellOverlap( for(ii=0; iinDim*2); jj+=2){ + for(jj=0; jjnDim2; jj+=2){ RtreeDValue x1, x2; x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); @@ -158129,7 +168486,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ int rc; /* Return code */ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ int iCell; /* Index of iDelete cell in pLeaf */ - RtreeNode *pRoot; /* Root node of rtree structure */ + RtreeNode *pRoot = 0; /* Root node of rtree structure */ /* Obtain a reference to the root node to initialize Rtree.iDepth */ @@ -158235,6 +168592,53 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){ } #endif /* !defined(SQLITE_RTREE_INT_ONLY) */ +/* +** A constraint has failed while inserting a row into an rtree table. +** Assuming no OOM error occurs, this function sets the error message +** (at pRtree->base.zErrMsg) to an appropriate value and returns +** SQLITE_CONSTRAINT. +** +** Parameter iCol is the index of the leftmost column involved in the +** constraint failure. If it is 0, then the constraint that failed is +** the unique constraint on the id column. Otherwise, it is the rtree +** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. +** +** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. +*/ +static int rtreeConstraintError(Rtree *pRtree, int iCol){ + sqlite3_stmt *pStmt = 0; + char *zSql; + int rc; + + assert( iCol==0 || iCol%2 ); + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); + if( zSql ){ + rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); + }else{ + rc = SQLITE_NOMEM; + } + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + if( iCol==0 ){ + const char *zCol = sqlite3_column_name(pStmt, 0); + pRtree->base.zErrMsg = sqlite3_mprintf( + "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol + ); + }else{ + const char *zCol1 = sqlite3_column_name(pStmt, iCol); + const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); + pRtree->base.zErrMsg = sqlite3_mprintf( + "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 + ); + } + } + + sqlite3_finalize(pStmt); + return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); +} + + /* ** The xUpdate method for rtree module virtual tables. @@ -158277,7 +168681,7 @@ static int rtreeUpdate( ** This problem was discovered after years of use, so we silently ignore ** these kinds of misdeclared tables to avoid breaking any legacy. */ - assert( nData<=(pRtree->nDim*2 + 3) ); + assert( nData<=(pRtree->nDim2 + 3) ); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ @@ -158285,7 +168689,7 @@ static int rtreeUpdate( cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]); cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ - rc = SQLITE_CONSTRAINT; + rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } @@ -158296,7 +168700,7 @@ static int rtreeUpdate( cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]); cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]); if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){ - rc = SQLITE_CONSTRAINT; + rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } @@ -158317,7 +168721,7 @@ static int rtreeUpdate( if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ - rc = SQLITE_CONSTRAINT; + rc = rtreeConstraintError(pRtree, 0); goto constraint; } } @@ -158367,6 +168771,27 @@ constraint: return rc; } +/* +** Called when a transaction starts. +*/ +static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + assert( pRtree->inWrTrans==0 ); + pRtree->inWrTrans++; + return SQLITE_OK; +} + +/* +** Called when a transaction completes (either by COMMIT or ROLLBACK). +** The sqlite3_blob object should be released at this point. +*/ +static int rtreeEndTransaction(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + return SQLITE_OK; +} + /* ** The xRename method for rtree module virtual tables. */ @@ -158382,12 +168807,37 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ , pRtree->zDb, pRtree->zName, zNewName ); if( zSql ){ + nodeBlobReset(pRtree); rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc; } +/* +** The xSavepoint method. +** +** This module does not need to do anything to support savepoints. However, +** it uses this hook to close any open blob handle. This is done because a +** DROP TABLE command - which fortunately always opens a savepoint - cannot +** succeed if there are any open blob handles. i.e. if the blob handle were +** not closed here, the following would fail: +** +** BEGIN; +** INSERT INTO rtree... +** DROP TABLE ; -- Would fail with SQLITE_LOCKED +** COMMIT; +*/ +static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ + Rtree *pRtree = (Rtree *)pVtab; + int iwt = pRtree->inWrTrans; + UNUSED_PARAMETER(iSavepoint); + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + pRtree->inWrTrans = iwt; + return SQLITE_OK; +} + /* ** This function populates the pRtree->nRowEst variable with an estimate ** of the number of rows in the virtual table. If possible, this is based @@ -158400,6 +168850,13 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ int rc; i64 nRow = 0; + rc = sqlite3_table_column_metadata( + db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 + ); + if( rc!=SQLITE_OK ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + return rc==SQLITE_ERROR ? SQLITE_OK : rc; + } zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; @@ -158426,7 +168883,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ } static sqlite3_module rtreeModule = { - 0, /* iVersion */ + 2, /* iVersion */ rtreeCreate, /* xCreate - create a table */ rtreeConnect, /* xConnect - connect to an existing table */ rtreeBestIndex, /* xBestIndex - Determine search strategy */ @@ -158440,15 +168897,15 @@ static sqlite3_module rtreeModule = { rtreeColumn, /* xColumn - read data */ rtreeRowid, /* xRowid - read data */ rtreeUpdate, /* xUpdate - write data */ - 0, /* xBegin - begin transaction */ - 0, /* xSync - sync transaction */ - 0, /* xCommit - commit transaction */ - 0, /* xRollback - rollback transaction */ + rtreeBeginTransaction, /* xBegin - begin transaction */ + rtreeEndTransaction, /* xSync - sync transaction */ + rtreeEndTransaction, /* xCommit - commit transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ 0, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ - 0, /* xSavepoint */ + rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ }; static int rtreeSqlInit( @@ -158460,10 +168917,9 @@ static int rtreeSqlInit( ){ int rc = SQLITE_OK; - #define N_STATEMENT 9 + #define N_STATEMENT 8 static const char *azSql[N_STATEMENT] = { - /* Read and write the xxx_node table */ - "SELECT data FROM '%q'.'%q_node' WHERE nodeno = :1", + /* Write the xxx_node table */ "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)", "DELETE FROM '%q'.'%q_node' WHERE nodeno = :1", @@ -158501,21 +168957,21 @@ static int rtreeSqlInit( } } - appStmt[0] = &pRtree->pReadNode; - appStmt[1] = &pRtree->pWriteNode; - appStmt[2] = &pRtree->pDeleteNode; - appStmt[3] = &pRtree->pReadRowid; - appStmt[4] = &pRtree->pWriteRowid; - appStmt[5] = &pRtree->pDeleteRowid; - appStmt[6] = &pRtree->pReadParent; - appStmt[7] = &pRtree->pWriteParent; - appStmt[8] = &pRtree->pDeleteParent; + appStmt[0] = &pRtree->pWriteNode; + appStmt[1] = &pRtree->pDeleteNode; + appStmt[2] = &pRtree->pReadRowid; + appStmt[3] = &pRtree->pWriteRowid; + appStmt[4] = &pRtree->pDeleteRowid; + appStmt[5] = &pRtree->pReadParent; + appStmt[6] = &pRtree->pWriteParent; + appStmt[7] = &pRtree->pDeleteParent; rc = rtreeQueryStat1(db, pRtree); for(i=0; iiNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + }else if( pRtree->iNodeSize<(512-64) ){ + rc = SQLITE_CORRUPT_VTAB; + *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", + pRtree->zName); } } @@ -158647,9 +169107,10 @@ static int rtreeInit( pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; - pRtree->nDim = (argc-4)/2; - pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2; - pRtree->eCoordType = eCoordType; + pRtree->nDim = (u8)((argc-4)/2); + pRtree->nDim2 = pRtree->nDim*2; + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; + pRtree->eCoordType = (u8)eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); @@ -158722,7 +169183,8 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); - tree.nDim = sqlite3_value_int(apArg[0]); + tree.nDim = (u8)sqlite3_value_int(apArg[0]); + tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); @@ -158735,7 +169197,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ nodeGetCell(&tree, &node, ii, &cell); sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); nCell = (int)strlen(zCell); - for(jj=0; jjmagic = RTREE_GEOMETRY_MAGIC; + pBlob->iSize = nBlob; pBlob->cb = pGeomCtx[0]; pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg]; pBlob->nParam = nArg; @@ -158877,7 +169339,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_result_error_nomem(ctx); rtreeMatchArgFree(pBlob); }else{ - sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree); + sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree); } } } @@ -158885,7 +169347,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ /* ** Register a new geometry function for use with the r-tree MATCH operator. */ -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback( +SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, /* Register SQL function on this connection */ const char *zGeom, /* Name of the new SQL function */ int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */ @@ -158909,7 +169371,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback( ** Register a new 2nd-generation geometry function for use with the ** r-tree MATCH operator. */ -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback( +SQLITE_API int sqlite3_rtree_query_callback( sqlite3 *db, /* Register SQL function on this connection */ const char *zQueryFunc, /* Name of new SQL function */ int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */ @@ -158934,7 +169396,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback( #ifdef _WIN32 __declspec(dllexport) #endif -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init( +SQLITE_API int sqlite3_rtree_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -159010,6 +169472,38 @@ static void xFree(void *p){ sqlite3_free(p); } +/* +** This lookup table is used to help decode the first byte of +** a multi-byte UTF8 character. It is copied here from SQLite source +** code file utf8.c. +*/ +static const unsigned char icuUtf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define SQLITE_ICU_READ_UTF8(zIn, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = icuUtf8Trans1[c-0xc0]; \ + while( (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + } + +#define SQLITE_ICU_SKIP_UTF8(zIn) \ + assert( *zIn ); \ + if( *(zIn++)>=0xc0 ){ \ + while( (*zIn & 0xc0)==0x80 ){zIn++;} \ + } + + /* ** Compare two UTF-8 strings for equality where the first string is ** a "LIKE" expression. Return true (1) if they are the same and @@ -159020,19 +169514,17 @@ static int icuLikeCompare( const uint8_t *zString, /* The UTF-8 string to compare against */ const UChar32 uEsc /* The escape character */ ){ - static const int MATCH_ONE = (UChar32)'_'; - static const int MATCH_ALL = (UChar32)'%'; - - int iPattern = 0; /* Current byte index in zPattern */ - int iString = 0; /* Current byte index in zString */ + static const uint32_t MATCH_ONE = (uint32_t)'_'; + static const uint32_t MATCH_ALL = (uint32_t)'%'; int prevEscape = 0; /* True if the previous character was uEsc */ - while( zPattern[iPattern]!=0 ){ + while( 1 ){ /* Read (and consume) the next character from the input pattern. */ - UChar32 uPattern; - U8_NEXT_UNSAFE(zPattern, iPattern, uPattern); + uint32_t uPattern; + SQLITE_ICU_READ_UTF8(zPattern, uPattern); + if( uPattern==0 ) break; /* There are now 4 possibilities: ** @@ -159049,39 +169541,39 @@ static int icuLikeCompare( ** MATCH_ALL. For each MATCH_ONE, skip one character in the ** test string. */ - while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){ + while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ if( c==MATCH_ONE ){ - if( zString[iString]==0 ) return 0; - U8_FWD_1_UNSAFE(zString, iString); + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); } - iPattern++; + zPattern++; } - if( zPattern[iPattern]==0 ) return 1; + if( *zPattern==0 ) return 1; - while( zString[iString] ){ - if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){ + while( *zString ){ + if( icuLikeCompare(zPattern, zString, uEsc) ){ return 1; } - U8_FWD_1_UNSAFE(zString, iString); + SQLITE_ICU_SKIP_UTF8(zString); } return 0; }else if( !prevEscape && uPattern==MATCH_ONE ){ /* Case 2. */ - if( zString[iString]==0 ) return 0; - U8_FWD_1_UNSAFE(zString, iString); + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); - }else if( !prevEscape && uPattern==uEsc){ + }else if( !prevEscape && uPattern==(uint32_t)uEsc){ /* Case 3. */ prevEscape = 1; }else{ /* Case 4. */ - UChar32 uString; - U8_NEXT_UNSAFE(zString, iString, uString); - uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT); - uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT); + uint32_t uString; + SQLITE_ICU_READ_UTF8(zString, uString); + uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); + uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); if( uString!=uPattern ){ return 0; } @@ -159089,7 +169581,7 @@ static int icuLikeCompare( } } - return zString[iString]==0; + return *zString==0; } /* @@ -159269,20 +169761,22 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ** of upper() or lower(). ** ** lower('I', 'en_us') -> 'i' -** lower('I', 'tr_tr') -> 'ı' (small dotless i) +** lower('I', 'tr_tr') -> '\u131' (small dotless i) ** ** http://www.icu-project.org/userguide/posix.html#case_mappings */ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ - const UChar *zInput; - UChar *zOutput; - int nInput; - int nOutput; - - UErrorCode status = U_ZERO_ERROR; + const UChar *zInput; /* Pointer to input string */ + UChar *zOutput = 0; /* Pointer to output buffer */ + int nInput; /* Size of utf-16 input string in bytes */ + int nOut; /* Size of output buffer in bytes */ + int cnt; + int bToUpper; /* True for toupper(), false for tolower() */ + UErrorCode status; const char *zLocale = 0; assert(nArg==1 || nArg==2); + bToUpper = (sqlite3_user_data(p)!=0); if( nArg==2 ){ zLocale = (const char *)sqlite3_value_text(apArg[1]); } @@ -159291,26 +169785,38 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ if( !zInput ){ return; } - nInput = sqlite3_value_bytes16(apArg[0]); - - nOutput = nInput * 2 + 2; - zOutput = sqlite3_malloc(nOutput); - if( !zOutput ){ + nOut = nInput = sqlite3_value_bytes16(apArg[0]); + if( nOut==0 ){ + sqlite3_result_text16(p, "", 0, SQLITE_STATIC); return; } - if( sqlite3_user_data(p) ){ - u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status); - }else{ - u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status); - } + for(cnt=0; cnt<2; cnt++){ + UChar *zNew = sqlite3_realloc(zOutput, nOut); + if( zNew==0 ){ + sqlite3_free(zOutput); + sqlite3_result_error_nomem(p); + return; + } + zOutput = zNew; + status = U_ZERO_ERROR; + if( bToUpper ){ + nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + }else{ + nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + } - if( !U_SUCCESS(status) ){ - icuFunctionError(p, "u_strToLower()/u_strToUpper", status); + if( U_SUCCESS(status) ){ + sqlite3_result_text16(p, zOutput, nOut, xFree); + }else if( status==U_BUFFER_OVERFLOW_ERROR ){ + assert( cnt==0 ); + continue; + }else{ + icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); + } return; } - - sqlite3_result_text16(p, zOutput, -1, xFree); + assert( 0 ); /* Unreachable */ } /* @@ -159399,38 +169905,36 @@ static void icuLoadCollation( ** Register the ICU extension functions with database db. */ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ - struct IcuScalar { + static const struct IcuScalar { const char *zName; /* Function name */ - int nArg; /* Number of arguments */ - int enc; /* Optimal text encoding */ - void *pContext; /* sqlite3_user_data() context */ + unsigned char nArg; /* Number of arguments */ + unsigned short enc; /* Optimal text encoding */ + unsigned char iContext; /* sqlite3_user_data() context */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } scalars[] = { - {"regexp", 2, SQLITE_ANY, 0, icuRegexpFunc}, - - {"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16}, - {"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF16, (void*)1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF16, (void*)1, icuCaseFunc16}, - - {"lower", 1, SQLITE_UTF8, 0, icuCaseFunc16}, - {"lower", 2, SQLITE_UTF8, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF8, (void*)1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF8, (void*)1, icuCaseFunc16}, - - {"like", 2, SQLITE_UTF8, 0, icuLikeFunc}, - {"like", 3, SQLITE_UTF8, 0, icuLikeFunc}, - - {"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation}, + {"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation}, + {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc}, + {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, + {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, }; - int rc = SQLITE_OK; int i; + for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ - struct IcuScalar *p = &scalars[i]; + const struct IcuScalar *p = &scalars[i]; rc = sqlite3_create_function( - db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0 + db, p->zName, p->nArg, p->enc, + p->iContext ? (void*)db : (void*)0, + p->xFunc, 0, 0 ); } @@ -159441,7 +169945,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ #ifdef _WIN32 __declspec(dllexport) #endif -SQLITE_API int SQLITE_STDCALL sqlite3_icu_init( +SQLITE_API int sqlite3_icu_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -159917,7 +170421,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** may also be named data_, where is any sequence ** of zero or more numeric characters (0-9). This can be significant because ** tables within the RBU database are always processed in order sorted by -** name. By judicious selection of the the portion of the names +** name. By judicious selection of the portion of the names ** of the RBU tables the user can therefore control the order in which they ** are processed. This can be useful, for example, to ensure that "external ** content" FTS4 tables are updated before their underlying content tables. @@ -160121,12 +170625,72 @@ typedef struct sqlite3rbu sqlite3rbu; ** not work out of the box with zipvfs. Refer to the comment describing ** the zipvfs_create_vfs() API below for details on using RBU with zipvfs. */ -SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( +SQLITE_API sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ); +/* +** Open an RBU handle to perform an RBU vacuum on database file zTarget. +** An RBU vacuum is similar to SQLite's built-in VACUUM command, except +** that it can be suspended and resumed like an RBU update. +** +** The second argument to this function identifies a database in which +** to store the state of the RBU vacuum operation if it is suspended. The +** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum +** operation, the state database should either not exist or be empty +** (contain no tables). If an RBU vacuum is suspended by calling +** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has +** returned SQLITE_DONE, the vacuum state is stored in the state database. +** The vacuum can be resumed by calling this function to open a new RBU +** handle specifying the same target and state databases. +** +** If the second argument passed to this function is NULL, then the +** 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. +** +** This function does not delete the state database after an RBU vacuum +** is completed, even if it created it. However, if the call to +** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents +** of the state tables within the state database are zeroed. This way, +** the next call to sqlite3rbu_vacuum() opens a handle that starts a +** new RBU vacuum operation. +** +** As with sqlite3rbu_open(), Zipvfs users should rever to the comment +** describing the sqlite3rbu_create_vfs() API function below for +** a description of the complications associated with using RBU with +** zipvfs databases. +*/ +SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( + const char *zTarget, + const char *zState +); + +/* +** Configure a limit for the amount of temp space that may be used by +** the RBU handle passed as the first argument. The new limit is specified +** in bytes by the second parameter. If it is positive, the limit is updated. +** If the second parameter to this function is passed zero, then the limit +** is removed entirely. If the second parameter is negative, the limit is +** not modified (this is useful for querying the current limit). +** +** In all cases the returned value is the current limit in bytes (zero +** indicates unlimited). +** +** If the temp space limit is exceeded during operation, an SQLITE_FULL +** error is returned. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64); + +/* +** Return the current amount of temp file space, in bytes, currently used by +** the RBU handle passed as the only argument. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*); + /* ** Internally, each RBU connection uses a separate SQLite database ** connection to access the target and rbu update databases. This @@ -160158,7 +170722,7 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( ** Database handles returned by this function remain valid until the next ** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db(). */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu); +SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu); /* ** Do some work towards applying the RBU update to the target db. @@ -160172,7 +170736,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu); ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops ** that immediately return the same value. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu); +SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu); /* ** Force RBU to save its state to disk. @@ -160184,7 +170748,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu); ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu); +SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); /* ** Close an RBU handle. @@ -160195,23 +170759,103 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu); ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an -** SQLite error code is returned. Additionally, *pzErrmsg may be set to -** point to a buffer containing a utf-8 formatted English language error -** message. It is the responsibility of the caller to eventually free any -** such buffer using sqlite3_free(). +** SQLite error code is returned. Additionally, if pzErrmsg is not NULL, +** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted +** English language error message. It is the responsibility of the caller to +** eventually free any such buffer using sqlite3_free(). ** ** Otherwise, if no error occurs, this function returns SQLITE_OK if the ** update has been partially applied, or SQLITE_DONE if it has been ** completely applied. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg); +SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg); /* ** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current RBU update was started. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu); +SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); + +/* +** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) +** progress indications for the two stages of an RBU update. This API may +** be useful for driving GUI progress indicators and similar. +** +** An RBU update is divided into two stages: +** +** * Stage 1, in which changes are accumulated in an oal/wal file, and +** * Stage 2, in which the contents of the wal file are copied into the +** main database. +** +** The update is visible to non-RBU clients during stage 2. During stage 1 +** non-RBU reader clients may see the original database. +** +** If this API is called during stage 2 of the update, output variable +** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo) +** to a value between 0 and 10000 to indicate the permyriadage progress of +** stage 2. A value of 5000 indicates that stage 2 is half finished, +** 9000 indicates that it is 90% finished, and so on. +** +** If this API is called during stage 1 of the update, output variable +** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The +** value to which (*pnOne) is set depends on whether or not the RBU +** database contains an "rbu_count" table. The rbu_count table, if it +** exists, must contain the same columns as the following: +** +** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID; +** +** There must be one row in the table for each source (data_xxx) table within +** the RBU database. The 'tbl' column should contain the name of the source +** table. The 'cnt' column should contain the number of rows within the +** source table. +** +** If the rbu_count table is present and populated correctly and this +** API is called during stage 1, the *pnOne output variable is set to the +** permyriadage progress of the same stage. If the rbu_count table does +** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count +** table exists but is not correctly populated, the value of the *pnOne +** output variable during stage 1 is undefined. +*/ +SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo); + +/* +** Obtain an indication as to the current stage of an RBU update or vacuum. +** This function always returns one of the SQLITE_RBU_STATE_XXX constants +** defined in this file. Return values should be interpreted as follows: +** +** SQLITE_RBU_STATE_OAL: +** RBU is currently building a *-oal file. The next call to sqlite3rbu_step() +** may either add further data to the *-oal file, or compute data that will +** be added by a subsequent call. +** +** SQLITE_RBU_STATE_MOVE: +** RBU has finished building the *-oal file. The next call to sqlite3rbu_step() +** will move the *-oal file to the equivalent *-wal path. If the current +** operation is an RBU update, then the updated version of the database +** file will become visible to ordinary SQLite clients following the next +** call to sqlite3rbu_step(). +** +** SQLITE_RBU_STATE_CHECKPOINT: +** RBU is currently performing an incremental checkpoint. The next call to +** sqlite3rbu_step() will copy a page of data from the *-wal file into +** the target database file. +** +** SQLITE_RBU_STATE_DONE: +** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step() +** will immediately return SQLITE_DONE. +** +** SQLITE_RBU_STATE_ERROR: +** An error has occurred. Any subsequent calls to sqlite3rbu_step() will +** immediately return the SQLite error code associated with the error. +*/ +#define SQLITE_RBU_STATE_OAL 1 +#define SQLITE_RBU_STATE_MOVE 2 +#define SQLITE_RBU_STATE_CHECKPOINT 3 +#define SQLITE_RBU_STATE_DONE 4 +#define SQLITE_RBU_STATE_ERROR 5 + +SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); /* ** Create an RBU VFS named zName that accesses the underlying file-system @@ -160255,7 +170899,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu); ** file-system via "rbu" all the time, even if it only uses RBU functionality ** occasionally. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent); +SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent); /* ** Deregister and destroy an RBU vfs created by an earlier call to @@ -160265,7 +170909,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha ** before all database handles that use it have been closed, the results ** are undefined. */ -SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName); +SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); #if 0 } /* end of the 'extern "C"' block */ @@ -160283,6 +170927,13 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName); /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 +/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM +** to enable checksum verification. +*/ +#ifndef RBU_ENABLE_DELTA_CKSUM +# define RBU_ENABLE_DELTA_CKSUM 0 +#endif + /* ** Swap two objects of type TYPE. */ @@ -160334,14 +170985,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName); ** RBU_STATE_OALSZ: ** Valid if STAGE==1. The size in bytes of the *-oal file. */ -#define RBU_STATE_STAGE 1 -#define RBU_STATE_TBL 2 -#define RBU_STATE_IDX 3 -#define RBU_STATE_ROW 4 -#define RBU_STATE_PROGRESS 5 -#define RBU_STATE_CKPT 6 -#define RBU_STATE_COOKIE 7 -#define RBU_STATE_OALSZ 8 +#define RBU_STATE_STAGE 1 +#define RBU_STATE_TBL 2 +#define RBU_STATE_IDX 3 +#define RBU_STATE_ROW 4 +#define RBU_STATE_PROGRESS 5 +#define RBU_STATE_CKPT 6 +#define RBU_STATE_COOKIE 7 +#define RBU_STATE_OALSZ 8 +#define RBU_STATE_PHASEONESTEP 9 #define RBU_STAGE_OAL 1 #define RBU_STAGE_MOVE 2 @@ -160362,6 +171014,7 @@ typedef struct RbuUpdateStmt RbuUpdateStmt; #if !defined(SQLITE_AMALGAMATION) typedef unsigned int u32; +typedef unsigned short u16; typedef unsigned char u8; typedef sqlite3_int64 i64; #endif @@ -160375,6 +171028,8 @@ typedef sqlite3_int64 i64; #define WAL_LOCK_CKPT 1 #define WAL_LOCK_READ0 3 +#define SQLITE_FCNTL_RBUCNT 5149216 + /* ** A structure to store values read from the rbu_state table in memory. */ @@ -160387,6 +171042,7 @@ struct RbuState { i64 nProgress; u32 iCookie; i64 iOalSz; + i64 nPhaseOneStep; }; struct RbuUpdateStmt { @@ -160431,6 +171087,7 @@ struct RbuObjIter { int iTnum; /* Root page of current object */ int iPkTnum; /* If eType==EXTERNAL, root of PK index */ int bUnique; /* Current index is unique */ + int nIndex; /* Number of aux. indexes on table zTbl */ /* Statements created by rbuObjIterPrepareAll() */ int nCol; /* Number of columns in current object */ @@ -160467,10 +171124,11 @@ struct RbuObjIter { */ #define RBU_INSERT 1 /* Insert on a main table b-tree */ #define RBU_DELETE 2 /* Delete a row from a main table b-tree */ -#define RBU_IDX_DELETE 3 /* Delete a row from an aux. index b-tree */ -#define RBU_IDX_INSERT 4 /* Insert on an aux. index b-tree */ -#define RBU_UPDATE 5 /* Update a row in a main table b-tree */ +#define RBU_REPLACE 3 /* Delete and then insert a row */ +#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */ +#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */ +#define RBU_UPDATE 6 /* Update a row in a main table b-tree */ /* ** A single step of an incremental checkpoint - frame iWalFrame of the wal @@ -160483,6 +171141,43 @@ struct RbuFrame { /* ** RBU handle. +** +** nPhaseOneStep: +** If the RBU database contains an rbu_count table, this value is set to +** a running estimate of the number of b-tree operations required to +** finish populating the *-oal file. This allows the sqlite3_bp_progress() +** API to calculate the permyriadage progress of populating the *-oal file +** using the formula: +** +** permyriadage = (10000 * nProgress) / nPhaseOneStep +** +** nPhaseOneStep is initialized to the sum of: +** +** nRow * (nIndex + 1) +** +** for all source tables in the RBU database, where nRow is the number +** of rows in the source table and nIndex the number of indexes on the +** corresponding target database table. +** +** This estimate is accurate if the RBU update consists entirely of +** INSERT operations. However, it is inaccurate if: +** +** * the RBU update contains any UPDATE operations. If the PK specified +** for an UPDATE operation does not exist in the target table, then +** no b-tree operations are required on index b-trees. Or if the +** specified PK does exist, then (nIndex*2) such operations are +** required (one delete and one insert on each index b-tree). +** +** * the RBU update contains any DELETE operations for which the specified +** PK does not exist. In this case no operations are required on index +** b-trees. +** +** * the RBU update contains REPLACE operations. These are similar to +** UPDATE operations. +** +** nPhaseOneStep is updated to account for the conditions above during the +** first pass of each source table. The updated nPhaseOneStep value is +** stored in the rbu_state table if the RBU update is suspended. */ struct sqlite3rbu { int eStage; /* Value of RBU_STATE_STAGE field */ @@ -160499,7 +171194,9 @@ struct sqlite3rbu { RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ + int nPagePerSector; /* Pages per sector for pTargetFd */ i64 iOalSz; + i64 nPhaseOneStep; /* The following state variables are used as part of the incremental ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding @@ -160512,31 +171209,48 @@ struct sqlite3rbu { int pgsz; u8 *aBuf; i64 iWalCksum; + i64 szTemp; /* Current size of all temp files in use */ + i64 szTempLimit; /* Total size limit for temp files */ + + /* Used in RBU vacuum mode only */ + int nRbu; /* Number of RBU VFS in the stack */ + rbu_file *pRbuFd; /* Fd for main db of dbRbu */ }; /* ** An rbu VFS is implemented using an instance of this structure. +** +** Variable pRbu is only non-NULL for automatically created RBU VFS objects. +** It is NULL for RBU VFS objects created explicitly using +** sqlite3rbu_create_vfs(). It is used to track the total amount of temp +** space used by the RBU handle. */ struct rbu_vfs { sqlite3_vfs base; /* rbu VFS shim methods */ 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 */ }; /* ** Each file opened by an rbu VFS is represented by an instance of ** the following structure. +** +** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable +** "sz" is set to the current size of the database file. */ struct rbu_file { sqlite3_file base; /* sqlite3_file methods */ sqlite3_file *pReal; /* Underlying file handle */ rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */ sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */ + i64 sz; /* Size of file in bytes (temp only) */ int openFlags; /* Flags this file was opened with */ u32 iCookie; /* Cookie value for main db files */ u8 iWriteVer; /* "write-version" value for main db files */ + u8 bNolock; /* True to fail EXCLUSIVE locks */ int nShm; /* Number of entries in apShm[] array */ char **apShm; /* Array of mmap'd *-shm regions */ @@ -160547,6 +171261,11 @@ struct rbu_file { rbu_file *pMainNext; /* Next MAIN_DB file */ }; +/* +** True for an RBU vacuum handle, or false otherwise. +*/ +#define rbuIsVacuum(p) ((p)->zTarget==0) + /************************************************************************* ** The following three functions, found below: @@ -160589,6 +171308,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ return v; } +#if RBU_ENABLE_DELTA_CKSUM /* ** Compute a 32-bit checksum on the N-byte buffer. Return the result. */ @@ -160623,6 +171343,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){ } return sum3; } +#endif /* ** Apply a delta. @@ -160653,7 +171374,7 @@ static int rbuDeltaApply( ){ unsigned int limit; unsigned int total = 0; -#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST +#if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif @@ -160708,7 +171429,7 @@ static int rbuDeltaApply( case ';': { zDelta++; lenDelta--; zOut[0] = 0; -#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST +#if RBU_ENABLE_DELTA_CKSUM if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){ /* ERROR: bad checksum */ return -1; @@ -160995,8 +171716,11 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){ /* ** The implementation of the rbu_target_name() SQL function. This function -** accepts one argument - the name of a table in the RBU database. If the -** table name matches the pattern: +** accepts one or two arguments. The first argument is the name of a table - +** the name of a table in the RBU database. The second, if it is present, is 1 +** for a view or 0 for a table. +** +** For a non-vacuum RBU handle, if the table name matches the pattern: ** ** data[0-9]_ ** @@ -161007,21 +171731,33 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){ ** "data_t1" -> "t1" ** "data0123_t2" -> "t2" ** "dataAB_t3" -> NULL +** +** For an rbu vacuum handle, a copy of the first argument is returned if +** the second argument is either missing or 0 (not a view). */ static void rbuTargetNameFunc( - sqlite3_context *context, + sqlite3_context *pCtx, int argc, sqlite3_value **argv ){ + sqlite3rbu *p = sqlite3_user_data(pCtx); const char *zIn; - assert( argc==1 ); + assert( argc==1 || argc==2 ); zIn = (const char*)sqlite3_value_text(argv[0]); - if( zIn && strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){ - int i; - for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++); - if( zIn[i]=='_' && zIn[i+1] ){ - sqlite3_result_text(context, &zIn[i+1], -1, SQLITE_STATIC); + if( zIn ){ + if( rbuIsVacuum(p) ){ + if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ + sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); + } + }else{ + if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){ + int i; + for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++); + if( zIn[i]=='_' && zIn[i+1] ){ + sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC); + } + } } } } @@ -161038,11 +171774,14 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); - rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, - "SELECT rbu_target_name(name) AS target, name FROM sqlite_master " + rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, + sqlite3_mprintf( + "SELECT rbu_target_name(name, type='view') AS target, name " + "FROM sqlite_master " "WHERE type IN ('table', 'view') AND target IS NOT NULL " + " %s " "ORDER BY name" - ); + , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, @@ -161122,7 +171861,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ assert( nByte>0 ); - pRet = sqlite3_malloc(nByte); + pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ p->rc = SQLITE_NOMEM; }else{ @@ -161168,8 +171907,8 @@ static char *rbuStrndup(const char *zStr, int *pRc){ assert( *pRc==SQLITE_OK ); if( zStr ){ - int nCopy = strlen(zStr) + 1; - zRet = (char*)sqlite3_malloc(nCopy); + size_t nCopy = strlen(zStr) + 1; + zRet = (char*)sqlite3_malloc64(nCopy); if( zRet ){ memcpy(zRet, zStr, nCopy); }else{ @@ -161330,6 +172069,7 @@ 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); sqlite3_stmt *pXInfo = 0; @@ -161343,6 +172083,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ } rbuFinalize(p, pXInfo); bIndex = 1; + pIter->nIndex++; + } + + if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ + /* "PRAGMA index_list" includes the main PK b-tree */ + pIter->nIndex--; } rbuFinalize(p, pList); @@ -161408,6 +172154,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ pStmt = 0; if( p->rc==SQLITE_OK + && rbuIsVacuum(p)==0 && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) ){ p->rc = SQLITE_ERROR; @@ -161456,6 +172203,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ rbuFinalize(p, pStmt); rbuObjIterCacheIndexedCols(p, pIter); assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 ); + assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 ); } return p->rc; @@ -161546,6 +172294,8 @@ static char *rbuObjIterGetIndexCols( for(i=0; pIter->abTblPk[i]==0; i++); assert( inTblCol ); zCol = pIter->azTblCol[i]; + }else if( rbuIsVacuum(p) ){ + zCol = "_rowid_"; }else{ zCol = "rbu_rowid"; } @@ -162009,6 +172759,14 @@ static void rbuTmpInsertFunc( int rc = SQLITE_OK; int i; + assert( sqlite3_value_int(apVal[0])!=0 + || p->objiter.eType==RBU_PK_EXTERNAL + || p->objiter.eType==RBU_PK_NONE + ); + if( sqlite3_value_int(apVal[0])!=0 ){ + p->nPhaseOneStep += p->objiter.nIndex; + } + for(i=0; rc==SQLITE_OK && iobjiter.pTmpInsert, i+1, apVal[i]); } @@ -162078,7 +172836,7 @@ static int rbuObjIterPrepareAll( } /* And to delete index entries */ - if( p->rc==SQLITE_OK ){ + if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError( p->dbMain, &pIter->pDelete, &p->zErrmsg, sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere) @@ -162088,6 +172846,15 @@ static int rbuObjIterPrepareAll( /* Create the SELECT statement to read keys in sorted order */ if( p->rc==SQLITE_OK ){ char *zSql; + if( rbuIsVacuum(p) ){ + zSql = sqlite3_mprintf( + "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s", + zCollist, + pIter->zDataTbl, + zCollist, zLimit + ); + }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", @@ -162096,13 +172863,13 @@ static int rbuObjIterPrepareAll( ); }else{ zSql = sqlite3_mprintf( + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' " + "UNION ALL " "SELECT %s, rbu_control FROM '%q' " "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 " - "UNION ALL " - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' " "ORDER BY %s%s", - zCollist, pIter->zDataTbl, zCollist, p->zStateDb, pIter->zDataTbl, + zCollist, pIter->zDataTbl, zCollist, zLimit ); } @@ -162114,7 +172881,9 @@ static int rbuObjIterPrepareAll( sqlite3_free(zWhere); sqlite3_free(zBind); }else{ - int bRbuRowid = (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE); + int bRbuRowid = (pIter->eType==RBU_PK_VTAB) + ||(pIter->eType==RBU_PK_NONE) + ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)); const char *zTbl = pIter->zTbl; /* Table this step applies to */ const char *zWrite; /* Imposter table name */ @@ -162141,8 +172910,10 @@ static int rbuObjIterPrepareAll( ); } - /* Create the DELETE statement to write to the target PK b-tree */ - if( p->rc==SQLITE_OK ){ + /* Create the DELETE statement to write to the target PK b-tree. + ** Because it only performs INSERT operations, this is not required for + ** an rbu vacuum handle. */ + if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz, sqlite3_mprintf( "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere @@ -162150,7 +172921,7 @@ static int rbuObjIterPrepareAll( ); } - if( pIter->abIndexed ){ + if( rbuIsVacuum(p)==0 && pIter->abIndexed ){ const char *zRbuRowid = ""; if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zRbuRowid = ", rbu_rowid"; @@ -162168,17 +172939,17 @@ static int rbuObjIterPrepareAll( rbuMPrintfExec(p, p->dbMain, "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" " "BEGIN " - " SELECT rbu_tmp_insert(2, %s);" + " SELECT rbu_tmp_insert(3, %s);" "END;" "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" " "BEGIN " - " SELECT rbu_tmp_insert(2, %s);" + " SELECT rbu_tmp_insert(3, %s);" "END;" "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" " "BEGIN " - " SELECT rbu_tmp_insert(3, %s);" + " SELECT rbu_tmp_insert(4, %s);" "END;", zWrite, zTbl, zOldlist, zWrite, zTbl, zOldlist, @@ -162200,10 +172971,16 @@ static int rbuObjIterPrepareAll( /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ + const char *zRbuRowid = ""; + if( bRbuRowid ){ + zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; + } p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, sqlite3_mprintf( - "SELECT %s, rbu_control%s FROM '%q'%s", - zCollist, (bRbuRowid ? ", rbu_rowid" : ""), + "SELECT %s,%s rbu_control%s FROM '%q'%s", + zCollist, + (rbuIsVacuum(p) ? "0 AS " : ""), + zRbuRowid, pIter->zDataTbl, zLimit ) ); @@ -162298,11 +173075,15 @@ static int rbuGetUpdateStmt( return p->rc; } -static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){ +static sqlite3 *rbuOpenDbhandle( + sqlite3rbu *p, + const char *zName, + int bUseVfs +){ sqlite3 *db = 0; if( p->rc==SQLITE_OK ){ const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI; - p->rc = sqlite3_open_v2(zName, &db, flags, p->zVfsName); + p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0); if( p->rc ){ p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); sqlite3_close(db); @@ -162312,17 +173093,113 @@ static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){ return db; } +/* +** Free an RbuState object allocated by rbuLoadState(). +*/ +static void rbuFreeState(RbuState *p){ + if( p ){ + sqlite3_free(p->zTbl); + sqlite3_free(p->zIdx); + sqlite3_free(p); + } +} + +/* +** Allocate an RbuState object and load the contents of the rbu_state +** table into it. Return a pointer to the new object. It is the +** responsibility of the caller to eventually free the object using +** sqlite3_free(). +** +** If an error occurs, leave an error code and message in the rbu handle +** and return NULL. +*/ +static RbuState *rbuLoadState(sqlite3rbu *p){ + RbuState *pRet = 0; + sqlite3_stmt *pStmt = 0; + int rc; + int rc2; + + pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState)); + if( pRet==0 ) return 0; + + rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb) + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + switch( sqlite3_column_int(pStmt, 0) ){ + case RBU_STATE_STAGE: + pRet->eStage = sqlite3_column_int(pStmt, 1); + if( pRet->eStage!=RBU_STAGE_OAL + && pRet->eStage!=RBU_STAGE_MOVE + && pRet->eStage!=RBU_STAGE_CKPT + ){ + p->rc = SQLITE_CORRUPT; + } + break; + + case RBU_STATE_TBL: + pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); + break; + + case RBU_STATE_IDX: + pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); + break; + + case RBU_STATE_ROW: + pRet->nRow = sqlite3_column_int(pStmt, 1); + break; + + case RBU_STATE_PROGRESS: + pRet->nProgress = sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_CKPT: + pRet->iWalCksum = sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_COOKIE: + pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_OALSZ: + pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_PHASEONESTEP: + pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); + break; + + default: + rc = SQLITE_CORRUPT; + break; + } + } + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + + p->rc = rc; + return pRet; +} + + /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ -static void rbuOpenDatabase(sqlite3rbu *p){ - assert( p->rc==SQLITE_OK ); - assert( p->dbMain==0 && p->dbRbu==0 ); +static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ + assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); + assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); - p->eStage = 0; - p->dbMain = rbuOpenDbhandle(p, p->zTarget); - p->dbRbu = rbuOpenDbhandle(p, p->zRbu); + /* Open the RBU database */ + p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); + + if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ + sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); + if( p->zState==0 ){ + const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); + p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); + } + } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ @@ -162333,6 +173210,105 @@ static void rbuOpenDatabase(sqlite3rbu *p){ memcpy(p->zStateDb, "main", 4); } +#if 0 + if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ + p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0); + } +#endif + + /* If it has not already been created, create the rbu_state table */ + rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb); + +#if 0 + if( rbuIsVacuum(p) ){ + if( p->rc==SQLITE_OK ){ + int rc2; + int bOk = 0; + sqlite3_stmt *pCnt = 0; + p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg, + "SELECT count(*) FROM stat.sqlite_master" + ); + if( p->rc==SQLITE_OK + && sqlite3_step(pCnt)==SQLITE_ROW + && 1==sqlite3_column_int(pCnt, 0) + ){ + bOk = 1; + } + rc2 = sqlite3_finalize(pCnt); + if( p->rc==SQLITE_OK ) p->rc = rc2; + + if( p->rc==SQLITE_OK && bOk==0 ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("invalid state database"); + } + + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); + } + } + } +#endif + + if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ + int bOpen = 0; + int rc; + p->nRbu = 0; + p->pRbuFd = 0; + rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); + if( rc!=SQLITE_NOTFOUND ) p->rc = rc; + if( p->eStage>=RBU_STAGE_MOVE ){ + bOpen = 1; + }else{ + RbuState *pState = rbuLoadState(p); + if( pState ){ + bOpen = (pState->eStage>=RBU_STAGE_MOVE); + rbuFreeState(pState); + } + } + if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1); + } + + p->eStage = 0; + if( p->rc==SQLITE_OK && p->dbMain==0 ){ + if( !rbuIsVacuum(p) ){ + p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1); + }else if( p->pRbuFd->pWalFd ){ + if( pbRetry ){ + p->pRbuFd->bNolock = 0; + sqlite3_close(p->dbRbu); + sqlite3_close(p->dbMain); + p->dbMain = 0; + p->dbRbu = 0; + *pbRetry = 1; + return; + } + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database"); + }else{ + char *zTarget; + char *zExtra = 0; + if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){ + zExtra = &p->zRbu[5]; + while( *zExtra ){ + if( *zExtra++=='?' ) break; + } + if( *zExtra=='\0' ) zExtra = 0; + } + + zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", + sqlite3_db_filename(p->dbRbu, "main"), + (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra) + ); + + if( zTarget==0 ){ + p->rc = SQLITE_NOMEM; + return; + } + p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1); + sqlite3_free(zTarget); + } + } + if( p->rc==SQLITE_OK ){ p->rc = sqlite3_create_function(p->dbMain, "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0 @@ -162347,7 +173323,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_create_function(p->dbRbu, - "rbu_target_name", 1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 + "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 ); } @@ -162396,9 +173372,9 @@ static void rbuFileSuffix3(const char *zBase, char *z){ #endif { int i, sz; - sz = sqlite3Strlen30(z); + sz = (int)strlen(z)&0xffffff; for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} - if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); + if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } #endif } @@ -162486,16 +173462,35 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; } - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK && p->nFrame>0 ){ p->eStage = RBU_STAGE_CKPT; p->nStep = (pState ? pState->nRow : 0); p->aBuf = rbuMalloc(p, p->pgsz); p->iWalCksum = rbuShmChecksum(p); } - if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){ - p->rc = SQLITE_DONE; - p->eStage = RBU_STAGE_DONE; + if( p->rc==SQLITE_OK ){ + if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){ + p->rc = SQLITE_DONE; + p->eStage = RBU_STAGE_DONE; + }else{ + int nSectorSize; + sqlite3_file *pDb = p->pTargetFd->pReal; + sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal; + assert( p->nPagePerSector==0 ); + nSectorSize = pDb->pMethods->xSectorSize(pDb); + if( nSectorSize>p->pgsz ){ + p->nPagePerSector = nSectorSize / p->pgsz; + }else{ + p->nPagePerSector = 1; + } + + /* Call xSync() on the wal file. This causes SQLite to sync the + ** directory in which the target database and the wal file reside, in + ** case it has not been synced since the rename() call in + ** rbuMoveOalFile(). */ + p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL); + } } } @@ -162517,7 +173512,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ if( pRbu->nFrame==pRbu->nFrameAlloc ){ int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2; RbuFrame *aNew; - aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame)); + aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame)); if( aNew==0 ) return SQLITE_NOMEM; pRbu->aFrame = aNew; pRbu->nFrameAlloc = nNew; @@ -162582,7 +173577,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){ if( nChar==0 ){ return 0; } - zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) ); + zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) ); if( zWideFilename==0 ){ return 0; } @@ -162606,9 +173601,15 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){ */ static void rbuMoveOalFile(sqlite3rbu *p){ const char *zBase = sqlite3_db_filename(p->dbMain, "main"); + const char *zMove = zBase; + char *zOal; + char *zWal; - char *zWal = sqlite3_mprintf("%s-wal", zBase); - char *zOal = sqlite3_mprintf("%s-oal", zBase); + if( rbuIsVacuum(p) ){ + zMove = sqlite3_db_filename(p->dbRbu, "main"); + } + zOal = sqlite3_mprintf("%s-oal", zMove); + zWal = sqlite3_mprintf("%s-wal", zMove); assert( p->eStage==RBU_STAGE_MOVE ); assert( p->rc==SQLITE_OK && p->zErrmsg==0 ); @@ -162629,8 +173630,8 @@ static void rbuMoveOalFile(sqlite3rbu *p){ /* Re-open the databases. */ rbuObjIterFinalize(&p->objiter); - sqlite3_close(p->dbMain); sqlite3_close(p->dbRbu); + sqlite3_close(p->dbMain); p->dbMain = 0; p->dbRbu = 0; @@ -162662,7 +173663,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){ #endif if( p->rc==SQLITE_OK ){ - rbuOpenDatabase(p); + rbuOpenDatabase(p, 0); rbuSetupCheckpoint(p, 0); } } @@ -162696,14 +173697,12 @@ static int rbuStepType(sqlite3rbu *p, const char **pzMask){ switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){ case SQLITE_INTEGER: { int iVal = sqlite3_column_int(p->objiter.pSelect, iCol); - if( iVal==0 ){ - res = RBU_INSERT; - }else if( iVal==1 ){ - res = RBU_DELETE; - }else if( iVal==2 ){ - res = RBU_IDX_DELETE; - }else if( iVal==3 ){ - res = RBU_IDX_INSERT; + switch( iVal ){ + case 0: res = RBU_INSERT; break; + case 1: res = RBU_DELETE; break; + case 2: res = RBU_REPLACE; break; + case 3: res = RBU_IDX_DELETE; break; + case 4: res = RBU_IDX_INSERT; break; } break; } @@ -162742,6 +173741,83 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){ # define assertColumnName(x,y,z) #endif +/* +** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or +** RBU_IDX_DELETE. This function performs the work of a single +** sqlite3rbu_step() call for the type of operation specified by eType. +*/ +static void rbuStepOneOp(sqlite3rbu *p, int eType){ + RbuObjIter *pIter = &p->objiter; + sqlite3_value *pVal; + sqlite3_stmt *pWriter; + int i; + + assert( p->rc==SQLITE_OK ); + assert( eType!=RBU_DELETE || pIter->zIdx==0 ); + assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE + || eType==RBU_INSERT || eType==RBU_IDX_INSERT + ); + + /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE + ** statement below does actually delete a row, nPhaseOneStep will be + ** incremented by the same amount when SQL function rbu_tmp_insert() + ** is invoked by the trigger. */ + if( eType==RBU_DELETE ){ + p->nPhaseOneStep -= p->objiter.nIndex; + } + + if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){ + pWriter = pIter->pDelete; + }else{ + pWriter = pIter->pInsert; + } + + for(i=0; inCol; i++){ + /* If this is an INSERT into a table b-tree and the table has an + ** explicit INTEGER PRIMARY KEY, check that this is not an attempt + ** to write a NULL into the IPK column. That is not permitted. */ + if( eType==RBU_INSERT + && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] + && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL + ){ + p->rc = SQLITE_MISMATCH; + p->zErrmsg = sqlite3_mprintf("datatype mismatch"); + return; + } + + if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){ + continue; + } + + pVal = sqlite3_column_value(pIter->pSelect, i); + p->rc = sqlite3_bind_value(pWriter, i+1, pVal); + if( p->rc ) return; + } + if( pIter->zIdx==0 ){ + if( pIter->eType==RBU_PK_VTAB + || pIter->eType==RBU_PK_NONE + || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) + ){ + /* For a virtual table, or a table with no primary key, the + ** SELECT statement is: + ** + ** SELECT , rbu_control, rbu_rowid FROM .... + ** + ** Hence column_value(pIter->nCol+1). + */ + assertColumnName(pIter->pSelect, pIter->nCol+1, + rbuIsVacuum(p) ? "rowid" : "rbu_rowid" + ); + pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1); + p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal); + } + } + if( p->rc==SQLITE_OK ){ + sqlite3_step(pWriter); + p->rc = resetAndCollectError(pWriter, &p->zErrmsg); + } +} + /* ** This function does the work for an sqlite3rbu_step() call. ** @@ -162756,78 +173832,36 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){ static int rbuStep(sqlite3rbu *p){ RbuObjIter *pIter = &p->objiter; const char *zMask = 0; - int i; int eType = rbuStepType(p, &zMask); if( eType ){ + assert( eType==RBU_INSERT || eType==RBU_DELETE + || eType==RBU_REPLACE || eType==RBU_IDX_DELETE + || eType==RBU_IDX_INSERT || eType==RBU_UPDATE + ); assert( eType!=RBU_UPDATE || pIter->zIdx==0 ); - if( pIter->zIdx==0 && eType==RBU_IDX_DELETE ){ + if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){ rbuBadControlError(p); } - else if( - eType==RBU_INSERT - || eType==RBU_DELETE - || eType==RBU_IDX_DELETE - || eType==RBU_IDX_INSERT - ){ - sqlite3_value *pVal; - sqlite3_stmt *pWriter; - - assert( eType!=RBU_UPDATE ); - assert( eType!=RBU_DELETE || pIter->zIdx==0 ); - - if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){ - pWriter = pIter->pDelete; - }else{ - pWriter = pIter->pInsert; + else if( eType==RBU_REPLACE ){ + if( pIter->zIdx==0 ){ + p->nPhaseOneStep += p->objiter.nIndex; + rbuStepOneOp(p, RBU_DELETE); } - - for(i=0; inCol; i++){ - /* If this is an INSERT into a table b-tree and the table has an - ** explicit INTEGER PRIMARY KEY, check that this is not an attempt - ** to write a NULL into the IPK column. That is not permitted. */ - if( eType==RBU_INSERT - && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] - && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL - ){ - p->rc = SQLITE_MISMATCH; - p->zErrmsg = sqlite3_mprintf("datatype mismatch"); - goto step_out; - } - - if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){ - continue; - } - - pVal = sqlite3_column_value(pIter->pSelect, i); - p->rc = sqlite3_bind_value(pWriter, i+1, pVal); - if( p->rc ) goto step_out; - } - if( pIter->zIdx==0 - && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) - ){ - /* For a virtual table, or a table with no primary key, the - ** SELECT statement is: - ** - ** SELECT , rbu_control, rbu_rowid FROM .... - ** - ** Hence column_value(pIter->nCol+1). - */ - assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid"); - pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1); - p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal); - } - if( p->rc==SQLITE_OK ){ - sqlite3_step(pWriter); - p->rc = resetAndCollectError(pWriter, &p->zErrmsg); - } - }else{ + if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT); + } + else if( eType!=RBU_UPDATE ){ + rbuStepOneOp(p, eType); + } + else{ sqlite3_value *pVal; sqlite3_stmt *pUpdate = 0; assert( eType==RBU_UPDATE ); + p->nPhaseOneStep -= p->objiter.nIndex; rbuGetUpdateStmt(p, pIter, zMask, &pUpdate); if( pUpdate ){ + int i; for(i=0; p->rc==SQLITE_OK && inCol; i++){ char c = zMask[pIter->aiSrcOrder[i]]; pVal = sqlite3_column_value(pIter->pSelect, i); @@ -162850,20 +173884,23 @@ static int rbuStep(sqlite3rbu *p){ } } } - - step_out: return p->rc; } /* ** Increment the schema cookie of the main database opened by p->dbMain. +** +** Or, if this is an RBU vacuum, set the schema cookie of the main db +** opened by p->dbMain to one more than the schema cookie of the main +** db opened by p->dbRbu. */ static void rbuIncrSchemaCookie(sqlite3rbu *p){ if( p->rc==SQLITE_OK ){ + sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain); int iCookie = 1000000; sqlite3_stmt *pStmt; - p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, + p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, "PRAGMA schema_version" ); if( p->rc==SQLITE_OK ){ @@ -162891,6 +173928,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){ static void rbuSaveState(sqlite3rbu *p, int eStage){ if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){ sqlite3_stmt *pInsert = 0; + rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd); int rc; assert( p->zErrmsg==0 ); @@ -162904,6 +173942,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ "(%d, %d), " "(%d, %lld), " "(%d, %lld), " + "(%d, %lld), " "(%d, %lld) ", p->zStateDb, RBU_STATE_STAGE, eStage, @@ -162912,8 +173951,9 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ RBU_STATE_ROW, p->nStep, RBU_STATE_PROGRESS, p->nProgress, RBU_STATE_CKPT, p->iWalCksum, - RBU_STATE_COOKIE, (i64)p->pTargetFd->iCookie, - RBU_STATE_OALSZ, p->iOalSz + RBU_STATE_COOKIE, (i64)pFd->iCookie, + RBU_STATE_OALSZ, p->iOalSz, + RBU_STATE_PHASEONESTEP, p->nPhaseOneStep ) ); assert( pInsert==0 || rc==SQLITE_OK ); @@ -162927,21 +173967,116 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ } +/* +** The second argument passed to this function is the name of a PRAGMA +** setting - "page_size", "auto_vacuum", "user_version" or "application_id". +** This function executes the following on sqlite3rbu.dbRbu: +** +** "PRAGMA main.$zPragma" +** +** where $zPragma is the string passed as the second argument, then +** on sqlite3rbu.dbMain: +** +** "PRAGMA main.$zPragma = $val" +** +** where $val is the value returned by the first PRAGMA invocation. +** +** In short, it copies the value of the specified PRAGMA setting from +** dbRbu to dbMain. +*/ +static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){ + if( p->rc==SQLITE_OK ){ + sqlite3_stmt *pPragma = 0; + p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.%s", zPragma) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){ + p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d", + zPragma, sqlite3_column_int(pPragma, 0) + ); + } + rbuFinalize(p, pPragma); + } +} + +/* +** The RBU handle passed as the only argument has just been opened and +** the state database is empty. If this RBU handle was opened for an +** RBU vacuum operation, create the schema in the target db. +*/ +static void rbuCreateTargetSchema(sqlite3rbu *p){ + sqlite3_stmt *pSql = 0; + sqlite3_stmt *pInsert = 0; + + assert( rbuIsVacuum(p) ); + p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg); + if( p->rc==SQLITE_OK ){ + p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, + "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0" + " AND name!='sqlite_sequence' " + " ORDER BY type DESC" + ); + } + + while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){ + const char *zSql = (const char*)sqlite3_column_text(pSql, 0); + p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg); + } + rbuFinalize(p, pSql); + if( p->rc!=SQLITE_OK ) return; + + if( p->rc==SQLITE_OK ){ + p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, + "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL" + ); + } + + if( p->rc==SQLITE_OK ){ + p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, + "INSERT INTO sqlite_master VALUES(?,?,?,?,?)" + ); + } + + while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){ + int i; + for(i=0; i<5; i++){ + sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i)); + } + sqlite3_step(pInsert); + p->rc = sqlite3_reset(pInsert); + } + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg); + } + + rbuFinalize(p, pSql); + rbuFinalize(p, pInsert); +} + /* ** Step the RBU object. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){ +SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){ if( p ){ switch( p->eStage ){ case RBU_STAGE_OAL: { RbuObjIter *pIter = &p->objiter; + + /* If this is an RBU vacuum operation and the state table was empty + ** when this handle was opened, create the target database schema. */ + if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){ + rbuCreateTargetSchema(p); + rbuCopyPragma(p, "user_version"); + rbuCopyPragma(p, "application_id"); + } + while( p->rc==SQLITE_OK && pIter->zTbl ){ if( pIter->bCleanup ){ /* Clean up the rbu_tmp_xxx table for the previous table. It ** cannot be dropped as there are currently active SQL statements. ** But the contents can be deleted. */ - if( pIter->abIndexed ){ + if( rbuIsVacuum(p)==0 && pIter->abIndexed ){ rbuMPrintfExec(p, p->dbRbu, "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl ); @@ -163010,9 +174145,26 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){ p->rc = SQLITE_DONE; } }else{ - RbuFrame *pFrame = &p->aFrame[p->nStep]; - rbuCheckpointFrame(p, pFrame); - p->nStep++; + /* At one point the following block copied a single frame from the + ** wal file to the database file. So that one call to sqlite3rbu_step() + ** checkpointed a single frame. + ** + ** However, if the sector-size is larger than the page-size, and the + ** application calls sqlite3rbu_savestate() or close() immediately + ** after this step, then rbu_step() again, then a power failure occurs, + ** then the database page written here may be damaged. Work around + ** this by checkpointing frames until the next page in the aFrame[] + ** lies on a different disk sector to the current one. */ + u32 iSector; + do{ + RbuFrame *pFrame = &p->aFrame[p->nStep]; + iSector = (pFrame->iDbPage-1) / p->nPagePerSector; + rbuCheckpointFrame(p, pFrame); + p->nStep++; + }while( p->nStepnFrame + && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector) + && p->rc==SQLITE_OK + ); } p->nProgress++; } @@ -163028,90 +174180,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){ } } -/* -** Free an RbuState object allocated by rbuLoadState(). -*/ -static void rbuFreeState(RbuState *p){ - if( p ){ - sqlite3_free(p->zTbl); - sqlite3_free(p->zIdx); - sqlite3_free(p); - } -} - -/* -** Allocate an RbuState object and load the contents of the rbu_state -** table into it. Return a pointer to the new object. It is the -** responsibility of the caller to eventually free the object using -** sqlite3_free(). -** -** If an error occurs, leave an error code and message in the rbu handle -** and return NULL. -*/ -static RbuState *rbuLoadState(sqlite3rbu *p){ - RbuState *pRet = 0; - sqlite3_stmt *pStmt = 0; - int rc; - int rc2; - - pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState)); - if( pRet==0 ) return 0; - - rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, - sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb) - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - switch( sqlite3_column_int(pStmt, 0) ){ - case RBU_STATE_STAGE: - pRet->eStage = sqlite3_column_int(pStmt, 1); - if( pRet->eStage!=RBU_STAGE_OAL - && pRet->eStage!=RBU_STAGE_MOVE - && pRet->eStage!=RBU_STAGE_CKPT - ){ - p->rc = SQLITE_CORRUPT; - } - break; - - case RBU_STATE_TBL: - pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); - break; - - case RBU_STATE_IDX: - pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); - break; - - case RBU_STATE_ROW: - pRet->nRow = sqlite3_column_int(pStmt, 1); - break; - - case RBU_STATE_PROGRESS: - pRet->nProgress = sqlite3_column_int64(pStmt, 1); - break; - - case RBU_STATE_CKPT: - pRet->iWalCksum = sqlite3_column_int64(pStmt, 1); - break; - - case RBU_STATE_COOKIE: - pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); - break; - - case RBU_STATE_OALSZ: - pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1); - break; - - default: - rc = SQLITE_CORRUPT; - break; - } - } - rc2 = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) rc = rc2; - - p->rc = rc; - return pRet; -} - /* ** Compare strings z1 and z2, returning 0 if they are identical, or non-zero ** otherwise. Either or both argument may be NULL. Two NULL values are @@ -163193,6 +174261,7 @@ static void rbuCreateVfs(sqlite3rbu *p){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd); assert( pVfs ); p->zVfsName = pVfs->zName; + ((rbu_vfs*)pVfs)->pRbu = p; } } @@ -163208,19 +174277,111 @@ static void rbuDeleteVfs(sqlite3rbu *p){ } /* -** Open and return a new RBU handle. +** This user-defined SQL function is invoked with a single argument - the +** name of a table expected to appear in the target database. It returns +** the number of auxilliary indexes on the table. */ -SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( +static void rbuIndexCntFunc( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +){ + sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx); + sqlite3_stmt *pStmt = 0; + char *zErrmsg = 0; + int rc; + + assert( nVal==1 ); + + rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, + sqlite3_mprintf("SELECT count(*) FROM sqlite_master " + "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0])) + ); + if( rc!=SQLITE_OK ){ + sqlite3_result_error(pCtx, zErrmsg, -1); + }else{ + int nIndex = 0; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + nIndex = sqlite3_column_int(pStmt, 0); + } + rc = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ){ + sqlite3_result_int(pCtx, nIndex); + }else{ + sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1); + } + } + + sqlite3_free(zErrmsg); +} + +/* +** If the RBU database contains the rbu_count table, use it to initialize +** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table +** is assumed to contain the same columns as: +** +** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID; +** +** There should be one row in the table for each data_xxx table in the +** database. The 'tbl' column should contain the name of a data_xxx table, +** and the cnt column the number of rows it contains. +** +** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt +** for all rows in the rbu_count table, where nIndex is the number of +** indexes on the corresponding target database table. +*/ +static void rbuInitPhaseOneSteps(sqlite3rbu *p){ + if( p->rc==SQLITE_OK ){ + sqlite3_stmt *pStmt = 0; + int bExists = 0; /* True if rbu_count exists */ + + p->nPhaseOneStep = -1; + + p->rc = sqlite3_create_function(p->dbRbu, + "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0 + ); + + /* Check for the rbu_count table. If it does not exist, or if an error + ** occurs, nPhaseOneStep will be left set to -1. */ + if( p->rc==SQLITE_OK ){ + p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'" + ); + } + if( p->rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + bExists = 1; + } + p->rc = sqlite3_finalize(pStmt); + } + + if( p->rc==SQLITE_OK && bExists ){ + p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))" + "FROM rbu_count" + ); + if( p->rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0); + } + p->rc = sqlite3_finalize(pStmt); + } + } + } +} + + +static sqlite3rbu *openRbuHandle( const char *zTarget, const char *zRbu, const char *zState ){ sqlite3rbu *p; - int nTarget = strlen(zTarget); - int nRbu = strlen(zRbu); - int nState = zState ? strlen(zState) : 0; + size_t nTarget = zTarget ? strlen(zTarget) : 0; + size_t nRbu = strlen(zRbu); + size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1; - p = (sqlite3rbu*)sqlite3_malloc(sizeof(sqlite3rbu)+nTarget+1+nRbu+1+nState+1); + p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; @@ -163228,21 +174389,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( memset(p, 0, sizeof(sqlite3rbu)); rbuCreateVfs(p); - /* Open the target database */ + /* Open the target, RBU and state databases */ if( p->rc==SQLITE_OK ){ - p->zTarget = (char*)&p[1]; - memcpy(p->zTarget, zTarget, nTarget+1); - p->zRbu = &p->zTarget[nTarget+1]; + char *pCsr = (char*)&p[1]; + int bRetry = 0; + if( zTarget ){ + p->zTarget = pCsr; + memcpy(p->zTarget, zTarget, nTarget+1); + pCsr += nTarget+1; + } + p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); + pCsr += nRbu+1; if( zState ){ - p->zState = &p->zRbu[nRbu+1]; - memcpy(p->zState, zState, nState+1); + p->zState = rbuMPrintf(p, "%s", zState); } - rbuOpenDatabase(p); - } - /* If it has not already been created, create the rbu_state table */ - rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb); + /* If the first attempt to open the database file fails and the bRetry + ** flag it set, this means that the db was not opened because it seemed + ** to be a wal-mode db. But, this may have happened due to an earlier + ** RBU vacuum operation leaving an old wal file in the directory. + ** If this is the case, it will have been checkpointed and deleted + ** when the handle was closed and a second attempt to open the + ** database may succeed. */ + rbuOpenDatabase(p, &bRetry); + if( bRetry ){ + rbuOpenDatabase(p, 0); + } + } if( p->rc==SQLITE_OK ){ pState = rbuLoadState(p); @@ -163251,9 +174425,11 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( if( pState->eStage==0 ){ rbuDeleteOalFile(p); + rbuInitPhaseOneSteps(p); p->eStage = RBU_STAGE_OAL; }else{ p->eStage = pState->eStage; + p->nPhaseOneStep = pState->nPhaseOneStep; } p->nProgress = pState->nProgress; p->iOalSz = pState->iOalSz; @@ -163271,38 +174447,27 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( } } - if( p->rc==SQLITE_OK + if( p->rc==SQLITE_OK && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE) - && pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie - ){ - /* At this point (pTargetFd->iCookie) contains the value of the - ** change-counter cookie (the thing that gets incremented when a - ** transaction is committed in rollback mode) currently stored on - ** page 1 of the database file. */ - p->rc = SQLITE_BUSY; - p->zErrmsg = sqlite3_mprintf("database modified during rbu update"); + && pState->eStage!=0 + ){ + rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd); + if( pFd->iCookie!=pState->iCookie ){ + /* At this point (pTargetFd->iCookie) contains the value of the + ** change-counter cookie (the thing that gets incremented when a + ** transaction is committed in rollback mode) currently stored on + ** page 1 of the database file. */ + p->rc = SQLITE_BUSY; + p->zErrmsg = sqlite3_mprintf("database modified during rbu %s", + (rbuIsVacuum(p) ? "vacuum" : "update") + ); + } } if( p->rc==SQLITE_OK ){ if( p->eStage==RBU_STAGE_OAL ){ sqlite3 *db = p->dbMain; - - /* Open transactions both databases. The *-oal file is opened or - ** created at this point. */ - p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); - if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); - } - - /* Check if the main database is a zipvfs db. If it is, set the upper - ** level pager to use "journal_mode=off". This prevents it from - ** generating a large journal using a temp file. */ - if( p->rc==SQLITE_OK ){ - int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); - if( frc==SQLITE_OK ){ - p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg); - } - } + p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg); /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ @@ -163313,12 +174478,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( ** update finished. */ if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){ p->rc = SQLITE_DONE; - } + p->eStage = RBU_STAGE_DONE; + }else{ + if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){ + rbuCopyPragma(p, "page_size"); + rbuCopyPragma(p, "auto_vacuum"); + } - if( p->rc==SQLITE_OK ){ - rbuSetupOal(p, pState); - } + /* Open transactions both databases. The *-oal file is opened or + ** created at this point. */ + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); + } + /* Check if the main database is a zipvfs db. If it is, set the upper + ** level pager to use "journal_mode=off". This prevents it from + ** generating a large journal using a temp file. */ + if( p->rc==SQLITE_OK ){ + int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); + if( frc==SQLITE_OK ){ + p->rc = sqlite3_exec( + db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg); + } + } + + if( p->rc==SQLITE_OK ){ + rbuSetupOal(p, pState); + } + } }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ @@ -163336,11 +174523,49 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( return p; } +/* +** Allocate and return an RBU handle with all fields zeroed except for the +** error code, which is set to SQLITE_MISUSE. +*/ +static sqlite3rbu *rbuMisuseError(void){ + sqlite3rbu *pRet; + pRet = sqlite3_malloc64(sizeof(sqlite3rbu)); + if( pRet ){ + memset(pRet, 0, sizeof(sqlite3rbu)); + pRet->rc = SQLITE_MISUSE; + } + return pRet; +} + +/* +** Open and return a new RBU handle. +*/ +SQLITE_API sqlite3rbu *sqlite3rbu_open( + const char *zTarget, + const char *zRbu, + const char *zState +){ + if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } + /* TODO: Check that zTarget and zRbu are non-NULL */ + return openRbuHandle(zTarget, zRbu, zState); +} + +/* +** Open a handle to begin or resume an RBU VACUUM operation. +*/ +SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( + const char *zTarget, + const char *zState +){ + if( zTarget==0 ){ return rbuMisuseError(); } + /* TODO: Check that both arguments are non-NULL */ + return openRbuHandle(0, zTarget, zState); +} /* ** Return the database handle used by pRbu. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){ +SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){ sqlite3 *db = 0; if( pRbu ){ db = (bRbu ? pRbu->dbRbu : pRbu->dbMain); @@ -163356,8 +174581,8 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){ */ static void rbuEditErrmsg(sqlite3rbu *p){ if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){ - int i; - int nErrmsg = strlen(p->zErrmsg); + unsigned int i; + size_t nErrmsg = strlen(p->zErrmsg); for(i=0; i<(nErrmsg-8); i++){ if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){ int nDel = 8; @@ -163372,7 +174597,7 @@ static void rbuEditErrmsg(sqlite3rbu *p){ /* ** Close the RBU handle. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ +SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ int rc; if( p ){ @@ -163381,6 +174606,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg); } + /* Sync the db file if currently doing an incremental checkpoint */ + if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){ + sqlite3_file *pDb = p->pTargetFd->pReal; + p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL); + } + rbuSaveState(p, p->eStage); if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){ @@ -163390,16 +174621,32 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ /* Close any open statement handles. */ rbuObjIterFinalize(&p->objiter); + /* If this is an RBU vacuum handle and the vacuum has either finished + ** successfully or encountered an error, delete the contents of the + ** state table. This causes the next call to sqlite3rbu_vacuum() + ** specifying the current target and state databases to start a new + ** vacuum from scratch. */ + if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){ + int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0); + if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2; + } + /* Close the open database handle and VFS object. */ - sqlite3_close(p->dbMain); sqlite3_close(p->dbRbu); + sqlite3_close(p->dbMain); + assert( p->szTemp==0 ); rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; - *pzErrmsg = p->zErrmsg; + if( pzErrmsg ){ + *pzErrmsg = p->zErrmsg; + }else{ + sqlite3_free(p->zErrmsg); + } + sqlite3_free(p->zState); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; @@ -163413,13 +174660,79 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ ** updates) that have been performed on the target database since the ** current RBU update was started. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu){ +SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){ return pRbu->nProgress; } -SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){ +/* +** Return permyriadage progress indications for the two main stages of +** an RBU update. +*/ +SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){ + const int MAX_PROGRESS = 10000; + switch( p->eStage ){ + case RBU_STAGE_OAL: + if( p->nPhaseOneStep>0 ){ + *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep); + }else{ + *pnOne = -1; + } + *pnTwo = 0; + break; + + case RBU_STAGE_MOVE: + *pnOne = MAX_PROGRESS; + *pnTwo = 0; + break; + + case RBU_STAGE_CKPT: + *pnOne = MAX_PROGRESS; + *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame); + break; + + case RBU_STAGE_DONE: + *pnOne = MAX_PROGRESS; + *pnTwo = MAX_PROGRESS; + break; + + default: + assert( 0 ); + } +} + +/* +** Return the current state of the RBU vacuum or update operation. +*/ +SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){ + int aRes[] = { + 0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE, + 0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE + }; + + assert( RBU_STAGE_OAL==1 ); + assert( RBU_STAGE_MOVE==2 ); + assert( RBU_STAGE_CKPT==4 ); + assert( RBU_STAGE_DONE==5 ); + assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL ); + assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE ); + assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT ); + assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE ); + + if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){ + return SQLITE_RBU_STATE_ERROR; + }else{ + assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE ); + assert( p->eStage==RBU_STAGE_OAL + || p->eStage==RBU_STAGE_MOVE + || p->eStage==RBU_STAGE_CKPT + || p->eStage==RBU_STAGE_DONE + ); + return aRes[p->eStage]; + } +} + +SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ int rc = p->rc; - if( rc==SQLITE_DONE ) return SQLITE_OK; assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE ); @@ -163428,6 +174741,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){ if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0); } + /* Sync the db file */ + if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){ + sqlite3_file *pDb = p->pTargetFd->pReal; + rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL); + } + p->rc = rc; rbuSaveState(p, p->eStage); rc = p->rc; @@ -163503,6 +174822,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){ */ static void rbuUnlockShm(rbu_file *p){ + assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); if( p->pRbu ){ int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock; int i; @@ -163515,6 +174835,18 @@ static void rbuUnlockShm(rbu_file *p){ } } +/* +*/ +static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){ + sqlite3rbu *pRbu = pFd->pRbu; + i64 nDiff = nNew - pFd->sz; + pRbu->szTemp += nDiff; + pFd->sz = nNew; + assert( pRbu->szTemp>=0 ); + if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL; + return SQLITE_OK; +} + /* ** Close an rbu file. */ @@ -163540,6 +174872,9 @@ static int rbuVfsClose(sqlite3_file *pFile){ rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } + else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ + rbuUpdateTempSize(p, 0); + } /* Close the underlying file handle */ rc = p->pReal->pMethods->xClose(p->pReal); @@ -163558,6 +174893,22 @@ static u32 rbuGetU32(u8 *aBuf){ + ((u32)aBuf[3]); } +/* +** Write an unsigned 32-bit value in big-endian format to the supplied +** buffer. +*/ +static void rbuPutU32(u8 *aBuf, u32 iVal){ + aBuf[0] = (iVal >> 24) & 0xFF; + aBuf[1] = (iVal >> 16) & 0xFF; + aBuf[2] = (iVal >> 8) & 0xFF; + aBuf[3] = (iVal >> 0) & 0xFF; +} + +static void rbuPutU16(u8 *aBuf, u16 iVal){ + aBuf[0] = (iVal >> 8) & 0xFF; + aBuf[1] = (iVal >> 0) & 0xFF; +} + /* ** Read data from an rbuVfs-file. */ @@ -163583,6 +174934,35 @@ static int rbuVfsRead( memset(zBuf, 0, iAmt); }else{ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); +#if 1 + /* If this is being called to read the first page of the target + ** database as part of an rbu vacuum operation, synthesize the + ** contents of the first page if it does not yet exist. Otherwise, + ** SQLite will not check for a *-wal file. */ + if( pRbu && rbuIsVacuum(pRbu) + && rc==SQLITE_IOERR_SHORT_READ && iOfst==0 + && (p->openFlags & SQLITE_OPEN_MAIN_DB) + && pRbu->rc==SQLITE_OK + ){ + sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd; + rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst); + if( rc==SQLITE_OK ){ + u8 *aBuf = (u8*)zBuf; + u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0; + rbuPutU32(&aBuf[52], iRoot); /* largest root page number */ + rbuPutU32(&aBuf[36], 0); /* number of free pages */ + rbuPutU32(&aBuf[32], 0); /* first page on free list trunk */ + rbuPutU32(&aBuf[28], 1); /* size of db file in pages */ + rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1); /* Change counter */ + + if( iAmt>100 ){ + memset(&aBuf[100], 0, iAmt-100); + rbuPutU16(&aBuf[105], iAmt & 0xFFFF); + aBuf[100] = 0x0D; + } + } + } +#endif } if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){ /* These look like magic numbers. But they are stable, as they are part @@ -163612,11 +174992,19 @@ static int rbuVfsWrite( assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); rc = rbuCaptureDbWrite(p->pRbu, iOfst); }else{ - if( pRbu && pRbu->eStage==RBU_STAGE_OAL - && (p->openFlags & SQLITE_OPEN_WAL) - && iOfst>=pRbu->iOalSz - ){ - pRbu->iOalSz = iAmt + iOfst; + if( pRbu ){ + if( pRbu->eStage==RBU_STAGE_OAL + && (p->openFlags & SQLITE_OPEN_WAL) + && iOfst>=pRbu->iOalSz + ){ + pRbu->iOalSz = iAmt + iOfst; + }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){ + i64 szNew = iAmt+iOfst; + if( szNew>p->sz ){ + rc = rbuUpdateTempSize(p, szNew); + if( rc!=SQLITE_OK ) return rc; + } + } } rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){ @@ -163635,6 +175023,10 @@ static int rbuVfsWrite( */ static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ rbu_file *p = (rbu_file*)pFile; + if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ + int rc = rbuUpdateTempSize(p, size); + if( rc!=SQLITE_OK ) return rc; + } return p->pReal->pMethods->xTruncate(p->pReal, size); } @@ -163657,7 +175049,20 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){ */ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ rbu_file *p = (rbu_file *)pFile; - return p->pReal->pMethods->xFileSize(p->pReal, pSize); + int rc; + rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); + + /* If this is an RBU vacuum operation and this is the target database, + ** pretend that it has at least one page. Otherwise, SQLite will not + ** check for the existance of a *-wal file. rbuVfsRead() contains + ** similar logic. */ + if( rc==SQLITE_OK && *pSize==0 + && p->pRbu && rbuIsVacuum(p->pRbu) + && (p->openFlags & SQLITE_OPEN_MAIN_DB) + ){ + *pSize = 1024; + } + return rc; } /* @@ -163669,7 +175074,9 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){ int rc = SQLITE_OK; assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); - if( pRbu && eLock==SQLITE_LOCK_EXCLUSIVE && pRbu->eStage!=RBU_STAGE_DONE ){ + if( eLock==SQLITE_LOCK_EXCLUSIVE + && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE)) + ){ /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this ** prevents it from checkpointing the database from sqlite3_close(). */ rc = SQLITE_BUSY; @@ -163732,6 +175139,12 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){ } return rc; } + else if( op==SQLITE_FCNTL_RBUCNT ){ + sqlite3rbu *pRbu = (sqlite3rbu*)pArg; + pRbu->nRbu++; + pRbu->pRbuFd = p; + p->bNolock = 1; + } rc = xControl(p->pReal, op, pArg); if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ @@ -163821,7 +175234,7 @@ static int rbuVfsShmMap( if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){ if( iRegion<=p->nShm ){ int nByte = (iRegion+1) * sizeof(char*); - char **apNew = (char**)sqlite3_realloc(p->apShm, nByte); + char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); if( apNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -163832,7 +175245,7 @@ static int rbuVfsShmMap( } if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){ - char *pNew = (char*)sqlite3_malloc(szRegion); + char *pNew = (char*)sqlite3_malloc64(szRegion); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -163890,11 +175303,38 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){ 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); + 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 +** the name of the *-wal file this db connection will use. SQLite +** happens to pass a pointer to this buffer when using xAccess() +** or xOpen() to operate on the *-wal file. +*/ +static const char *rbuMainToWal(const char *zName, int flags){ + int n = (int)strlen(zName); + const char *z = &zName[n]; + if( flags & SQLITE_OPEN_URI ){ + int odd = 0; + while( 1 ){ + if( z[0]==0 ){ + odd = 1 - odd; + if( odd && z[1]==0 ) break; + } + z++; + } + z += 2; + }else{ + while( *z==0 ) z++; + } + z += (n + 8 + 1); + return z; +} + /* ** Open an rbu file handle. */ @@ -163930,6 +175370,7 @@ static int rbuVfsOpen( rbu_file *pFd = (rbu_file *)pFile; int rc = SQLITE_OK; const char *zOpen = zName; + int oflags = flags; memset(pFd, 0, sizeof(rbu_file)); pFd->pReal = (sqlite3_file*)&pFd[1]; @@ -163942,23 +175383,7 @@ static int rbuVfsOpen( ** the name of the *-wal file this db connection will use. SQLite ** happens to pass a pointer to this buffer when using xAccess() ** or xOpen() to operate on the *-wal file. */ - int n = strlen(zName); - const char *z = &zName[n]; - if( flags & SQLITE_OPEN_URI ){ - int odd = 0; - while( 1 ){ - if( z[0]==0 ){ - odd = 1 - odd; - if( odd && z[1]==0 ) break; - } - z++; - } - z += 2; - }else{ - while( *z==0 ) z++; - } - z += (n + 8 + 1); - pFd->zWal = z; + pFd->zWal = rbuMainToWal(zName, flags); } else if( flags & SQLITE_OPEN_WAL ){ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName); @@ -163968,10 +175393,17 @@ static int rbuVfsOpen( ** code ensures that the string passed to xOpen() is terminated by a ** pair of '\0' bytes in case the VFS attempts to extract a URI ** parameter from it. */ - int nCopy = strlen(zName); - char *zCopy = sqlite3_malloc(nCopy+2); + const char *zBase = zName; + size_t nCopy; + char *zCopy; + if( rbuIsVacuum(pDb->pRbu) ){ + zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); + zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI); + } + nCopy = strlen(zBase); + zCopy = sqlite3_malloc64(nCopy+2); if( zCopy ){ - memcpy(zCopy, zName, nCopy); + memcpy(zCopy, zBase, nCopy); zCopy[nCopy-3] = 'o'; zCopy[nCopy] = '\0'; zCopy[nCopy+1] = '\0'; @@ -163984,10 +175416,21 @@ static int rbuVfsOpen( pDb->pWalFd = pFd; } } + }else{ + pFd->pRbu = pRbuVfs->pRbu; + } + + if( oflags & SQLITE_OPEN_MAIN_DB + && sqlite3_uri_boolean(zName, "rbu_memory", 0) + ){ + assert( oflags & SQLITE_OPEN_MAIN_DB ); + oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; + zOpen = 0; } if( rc==SQLITE_OK ){ - rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags); + rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags); } if( pFd->pReal->pMethods ){ /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods @@ -164051,7 +175494,9 @@ static int rbuVfsAccess( if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ - *pResOut = 1; + sqlite3_int64 sz = 0; + rc = rbuVfsFileSize(&pDb->base, &sz); + *pResOut = (sz>0); } } } @@ -164151,7 +175596,7 @@ static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ ** Deregister and destroy an RBU vfs created by an earlier call to ** sqlite3rbu_create_vfs(). */ -SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){ +SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); if( pVfs && pVfs->xOpen==rbuVfsOpen ){ sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex); @@ -164165,7 +175610,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){ ** via existing VFS zParent. The new object is registered as a non-default ** VFS with SQLite before returning. */ -SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent){ +SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){ /* Template for VFS */ static sqlite3_vfs vfs_template = { @@ -164198,13 +175643,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha }; rbu_vfs *pNew = 0; /* Newly allocated VFS */ - int nName; int rc = SQLITE_OK; + size_t nName; + size_t nByte; - int nByte; nName = strlen(zName); nByte = sizeof(rbu_vfs) + nName + 1; - pNew = (rbu_vfs*)sqlite3_malloc(nByte); + pNew = (rbu_vfs*)sqlite3_malloc64(nByte); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -164240,6 +175685,20 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha return rc; } +/* +** Configure the aggregate temp file size limit for this RBU handle. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){ + if( n>=0 ){ + pRbu->szTempLimit = n; + } + return pRbu->szTempLimit; +} + +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){ + return pRbu->szTemp; +} + /**************************************************************************/ @@ -164307,10 +175766,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ - " name STRING, /* Name of table or index */" \ - " path INTEGER, /* Path to page from root */" \ + " name TEXT, /* Name of table or index */" \ + " path TEXT, /* Path to page from root */" \ " pageno INTEGER, /* Page number */" \ - " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \ + " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \ " ncell INTEGER, /* Cells on page (0 for overflow) */" \ " payload INTEGER, /* Bytes of payload on this page */" \ " unused INTEGER, /* Bytes of unused space on this page */" \ @@ -164398,7 +175857,9 @@ static int statConnect( int iDb; if( argc>=4 ){ - iDb = sqlite3FindDbName(db, argv[3]); + Token nm; + sqlite3TokenInit(&nm, (char*)argv[3]); + iDb = sqlite3FindDb(db, &nm); if( iDb<0 ){ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); return SQLITE_ERROR; @@ -164409,7 +175870,7 @@ static int statConnect( rc = sqlite3_declare_vtab(db, VTAB_SCHEMA); if( rc==SQLITE_OK ){ pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable)); - if( pTab==0 ) rc = SQLITE_NOMEM; + if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; } assert( rc==SQLITE_OK || pTab==0 ); @@ -164490,7 +175951,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor)); if( pCsr==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; }else{ memset(pCsr, 0, sizeof(StatCursor)); pCsr->base.pVtab = pVTab; @@ -164596,7 +176057,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell)); - if( p->aCell==0 ) return SQLITE_NOMEM; + if( p->aCell==0 ) return SQLITE_NOMEM_BKPT; memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); for(i=0; inCell; i++){ @@ -164629,7 +176090,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); - if( pCell->aOvfl==0 ) return SQLITE_NOMEM; + if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT; pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); for(j=1; jaPage[0].iCell = 0; pCsr->aPage[0].zPath = z = sqlite3_mprintf("/"); pCsr->iPage = 0; - if( z==0 ) rc = SQLITE_NOMEM; + if( z==0 ) rc = SQLITE_NOMEM_BKPT; }else{ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); @@ -164743,7 +176204,7 @@ statNextRestart: } pCell->iOvfl++; statSizeAndOffset(pCsr); - return z==0 ? SQLITE_NOMEM : SQLITE_OK; + return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; } if( p->iRightChildPg ) break; p->iCell++; @@ -164767,7 +176228,7 @@ statNextRestart: p[1].iCell = 0; p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); p->iCell++; - if( z==0 ) rc = SQLITE_NOMEM; + if( z==0 ) rc = SQLITE_NOMEM_BKPT; } @@ -164801,7 +176262,7 @@ statNextRestart: pCsr->nUnused = p->nUnused; pCsr->nMxPayload = p->nMxPayload; pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath); - if( z==0 ) rc = SQLITE_NOMEM; + if( z==0 ) rc = SQLITE_NOMEM_BKPT; nPayload = 0; for(i=0; inCell; i++){ nPayload += p->aCell[i].nLocal; @@ -164835,7 +176296,7 @@ static int statFilter( if( pCsr->iDb<0 ){ sqlite3_free(pCursor->pVtab->zErrMsg); pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase); - return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT; } }else{ pCsr->iDb = pTab->iDb; @@ -164849,9 +176310,9 @@ static int statFilter( " UNION ALL " "SELECT name, rootpage, type" " FROM \"%w\".%s WHERE rootpage!=0" - " ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster); + " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster); if( zSql==0 ){ - return SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; }else{ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); sqlite3_free(zSql); @@ -164903,7 +176364,7 @@ static int statColumn( default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; - sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC); + sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC); break; } } @@ -164941,6 +176402,9 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -164949,6 +176413,4996 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; } #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ /************** End of dbstat.c **********************************************/ +/************** Begin file dbpage.c ******************************************/ +/* +** 2017-10-11 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains an implementation of the "sqlite_dbpage" virtual table. +** +** The sqlite_dbpage virtual table is used to read or write whole raw +** pages of the database file. The pager interface is used so that +** uncommitted changes and changes recorded in the WAL file are correctly +** retrieved. +** +** Usage example: +** +** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123; +** +** This is an eponymous virtual table so it does not need to be created before +** use. The optional argument to the sqlite_dbpage() table name is the +** schema for the database file that is to be read. The default schema is +** "main". +** +** The data field of sqlite_dbpage table can be updated. The new +** value must be a BLOB which is the correct page size, otherwise the +** update fails. Rows may not be deleted or inserted. +*/ + +/* #include "sqliteInt.h" ** Requires access to internal data structures ** */ +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) + +typedef struct DbpageTable DbpageTable; +typedef struct DbpageCursor DbpageCursor; + +struct DbpageCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + int pgno; /* Current page number */ + int mxPgno; /* Last page to visit on this scan */ +}; + +struct DbpageTable { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* The database */ + Pager *pPager; /* Pager being read/written */ + int iDb; /* Index of database to analyze */ + int szPage; /* Size of each page in bytes */ + int nPage; /* Number of pages in the file */ +}; + +/* +** Connect to or create a dbpagevfs virtual table. +*/ +static int dbpageConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + DbpageTable *pTab = 0; + int rc = SQLITE_OK; + int iDb; + + if( argc>=4 ){ + Token nm; + sqlite3TokenInit(&nm, (char*)argv[3]); + iDb = sqlite3FindDb(db, &nm); + if( iDb<0 ){ + *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]); + return SQLITE_ERROR; + } + }else{ + iDb = 0; + } + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); + if( rc==SQLITE_OK ){ + pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); + if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; + } + + assert( rc==SQLITE_OK || pTab==0 ); + if( rc==SQLITE_OK ){ + Btree *pBt = db->aDb[iDb].pBt; + memset(pTab, 0, sizeof(DbpageTable)); + pTab->db = db; + pTab->iDb = iDb; + pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0; + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** Disconnect from or destroy a dbpagevfs virtual table. +*/ +static int dbpageDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** idxNum: +** +** 0 full table scan +** 1 pgno=?1 +*/ +static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int i; + pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; + if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + pIdxInfo->estimatedCost = 1.0; + pIdxInfo->idxNum = 1; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + break; + } + } + if( pIdxInfo->nOrderBy>=1 + && pIdxInfo->aOrderBy[0].iColumn<=0 + && pIdxInfo->aOrderBy[0].desc==0 + ){ + pIdxInfo->orderByConsumed = 1; + } + return SQLITE_OK; +} + +/* +** Open a new dbpagevfs cursor. +*/ +static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + DbpageCursor *pCsr; + + pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM_BKPT; + }else{ + memset(pCsr, 0, sizeof(DbpageCursor)); + pCsr->base.pVtab = pVTab; + pCsr->pgno = -1; + } + + *ppCursor = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a dbpagevfs cursor. +*/ +static int dbpageClose(sqlite3_vtab_cursor *pCursor){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Move a dbpagevfs cursor to the next entry in the file. +*/ +static int dbpageNext(sqlite3_vtab_cursor *pCursor){ + int rc = SQLITE_OK; + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + pCsr->pgno++; + return rc; +} + +static int dbpageEof(sqlite3_vtab_cursor *pCursor){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + return pCsr->pgno > pCsr->mxPgno; +} + +static int dbpageFilter( + sqlite3_vtab_cursor *pCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; + int rc = SQLITE_OK; + Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; + + pTab->szPage = sqlite3BtreeGetPageSize(pBt); + pTab->nPage = sqlite3BtreeLastPage(pBt); + if( idxNum==1 ){ + pCsr->pgno = sqlite3_value_int(argv[0]); + if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){ + pCsr->pgno = 1; + pCsr->mxPgno = 0; + }else{ + pCsr->mxPgno = pCsr->pgno; + } + }else{ + pCsr->pgno = 1; + pCsr->mxPgno = pTab->nPage; + } + return rc; +} + +static int dbpageColumn( + sqlite3_vtab_cursor *pCursor, + sqlite3_context *ctx, + int i +){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; + int rc = SQLITE_OK; + switch( i ){ + case 0: { /* pgno */ + sqlite3_result_int(ctx, pCsr->pgno); + break; + } + case 1: { /* data */ + DbPage *pDbPage = 0; + rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); + if( rc==SQLITE_OK ){ + sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage, + SQLITE_TRANSIENT); + } + sqlite3PagerUnref(pDbPage); + break; + } + default: { /* schema */ + sqlite3 *db = sqlite3_context_db_handle(ctx); + sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC); + break; + } + } + return SQLITE_OK; +} + +static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + *pRowid = pCsr->pgno; + return SQLITE_OK; +} + +static int dbpageUpdate( + sqlite3_vtab *pVtab, + int argc, + sqlite3_value **argv, + sqlite_int64 *pRowid +){ + DbpageTable *pTab = (DbpageTable *)pVtab; + int pgno; + DbPage *pDbPage = 0; + int rc = SQLITE_OK; + char *zErr = 0; + + if( argc==1 ){ + zErr = "cannot delete"; + goto update_fail; + } + pgno = sqlite3_value_int(argv[0]); + if( pgno<1 || pgno>pTab->nPage ){ + zErr = "bad page number"; + goto update_fail; + } + if( sqlite3_value_int(argv[1])!=pgno ){ + zErr = "cannot insert"; + goto update_fail; + } + if( sqlite3_value_type(argv[3])!=SQLITE_BLOB + || sqlite3_value_bytes(argv[3])!=pTab->szPage + ){ + zErr = "bad page value"; + goto update_fail; + } + rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pDbPage); + if( rc==SQLITE_OK ){ + memcpy(sqlite3PagerGetData(pDbPage), + sqlite3_value_blob(argv[3]), + pTab->szPage); + } + } + sqlite3PagerUnref(pDbPage); + return rc; + +update_fail: + sqlite3_free(pVtab->zErrMsg); + pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); + return SQLITE_ERROR; +} + +/* +** Invoke this routine to register the "dbpage" virtual table module +*/ +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ + static sqlite3_module dbpage_module = { + 0, /* iVersion */ + dbpageConnect, /* xCreate */ + dbpageConnect, /* xConnect */ + dbpageBestIndex, /* xBestIndex */ + dbpageDisconnect, /* xDisconnect */ + dbpageDisconnect, /* xDestroy */ + dbpageOpen, /* xOpen - open a cursor */ + dbpageClose, /* xClose - close a cursor */ + dbpageFilter, /* xFilter - configure scan constraints */ + dbpageNext, /* xNext - advance a cursor */ + dbpageEof, /* xEof - check for end of scan */ + dbpageColumn, /* xColumn - read data */ + dbpageRowid, /* xRowid - read data */ + dbpageUpdate, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + }; + return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); +} +#elif defined(SQLITE_ENABLE_DBPAGE_VTAB) +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } +#endif /* SQLITE_ENABLE_DBSTAT_VTAB */ + +/************** End of dbpage.c **********************************************/ +/************** Begin file sqlite3session.c **********************************/ + +#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) +/* #include "sqlite3session.h" */ +/* #include */ +/* #include */ + +#ifndef SQLITE_AMALGAMATION +/* # include "sqliteInt.h" */ +/* # include "vdbeInt.h" */ +#endif + +typedef struct SessionTable SessionTable; +typedef struct SessionChange SessionChange; +typedef struct SessionBuffer SessionBuffer; +typedef struct SessionInput SessionInput; + +/* +** Minimum chunk size used by streaming versions of functions. +*/ +#ifndef SESSIONS_STRM_CHUNK_SIZE +# ifdef SQLITE_TEST +# define SESSIONS_STRM_CHUNK_SIZE 64 +# else +# define SESSIONS_STRM_CHUNK_SIZE 1024 +# endif +#endif + +typedef struct SessionHook SessionHook; +struct SessionHook { + void *pCtx; + int (*xOld)(void*,int,sqlite3_value**); + int (*xNew)(void*,int,sqlite3_value**); + int (*xCount)(void*); + int (*xDepth)(void*); +}; + +/* +** Session handle structure. +*/ +struct sqlite3_session { + sqlite3 *db; /* Database handle session is attached to */ + char *zDb; /* Name of database session is attached to */ + int bEnable; /* True if currently recording */ + int bIndirect; /* True if all changes are indirect */ + int bAutoAttach; /* True to auto-attach tables */ + int rc; /* Non-zero if an error has occurred */ + void *pFilterCtx; /* First argument to pass to xTableFilter */ + int (*xTableFilter)(void *pCtx, const char *zTab); + sqlite3_session *pNext; /* Next session object on same db. */ + SessionTable *pTable; /* List of attached tables */ + SessionHook hook; /* APIs to grab new and old data with */ +}; + +/* +** Instances of this structure are used to build strings or binary records. +*/ +struct SessionBuffer { + u8 *aBuf; /* Pointer to changeset buffer */ + int nBuf; /* Size of buffer aBuf */ + int nAlloc; /* Size of allocation containing aBuf */ +}; + +/* +** An object of this type is used internally as an abstraction for +** input data. Input data may be supplied either as a single large buffer +** (e.g. sqlite3changeset_start()) or using a stream function (e.g. +** sqlite3changeset_start_strm()). +*/ +struct SessionInput { + int bNoDiscard; /* If true, discard no data */ + int iCurrent; /* Offset in aData[] of current change */ + int iNext; /* Offset in aData[] of next change */ + u8 *aData; /* Pointer to buffer containing changeset */ + int nData; /* Number of bytes in aData */ + + SessionBuffer buf; /* Current read buffer */ + int (*xInput)(void*, void*, int*); /* Input stream call (or NULL) */ + void *pIn; /* First argument to xInput */ + int bEof; /* Set to true after xInput finished */ +}; + +/* +** Structure for changeset iterators. +*/ +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 rc; /* Iterator error code */ + sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ + char *zTab; /* Current table */ + int nCol; /* Number of columns in zTab */ + int op; /* Current operation */ + int bIndirect; /* True if current change was indirect */ + u8 *abPK; /* Primary key array */ + sqlite3_value **apValue; /* old.* and new.* values */ +}; + +/* +** Each session object maintains a set of the following structures, one +** for each table the session object is monitoring. The structures are +** stored in a linked list starting at sqlite3_session.pTable. +** +** The keys of the SessionTable.aChange[] hash table are all rows that have +** been modified in any way since the session object was attached to the +** table. +** +** The data associated with each hash-table entry is a structure containing +** a subset of the initial values that the modified row contained at the +** start of the session. Or no initial values if the row was inserted. +*/ +struct SessionTable { + SessionTable *pNext; + char *zName; /* Local name of table */ + int nCol; /* Number of columns in table zName */ + const char **azCol; /* Column names */ + u8 *abPK; /* Array of primary key flags */ + int nEntry; /* Total number of entries in hash table */ + int nChange; /* Size of apChange[] array */ + SessionChange **apChange; /* Hash table buckets */ +}; + +/* +** RECORD FORMAT: +** +** The following record format is similar to (but not compatible with) that +** used in SQLite database files. This format is used as part of the +** change-set binary format, and so must be architecture independent. +** +** Unlike the SQLite database record format, each field is self-contained - +** there is no separation of header and data. Each field begins with a +** single byte describing its type, as follows: +** +** 0x00: Undefined value. +** 0x01: Integer value. +** 0x02: Real value. +** 0x03: Text value. +** 0x04: Blob value. +** 0x05: SQL NULL value. +** +** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT +** and so on in sqlite3.h. For undefined and NULL values, the field consists +** only of the single type byte. For other types of values, the type byte +** is followed by: +** +** Text values: +** A varint containing the number of bytes in the value (encoded using +** UTF-8). Followed by a buffer containing the UTF-8 representation +** of the text value. There is no nul terminator. +** +** Blob values: +** A varint containing the number of bytes in the value, followed by +** a buffer containing the value itself. +** +** Integer values: +** An 8-byte big-endian integer value. +** +** Real values: +** An 8-byte big-endian IEEE 754-2008 real value. +** +** Varint values are encoded in the same way as varints in the SQLite +** record format. +** +** CHANGESET FORMAT: +** +** A changeset is a collection of DELETE, UPDATE and INSERT operations on +** one or more tables. Operations on a single table are grouped together, +** but may occur in any order (i.e. deletes, updates and inserts are all +** mixed together). +** +** Each group of changes begins with a table header: +** +** 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 changes to the table. +** +** 1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09). +** 1 byte: The "indirect-change" flag. +** old.* record: (delete and update only) +** new.* record: (insert and update only) +** +** The "old.*" and "new.*" records, if present, are N field records in the +** format described above under "RECORD FORMAT", where N is the number of +** columns in the table. The i'th field of each record is associated with +** the i'th column of the table, counting from left to right in the order +** in which columns were declared in the CREATE TABLE statement. +** +** The new.* record that is part of each INSERT change contains the values +** that make up the new row. Similarly, the old.* record that is part of each +** DELETE change contains the values that made up the row that was deleted +** from the database. In the changeset format, the records that are part +** of INSERT or DELETE changes never contain any undefined (type byte 0x00) +** fields. +** +** Within the old.* record associated with an UPDATE change, all fields +** associated with table columns that are not PRIMARY KEY columns and are +** not modified by the UPDATE change are set to "undefined". Other fields +** are set to the values that made up the row before the UPDATE that the +** change records took place. Within the new.* record, fields associated +** with table columns modified by the UPDATE change contain the new +** values. Fields associated with table columns that are not modified +** are set to "undefined". +** +** PATCHSET FORMAT: +** +** A patchset is also a collection of changes. It is similar to a changeset, +** but leaves undefined those fields that are not useful if no conflict +** resolution is required when applying the changeset. +** +** Each group of changes begins with a table header: +** +** 1 byte: Constant 0x50 (capital 'P') +** 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 changes to the table. +** +** 1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09). +** 1 byte: The "indirect-change" flag. +** single record: (PK fields for DELETE, PK and modified fields for UPDATE, +** full record for INSERT). +** +** As in the changeset format, each field of the single record that is part +** of a patchset change is associated with the correspondingly positioned +** table column, counting from left to right within the CREATE TABLE +** statement. +** +** For a DELETE change, all fields within the record except those associated +** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields +** contain the values identifying the row to delete. +** +** For an UPDATE change, all fields except those associated with PRIMARY KEY +** columns and columns that are modified by the UPDATE are set to "undefined". +** PRIMARY KEY fields contain the values identifying the table row to update, +** and fields associated with modified columns contain the new column values. +** +** 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". +*/ + +/* +** For each row modified during a session, there exists a single instance of +** this structure stored in a SessionTable.aChange[] hash table. +*/ +struct SessionChange { + int op; /* One of UPDATE, DELETE, INSERT */ + int bIndirect; /* True if this change is "indirect" */ + int nRecord; /* Number of bytes in buffer aRecord[] */ + u8 *aRecord; /* Buffer containing old.* record */ + SessionChange *pNext; /* For hash-table collisions */ +}; + +/* +** Write a varint with value iVal into the buffer at aBuf. Return the +** number of bytes written. +*/ +static int sessionVarintPut(u8 *aBuf, int iVal){ + return putVarint32(aBuf, iVal); +} + +/* +** Return the number of bytes required to store value iVal as a varint. +*/ +static int sessionVarintLen(int iVal){ + return sqlite3VarintLen(iVal); +} + +/* +** Read a varint value from aBuf[] into *piVal. Return the number of +** bytes read. +*/ +static int sessionVarintGet(u8 *aBuf, int *piVal){ + return getVarint32(aBuf, *piVal); +} + +/* Load an unaligned and unsigned 32-bit integer */ +#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) + +/* +** Read a 64-bit big-endian integer value from buffer aRec[]. Return +** the value read. +*/ +static sqlite3_int64 sessionGetI64(u8 *aRec){ + u64 x = SESSION_UINT32(aRec); + u32 y = SESSION_UINT32(aRec+4); + x = (x<<32) + y; + return (sqlite3_int64)x; +} + +/* +** Write a 64-bit big-endian integer value to the buffer aBuf[]. +*/ +static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){ + aBuf[0] = (i>>56) & 0xFF; + aBuf[1] = (i>>48) & 0xFF; + aBuf[2] = (i>>40) & 0xFF; + aBuf[3] = (i>>32) & 0xFF; + aBuf[4] = (i>>24) & 0xFF; + aBuf[5] = (i>>16) & 0xFF; + aBuf[6] = (i>> 8) & 0xFF; + aBuf[7] = (i>> 0) & 0xFF; +} + +/* +** This function is used to serialize the contents of value pValue (see +** comment titled "RECORD FORMAT" above). +** +** If it is non-NULL, the serialized form of the value is written to +** buffer aBuf. *pnWrite is set to the number of bytes written before +** returning. Or, if aBuf is NULL, the only thing this function does is +** set *pnWrite. +** +** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs +** within a call to sqlite3_value_text() (may fail if the db is utf-16)) +** SQLITE_NOMEM is returned. +*/ +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 */ +){ + int nByte; /* Size of serialized value in bytes */ + + if( pValue ){ + int eType; /* Value type (SQLITE_NULL, TEXT etc.) */ + + eType = sqlite3_value_type(pValue); + if( aBuf ) aBuf[0] = eType; + + switch( eType ){ + case SQLITE_NULL: + nByte = 1; + break; + + case SQLITE_INTEGER: + case SQLITE_FLOAT: + if( aBuf ){ + /* TODO: SQLite does something special to deal with mixed-endian + ** floating point values (e.g. ARM7). This code probably should + ** too. */ + u64 i; + if( eType==SQLITE_INTEGER ){ + i = (u64)sqlite3_value_int64(pValue); + }else{ + double r; + assert( sizeof(double)==8 && sizeof(u64)==8 ); + r = sqlite3_value_double(pValue); + memcpy(&i, &r, 8); + } + sessionPutI64(&aBuf[1], i); + } + nByte = 9; + break; + + default: { + u8 *z; + int n; + int nVarint; + + assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); + if( eType==SQLITE_TEXT ){ + z = (u8 *)sqlite3_value_text(pValue); + }else{ + z = (u8 *)sqlite3_value_blob(pValue); + } + n = sqlite3_value_bytes(pValue); + if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; + nVarint = sessionVarintLen(n); + + if( aBuf ){ + sessionVarintPut(&aBuf[1], n); + if( n ) memcpy(&aBuf[nVarint + 1], z, n); + } + + nByte = 1 + nVarint + n; + break; + } + } + }else{ + nByte = 1; + if( aBuf ) aBuf[0] = '\0'; + } + + if( pnWrite ) *pnWrite += nByte; + return SQLITE_OK; +} + + +/* +** This macro is used to calculate hash key values for data structures. In +** order to use this macro, the entire data structure must be represented +** as a series of unsigned integers. In order to calculate a hash-key value +** for a data structure represented as three such integers, the macro may +** then be used as follows: +** +** int hash_key_value; +** hash_key_value = HASH_APPEND(0, ); +** hash_key_value = HASH_APPEND(hash_key_value, ); +** hash_key_value = HASH_APPEND(hash_key_value, ); +** +** In practice, the data structures this macro is used for are the primary +** key values of modified rows. +*/ +#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add) + +/* +** Append the hash of the 64-bit integer passed as the second argument to the +** hash-key value passed as the first. Return the new hash-key value. +*/ +static unsigned int sessionHashAppendI64(unsigned int h, i64 i){ + h = HASH_APPEND(h, i & 0xFFFFFFFF); + return HASH_APPEND(h, (i>>32)&0xFFFFFFFF); +} + +/* +** Append the hash of the blob passed via the second and third arguments to +** the hash-key value passed as the first. Return the new hash-key value. +*/ +static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){ + int i; + for(i=0; inCol==pSession->hook.xCount(pSession->hook.pCtx) ); + for(i=0; inCol; i++){ + if( pTab->abPK[i] ){ + int rc; + int eType; + sqlite3_value *pVal; + + if( bNew ){ + rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + }else{ + rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + } + if( rc!=SQLITE_OK ) return rc; + + eType = sqlite3_value_type(pVal); + h = sessionHashAppendType(h, eType); + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + i64 iVal; + if( eType==SQLITE_INTEGER ){ + iVal = sqlite3_value_int64(pVal); + }else{ + double rVal = sqlite3_value_double(pVal); + assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); + memcpy(&iVal, &rVal, 8); + } + h = sessionHashAppendI64(h, iVal); + }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + const u8 *z; + int n; + if( eType==SQLITE_TEXT ){ + z = (const u8 *)sqlite3_value_text(pVal); + }else{ + z = (const u8 *)sqlite3_value_blob(pVal); + } + n = sqlite3_value_bytes(pVal); + if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; + h = sessionHashAppendBlob(h, n, z); + }else{ + assert( eType==SQLITE_NULL ); + *pbNullPK = 1; + } + } + } + + *piHash = (h % pTab->nChange); + return SQLITE_OK; +} + +/* +** The buffer that the argument points to contains a serialized SQL value. +** Return the number of bytes of space occupied by the value (including +** the type byte). +*/ +static int sessionSerialLen(u8 *a){ + int e = *a; + int n; + if( e==0 ) return 1; + if( e==SQLITE_NULL ) return 1; + if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9; + return sessionVarintGet(&a[1], &n) + 1 + n; +} + +/* +** Based on the primary key values stored in change aRecord, calculate a +** hash key. Assume the has table has nBucket buckets. The hash keys +** calculated by this function are compatible with those calculated by +** sessionPreupdateHash(). +** +** The bPkOnly argument is non-zero if the record at aRecord[] is from +** a patchset DELETE. In this case the non-PK fields are omitted entirely. +*/ +static unsigned int sessionChangeHash( + SessionTable *pTab, /* Table handle */ + int bPkOnly, /* Record consists of PK fields only */ + u8 *aRecord, /* Change record */ + int nBucket /* Assume this many buckets in hash table */ +){ + unsigned int h = 0; /* Value to return */ + int i; /* Used to iterate through columns */ + u8 *a = aRecord; /* Used to iterate through change record */ + + for(i=0; inCol; i++){ + int eType = *a; + int isPK = pTab->abPK[i]; + if( bPkOnly && isPK==0 ) continue; + + /* It is not possible for eType to be SQLITE_NULL here. The session + ** module does not record changes for rows with NULL values stored in + ** primary key columns. */ + assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT + || eType==SQLITE_TEXT || eType==SQLITE_BLOB + || eType==SQLITE_NULL || eType==0 + ); + assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) ); + + if( isPK ){ + a++; + h = sessionHashAppendType(h, eType); + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + h = sessionHashAppendI64(h, sessionGetI64(a)); + a += 8; + }else{ + int n; + a += sessionVarintGet(a, &n); + h = sessionHashAppendBlob(h, n, a); + a += n; + } + }else{ + a += sessionSerialLen(a); + } + } + return (h % nBucket); +} + +/* +** Arguments aLeft and aRight are pointers to change records for table pTab. +** This function returns true if the two records apply to the same row (i.e. +** have the same values stored in the primary key columns), or false +** otherwise. +*/ +static int sessionChangeEqual( + SessionTable *pTab, /* Table used for PK definition */ + int bLeftPkOnly, /* True if aLeft[] contains PK fields only */ + u8 *aLeft, /* Change record */ + int bRightPkOnly, /* True if aRight[] contains PK fields only */ + u8 *aRight /* Change record */ +){ + u8 *a1 = aLeft; /* Cursor to iterate through aLeft */ + u8 *a2 = aRight; /* Cursor to iterate through aRight */ + int iCol; /* Used to iterate through table columns */ + + for(iCol=0; iColnCol; iCol++){ + if( pTab->abPK[iCol] ){ + int n1 = sessionSerialLen(a1); + int n2 = sessionSerialLen(a2); + + if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){ + return 0; + } + a1 += n1; + a2 += n2; + }else{ + if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1); + if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2); + } + } + + return 1; +} + +/* +** Arguments aLeft and aRight both point to buffers containing change +** records with nCol columns. This function "merges" the two records into +** a single records which is written to the buffer at *paOut. *paOut is +** then set to point to one byte after the last byte written before +** returning. +** +** The merging of records is done as follows: For each column, if the +** aRight record contains a value for the column, copy the value from +** their. Otherwise, if aLeft contains a value, copy it. If neither +** record contains a value for a given column, then neither does the +** output record. +*/ +static void sessionMergeRecord( + u8 **paOut, + int nCol, + u8 *aLeft, + u8 *aRight +){ + u8 *a1 = aLeft; /* Cursor used to iterate through aLeft */ + u8 *a2 = aRight; /* Cursor used to iterate through aRight */ + u8 *aOut = *paOut; /* Output cursor */ + int iCol; /* Used to iterate from 0 to nCol */ + + for(iCol=0; iColnCol; i++){ + int nOld; + u8 *aOld; + int nNew; + u8 *aNew; + + aOld = sessionMergeValue(&aOld1, &aOld2, &nOld); + aNew = sessionMergeValue(&aNew1, &aNew2, &nNew); + if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){ + if( pTab->abPK[i]==0 ) bRequired = 1; + memcpy(aOut, aOld, nOld); + aOut += nOld; + }else{ + *(aOut++) = '\0'; + } + } + + if( !bRequired ) return 0; + } + + /* Write the new.* vector */ + aOld1 = aOldRecord1; + aOld2 = aOldRecord2; + aNew1 = aNewRecord1; + aNew2 = aNewRecord2; + for(i=0; inCol; i++){ + int nOld; + u8 *aOld; + int nNew; + u8 *aNew; + + aOld = sessionMergeValue(&aOld1, &aOld2, &nOld); + aNew = sessionMergeValue(&aNew1, &aNew2, &nNew); + if( bPatchset==0 + && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) + ){ + *(aOut++) = '\0'; + }else{ + memcpy(aOut, aNew, nNew); + aOut += nNew; + } + } + + *paOut = aOut; + return 1; +} + +/* +** This function is only called from within a pre-update-hook callback. +** It determines if the current pre-update-hook change affects the same row +** as the change stored in argument pChange. If so, it returns true. Otherwise +** if the pre-update-hook does not affect the same row as pChange, it returns +** false. +*/ +static int sessionPreupdateEqual( + sqlite3_session *pSession, /* Session object that owns SessionTable */ + SessionTable *pTab, /* Table associated with change */ + SessionChange *pChange, /* Change to compare to */ + int op /* Current pre-update operation */ +){ + int iCol; /* Used to iterate through columns */ + u8 *a = pChange->aRecord; /* Cursor used to scan change record */ + + assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); + for(iCol=0; iColnCol; iCol++){ + if( !pTab->abPK[iCol] ){ + a += sessionSerialLen(a); + }else{ + sqlite3_value *pVal; /* Value returned by preupdate_new/old */ + int rc; /* Error code from preupdate_new/old */ + int eType = *a++; /* Type of value from change record */ + + /* The following calls to preupdate_new() and preupdate_old() can not + ** fail. This is because they cache their return values, and by the + ** time control flows to here they have already been called once from + ** within sessionPreupdateHash(). The first two asserts below verify + ** this (that the method has already been called). */ + if( op==SQLITE_INSERT ){ + /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */ + rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal); + }else{ + /* assert( db->pPreUpdate->pUnpacked ); */ + rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal); + } + assert( rc==SQLITE_OK ); + if( sqlite3_value_type(pVal)!=eType ) return 0; + + /* A SessionChange object never has a NULL value in a PK column */ + assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT + || eType==SQLITE_BLOB || eType==SQLITE_TEXT + ); + + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + i64 iVal = sessionGetI64(a); + a += 8; + if( eType==SQLITE_INTEGER ){ + if( sqlite3_value_int64(pVal)!=iVal ) return 0; + }else{ + double rVal; + assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); + memcpy(&rVal, &iVal, 8); + if( sqlite3_value_double(pVal)!=rVal ) return 0; + } + }else{ + int n; + const u8 *z; + a += sessionVarintGet(a, &n); + if( sqlite3_value_bytes(pVal)!=n ) return 0; + if( eType==SQLITE_TEXT ){ + z = sqlite3_value_text(pVal); + }else{ + z = sqlite3_value_blob(pVal); + } + if( memcmp(a, z, n) ) return 0; + a += n; + break; + } + } + } + + return 1; +} + +/* +** If required, grow the hash table used to store changes on table pTab +** (part of the session pSession). If a fatal OOM error occurs, set the +** session object to failed and return SQLITE_ERROR. Otherwise, return +** SQLITE_OK. +** +** It is possible that a non-fatal OOM error occurs in this function. In +** that case the hash-table does not grow, but SQLITE_OK is returned anyway. +** Growing the hash table in this case is a performance optimization only, +** it is not required for correct operation. +*/ +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; + + apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew); + if( apNew==0 ){ + if( pTab->nChange==0 ){ + return SQLITE_ERROR; + } + return SQLITE_OK; + } + memset(apNew, 0, sizeof(SessionChange *) * nNew); + + for(i=0; inChange; i++){ + SessionChange *p; + SessionChange *pNext; + for(p=pTab->apChange[i]; p; p=pNext){ + int bPkOnly = (p->op==SQLITE_DELETE && bPatchset); + int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew); + pNext = p->pNext; + p->pNext = apNew[iHash]; + apNew[iHash] = p; + } + } + + sqlite3_free(pTab->apChange); + pTab->nChange = nNew; + pTab->apChange = apNew; + } + + return SQLITE_OK; +} + +/* +** This function queries the database for the names of the columns of table +** zThis, in schema zDb. It is expected that the table has nCol columns. If +** not, SQLITE_SCHEMA is returned and none of the output variables are +** populated. +** +** Otherwise, if they are not NULL, variable *pnCol is set to the number +** of columns in the database table and variable *pzTab is set to point to a +** nul-terminated copy of the table name. *pazCol (if not NULL) is set to +** point to an array of pointers to column names. And *pabPK (again, if not +** NULL) is set to point to an array of booleans - true if the corresponding +** column is part of the primary key. +** +** For example, if the table is declared as: +** +** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z)); +** +** Then the four output variables are populated as follows: +** +** *pnCol = 4 +** *pzTab = "tbl1" +** *pazCol = {"w", "x", "y", "z"} +** *pabPK = {1, 0, 0, 1} +** +** All returned buffers are part of the same single allocation, which must +** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then +** pointer *pazCol should be freed to release all memory. Otherwise, pointer +** *pabPK. It is illegal for both pazCol and pabPK to be NULL. +*/ +static int sessionTableInfo( + sqlite3 *db, /* Database connection */ + const char *zDb, /* Name of attached database (e.g. "main") */ + const char *zThis, /* Table name */ + int *pnCol, /* OUT: number of columns */ + const char **pzTab, /* OUT: Copy of zThis */ + const char ***pazCol, /* OUT: Array of column names for table */ + u8 **pabPK /* OUT: Array of booleans - true for PK col */ +){ + char *zPragma; + sqlite3_stmt *pStmt; + int rc; + int nByte; + int nDbCol = 0; + int nThis; + int i; + u8 *pAlloc = 0; + char **azCol = 0; + u8 *abPK = 0; + + assert( pazCol && pabPK ); + + nThis = sqlite3Strlen30(zThis); + zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); + if( !zPragma ) return SQLITE_NOMEM; + + rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); + sqlite3_free(zPragma); + if( rc!=SQLITE_OK ) return rc; + + nByte = nThis + 1; + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + nByte += sqlite3_column_bytes(pStmt, 1); + nDbCol++; + } + rc = sqlite3_reset(pStmt); + + if( rc==SQLITE_OK ){ + nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); + pAlloc = sqlite3_malloc(nByte); + if( pAlloc==0 ){ + rc = SQLITE_NOMEM; + } + } + if( rc==SQLITE_OK ){ + azCol = (char **)pAlloc; + pAlloc = (u8 *)&azCol[nDbCol]; + abPK = (u8 *)pAlloc; + pAlloc = &abPK[nDbCol]; + if( pzTab ){ + memcpy(pAlloc, zThis, nThis+1); + *pzTab = (char *)pAlloc; + pAlloc += nThis+1; + } + + i = 0; + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + int nName = sqlite3_column_bytes(pStmt, 1); + const unsigned char *zName = sqlite3_column_text(pStmt, 1); + if( zName==0 ) break; + memcpy(pAlloc, zName, nName+1); + azCol[i] = (char *)pAlloc; + pAlloc += nName+1; + abPK[i] = sqlite3_column_int(pStmt, 5); + i++; + } + rc = sqlite3_reset(pStmt); + + } + + /* If successful, populate the output variables. Otherwise, zero them and + ** free any allocation made. An error code will be returned in this case. + */ + if( rc==SQLITE_OK ){ + *pazCol = (const char **)azCol; + *pabPK = abPK; + *pnCol = nDbCol; + }else{ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + sqlite3_free(azCol); + } + sqlite3_finalize(pStmt); + return rc; +} + +/* +** This function is only called from within a pre-update handler for a +** write to table pTab, part of session pSession. If this is the first +** write to this table, initalize the SessionTable.nCol, azCol[] and +** abPK[] arrays accordingly. +** +** If an error occurs, an error code is stored in sqlite3_session.rc and +** non-zero returned. Or, if no error occurs but the table has no primary +** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to +** indicate that updates on this table should be ignored. SessionTable.abPK +** is set to NULL in this case. +*/ +static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ + if( pTab->nCol==0 ){ + u8 *abPK; + assert( pTab->azCol==0 || pTab->abPK==0 ); + pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, + pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK + ); + if( pSession->rc==SQLITE_OK ){ + int i; + for(i=0; inCol; i++){ + if( abPK[i] ){ + pTab->abPK = abPK; + break; + } + } + } + } + return (pSession->rc || pTab->abPK==0); +} + +/* +** This function is only called from with a pre-update-hook reporting a +** change on table pTab (attached to session pSession). The type of change +** (UPDATE, INSERT, DELETE) is specified by the first argument. +** +** Unless one is already present or an error occurs, an entry is added +** to the changed-rows hash table associated with table pTab. +*/ +static void sessionPreupdateOneChange( + int op, /* One of SQLITE_UPDATE, INSERT, DELETE */ + sqlite3_session *pSession, /* Session object pTab is attached to */ + SessionTable *pTab /* Table that change applies to */ +){ + int iHash; + int bNull = 0; + int rc = SQLITE_OK; + + if( pSession->rc ) return; + + /* Load table details if required */ + if( sessionInitTable(pSession, pTab) ) return; + + /* Check the number of columns in this xPreUpdate call matches the + ** number of columns in the table. */ + if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ + pSession->rc = SQLITE_SCHEMA; + return; + } + + /* Grow the hash table if required */ + if( sessionGrowHash(0, pTab) ){ + pSession->rc = SQLITE_NOMEM; + return; + } + + /* Calculate the hash-key for this change. If the primary key of the row + ** includes a NULL value, exit early. Such changes are ignored by the + ** session module. */ + rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull); + if( rc!=SQLITE_OK ) goto error_out; + + if( bNull==0 ){ + /* Search the hash table for an existing record for this row. */ + SessionChange *pC; + for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){ + if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break; + } + + if( pC==0 ){ + /* Create a new change object containing all the old values (if + ** 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 */ + int i; /* Used to iterate through columns */ + + assert( rc==SQLITE_OK ); + pTab->nEntry++; + + /* Figure out how large an allocation is required */ + nByte = sizeof(SessionChange); + for(i=0; inCol; i++){ + sqlite3_value *p = 0; + if( op!=SQLITE_INSERT ){ + TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p); + assert( trc==SQLITE_OK ); + }else if( pTab->abPK[i] ){ + TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p); + assert( trc==SQLITE_OK ); + } + + /* This may fail if SQLite value p contains a utf-16 string that must + ** be converted to utf-8 and an OOM error occurs while doing so. */ + rc = sessionSerializeValue(0, p, &nByte); + if( rc!=SQLITE_OK ) goto error_out; + } + + /* Allocate the change object */ + pChange = (SessionChange *)sqlite3_malloc(nByte); + if( !pChange ){ + rc = SQLITE_NOMEM; + goto error_out; + }else{ + memset(pChange, 0, sizeof(SessionChange)); + pChange->aRecord = (u8 *)&pChange[1]; + } + + /* Populate the change object. None of the preupdate_old(), + ** preupdate_new() or SerializeValue() calls below may fail as all + ** required values and encodings have already been cached in memory. + ** It is not possible for an OOM to occur in this block. */ + nByte = 0; + for(i=0; inCol; i++){ + sqlite3_value *p = 0; + if( op!=SQLITE_INSERT ){ + pSession->hook.xOld(pSession->hook.pCtx, i, &p); + }else if( pTab->abPK[i] ){ + pSession->hook.xNew(pSession->hook.pCtx, i, &p); + } + sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte); + } + + /* Add the change to the hash-table */ + if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){ + pChange->bIndirect = 1; + } + pChange->nRecord = nByte; + pChange->op = op; + pChange->pNext = pTab->apChange[iHash]; + pTab->apChange[iHash] = pChange; + + }else if( pC->bIndirect ){ + /* If the existing change is considered "indirect", but this current + ** change is "direct", mark the change object as direct. */ + if( pSession->hook.xDepth(pSession->hook.pCtx)==0 + && pSession->bIndirect==0 + ){ + pC->bIndirect = 0; + } + } + } + + /* If an error has occurred, mark the session object as failed. */ + error_out: + if( rc!=SQLITE_OK ){ + pSession->rc = rc; + } +} + +static int sessionFindTable( + sqlite3_session *pSession, + const char *zName, + SessionTable **ppTab +){ + int rc = SQLITE_OK; + int nName = sqlite3Strlen30(zName); + SessionTable *pRet; + + /* Search for an existing table */ + for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){ + if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break; + } + + if( pRet==0 && pSession->bAutoAttach ){ + /* If there is a table-filter configured, invoke it. If it returns 0, + ** do not automatically add the new table. */ + if( pSession->xTableFilter==0 + || pSession->xTableFilter(pSession->pFilterCtx, zName) + ){ + rc = sqlite3session_attach(pSession, zName); + if( rc==SQLITE_OK ){ + for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext); + assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ); + } + } + } + + assert( rc==SQLITE_OK || pRet==0 ); + *ppTab = pRet; + return rc; +} + +/* +** The 'pre-update' hook registered by this module with SQLite databases. +*/ +static void xPreUpdate( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ +){ + sqlite3_session *pSession; + int nDb = sqlite3Strlen30(zDb); + + assert( sqlite3_mutex_held(db->mutex) ); + + for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ + SessionTable *pTab; + + /* If this session is attached to a different database ("main", "temp" + ** etc.), or if it is not currently enabled, there is nothing to do. Skip + ** to the next session object attached to this database. */ + if( pSession->bEnable==0 ) continue; + if( pSession->rc ) continue; + if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue; + + pSession->rc = sessionFindTable(pSession, zName, &pTab); + if( pTab ){ + assert( pSession->rc==SQLITE_OK ); + sessionPreupdateOneChange(op, pSession, pTab); + if( op==SQLITE_UPDATE ){ + sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab); + } + } + } +} + +/* +** The pre-update hook implementations. +*/ +static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){ + return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal); +} +static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){ + return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal); +} +static int sessionPreupdateCount(void *pCtx){ + return sqlite3_preupdate_count((sqlite3*)pCtx); +} +static int sessionPreupdateDepth(void *pCtx){ + return sqlite3_preupdate_depth((sqlite3*)pCtx); +} + +/* +** Install the pre-update hooks on the session object passed as the only +** argument. +*/ +static void sessionPreupdateHooks( + sqlite3_session *pSession +){ + pSession->hook.pCtx = (void*)pSession->db; + pSession->hook.xOld = sessionPreupdateOld; + pSession->hook.xNew = sessionPreupdateNew; + pSession->hook.xCount = sessionPreupdateCount; + pSession->hook.xDepth = sessionPreupdateDepth; +} + +typedef struct SessionDiffCtx SessionDiffCtx; +struct SessionDiffCtx { + sqlite3_stmt *pStmt; + int nOldOff; +}; + +/* +** The diff hook implementations. +*/ +static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){ + SessionDiffCtx *p = (SessionDiffCtx*)pCtx; + *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff); + return SQLITE_OK; +} +static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){ + SessionDiffCtx *p = (SessionDiffCtx*)pCtx; + *ppVal = sqlite3_column_value(p->pStmt, iVal); + return SQLITE_OK; +} +static int sessionDiffCount(void *pCtx){ + SessionDiffCtx *p = (SessionDiffCtx*)pCtx; + return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); +} +static int sessionDiffDepth(void *pCtx){ + return 0; +} + +/* +** Install the diff hooks on the session object passed as the only +** argument. +*/ +static void sessionDiffHooks( + sqlite3_session *pSession, + SessionDiffCtx *pDiffCtx +){ + pSession->hook.pCtx = (void*)pDiffCtx; + pSession->hook.xOld = sessionDiffOld; + pSession->hook.xNew = sessionDiffNew; + pSession->hook.xCount = sessionDiffCount; + pSession->hook.xDepth = sessionDiffDepth; +} + +static char *sessionExprComparePK( + int nCol, + const char *zDb1, const char *zDb2, + const char *zTab, + const char **azCol, u8 *abPK +){ + int i; + const char *zSep = ""; + char *zRet = 0; + + for(i=0; inCol, zDb1, zDb2, pTab->zName,zExpr); + + if( zStmt==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pStmt; + rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; + pDiffCtx->pStmt = pStmt; + pDiffCtx->nOldOff = 0; + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + sessionPreupdateOneChange(op, pSession, pTab); + } + rc = sqlite3_finalize(pStmt); + } + sqlite3_free(zStmt); + } + + return rc; +} + +static int sessionDiffFindModified( + sqlite3_session *pSession, + SessionTable *pTab, + const char *zFrom, + const char *zExpr +){ + int rc = SQLITE_OK; + + char *zExpr2 = sessionExprCompareOther(pTab->nCol, + pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK + ); + if( zExpr2==0 ){ + rc = SQLITE_NOMEM; + }else{ + char *zStmt = sqlite3_mprintf( + "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", + pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 + ); + if( zStmt==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pStmt; + rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); + + if( rc==SQLITE_OK ){ + SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; + pDiffCtx->pStmt = pStmt; + pDiffCtx->nOldOff = pTab->nCol; + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab); + } + rc = sqlite3_finalize(pStmt); + } + sqlite3_free(zStmt); + } + } + + return rc; +} + +SQLITE_API int sqlite3session_diff( + sqlite3_session *pSession, + const char *zFrom, + const char *zTbl, + char **pzErrMsg +){ + const char *zDb = pSession->zDb; + int rc = pSession->rc; + SessionDiffCtx d; + + memset(&d, 0, sizeof(d)); + sessionDiffHooks(pSession, &d); + + sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); + if( pzErrMsg ) *pzErrMsg = 0; + if( rc==SQLITE_OK ){ + char *zExpr = 0; + sqlite3 *db = pSession->db; + SessionTable *pTo; /* Table zTbl */ + + /* Locate and if necessary initialize the target table object */ + rc = sessionFindTable(pSession, zTbl, &pTo); + if( pTo==0 ) goto diff_out; + if( sessionInitTable(pSession, pTo) ){ + rc = pSession->rc; + goto diff_out; + } + + /* Check the table schemas match */ + if( rc==SQLITE_OK ){ + int bHasPk = 0; + int bMismatch = 0; + int nCol; /* Columns in zFrom.zTbl */ + u8 *abPK; + const char **azCol = 0; + rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); + if( rc==SQLITE_OK ){ + if( pTo->nCol!=nCol ){ + bMismatch = 1; + }else{ + int i; + for(i=0; iabPK[i]!=abPK[i] ) bMismatch = 1; + if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1; + if( abPK[i] ) bHasPk = 1; + } + } + + } + sqlite3_free((char*)azCol); + if( bMismatch ){ + *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + rc = SQLITE_SCHEMA; + } + if( bHasPk==0 ){ + /* Ignore tables with no primary keys */ + goto diff_out; + } + } + + if( rc==SQLITE_OK ){ + zExpr = sessionExprComparePK(pTo->nCol, + zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK + ); + } + + /* Find new rows */ + if( rc==SQLITE_OK ){ + rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr); + } + + /* Find old rows */ + if( rc==SQLITE_OK ){ + rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr); + } + + /* Find modified rows */ + if( rc==SQLITE_OK ){ + rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr); + } + + sqlite3_free(zExpr); + } + + diff_out: + sessionPreupdateHooks(pSession); + sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); + return rc; +} + +/* +** Create a session object. This session object will record changes to +** database zDb attached to connection db. +*/ +SQLITE_API int sqlite3session_create( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (e.g. "main") */ + sqlite3_session **ppSession /* OUT: New session object */ +){ + sqlite3_session *pNew; /* Newly allocated session object */ + sqlite3_session *pOld; /* Session object already attached to db */ + int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */ + + /* Zero the output value in case an error occurs. */ + *ppSession = 0; + + /* Allocate and populate the new session object. */ + pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1); + if( !pNew ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(sqlite3_session)); + pNew->db = db; + pNew->zDb = (char *)&pNew[1]; + pNew->bEnable = 1; + memcpy(pNew->zDb, zDb, nDb+1); + sessionPreupdateHooks(pNew); + + /* Add the new session object to the linked list of session objects + ** attached to database handle $db. Do this under the cover of the db + ** handle mutex. */ + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew); + pNew->pNext = pOld; + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + + *ppSession = pNew; + return SQLITE_OK; +} + +/* +** Free the list of table objects passed as the first argument. The contents +** of the changed-rows hash tables are also deleted. +*/ +static void sessionDeleteTable(SessionTable *pList){ + SessionTable *pNext; + SessionTable *pTab; + + for(pTab=pList; pTab; pTab=pNext){ + int i; + pNext = pTab->pNext; + for(i=0; inChange; i++){ + SessionChange *p; + SessionChange *pNextChange; + for(p=pTab->apChange[i]; p; p=pNextChange){ + pNextChange = p->pNext; + sqlite3_free(p); + } + } + sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */ + sqlite3_free(pTab->apChange); + sqlite3_free(pTab); + } +} + +/* +** Delete a session object previously allocated using sqlite3session_create(). +*/ +SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){ + sqlite3 *db = pSession->db; + sqlite3_session *pHead; + sqlite3_session **pp; + + /* Unlink the session from the linked list of sessions attached to the + ** database handle. Hold the db mutex while doing so. */ + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0); + for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){ + if( (*pp)==pSession ){ + *pp = (*pp)->pNext; + if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead); + break; + } + } + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + + /* Delete all attached table objects. And the contents of their + ** associated hash-tables. */ + sessionDeleteTable(pSession->pTable); + + /* Free the session object itself. */ + sqlite3_free(pSession); +} + +/* +** Set a table filter on a Session Object. +*/ +SQLITE_API void sqlite3session_table_filter( + sqlite3_session *pSession, + int(*xFilter)(void*, const char*), + void *pCtx /* First argument passed to xFilter */ +){ + pSession->bAutoAttach = 1; + pSession->pFilterCtx = pCtx; + pSession->xTableFilter = xFilter; +} + +/* +** Attach a table to a session. All subsequent changes made to the table +** while the session object is enabled will be recorded. +** +** Only tables that have a PRIMARY KEY defined may be attached. It does +** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) +** or not. +*/ +SQLITE_API int sqlite3session_attach( + sqlite3_session *pSession, /* Session object */ + const char *zName /* Table name */ +){ + int rc = SQLITE_OK; + sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); + + if( !zName ){ + pSession->bAutoAttach = 1; + }else{ + SessionTable *pTab; /* New table object (if required) */ + int nName; /* Number of bytes in string zName */ + + /* First search for an existing entry. If one is found, this call is + ** a no-op. Return early. */ + nName = sqlite3Strlen30(zName); + for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break; + } + + if( !pTab ){ + /* Allocate new SessionTable object. */ + pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1); + if( !pTab ){ + rc = SQLITE_NOMEM; + }else{ + /* Populate the new SessionTable object and link it into the list. + ** The new object must be linked onto the end of the list, not + ** simply added to the start of it in order to ensure that tables + ** appear in the correct order when a changeset or patchset is + ** eventually generated. */ + SessionTable **ppTab; + memset(pTab, 0, sizeof(SessionTable)); + pTab->zName = (char *)&pTab[1]; + memcpy(pTab->zName, zName, nName+1); + for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext); + *ppTab = pTab; + } + } + } + + sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); + return rc; +} + +/* +** Ensure that there is room in the buffer to append nByte bytes of data. +** If not, use sqlite3_realloc() to grow the buffer so that there is. +** +** 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->nAlloc : 128; + do { + nNew = nNew*2; + }while( nNew<(p->nBuf+nByte) ); + + aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew); + if( 0==aNew ){ + *pRc = SQLITE_NOMEM; + }else{ + p->aBuf = aNew; + p->nAlloc = nNew; + } + } + return (*pRc!=SQLITE_OK); +} + +/* +** Append the value passed as the second argument to the buffer passed +** as the first. +** +** This function is a no-op if *pRc is non-zero when it is called. +** Otherwise, if an error occurs, *pRc is set to an SQLite error code +** before returning. +*/ +static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){ + int rc = *pRc; + if( rc==SQLITE_OK ){ + int nByte = 0; + rc = sessionSerializeValue(0, pVal, &nByte); + sessionBufferGrow(p, nByte, &rc); + if( rc==SQLITE_OK ){ + rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0); + p->nBuf += nByte; + }else{ + *pRc = rc; + } + } +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a single byte to the buffer. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){ + if( 0==sessionBufferGrow(p, 1, pRc) ){ + p->aBuf[p->nBuf++] = v; + } +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a single varint to the buffer. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){ + if( 0==sessionBufferGrow(p, 9, pRc) ){ + p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v); + } +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a blob of data to the buffer. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendBlob( + SessionBuffer *p, + const u8 *aBlob, + int nBlob, + int *pRc +){ + if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){ + memcpy(&p->aBuf[p->nBuf], aBlob, nBlob); + p->nBuf += nBlob; + } +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a string to the buffer. All bytes in the string +** up to (but not including) the nul-terminator are written to the buffer. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendStr( + SessionBuffer *p, + const char *zStr, + int *pRc +){ + int nStr = sqlite3Strlen30(zStr); + if( 0==sessionBufferGrow(p, nStr, pRc) ){ + memcpy(&p->aBuf[p->nBuf], zStr, nStr); + p->nBuf += nStr; + } +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append the string representation of integer iVal +** to the buffer. No nul-terminator is written. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendInteger( + SessionBuffer *p, /* Buffer to append to */ + int iVal, /* Value to write the string rep. of */ + int *pRc /* IN/OUT: Error code */ +){ + char aBuf[24]; + sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal); + sessionAppendStr(p, aBuf, pRc); +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append the string zStr enclosed in quotes (") and +** with any embedded quote characters escaped to the buffer. No +** nul-terminator byte is written. +** +** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before +** returning. +*/ +static void sessionAppendIdent( + SessionBuffer *p, /* Buffer to a append to */ + const char *zStr, /* String to quote, escape and append */ + int *pRc /* IN/OUT: Error code */ +){ + int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1; + if( 0==sessionBufferGrow(p, nStr, pRc) ){ + char *zOut = (char *)&p->aBuf[p->nBuf]; + const char *zIn = zStr; + *zOut++ = '"'; + while( *zIn ){ + if( *zIn=='"' ) *zOut++ = '"'; + *zOut++ = *(zIn++); + } + *zOut++ = '"'; + p->nBuf = (int)((u8 *)zOut - p->aBuf); + } +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwse, it appends the serialized version of the value stored +** in column iCol of the row that SQL statement pStmt currently points +** to to the buffer. +*/ +static void sessionAppendCol( + SessionBuffer *p, /* Buffer to append to */ + sqlite3_stmt *pStmt, /* Handle pointing to row containing value */ + int iCol, /* Column to read value from */ + int *pRc /* IN/OUT: Error code */ +){ + if( *pRc==SQLITE_OK ){ + int eType = sqlite3_column_type(pStmt, iCol); + sessionAppendByte(p, (u8)eType, pRc); + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + sqlite3_int64 i; + u8 aBuf[8]; + if( eType==SQLITE_INTEGER ){ + i = sqlite3_column_int64(pStmt, iCol); + }else{ + double r = sqlite3_column_double(pStmt, iCol); + memcpy(&i, &r, 8); + } + sessionPutI64(aBuf, i); + sessionAppendBlob(p, aBuf, 8, pRc); + } + if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){ + u8 *z; + int nByte; + if( eType==SQLITE_BLOB ){ + z = (u8 *)sqlite3_column_blob(pStmt, iCol); + }else{ + z = (u8 *)sqlite3_column_text(pStmt, iCol); + } + nByte = sqlite3_column_bytes(pStmt, iCol); + if( z || (eType==SQLITE_BLOB && nByte==0) ){ + sessionAppendVarint(p, nByte, pRc); + sessionAppendBlob(p, z, nByte, pRc); + }else{ + *pRc = SQLITE_NOMEM; + } + } + } +} + +/* +** +** This function appends an update change to the buffer (see the comments +** under "CHANGESET FORMAT" at the top of the file). An update change +** consists of: +** +** 1 byte: SQLITE_UPDATE (0x17) +** n bytes: old.* record (see RECORD FORMAT) +** m bytes: new.* record (see RECORD FORMAT) +** +** The SessionChange object passed as the third argument contains the +** values that were stored in the row when the session began (the old.* +** values). The statement handle passed as the second argument points +** at the current version of the row (the new.* values). +** +** If all of the old.* values are equal to their corresponding new.* value +** (i.e. nothing has changed), then no data at all is appended to the buffer. +** +** Otherwise, the old.* record contains all primary key values and the +** original values of any fields that have been modified. The new.* record +** contains the new values of only those fields that have been modified. +*/ +static int sessionAppendUpdate( + SessionBuffer *pBuf, /* Buffer to append to */ + int bPatchset, /* True for "patchset", 0 for "changeset" */ + sqlite3_stmt *pStmt, /* Statement handle pointing at new row */ + SessionChange *p, /* Object containing old values */ + u8 *abPK /* Boolean array - true for PK columns */ +){ + int rc = SQLITE_OK; + SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */ + int bNoop = 1; /* Set to zero if any values are modified */ + int nRewind = pBuf->nBuf; /* Set to zero if any values are modified */ + int i; /* Used to iterate through columns */ + u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */ + + sessionAppendByte(pBuf, SQLITE_UPDATE, &rc); + sessionAppendByte(pBuf, p->bIndirect, &rc); + for(i=0; inBuf = nRewind; + }else{ + sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc); + } + sqlite3_free(buf2.aBuf); + + return rc; +} + +/* +** Append a DELETE change to the buffer passed as the first argument. Use +** the changeset format if argument bPatchset is zero, or the patchset +** format otherwise. +*/ +static int sessionAppendDelete( + SessionBuffer *pBuf, /* Buffer to append to */ + int bPatchset, /* True for "patchset", 0 for "changeset" */ + SessionChange *p, /* Object containing old values */ + int nCol, /* Number of columns in table */ + u8 *abPK /* Boolean array - true for PK columns */ +){ + int rc = SQLITE_OK; + + sessionAppendByte(pBuf, SQLITE_DELETE, &rc); + sessionAppendByte(pBuf, p->bIndirect, &rc); + + if( bPatchset==0 ){ + sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc); + }else{ + int i; + u8 *a = p->aRecord; + for(i=0; iaRecord)==p->nRecord ); + } + + return rc; +} + +/* +** Formulate and prepare a SELECT statement to retrieve a row from table +** zTab in database zDb based on its primary key. i.e. +** +** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ... +*/ +static int sessionSelectStmt( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Database name */ + const char *zTab, /* Table name */ + int nCol, /* Number of columns in table */ + const char **azCol, /* Names of table columns */ + u8 *abPK, /* PRIMARY KEY array */ + sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */ +){ + int rc = SQLITE_OK; + int i; + const char *zSep = ""; + SessionBuffer buf = {0, 0, 0}; + + sessionAppendStr(&buf, "SELECT * FROM ", &rc); + sessionAppendIdent(&buf, zDb, &rc); + sessionAppendStr(&buf, ".", &rc); + sessionAppendIdent(&buf, zTab, &rc); + sessionAppendStr(&buf, " WHERE ", &rc); + for(i=0; iaRecord; + + for(i=0; inCol, pRc); + sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc); + sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc); +} + +/* +** Generate either a changeset (if argument bPatchset is zero) or a patchset +** (if it is non-zero) based on the current contents of the session object +** passed as the first argument. +** +** If no error occurs, SQLITE_OK is returned and the new changeset/patchset +** stored in output variables *pnChangeset and *ppChangeset. Or, if an error +** occurs, an SQLite error code is returned and both output variables set +** to 0. +*/ +static int sessionGenerateChangeset( + sqlite3_session *pSession, /* Session object */ + int bPatchset, /* True for patchset, false for changeset */ + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut, /* First argument for xOutput */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ +){ + sqlite3 *db = pSession->db; /* Source database handle */ + SessionTable *pTab; /* Used to iterate through attached tables */ + SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ + int rc; /* Return code */ + + assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) ); + + /* Zero the output variables in case an error occurs. If this session + ** object is already in the error state (sqlite3_session.rc != SQLITE_OK), + ** this call will be a no-op. */ + if( xOutput==0 ){ + *pnChangeset = 0; + *ppChangeset = 0; + } + + if( pSession->rc ) return pSession->rc; + rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); + if( rc!=SQLITE_OK ) return rc; + + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + + for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ + if( pTab->nEntry ){ + const char *zName = pTab->zName; + int nCol; /* Number of columns in table */ + u8 *abPK; /* Primary key array */ + const char **azCol = 0; /* Table columns */ + int i; /* Used to iterate through hash buckets */ + sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ + int nRewind = buf.nBuf; /* Initial size of write buffer */ + int nNoop; /* Size of buffer after writing tbl header */ + + /* Check the table schema is still Ok. */ + rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK); + if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ + rc = SQLITE_SCHEMA; + } + + /* Write a table header */ + sessionAppendTableHdr(&buf, bPatchset, pTab, &rc); + + /* Build and compile a statement to execute: */ + if( rc==SQLITE_OK ){ + rc = sessionSelectStmt( + db, pSession->zDb, zName, nCol, azCol, abPK, &pSel); + } + + nNoop = buf.nBuf; + for(i=0; inChange && rc==SQLITE_OK; i++){ + SessionChange *p; /* Used to iterate through changes */ + + for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){ + rc = sessionSelectBind(pSel, nCol, abPK, p); + if( rc!=SQLITE_OK ) continue; + if( sqlite3_step(pSel)==SQLITE_ROW ){ + if( p->op==SQLITE_INSERT ){ + int iCol; + sessionAppendByte(&buf, SQLITE_INSERT, &rc); + sessionAppendByte(&buf, p->bIndirect, &rc); + for(iCol=0; iColop!=SQLITE_INSERT ){ + rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_reset(pSel); + } + + /* 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 + ){ + rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf); + nNoop = -1; + buf.nBuf = 0; + } + + } + } + + sqlite3_finalize(pSel); + if( buf.nBuf==nNoop ){ + buf.nBuf = nRewind; + } + sqlite3_free((char*)azCol); /* cast works around VC++ bug */ + } + } + + if( rc==SQLITE_OK ){ + if( xOutput==0 ){ + *pnChangeset = buf.nBuf; + *ppChangeset = buf.aBuf; + buf.aBuf = 0; + }else if( buf.nBuf>0 ){ + rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf); + } + } + + sqlite3_free(buf.aBuf); + sqlite3_exec(db, "RELEASE changeset", 0, 0, 0); + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + return rc; +} + +/* +** Obtain a changeset object containing all changes recorded by the +** session object passed as the first argument. +** +** It is the responsibility of the caller to eventually free the buffer +** using sqlite3_free(). +*/ +SQLITE_API int sqlite3session_changeset( + sqlite3_session *pSession, /* Session object */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ +){ + return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset); +} + +/* +** Streaming version of sqlite3session_changeset(). +*/ +SQLITE_API int sqlite3session_changeset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +){ + return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0); +} + +/* +** Streaming version of sqlite3session_patchset(). +*/ +SQLITE_API int sqlite3session_patchset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +){ + return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0); +} + +/* +** Obtain a patchset object containing all changes recorded by the +** session object passed as the first argument. +** +** It is the responsibility of the caller to eventually free the buffer +** using sqlite3_free(). +*/ +SQLITE_API int sqlite3session_patchset( + sqlite3_session *pSession, /* Session object */ + int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ + void **ppPatchset /* OUT: Buffer containing changeset */ +){ + return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset); +} + +/* +** Enable or disable the session object passed as the first argument. +*/ +SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){ + int ret; + sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); + if( bEnable>=0 ){ + pSession->bEnable = bEnable; + } + ret = pSession->bEnable; + sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); + return ret; +} + +/* +** Enable or disable the session object passed as the first argument. +*/ +SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){ + int ret; + sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); + if( bIndirect>=0 ){ + pSession->bIndirect = bIndirect; + } + ret = pSession->bIndirect; + sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); + return ret; +} + +/* +** Return true if there have been no changes to monitored tables recorded +** by the session object passed as the only argument. +*/ +SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){ + int ret = 0; + SessionTable *pTab; + + sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db)); + for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){ + ret = (pTab->nEntry>0); + } + sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); + + return (ret==0); +} + +/* +** Do the work for either sqlite3changeset_start() or start_strm(). +*/ +static int sessionChangesetStart( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + 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 */ +){ + sqlite3_changeset_iter *pRet; /* Iterator to return */ + int nByte; /* Number of bytes to allocate for iterator */ + + assert( xInput==0 || (pChangeset==0 && nChangeset==0) ); + + /* Zero the output variable in case an error occurs. */ + *pp = 0; + + /* Allocate and initialize the iterator structure. */ + nByte = sizeof(sqlite3_changeset_iter); + pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte); + if( !pRet ) return SQLITE_NOMEM; + memset(pRet, 0, sizeof(sqlite3_changeset_iter)); + pRet->in.aData = (u8 *)pChangeset; + pRet->in.nData = nChangeset; + pRet->in.xInput = xInput; + pRet->in.pIn = pIn; + pRet->in.bEof = (xInput ? 0 : 1); + + /* Populate the output variable and return success. */ + *pp = pRet; + return SQLITE_OK; +} + +/* +** Create an iterator used to iterate through the contents of a changeset. +*/ +SQLITE_API int sqlite3changeset_start( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int nChangeset, /* Size of buffer pChangeset in bytes */ + void *pChangeset /* Pointer to buffer containing changeset */ +){ + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset); +} + +/* +** Streaming version of sqlite3changeset_start(). +*/ +SQLITE_API int sqlite3changeset_start_strm( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +){ + return sessionChangesetStart(pp, xInput, pIn, 0, 0); +} + +/* +** If the SessionInput object passed as the only argument is a streaming +** object and the buffer is full, discard some data to free up space. +*/ +static void sessionDiscardData(SessionInput *pIn){ + if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){ + int nMove = pIn->buf.nBuf - pIn->iNext; + assert( nMove>=0 ); + if( nMove>0 ){ + memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove); + } + pIn->buf.nBuf -= pIn->iNext; + pIn->iNext = 0; + pIn->nData = pIn->buf.nBuf; + } +} + +/* +** Ensure that there are at least nByte bytes available in the buffer. Or, +** if there are not nByte bytes remaining in the input, that all available +** data is in the buffer. +** +** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. +*/ +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; + + if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn); + if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){ + rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew); + if( nNew==0 ){ + pIn->bEof = 1; + }else{ + pIn->buf.nBuf += nNew; + } + } + + pIn->aData = pIn->buf.aBuf; + pIn->nData = pIn->buf.nBuf; + } + } + return rc; +} + +/* +** When this function is called, *ppRec points to the start of a record +** that contains nCol values. This function advances the pointer *ppRec +** until it points to the byte immediately following that record. +*/ +static void sessionSkipRecord( + u8 **ppRec, /* IN/OUT: Record pointer */ + int nCol /* Number of values in record */ +){ + u8 *aRec = *ppRec; + int i; + for(i=0; iaData[pIn->iNext++]; + } + + assert( apOut[i]==0 ); + if( eType ){ + apOut[i] = sqlite3ValueNew(0); + if( !apOut[i] ) rc = SQLITE_NOMEM; + } + + if( rc==SQLITE_OK ){ + u8 *aVal = &pIn->aData[pIn->iNext]; + if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + int nByte; + pIn->iNext += sessionVarintGet(aVal, &nByte); + rc = sessionInputBuffer(pIn, nByte); + if( rc==SQLITE_OK ){ + u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0); + rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc); + } + pIn->iNext += nByte; + } + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + sqlite3_int64 v = sessionGetI64(aVal); + if( eType==SQLITE_INTEGER ){ + sqlite3VdbeMemSetInt64(apOut[i], v); + }else{ + double d; + memcpy(&d, &v, 8); + sqlite3VdbeMemSetDouble(apOut[i], d); + } + pIn->iNext += 8; + } + } + } + + return rc; +} + +/* +** The input pointer currently points to the second byte of a table-header. +** Specifically, to the following: +** +** + number of columns in table (varint) +** + array of PK flags (1 byte per column), +** + table name (nul terminated). +** +** This function ensures that all of the above is present in the input +** buffer (i.e. that it can be accessed without any calls to xInput()). +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +** The input pointer is not moved. +*/ +static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){ + int rc = SQLITE_OK; + int nCol = 0; + int nRead = 0; + + rc = sessionInputBuffer(pIn, 9); + if( rc==SQLITE_OK ){ + nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol); + rc = sessionInputBuffer(pIn, nRead+nCol+100); + nRead += nCol; + } + + while( rc==SQLITE_OK ){ + while( (pIn->iNext + nRead)nData && pIn->aData[pIn->iNext + nRead] ){ + nRead++; + } + if( (pIn->iNext + nRead)nData ) break; + rc = sessionInputBuffer(pIn, nRead + 100); + } + *pnByte = nRead+1; + return rc; +} + +/* +** The input pointer currently points to the first byte of the first field +** of a record consisting of nCol columns. This function ensures the entire +** record is buffered. It does not move the input pointer. +** +** If successful, SQLITE_OK is returned and *pnByte is set to the size of +** the record in bytes. Otherwise, an SQLite error code is returned. The +** final value of *pnByte is undefined in this case. +*/ +static int sessionChangesetBufferRecord( + SessionInput *pIn, /* Input data */ + int nCol, /* Number of columns in record */ + int *pnByte /* OUT: Size of record in bytes */ +){ + int rc = SQLITE_OK; + int nByte = 0; + int i; + for(i=0; rc==SQLITE_OK && iaData[pIn->iNext + nByte++]; + if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + int n; + nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n); + nByte += n; + rc = sessionInputBuffer(pIn, nByte); + }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + nByte += 8; + } + } + } + *pnByte = nByte; + return rc; +} + +/* +** The input pointer currently points to the second byte of a table-header. +** Specifically, to the following: +** +** + number of columns in table (varint) +** + array of PK flags (1 byte per column), +** + table name (nul terminated). +** +** This function decodes the table-header and populates the p->nCol, +** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is +** also allocated or resized according to the new value of p->nCol. The +** input pointer is left pointing to the byte following the table header. +** +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code +** is returned and the final values of the various fields enumerated above +** are undefined. +*/ +static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){ + int rc; + int nCopy; + assert( p->rc==SQLITE_OK ); + + rc = sessionChangesetBufferTblhdr(&p->in, &nCopy); + if( rc==SQLITE_OK ){ + int nByte; + int nVarint; + nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol); + nCopy -= nVarint; + p->in.iNext += nVarint; + nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy; + p->tblhdr.nBuf = 0; + sessionBufferGrow(&p->tblhdr, nByte, &rc); + } + + if( rc==SQLITE_OK ){ + int 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; + } + + p->apValue = (sqlite3_value**)p->tblhdr.aBuf; + p->abPK = (u8*)&p->apValue[p->nCol*2]; + p->zTab = (char*)&p->abPK[p->nCol]; + return (p->rc = rc); +} + +/* +** Advance the changeset iterator to the next change. +** +** If both paRec and pnRec are NULL, then this function works like the public +** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the +** sqlite3changeset_new() and old() APIs may be used to query for values. +** +** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change +** record is written to *paRec before returning and the number of bytes in +** the record to *pnRec. +** +** Either way, this function returns SQLITE_ROW if the iterator is +** successfully advanced to the next change in the changeset, an SQLite +** error code if an error occurs, or SQLITE_DONE if there are no further +** changes in the changeset. +*/ +static int sessionChangesetNext( + sqlite3_changeset_iter *p, /* Changeset iterator */ + u8 **paRec, /* If non-NULL, store record pointer here */ + int *pnRec /* If non-NULL, store size of record here */ +){ + int i; + u8 op; + + assert( (paRec==0 && pnRec==0) || (paRec && pnRec) ); + + /* If the iterator is in the error-state, return immediately. */ + if( p->rc!=SQLITE_OK ) return p->rc; + + /* Free the current contents of p->apValue[], if any. */ + if( p->apValue ){ + for(i=0; inCol*2; i++){ + sqlite3ValueFree(p->apValue[i]); + } + memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2); + } + + /* Make sure the buffer contains at least 10 bytes of input data, or all + ** remaining data if there are less than 10 bytes available. This is + ** sufficient either for the 'T' or 'P' byte and the varint that follows + ** it, or for the two single byte values otherwise. */ + p->rc = sessionInputBuffer(&p->in, 2); + if( p->rc!=SQLITE_OK ) return p->rc; + + /* If the iterator is already at the end of the changeset, return DONE. */ + if( p->in.iNext>=p->in.nData ){ + return SQLITE_DONE; + } + + sessionDiscardData(&p->in); + p->in.iCurrent = p->in.iNext; + + op = p->in.aData[p->in.iNext++]; + while( op=='T' || op=='P' ){ + p->bPatchset = (op=='P'); + if( sessionChangesetReadTblhdr(p) ) return p->rc; + if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc; + p->in.iCurrent = p->in.iNext; + if( p->in.iNext>=p->in.nData ) return SQLITE_DONE; + op = p->in.aData[p->in.iNext++]; + } + + p->op = op; + p->bIndirect = p->in.aData[p->in.iNext++]; + if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ + return (p->rc = SQLITE_CORRUPT_BKPT); + } + + if( paRec ){ + int nVal; /* Number of values to buffer */ + if( p->bPatchset==0 && op==SQLITE_UPDATE ){ + nVal = p->nCol * 2; + }else if( p->bPatchset && op==SQLITE_DELETE ){ + nVal = 0; + for(i=0; inCol; i++) if( p->abPK[i] ) nVal++; + }else{ + nVal = p->nCol; + } + p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec); + if( p->rc!=SQLITE_OK ) return p->rc; + *paRec = &p->in.aData[p->in.iNext]; + p->in.iNext += *pnRec; + }else{ + + /* 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); + 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]); + if( p->rc!=SQLITE_OK ) return p->rc; + } + + if( p->bPatchset && 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->abPK[i]==0 || p->apValue[i+p->nCol] ); + if( p->abPK[i] ){ + p->apValue[i] = p->apValue[i+p->nCol]; + p->apValue[i+p->nCol] = 0; + } + } + } + } + + return SQLITE_ROW; +} + +/* +** Advance an iterator created by sqlite3changeset_start() to the next +** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE +** or SQLITE_CORRUPT. +** +** This function may not be called on iterators passed to a conflict handler +** callback by changeset_apply(). +*/ +SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){ + return sessionChangesetNext(p, 0, 0); +} + +/* +** The following function extracts information on the current change +** from a changeset iterator. It may only be called after changeset_next() +** has returned SQLITE_ROW. +*/ +SQLITE_API int sqlite3changeset_op( + sqlite3_changeset_iter *pIter, /* Iterator handle */ + const char **pzTab, /* OUT: Pointer to table name */ + int *pnCol, /* OUT: Number of columns in table */ + int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int *pbIndirect /* OUT: True if change is indirect */ +){ + *pOp = pIter->op; + *pnCol = pIter->nCol; + *pzTab = pIter->zTab; + if( pbIndirect ) *pbIndirect = pIter->bIndirect; + return SQLITE_OK; +} + +/* +** Return information regarding the PRIMARY KEY and number of columns in +** the database table affected by the change that pIter currently points +** to. This function may only be called after changeset_next() returns +** SQLITE_ROW. +*/ +SQLITE_API int sqlite3changeset_pk( + sqlite3_changeset_iter *pIter, /* Iterator object */ + unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ + int *pnCol /* OUT: Number of entries in output array */ +){ + *pabPK = pIter->abPK; + if( pnCol ) *pnCol = pIter->nCol; + return SQLITE_OK; +} + +/* +** This function may only be called while the iterator is pointing to an +** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()). +** Otherwise, SQLITE_MISUSE is returned. +** +** It sets *ppValue to point to an sqlite3_value structure containing the +** iVal'th value in the old.* record. Or, if that particular value is not +** included in the record (because the change is an UPDATE and the field +** was not modified and is not a PK column), set *ppValue to NULL. +** +** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is +** not modified. Otherwise, SQLITE_OK. +*/ +SQLITE_API int sqlite3changeset_old( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Index of old.* value to retrieve */ + sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ +){ + if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){ + return SQLITE_MISUSE; + } + if( iVal<0 || iVal>=pIter->nCol ){ + return SQLITE_RANGE; + } + *ppValue = pIter->apValue[iVal]; + return SQLITE_OK; +} + +/* +** This function may only be called while the iterator is pointing to an +** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()). +** Otherwise, SQLITE_MISUSE is returned. +** +** It sets *ppValue to point to an sqlite3_value structure containing the +** iVal'th value in the new.* record. Or, if that particular value is not +** included in the record (because the change is an UPDATE and the field +** was not modified), set *ppValue to NULL. +** +** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is +** not modified. Otherwise, SQLITE_OK. +*/ +SQLITE_API int sqlite3changeset_new( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Index of new.* value to retrieve */ + sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ +){ + if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){ + return SQLITE_MISUSE; + } + if( iVal<0 || iVal>=pIter->nCol ){ + return SQLITE_RANGE; + } + *ppValue = pIter->apValue[pIter->nCol+iVal]; + return SQLITE_OK; +} + +/* +** The following two macros are used internally. They are similar to the +** sqlite3changeset_new() and sqlite3changeset_old() functions, except that +** they omit all error checking and return a pointer to the requested value. +*/ +#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)] +#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)] + +/* +** This function may only be called with a changeset iterator that has been +** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT +** conflict-handler function. Otherwise, SQLITE_MISUSE is returned. +** +** If successful, *ppValue is set to point to an sqlite3_value structure +** containing the iVal'th value of the conflicting record. +** +** If value iVal is out-of-range or some other error occurs, an SQLite error +** code is returned. Otherwise, SQLITE_OK. +*/ +SQLITE_API int sqlite3changeset_conflict( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Index of conflict record value to fetch */ + sqlite3_value **ppValue /* OUT: Value from conflicting row */ +){ + if( !pIter->pConflict ){ + return SQLITE_MISUSE; + } + if( iVal<0 || iVal>=pIter->nCol ){ + return SQLITE_RANGE; + } + *ppValue = sqlite3_column_value(pIter->pConflict, iVal); + return SQLITE_OK; +} + +/* +** This function may only be called with an iterator passed to an +** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case +** it sets the output variable to the total number of known foreign key +** violations in the destination database and returns SQLITE_OK. +** +** In all other cases this function returns SQLITE_MISUSE. +*/ +SQLITE_API int sqlite3changeset_fk_conflicts( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int *pnOut /* OUT: Number of FK violations */ +){ + if( pIter->pConflict || pIter->apValue ){ + return SQLITE_MISUSE; + } + *pnOut = pIter->nCol; + return SQLITE_OK; +} + + +/* +** Finalize an iterator allocated with sqlite3changeset_start(). +** +** This function may not be called on iterators passed to a conflict handler +** callback by changeset_apply(). +*/ +SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){ + int rc = SQLITE_OK; + if( p ){ + int i; /* Used to iterate through p->apValue[] */ + rc = p->rc; + if( p->apValue ){ + for(i=0; inCol*2; i++) sqlite3ValueFree(p->apValue[i]); + } + sqlite3_free(p->tblhdr.aBuf); + sqlite3_free(p->in.buf.aBuf); + sqlite3_free(p); + } + return rc; +} + +static int sessionChangesetInvert( + SessionInput *pInput, /* Input changeset */ + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut, + int *pnInverted, /* OUT: Number of bytes in output changeset */ + void **ppInverted /* OUT: Inverse of pChangeset */ +){ + int rc = SQLITE_OK; /* Return value */ + SessionBuffer sOut; /* Output buffer */ + int nCol = 0; /* Number of cols in current table */ + u8 *abPK = 0; /* PK array for current table */ + sqlite3_value **apVal = 0; /* Space for values for UPDATE inversion */ + SessionBuffer sPK = {0, 0, 0}; /* PK array for current table */ + + /* Initialize the output buffer */ + memset(&sOut, 0, sizeof(SessionBuffer)); + + /* Zero the output variables in case an error occurs. */ + if( ppInverted ){ + *ppInverted = 0; + *pnInverted = 0; + } + + while( 1 ){ + u8 eType; + + /* Test for EOF. */ + if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert; + if( pInput->iNext>=pInput->nData ) break; + eType = pInput->aData[pInput->iNext]; + + switch( eType ){ + case 'T': { + /* A 'table' record consists of: + ** + ** * A constant 'T' character, + ** * Number of columns in said table (a varint), + ** * An array of nCol bytes (sPK), + ** * A nul-terminated table name. + */ + int nByte; + int nVar; + pInput->iNext++; + if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){ + goto finished_invert; + } + nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol); + sPK.nBuf = 0; + sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc); + sessionAppendByte(&sOut, eType, &rc); + sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc); + if( rc ) goto finished_invert; + + pInput->iNext += nByte; + sqlite3_free(apVal); + apVal = 0; + abPK = sPK.aBuf; + break; + } + + case SQLITE_INSERT: + case SQLITE_DELETE: { + int nByte; + int bIndirect = pInput->aData[pInput->iNext+1]; + int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE); + pInput->iNext += 2; + assert( rc==SQLITE_OK ); + rc = sessionChangesetBufferRecord(pInput, nCol, &nByte); + sessionAppendByte(&sOut, eType2, &rc); + sessionAppendByte(&sOut, bIndirect, &rc); + sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc); + pInput->iNext += nByte; + if( rc ) goto finished_invert; + break; + } + + case SQLITE_UPDATE: { + int iCol; + + if( 0==apVal ){ + apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2); + if( 0==apVal ){ + rc = SQLITE_NOMEM; + goto finished_invert; + } + memset(apVal, 0, sizeof(apVal[0])*nCol*2); + } + + /* Write the header for the new UPDATE change. Same as the original. */ + sessionAppendByte(&sOut, eType, &rc); + sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc); + + /* Read the old.* and new.* records for the update change. */ + pInput->iNext += 2; + rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]); + if( rc==SQLITE_OK ){ + rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]); + } + + /* Write the new old.* record. Consists of the PK columns from the + ** original old.* record, and the other values from the original + ** new.* record. */ + for(iCol=0; iCol=SESSIONS_STRM_CHUNK_SIZE ){ + rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); + sOut.nBuf = 0; + if( rc!=SQLITE_OK ) goto finished_invert; + } + } + + assert( rc==SQLITE_OK ); + if( pnInverted ){ + *pnInverted = sOut.nBuf; + *ppInverted = sOut.aBuf; + sOut.aBuf = 0; + }else if( sOut.nBuf>0 ){ + rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); + } + + finished_invert: + sqlite3_free(sOut.aBuf); + sqlite3_free(apVal); + sqlite3_free(sPK.aBuf); + return rc; +} + + +/* +** Invert a changeset object. +*/ +SQLITE_API int sqlite3changeset_invert( + int nChangeset, /* Number of bytes in input */ + const void *pChangeset, /* Input changeset */ + int *pnInverted, /* OUT: Number of bytes in output changeset */ + void **ppInverted /* OUT: Inverse of pChangeset */ +){ + SessionInput sInput; + + /* Set up the input stream */ + memset(&sInput, 0, sizeof(SessionInput)); + sInput.nData = nChangeset; + sInput.aData = (u8*)pChangeset; + + return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted); +} + +/* +** Streaming version of sqlite3changeset_invert(). +*/ +SQLITE_API int sqlite3changeset_invert_strm( + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +){ + SessionInput sInput; + int rc; + + /* Set up the input stream */ + memset(&sInput, 0, sizeof(SessionInput)); + sInput.xInput = xInput; + sInput.pIn = pIn; + + rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0); + sqlite3_free(sInput.buf.aBuf); + return rc; +} + +typedef struct SessionApplyCtx SessionApplyCtx; +struct SessionApplyCtx { + sqlite3 *db; + sqlite3_stmt *pDelete; /* DELETE statement */ + sqlite3_stmt *pUpdate; /* UPDATE statement */ + sqlite3_stmt *pInsert; /* INSERT statement */ + sqlite3_stmt *pSelect; /* SELECT statement */ + int nCol; /* Size of azCol[] and abPK[] arrays */ + const char **azCol; /* Array of column names */ + u8 *abPK; /* Boolean array - true if column is in PK */ + + int bDeferConstraints; /* True to defer constraints */ + SessionBuffer constraints; /* Deferred constraints are stored here */ +}; + +/* +** Formulate a statement to DELETE a row from database db. Assuming a table +** structure like this: +** +** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); +** +** The DELETE statement looks like this: +** +** DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4) +** +** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require +** matching b and d values, or 1 otherwise. The second case comes up if the +** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE. +** +** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left +** pointing to the prepared version of the SQL statement. +*/ +static int sessionDeleteRow( + sqlite3 *db, /* Database handle */ + const char *zTab, /* Table name */ + SessionApplyCtx *p /* Session changeset-apply context */ +){ + int i; + const char *zSep = ""; + int rc = SQLITE_OK; + SessionBuffer buf = {0, 0, 0}; + int nPk = 0; + + sessionAppendStr(&buf, "DELETE FROM ", &rc); + sessionAppendIdent(&buf, zTab, &rc); + sessionAppendStr(&buf, " WHERE ", &rc); + + for(i=0; inCol; i++){ + if( p->abPK[i] ){ + nPk++; + sessionAppendStr(&buf, zSep, &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + sessionAppendStr(&buf, " = ?", &rc); + sessionAppendInteger(&buf, i+1, &rc); + zSep = " AND "; + } + } + + if( nPknCol ){ + sessionAppendStr(&buf, " AND (?", &rc); + sessionAppendInteger(&buf, p->nCol+1, &rc); + sessionAppendStr(&buf, " OR ", &rc); + + zSep = ""; + for(i=0; inCol; i++){ + if( !p->abPK[i] ){ + sessionAppendStr(&buf, zSep, &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + sessionAppendStr(&buf, " IS ?", &rc); + sessionAppendInteger(&buf, i+1, &rc); + zSep = "AND "; + } + } + sessionAppendStr(&buf, ")", &rc); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0); + } + sqlite3_free(buf.aBuf); + + return rc; +} + +/* +** Formulate and prepare a statement to UPDATE a row from database db. +** Assuming a table structure like this: +** +** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); +** +** The UPDATE statement looks like this: +** +** UPDATE x SET +** a = CASE WHEN ?2 THEN ?3 ELSE a END, +** b = CASE WHEN ?5 THEN ?6 ELSE b END, +** c = CASE WHEN ?8 THEN ?9 ELSE c END, +** d = CASE WHEN ?11 THEN ?12 ELSE d END +** WHERE a = ?1 AND c = ?7 AND (?13 OR +** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND +** ) +** +** For each column in the table, there are three variables to bind: +** +** ?(i*3+1) The old.* value of the column, if any. +** ?(i*3+2) A boolean flag indicating that the value is being modified. +** ?(i*3+3) The new.* value of the column, if any. +** +** Also, a boolean flag that, if set to true, causes the statement to update +** a row even if the non-PK values do not match. This is required if the +** conflict-handler is invoked with CHANGESET_DATA and returns +** CHANGESET_REPLACE. This is variable "?(nCol*3+1)". +** +** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left +** pointing to the prepared version of the SQL statement. +*/ +static int sessionUpdateRow( + sqlite3 *db, /* Database handle */ + const char *zTab, /* Table name */ + SessionApplyCtx *p /* Session changeset-apply context */ +){ + int rc = SQLITE_OK; + int i; + const char *zSep = ""; + SessionBuffer buf = {0, 0, 0}; + + /* Append "UPDATE tbl SET " */ + sessionAppendStr(&buf, "UPDATE ", &rc); + sessionAppendIdent(&buf, zTab, &rc); + sessionAppendStr(&buf, " SET ", &rc); + + /* Append the assignments */ + for(i=0; inCol; i++){ + sessionAppendStr(&buf, zSep, &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + sessionAppendStr(&buf, " = CASE WHEN ?", &rc); + sessionAppendInteger(&buf, i*3+2, &rc); + sessionAppendStr(&buf, " THEN ?", &rc); + sessionAppendInteger(&buf, i*3+3, &rc); + sessionAppendStr(&buf, " ELSE ", &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + sessionAppendStr(&buf, " END", &rc); + zSep = ", "; + } + + /* Append the PK part of the WHERE clause */ + sessionAppendStr(&buf, " WHERE ", &rc); + for(i=0; inCol; i++){ + if( p->abPK[i] ){ + sessionAppendIdent(&buf, p->azCol[i], &rc); + sessionAppendStr(&buf, " = ?", &rc); + sessionAppendInteger(&buf, i*3+1, &rc); + sessionAppendStr(&buf, " AND ", &rc); + } + } + + /* Append the non-PK part of the WHERE clause */ + sessionAppendStr(&buf, " (?", &rc); + sessionAppendInteger(&buf, p->nCol*3+1, &rc); + sessionAppendStr(&buf, " OR 1", &rc); + for(i=0; inCol; i++){ + if( !p->abPK[i] ){ + sessionAppendStr(&buf, " AND (?", &rc); + sessionAppendInteger(&buf, i*3+2, &rc); + sessionAppendStr(&buf, "=0 OR ", &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + sessionAppendStr(&buf, " IS ?", &rc); + sessionAppendInteger(&buf, i*3+1, &rc); + sessionAppendStr(&buf, ")", &rc); + } + } + sessionAppendStr(&buf, ")", &rc); + + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0); + } + sqlite3_free(buf.aBuf); + + return rc; +} + +/* +** Formulate and prepare an SQL statement to query table zTab by primary +** key. Assuming the following table structure: +** +** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); +** +** The SELECT statement looks like this: +** +** SELECT * FROM x WHERE a = ?1 AND c = ?3 +** +** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left +** pointing to the prepared version of the SQL statement. +*/ +static int sessionSelectRow( + sqlite3 *db, /* Database handle */ + const char *zTab, /* Table name */ + SessionApplyCtx *p /* Session changeset-apply context */ +){ + return sessionSelectStmt( + db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect); +} + +/* +** Formulate and prepare an INSERT statement to add a record to table zTab. +** For example: +** +** INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...); +** +** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left +** pointing to the prepared version of the SQL statement. +*/ +static int sessionInsertRow( + sqlite3 *db, /* Database handle */ + const char *zTab, /* Table name */ + SessionApplyCtx *p /* Session changeset-apply context */ +){ + int rc = SQLITE_OK; + int i; + SessionBuffer buf = {0, 0, 0}; + + sessionAppendStr(&buf, "INSERT INTO main.", &rc); + sessionAppendIdent(&buf, zTab, &rc); + sessionAppendStr(&buf, "(", &rc); + for(i=0; inCol; i++){ + if( i!=0 ) sessionAppendStr(&buf, ", ", &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + } + + sessionAppendStr(&buf, ") VALUES(?", &rc); + for(i=1; inCol; i++){ + sessionAppendStr(&buf, ", ?", &rc); + } + sessionAppendStr(&buf, ")", &rc); + + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0); + } + sqlite3_free(buf.aBuf); + return rc; +} + +/* +** A wrapper around sqlite3_bind_value() that detects an extra problem. +** See comments in the body of this function for details. +*/ +static int sessionBindValue( + sqlite3_stmt *pStmt, /* Statement to bind value to */ + int i, /* Parameter number to bind to */ + sqlite3_value *pVal /* Value to bind */ +){ + int eType = sqlite3_value_type(pVal); + /* COVERAGE: The (pVal->z==0) branch is never true using current versions + ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either + ** the (pVal->z) variable remains as it was or the type of the value is + ** set to SQLITE_NULL. */ + if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){ + /* This condition occurs when an earlier OOM in a call to + ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within + ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */ + return SQLITE_NOMEM; + } + return sqlite3_bind_value(pStmt, i, pVal); +} + +/* +** Iterator pIter must point to an SQLITE_INSERT entry. This function +** transfers new.* values from the current iterator entry to statement +** pStmt. The table being inserted into has nCol columns. +** +** New.* value $i from the iterator is bound to variable ($i+1) of +** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1) +** are transfered to the statement. Otherwise, if abPK is not NULL, it points +** to an array nCol elements in size. In this case only those values for +** which abPK[$i] is true are read from the iterator and bound to the +** statement. +** +** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK. +*/ +static int sessionBindRow( + sqlite3_changeset_iter *pIter, /* Iterator to read values from */ + int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **), + int nCol, /* Number of columns */ + u8 *abPK, /* If not NULL, bind only if true */ + sqlite3_stmt *pStmt /* Bind values to this statement */ +){ + int i; + int rc = SQLITE_OK; + + /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the + ** argument iterator points to a suitable entry. Make sure that xValue + ** is one of these to guarantee that it is safe to ignore the return + ** in the code below. */ + assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); + + for(i=0; rc==SQLITE_OK && idb, pIter, p->abPK, p->pSelect); + }else{ + rc = SQLITE_OK; + } + + if( rc==SQLITE_ROW ){ + /* There exists another row with the new.* primary key. */ + pIter->pConflict = p->pSelect; + res = xConflict(pCtx, eType, pIter); + pIter->pConflict = 0; + rc = sqlite3_reset(p->pSelect); + }else if( rc==SQLITE_OK ){ + if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){ + /* Instead of invoking the conflict handler, append the change blob + ** to the SessionApplyCtx.constraints buffer. */ + u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent]; + int nBlob = pIter->in.iNext - pIter->in.iCurrent; + sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc); + res = SQLITE_CHANGESET_OMIT; + }else{ + /* No other row with the new.* primary key. */ + res = xConflict(pCtx, eType+1, pIter); + if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE; + } + } + + if( rc==SQLITE_OK ){ + switch( res ){ + case SQLITE_CHANGESET_REPLACE: + assert( pbReplace ); + *pbReplace = 1; + break; + + case SQLITE_CHANGESET_OMIT: + break; + + case SQLITE_CHANGESET_ABORT: + rc = SQLITE_ABORT; + break; + + default: + rc = SQLITE_MISUSE; + break; + } + } + + return rc; +} + +/* +** Attempt to apply the change that the iterator passed as the first argument +** currently points to to the database. If a conflict is encountered, invoke +** the conflict handler callback. +** +** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If +** one is encountered, update or delete the row with the matching primary key +** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs, +** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry +** to true before returning. In this case the caller will invoke this function +** again, this time with pbRetry set to NULL. +** +** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is +** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead. +** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such +** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true +** before retrying. In this case the caller attempts to remove the conflicting +** row before invoking this function again, this time with pbReplace set +** to NULL. +** +** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function +** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is +** returned. +*/ +static int sessionApplyOneOp( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + SessionApplyCtx *p, /* changeset_apply() context */ + int(*xConflict)(void *, int, sqlite3_changeset_iter *), + void *pCtx, /* First argument for the conflict handler */ + int *pbReplace, /* OUT: True to remove PK row and retry */ + int *pbRetry /* OUT: True to retry. */ +){ + const char *zDummy; + int op; + int nCol; + int rc = SQLITE_OK; + + assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect ); + assert( p->azCol && p->abPK ); + assert( !pbReplace || *pbReplace==0 ); + + sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); + + if( op==SQLITE_DELETE ){ + + /* Bind values to the DELETE statement. If conflict handling is required, + ** bind values for all columns and set bound variable (nCol+1) to true. + ** Or, if conflict handling is not required, bind just the PK column + ** values and, if it exists, set (nCol+1) to false. Conflict handling + ** is not required if: + ** + ** * this is a patchset, or + ** * (pbRetry==0), or + ** * all columns of the table are PK columns (in this case there is + ** no (nCol+1) variable to bind to). + */ + u8 *abPK = (pIter->bPatchset ? p->abPK : 0); + rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete); + if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){ + rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK)); + } + if( rc!=SQLITE_OK ) return rc; + + sqlite3_step(p->pDelete); + rc = sqlite3_reset(p->pDelete); + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ + rc = sessionConflictHandler( + SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry + ); + }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ + rc = sessionConflictHandler( + SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 + ); + } + + }else if( op==SQLITE_UPDATE ){ + int i; + + /* Bind values to the UPDATE statement. */ + for(i=0; rc==SQLITE_OK && ipUpdate, i*3+2, !!pNew); + if( pOld ){ + rc = sessionBindValue(p->pUpdate, i*3+1, pOld); + } + if( rc==SQLITE_OK && pNew ){ + rc = sessionBindValue(p->pUpdate, i*3+3, pNew); + } + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset); + } + if( rc!=SQLITE_OK ) return rc; + + /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict, + ** the result will be SQLITE_OK with 0 rows modified. */ + sqlite3_step(p->pUpdate); + rc = sqlite3_reset(p->pUpdate); + + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ + /* A NOTFOUND or DATA error. Search the table to see if it contains + ** a row with a matching primary key. If so, this is a DATA conflict. + ** Otherwise, if there is no primary key match, it is a NOTFOUND. */ + + rc = sessionConflictHandler( + SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry + ); + + }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ + /* This is always a CONSTRAINT conflict. */ + rc = sessionConflictHandler( + SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 + ); + } + + }else{ + assert( op==SQLITE_INSERT ); + rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert); + if( rc!=SQLITE_OK ) return rc; + + sqlite3_step(p->pInsert); + rc = sqlite3_reset(p->pInsert); + if( (rc&0xff)==SQLITE_CONSTRAINT ){ + rc = sessionConflictHandler( + SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace + ); + } + } + + return rc; +} + +/* +** Attempt to apply the change that the iterator passed as the first argument +** currently points to to the database. If a conflict is encountered, invoke +** the conflict handler callback. +** +** The difference between this function and sessionApplyOne() is that this +** function handles the case where the conflict-handler is invoked and +** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be +** retried in some manner. +*/ +static int sessionApplyOneWithRetry( + sqlite3 *db, /* Apply change to "main" db of this handle */ + sqlite3_changeset_iter *pIter, /* Changeset iterator to read change from */ + SessionApplyCtx *pApply, /* Apply context */ + int(*xConflict)(void*, int, sqlite3_changeset_iter*), + void *pCtx /* First argument passed to xConflict */ +){ + int bReplace = 0; + int bRetry = 0; + int rc; + + rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry); + assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) ); + + /* If the bRetry flag is set, the change has not been applied due to an + ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and + ** a row with the correct PK is present in the db, but one or more other + ** fields do not contain the expected values) and the conflict handler + ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation, + ** but pass NULL as the final argument so that sessionApplyOneOp() ignores + ** the SQLITE_CHANGESET_DATA problem. */ + if( bRetry ){ + assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE ); + rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0); + } + + /* If the bReplace flag is set, the change is an INSERT that has not + ** been performed because the database already contains a row with the + ** specified primary key and the conflict handler returned + ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row + ** before reattempting the INSERT. */ + else if( bReplace ){ + assert( pIter->op==SQLITE_INSERT ); + rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sessionBindRow(pIter, + sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete); + sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1); + } + if( rc==SQLITE_OK ){ + sqlite3_step(pApply->pDelete); + rc = sqlite3_reset(pApply->pDelete); + } + if( rc==SQLITE_OK ){ + rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0); + } + } + + return rc; +} + +/* +** Retry the changes accumulated in the pApply->constraints buffer. +*/ +static int sessionRetryConstraints( + sqlite3 *db, + int bPatchset, + const char *zTab, + SessionApplyCtx *pApply, + int(*xConflict)(void*, int, sqlite3_changeset_iter*), + void *pCtx /* First argument passed to xConflict */ +){ + int rc = SQLITE_OK; + + while( pApply->constraints.nBuf ){ + sqlite3_changeset_iter *pIter2 = 0; + SessionBuffer cons = pApply->constraints; + memset(&pApply->constraints, 0, sizeof(SessionBuffer)); + + rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf); + if( rc==SQLITE_OK ){ + int nByte = 2*pApply->nCol*sizeof(sqlite3_value*); + int rc2; + pIter2->bPatchset = bPatchset; + pIter2->zTab = (char*)zTab; + pIter2->nCol = pApply->nCol; + pIter2->abPK = pApply->abPK; + sessionBufferGrow(&pIter2->tblhdr, nByte, &rc); + pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf; + if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte); + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){ + rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx); + } + + rc2 = sqlite3changeset_finalize(pIter2); + if( rc==SQLITE_OK ) rc = rc2; + } + assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 ); + + sqlite3_free(cons.aBuf); + if( rc!=SQLITE_OK ) break; + if( pApply->constraints.nBuf>=cons.nBuf ){ + /* No progress was made on the last round. */ + pApply->bDeferConstraints = 0; + } + } + + return rc; +} + +/* +** Argument pIter is a changeset iterator that has been initialized, but +** not yet passed to sqlite3changeset_next(). This function applies the +** changeset to the main database attached to handle "db". The supplied +** conflict handler callback is invoked to resolve any conflicts encountered +** while applying the change. +*/ +static int sessionChangesetApply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + sqlite3_changeset_iter *pIter, /* Changeset to apply */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of fifth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +){ + int schemaMismatch = 0; + int rc; /* Return code */ + const char *zTab = 0; /* Name of current table */ + int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ + SessionApplyCtx sApply; /* changeset_apply() context object */ + int bPatchset; + + assert( xConflict!=0 ); + + pIter->in.bNoDiscard = 1; + memset(&sApply, 0, sizeof(sApply)); + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0); + } + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){ + int nCol; + int op; + const char *zNew; + + sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0); + + if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){ + u8 *abPK; + + rc = sessionRetryConstraints( + db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx + ); + if( rc!=SQLITE_OK ) break; + + sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ + sqlite3_finalize(sApply.pDelete); + sqlite3_finalize(sApply.pUpdate); + sqlite3_finalize(sApply.pInsert); + sqlite3_finalize(sApply.pSelect); + memset(&sApply, 0, sizeof(sApply)); + sApply.db = db; + sApply.bDeferConstraints = 1; + + /* If an xFilter() callback was specified, invoke it now. If the + ** xFilter callback returns zero, skip this table. If it returns + ** non-zero, proceed. */ + schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew))); + if( schemaMismatch ){ + zTab = sqlite3_mprintf("%s", zNew); + if( zTab==0 ){ + rc = SQLITE_NOMEM; + break; + } + nTab = (int)strlen(zTab); + sApply.azCol = (const char **)zTab; + }else{ + int nMinCol = 0; + int i; + + sqlite3changeset_pk(pIter, &abPK, 0); + rc = sessionTableInfo( + db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK + ); + if( rc!=SQLITE_OK ) break; + for(i=0; ibPatchset; + if( rc==SQLITE_OK ){ + rc = sqlite3changeset_finalize(pIter); + }else{ + sqlite3changeset_finalize(pIter); + } + + if( rc==SQLITE_OK ){ + rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx); + } + + if( rc==SQLITE_OK ){ + int nFk, notUsed; + sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, ¬Used, 0); + if( nFk!=0 ){ + int res = SQLITE_CHANGESET_ABORT; + sqlite3_changeset_iter sIter; + memset(&sIter, 0, sizeof(sIter)); + sIter.nCol = nFk; + res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter); + if( res!=SQLITE_CHANGESET_OMIT ){ + rc = SQLITE_CONSTRAINT; + } + } + } + sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0); + + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); + }else{ + sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0); + sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); + } + + sqlite3_finalize(sApply.pInsert); + sqlite3_finalize(sApply.pDelete); + sqlite3_finalize(sApply.pUpdate); + sqlite3_finalize(sApply.pSelect); + sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ + sqlite3_free((char*)sApply.constraints.aBuf); + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + return rc; +} + +/* +** Apply the changeset passed via pChangeset/nChangeset to the main database +** attached to handle "db". Invoke the supplied conflict handler callback +** to resolve any conflicts encountered while applying the change. +*/ +SQLITE_API int sqlite3changeset_apply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of fifth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +){ + sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ + int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + if( rc==SQLITE_OK ){ + rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx); + } + return rc; +} + +/* +** Apply the changeset passed via xInput/pIn to the main database +** attached to handle "db". Invoke the supplied conflict handler callback +** to resolve any conflicts encountered while applying the change. +*/ +SQLITE_API int sqlite3changeset_apply_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +){ + sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ + int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); + if( rc==SQLITE_OK ){ + rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx); + } + return rc; +} + +/* +** sqlite3_changegroup handle. +*/ +struct sqlite3_changegroup { + int rc; /* Error code */ + int bPatch; /* True to accumulate patchsets */ + SessionTable *pList; /* List of tables in current patch */ +}; + +/* +** This function is called to merge two changes to the same row together as +** part of an sqlite3changeset_concat() operation. A new change object is +** allocated and a pointer to it stored in *ppNew. +*/ +static int sessionChangeMerge( + SessionTable *pTab, /* Table structure */ + int bPatchset, /* True for patchsets */ + SessionChange *pExist, /* Existing change */ + int op2, /* Second change operation */ + int bIndirect, /* True if second change is indirect */ + u8 *aRec, /* Second change record */ + int nRec, /* Number of bytes in aRec */ + SessionChange **ppNew /* OUT: Merged change */ +){ + SessionChange *pNew = 0; + + if( !pExist ){ + pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec); + if( !pNew ){ + return SQLITE_NOMEM; + } + memset(pNew, 0, sizeof(SessionChange)); + pNew->op = op2; + pNew->bIndirect = bIndirect; + pNew->nRecord = nRec; + pNew->aRecord = (u8*)&pNew[1]; + memcpy(pNew->aRecord, aRec, nRec); + }else{ + int op1 = pExist->op; + + /* + ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2. + ** op1=INSERT, op2=UPDATE -> INSERT. + ** op1=INSERT, op2=DELETE -> (none) + ** + ** op1=UPDATE, op2=INSERT -> Unsupported. Discard op2. + ** op1=UPDATE, op2=UPDATE -> UPDATE. + ** op1=UPDATE, op2=DELETE -> DELETE. + ** + ** op1=DELETE, op2=INSERT -> UPDATE. + ** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2. + ** op1=DELETE, op2=DELETE -> Unsupported. Discard op2. + */ + if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT) + || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT) + || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE) + || (op1==SQLITE_DELETE && op2==SQLITE_DELETE) + ){ + pNew = pExist; + }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){ + sqlite3_free(pExist); + assert( pNew==0 ); + }else{ + u8 *aExist = pExist->aRecord; + int 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); + if( !pNew ){ + sqlite3_free(pExist); + return SQLITE_NOMEM; + } + memset(pNew, 0, sizeof(SessionChange)); + pNew->bIndirect = (bIndirect && pExist->bIndirect); + aCsr = pNew->aRecord = (u8 *)&pNew[1]; + + if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */ + u8 *a1 = aRec; + assert( op2==SQLITE_UPDATE ); + pNew->op = SQLITE_INSERT; + if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol); + sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1); + }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */ + assert( op2==SQLITE_INSERT ); + pNew->op = SQLITE_UPDATE; + if( bPatchset ){ + memcpy(aCsr, aRec, nRec); + aCsr += nRec; + }else{ + if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){ + sqlite3_free(pNew); + pNew = 0; + } + } + }else if( op2==SQLITE_UPDATE ){ /* UPDATE + UPDATE */ + u8 *a1 = aExist; + u8 *a2 = aRec; + assert( op1==SQLITE_UPDATE ); + if( bPatchset==0 ){ + sessionSkipRecord(&a1, pTab->nCol); + sessionSkipRecord(&a2, pTab->nCol); + } + pNew->op = SQLITE_UPDATE; + if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){ + sqlite3_free(pNew); + pNew = 0; + } + }else{ /* UPDATE + DELETE */ + assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE ); + pNew->op = SQLITE_DELETE; + if( bPatchset ){ + memcpy(aCsr, aRec, nRec); + aCsr += nRec; + }else{ + sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist); + } + } + + if( pNew ){ + pNew->nRecord = (int)(aCsr - pNew->aRecord); + } + sqlite3_free(pExist); + } + } + + *ppNew = pNew; + return SQLITE_OK; +} + +/* +** Add all changes in the changeset traversed by the iterator passed as +** the first argument to the changegroup hash tables. +*/ +static int sessionChangesetToHash( + sqlite3_changeset_iter *pIter, /* Iterator to read from */ + sqlite3_changegroup *pGrp /* Changegroup object to add changeset to */ +){ + u8 *aRec; + int nRec; + int rc = SQLITE_OK; + SessionTable *pTab = 0; + + + while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){ + const char *zNew; + int nCol; + int op; + int iHash; + int bIndirect; + SessionChange *pChange; + SessionChange *pExist = 0; + SessionChange **pp; + + if( pGrp->pList==0 ){ + pGrp->bPatch = pIter->bPatchset; + }else if( pIter->bPatchset!=pGrp->bPatch ){ + rc = SQLITE_ERROR; + break; + } + + sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect); + if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){ + /* Search the list for a matching table */ + int nNew = (int)strlen(zNew); + u8 *abPK; + + sqlite3changeset_pk(pIter, &abPK, 0); + for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break; + } + if( !pTab ){ + SessionTable **ppTab; + + pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1); + if( !pTab ){ + rc = SQLITE_NOMEM; + break; + } + memset(pTab, 0, sizeof(SessionTable)); + pTab->nCol = nCol; + pTab->abPK = (u8*)&pTab[1]; + memcpy(pTab->abPK, abPK, nCol); + pTab->zName = (char*)&pTab->abPK[nCol]; + memcpy(pTab->zName, zNew, nNew+1); + + /* The new object must be linked on to the end of the list, not + ** simply added to the start of it. This is to ensure that the + ** tables within the output of sqlite3changegroup_output() are in + ** the right order. */ + for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext); + *ppTab = pTab; + }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ + rc = SQLITE_SCHEMA; + break; + } + } + + if( sessionGrowHash(pIter->bPatchset, pTab) ){ + rc = SQLITE_NOMEM; + break; + } + iHash = sessionChangeHash( + pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange + ); + + /* Search for existing entry. If found, remove it from the hash table. + ** Code below may link it back in. + */ + for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){ + int bPkOnly1 = 0; + int bPkOnly2 = 0; + if( pIter->bPatchset ){ + bPkOnly1 = (*pp)->op==SQLITE_DELETE; + bPkOnly2 = op==SQLITE_DELETE; + } + if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){ + pExist = *pp; + *pp = (*pp)->pNext; + pTab->nEntry--; + break; + } + } + + rc = sessionChangeMerge(pTab, + pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange + ); + if( rc ) break; + if( pChange ){ + pChange->pNext = pTab->apChange[iHash]; + pTab->apChange[iHash] = pChange; + pTab->nEntry++; + } + } + + if( rc==SQLITE_OK ) rc = pIter->rc; + return rc; +} + +/* +** Serialize a changeset (or patchset) based on all changesets (or patchsets) +** added to the changegroup object passed as the first argument. +** +** If xOutput is not NULL, then the changeset/patchset is returned to the +** user via one or more calls to xOutput, as with the other streaming +** interfaces. +** +** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a +** buffer containing the output changeset before this function returns. In +** this case (*pnOut) is set to the size of the output buffer in bytes. It +** is the responsibility of the caller to free the output buffer using +** sqlite3_free() when it is no longer required. +** +** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite +** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut) +** are both set to 0 before returning. +*/ +static int sessionChangegroupOutput( + sqlite3_changegroup *pGrp, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut, + int *pnOut, + void **ppOut +){ + int rc = SQLITE_OK; + SessionBuffer buf = {0, 0, 0}; + SessionTable *pTab; + assert( xOutput==0 || (ppOut==0 && pnOut==0) ); + + /* Create the serialized output changeset based on the contents of the + ** hash tables attached to the SessionTable objects in list p->pList. + */ + for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ + int i; + if( pTab->nEntry==0 ) continue; + + sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc); + for(i=0; inChange; i++){ + SessionChange *p; + for(p=pTab->apChange[i]; p; p=p->pNext){ + 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 ){ + if( xOutput ){ + if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); + }else{ + *ppOut = buf.aBuf; + *pnOut = buf.nBuf; + buf.aBuf = 0; + } + } + sqlite3_free(buf.aBuf); + + return rc; +} + +/* +** Allocate a new, empty, sqlite3_changegroup. +*/ +SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){ + int rc = SQLITE_OK; /* Return code */ + sqlite3_changegroup *p; /* New object */ + p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup)); + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(p, 0, sizeof(sqlite3_changegroup)); + } + *pp = p; + return rc; +} + +/* +** Add the changeset currently stored in buffer pData, size nData bytes, +** to changeset-group p. +*/ +SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){ + sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */ + int rc; /* Return code */ + + rc = sqlite3changeset_start(&pIter, nData, pData); + if( rc==SQLITE_OK ){ + rc = sessionChangesetToHash(pIter, pGrp); + } + sqlite3changeset_finalize(pIter); + return rc; +} + +/* +** Obtain a buffer containing a changeset representing the concatenation +** of all changesets added to the group so far. +*/ +SQLITE_API int sqlite3changegroup_output( + sqlite3_changegroup *pGrp, + int *pnData, + void **ppData +){ + return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData); +} + +/* +** Streaming versions of changegroup_add(). +*/ +SQLITE_API int sqlite3changegroup_add_strm( + sqlite3_changegroup *pGrp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +){ + sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */ + int rc; /* Return code */ + + rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); + if( rc==SQLITE_OK ){ + rc = sessionChangesetToHash(pIter, pGrp); + } + sqlite3changeset_finalize(pIter); + return rc; +} + +/* +** Streaming versions of changegroup_output(). +*/ +SQLITE_API int sqlite3changegroup_output_strm( + sqlite3_changegroup *pGrp, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +){ + return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0); +} + +/* +** Delete a changegroup object. +*/ +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ + if( pGrp ){ + sessionDeleteTable(pGrp->pList); + sqlite3_free(pGrp); + } +} + +/* +** Combine two changesets together. +*/ +SQLITE_API int sqlite3changeset_concat( + int nLeft, /* Number of bytes in lhs input */ + void *pLeft, /* Lhs input changeset */ + int nRight /* Number of bytes in rhs input */, + void *pRight, /* Rhs input changeset */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: changeset (left right) */ +){ + sqlite3_changegroup *pGrp; + int rc; + + rc = sqlite3changegroup_new(&pGrp); + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add(pGrp, nLeft, pLeft); + } + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add(pGrp, nRight, pRight); + } + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); + } + sqlite3changegroup_delete(pGrp); + + return rc; +} + +/* +** Streaming version of sqlite3changeset_concat(). +*/ +SQLITE_API int sqlite3changeset_concat_strm( + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +){ + sqlite3_changegroup *pGrp; + int rc; + + rc = sqlite3changegroup_new(&pGrp); + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA); + } + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB); + } + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut); + } + sqlite3changegroup_delete(pGrp); + + return rc; +} + +#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ + +/************** End of sqlite3session.c **************************************/ /************** Begin file json1.c *******************************************/ /* ** 2015-08-12 @@ -164974,7 +181428,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; } ** how JSONB might improve on that.) */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) -#if !defined(_SQLITEINT_H_) +#if !defined(SQLITEINT_H) /* #include "sqlite3ext.h" */ #endif SQLITE_EXTENSION_INIT1 @@ -164983,7 +181437,11 @@ SQLITE_EXTENSION_INIT1 /* #include */ /* #include */ -#define UNUSED_PARAM(X) (void)(X) +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAM +# define UNUSED_PARAM(X) (void)(X) +#endif #ifndef LARGEST_INT64 # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) @@ -164997,13 +181455,15 @@ SQLITE_EXTENSION_INIT1 #ifdef sqlite3Isdigit /* Use the SQLite core versions if this routine is part of the ** SQLite amalgamation */ -# define safe_isdigit(x) sqlite3Isdigit(x) -# define safe_isalnum(x) sqlite3Isalnum(x) +# define safe_isdigit(x) sqlite3Isdigit(x) +# define safe_isalnum(x) sqlite3Isalnum(x) +# define safe_isxdigit(x) sqlite3Isxdigit(x) #else /* Use the standard library for separate compilation */ #include /* amalgamator: keep */ -# define safe_isdigit(x) isdigit((unsigned char)(x)) -# define safe_isalnum(x) isalnum((unsigned char)(x)) +# define safe_isdigit(x) isdigit((unsigned char)(x)) +# define safe_isalnum(x) isalnum((unsigned char)(x)) +# define safe_isxdigit(x) isxdigit((unsigned char)(x)) #endif /* @@ -165036,6 +181496,7 @@ static const char jsonIsSpace[] = { ** but the definitions need to be repeated for separate compilation. */ typedef sqlite3_uint64 u64; typedef unsigned int u32; + typedef unsigned short int u16; typedef unsigned char u8; #endif @@ -165084,9 +181545,10 @@ static const char * const jsonType[] = { #define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ #define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ #define JNODE_REMOVE 0x04 /* Do not output */ -#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */ -#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ -#define JNODE_LABEL 0x20 /* Is a label of an object */ +#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */ +#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */ +#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */ +#define JNODE_LABEL 0x40 /* Is a label of an object */ /* A single node of parsed JSON @@ -165094,12 +181556,13 @@ static const char * const jsonType[] = { struct JsonNode { u8 eType; /* One of the JSON_ type values */ u8 jnFlags; /* JNODE flags */ - u8 iVal; /* Replacement value when JNODE_REPLACE */ u32 n; /* Bytes of content, or number of sub-nodes */ union { const char *zJContent; /* Content for INT, REAL, and STRING */ u32 iAppend; /* More terms for ARRAY and OBJECT */ u32 iKey; /* Key for ARRAY objects in json_tree() */ + u32 iReplace; /* Replacement content for JNODE_REPLACE */ + JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */ } u; }; @@ -165113,8 +181576,19 @@ struct JsonParse { u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ + u16 iDepth; /* Nesting depth */ + int nJson; /* Length of the zJson string in bytes */ }; +/* +** Maximum nesting depth of JSON for this implementation. +** +** This limit is needed to avoid a stack overflow in the recursive +** descent parser. A depth of 2000 is far deeper than any sane JSON +** should go. +*/ +#define JSON_MAX_DEPTH 2000 + /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ @@ -165228,10 +181702,33 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; p->zBuf[p->nUsed++] = '"'; for(i=0; inUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; + }else if( c<=0x1f ){ + static const char aSpecial[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assert( sizeof(aSpecial)==32 ); + assert( aSpecial['\b']=='b' ); + assert( aSpecial['\f']=='f' ); + assert( aSpecial['\n']=='n' ); + assert( aSpecial['\r']=='r' ); + assert( aSpecial['\t']=='t' ); + if( aSpecial[c] ){ + c = aSpecial[c]; + goto json_simple_escape; + } + if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + p->zBuf[p->nUsed++] = 'u'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0' + (c>>4); + c = "0123456789abcdef"[c&0xf]; } p->zBuf[p->nUsed++] = c; } @@ -165272,7 +181769,7 @@ static void jsonAppendValue( default: { if( p->bErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); - p->bErr = 1; + p->bErr = 2; jsonReset(p); } break; @@ -165323,6 +181820,14 @@ static void jsonParseReset(JsonParse *pParse){ pParse->aUp = 0; } +/* +** Free a JsonParse object that was obtained from sqlite3_malloc(). +*/ +static void jsonParseFree(JsonParse *pParse){ + jsonParseReset(pParse); + sqlite3_free(pParse); +} + /* ** Convert the JsonNode pNode into a pure JSON string and ** append to pOut. Subsubstructure is also included. Return @@ -165333,6 +181838,13 @@ static void jsonRenderNode( JsonString *pOut, /* Write JSON here */ sqlite3_value **aReplace /* Replacement values */ ){ + if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ + if( pNode->jnFlags & JNODE_REPLACE ){ + jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); + return; + } + pNode = pNode->u.pPatch; + } switch( pNode->eType ){ default: { assert( pNode->eType==JSON_NULL ); @@ -165364,12 +181876,7 @@ static void jsonRenderNode( jsonAppendChar(pOut, '['); for(;;){ while( j<=pNode->n ){ - if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){ - if( pNode[j].jnFlags & JNODE_REPLACE ){ - jsonAppendSeparator(pOut); - jsonAppendValue(pOut, aReplace[pNode[j].iVal]); - } - }else{ + if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){ jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); } @@ -165391,11 +181898,7 @@ static void jsonRenderNode( jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); jsonAppendChar(pOut, ':'); - if( pNode[j+1].jnFlags & JNODE_REPLACE ){ - jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]); - }else{ - jsonRenderNode(&pNode[j+1], pOut, aReplace); - } + jsonRenderNode(&pNode[j+1], pOut, aReplace); } j += 1 + jsonNodeSize(&pNode[j+1]); } @@ -165518,12 +182021,13 @@ static void jsonReturn( c = z[++i]; if( c=='u' ){ u32 v = 0, k; - for(k=0; k<4 && i='0' && c<='9' ) v = v*16 + c - '0'; - else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10; - else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10; - else break; + assert( safe_isxdigit(c) ); + if( c<='9' ) v = v*16 + c - '0'; + else if( c<='F' ) v = v*16 + c - 'A' + 10; + else v = v*16 + c - 'a' + 10; } if( v==0 ) break; if( v<=0x7f ){ @@ -165621,12 +182125,20 @@ static int jsonParseAddNode( p = &pParse->aNode[pParse->nNode]; p->eType = (u8)eType; p->jnFlags = 0; - p->iVal = 0; p->n = n; p->u.zJContent = zContent; return pParse->nNode++; } +/* +** Return true if z[] begins with 4 (or more) hexadecimal digits +*/ +static int jsonIs4Hex(const char *z){ + int i; + for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0; + return 1; +} + /* ** Parse a single JSON value which begins at pParse->zJson[i]. Return the ** index of the first character past the end of the value parsed. @@ -165641,15 +182153,18 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ int iThis; int x; JsonNode *pNode; - while( safe_isspace(pParse->zJson[i]) ){ i++; } - if( (c = pParse->zJson[i])=='{' ){ + const char *z = pParse->zJson; + while( safe_isspace(z[i]) ){ i++; } + if( (c = z[i])=='{' ){ /* Parse object */ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; x = jsonParseValue(pParse, j); if( x<0 ){ + pParse->iDepth--; if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } @@ -165658,14 +182173,15 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( pNode->eType!=JSON_STRING ) return -1; pNode->jnFlags |= JNODE_LABEL; j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - if( pParse->zJson[j]!=':' ) return -1; + while( safe_isspace(z[j]) ){ j++; } + if( z[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); + pParse->iDepth--; if( x<0 ) return -1; j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; if( c==',' ) continue; if( c!='}' ) return -1; break; @@ -165677,15 +182193,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; x = jsonParseValue(pParse, j); + pParse->iDepth--; if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; if( c==',' ) continue; if( c!=']' ) return -1; break; @@ -165697,66 +182215,79 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ u8 jnFlags = 0; j = i+1; for(;;){ - c = pParse->zJson[j]; - if( c==0 ) return -1; + c = z[j]; + if( (c & ~0x1f)==0 ){ + /* Control characters are not allowed in strings */ + return -1; + } if( c=='\\' ){ - c = pParse->zJson[++j]; - if( c==0 ) return -1; - jnFlags = JNODE_ESCAPE; + c = z[++j]; + if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' + || c=='n' || c=='r' || c=='t' + || (c=='u' && jsonIs4Hex(z+j+1)) ){ + jnFlags = JNODE_ESCAPE; + }else{ + return -1; + } }else if( c=='"' ){ break; } j++; } - jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; return j+1; }else if( c=='n' - && strncmp(pParse->zJson+i,"null",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ + && strncmp(z+i,"null",4)==0 + && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; }else if( c=='t' - && strncmp(pParse->zJson+i,"true",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ + && strncmp(z+i,"true",4)==0 + && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; }else if( c=='f' - && strncmp(pParse->zJson+i,"false",5)==0 - && !safe_isalnum(pParse->zJson[i+5]) ){ + && strncmp(z+i,"false",5)==0 + && !safe_isalnum(z[i+5]) ){ jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; }else if( c=='-' || (c>='0' && c<='9') ){ /* Parse number */ u8 seenDP = 0; u8 seenE = 0; + assert( '-' < '0' ); + if( c<='0' ){ + j = c=='-' ? i+1 : i; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; + } j = i+1; for(;; j++){ - c = pParse->zJson[j]; + c = z[j]; if( c>='0' && c<='9' ) continue; if( c=='.' ){ - if( pParse->zJson[j-1]=='-' ) return -1; + if( z[j-1]=='-' ) return -1; if( seenDP ) return -1; seenDP = 1; continue; } if( c=='e' || c=='E' ){ - if( pParse->zJson[j-1]<'0' ) return -1; + if( z[j-1]<'0' ) return -1; if( seenE ) return -1; seenDP = seenE = 1; - c = pParse->zJson[j+1]; + c = z[j+1]; if( c=='+' || c=='-' ){ j++; - c = pParse->zJson[j+1]; + c = z[j+1]; } if( c<'0' || c>'9' ) return -1; continue; } break; } - if( pParse->zJson[j-1]<'0' ) return -1; + if( z[j-1]<'0' ) return -1; jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, - j - i, &pParse->zJson[i]); + j - i, &z[i]); return j; }else if( c=='}' ){ return -2; /* End of {...} */ @@ -165788,6 +182319,7 @@ static int jsonParse( i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ + assert( pParse->iDepth==0 ); while( safe_isspace(zJson[i]) ) i++; if( zJson[i] ) i = -1; } @@ -165847,6 +182379,49 @@ static int jsonParseFindParents(JsonParse *pParse){ return SQLITE_OK; } +/* +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() +*/ +#define JSON_CACHE_ID (-429938) + +/* +** Obtain a complete parse of the JSON found in the first argument +** of the argv array. Use the sqlite3_get_auxdata() cache for this +** parse if it is available. If the cache is not available or if it +** is no longer valid, parse the JSON again and return the new parse, +** and also register the new parse so that it will be available for +** future sqlite3_get_auxdata() calls. +*/ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, + sqlite3_value **argv +){ + const char *zJson = (const char*)sqlite3_value_text(argv[0]); + int nJson = sqlite3_value_bytes(argv[0]); + JsonParse *p; + if( zJson==0 ) return 0; + p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); + if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ + p->nErr = 0; + return p; /* The cached entry matches, so return it */ + } + p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, sizeof(*p)); + p->zJson = (char*)&p[1]; + memcpy((char*)p->zJson, zJson, nJson+1); + if( jsonParse(p, pCtx, p->zJson) ){ + sqlite3_free(p); + return 0; + } + p->nJson = nJson; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); +} + /* ** Compare the OBJECT label at pNode against zKey,nKey. Return true on ** a match. @@ -166073,6 +182648,25 @@ static void jsonWrongNumArgs( sqlite3_free(zMsg); } +/* +** Mark all NULL entries in the Object passed in as JNODE_REMOVE. +*/ +static void jsonRemoveAllNulls(JsonNode *pNode){ + int i, n; + assert( pNode->eType==JSON_OBJECT ); + n = pNode->n; + for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ + switch( pNode[i].eType ){ + case JSON_NULL: + pNode[i].jnFlags |= JNODE_REMOVE; + break; + case JSON_OBJECT: + jsonRemoveAllNulls(&pNode[i]); + break; + } + } +} + /**************************************************************************** ** SQL functions used for testing and debugging @@ -166136,6 +182730,26 @@ static void jsonTest1Func( ** Scalar SQL function implementations ****************************************************************************/ +/* +** Implementation of the json_QUOTE(VALUE) function. Return a JSON value +** corresponding to the SQL value input. Mostly this means putting +** double-quotes around strings and returning the unquoted string "null" +** when given a NULL input. +*/ +static void jsonQuoteFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString jx; + UNUSED_PARAM(argc); + + jsonInit(&jx, ctx); + jsonAppendValue(&jx, argv[0]); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} + /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument @@ -166173,29 +182787,30 @@ static void jsonArrayLengthFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ sqlite3_int64 n = 0; u32 i; JsonNode *pNode; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); + p = jsonParseCached(ctx, argv); + if( p==0 ) return; + assert( p->nNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - pNode = x.aNode; + pNode = p->aNode; } if( pNode==0 ){ - x.nErr = 1; - }else if( pNode->eType==JSON_ARRAY ){ + return; + } + if( pNode->eType==JSON_ARRAY ){ assert( (pNode->jnFlags & JNODE_APPEND)==0 ); for(i=1; i<=pNode->n; n++){ i += jsonNodeSize(&pNode[i]); } } - if( x.nErr==0 ) sqlite3_result_int64(ctx, n); - jsonParseReset(&x); + sqlite3_result_int64(ctx, n); } /* @@ -166211,20 +182826,21 @@ static void jsonExtractFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; JsonString jx; int i; if( argc<2 ) return; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + p = jsonParseCached(ctx, argv); + if( p==0 ) return; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=1; inErr ) break; if( argc>2 ){ jsonAppendSeparator(&jx); if( pNode ){ @@ -166242,9 +182858,107 @@ static void jsonExtractFunc( sqlite3_result_subtype(ctx, JSON_SUBTYPE); } jsonReset(&jx); - jsonParseReset(&x); } +/* This is the RFC 7396 MergePatch algorithm. +*/ +static JsonNode *jsonMergePatch( + JsonParse *pParse, /* The JSON parser that contains the TARGET */ + u32 iTarget, /* Node of the TARGET in pParse */ + JsonNode *pPatch /* The PATCH */ +){ + u32 i, j; + u32 iRoot; + JsonNode *pTarget; + if( pPatch->eType!=JSON_OBJECT ){ + return pPatch; + } + assert( iTarget>=0 && iTargetnNode ); + pTarget = &pParse->aNode[iTarget]; + assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); + if( pTarget->eType!=JSON_OBJECT ){ + jsonRemoveAllNulls(pPatch); + return pPatch; + } + iRoot = iTarget; + for(i=1; in; i += jsonNodeSize(&pPatch[i+1])+1){ + u32 nKey; + const char *zKey; + assert( pPatch[i].eType==JSON_STRING ); + assert( pPatch[i].jnFlags & JNODE_LABEL ); + nKey = pPatch[i].n; + zKey = pPatch[i].u.zJContent; + assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); + for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){ + assert( pTarget[j].eType==JSON_STRING ); + assert( pTarget[j].jnFlags & JNODE_LABEL ); + assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); + if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){ + if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break; + if( pPatch[i+1].eType==JSON_NULL ){ + pTarget[j+1].jnFlags |= JNODE_REMOVE; + }else{ + JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); + if( pNew==0 ) return 0; + pTarget = &pParse->aNode[iTarget]; + if( pNew!=&pTarget[j+1] ){ + pTarget[j+1].u.pPatch = pNew; + pTarget[j+1].jnFlags |= JNODE_PATCH; + } + } + break; + } + } + if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ + int iStart, iPatch; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); + iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + if( pParse->oom ) return 0; + jsonRemoveAllNulls(pPatch); + pTarget = &pParse->aNode[iTarget]; + pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; + pParse->aNode[iRoot].u.iAppend = iStart - iRoot; + iRoot = iStart; + pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; + pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; + } + } + return pTarget; +} + +/* +** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON +** object that is the result of running the RFC 7396 MergePatch() algorithm +** on the two arguments. +*/ +static void jsonPatchFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The JSON that is being patched */ + JsonParse y; /* The patch */ + JsonNode *pResult; /* The result of the merge */ + + UNUSED_PARAM(argc); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){ + jsonParseReset(&x); + return; + } + pResult = jsonMergePatch(&x, 0, y.aNode); + assert( pResult!=0 || x.oom ); + if( pResult ){ + jsonReturnJson(pResult, ctx, 0); + }else{ + sqlite3_result_error_nomem(ctx); + } + jsonParseReset(&x); + jsonParseReset(&y); +} + + /* ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON ** object that contains all name/value given in arguments. Or if any name @@ -166348,11 +183062,11 @@ static void jsonReplaceFunc( if( x.nErr ) goto replace_err; if( pNode ){ pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->iVal = (u8)(i+1); + pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); } @@ -166402,11 +183116,11 @@ static void jsonSetFunc( goto jsonSetDone; }else if( pNode && (bApnd || bIsSet) ){ pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->iVal = (u8)(i+1); + pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); } @@ -166481,6 +183195,7 @@ static void jsonArrayStep( sqlite3_value **argv ){ JsonString *pStr; + UNUSED_PARAM(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ @@ -166500,7 +183215,7 @@ static void jsonArrayFinal(sqlite3_context *ctx){ pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); if( pStr->bErr ){ - sqlite3_result_error_nomem(ctx); + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else{ sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, @@ -166526,6 +183241,7 @@ static void jsonObjectStep( JsonString *pStr; const char *z; u32 n; + UNUSED_PARAM(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ @@ -166548,7 +183264,7 @@ static void jsonObjectFinal(sqlite3_context *ctx){ if( pStr ){ jsonAppendChar(pStr, '}'); if( pStr->bErr ){ - sqlite3_result_error_nomem(ctx); + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else{ sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, @@ -166826,9 +183542,9 @@ static int jsonEachColumn( /* For json_each() path and root are the same so fall through ** into the root case */ } - case JEACH_ROOT: { + default: { const char *zRoot = p->zRoot; - if( zRoot==0 ) zRoot = "$"; + if( zRoot==0 ) zRoot = "$"; sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); break; } @@ -167047,6 +183763,8 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){ { "json_extract", -1, 0, jsonExtractFunc }, { "json_insert", -1, 0, jsonSetFunc }, { "json_object", -1, 0, jsonObjectFunc }, + { "json_patch", 2, 0, jsonPatchFunc }, + { "json_quote", 1, 0, jsonQuoteFunc }, { "json_remove", -1, 0, jsonRemoveFunc }, { "json_replace", -1, 0, jsonReplaceFunc }, { "json_set", -1, 1, jsonSetFunc }, @@ -167102,7 +183820,7 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){ #ifdef _WIN32 __declspec(dllexport) #endif -SQLITE_API int SQLITE_STDCALL sqlite3_json_init( +SQLITE_API int sqlite3_json_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -167213,6 +183931,9 @@ struct Fts5PhraseIter { ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** ** xColumnText: ** This function attempts to retrieve the text of column iCol of the ** current document. If successful, (*pz) is set to point to a buffer @@ -167233,15 +183954,29 @@ struct Fts5PhraseIter { ** the query within the current row. Return 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. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). ** +** 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. ** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** ** xRowid: ** Returns the rowid of the current row. ** @@ -167255,11 +183990,13 @@ struct Fts5PhraseIter { ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid ** ** with $p set to a phrase equivalent to the phrase iPhrase of the -** current query is executed. For each row visited, the callback function -** passed as the fourth argument is invoked. The context and API objects -** passed to the callback function may be used to access the properties of -** each matched row. Invoking Api.xUserData() returns a copy of the pointer -** passed as the third argument to pUserData. +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. @@ -167325,7 +184062,7 @@ struct Fts5PhraseIter { ** Fts5PhraseIter iter; ** int iCol, iOff; ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); -** iOff>=0; +** iCol>=0; ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) ** ){ ** // An instance of phrase iPhrase at offset iOff of column iCol @@ -167333,13 +184070,51 @@ struct Fts5PhraseIter { ** ** The Fts5PhraseIter structure is defined above. Applications should not ** modify this structure directly - it should only be used as shown above -** with the xPhraseFirst() and xPhraseNext() API methods. +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** ** xPhraseNext() ** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 1 */ + int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); @@ -167369,8 +184144,11 @@ struct Fts5ExtensionApi { int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); void *(*xGetAuxdata)(Fts5Context*, int bClear); - void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; /* @@ -167387,7 +184165,7 @@ struct Fts5ExtensionApi { ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: -** This function is used to allocate and inititalize a tokenizer instance. +** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) @@ -167647,7 +184425,6 @@ struct fts5_api { #endif /* _FTS5_H */ - /* ** 2014 May 31 ** @@ -167676,10 +184453,13 @@ SQLITE_EXTENSION_INIT1 typedef unsigned char u8; typedef unsigned int u32; typedef unsigned short u16; +typedef short i16; typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; -#define ArraySize(x) (sizeof(x) / sizeof(x[0])) +#ifndef ArraySize +# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) +#endif #define testcase(x) #define ALWAYS(x) 1 @@ -167696,6 +184476,10 @@ typedef sqlite3_uint64 u64; #endif +/* Truncate very long tokens to this many bytes. Hard limit is +** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset +** field that occurs at the start of each leaf page (see fts5_index.c). */ +#define FTS5_MAX_TOKEN_SIZE 32768 /* ** Maximum number of prefix indexes on single FTS5 table. This must be @@ -167730,6 +184514,16 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(x) #endif +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAM +# define UNUSED_PARAM(X) (void)(X) +#endif + +#ifndef UNUSED_PARAM2 +# define UNUSED_PARAM2(X, Y) (void)(X), (void)(Y) +#endif + typedef struct Fts5Global Fts5Global; typedef struct Fts5Colset Fts5Colset; @@ -167801,6 +184595,7 @@ struct Fts5Config { char *zContent; /* content table */ char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ + int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5Tokenizer *pTok; fts5_tokenizer *pTokApi; @@ -167810,6 +184605,7 @@ struct Fts5Config { int pgsz; /* Approximate page size used in %_data */ int nAutomerge; /* 'automerge' setting */ int nCrisisMerge; /* Maximum allowed segments per level */ + int nUsermerge; /* 'usermerge' setting */ int nHashSize; /* Bytes of memory for in-memory hash */ char *zRank; /* Name of rank function */ char *zRankArgs; /* Arguments to rank function */ @@ -167829,6 +184625,9 @@ struct Fts5Config { #define FTS5_CONTENT_NONE 1 #define FTS5_CONTENT_EXTERNAL 2 +#define FTS5_DETAIL_FULL 0 +#define FTS5_DETAIL_NONE 1 +#define FTS5_DETAIL_COLUMNS 2 @@ -167875,9 +184674,9 @@ struct Fts5Buffer { int nSpace; }; -static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, int); +static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32); static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64); -static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*); +static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*); static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*); static void sqlite3Fts5BufferFree(Fts5Buffer*); static void sqlite3Fts5BufferZero(Fts5Buffer*); @@ -167893,7 +184692,7 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); #define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d) #define fts5BufferGrow(pRc,pBuf,nn) ( \ - (pBuf)->n + (nn) <= (pBuf)->nSpace ? 0 : \ + (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \ sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \ ) @@ -167928,6 +184727,7 @@ struct Fts5PoslistWriter { i64 iPrev; }; static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64); +static void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64); static int sqlite3Fts5PoslistNext64( const u8 *a, int n, /* Buffer containing poslist */ @@ -167942,6 +184742,13 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); /* Character set tests (like isspace(), isalpha() etc.) */ static int sqlite3Fts5IsBareword(char t); + +/* Bucket of terms object used by the integrity-check in offsets=0 mode. */ +typedef struct Fts5Termset Fts5Termset; +static int sqlite3Fts5TermsetNew(Fts5Termset**); +static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent); +static void sqlite3Fts5TermsetFree(Fts5Termset*); + /* ** End of interface to code in fts5_buffer.c. **************************************************************************/ @@ -167954,6 +184761,15 @@ static int sqlite3Fts5IsBareword(char t); typedef struct Fts5Index Fts5Index; typedef struct Fts5IndexIter Fts5IndexIter; +struct Fts5IndexIter { + i64 iRowid; + const u8 *pData; + int nData; + u8 bEof; +}; + +#define sqlite3Fts5IterEof(x) ((x)->bEof) + /* ** Values used as part of the flags argument passed to IndexQuery(). */ @@ -167962,6 +184778,12 @@ typedef struct Fts5IndexIter Fts5IndexIter; #define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ #define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ +/* The following are used internally by the fts5_index.c module. They are +** defined here only to make it easier to avoid clashes with the flags +** above. */ +#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 +#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 + /* ** Create/destroy an Fts5Index object. */ @@ -167969,14 +184791,27 @@ static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, c static int sqlite3Fts5IndexClose(Fts5Index *p); /* -** for( -** sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter); -** 0==sqlite3Fts5IterEof(pIter); -** sqlite3Fts5IterNext(pIter) -** ){ -** i64 iRowid = sqlite3Fts5IterRowid(pIter); -** } +** Return a simple checksum value based on the arguments. */ +static u64 sqlite3Fts5IndexEntryCksum( + i64 iRowid, + int iCol, + int iPos, + int iIdx, + const char *pTerm, + int nTerm +); + +/* +** Argument p points to a buffer containing utf-8 text that is n bytes in +** size. Return the number of bytes in the nChar character prefix of the +** buffer, or 0 if there are less than nChar characters in total. +*/ +static int sqlite3Fts5IndexCharlenToBytelen( + const char *p, + int nByte, + int nChar +); /* ** Open a new iterator to iterate though all rowids that match the @@ -167994,12 +184829,8 @@ static int sqlite3Fts5IndexQuery( ** The various operations on open token or token prefix iterators opened ** using sqlite3Fts5IndexQuery(). */ -static int sqlite3Fts5IterEof(Fts5IndexIter*); static int sqlite3Fts5IterNext(Fts5IndexIter*); static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); -static i64 sqlite3Fts5IterRowid(Fts5IndexIter*); -static int sqlite3Fts5IterPoslist(Fts5IndexIter*,Fts5Colset*, const u8**, int*, i64*); -static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf); /* ** Close an iterator opened by sqlite3Fts5IndexQuery(). @@ -168042,9 +184873,9 @@ static int sqlite3Fts5IndexBeginWrite( /* ** Flush any data stored in the in-memory hash tables to the database. -** If the bCommit flag is true, also close any open blob handles. +** Also close any open blob handles. */ -static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit); +static int sqlite3Fts5IndexSync(Fts5Index *p); /* ** Discard any data stored in the in-memory hash tables. Do not write it @@ -168063,7 +184894,6 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); /* ** Functions called by the storage module as part of integrity-check. */ -static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int); static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); /* @@ -168083,6 +184913,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p); static int sqlite3Fts5IndexReinit(Fts5Index *p); static int sqlite3Fts5IndexOptimize(Fts5Index *p); static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge); +static int sqlite3Fts5IndexReset(Fts5Index *p); static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); @@ -168142,7 +184973,7 @@ typedef struct Fts5Hash Fts5Hash; /* ** Create a hash table, free a hash table. */ -static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize); +static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize); static void sqlite3Fts5HashFree(Fts5Hash*); static int sqlite3Fts5HashWrite( @@ -168201,7 +185032,7 @@ static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); static int sqlite3Fts5DropAll(Fts5Config*); static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64); +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); @@ -168214,19 +185045,18 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg); static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow); -static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit); +static int sqlite3Fts5StorageSync(Fts5Storage *p); static int sqlite3Fts5StorageRollback(Fts5Storage *p); static int sqlite3Fts5StorageConfigValue( Fts5Storage *p, const char*, sqlite3_value*, int ); -static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**); - static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p); static int sqlite3Fts5StorageRebuild(Fts5Storage *p); static int sqlite3Fts5StorageOptimize(Fts5Storage *p); static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); +static int sqlite3Fts5StorageReset(Fts5Storage *p); /* ** End of interface to code in fts5_storage.c. @@ -168251,6 +185081,7 @@ struct Fts5Token { /* Parse a MATCH expression. */ static int sqlite3Fts5ExprNew( Fts5Config *pConfig, + int iCol, /* Column on LHS of MATCH operator */ const char *zExpr, Fts5Expr **ppNew, char **pzErr @@ -168279,7 +185110,16 @@ static int sqlite3Fts5ExprPhraseCount(Fts5Expr*); static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase); static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **); -static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**); +typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; +static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); +static int sqlite3Fts5ExprPopulatePoslists( + Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int +); +static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); + +static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); + +static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); /******************************************* ** The fts5_expr.c API above this point is used by the other hand-written @@ -168296,6 +185136,12 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( Fts5ExprNearset *pNear ); +static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( + Fts5Parse *pParse, + Fts5ExprNode *pLeft, + Fts5ExprNode *pRight +); + static Fts5ExprPhrase *sqlite3Fts5ParseTerm( Fts5Parse *pParse, Fts5ExprPhrase *pPhrase, @@ -168320,7 +185166,8 @@ static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); -static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); +static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*); +static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*); static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); @@ -168376,14 +185223,15 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); #define FTS5_NOT 3 #define FTS5_TERM 4 #define FTS5_COLON 5 -#define FTS5_LP 6 -#define FTS5_RP 7 -#define FTS5_LCP 8 -#define FTS5_RCP 9 -#define FTS5_STRING 10 -#define FTS5_COMMA 11 -#define FTS5_PLUS 12 -#define FTS5_STAR 13 +#define FTS5_MINUS 6 +#define FTS5_LCP 7 +#define FTS5_RCP 8 +#define FTS5_STRING 9 +#define FTS5_LP 10 +#define FTS5_RP 11 +#define FTS5_COMMA 12 +#define FTS5_PLUS 13 +#define FTS5_STAR 14 /* ** 2000-05-29 @@ -168487,7 +185335,8 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** fts5YY_MAX_SHIFT Maximum value for shift actions ** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** fts5YY_MIN_REDUCE Maximum value for reduce actions +** fts5YY_MIN_REDUCE Minimum value for reduce actions +** fts5YY_MAX_REDUCE Maximum value for reduce actions ** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error ** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept ** fts5YY_NO_ACTION The fts5yy_action[] code for no-op @@ -168497,17 +185346,17 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); #endif /************* Begin control #defines *****************************************/ #define fts5YYCODETYPE unsigned char -#define fts5YYNOCODE 27 +#define fts5YYNOCODE 28 #define fts5YYACTIONTYPE unsigned char #define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token typedef union { int fts5yyinit; sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0; - Fts5Colset* fts5yy3; - Fts5ExprPhrase* fts5yy11; - Fts5ExprNode* fts5yy18; - int fts5yy20; - Fts5ExprNearset* fts5yy26; + int fts5yy4; + Fts5Colset* fts5yy11; + Fts5ExprNode* fts5yy24; + Fts5ExprNearset* fts5yy46; + Fts5ExprPhrase* fts5yy53; } fts5YYMINORTYPE; #ifndef fts5YYSTACKDEPTH #define fts5YYSTACKDEPTH 100 @@ -168516,22 +185365,18 @@ typedef union { #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse -#define fts5YYNSTATE 26 -#define fts5YYNRULE 24 -#define fts5YY_MAX_SHIFT 25 -#define fts5YY_MIN_SHIFTREDUCE 40 -#define fts5YY_MAX_SHIFTREDUCE 63 -#define fts5YY_MIN_REDUCE 64 -#define fts5YY_MAX_REDUCE 87 -#define fts5YY_ERROR_ACTION 88 -#define fts5YY_ACCEPT_ACTION 89 -#define fts5YY_NO_ACTION 90 +#define fts5YYNSTATE 33 +#define fts5YYNRULE 27 +#define fts5YY_MAX_SHIFT 32 +#define fts5YY_MIN_SHIFTREDUCE 50 +#define fts5YY_MAX_SHIFTREDUCE 76 +#define fts5YY_MIN_REDUCE 77 +#define fts5YY_MAX_REDUCE 103 +#define fts5YY_ERROR_ACTION 104 +#define fts5YY_ACCEPT_ACTION 105 +#define fts5YY_NO_ACTION 106 /************* End control #defines *******************************************/ -/* The fts5yyzerominor constant is used to initialize instances of -** fts5YYMINORTYPE objects to zero. */ -static const fts5YYMINORTYPE fts5yyzerominor = { 0 }; - /* Define the fts5yytestcase() macro to be a no-op if is not already defined ** otherwise. ** @@ -168561,7 +185406,7 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 }; ** ** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE ** and fts5YY_MAX_REDUCE - +** ** N == fts5YY_ERROR_ACTION A syntax error has occurred. ** ** N == fts5YY_ACCEPT_ACTION The parser accepts its input. @@ -168570,16 +185415,20 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 }; ** slots in the fts5yy_action[] table. ** ** The action table is constructed as a single large table named fts5yy_action[]. -** Given state S and lookahead X, the action is computed as +** Given state S and lookahead X, the action is computed as either: ** -** fts5yy_action[ fts5yy_shift_ofst[S] + X ] +** (A) N = fts5yy_action[ fts5yy_shift_ofst[S] + X ] +** (B) N = fts5yy_default[S] ** -** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value -** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S] -** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that fts5yy_default[S] should be used instead. +** The (A) formula is preferred. The B formula is used instead if: +** (1) The fts5yy_shift_ofst[S]+X value is out of range, or +** (2) fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X, or +** (3) fts5yy_shift_ofst[S] equal fts5YY_SHIFT_USE_DFLT. +** (Implementation note: fts5YY_SHIFT_USE_DFLT is chosen so that +** fts5YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) ** -** The formula above is for computing the action when the lookahead is +** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of ** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of @@ -168597,48 +185446,54 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 }; ** fts5yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define fts5YY_ACTTAB_COUNT (78) +#define fts5YY_ACTTAB_COUNT (98) static const fts5YYACTIONTYPE fts5yy_action[] = { - /* 0 */ 89, 15, 46, 5, 48, 24, 12, 19, 23, 14, - /* 10 */ 46, 5, 48, 24, 20, 21, 23, 43, 46, 5, - /* 20 */ 48, 24, 6, 18, 23, 17, 46, 5, 48, 24, - /* 30 */ 75, 7, 23, 25, 46, 5, 48, 24, 62, 47, - /* 40 */ 23, 48, 24, 7, 11, 23, 9, 3, 4, 2, - /* 50 */ 62, 50, 52, 44, 64, 3, 4, 2, 49, 4, - /* 60 */ 2, 1, 23, 11, 16, 9, 12, 2, 10, 61, - /* 70 */ 53, 59, 62, 60, 22, 13, 55, 8, + /* 0 */ 105, 19, 90, 6, 26, 93, 92, 24, 24, 17, + /* 10 */ 90, 6, 26, 16, 92, 54, 24, 18, 90, 6, + /* 20 */ 26, 10, 92, 12, 24, 75, 86, 90, 6, 26, + /* 30 */ 13, 92, 75, 24, 20, 90, 6, 26, 101, 92, + /* 40 */ 56, 24, 27, 90, 6, 26, 100, 92, 21, 24, + /* 50 */ 23, 15, 30, 11, 1, 91, 22, 25, 9, 92, + /* 60 */ 7, 24, 3, 4, 5, 3, 4, 5, 3, 77, + /* 70 */ 4, 5, 3, 61, 23, 15, 60, 11, 80, 12, + /* 80 */ 2, 13, 68, 10, 29, 52, 55, 75, 31, 32, + /* 90 */ 8, 28, 5, 3, 51, 55, 72, 14, }; static const fts5YYCODETYPE fts5yy_lookahead[] = { - /* 0 */ 15, 16, 17, 18, 19, 20, 10, 11, 23, 16, - /* 10 */ 17, 18, 19, 20, 23, 24, 23, 16, 17, 18, - /* 20 */ 19, 20, 22, 23, 23, 16, 17, 18, 19, 20, - /* 30 */ 5, 6, 23, 16, 17, 18, 19, 20, 13, 17, - /* 40 */ 23, 19, 20, 6, 8, 23, 10, 1, 2, 3, - /* 50 */ 13, 9, 10, 7, 0, 1, 2, 3, 19, 2, - /* 60 */ 3, 6, 23, 8, 21, 10, 10, 3, 10, 25, - /* 70 */ 10, 10, 13, 25, 12, 10, 7, 5, + /* 0 */ 16, 17, 18, 19, 20, 22, 22, 24, 24, 17, + /* 10 */ 18, 19, 20, 7, 22, 9, 24, 17, 18, 19, + /* 20 */ 20, 10, 22, 9, 24, 14, 17, 18, 19, 20, + /* 30 */ 9, 22, 14, 24, 17, 18, 19, 20, 26, 22, + /* 40 */ 9, 24, 17, 18, 19, 20, 26, 22, 21, 24, + /* 50 */ 6, 7, 13, 9, 10, 18, 21, 20, 5, 22, + /* 60 */ 5, 24, 3, 1, 2, 3, 1, 2, 3, 0, + /* 70 */ 1, 2, 3, 11, 6, 7, 11, 9, 5, 9, + /* 80 */ 10, 9, 11, 10, 12, 8, 9, 14, 24, 25, + /* 90 */ 23, 24, 2, 3, 8, 9, 9, 9, }; -#define fts5YY_SHIFT_USE_DFLT (-5) -#define fts5YY_SHIFT_COUNT (25) -#define fts5YY_SHIFT_MIN (-4) -#define fts5YY_SHIFT_MAX (72) -static const signed char fts5yy_shift_ofst[] = { - /* 0 */ 55, 55, 55, 55, 55, 36, -4, 56, 58, 25, - /* 10 */ 37, 60, 59, 59, 46, 54, 42, 57, 62, 61, - /* 20 */ 62, 69, 65, 62, 72, 64, +#define fts5YY_SHIFT_USE_DFLT (98) +#define fts5YY_SHIFT_COUNT (32) +#define fts5YY_SHIFT_MIN (0) +#define fts5YY_SHIFT_MAX (90) +static const unsigned char fts5yy_shift_ofst[] = { + /* 0 */ 44, 44, 44, 44, 44, 44, 68, 70, 72, 14, + /* 10 */ 21, 73, 11, 18, 18, 31, 31, 62, 65, 69, + /* 20 */ 90, 77, 86, 6, 39, 53, 55, 59, 39, 87, + /* 30 */ 88, 39, 71, }; -#define fts5YY_REDUCE_USE_DFLT (-16) -#define fts5YY_REDUCE_COUNT (13) -#define fts5YY_REDUCE_MIN (-15) -#define fts5YY_REDUCE_MAX (48) +#define fts5YY_REDUCE_USE_DFLT (-18) +#define fts5YY_REDUCE_COUNT (16) +#define fts5YY_REDUCE_MIN (-17) +#define fts5YY_REDUCE_MAX (67) static const signed char fts5yy_reduce_ofst[] = { - /* 0 */ -15, -7, 1, 9, 17, 22, -9, 0, 39, 44, - /* 10 */ 44, 43, 44, 48, + /* 0 */ -16, -8, 0, 9, 17, 25, 37, -17, 64, -17, + /* 10 */ 67, 12, 12, 12, 20, 27, 35, }; static const fts5YYACTIONTYPE fts5yy_default[] = { - /* 0 */ 88, 88, 88, 88, 88, 69, 82, 88, 88, 87, - /* 10 */ 87, 88, 87, 87, 88, 88, 88, 66, 80, 88, - /* 20 */ 81, 88, 88, 78, 88, 65, + /* 0 */ 104, 104, 104, 104, 104, 104, 89, 104, 98, 104, + /* 10 */ 104, 103, 103, 103, 103, 104, 104, 104, 104, 104, + /* 20 */ 85, 104, 104, 104, 94, 104, 104, 84, 96, 104, + /* 30 */ 104, 97, 104, }; /********** End of lemon-generated parsing tables *****************************/ @@ -168689,17 +185544,21 @@ typedef struct fts5yyStackEntry fts5yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct fts5yyParser { - int fts5yyidx; /* Index of top element in stack */ + fts5yyStackEntry *fts5yytos; /* Pointer to top element of the stack */ #ifdef fts5YYTRACKMAXSTACKDEPTH - int fts5yyidxMax; /* Maximum value of fts5yyidx */ + int fts5yyhwm; /* High-water mark of the stack */ #endif +#ifndef fts5YYNOERRORRECOVERY int fts5yyerrcnt; /* Shifts left before out of the error */ +#endif sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ #if fts5YYSTACKDEPTH<=0 int fts5yystksz; /* Current side of the stack */ fts5yyStackEntry *fts5yystack; /* The parser's stack */ + fts5yyStackEntry fts5yystk0; /* First stack entry */ #else fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */ + fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */ #endif }; typedef struct fts5yyParser fts5yyParser; @@ -168741,12 +185600,12 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){ ** are required. The following table supplies these names */ static const char *const fts5yyTokenName[] = { "$", "OR", "AND", "NOT", - "TERM", "COLON", "LP", "RP", - "LCP", "RCP", "STRING", "COMMA", - "PLUS", "STAR", "error", "input", - "expr", "cnearset", "exprlist", "nearset", - "colset", "colsetlist", "nearphrases", "phrase", - "neardist_opt", "star_opt", + "TERM", "COLON", "MINUS", "LCP", + "RCP", "STRING", "LP", "RP", + "COMMA", "PLUS", "STAR", "error", + "input", "expr", "cnearset", "exprlist", + "colset", "colsetlist", "nearset", "nearphrases", + "phrase", "neardist_opt", "star_opt", }; #endif /* NDEBUG */ @@ -168755,53 +185614,66 @@ static const char *const fts5yyTokenName[] = { */ static const char *const fts5yyRuleName[] = { /* 0 */ "input ::= expr", - /* 1 */ "expr ::= expr AND expr", - /* 2 */ "expr ::= expr OR expr", - /* 3 */ "expr ::= expr NOT expr", - /* 4 */ "expr ::= LP expr RP", - /* 5 */ "expr ::= exprlist", - /* 6 */ "exprlist ::= cnearset", - /* 7 */ "exprlist ::= exprlist cnearset", - /* 8 */ "cnearset ::= nearset", - /* 9 */ "cnearset ::= colset COLON nearset", - /* 10 */ "colset ::= LCP colsetlist RCP", - /* 11 */ "colset ::= STRING", - /* 12 */ "colsetlist ::= colsetlist STRING", - /* 13 */ "colsetlist ::= STRING", - /* 14 */ "nearset ::= phrase", - /* 15 */ "nearset ::= STRING LP nearphrases neardist_opt RP", - /* 16 */ "nearphrases ::= phrase", - /* 17 */ "nearphrases ::= nearphrases phrase", - /* 18 */ "neardist_opt ::=", - /* 19 */ "neardist_opt ::= COMMA STRING", - /* 20 */ "phrase ::= phrase PLUS STRING star_opt", - /* 21 */ "phrase ::= STRING star_opt", - /* 22 */ "star_opt ::= STAR", - /* 23 */ "star_opt ::=", + /* 1 */ "colset ::= MINUS LCP colsetlist RCP", + /* 2 */ "colset ::= LCP colsetlist RCP", + /* 3 */ "colset ::= STRING", + /* 4 */ "colset ::= MINUS STRING", + /* 5 */ "colsetlist ::= colsetlist STRING", + /* 6 */ "colsetlist ::= STRING", + /* 7 */ "expr ::= expr AND expr", + /* 8 */ "expr ::= expr OR expr", + /* 9 */ "expr ::= expr NOT expr", + /* 10 */ "expr ::= colset COLON LP expr RP", + /* 11 */ "expr ::= LP expr RP", + /* 12 */ "expr ::= exprlist", + /* 13 */ "exprlist ::= cnearset", + /* 14 */ "exprlist ::= exprlist cnearset", + /* 15 */ "cnearset ::= nearset", + /* 16 */ "cnearset ::= colset COLON nearset", + /* 17 */ "nearset ::= phrase", + /* 18 */ "nearset ::= STRING LP nearphrases neardist_opt RP", + /* 19 */ "nearphrases ::= phrase", + /* 20 */ "nearphrases ::= nearphrases phrase", + /* 21 */ "neardist_opt ::=", + /* 22 */ "neardist_opt ::= COMMA STRING", + /* 23 */ "phrase ::= phrase PLUS STRING star_opt", + /* 24 */ "phrase ::= STRING star_opt", + /* 25 */ "star_opt ::= STAR", + /* 26 */ "star_opt ::=", }; #endif /* NDEBUG */ #if fts5YYSTACKDEPTH<=0 /* -** Try to increase the size of the parser stack. +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. */ -static void fts5yyGrowStack(fts5yyParser *p){ +static int fts5yyGrowStack(fts5yyParser *p){ int newSize; + int idx; fts5yyStackEntry *pNew; newSize = p->fts5yystksz*2 + 100; - pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); + idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0; + if( p->fts5yystack==&p->fts5yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->fts5yystk0; + }else{ + pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); + } if( pNew ){ p->fts5yystack = pNew; - p->fts5yystksz = newSize; + p->fts5yytos = &p->fts5yystack[idx]; #ifndef NDEBUG if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n", - fts5yyTracePrompt, p->fts5yystksz); + fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", + fts5yyTracePrompt, p->fts5yystksz, newSize); } #endif + p->fts5yystksz = newSize; } + return pNew==0; } #endif @@ -168814,6 +185686,34 @@ static void fts5yyGrowStack(fts5yyParser *p){ # define fts5YYMALLOCARGTYPE size_t #endif +/* Initialize a new parser that has already been allocated. +*/ +static void sqlite3Fts5ParserInit(void *fts5yypParser){ + fts5yyParser *pParser = (fts5yyParser*)fts5yypParser; +#ifdef fts5YYTRACKMAXSTACKDEPTH + pParser->fts5yyhwm = 0; +#endif +#if fts5YYSTACKDEPTH<=0 + pParser->fts5yytos = NULL; + pParser->fts5yystack = NULL; + pParser->fts5yystksz = 0; + if( fts5yyGrowStack(pParser) ){ + pParser->fts5yystack = &pParser->fts5yystk0; + pParser->fts5yystksz = 1; + } +#endif +#ifndef fts5YYNOERRORRECOVERY + pParser->fts5yyerrcnt = -1; +#endif + pParser->fts5yytos = pParser->fts5yystack; + pParser->fts5yystack[0].stateno = 0; + pParser->fts5yystack[0].major = 0; +#if fts5YYSTACKDEPTH>0 + pParser->fts5yystackEnd = &pParser->fts5yystack[fts5YYSTACKDEPTH-1]; +#endif +} + +#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like @@ -168829,19 +185729,11 @@ static void fts5yyGrowStack(fts5yyParser *p){ static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){ fts5yyParser *pParser; pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); - if( pParser ){ - pParser->fts5yyidx = -1; -#ifdef fts5YYTRACKMAXSTACKDEPTH - pParser->fts5yyidxMax = 0; -#endif -#if fts5YYSTACKDEPTH<=0 - pParser->fts5yystack = NULL; - pParser->fts5yystksz = 0; - fts5yyGrowStack(pParser); -#endif - } + if( pParser ) sqlite3Fts5ParserInit(pParser); return pParser; } +#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */ + /* The following function deletes the "minor type" or semantic value ** associated with a symbol. The symbol can be either a terminal @@ -168868,33 +185760,33 @@ static void fts5yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 15: /* input */ + case 16: /* input */ { (void)pParse; } break; - case 16: /* expr */ - case 17: /* cnearset */ - case 18: /* exprlist */ + case 17: /* expr */ + case 18: /* cnearset */ + case 19: /* exprlist */ { - sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18)); -} - break; - case 19: /* nearset */ - case 22: /* nearphrases */ -{ - sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26)); + sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24)); } break; case 20: /* colset */ case 21: /* colsetlist */ { - sqlite3_free((fts5yypminor->fts5yy3)); + sqlite3_free((fts5yypminor->fts5yy11)); } break; - case 23: /* phrase */ + case 22: /* nearset */ + case 23: /* nearphrases */ { - sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11)); + sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46)); +} + break; + case 24: /* phrase */ +{ + sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53)); } break; /********* End destructor definitions *****************************************/ @@ -168910,8 +185802,9 @@ static void fts5yy_destructor( */ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){ fts5yyStackEntry *fts5yytos; - assert( pParser->fts5yyidx>=0 ); - fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx--]; + assert( pParser->fts5yytos!=0 ); + assert( pParser->fts5yytos > pParser->fts5yystack ); + fts5yytos = pParser->fts5yytos--; #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sPopping %s\n", @@ -168922,6 +185815,18 @@ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){ fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor); } +/* +** Clear all secondary memory allocations from the parser +*/ +static void sqlite3Fts5ParserFinalize(void *p){ + fts5yyParser *pParser = (fts5yyParser*)p; + while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser); +#if fts5YYSTACKDEPTH<=0 + if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack); +#endif +} + +#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK /* ** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. @@ -168934,16 +185839,13 @@ static void sqlite3Fts5ParserFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ - fts5yyParser *pParser = (fts5yyParser*)p; #ifndef fts5YYPARSEFREENEVERNULL - if( pParser==0 ) return; + if( p==0 ) return; #endif - while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser); -#if fts5YYSTACKDEPTH<=0 - free(pParser->fts5yystack); -#endif - (*freeProc)((void*)pParser); + sqlite3Fts5ParserFinalize(p); + (*freeProc)(p); } +#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */ /* ** Return the peak depth of the stack for a parser. @@ -168951,7 +185853,7 @@ static void sqlite3Fts5ParserFree( #ifdef fts5YYTRACKMAXSTACKDEPTH static int sqlite3Fts5ParserStackPeak(void *p){ fts5yyParser *pParser = (fts5yyParser*)p; - return pParser->fts5yyidxMax; + return pParser->fts5yyhwm; } #endif @@ -168959,61 +185861,58 @@ static int sqlite3Fts5ParserStackPeak(void *p){ ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. */ -static int fts5yy_find_shift_action( +static unsigned int fts5yy_find_shift_action( fts5yyParser *pParser, /* The parser */ fts5YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; - int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno; + int stateno = pParser->fts5yytos->stateno; if( stateno>=fts5YY_MIN_REDUCE ) return stateno; assert( stateno <= fts5YY_SHIFT_COUNT ); do{ i = fts5yy_shift_ofst[stateno]; - if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno]; assert( iLookAhead!=fts5YYNOCODE ); i += iLookAhead; if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ #ifdef fts5YYFALLBACK - fts5YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]); - } -#endif - assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n", + fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]); } +#endif + assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } #endif #ifdef fts5YYWILDCARD - { - int j = i - iLookAhead + fts5YYWILDCARD; - if( + { + int j = i - iLookAhead + fts5YYWILDCARD; + if( #if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0 - j>=0 && + j>=0 && #endif #if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT - j0 + ){ #ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n", - fts5yyTracePrompt, fts5yyTokenName[iLookAhead], - fts5yyTokenName[fts5YYWILDCARD]); - } -#endif /* NDEBUG */ - return fts5yy_action[j]; + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n", + fts5yyTracePrompt, fts5yyTokenName[iLookAhead], + fts5yyTokenName[fts5YYWILDCARD]); } +#endif /* NDEBUG */ + return fts5yy_action[j]; } -#endif /* fts5YYWILDCARD */ } +#endif /* fts5YYWILDCARD */ return fts5yy_default[stateno]; }else{ return fts5yy_action[i]; @@ -169055,20 +185954,19 @@ static int fts5yy_find_reduce_action( /* ** The following routine is called if the stack overflows. */ -static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *fts5yypMinor){ +static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){ sqlite3Fts5ParserARG_FETCH; - fts5yypParser->fts5yyidx--; #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt); } #endif - while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser); + while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ - assert( 0 ); + sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); /******** End %stack_overflow code ********************************************/ sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ } @@ -169081,11 +185979,11 @@ static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){ if( fts5yyTraceFILE ){ if( fts5yyNewStatefts5yystack[fts5yypParser->fts5yyidx].major], + fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major], fts5yyNewState); }else{ fprintf(fts5yyTraceFILE,"%sShift '%s'\n", - fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major]); + fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major]); } } } @@ -169100,33 +185998,38 @@ static void fts5yy_shift( fts5yyParser *fts5yypParser, /* The parser to be shifted */ int fts5yyNewState, /* The new state to shift in */ int fts5yyMajor, /* The major token to shift in */ - fts5YYMINORTYPE *fts5yypMinor /* Pointer to the minor token to shift in */ + sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */ ){ fts5yyStackEntry *fts5yytos; - fts5yypParser->fts5yyidx++; + fts5yypParser->fts5yytos++; #ifdef fts5YYTRACKMAXSTACKDEPTH - if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){ - fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx; + if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) ); } #endif #if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){ - fts5yyStackOverflow(fts5yypParser, fts5yypMinor); + if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){ + fts5yypParser->fts5yytos--; + fts5yyStackOverflow(fts5yypParser); return; } #else - if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){ - fts5yyGrowStack(fts5yypParser); - if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){ - fts5yyStackOverflow(fts5yypParser, fts5yypMinor); + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){ + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yypParser->fts5yytos--; + fts5yyStackOverflow(fts5yypParser); return; } } #endif - fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx]; + if( fts5yyNewState > fts5YY_MAX_SHIFT ){ + fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; + } + fts5yytos = fts5yypParser->fts5yytos; fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState; fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor; - fts5yytos->minor = *fts5yypMinor; + fts5yytos->minor.fts5yy0 = fts5yyMinor; fts5yyTraceShift(fts5yypParser, fts5yyNewState); } @@ -169134,33 +186037,36 @@ static void fts5yy_shift( ** is used during the reduce. */ static const struct { - fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ + 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[] = { - { 15, 1 }, - { 16, 3 }, - { 16, 3 }, - { 16, 3 }, - { 16, 3 }, - { 16, 1 }, - { 18, 1 }, - { 18, 2 }, - { 17, 1 }, - { 17, 3 }, - { 20, 3 }, - { 20, 1 }, - { 21, 2 }, - { 21, 1 }, - { 19, 1 }, - { 19, 5 }, - { 22, 1 }, - { 22, 2 }, - { 24, 0 }, - { 24, 2 }, - { 23, 4 }, - { 23, 2 }, - { 25, 1 }, + { 16, -1 }, + { 20, -4 }, + { 20, -3 }, + { 20, -1 }, + { 20, -2 }, + { 21, -2 }, + { 21, -1 }, + { 17, -3 }, + { 17, -3 }, + { 17, -3 }, + { 17, -5 }, + { 17, -3 }, + { 17, -1 }, + { 19, -1 }, + { 19, -2 }, + { 18, -1 }, + { 18, -3 }, + { 22, -1 }, + { 22, -5 }, + { 23, -1 }, + { 23, -2 }, { 25, 0 }, + { 25, -2 }, + { 24, -4 }, + { 24, -2 }, + { 26, -1 }, + { 26, 0 }, }; static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ @@ -169171,24 +186077,47 @@ static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ */ static void fts5yy_reduce( fts5yyParser *fts5yypParser, /* The parser */ - int fts5yyruleno /* Number of the rule by which to reduce */ + unsigned int fts5yyruleno /* Number of the rule by which to reduce */ ){ int fts5yygoto; /* The next state */ int fts5yyact; /* The next action */ - fts5YYMINORTYPE fts5yygotominor; /* The LHS of the rule reduced */ fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */ int fts5yysize; /* Amount to pop the stack */ sqlite3Fts5ParserARG_FETCH; - fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx]; + fts5yymsp = fts5yypParser->fts5yytos; #ifndef NDEBUG - if( fts5yyTraceFILE && fts5yyruleno>=0 - && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ + if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt, - fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno); + fts5yyRuleName[fts5yyruleno], fts5yymsp[fts5yysize].stateno); } #endif /* NDEBUG */ - fts5yygotominor = fts5yyzerominor; + + /* 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 ){ +#ifdef fts5YYTRACKMAXSTACKDEPTH + if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)); + } +#endif +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){ + fts5yyStackOverflow(fts5yypParser); + return; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yyStackOverflow(fts5yypParser); + return; + } + fts5yymsp = fts5yypParser->fts5yytos; + } +#endif + } switch( fts5yyruleno ){ /* Beginning here are the reduction cases. A typical example @@ -169200,134 +186129,166 @@ static void fts5yy_reduce( ** break; */ /********** Begin reduce actions **********************************************/ + fts5YYMINORTYPE fts5yylhsminor; case 0: /* input ::= expr */ -{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); } +{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); } break; - case 1: /* expr ::= expr AND expr */ -{ - fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); -} - break; - case 2: /* expr ::= expr OR expr */ -{ - fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); -} - break; - case 3: /* expr ::= expr NOT expr */ -{ - fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); -} - break; - case 4: /* expr ::= LP expr RP */ -{fts5yygotominor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;} - break; - case 5: /* expr ::= exprlist */ - case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6); -{fts5yygotominor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;} - break; - case 7: /* exprlist ::= exprlist cnearset */ -{ - fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); -} - break; - case 8: /* cnearset ::= nearset */ + case 1: /* colset ::= MINUS LCP colsetlist RCP */ { - fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); + fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); } break; - case 9: /* cnearset ::= colset COLON nearset */ -{ - sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3); - fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); -} + case 2: /* colset ::= LCP colsetlist RCP */ +{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; } break; - case 10: /* colset ::= LCP colsetlist RCP */ -{ fts5yygotominor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; } - break; - case 11: /* colset ::= STRING */ + case 3: /* colset ::= STRING */ { - fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 4: /* colset ::= MINUS STRING */ +{ + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); } break; - case 12: /* colsetlist ::= colsetlist STRING */ + case 5: /* colsetlist ::= colsetlist STRING */ { - fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); } + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); } + fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; break; - case 13: /* colsetlist ::= STRING */ + case 6: /* colsetlist ::= STRING */ { - fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); } + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; break; - case 14: /* nearset ::= phrase */ -{ fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); } + case 7: /* expr ::= expr AND expr */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); +} + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */ + case 8: /* expr ::= expr OR expr */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); +} + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 9: /* expr ::= expr NOT expr */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); +} + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 10: /* expr ::= colset COLON LP expr RP */ +{ + sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[-4].minor.fts5yy11); + fts5yylhsminor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24; +} + fts5yymsp[-4].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 11: /* expr ::= LP expr RP */ +{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;} + break; + case 12: /* expr ::= exprlist */ + case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13); +{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;} + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 14: /* exprlist ::= exprlist cnearset */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24); +} + fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 15: /* cnearset ::= nearset */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); +} + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 16: /* cnearset ::= colset COLON nearset */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); + sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy24, fts5yymsp[-2].minor.fts5yy11); +} + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 17: /* nearset ::= phrase */ +{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 18: /* nearset ::= STRING LP nearphrases neardist_opt RP */ { sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0); - sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0); - fts5yygotominor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26; + sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0); + fts5yylhsminor.fts5yy46 = fts5yymsp[-2].minor.fts5yy46; } + fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 16: /* nearphrases ::= phrase */ + case 19: /* nearphrases ::= phrase */ { - fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 17: /* nearphrases ::= nearphrases phrase */ + case 20: /* nearphrases ::= nearphrases phrase */ { - fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11); + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53); } + fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 18: /* neardist_opt ::= */ -{ fts5yygotominor.fts5yy0.p = 0; fts5yygotominor.fts5yy0.n = 0; } + case 21: /* neardist_opt ::= */ +{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; } break; - case 19: /* neardist_opt ::= COMMA STRING */ -{ fts5yygotominor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; } + case 22: /* neardist_opt ::= COMMA STRING */ +{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; } break; - case 20: /* phrase ::= phrase PLUS STRING star_opt */ + case 23: /* phrase ::= phrase PLUS STRING star_opt */ { - fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20); + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); } + fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53; break; - case 21: /* phrase ::= STRING star_opt */ + case 24: /* phrase ::= STRING star_opt */ { - fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20); + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); } + fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53; break; - case 22: /* star_opt ::= STAR */ -{ fts5yygotominor.fts5yy20 = 1; } + case 25: /* star_opt ::= STAR */ +{ fts5yymsp[0].minor.fts5yy4 = 1; } break; - case 23: /* star_opt ::= */ -{ fts5yygotominor.fts5yy20 = 0; } + case 26: /* star_opt ::= */ +{ fts5yymsp[1].minor.fts5yy4 = 0; } break; default: break; /********** End reduce actions ************************************************/ }; - assert( fts5yyruleno>=0 && fts5yyrulenofts5yyidx -= fts5yysize; - fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto); - if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ - if( fts5yyact>fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; - /* If the reduce action popped at least - ** one element off the stack, then we can push the new element back - ** onto the stack here, and skip the stack overflow test in fts5yy_shift(). - ** That gives a significant speed improvement. */ - if( fts5yysize ){ - fts5yypParser->fts5yyidx++; - fts5yymsp -= fts5yysize-1; - fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; - fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; - fts5yymsp->minor = fts5yygotominor; - fts5yyTraceShift(fts5yypParser, fts5yyact); - }else{ - fts5yy_shift(fts5yypParser,fts5yyact,fts5yygoto,&fts5yygotominor); - } - }else{ - assert( fts5yyact == fts5YY_ACCEPT_ACTION ); + fts5yyact = fts5yy_find_reduce_action(fts5yymsp[fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto); + + /* There are no SHIFTREDUCE actions on nonterminals because the table + ** generator has simplified them to pure REDUCE actions. */ + assert( !(fts5yyact>fts5YY_MAX_SHIFT && fts5yyact<=fts5YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( fts5yyact!=fts5YY_ERROR_ACTION ); + + if( fts5yyact==fts5YY_ACCEPT_ACTION ){ + fts5yypParser->fts5yytos += fts5yysize; fts5yy_accept(fts5yypParser); + }else{ + fts5yymsp += fts5yysize+1; + fts5yypParser->fts5yytos = fts5yymsp; + fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; + fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; + fts5yyTraceShift(fts5yypParser, fts5yyact); } } @@ -169344,7 +186305,7 @@ static void fts5yy_parse_failed( fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt); } #endif - while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser); + while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ @@ -169359,12 +186320,13 @@ static void fts5yy_parse_failed( static void fts5yy_syntax_error( fts5yyParser *fts5yypParser, /* The parser */ int fts5yymajor, /* The major type of the error token */ - fts5YYMINORTYPE fts5yyminor /* The minor type of the error token */ + sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */ ){ sqlite3Fts5ParserARG_FETCH; -#define FTS5TOKEN (fts5yyminor.fts5yy0) +#define FTS5TOKEN fts5yyminor /************ Begin %syntax_error code ****************************************/ + UNUSED_PARAM(fts5yymajor); /* Silence a compiler warning */ sqlite3Fts5ParseError( pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p ); @@ -169384,7 +186346,10 @@ static void fts5yy_accept( fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt); } #endif - while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif + assert( fts5yypParser->fts5yytos==fts5yypParser->fts5yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ @@ -169418,7 +186383,7 @@ static void sqlite3Fts5Parser( sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */ ){ fts5YYMINORTYPE fts5yyminorunion; - int fts5yyact; /* The parser action. */ + unsigned int fts5yyact; /* The parser action. */ #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) int fts5yyendofinput; /* True if we are at the end of input */ #endif @@ -169427,29 +186392,8 @@ static void sqlite3Fts5Parser( #endif fts5yyParser *fts5yypParser; /* The parser */ - /* (re)initialize the parser, if necessary */ fts5yypParser = (fts5yyParser*)fts5yyp; - if( fts5yypParser->fts5yyidx<0 ){ -#if fts5YYSTACKDEPTH<=0 - if( fts5yypParser->fts5yystksz <=0 ){ - /*memset(&fts5yyminorunion, 0, sizeof(fts5yyminorunion));*/ - fts5yyminorunion = fts5yyzerominor; - fts5yyStackOverflow(fts5yypParser, &fts5yyminorunion); - return; - } -#endif - fts5yypParser->fts5yyidx = 0; - fts5yypParser->fts5yyerrcnt = -1; - fts5yypParser->fts5yystack[0].stateno = 0; - fts5yypParser->fts5yystack[0].major = 0; -#ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sInitialize. Empty stack. State 0\n", - fts5yyTracePrompt); - } -#endif - } - fts5yyminorunion.fts5yy0 = fts5yyminor; + assert( fts5yypParser->fts5yytos!=0 ); #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) fts5yyendofinput = (fts5yymajor==0); #endif @@ -169464,14 +186408,16 @@ static void sqlite3Fts5Parser( do{ fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor); if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ - if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; - fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,&fts5yyminorunion); + fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor); +#ifndef fts5YYNOERRORRECOVERY fts5yypParser->fts5yyerrcnt--; +#endif fts5yymajor = fts5YYNOCODE; }else if( fts5yyact <= fts5YY_MAX_REDUCE ){ fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE); }else{ assert( fts5yyact == fts5YY_ERROR_ACTION ); + fts5yyminorunion.fts5yy0 = fts5yyminor; #ifdef fts5YYERRORSYMBOL int fts5yymx; #endif @@ -169501,9 +186447,9 @@ static void sqlite3Fts5Parser( ** */ if( fts5yypParser->fts5yyerrcnt<0 ){ - fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion); + fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor); } - fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major; + fts5yymx = fts5yypParser->fts5yytos->major; if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){ #ifndef NDEBUG if( fts5yyTraceFILE ){ @@ -169511,26 +186457,26 @@ static void sqlite3Fts5Parser( fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]); } #endif - fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); + fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion); fts5yymajor = fts5YYNOCODE; }else{ - while( - fts5yypParser->fts5yyidx >= 0 && - fts5yymx != fts5YYERRORSYMBOL && - (fts5yyact = fts5yy_find_reduce_action( - fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno, + while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack + && fts5yymx != fts5YYERRORSYMBOL + && (fts5yyact = fts5yy_find_reduce_action( + fts5yypParser->fts5yytos->stateno, fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE ){ fts5yy_pop_parser_stack(fts5yypParser); } - if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){ + if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){ fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); fts5yy_parse_failed(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif fts5yymajor = fts5YYNOCODE; }else if( fts5yymx!=fts5YYERRORSYMBOL ){ - fts5YYMINORTYPE u2; - u2.fts5YYERRSYMDT = 0; - fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,&u2); + fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor); } } fts5yypParser->fts5yyerrcnt = 3; @@ -169543,7 +186489,7 @@ static void sqlite3Fts5Parser( ** Applications can set this macro (for example inside %include) if ** they intend to abandon the parse upon the first syntax error seen. */ - fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion); + fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor); fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); fts5yymajor = fts5YYNOCODE; @@ -169558,24 +186504,29 @@ static void sqlite3Fts5Parser( ** three input tokens have been successfully shifted. */ if( fts5yypParser->fts5yyerrcnt<=0 ){ - fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion); + fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor); } fts5yypParser->fts5yyerrcnt = 3; fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); if( fts5yyendofinput ){ fts5yy_parse_failed(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif } fts5yymajor = fts5YYNOCODE; #endif } - }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 ); + }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ); #ifndef NDEBUG if( fts5yyTraceFILE ){ - int i; + fts5yyStackEntry *i; + char cDiv = '['; fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt); - for(i=1; i<=fts5yypParser->fts5yyidx; i++) - fprintf(fts5yyTraceFILE,"%c%s", i==1 ? '[' : ' ', - fts5yyTokenName[fts5yypParser->fts5yystack[i].major]); + for(i=&fts5yypParser->fts5yystack[1]; i<=fts5yypParser->fts5yytos; i++){ + fprintf(fts5yyTraceFILE,"%c%s", cDiv, fts5yyTokenName[i->major]); + cDiv = ' '; + } fprintf(fts5yyTraceFILE,"]\n"); } #endif @@ -169742,6 +186693,8 @@ static int fts5HighlightCb( int rc = SQLITE_OK; int iPos; + UNUSED_PARAM2(pToken, nToken); + if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK; iPos = p->iPos++; @@ -169771,7 +186724,7 @@ static int fts5HighlightCb( if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; - if( iPositer.iEnd ){ + if( iPos>=p->iter.iStart && iPositer.iEnd ){ fts5HighlightAppend(&rc, p, p->zClose, -1); } } @@ -169828,6 +186781,118 @@ static void fts5HighlightFunction( ** End of highlight() implementation. **************************************************************************/ +/* +** Context object passed to the fts5SentenceFinderCb() function. +*/ +typedef struct Fts5SFinder Fts5SFinder; +struct Fts5SFinder { + int iPos; /* Current token position */ + int nFirstAlloc; /* Allocated size of aFirst[] */ + int nFirst; /* Number of entries in aFirst[] */ + int *aFirst; /* Array of first token in each sentence */ + const char *zDoc; /* Document being tokenized */ +}; + +/* +** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if +** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an +** error occurs. +*/ +static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ + if( p->nFirstAlloc==p->nFirst ){ + int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; + int *aNew; + + aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int)); + if( aNew==0 ) return SQLITE_NOMEM; + p->aFirst = aNew; + p->nFirstAlloc = nNew; + } + p->aFirst[p->nFirst++] = iAdd; + return SQLITE_OK; +} + +/* +** This function is an xTokenize() callback used by the auxiliary snippet() +** function. Its job is to identify tokens that are the first in a sentence. +** For each such token, an entry is added to the SFinder.aFirst[] array. +*/ +static int fts5SentenceFinderCb( + void *pContext, /* Pointer to HighlightContext object */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStartOff, /* Start offset of token */ + int iEndOff /* End offset of token */ +){ + int rc = SQLITE_OK; + + UNUSED_PARAM2(pToken, nToken); + UNUSED_PARAM(iEndOff); + + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ + Fts5SFinder *p = (Fts5SFinder*)pContext; + if( p->iPos>0 ){ + int i; + char c = 0; + for(i=iStartOff-1; i>=0; i--){ + c = p->zDoc[i]; + if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) break; + } + if( i!=iStartOff-1 && (c=='.' || c==':') ){ + rc = fts5SentenceFinderAdd(p, p->iPos); + } + }else{ + rc = fts5SentenceFinderAdd(p, 0); + } + p->iPos++; + } + return rc; +} + +static int fts5SnippetScore( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + int nDocsize, /* Size of column in tokens */ + unsigned char *aSeen, /* Array with one element per query phrase */ + int iCol, /* Column to score */ + int iPos, /* Starting offset to score */ + int nToken, /* Max tokens per snippet */ + int *pnScore, /* OUT: Score */ + int *piPos /* OUT: Adjusted offset */ +){ + int rc; + int i; + int ip = 0; + int ic = 0; + int iOff = 0; + int iFirst = -1; + int nInst; + int nScore = 0; + int iLast = 0; + + 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) ){ + nScore += (aSeen[ip] ? 1 : 1000); + aSeen[ip] = 1; + if( iFirst<0 ) iFirst = iOff; + iLast = iOff + pApi->xPhraseSize(pFts, ip); + } + } + + *pnScore = nScore; + if( piPos ){ + int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2; + if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken; + if( iAdj<0 ) iAdj = 0; + *piPos = iAdj; + } + + return rc; +} + /* ** Implementation of snippet() function. */ @@ -169849,9 +186914,10 @@ static void fts5SnippetFunction( unsigned char *aSeen; /* Array of "seen instance" flags */ int iBestCol; /* Column containing best snippet */ int iBestStart = 0; /* First token of best snippet */ - int iBestLast; /* Last token of best snippet */ int nBestScore = 0; /* Score of best snippet */ int nColSize = 0; /* Total size of iBestCol in tokens */ + Fts5SFinder sFinder; /* Used to find the beginnings of sentences */ + int nCol; if( nVal!=5 ){ const char *zErr = "wrong number of arguments to function snippet()"; @@ -169859,13 +186925,13 @@ static void fts5SnippetFunction( return; } + nCol = pApi->xColumnCount(pFts); memset(&ctx, 0, sizeof(HighlightContext)); iCol = sqlite3_value_int(apVal[0]); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); zEllips = (const char*)sqlite3_value_text(apVal[3]); nToken = sqlite3_value_int(apVal[4]); - iBestLast = nToken-1; iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); @@ -169873,65 +186939,94 @@ static void fts5SnippetFunction( if( aSeen==0 ){ rc = SQLITE_NOMEM; } - if( rc==SQLITE_OK ){ rc = pApi->xInstCount(pFts, &nInst); } - for(i=0; rc==SQLITE_OK && ixInst(pFts, i, &ip, &iSnippetCol, &iStart); - if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){ - int nScore = 1000; - int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip); - int j; - aSeen[ip] = 1; - for(j=i+1; rc==SQLITE_OK && jxInst(pFts, j, &ip, &ic, &io); - iFinal = io + pApi->xPhraseSize(pFts, ip) - 1; - if( rc==SQLITE_OK && ic==iSnippetCol && iLastiLast ) iLast = iFinal; + memset(&sFinder, 0, sizeof(Fts5SFinder)); + for(i=0; ixColumnText(pFts, i, &sFinder.zDoc, &nDoc); + if( rc!=SQLITE_OK ) break; + rc = pApi->xTokenize(pFts, + sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb + ); + if( rc!=SQLITE_OK ) break; + rc = pApi->xColumnSize(pFts, i, &nDocsize); + if( rc!=SQLITE_OK ) break; + + for(ii=0; rc==SQLITE_OK && iixInst(pFts, ii, &ip, &ic, &io); + if( ic!=i || rc!=SQLITE_OK ) continue; + memset(aSeen, 0, nPhrase); + rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, + io, nToken, &nScore, &iAdj + ); + if( rc==SQLITE_OK && nScore>nBestScore ){ + nBestScore = nScore; + iBestCol = i; + iBestStart = iAdj; + nColSize = nDocsize; } - } - if( rc==SQLITE_OK && nScore>nBestScore ){ - iBestCol = iSnippetCol; - iBestStart = iStart; - iBestLast = iLast; - nBestScore = nScore; + if( rc==SQLITE_OK && sFinder.nFirst && nDocsize>nToken ){ + for(jj=0; jj<(sFinder.nFirst-1); jj++){ + if( sFinder.aFirst[jj+1]>io ) break; + } + + if( sFinder.aFirst[jj]nBestScore ){ + nBestScore = nScore; + iBestCol = i; + iBestStart = sFinder.aFirst[jj]; + nColSize = nDocsize; + } + } + } } } } - if( rc==SQLITE_OK ){ - rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); - } if( rc==SQLITE_OK ){ rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); } + if( rc==SQLITE_OK && nColSize==0 ){ + rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); + } if( ctx.zIn ){ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); } - if( (iBestStart+nToken-1)>iBestLast ){ - iBestStart -= (iBestStart+nToken-1-iBestLast) / 2; - } - if( iBestStart+nToken>nColSize ){ - iBestStart = nColSize - nToken; - } - if( iBestStart<0 ) iBestStart = 0; - ctx.iRangeStart = iBestStart; ctx.iRangeEnd = iBestStart + nToken - 1; if( iBestStart>0 ){ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } + + /* Advance iterator ctx.iter so that it points to the first coalesced + ** phrase instance at or following position iBestStart. */ + while( ctx.iter.iStart>=0 && ctx.iter.iStartxTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } @@ -169940,15 +187035,15 @@ static void fts5SnippetFunction( }else{ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } - - if( rc==SQLITE_OK ){ - sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); - }else{ - sqlite3_result_error_code(pCtx, rc); - } - sqlite3_free(ctx.zOut); } + if( rc==SQLITE_OK ){ + sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); + }else{ + sqlite3_result_error_code(pCtx, rc); + } + sqlite3_free(ctx.zOut); sqlite3_free(aSeen); + sqlite3_free(sFinder.aFirst); } /************************************************************************/ @@ -169975,6 +187070,7 @@ static int fts5CountCb( void *pUserData /* Pointer to sqlite3_int64 variable */ ){ sqlite3_int64 *pn = (sqlite3_int64*)pUserData; + UNUSED_PARAM2(pApi, pFts); (*pn)++; return SQLITE_OK; } @@ -170128,7 +187224,7 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ - for(i=0; rc==SQLITE_OK && i<(int)ArraySize(aBuiltin); i++){ + for(i=0; rc==SQLITE_OK && ixCreateFunction(pApi, aBuiltin[i].zFunc, aBuiltin[i].pUserData, @@ -170159,19 +187255,21 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ /* #include "fts5Int.h" */ -static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, int nByte){ - int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64; - u8 *pNew; - while( nNewp, nNew); - if( pNew==0 ){ - *pRc = SQLITE_NOMEM; - return 1; - }else{ - pBuf->nSpace = nNew; - pBuf->p = pNew; +static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ + if( (u32)pBuf->nSpacenSpace ? pBuf->nSpace : 64; + u8 *pNew; + while( nNewp, nNew); + if( pNew==0 ){ + *pRc = SQLITE_NOMEM; + return 1; + }else{ + pBuf->nSpace = nNew; + pBuf->p = pNew; + } } return 0; } @@ -170205,13 +187303,15 @@ static int sqlite3Fts5Get32(const u8 *aBuf){ static void sqlite3Fts5BufferAppendBlob( int *pRc, Fts5Buffer *pBuf, - int nData, + u32 nData, const u8 *pData ){ - assert( *pRc || nData>=0 ); - if( fts5BufferGrow(pRc, pBuf, nData) ) return; - memcpy(&pBuf->p[pBuf->n], pData, nData); - pBuf->n += nData; + assert_nc( *pRc || nData>=0 ); + if( nData ){ + if( fts5BufferGrow(pRc, pBuf, nData) ) return; + memcpy(&pBuf->p[pBuf->n], pData, nData); + pBuf->n += nData; + } } /* @@ -170352,31 +187452,44 @@ static int sqlite3Fts5PoslistReaderInit( return pIter->bEof; } +/* +** Append position iPos to the position list being accumulated in buffer +** pBuf, which must be already be large enough to hold the new data. +** The previous position written to this list is *piPrev. *piPrev is set +** to iPos before returning. +*/ +static void sqlite3Fts5PoslistSafeAppend( + Fts5Buffer *pBuf, + i64 *piPrev, + i64 iPos +){ + static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; + if( (iPos & colmask) != (*piPrev & colmask) ){ + pBuf->p[pBuf->n++] = 1; + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); + *piPrev = (iPos & colmask); + } + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2); + *piPrev = iPos; +} + static int sqlite3Fts5PoslistWriterAppend( Fts5Buffer *pBuf, Fts5PoslistWriter *pWriter, i64 iPos ){ - static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; - int rc = SQLITE_OK; - if( 0==fts5BufferGrow(&rc, pBuf, 5+5+5) ){ - if( (iPos & colmask) != (pWriter->iPrev & colmask) ){ - pBuf->p[pBuf->n++] = 1; - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); - pWriter->iPrev = (iPos & colmask); - } - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2); - pWriter->iPrev = iPos; - } - return rc; + int rc = 0; /* Initialized only to suppress erroneous warning from Clang */ + if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc; + sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos); + return SQLITE_OK; } static void *sqlite3Fts5MallocZero(int *pRc, int nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc(nByte); - if( pRet==0 && nByte>0 ){ - *pRc = SQLITE_NOMEM; + if( pRet==0 ){ + if( nByte>0 ) *pRc = SQLITE_NOMEM; }else{ memset(pRet, 0, nByte); } @@ -170436,6 +187549,89 @@ static int sqlite3Fts5IsBareword(char t){ } +/************************************************************************* +*/ +typedef struct Fts5TermsetEntry Fts5TermsetEntry; +struct Fts5TermsetEntry { + char *pTerm; + int nTerm; + int iIdx; /* Index (main or aPrefix[] entry) */ + Fts5TermsetEntry *pNext; +}; + +struct Fts5Termset { + Fts5TermsetEntry *apHash[512]; +}; + +static int sqlite3Fts5TermsetNew(Fts5Termset **pp){ + int rc = SQLITE_OK; + *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset)); + return rc; +} + +static int sqlite3Fts5TermsetAdd( + Fts5Termset *p, + int iIdx, + const char *pTerm, int nTerm, + int *pbPresent +){ + int rc = SQLITE_OK; + *pbPresent = 0; + if( p ){ + int i; + u32 hash = 13; + Fts5TermsetEntry *pEntry; + + /* Calculate a hash value for this term. This is the same hash checksum + ** used by the fts5_hash.c module. This is not important for correct + ** operation of the module, but is necessary to ensure that some tests + ** designed to produce hash table collisions really do work. */ + for(i=nTerm-1; i>=0; i--){ + hash = (hash << 3) ^ hash ^ pTerm[i]; + } + hash = (hash << 3) ^ hash ^ iIdx; + hash = hash % ArraySize(p->apHash); + + for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){ + if( pEntry->iIdx==iIdx + && pEntry->nTerm==nTerm + && memcmp(pEntry->pTerm, pTerm, nTerm)==0 + ){ + *pbPresent = 1; + break; + } + } + + if( pEntry==0 ){ + pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm); + if( pEntry ){ + pEntry->pTerm = (char*)&pEntry[1]; + pEntry->nTerm = nTerm; + pEntry->iIdx = iIdx; + memcpy(pEntry->pTerm, pTerm, nTerm); + pEntry->pNext = p->apHash[hash]; + p->apHash[hash] = pEntry; + } + } + } + + return rc; +} + +static void sqlite3Fts5TermsetFree(Fts5Termset *p){ + if( p ){ + u32 i; + for(i=0; iapHash); i++){ + Fts5TermsetEntry *pEntry = p->apHash[i]; + while( pEntry ){ + Fts5TermsetEntry *pDel = pEntry; + pEntry = pEntry->pNext; + sqlite3_free(pDel); + } + } + sqlite3_free(p); + } +} /* ** 2014 Jun 09 @@ -170453,11 +187649,11 @@ static int sqlite3Fts5IsBareword(char t){ */ - /* #include "fts5Int.h" */ #define FTS5_DEFAULT_PAGE_SIZE 4050 #define FTS5_DEFAULT_AUTOMERGE 4 +#define FTS5_DEFAULT_USERMERGE 4 #define FTS5_DEFAULT_CRISISMERGE 16 #define FTS5_DEFAULT_HASHSIZE (1024*1024) @@ -170634,6 +187830,33 @@ static void sqlite3Fts5Dequote(char *z){ } } + +struct Fts5Enum { + const char *zName; + int eVal; +}; +typedef struct Fts5Enum Fts5Enum; + +static int fts5ConfigSetEnum( + const Fts5Enum *aEnum, + const char *zEnum, + int *peVal +){ + int nEnum = (int)strlen(zEnum); + int i; + int iVal = -1; + + for(i=0; aEnum[i].zName; i++){ + if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){ + if( iVal>=0 ) return SQLITE_ERROR; + iVal = aEnum[i].eVal; + } + } + + *peVal = iVal; + return iVal<0 ? SQLITE_ERROR : SQLITE_OK; +} + /* ** Parse a "special" CREATE VIRTUAL TABLE directive and update ** configuration object pConfig as appropriate. @@ -170691,7 +187914,7 @@ static int fts5ConfigParseSpecial( p++; } - if( rc==SQLITE_OK && (nPre<=0 || nPre>=1000) ){ + if( nPre<=0 || nPre>=1000 ){ *pzErr = sqlite3_mprintf("prefix length out of range (max 999)"); rc = SQLITE_ERROR; break; @@ -170784,6 +188007,20 @@ static int fts5ConfigParseSpecial( return rc; } + if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ + const Fts5Enum aDetail[] = { + { "none", FTS5_DETAIL_NONE }, + { "full", FTS5_DETAIL_FULL }, + { "columns", FTS5_DETAIL_COLUMNS }, + { 0, 0 } + }; + + if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ + *pzErr = sqlite3_mprintf("malformed detail=... directive"); + } + return rc; + } + *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); return SQLITE_ERROR; } @@ -170840,7 +188077,9 @@ static const char *fts5ConfigGobbleWord( *pbQuoted = 1; }else{ zRet = fts5ConfigSkipBareword(zIn); - zOut[zRet-zIn] = '\0'; + if( zRet ){ + zOut[zRet-zIn] = '\0'; + } } } @@ -170939,6 +188178,7 @@ static int sqlite3Fts5ConfigParse( pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); pRet->bColumnsize = 1; + pRet->eDetail = FTS5_DETAIL_FULL; #ifdef SQLITE_DEBUG pRet->bPrefixIndex = 1; #endif @@ -171255,6 +188495,18 @@ static int sqlite3Fts5ConfigSetValue( } } + else if( 0==sqlite3_stricmp(zKey, "usermerge") ){ + int nUsermerge = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + nUsermerge = sqlite3_value_int(pVal); + } + if( nUsermerge<2 || nUsermerge>16 ){ + *pbBadkey = 1; + }else{ + pConfig->nUsermerge = nUsermerge; + } + } + else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){ int nCrisisMerge = -1; if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ @@ -171301,6 +188553,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ /* Set default values */ pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE; pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE; + pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE; pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE; @@ -171342,7 +188595,6 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ return rc; } - /* ** 2014 May 31 ** @@ -171385,6 +188637,7 @@ static void sqlite3Fts5ParserTrace(FILE*, char*); struct Fts5Expr { Fts5Index *pIndex; + Fts5Config *pConfig; Fts5ExprNode *pRoot; int bDesc; /* Iterate in descending rowid order */ int nPhrase; /* Number of phrases in expression */ @@ -171406,6 +188659,9 @@ struct Fts5ExprNode { int bEof; /* True at EOF */ int bNomatch; /* True if entry is not a match */ + /* Next method for this node. */ + int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64); + i64 iRowid; /* Current rowid */ Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ @@ -171417,6 +188673,12 @@ struct Fts5ExprNode { #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) +/* +** Invoke the xNext method of an Fts5ExprNode object. This macro should be +** used as if it has the same signature as the xNext() methods themselves. +*/ +#define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d)) + /* ** An instance of the following structure represents a single search term ** or term prefix. @@ -171502,6 +188764,7 @@ static int fts5ExprGetToken( case ',': tok = FTS5_COMMA; break; case '+': tok = FTS5_PLUS; break; case '*': tok = FTS5_STAR; break; + case '-': tok = FTS5_MINUS; break; case '\0': tok = FTS5_EOF; break; case '"': { @@ -171547,6 +188810,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); } static int sqlite3Fts5ExprNew( Fts5Config *pConfig, /* FTS5 Configuration */ + int iCol, const char *zExpr, /* Expression text */ Fts5Expr **ppNew, char **pzErr @@ -171571,6 +188835,18 @@ static int sqlite3Fts5ExprNew( }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); sqlite3Fts5ParserFree(pEngine, fts5ParseFree); + /* If the LHS of the MATCH expression was a user column, apply the + ** implicit column-filter. */ + if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){ + int n = sizeof(Fts5Colset); + Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); + if( pColset ){ + pColset->nCol = 1; + pColset->aiCol[0] = iCol; + sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset); + } + } + assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); if( sParse.rc==SQLITE_OK ){ *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); @@ -171578,12 +188854,23 @@ static int sqlite3Fts5ExprNew( sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); }else{ - pNew->pRoot = sParse.pExpr; + if( !sParse.pExpr ){ + const int nByte = sizeof(Fts5ExprNode); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); + if( pNew->pRoot ){ + pNew->pRoot->bEof = 1; + } + }else{ + pNew->pRoot = sParse.pExpr; + } pNew->pIndex = 0; + pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; sParse.apPhrase = 0; } + }else{ + sqlite3Fts5ParseNodeFree(sParse.pExpr); } sqlite3_free(sParse.apPhrase); @@ -171629,7 +188916,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ assert( bDesc==0 || bDesc==1 ); for(p=pTerm; p; p=p->pSynonym){ if( 0==sqlite3Fts5IterEof(p->pIter) ){ - i64 iRowid = sqlite3Fts5IterRowid(p->pIter); + i64 iRowid = p->pIter->iRowid; if( bRetValid==0 || (bDesc!=(iRowidpSynonym ); for(p=pTerm; p; p=p->pSynonym){ Fts5IndexIter *pIter = p->pIter; - if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){ - const u8 *a; - int n; - i64 dummy; - rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy); - if( rc!=SQLITE_OK ) goto synonym_poslist_out; + 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); @@ -171679,20 +188961,19 @@ static int fts5ExprSynonymPoslist( if( aIter!=aStatic ) sqlite3_free(aIter); aIter = aNew; } - sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]); + sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]); assert( aIter[nIter].bEof==0 ); nIter++; } } - assert( *pbDel==0 ); if( nIter==1 ){ *pa = (u8*)aIter[0].a; *pn = aIter[0].n; }else{ Fts5PoslistWriter writer = {0}; - Fts5Buffer buf = {0,0,0}; i64 iPrev = -1; + fts5BufferZero(pBuf); while( 1 ){ int i; i64 iMin = FTS5_LARGEST_INT64; @@ -171707,15 +188988,12 @@ static int fts5ExprSynonymPoslist( } } if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break; - rc = sqlite3Fts5PoslistWriterAppend(&buf, &writer, iMin); + rc = sqlite3Fts5PoslistWriterAppend(pBuf, &writer, iMin); iPrev = iMin; } - if( rc ){ - sqlite3_free(buf.p); - }else{ - *pa = buf.p; - *pn = buf.n; - *pbDel = 1; + if( rc==SQLITE_OK ){ + *pa = pBuf->p; + *pn = pBuf->n; } } @@ -171738,7 +189016,6 @@ static int fts5ExprSynonymPoslist( */ static int fts5ExprPhraseIsMatch( Fts5ExprNode *pNode, /* Node pPhrase belongs to */ - Fts5Colset *pColset, /* Restrict matches to these columns */ Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */ int *pbMatch /* OUT: Set to true if really a match */ ){ @@ -171752,7 +189029,7 @@ 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>(int)ArraySize(aStatic) ){ + if( pPhrase->nTerm>ArraySize(aStatic) ){ int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); if( !aIter ) return SQLITE_NOMEM; @@ -171762,18 +189039,21 @@ static int fts5ExprPhraseIsMatch( /* Initialize a term iterator for each term in the phrase */ for(i=0; inTerm; i++){ Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; - i64 dummy; int n = 0; int bFlag = 0; - const u8 *a = 0; + u8 *a = 0; if( pTerm->pSynonym ){ - rc = fts5ExprSynonymPoslist( - pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n - ); + Fts5Buffer buf = {0, 0, 0}; + rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n); + if( rc ){ + sqlite3_free(a); + goto ismatch_out; + } + if( a==buf.p ) bFlag = 1; }else{ - rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy); + a = (u8*)pTerm->pIter->pData; + n = pTerm->pIter->nData; } - if( rc!=SQLITE_OK ) goto ismatch_out; sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); aIter[i].bFlag = (u8)bFlag; if( aIter[i].bEof ) goto ismatch_out; @@ -171845,12 +189125,6 @@ static int fts5LookaheadReaderInit( return fts5LookaheadReaderNext(p); } -#if 0 -static int fts5LookaheadReaderEof(Fts5LookaheadReader *p){ - return (p->iPos==FTS5_LOOKAHEAD_EOF); -} -#endif - typedef struct Fts5NearTrimmer Fts5NearTrimmer; struct Fts5NearTrimmer { Fts5LookaheadReader reader; /* Input iterator */ @@ -171888,7 +189162,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>(int)ArraySize(aStatic) ){ + if( pNear->nPhrase>ArraySize(aStatic) ){ int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); }else{ @@ -171965,6 +189239,327 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ } } +/* +** Advance iterator pIter until it points to a value equal to or laster +** than the initial value of *piLast. If this means the iterator points +** to a value laster than *piLast, update *piLast to the new lastest value. +** +** If the iterator reaches EOF, set *pbEof to true before returning. If +** an error occurs, set *pRc to an error code. If either *pbEof or *pRc +** are set, return a non-zero value. Otherwise, return zero. +*/ +static int fts5ExprAdvanceto( + Fts5IndexIter *pIter, /* Iterator to advance */ + int bDesc, /* True if iterator is "rowid DESC" */ + i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ + int *pRc, /* OUT: Error code */ + int *pbEof /* OUT: Set to true if EOF */ +){ + i64 iLast = *piLast; + i64 iRowid; + + iRowid = pIter->iRowid; + if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastiRowid; + assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) ); + } + *piLast = iRowid; + + return 0; +} + +static int fts5ExprSynonymAdvanceto( + Fts5ExprTerm *pTerm, /* Term iterator to advance */ + int bDesc, /* True if iterator is "rowid DESC" */ + i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ + int *pRc /* OUT: Error code */ +){ + int rc = SQLITE_OK; + i64 iLast = *piLast; + Fts5ExprTerm *p; + int bEof = 0; + + for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){ + if( sqlite3Fts5IterEof(p->pIter)==0 ){ + i64 iRowid = p->pIter->iRowid; + if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastpIter, iLast); + } + } + } + + if( rc!=SQLITE_OK ){ + *pRc = rc; + bEof = 1; + }else{ + *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof); + } + return bEof; +} + + +static int fts5ExprNearTest( + int *pRc, + Fts5Expr *pExpr, /* Expression that pNear is a part of */ + Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ +){ + Fts5ExprNearset *pNear = pNode->pNear; + int rc = *pRc; + + if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5ExprTerm *pTerm; + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + pPhrase->poslist.n = 0; + for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + Fts5IndexIter *pIter = pTerm->pIter; + if( sqlite3Fts5IterEof(pIter)==0 ){ + if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){ + pPhrase->poslist.n = 1; + } + } + } + return pPhrase->poslist.n; + }else{ + int i; + + /* Check that each phrase in the nearset matches the current row. + ** Populate the pPhrase->poslist buffers at the same time. If any + ** phrase is not a match, break out of the loop early. */ + for(i=0; rc==SQLITE_OK && inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ + int bMatch = 0; + rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch); + if( bMatch==0 ) break; + }else{ + Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; + fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData); + } + } + + *pRc = rc; + if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ + return 1; + } + return 0; + } +} + + +/* +** Initialize all term iterators in the pNear object. If any term is found +** to match no documents at all, return immediately without initializing any +** further iterators. +** +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. It is not considered an error if some term matches zero +** documents. +*/ +static int fts5ExprNearInitAll( + Fts5Expr *pExpr, + Fts5ExprNode *pNode +){ + Fts5ExprNearset *pNear = pNode->pNear; + int i; + + assert( pNode->bNomatch==0 ); + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + if( pPhrase->nTerm==0 ){ + pNode->bEof = 1; + return SQLITE_OK; + }else{ + int j; + for(j=0; jnTerm; j++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; + Fts5ExprTerm *p; + int bHit = 0; + + for(p=pTerm; p; p=p->pSynonym){ + int rc; + if( p->pIter ){ + sqlite3Fts5IterClose(p->pIter); + p->pIter = 0; + } + rc = sqlite3Fts5IndexQuery( + pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), + (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | + (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), + pNear->pColset, + &p->pIter + ); + assert( (rc==SQLITE_OK)==(p->pIter!=0) ); + if( rc!=SQLITE_OK ) return rc; + if( 0==sqlite3Fts5IterEof(p->pIter) ){ + bHit = 1; + } + } + + if( bHit==0 ){ + pNode->bEof = 1; + return SQLITE_OK; + } + } + } + } + + pNode->bEof = 0; + return SQLITE_OK; +} + +/* +** If pExpr is an ASC iterator, this function returns a value with the +** same sign as: +** +** (iLhs - iRhs) +** +** Otherwise, if this is a DESC iterator, the opposite is returned: +** +** (iRhs - iLhs) +*/ +static int fts5RowidCmp( + Fts5Expr *pExpr, + i64 iLhs, + i64 iRhs +){ + assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); + if( pExpr->bDesc==0 ){ + if( iLhs iRhs); + }else{ + if( iLhs>iRhs ) return -1; + return (iLhs < iRhs); + } +} + +static void fts5ExprSetEof(Fts5ExprNode *pNode){ + int i; + pNode->bEof = 1; + pNode->bNomatch = 0; + for(i=0; inChild; i++){ + fts5ExprSetEof(pNode->apChild[i]); + } +} + +static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ + if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pNode->pNear; + int i; + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + pPhrase->poslist.n = 0; + } + }else{ + int i; + for(i=0; inChild; i++){ + fts5ExprNodeZeroPoslist(pNode->apChild[i]); + } + } +} + + + +/* +** Compare the values currently indicated by the two nodes as follows: +** +** res = (*p1) - (*p2) +** +** Nodes that point to values that come later in the iteration order are +** considered to be larger. Nodes at EOF are the largest of all. +** +** This means that if the iteration order is ASC, then numerically larger +** rowids are considered larger. Or if it is the default DESC, numerically +** smaller rowids are larger. +*/ +static int fts5NodeCompare( + Fts5Expr *pExpr, + Fts5ExprNode *p1, + Fts5ExprNode *p2 +){ + if( p2->bEof ) return -1; + if( p1->bEof ) return +1; + return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid); +} + +/* +** All individual term iterators in pNear are guaranteed to be valid when +** this function is called. This function checks if all term iterators +** point to the same rowid, and if not, advances them until they do. +** If an EOF is reached before this happens, *pbEof is set to true before +** returning. +** +** SQLITE_OK is returned if an error occurs, or an SQLite error code +** otherwise. It is not considered an error code if an iterator reaches +** EOF. +*/ +static int fts5ExprNodeTest_STRING( + Fts5Expr *pExpr, /* Expression pPhrase belongs to */ + Fts5ExprNode *pNode +){ + Fts5ExprNearset *pNear = pNode->pNear; + Fts5ExprPhrase *pLeft = pNear->apPhrase[0]; + int rc = SQLITE_OK; + i64 iLast; /* Lastest rowid any iterator points to */ + int i, j; /* Phrase and token index, respectively */ + int bMatch; /* True if all terms are at the same rowid */ + const int bDesc = pExpr->bDesc; + + /* Check that this node should not be FTS5_TERM */ + assert( pNear->nPhrase>1 + || pNear->apPhrase[0]->nTerm>1 + || pNear->apPhrase[0]->aTerm[0].pSynonym + ); + + /* Initialize iLast, the "lastest" rowid any iterator points to. If the + ** iterator skips through rowids in the default ascending order, this means + ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it + ** means the minimum rowid. */ + if( pLeft->aTerm[0].pSynonym ){ + iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0); + }else{ + iLast = pLeft->aTerm[0].pIter->iRowid; + } + + do { + bMatch = 1; + for(i=0; inPhrase; i++){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; + for(j=0; jnTerm; j++){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; + if( pTerm->pSynonym ){ + i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0); + if( iRowid==iLast ) continue; + bMatch = 0; + if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){ + pNode->bNomatch = 0; + pNode->bEof = 1; + return rc; + } + }else{ + Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; + if( pIter->iRowid==iLast || pIter->bEof ) continue; + bMatch = 0; + if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ + return rc; + } + } + } + } + }while( bMatch==0 ); + + pNode->iRowid = iLast; + pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK); + assert( pNode->bEof==0 || pNode->bNomatch==0 ); + + return rc; +} + /* ** Advance the first term iterator in the first phrase of pNear. Set output ** variable *pbEof to true if it reaches EOF or if an error occurs. @@ -171972,7 +189567,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ ** Return SQLITE_OK if successful, or an SQLite error code if an error ** occurs. */ -static int fts5ExprNearAdvanceFirst( +static int fts5ExprNodeNext_STRING( Fts5Expr *pExpr, /* Expression pPhrase belongs to */ Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */ int bFromValid, @@ -171981,6 +189576,7 @@ static int fts5ExprNearAdvanceFirst( Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0]; int rc = SQLITE_OK; + pNode->bNomatch = 0; if( pTerm->pSynonym ){ int bEof = 1; Fts5ExprTerm *p; @@ -171992,7 +189588,7 @@ static int fts5ExprNearAdvanceFirst( ** is valid - each iterator that points to a rowid before iFrom. */ for(p=pTerm; p; p=p->pSynonym){ if( sqlite3Fts5IterEof(p->pIter)==0 ){ - i64 ii = sqlite3Fts5IterRowid(p->pIter); + i64 ii = p->pIter->iRowid; if( ii==iRowid || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) ){ @@ -172027,108 +189623,16 @@ static int fts5ExprNearAdvanceFirst( pNode->bEof = (rc || sqlite3Fts5IterEof(pIter)); } + if( pNode->bEof==0 ){ + assert( rc==SQLITE_OK ); + rc = fts5ExprNodeTest_STRING(pExpr, pNode); + } + return rc; } -/* -** Advance iterator pIter until it points to a value equal to or laster -** than the initial value of *piLast. If this means the iterator points -** to a value laster than *piLast, update *piLast to the new lastest value. -** -** If the iterator reaches EOF, set *pbEof to true before returning. If -** an error occurs, set *pRc to an error code. If either *pbEof or *pRc -** are set, return a non-zero value. Otherwise, return zero. -*/ -static int fts5ExprAdvanceto( - Fts5IndexIter *pIter, /* Iterator to advance */ - int bDesc, /* True if iterator is "rowid DESC" */ - i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ - int *pRc, /* OUT: Error code */ - int *pbEof /* OUT: Set to true if EOF */ -){ - i64 iLast = *piLast; - i64 iRowid; - iRowid = sqlite3Fts5IterRowid(pIter); - if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast=iLast) || (bDesc==1 && iRowid<=iLast) ); - } - *piLast = iRowid; - - return 0; -} - -static int fts5ExprSynonymAdvanceto( - Fts5ExprTerm *pTerm, /* Term iterator to advance */ - int bDesc, /* True if iterator is "rowid DESC" */ - i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ - int *pRc /* OUT: Error code */ -){ - int rc = SQLITE_OK; - i64 iLast = *piLast; - Fts5ExprTerm *p; - int bEof = 0; - - for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){ - if( sqlite3Fts5IterEof(p->pIter)==0 ){ - i64 iRowid = sqlite3Fts5IterRowid(p->pIter); - if( (bDesc==0 && iLast>iRowid) || (bDesc && iLastpIter, iLast); - } - } - } - - if( rc!=SQLITE_OK ){ - *pRc = rc; - bEof = 1; - }else{ - *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof); - } - return bEof; -} - - -static int fts5ExprNearTest( - int *pRc, - Fts5Expr *pExpr, /* Expression that pNear is a part of */ - Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ -){ - Fts5ExprNearset *pNear = pNode->pNear; - int rc = *pRc; - int i; - - /* Check that each phrase in the nearset matches the current row. - ** Populate the pPhrase->poslist buffers at the same time. If any - ** phrase is not a match, break out of the loop early. */ - for(i=0; rc==SQLITE_OK && inPhrase; i++){ - Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; - if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ - int bMatch = 0; - rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch); - if( bMatch==0 ) break; - }else{ - rc = sqlite3Fts5IterPoslistBuffer( - pPhrase->aTerm[0].pIter, &pPhrase->poslist - ); - } - } - - *pRc = rc; - if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ - return 1; - } - - return 0; -} - -static int fts5ExprTokenTest( +static int fts5ExprNodeTest_TERM( Fts5Expr *pExpr, /* Expression that pNear is a part of */ Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ ){ @@ -172137,203 +189641,101 @@ static int fts5ExprTokenTest( ** fts5_index.c iterator object. This is much faster than synthesizing ** a new poslist the way we have to for more complicated phrase or NEAR ** expressions. */ - Fts5ExprNearset *pNear = pNode->pNear; - Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0]; Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; - Fts5Colset *pColset = pNear->pColset; - int rc; assert( pNode->eType==FTS5_TERM ); - assert( pNear->nPhrase==1 && pPhrase->nTerm==1 ); + assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 ); assert( pPhrase->aTerm[0].pSynonym==0 ); - rc = sqlite3Fts5IterPoslist(pIter, pColset, - (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid - ); + pPhrase->poslist.n = pIter->nData; + if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){ + pPhrase->poslist.p = (u8*)pIter->pData; + } + pNode->iRowid = pIter->iRowid; pNode->bNomatch = (pPhrase->poslist.n==0); - return rc; + return SQLITE_OK; } /* -** All individual term iterators in pNear are guaranteed to be valid when -** this function is called. This function checks if all term iterators -** point to the same rowid, and if not, advances them until they do. -** If an EOF is reached before this happens, *pbEof is set to true before -** returning. -** -** SQLITE_OK is returned if an error occurs, or an SQLite error code -** otherwise. It is not considered an error code if an iterator reaches -** EOF. +** xNext() method for a node of type FTS5_TERM. */ -static int fts5ExprNearNextMatch( - Fts5Expr *pExpr, /* Expression pPhrase belongs to */ - Fts5ExprNode *pNode +static int fts5ExprNodeNext_TERM( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom ){ - Fts5ExprNearset *pNear = pNode->pNear; - Fts5ExprPhrase *pLeft = pNear->apPhrase[0]; - int rc = SQLITE_OK; - i64 iLast; /* Lastest rowid any iterator points to */ - int i, j; /* Phrase and token index, respectively */ - int bMatch; /* True if all terms are at the same rowid */ - const int bDesc = pExpr->bDesc; + int rc; + Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter; - /* Check that this node should not be FTS5_TERM */ - assert( pNear->nPhrase>1 - || pNear->apPhrase[0]->nTerm>1 - || pNear->apPhrase[0]->aTerm[0].pSynonym - ); - - /* Initialize iLast, the "lastest" rowid any iterator points to. If the - ** iterator skips through rowids in the default ascending order, this means - ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it - ** means the minimum rowid. */ - if( pLeft->aTerm[0].pSynonym ){ - iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0); + assert( pNode->bEof==0 ); + if( bFromValid ){ + rc = sqlite3Fts5IterNextFrom(pIter, iFrom); }else{ - iLast = sqlite3Fts5IterRowid(pLeft->aTerm[0].pIter); + rc = sqlite3Fts5IterNext(pIter); } - - do { - bMatch = 1; - for(i=0; inPhrase; i++){ - Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; - for(j=0; jnTerm; j++){ - Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; - if( pTerm->pSynonym ){ - i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0); - if( iRowid==iLast ) continue; - bMatch = 0; - if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){ - pNode->bEof = 1; - return rc; - } - }else{ - Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; - i64 iRowid = sqlite3Fts5IterRowid(pIter); - if( iRowid==iLast ) continue; - bMatch = 0; - if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ - return rc; - } - } - } - } - }while( bMatch==0 ); - - pNode->iRowid = iLast; - pNode->bNomatch = (0==fts5ExprNearTest(&rc, pExpr, pNode)); - - return rc; -} - -/* -** Initialize all term iterators in the pNear object. If any term is found -** to match no documents at all, return immediately without initializing any -** further iterators. -*/ -static int fts5ExprNearInitAll( - Fts5Expr *pExpr, - Fts5ExprNode *pNode -){ - Fts5ExprNearset *pNear = pNode->pNear; - int i, j; - int rc = SQLITE_OK; - - for(i=0; rc==SQLITE_OK && inPhrase; i++){ - Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; - for(j=0; jnTerm; j++){ - Fts5ExprTerm *pTerm = &pPhrase->aTerm[j]; - Fts5ExprTerm *p; - int bEof = 1; - - for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){ - if( p->pIter ){ - sqlite3Fts5IterClose(p->pIter); - p->pIter = 0; - } - rc = sqlite3Fts5IndexQuery( - pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), - (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | - (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), - pNear->pColset, - &p->pIter - ); - assert( rc==SQLITE_OK || p->pIter==0 ); - if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){ - bEof = 0; - } - } - - if( bEof ){ - pNode->bEof = 1; - return rc; - } - } - } - - return rc; -} - -/* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */ -static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*); - - -/* -** If pExpr is an ASC iterator, this function returns a value with the -** same sign as: -** -** (iLhs - iRhs) -** -** Otherwise, if this is a DESC iterator, the opposite is returned: -** -** (iRhs - iLhs) -*/ -static int fts5RowidCmp( - Fts5Expr *pExpr, - i64 iLhs, - i64 iRhs -){ - assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); - if( pExpr->bDesc==0 ){ - if( iLhs iRhs); + if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){ + rc = fts5ExprNodeTest_TERM(pExpr, pNode); }else{ - if( iLhs>iRhs ) return -1; - return (iLhs < iRhs); + pNode->bEof = 1; + pNode->bNomatch = 0; } + return rc; } -static void fts5ExprSetEof(Fts5ExprNode *pNode){ +static void fts5ExprNodeTest_OR( + Fts5Expr *pExpr, /* Expression of which pNode is a part */ + Fts5ExprNode *pNode /* Expression node to test */ +){ + Fts5ExprNode *pNext = pNode->apChild[0]; int i; - pNode->bEof = 1; + + for(i=1; inChild; i++){ + Fts5ExprNode *pChild = pNode->apChild[i]; + int cmp = fts5NodeCompare(pExpr, pNext, pChild); + if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){ + pNext = pChild; + } + } + pNode->iRowid = pNext->iRowid; + pNode->bEof = pNext->bEof; + pNode->bNomatch = pNext->bNomatch; +} + +static int fts5ExprNodeNext_OR( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int i; + i64 iLast = pNode->iRowid; + for(i=0; inChild; i++){ - fts5ExprSetEof(pNode->apChild[i]); - } -} - -static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ - if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ - Fts5ExprNearset *pNear = pNode->pNear; - int i; - for(i=0; inPhrase; i++){ - Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; - pPhrase->poslist.n = 0; - } - }else{ - int i; - for(i=0; inChild; i++){ - fts5ExprNodeZeroPoslist(pNode->apChild[i]); + Fts5ExprNode *p1 = pNode->apChild[i]; + assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); + if( p1->bEof==0 ){ + if( (p1->iRowid==iLast) + || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) + ){ + int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); + if( rc!=SQLITE_OK ){ + pNode->bNomatch = 0; + return rc; + } + } } } + + fts5ExprNodeTest_OR(pExpr, pNode); + return SQLITE_OK; } - -static int fts5ExprNodeNext(Fts5Expr*, Fts5ExprNode*, int, i64); - /* ** Argument pNode is an FTS5_AND node. */ -static int fts5ExprAndNextRowid( +static int fts5ExprNodeTest_AND( Fts5Expr *pExpr, /* Expression pPhrase belongs to */ Fts5ExprNode *pAnd /* FTS5_AND node to advance */ ){ @@ -172348,14 +189750,13 @@ static int fts5ExprAndNextRowid( bMatch = 1; for(iChild=0; iChildnChild; iChild++){ Fts5ExprNode *pChild = pAnd->apChild[iChild]; - if( 0 && pChild->eType==FTS5_STRING ){ - /* TODO */ - }else{ - int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid); - if( cmp>0 ){ - /* Advance pChild until it points to iLast or laster */ - rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); - if( rc!=SQLITE_OK ) return rc; + int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid); + if( cmp>0 ){ + /* Advance pChild until it points to iLast or laster */ + rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); + if( rc!=SQLITE_OK ){ + pAnd->bNomatch = 0; + return rc; } } @@ -172386,126 +189787,71 @@ static int fts5ExprAndNextRowid( return SQLITE_OK; } - -/* -** Compare the values currently indicated by the two nodes as follows: -** -** res = (*p1) - (*p2) -** -** Nodes that point to values that come later in the iteration order are -** considered to be larger. Nodes at EOF are the largest of all. -** -** This means that if the iteration order is ASC, then numerically larger -** rowids are considered larger. Or if it is the default DESC, numerically -** smaller rowids are larger. -*/ -static int fts5NodeCompare( - Fts5Expr *pExpr, - Fts5ExprNode *p1, - Fts5ExprNode *p2 -){ - if( p2->bEof ) return -1; - if( p1->bEof ) return +1; - return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid); -} - -/* -** Advance node iterator pNode, part of expression pExpr. If argument -** bFromValid is zero, then pNode is advanced exactly once. Or, if argument -** bFromValid is non-zero, then pNode is advanced until it is at or past -** rowid value iFrom. Whether "past" means "less than" or "greater than" -** depends on whether this is an ASC or DESC iterator. -*/ -static int fts5ExprNodeNext( +static int fts5ExprNodeNext_AND( Fts5Expr *pExpr, Fts5ExprNode *pNode, int bFromValid, i64 iFrom ){ - int rc = SQLITE_OK; - - if( pNode->bEof==0 ){ - switch( pNode->eType ){ - case FTS5_STRING: { - rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom); - break; - }; - - case FTS5_TERM: { - Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter; - if( bFromValid ){ - rc = sqlite3Fts5IterNextFrom(pIter, iFrom); - }else{ - rc = sqlite3Fts5IterNext(pIter); - } - if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){ - assert( rc==SQLITE_OK ); - rc = fts5ExprTokenTest(pExpr, pNode); - }else{ - pNode->bEof = 1; - } - return rc; - }; - - case FTS5_AND: { - Fts5ExprNode *pLeft = pNode->apChild[0]; - rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom); - break; - } - - case FTS5_OR: { - int i; - i64 iLast = pNode->iRowid; - - for(i=0; rc==SQLITE_OK && inChild; i++){ - Fts5ExprNode *p1 = pNode->apChild[i]; - assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); - if( p1->bEof==0 ){ - if( (p1->iRowid==iLast) - || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) - ){ - rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); - } - } - } - - break; - } - - default: assert( pNode->eType==FTS5_NOT ); { - assert( pNode->nChild==2 ); - rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); - break; - } - } - - if( rc==SQLITE_OK ){ - rc = fts5ExprNodeNextMatch(pExpr, pNode); - } + int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest_AND(pExpr, pNode); + }else{ + pNode->bNomatch = 0; } - - /* Assert that if bFromValid was true, either: - ** - ** a) an error occurred, or - ** b) the node is now at EOF, or - ** c) the node is now at or past rowid iFrom. - */ - assert( bFromValid==0 - || rc!=SQLITE_OK /* a */ - || pNode->bEof /* b */ - || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowidapChild[0]; + Fts5ExprNode *p2 = pNode->apChild[1]; + assert( pNode->nChild==2 ); + + while( rc==SQLITE_OK && p1->bEof==0 ){ + int cmp = fts5NodeCompare(pExpr, p1, p2); + if( cmp>0 ){ + rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid); + cmp = fts5NodeCompare(pExpr, p1, p2); + } + assert( rc!=SQLITE_OK || cmp<=0 ); + if( cmp || p2->bNomatch ) break; + rc = fts5ExprNodeNext(pExpr, p1, 0, 0); + } + pNode->bEof = p1->bEof; + pNode->bNomatch = p1->bNomatch; + pNode->iRowid = p1->iRowid; + if( p1->bEof ){ + fts5ExprNodeZeroPoslist(p2); + } + return rc; +} + +static int fts5ExprNodeNext_NOT( + Fts5Expr *pExpr, + Fts5ExprNode *pNode, + int bFromValid, + i64 iFrom +){ + int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeTest_NOT(pExpr, pNode); + } + if( rc!=SQLITE_OK ){ + pNode->bNomatch = 0; + } + return rc; +} /* ** If pNode currently points to a match, this function returns SQLITE_OK ** without modifying it. Otherwise, pNode is advanced until it does point ** to a match or EOF is reached. */ -static int fts5ExprNodeNextMatch( +static int fts5ExprNodeTest( Fts5Expr *pExpr, /* Expression of which pNode is a part */ Fts5ExprNode *pNode /* Expression node to test */ ){ @@ -172514,55 +189860,27 @@ static int fts5ExprNodeNextMatch( switch( pNode->eType ){ case FTS5_STRING: { - /* Advance the iterators until they all point to the same rowid */ - rc = fts5ExprNearNextMatch(pExpr, pNode); + rc = fts5ExprNodeTest_STRING(pExpr, pNode); break; } case FTS5_TERM: { - rc = fts5ExprTokenTest(pExpr, pNode); + rc = fts5ExprNodeTest_TERM(pExpr, pNode); break; } case FTS5_AND: { - rc = fts5ExprAndNextRowid(pExpr, pNode); + rc = fts5ExprNodeTest_AND(pExpr, pNode); break; } case FTS5_OR: { - Fts5ExprNode *pNext = pNode->apChild[0]; - int i; - - for(i=1; inChild; i++){ - Fts5ExprNode *pChild = pNode->apChild[i]; - int cmp = fts5NodeCompare(pExpr, pNext, pChild); - if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){ - pNext = pChild; - } - } - pNode->iRowid = pNext->iRowid; - pNode->bEof = pNext->bEof; - pNode->bNomatch = pNext->bNomatch; + fts5ExprNodeTest_OR(pExpr, pNode); break; } default: assert( pNode->eType==FTS5_NOT ); { - Fts5ExprNode *p1 = pNode->apChild[0]; - Fts5ExprNode *p2 = pNode->apChild[1]; - assert( pNode->nChild==2 ); - - while( rc==SQLITE_OK && p1->bEof==0 ){ - int cmp = fts5NodeCompare(pExpr, p1, p2); - if( cmp>0 ){ - rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid); - cmp = fts5NodeCompare(pExpr, p1, p2); - } - assert( rc!=SQLITE_OK || cmp<=0 ); - if( cmp || p2->bNomatch ) break; - rc = fts5ExprNodeNext(pExpr, p1, 0, 0); - } - pNode->bEof = p1->bEof; - pNode->iRowid = p1->iRowid; + rc = fts5ExprNodeTest_NOT(pExpr, pNode); break; } } @@ -172581,20 +189899,42 @@ static int fts5ExprNodeNextMatch( static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ int rc = SQLITE_OK; pNode->bEof = 0; + pNode->bNomatch = 0; if( Fts5NodeIsString(pNode) ){ /* Initialize all term iterators in the NEAR object. */ rc = fts5ExprNearInitAll(pExpr, pNode); + }else if( pNode->xNext==0 ){ + pNode->bEof = 1; }else{ int i; + int nEof = 0; for(i=0; inChild && rc==SQLITE_OK; i++){ + Fts5ExprNode *pChild = pNode->apChild[i]; rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]); + assert( pChild->bEof==0 || pChild->bEof==1 ); + nEof += pChild->bEof; } pNode->iRowid = pNode->apChild[0]->iRowid; + + switch( pNode->eType ){ + case FTS5_AND: + if( nEof>0 ) fts5ExprSetEof(pNode); + break; + + case FTS5_OR: + if( pNode->nChild==nEof ) fts5ExprSetEof(pNode); + break; + + default: + assert( pNode->eType==FTS5_NOT ); + pNode->bEof = pNode->apChild[0]->bEof; + break; + } } if( rc==SQLITE_OK ){ - rc = fts5ExprNodeNextMatch(pExpr, pNode); + rc = fts5ExprNodeTest(pExpr, pNode); } return rc; } @@ -172617,22 +189957,25 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ */ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){ Fts5ExprNode *pRoot = p->pRoot; - int rc = SQLITE_OK; - if( pRoot ){ - p->pIndex = pIdx; - p->bDesc = bDesc; - rc = fts5ExprNodeFirst(p, pRoot); + int rc; /* Return code */ - /* If not at EOF but the current rowid occurs earlier than iFirst in - ** the iteration order, move to document iFirst or later. */ - if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ - rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); - } + p->pIndex = pIdx; + p->bDesc = bDesc; + rc = fts5ExprNodeFirst(p, pRoot); - /* If the iterator is not at a real match, skip forward until it is. */ - while( pRoot->bNomatch && rc==SQLITE_OK && pRoot->bEof==0 ){ - rc = fts5ExprNodeNext(p, pRoot, 0, 0); - } + /* If not at EOF but the current rowid occurs earlier than iFirst in + ** the iteration order, move to document iFirst or later. */ + if( rc==SQLITE_OK + && 0==pRoot->bEof + && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 + ){ + rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); + } + + /* If the iterator is not at a real match, skip forward until it is. */ + while( pRoot->bNomatch ){ + assert( pRoot->bEof==0 && rc==SQLITE_OK ); + rc = fts5ExprNodeNext(p, pRoot, 0, 0); } return rc; } @@ -172646,9 +189989,11 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){ int rc; Fts5ExprNode *pRoot = p->pRoot; + assert( pRoot->bEof==0 && pRoot->bNomatch==0 ); do { rc = fts5ExprNodeNext(p, pRoot, 0, 0); - }while( pRoot->bNomatch && pRoot->bEof==0 && rc==SQLITE_OK ); + assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) ); + }while( pRoot->bNomatch ); if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){ pRoot->bEof = 1; } @@ -172656,7 +190001,7 @@ static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){ } static int sqlite3Fts5ExprEof(Fts5Expr *p){ - return (p->pRoot==0 || p->pRoot->bEof); + return p->pRoot->bEof; } static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){ @@ -172681,10 +190026,10 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; sqlite3_free(pTerm->zTerm); sqlite3Fts5IterClose(pTerm->pIter); - for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ pNext = pSyn->pSynonym; sqlite3Fts5IterClose(pSyn->pIter); + fts5BufferFree((Fts5Buffer*)&pSyn[1]); sqlite3_free(pSyn); } } @@ -172739,6 +190084,21 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( sqlite3Fts5ParseNearsetFree(pNear); sqlite3Fts5ParsePhraseFree(pPhrase); }else{ + if( pRet->nPhrase>0 ){ + Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1]; + assert( pLast==pParse->apPhrase[pParse->nPhrase-2] ); + if( pPhrase->nTerm==0 ){ + fts5ExprPhraseFree(pPhrase); + pRet->nPhrase--; + pParse->nPhrase--; + pPhrase = pLast; + }else if( pLast->nTerm==0 ){ + fts5ExprPhraseFree(pLast); + pParse->apPhrase[pParse->nPhrase-2] = pPhrase; + pParse->nPhrase--; + pRet->nPhrase--; + } + } pRet->apPhrase[pRet->nPhrase++] = pPhrase; } return pRet; @@ -172766,19 +190126,21 @@ static int fts5ParseTokenize( TokenCtx *pCtx = (TokenCtx*)pContext; Fts5ExprPhrase *pPhrase = pCtx->pPhrase; + UNUSED_PARAM2(iUnused1, iUnused2); + /* If an error has already occurred, this is a no-op */ if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; - assert( pPhrase==0 || pPhrase->nTerm>0 ); - if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){ + if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ Fts5ExprTerm *pSyn; - int nByte = sizeof(Fts5ExprTerm) + nToken+1; + int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ memset(pSyn, 0, nByte); - pSyn->zTerm = (char*)&pSyn[1]; + pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; @@ -172860,7 +190222,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( rc = fts5ParseStringFromToken(pToken, &z); if( rc==SQLITE_OK ){ - int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0); + int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0); int n; sqlite3Fts5Dequote(z); n = (int)strlen(z); @@ -172871,7 +190233,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( pParse->rc = rc; fts5ExprPhraseFree(sCtx.pPhrase); sCtx.pPhrase = 0; - }else if( sCtx.pPhrase ){ + }else{ if( pAppend==0 ){ if( (pParse->nPhrase % 8)==0 ){ @@ -172888,9 +190250,14 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( pParse->nPhrase++; } + if( sCtx.pPhrase==0 ){ + /* This happens when parsing a token or quoted phrase that contains + ** no token characters at all. (e.g ... MATCH '""'). */ + sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); + }else if( sCtx.pPhrase->nTerm ){ + sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; + } pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; - assert( sCtx.pPhrase->nTerm>0 ); - sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; } return sCtx.pPhrase; @@ -172901,22 +190268,16 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( ** expression passed as the second argument. */ static int sqlite3Fts5ExprClonePhrase( - Fts5Config *pConfig, Fts5Expr *pExpr, int iPhrase, Fts5Expr **ppNew ){ int rc = SQLITE_OK; /* Return code */ Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ - int i; /* Used to iterate through phrase terms */ - Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ - TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ - pOrig = pExpr->apExprPhrase[iPhrase]; - pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); if( rc==SQLITE_OK ){ pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, @@ -172930,24 +190291,43 @@ static int sqlite3Fts5ExprClonePhrase( pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } + 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); + if( pColset ){ + memcpy(pColset, pColsetOrig, nByte); + } + pNew->pRoot->pNear->pColset = pColset; + } + } - for(i=0; rc==SQLITE_OK && inTerm; i++){ - int tflags = 0; - Fts5ExprTerm *p; - for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ - const char *zTerm = p->zTerm; - rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), - 0, 0); - tflags = FTS5_TOKEN_COLOCATED; - } - if( rc==SQLITE_OK ){ - sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; + if( pOrig->nTerm ){ + int i; /* Used to iterate through phrase terms */ + for(i=0; rc==SQLITE_OK && inTerm; i++){ + int tflags = 0; + Fts5ExprTerm *p; + for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ + const char *zTerm = p->zTerm; + rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), + 0, 0); + tflags = FTS5_TOKEN_COLOCATED; + } + if( rc==SQLITE_OK ){ + sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; + } } + }else{ + /* This happens when parsing a token or quoted phrase that contains + ** no token characters at all. (e.g ... MATCH '""'). */ + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } if( rc==SQLITE_OK ){ /* All the allocations succeeded. Put the expression object together. */ pNew->pIndex = pExpr->pIndex; + pNew->pConfig = pExpr->pConfig; pNew->nPhrase = 1; pNew->apExprPhrase[0] = sCtx.pPhrase; pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; @@ -172956,8 +190336,10 @@ static int sqlite3Fts5ExprClonePhrase( if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){ pNew->pRoot->eType = FTS5_TERM; + pNew->pRoot->xNext = fts5ExprNodeNext_TERM; }else{ pNew->pRoot->eType = FTS5_STRING; + pNew->pRoot->xNext = fts5ExprNodeNext_STRING; } }else{ sqlite3Fts5ExprFree(pNew); @@ -172988,23 +190370,25 @@ static void sqlite3Fts5ParseSetDistance( Fts5ExprNearset *pNear, Fts5Token *p ){ - int nNear = 0; - int i; - if( p->n ){ - for(i=0; in; i++){ - char c = (char)p->p[i]; - if( c<'0' || c>'9' ){ - sqlite3Fts5ParseError( - pParse, "expected integer, got \"%.*s\"", p->n, p->p - ); - return; + if( pNear ){ + int nNear = 0; + int i; + if( p->n ){ + for(i=0; in; i++){ + char c = (char)p->p[i]; + if( c<'0' || c>'9' ){ + sqlite3Fts5ParseError( + pParse, "expected integer, got \"%.*s\"", p->n, p->p + ); + return; + } + nNear = nNear * 10 + (p->p[i] - '0'); } - nNear = nNear * 10 + (p->p[i] - '0'); + }else{ + nNear = FTS5_DEFAULT_NEARDIST; } - }else{ - nNear = FTS5_DEFAULT_NEARDIST; + pNear->nNear = nNear; } - pNear->nNear = nNear; } /* @@ -173052,6 +190436,34 @@ static Fts5Colset *fts5ParseColset( return pNew; } +/* +** Allocate and return an Fts5Colset object specifying the inverse of +** the colset passed as the second argument. Free the colset passed +** as the second argument before returning. +*/ +static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){ + Fts5Colset *pRet; + int nCol = pParse->pConfig->nCol; + + pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, + sizeof(Fts5Colset) + sizeof(int)*nCol + ); + if( pRet ){ + int i; + int iOld = 0; + for(i=0; i=p->nCol || p->aiCol[iOld]!=i ){ + pRet->aiCol[pRet->nCol++] = i; + }else{ + iOld++; + } + } + } + + sqlite3_free(p); + return pRet; +} + static Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *pColset, /* Existing colset object */ @@ -173084,15 +190496,141 @@ static Fts5Colset *sqlite3Fts5ParseColset( return pRet; } +/* +** If argument pOrig is NULL, or if (*pRc) is set to anything other than +** SQLITE_OK when this function is called, NULL is returned. +** +** Otherwise, a copy of (*pOrig) is made into memory obtained from +** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation +** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned. +*/ +static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ + Fts5Colset *pRet; + if( pOrig ){ + int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); + pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); + if( pRet ){ + memcpy(pRet, pOrig, nByte); + } + }else{ + pRet = 0; + } + return pRet; +} + +/* +** Remove from colset pColset any columns that are not also in colset pMerge. +*/ +static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){ + int iIn = 0; /* Next input in pColset */ + int iMerge = 0; /* Next input in pMerge */ + int iOut = 0; /* Next output slot in pColset */ + + while( iInnCol && iMergenCol ){ + int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge]; + if( iDiff==0 ){ + pColset->aiCol[iOut++] = pMerge->aiCol[iMerge]; + iMerge++; + iIn++; + }else if( iDiff>0 ){ + iMerge++; + }else{ + iIn++; + } + } + pColset->nCol = iOut; +} + +/* +** Recursively apply colset pColset to expression node pNode and all of +** its decendents. If (*ppFree) is not NULL, it contains a spare copy +** of pColset. This function may use the spare copy and set (*ppFree) to +** zero, or it may create copies of pColset using fts5CloneColset(). +*/ +static void fts5ParseSetColset( + Fts5Parse *pParse, + Fts5ExprNode *pNode, + Fts5Colset *pColset, + Fts5Colset **ppFree +){ + if( pParse->rc==SQLITE_OK ){ + assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING + || pNode->eType==FTS5_AND || pNode->eType==FTS5_OR + || pNode->eType==FTS5_NOT || pNode->eType==FTS5_EOF + ); + if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pNode->pNear; + if( pNear->pColset ){ + fts5MergeColset(pNear->pColset, pColset); + if( pNear->pColset->nCol==0 ){ + pNode->eType = FTS5_EOF; + pNode->xNext = 0; + } + }else if( *ppFree ){ + pNear->pColset = pColset; + *ppFree = 0; + }else{ + pNear->pColset = fts5CloneColset(&pParse->rc, pColset); + } + }else{ + int i; + assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 ); + for(i=0; inChild; i++){ + fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree); + } + } + } +} + +/* +** Apply colset pColset to expression node pExpr and all of its descendents. +*/ static void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, - Fts5ExprNearset *pNear, + Fts5ExprNode *pExpr, Fts5Colset *pColset ){ - if( pNear ){ - pNear->pColset = pColset; + Fts5Colset *pFree = pColset; + if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ + pParse->rc = SQLITE_ERROR; + pParse->zErr = sqlite3_mprintf( + "fts5: column queries are not supported (detail=none)" + ); }else{ - sqlite3_free(pColset); + fts5ParseSetColset(pParse, pExpr, pColset, &pFree); + } + sqlite3_free(pFree); +} + +static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ + switch( pNode->eType ){ + case FTS5_STRING: { + Fts5ExprNearset *pNear = pNode->pNear; + if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 + && pNear->apPhrase[0]->aTerm[0].pSynonym==0 + ){ + pNode->eType = FTS5_TERM; + pNode->xNext = fts5ExprNodeNext_TERM; + }else{ + pNode->xNext = fts5ExprNodeNext_STRING; + } + break; + }; + + case FTS5_OR: { + pNode->xNext = fts5ExprNodeNext_OR; + break; + }; + + case FTS5_AND: { + pNode->xNext = fts5ExprNodeNext_AND; + break; + }; + + default: assert( pNode->eType==FTS5_NOT ); { + pNode->xNext = fts5ExprNodeNext_NOT; + break; + }; } } @@ -173145,17 +190683,31 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( pRet ){ pRet->eType = eType; pRet->pNear = pNear; + fts5ExprAssignXNext(pRet); if( eType==FTS5_STRING ){ int iPhrase; for(iPhrase=0; iPhrasenPhrase; iPhrase++){ pNear->apPhrase[iPhrase]->pNode = pRet; + if( pNear->apPhrase[iPhrase]->nTerm==0 ){ + pRet->xNext = 0; + pRet->eType = FTS5_EOF; + } } - if( pNear->nPhrase==1 - && pNear->apPhrase[0]->nTerm==1 - && pNear->apPhrase[0]->aTerm[0].pSynonym==0 + + if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL + && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1) ){ - pRet->eType = FTS5_TERM; + assert( pParse->rc==SQLITE_OK ); + pParse->rc = SQLITE_ERROR; + assert( pParse->zErr==0 ); + pParse->zErr = sqlite3_mprintf( + "fts5: %s queries are not supported (detail!=full)", + pNear->nPhrase==1 ? "phrase": "NEAR" + ); + sqlite3_free(pRet); + pRet = 0; } + }else{ fts5ExprAddChildren(pRet, pLeft); fts5ExprAddChildren(pRet, pRight); @@ -173172,6 +190724,70 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( return pRet; } +static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( + Fts5Parse *pParse, /* Parse context */ + Fts5ExprNode *pLeft, /* Left hand child expression */ + Fts5ExprNode *pRight /* Right hand child expression */ +){ + Fts5ExprNode *pRet = 0; + Fts5ExprNode *pPrev; + + if( pParse->rc ){ + sqlite3Fts5ParseNodeFree(pLeft); + sqlite3Fts5ParseNodeFree(pRight); + }else{ + + assert( pLeft->eType==FTS5_STRING + || pLeft->eType==FTS5_TERM + || pLeft->eType==FTS5_EOF + || pLeft->eType==FTS5_AND + ); + assert( pRight->eType==FTS5_STRING + || pRight->eType==FTS5_TERM + || pRight->eType==FTS5_EOF + ); + + if( pLeft->eType==FTS5_AND ){ + pPrev = pLeft->apChild[pLeft->nChild-1]; + }else{ + pPrev = pLeft; + } + assert( pPrev->eType==FTS5_STRING + || pPrev->eType==FTS5_TERM + || pPrev->eType==FTS5_EOF + ); + + if( pRight->eType==FTS5_EOF ){ + assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); + sqlite3Fts5ParseNodeFree(pRight); + pRet = pLeft; + pParse->nPhrase--; + } + else if( pPrev->eType==FTS5_EOF ){ + Fts5ExprPhrase **ap; + + if( pPrev==pLeft ){ + pRet = pRight; + }else{ + pLeft->apChild[pLeft->nChild-1] = pRight; + pRet = pLeft; + } + + ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase]; + assert( ap[0]==pPrev->pNear->apPhrase[0] ); + memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase); + pParse->nPhrase--; + + sqlite3Fts5ParseNodeFree(pPrev); + } + else{ + pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); + } + } + + return pRet; +} + static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ int nByte = 0; Fts5ExprTerm *p; @@ -173268,6 +190884,9 @@ static char *fts5ExprPrintTcl( for(iTerm=0; zRet && iTermnTerm; iTerm++){ char *zTerm = pPhrase->aTerm[iTerm].zTerm; zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); + if( pPhrase->aTerm[iTerm].bPrefix ){ + zRet = fts5PrintfAppend(zRet, "*"); + } } if( zRet ) zRet = fts5PrintfAppend(zRet, "}"); @@ -173303,6 +190922,9 @@ static char *fts5ExprPrintTcl( static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ char *zRet = 0; + if( pExpr->eType==0 ){ + return sqlite3_mprintf("\"\""); + }else if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; int i; @@ -173363,7 +190985,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ zRet = 0; }else{ int e = pExpr->apChild[i]->eType; - int b = (e!=FTS5_STRING && e!=FTS5_TERM); + int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF); zRet = fts5PrintfAppend(zRet, "%s%s%z%s", (i==0 ? "" : zOp), (b?"(":""), z, (b?")":"") @@ -173431,11 +191053,11 @@ static void fts5ExprFunction( rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr); + rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr); } if( rc==SQLITE_OK ){ char *zText; - if( pExpr->pRoot==0 ){ + if( pExpr->pRoot->xNext==0 ){ zText = sqlite3_mprintf(""); }else if( bTcl ){ zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot); @@ -173535,7 +191157,7 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ int rc = SQLITE_OK; void *pCtx = (void*)pGlobal; - for(i=0; rc==SQLITE_OK && i<(int)ArraySize(aFunc); i++){ + for(i=0; rc==SQLITE_OK && iz, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } @@ -173581,6 +191203,215 @@ static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){ return nRet; } +struct Fts5PoslistPopulator { + Fts5PoslistWriter writer; + int bOk; /* True if ok to populate */ + int bMiss; +}; + +static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ + Fts5PoslistPopulator *pRet; + pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + if( pRet ){ + int i; + memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + for(i=0; inPhrase; i++){ + Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; + assert( pExpr->apExprPhrase[i]->nTerm==1 ); + if( bLive && + (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) + ){ + pRet[i].bMiss = 1; + }else{ + pBuf->n = 0; + } + } + } + return pRet; +} + +struct Fts5ExprCtx { + Fts5Expr *pExpr; + Fts5PoslistPopulator *aPopulator; + i64 iOff; +}; +typedef struct Fts5ExprCtx Fts5ExprCtx; + +/* +** TODO: Make this more efficient! +*/ +static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + +static int fts5ExprPopulatePoslistsCb( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iUnused1, /* Byte offset of token within input text */ + int iUnused2 /* Byte offset of end of token within input text */ +){ + Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx; + Fts5Expr *pExpr = p->pExpr; + int i; + + UNUSED_PARAM2(iUnused1, iUnused2); + + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; + for(i=0; inPhrase; i++){ + Fts5ExprTerm *pTerm; + if( p->aPopulator[i].bOk==0 ) continue; + for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + int nTerm = (int)strlen(pTerm->zTerm); + if( (nTerm==nToken || (nTermbPrefix)) + && memcmp(pTerm->zTerm, pToken, nTerm)==0 + ){ + int rc = sqlite3Fts5PoslistWriterAppend( + &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff + ); + if( rc ) return rc; + break; + } + } + } + return SQLITE_OK; +} + +static int sqlite3Fts5ExprPopulatePoslists( + Fts5Config *pConfig, + Fts5Expr *pExpr, + Fts5PoslistPopulator *aPopulator, + int iCol, + const char *z, int n +){ + int i; + Fts5ExprCtx sCtx; + sCtx.pExpr = pExpr; + sCtx.aPopulator = aPopulator; + sCtx.iOff = (((i64)iCol) << 32) - 1; + + for(i=0; inPhrase; i++){ + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; + Fts5Colset *pColset = pNode->pNear->pColset; + if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) + || aPopulator[i].bMiss + ){ + aPopulator[i].bOk = 0; + }else{ + aPopulator[i].bOk = 1; + } + } + + return sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb + ); +} + +static void fts5ExprClearPoslists(Fts5ExprNode *pNode){ + if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){ + pNode->pNear->apPhrase[0]->poslist.n = 0; + }else{ + int i; + for(i=0; inChild; i++){ + fts5ExprClearPoslists(pNode->apChild[i]); + } + } +} + +static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ + pNode->iRowid = iRowid; + pNode->bEof = 0; + switch( pNode->eType ){ + case FTS5_TERM: + case FTS5_STRING: + return (pNode->pNear->apPhrase[0]->poslist.n>0); + + case FTS5_AND: { + int i; + for(i=0; inChild; i++){ + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){ + fts5ExprClearPoslists(pNode); + return 0; + } + } + break; + } + + case FTS5_OR: { + int i; + int bRet = 0; + for(i=0; inChild; i++){ + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){ + bRet = 1; + } + } + return bRet; + } + + default: { + assert( pNode->eType==FTS5_NOT ); + if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid) + || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid) + ){ + fts5ExprClearPoslists(pNode); + return 0; + } + break; + } + } + return 1; +} + +static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ + fts5ExprCheckPoslists(pExpr->pRoot, iRowid); +} + +/* +** This function is only called for detail=columns tables. +*/ +static int sqlite3Fts5ExprPhraseCollist( + Fts5Expr *pExpr, + int iPhrase, + const u8 **ppCollist, + int *pnCollist +){ + Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; + Fts5ExprNode *pNode = pPhrase->pNode; + int rc = SQLITE_OK; + + assert( iPhrase>=0 && iPhrasenPhrase ); + assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + + if( pNode->bEof==0 + && pNode->iRowid==pExpr->pRoot->iRowid + && pPhrase->poslist.n>0 + ){ + Fts5ExprTerm *pTerm = &pPhrase->aTerm[0]; + if( pTerm->pSynonym ){ + Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1]; + rc = fts5ExprSynonymList( + pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist + ); + }else{ + *ppCollist = pPhrase->aTerm[0].pIter->pData; + *pnCollist = pPhrase->aTerm[0].pIter->nData; + } + }else{ + *ppCollist = 0; + *pnCollist = 0; + } + + return rc; +} + + /* ** 2014 August 11 ** @@ -173609,6 +191440,7 @@ typedef struct Fts5HashEntry Fts5HashEntry; struct Fts5Hash { + int eDetail; /* Copy of Fts5Config.eDetail */ int *pnByte; /* Pointer to bytes counter */ int nEntry; /* Number of entries currently in hash */ int nSlot; /* Size of aSlot[] array */ @@ -173618,9 +191450,10 @@ struct Fts5Hash { /* ** Each entry in the hash table is represented by an object of the -** following type. Each object, its key (zKey[]) and its current data -** are stored in a single memory allocation. The position list data -** immediately follows the key data in memory. +** following type. Each object, its key (a nul-terminated string) and +** its current data are stored in a single memory allocation. The +** key immediately follows the object in memory. The position list +** data immediately follows the key data in memory. ** ** The data that follows the key is in a similar, but not identical format ** to the doclist data stored in the database. It is: @@ -173644,25 +191477,26 @@ struct Fts5HashEntry { int nAlloc; /* Total size of allocation */ int iSzPoslist; /* Offset of space for 4-byte poslist size */ int nData; /* Total bytes of data (incl. structure) */ + int nKey; /* Length of key in bytes */ u8 bDel; /* Set delete-flag @ iSzPoslist */ - - int iCol; /* Column of last value written */ + u8 bContent; /* Set content-flag (detail=none mode) */ + i16 iCol; /* Column of last value written */ int iPos; /* Position of last value written */ i64 iRowid; /* Rowid of last value written */ - char zKey[8]; /* Nul-terminated entry key */ }; /* -** Size of Fts5HashEntry without the zKey[] array. +** Eqivalent to: +** +** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; } */ -#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8) - +#define fts5EntryKey(p) ( ((char *)(&(p)[1])) ) /* ** Allocate a new hash table. */ -static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ +static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ int rc = SQLITE_OK; Fts5Hash *pNew; @@ -173673,6 +191507,7 @@ static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ int nByte; memset(pNew, 0, sizeof(Fts5Hash)); pNew->pnByte = pnByte; + pNew->eDetail = pConfig->eDetail; pNew->nSlot = 1024; nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; @@ -173750,10 +191585,11 @@ static int fts5HashResize(Fts5Hash *pHash){ for(i=0; inSlot; i++){ while( apOld[i] ){ - int iHash; + unsigned int iHash; Fts5HashEntry *p = apOld[i]; apOld[i] = p->pHashNext; - iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey)); + iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), + (int)strlen(fts5EntryKey(p))); p->pHashNext = apNew[iHash]; apNew[iHash] = p; } @@ -173765,26 +191601,46 @@ static int fts5HashResize(Fts5Hash *pHash){ return SQLITE_OK; } -static void fts5HashAddPoslistSize(Fts5HashEntry *p){ +static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ if( p->iSzPoslist ){ u8 *pPtr = (u8*)p; - int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ - int nPos = nSz*2 + p->bDel; /* Value of nPos field */ - - assert( p->bDel==0 || p->bDel==1 ); - if( nPos<=127 ){ - pPtr[p->iSzPoslist] = (u8)nPos; + if( pHash->eDetail==FTS5_DETAIL_NONE ){ + assert( p->nData==p->iSzPoslist ); + if( p->bDel ){ + pPtr[p->nData++] = 0x00; + if( p->bContent ){ + pPtr[p->nData++] = 0x00; + } + } }else{ - int nByte = sqlite3Fts5GetVarintLen((u32)nPos); - memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); - sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); - p->nData += (nByte-1); + int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nPos = nSz*2 + p->bDel; /* Value of nPos field */ + + assert( p->bDel==0 || p->bDel==1 ); + if( nPos<=127 ){ + pPtr[p->iSzPoslist] = (u8)nPos; + }else{ + int nByte = sqlite3Fts5GetVarintLen((u32)nPos); + memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); + sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); + p->nData += (nByte-1); + } } - p->bDel = 0; + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; } } +/* +** Add an entry to the in-memory hash table. The key is the concatenation +** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). +** +** (bByte || pToken) -> (iRowid,iCol,iPos) +** +** Or, if iCol is negative, then the value is a delete marker. +*/ static int sqlite3Fts5HashWrite( Fts5Hash *pHash, i64 iRowid, /* Rowid for this entry */ @@ -173797,13 +191653,17 @@ static int sqlite3Fts5HashWrite( Fts5HashEntry *p; u8 *pPtr; int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ + int bNew; /* If non-delete entry should be written */ + + bNew = (pHash->eDetail==FTS5_DETAIL_FULL); /* Attempt to locate an existing hash entry */ iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ - if( p->zKey[0]==bByte - && memcmp(&p->zKey[1], pToken, nToken)==0 - && p->zKey[nToken+1]==0 + char *zKey = fts5EntryKey(p); + if( zKey[0]==bByte + && p->nKey==nToken + && memcmp(&zKey[1], pToken, nToken)==0 ){ break; } @@ -173811,88 +191671,119 @@ static int sqlite3Fts5HashWrite( /* If an existing hash entry cannot be found, create a new one. */ if( p==0 ){ - int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; + /* Figure out how much space to allocate */ + char *zKey; + int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64; if( nByte<128 ) nByte = 128; + /* Grow the Fts5Hash.aSlot[] array if necessary. */ if( (pHash->nEntry*2)>=pHash->nSlot ){ int rc = fts5HashResize(pHash); if( rc!=SQLITE_OK ) return rc; iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); } + /* Allocate new Fts5HashEntry and add it to the hash table. */ p = (Fts5HashEntry*)sqlite3_malloc(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, FTS5_HASHENTRYSIZE); + memset(p, 0, sizeof(Fts5HashEntry)); p->nAlloc = nByte; - p->zKey[0] = bByte; - memcpy(&p->zKey[1], pToken, nToken); - assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); - p->zKey[nToken+1] = '\0'; - p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; - p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); - p->iSzPoslist = p->nData; - p->nData += 1; - p->iRowid = iRowid; + zKey = fts5EntryKey(p); + zKey[0] = bByte; + memcpy(&zKey[1], pToken, nToken); + assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); + p->nKey = nToken; + zKey[nToken+1] = '\0'; + p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry); p->pHashNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; - nIncr += p->nData; - } - /* Check there is enough space to append a new entry. Worst case scenario - ** is: - ** - ** + 9 bytes for a new rowid, - ** + 4 byte reserved for the "poslist size" varint. - ** + 1 byte for a "new column" byte, - ** + 3 bytes for a new column number (16-bit max) as a varint, - ** + 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; - Fts5HashEntry *pNew; - Fts5HashEntry **pp; - pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); - if( pNew==0 ) return SQLITE_NOMEM; - pNew->nAlloc = nNew; - for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); - *pp = pNew; - p = pNew; + /* Add the first rowid field to the hash-entry */ + p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); + p->iRowid = iRowid; + + p->iSzPoslist = p->nData; + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ + p->nData += 1; + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); + } + + nIncr += p->nData; + }else{ + + /* Appending to an existing hash-entry. Check that there is enough + ** space to append the largest possible new entry. Worst case scenario + ** is: + ** + ** + 9 bytes for a new rowid, + ** + 4 byte reserved for the "poslist size" varint. + ** + 1 byte for a "new column" byte, + ** + 3 bytes for a new column number (16-bit max) as a varint, + ** + 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; + Fts5HashEntry *pNew; + Fts5HashEntry **pp; + pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->nAlloc = nNew; + for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); + *pp = pNew; + p = pNew; + } + nIncr -= p->nData; } + assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); + pPtr = (u8*)p; - nIncr -= p->nData; /* 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(p); + fts5HashAddPoslistSize(pHash, p); p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); - p->iSzPoslist = p->nData; - p->nData += 1; - p->iCol = 0; - p->iPos = 0; p->iRowid = iRowid; + bNew = 1; + p->iSzPoslist = p->nData; + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ + p->nData += 1; + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); + p->iPos = 0; + } } if( iCol>=0 ){ - /* Append a new column value, if necessary */ - assert( iCol>=p->iCol ); - if( iCol!=p->iCol ){ - pPtr[p->nData++] = 0x01; - p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); - p->iCol = iCol; - p->iPos = 0; - } + if( pHash->eDetail==FTS5_DETAIL_NONE ){ + p->bContent = 1; + }else{ + /* Append a new column value, if necessary */ + assert( iCol>=p->iCol ); + if( iCol!=p->iCol ){ + if( pHash->eDetail==FTS5_DETAIL_FULL ){ + pPtr[p->nData++] = 0x01; + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); + p->iCol = (i16)iCol; + p->iPos = 0; + }else{ + bNew = 1; + p->iCol = (i16)(iPos = iCol); + } + } - /* Append the new position offset */ - p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); - p->iPos = iPos; + /* Append the new position offset, if necessary */ + if( bNew ){ + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); + p->iPos = iPos; + } + } }else{ /* This is a delete. Set the delete flag. */ p->bDel = 1; } - nIncr += p->nData; + nIncr += p->nData; *pHash->pnByte += nIncr; return SQLITE_OK; } @@ -173921,9 +191812,11 @@ static Fts5HashEntry *fts5HashEntryMerge( p1 = 0; }else{ int i = 0; - while( p1->zKey[i]==p2->zKey[i] ) i++; + char *zKey1 = fts5EntryKey(p1); + char *zKey2 = fts5EntryKey(p2); + while( zKey1[i]==zKey2[i] ) i++; - if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){ + if( ((u8)zKey1[i])>((u8)zKey2[i]) ){ /* p2 is smaller */ *ppOut = p2; ppOut = &p2->pScanNext; @@ -173966,7 +191859,7 @@ static int fts5HashEntrySort( for(iSlot=0; iSlotnSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ - if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){ + if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ @@ -173999,16 +191892,18 @@ static int sqlite3Fts5HashQuery( int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); + char *zKey = 0; Fts5HashEntry *p; for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ - if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; + zKey = fts5EntryKey(p); + if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break; } if( p ){ - fts5HashAddPoslistSize(p); - *ppDoclist = (const u8*)&p->zKey[nTerm+1]; - *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + fts5HashAddPoslistSize(pHash, p); + *ppDoclist = (const u8*)&zKey[nTerm+1]; + *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *ppDoclist = 0; *pnDoclist = 0; @@ -174041,11 +191936,12 @@ static void sqlite3Fts5HashScanEntry( ){ Fts5HashEntry *p; if( (p = pHash->pScan) ){ - int nTerm = (int)strlen(p->zKey); - fts5HashAddPoslistSize(p); - *pzTerm = p->zKey; - *ppDoclist = (const u8*)&p->zKey[nTerm+1]; - *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + char *zKey = fts5EntryKey(p); + int nTerm = (int)strlen(zKey); + fts5HashAddPoslistSize(pHash, p); + *pzTerm = zKey; + *ppDoclist = (const u8*)&zKey[nTerm+1]; + *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *pzTerm = 0; *ppDoclist = 0; @@ -174317,6 +192213,7 @@ typedef struct Fts5Data Fts5Data; typedef struct Fts5DlidxIter Fts5DlidxIter; typedef struct Fts5DlidxLvl Fts5DlidxLvl; typedef struct Fts5DlidxWriter Fts5DlidxWriter; +typedef struct Fts5Iter Fts5Iter; typedef struct Fts5PageWriter Fts5PageWriter; typedef struct Fts5SegIter Fts5SegIter; typedef struct Fts5DoclistIter Fts5DoclistIter; @@ -174359,6 +192256,10 @@ struct Fts5Index { sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */ sqlite3_stmt *pIdxSelect; int nRead; /* Total number of blocks read */ + + sqlite3_stmt *pDataVersion; + i64 iStructVersion; /* data_version when pStruct read */ + Fts5Structure *pStruct; /* Current db structure (or NULL) */ }; struct Fts5DoclistIter { @@ -174489,6 +192390,9 @@ struct Fts5SegIter { Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ int iLeafOffset; /* Byte offset within current leaf */ + /* Next method */ + void (*xNext)(Fts5Index*, Fts5SegIter*, int*); + /* The page and offset from which the current term was read. The offset ** is the offset of the first rowid in the current doclist. */ int iTermLeafPgno; @@ -174508,7 +192412,7 @@ struct Fts5SegIter { Fts5Buffer term; /* Current term */ i64 iRowid; /* Current rowid */ int nPos; /* Number of bytes in current position list */ - int bDel; /* True if the delete flag is set */ + u8 bDel; /* True if the delete flag is set */ }; /* @@ -174522,7 +192426,6 @@ struct Fts5SegIter { #define FTS5_SEGITER_ONETERM 0x01 #define FTS5_SEGITER_REVERSE 0x02 - /* ** Argument is a pointer to an Fts5Data structure that contains a leaf ** page. This macro evaluates to true if the leaf contains no terms, or @@ -174557,16 +192460,20 @@ struct Fts5SegIter { ** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. ** There is no way to tell if this is populated or not. */ -struct Fts5IndexIter { +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 */ + + /* Invoked to set output variables. */ + void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*); int nSeg; /* Size of aSeg[] array */ int bRev; /* True to iterate in reverse order */ u8 bSkipEmpty; /* True to skip deleted entries */ - u8 bEof; /* True at EOF */ - u8 bFiltered; /* True if column-filter already applied */ i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ @@ -174656,17 +192563,6 @@ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ return (res==0 ? (pLeft->n - pRight->n) : res); } -#ifdef SQLITE_DEBUG -static int fts5BlobCompare( - const u8 *pLeft, int nLeft, - const u8 *pRight, int nRight -){ - int nCmp = MIN(nLeft, nRight); - int res = memcmp(pLeft, pRight, nCmp); - return (res==0 ? (nLeft - nRight) : res); -} -#endif - static int fts5LeafFirstTermOff(Fts5Data *pLeaf){ int ret; fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret); @@ -174684,7 +192580,6 @@ static void fts5CloseReader(Fts5Index *p){ } } - /* ** Retrieve a record from the %_data table. ** @@ -174766,6 +192661,18 @@ static void fts5DataRelease(Fts5Data *pData){ sqlite3_free(pData); } +static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ + Fts5Data *pRet = fts5DataRead(p, iRowid); + if( pRet ){ + if( pRet->szLeaf>pRet->nn ){ + p->rc = FTS5_CORRUPT; + fts5DataRelease(pRet); + pRet = 0; + } + } + return pRet; +} + static int fts5IndexPrepareStmt( Fts5Index *p, sqlite3_stmt **ppStmt, @@ -174773,7 +192680,8 @@ static int fts5IndexPrepareStmt( ){ if( p->rc==SQLITE_OK ){ if( zSql ){ - p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0); + p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, ppStmt, 0); }else{ p->rc = SQLITE_NOMEM; } @@ -174822,7 +192730,8 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0); sqlite3_free(zSql); } if( rc!=SQLITE_OK ){ @@ -174925,28 +192834,37 @@ static int fts5StructureDecode( for(iLvl=0; rc==SQLITE_OK && iLvlaLevel[iLvl]; - int nTotal; + int nTotal = 0; int iSeg; - i += fts5GetVarint32(&pData[i], pLvl->nMerge); - i += fts5GetVarint32(&pData[i], nTotal); - assert( nTotal>=pLvl->nMerge ); - pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, - nTotal * sizeof(Fts5StructureSegment) - ); + if( i>=nData ){ + rc = FTS5_CORRUPT; + }else{ + i += fts5GetVarint32(&pData[i], pLvl->nMerge); + i += fts5GetVarint32(&pData[i], nTotal); + assert( nTotal>=pLvl->nMerge ); + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, + nTotal * sizeof(Fts5StructureSegment) + ); + } if( rc==SQLITE_OK ){ pLvl->nSeg = nTotal; for(iSeg=0; iSeg=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); } - }else{ - fts5StructureRelease(pRet); - pRet = 0; } } + if( rc!=SQLITE_OK ){ + fts5StructureRelease(pRet); + pRet = 0; + } } *ppOut = pRet; @@ -175009,6 +192927,50 @@ static void fts5StructureExtendLevel( } } +static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){ + Fts5Structure *pRet = 0; + Fts5Config *pConfig = p->pConfig; + int iCookie; /* Configuration cookie */ + Fts5Data *pData; + + pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); + if( p->rc==SQLITE_OK ){ + /* 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 ){ + p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); + } + fts5DataRelease(pData); + if( p->rc!=SQLITE_OK ){ + fts5StructureRelease(pRet); + pRet = 0; + } + } + + return pRet; +} + +static i64 fts5IndexDataVersion(Fts5Index *p){ + i64 iVersion = 0; + + if( p->rc==SQLITE_OK ){ + if( p->pDataVersion==0 ){ + p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, + sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb) + ); + if( p->rc ) return 0; + } + + if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){ + iVersion = sqlite3_column_int64(p->pDataVersion, 0); + } + p->rc = sqlite3_reset(p->pDataVersion); + } + + return iVersion; +} + /* ** Read, deserialize and return the structure record. ** @@ -175021,26 +192983,49 @@ static void fts5StructureExtendLevel( ** is called, it is a no-op. */ static Fts5Structure *fts5StructureRead(Fts5Index *p){ - Fts5Config *pConfig = p->pConfig; - Fts5Structure *pRet = 0; /* Object to return */ - int iCookie; /* Configuration cookie */ - Fts5Data *pData; - pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); - if( p->rc ) return 0; - /* 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 ){ - p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); + if( p->pStruct==0 ){ + p->iStructVersion = fts5IndexDataVersion(p); + if( p->rc==SQLITE_OK ){ + p->pStruct = fts5StructureReadUncached(p); + } } - fts5DataRelease(pData); - if( p->rc!=SQLITE_OK ){ - fts5StructureRelease(pRet); - pRet = 0; +#if 0 + else{ + Fts5Structure *pTest = fts5StructureReadUncached(p); + if( pTest ){ + int i, j; + assert_nc( p->pStruct->nSegment==pTest->nSegment ); + assert_nc( p->pStruct->nLevel==pTest->nLevel ); + for(i=0; inLevel; i++){ + assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge ); + assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg ); + for(j=0; jaLevel[i].nSeg; j++){ + Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j]; + Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j]; + assert_nc( p1->iSegid==p2->iSegid ); + assert_nc( p1->pgnoFirst==p2->pgnoFirst ); + assert_nc( p1->pgnoLast==p2->pgnoLast ); + } + } + fts5StructureRelease(pTest); + } + } +#endif + + if( p->rc!=SQLITE_OK ) return 0; + assert( p->iStructVersion!=0 ); + assert( p->pStruct!=0 ); + fts5StructureRef(p->pStruct); + return p->pStruct; +} + +static void fts5StructureInvalidate(Fts5Index *p){ + if( p->pStruct ){ + fts5StructureRelease(p->pStruct); + p->pStruct = 0; } - return pRet; } /* @@ -175498,7 +193483,7 @@ static void fts5SegIterNextPage( pIter->pLeaf = pIter->pNextLeaf; pIter->pNextLeaf = 0; }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){ - pIter->pLeaf = fts5DataRead(p, + pIter->pLeaf = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno) ); }else{ @@ -175548,13 +193533,29 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){ static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ if( p->rc==SQLITE_OK ){ int iOff = pIter->iLeafOffset; /* Offset to read at */ - int nSz; ASSERT_SZLEAF_OK(pIter->pLeaf); - fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz); - pIter->bDel = (nSz & 0x0001); - pIter->nPos = nSz>>1; + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf); + pIter->bDel = 0; + pIter->nPos = 1; + if( iOffpLeaf->p[iOff]==0 ){ + pIter->bDel = 1; + iOff++; + if( iOffpLeaf->p[iOff]==0 ){ + pIter->nPos = 1; + iOff++; + }else{ + pIter->nPos = 0; + } + } + }else{ + int nSz; + fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz); + pIter->bDel = (nSz & 0x0001); + pIter->nPos = nSz>>1; + assert_nc( pIter->nPos>=0 ); + } pIter->iLeafOffset = iOff; - assert_nc( pIter->nPos>=0 ); } } @@ -175597,6 +193598,10 @@ 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 ){ + p->rc = FTS5_CORRUPT; + return; + } pIter->term.n = nKeep; fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); iOff += nNew; @@ -175615,6 +193620,20 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ fts5SegIterLoadRowid(p, pIter); } +static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*); +static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*); +static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*); + +static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ + if( pIter->flags & FTS5_SEGITER_REVERSE ){ + pIter->xNext = fts5SegIterNext_Reverse; + }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + pIter->xNext = fts5SegIterNext_None; + }else{ + pIter->xNext = fts5SegIterNext; + } +} + /* ** Initialize the iterator object pIter to iterate through the entries in ** segment pSeg. The iterator is left pointing to the first entry when @@ -175640,6 +193659,7 @@ static void fts5SegIterInit( if( p->rc==SQLITE_OK ){ memset(pIter, 0, sizeof(*pIter)); + fts5SegIterSetNext(p, pIter); pIter->pSeg = pSeg; pIter->iLeafPgno = pSeg->pgnoFirst-1; fts5SegIterNextPage(p, pIter); @@ -175671,6 +193691,7 @@ static void fts5SegIterInit( ** byte of the position list content associated with said rowid. */ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ + int eDetail = p->pConfig->eDetail; int n = pIter->pLeaf->szLeaf; int i = pIter->iLeafOffset; u8 *a = pIter->pLeaf->p; @@ -175683,15 +193704,24 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ i64 iDelta = 0; - int nPos; - int bDummy; - i += fts5GetPoslistSize(&a[i], &nPos, &bDummy); - i += nPos; + if( eDetail==FTS5_DETAIL_NONE ){ + /* todo */ + if( i=n ) break; i += fts5GetVarint(&a[i], (u64*)&iDelta); pIter->iRowid += iDelta; + /* 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)); @@ -175765,11 +193795,115 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ ** points to a delete marker. A delete marker is an entry with a 0 byte ** position-list. */ -static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){ +static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0); } +/* +** Advance iterator pIter to the next entry. +** +** This version of fts5SegIterNext() is only used by reverse iterators. +*/ +static void fts5SegIterNext_Reverse( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbUnused /* Unused */ +){ + assert( pIter->flags & FTS5_SEGITER_REVERSE ); + assert( pIter->pNextLeaf==0 ); + UNUSED_PARAM(pbUnused); + + if( pIter->iRowidOffset>0 ){ + u8 *a = pIter->pLeaf->p; + int iOff; + i64 iDelta; + + pIter->iRowidOffset--; + pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; + fts5SegIterLoadNPos(p, pIter); + iOff = pIter->iLeafOffset; + if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ + iOff += pIter->nPos; + } + fts5GetVarint(&a[iOff], (u64*)&iDelta); + pIter->iRowid -= iDelta; + }else{ + fts5SegIterReverseNewPage(p, pIter); + } +} + +/* +** Advance iterator pIter to the next entry. +** +** This version of fts5SegIterNext() is only used if detail=none and the +** iterator is not a reverse direction iterator. +*/ +static void fts5SegIterNext_None( + Fts5Index *p, /* FTS5 backend object */ + Fts5SegIter *pIter, /* Iterator to advance */ + int *pbNewTerm /* OUT: Set for new term */ +){ + int iOff; + + assert( p->rc==SQLITE_OK ); + assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 ); + assert( p->pConfig->eDetail==FTS5_DETAIL_NONE ); + + ASSERT_SZLEAF_OK(pIter->pLeaf); + iOff = pIter->iLeafOffset; + + /* Next entry is on the next page */ + if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ + fts5SegIterNextPage(p, pIter); + if( p->rc || pIter->pLeaf==0 ) return; + pIter->iRowid = 0; + iOff = 4; + } + + if( iOffiEndofDoclist ){ + /* Next entry is on the current page */ + i64 iDelta; + iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta); + pIter->iLeafOffset = iOff; + pIter->iRowid += iDelta; + }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){ + if( pIter->pSeg ){ + int nKeep = 0; + if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){ + iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep); + } + pIter->iLeafOffset = iOff; + fts5SegIterLoadTerm(p, pIter, nKeep); + }else{ + const u8 *pList = 0; + const char *zTerm = 0; + int nList; + sqlite3Fts5HashScanNext(p->pHash); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); + if( pList==0 ) goto next_none_eof; + pIter->pLeaf->p = (u8*)pList; + pIter->pLeaf->nn = nList; + pIter->pLeaf->szLeaf = nList; + pIter->iEndofDoclist = nList; + sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); + } + + if( pbNewTerm ) *pbNewTerm = 1; + }else{ + goto next_none_eof; + } + + fts5SegIterLoadNPos(p, pIter); + + return; + next_none_eof: + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; +} + + /* ** Advance iterator pIter to the next entry. ** @@ -175782,141 +193916,132 @@ static void fts5SegIterNext( Fts5SegIter *pIter, /* Iterator to advance */ int *pbNewTerm /* OUT: Set for new term */ ){ - assert( pbNewTerm==0 || *pbNewTerm==0 ); - if( p->rc==SQLITE_OK ){ - if( pIter->flags & FTS5_SEGITER_REVERSE ){ - assert( pIter->pNextLeaf==0 ); - if( pIter->iRowidOffset>0 ){ - u8 *a = pIter->pLeaf->p; - int iOff; - int nPos; - int bDummy; - i64 iDelta; + Fts5Data *pLeaf = pIter->pLeaf; + int iOff; + int bNewTerm = 0; + int nKeep = 0; + u8 *a; + int n; - pIter->iRowidOffset--; - pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset]; - iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy); - iOff += nPos; - fts5GetVarint(&a[iOff], (u64*)&iDelta); - pIter->iRowid -= iDelta; - fts5SegIterLoadNPos(p, pIter); - }else{ - fts5SegIterReverseNewPage(p, pIter); + assert( pbNewTerm==0 || *pbNewTerm==0 ); + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); + + /* Search for the end of the position list within the current page. */ + a = pLeaf->p; + n = pLeaf->szLeaf; + + ASSERT_SZLEAF_OK(pLeaf); + iOff = pIter->iLeafOffset + pIter->nPos; + + if( iOffiEndofDoclist ); + if( iOff>=pIter->iEndofDoclist ){ + bNewTerm = 1; + if( iOff!=fts5LeafFirstTermOff(pLeaf) ){ + iOff += fts5GetVarint32(&a[iOff], nKeep); } }else{ - Fts5Data *pLeaf = pIter->pLeaf; - int iOff; - int bNewTerm = 0; - int nKeep = 0; - - /* Search for the end of the position list within the current page. */ - u8 *a = pLeaf->p; - int n = pLeaf->szLeaf; + u64 iDelta; + iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta); + pIter->iRowid += iDelta; + assert_nc( iDelta>0 ); + } + pIter->iLeafOffset = iOff; + }else if( pIter->pSeg==0 ){ + const u8 *pList = 0; + const char *zTerm = 0; + int nList = 0; + assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); + if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ + sqlite3Fts5HashScanNext(p->pHash); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); + } + if( pList==0 ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; + }else{ + pIter->pLeaf->p = (u8*)pList; + pIter->pLeaf->nn = nList; + pIter->pLeaf->szLeaf = nList; + pIter->iEndofDoclist = nList+1; + sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), + (u8*)zTerm); + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); + *pbNewTerm = 1; + } + }else{ + iOff = 0; + /* Next entry is not on the current page */ + while( iOff==0 ){ + fts5SegIterNextPage(p, pIter); + pLeaf = pIter->pLeaf; + if( pLeaf==0 ) break; ASSERT_SZLEAF_OK(pLeaf); - iOff = pIter->iLeafOffset + pIter->nPos; - - if( iOffiEndofDoclist ); - if( iOff>=pIter->iEndofDoclist ){ - bNewTerm = 1; - if( iOff!=fts5LeafFirstTermOff(pLeaf) ){ - iOff += fts5GetVarint32(&a[iOff], nKeep); - } - }else{ - u64 iDelta; - iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta); - pIter->iRowid += iDelta; - assert_nc( iDelta>0 ); - } + if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOffszLeaf ){ + iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid); pIter->iLeafOffset = iOff; - }else if( pIter->pSeg==0 ){ - const u8 *pList = 0; - const char *zTerm = 0; - int nList = 0; - assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); - if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ - sqlite3Fts5HashScanNext(p->pHash); - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); - } - if( pList==0 ){ - fts5DataRelease(pIter->pLeaf); - pIter->pLeaf = 0; - }else{ - pIter->pLeaf->p = (u8*)pList; - pIter->pLeaf->nn = nList; - pIter->pLeaf->szLeaf = nList; - pIter->iEndofDoclist = nList+1; - sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), - (u8*)zTerm); - pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); - *pbNewTerm = 1; + if( pLeaf->nn>pLeaf->szLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( + &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist + ); } + } + else if( pLeaf->nn>pLeaf->szLeaf ){ + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( + &pLeaf->p[pLeaf->szLeaf], iOff + ); + pIter->iLeafOffset = iOff; + pIter->iEndofDoclist = iOff; + bNewTerm = 1; + } + assert_nc( iOffszLeaf ); + if( iOff>pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } + } + } + + /* Check if the iterator is now at EOF. If so, return early. */ + if( pIter->pLeaf ){ + if( bNewTerm ){ + if( pIter->flags & FTS5_SEGITER_ONETERM ){ + fts5DataRelease(pIter->pLeaf); + pIter->pLeaf = 0; }else{ - iOff = 0; - /* Next entry is not on the current page */ - while( iOff==0 ){ - fts5SegIterNextPage(p, pIter); - pLeaf = pIter->pLeaf; - if( pLeaf==0 ) break; - ASSERT_SZLEAF_OK(pLeaf); - if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOffszLeaf ){ - iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid); - pIter->iLeafOffset = iOff; - - if( pLeaf->nn>pLeaf->szLeaf ){ - pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( - &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist - ); - } - - } - else if( pLeaf->nn>pLeaf->szLeaf ){ - pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( - &pLeaf->p[pLeaf->szLeaf], iOff - ); - pIter->iLeafOffset = iOff; - pIter->iEndofDoclist = iOff; - bNewTerm = 1; - } - if( iOff>=pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; - return; - } - } - } - - /* Check if the iterator is now at EOF. If so, return early. */ - if( pIter->pLeaf ){ - if( bNewTerm ){ - if( pIter->flags & FTS5_SEGITER_ONETERM ){ - fts5DataRelease(pIter->pLeaf); - pIter->pLeaf = 0; - }else{ - fts5SegIterLoadTerm(p, pIter, nKeep); - fts5SegIterLoadNPos(p, pIter); - if( pbNewTerm ) *pbNewTerm = 1; - } - }else{ - /* The following could be done by calling fts5SegIterLoadNPos(). But - ** this block is particularly performance critical, so equivalent - ** code is inlined. */ - int nSz; - assert( p->rc==SQLITE_OK ); - fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); - pIter->bDel = (nSz & 0x0001); - pIter->nPos = nSz>>1; - assert_nc( pIter->nPos>=0 ); - } + fts5SegIterLoadTerm(p, pIter, nKeep); + fts5SegIterLoadNPos(p, pIter); + if( pbNewTerm ) *pbNewTerm = 1; } + }else{ + /* The following could be done by calling fts5SegIterLoadNPos(). But + ** this block is particularly performance critical, so equivalent + ** code is inlined. + ** + ** Later: Switched back to fts5SegIterLoadNPos() because it supports + ** detail=none mode. Not ideal. + */ + int nSz; + assert( p->rc==SQLITE_OK ); + assert( pIter->iLeafOffset<=pIter->pLeaf->nn ); + fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); + pIter->bDel = (nSz & 0x0001); + pIter->nPos = nSz>>1; + assert_nc( pIter->nPos>=0 ); } } } #define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; } +#define fts5IndexSkipVarint(a, iOff) { \ + int iEnd = iOff+9; \ + while( (a[iOff++] & 0x80) && iOffiLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel); + int iPoslist; + if( pIter->iTermLeafPgno==pIter->iLeafPgno ){ + iPoslist = pIter->iTermLeafOffset; + }else{ + iPoslist = 4; + } + fts5IndexSkipVarint(pLeaf->p, iPoslist); + pIter->iLeafOffset = iPoslist; /* If this condition is true then the largest rowid for the current ** term may not be stored on the current page. So search forward to @@ -176021,11 +194153,6 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){ pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno); } -#define fts5IndexSkipVarint(a, iOff) { \ - int iEnd = iOff+9; \ - while( (a[iOff++] & 0x80) && iOffn ){ + p->rc = FTS5_CORRUPT; + return; + } while( 1 ){ @@ -176102,6 +194233,11 @@ static void fts5LeafSeek( iTermOff += nKeep; iOff = iTermOff; + if( iOff>=n ){ + p->rc = FTS5_CORRUPT; + return; + } + /* Read the nKeep field of the next term. */ fts5FastGetVarint32(a, iOff, nKeep); } @@ -176154,6 +194290,18 @@ static void fts5LeafSeek( fts5SegIterLoadNPos(p, pIter); } +static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){ + if( p->pIdxSelect==0 ){ + Fts5Config *pConfig = p->pConfig; + fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf( + "SELECT pgno FROM '%q'.'%q_idx' WHERE " + "segid=? AND term<=? ORDER BY term DESC LIMIT 1", + pConfig->zDb, pConfig->zName + )); + } + return p->pIdxSelect; +} + /* ** Initialize the object pIter to point to term pTerm/nTerm within segment ** pSeg. If there is no such term in the index, the iterator is set to EOF. @@ -176163,7 +194311,6 @@ static void fts5LeafSeek( */ static void fts5SegIterSeekInit( Fts5Index *p, /* FTS5 backend */ - Fts5Buffer *pBuf, /* Buffer to use for loading pages */ const u8 *pTerm, int nTerm, /* Term to seek to */ int flags, /* Mask of FTS5INDEX_XXX flags */ Fts5StructureSegment *pSeg, /* Description of segment */ @@ -176172,9 +194319,7 @@ static void fts5SegIterSeekInit( int iPg = 1; int bGe = (flags & FTS5INDEX_QUERY_SCAN); int bDlidx = 0; /* True if there is a doclist-index */ - - static int nCall = 0; - nCall++; + sqlite3_stmt *pIdxSelect = 0; assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 ); assert( pTerm && nTerm ); @@ -176183,23 +194328,16 @@ static void fts5SegIterSeekInit( /* This block sets stack variable iPg to the leaf page number that may ** contain term (pTerm/nTerm), if it is present in the segment. */ - if( p->pIdxSelect==0 ){ - Fts5Config *pConfig = p->pConfig; - fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf( - "SELECT pgno FROM '%q'.'%q_idx' WHERE " - "segid=? AND term<=? ORDER BY term DESC LIMIT 1", - pConfig->zDb, pConfig->zName - )); - } + pIdxSelect = fts5IdxSelectStmt(p); if( p->rc ) return; - sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid); - sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC); - if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){ - i64 val = sqlite3_column_int(p->pIdxSelect, 0); + sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid); + sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){ + i64 val = sqlite3_column_int(pIdxSelect, 0); iPg = (int)(val>>1); bDlidx = (val & 0x0001); } - p->rc = sqlite3_reset(p->pIdxSelect); + p->rc = sqlite3_reset(pIdxSelect); if( iPgpgnoFirst ){ iPg = pSeg->pgnoFirst; @@ -176228,6 +194366,8 @@ static void fts5SegIterSeekInit( } } + fts5SegIterSetNext(p, pIter); + /* Either: ** ** 1) an error has occurred, or @@ -176285,7 +194425,7 @@ static void fts5SegIterHashInit( pLeaf->nn = pLeaf->szLeaf = nList; pIter->pLeaf = pLeaf; pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); - pIter->iEndofDoclist = pLeaf->nn+1; + pIter->iEndofDoclist = pLeaf->nn; if( flags & FTS5INDEX_QUERY_DESC ){ pIter->flags |= FTS5_SEGITER_REVERSE; @@ -176294,6 +194434,8 @@ static void fts5SegIterHashInit( fts5SegIterLoadNPos(p, pIter); } } + + fts5SegIterSetNext(p, pIter); } /* @@ -176317,7 +194459,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){ ** two iterators. */ static void fts5AssertComparisonResult( - Fts5IndexIter *pIter, + Fts5Iter *pIter, Fts5SegIter *p1, Fts5SegIter *p2, Fts5CResult *pRes @@ -176358,12 +194500,12 @@ static void fts5AssertComparisonResult( ** statement used to verify that the contents of the pIter->aFirst[] array ** are correct. */ -static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){ +static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){ if( p->rc==SQLITE_OK ){ Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; int i; - assert( (pFirst->pLeaf==0)==pIter->bEof ); + assert( (pFirst->pLeaf==0)==pIter->base.bEof ); /* Check that pIter->iSwitchRowid is set correctly. */ for(i=0; inSeg; i++){ @@ -176403,7 +194545,7 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){ ** to a key that is a duplicate of another, higher priority, ** segment-iterator in the pSeg->aSeg[] array. */ -static int fts5MultiIterDoCompare(Fts5IndexIter *pIter, int iOut){ +static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ int i1; /* Index of left-hand Fts5SegIter */ int i2; /* Index of right-hand Fts5SegIter */ int iRes; @@ -176537,7 +194679,7 @@ static void fts5SegIterNextFrom( } do{ - if( bMove ) fts5SegIterNext(p, pIter, 0); + if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0); if( pIter->pLeaf==0 ) break; if( bRev==0 && pIter->iRowid>=iMatch ) break; if( bRev!=0 && pIter->iRowid<=iMatch ) break; @@ -176549,7 +194691,7 @@ static void fts5SegIterNextFrom( /* ** Free the iterator object passed as the second argument. */ -static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){ +static void fts5MultiIterFree(Fts5Iter *pIter){ if( pIter ){ int i; for(i=0; inSeg; i++){ @@ -176563,7 +194705,7 @@ static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){ static void fts5MultiIterAdvanced( Fts5Index *p, /* FTS5 backend to iterate within */ - Fts5IndexIter *pIter, /* Iterator to update aFirst[] array for */ + Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ int iChanged, /* Index of sub-iterator just advanced */ int iMinset /* Minimum entry in aFirst[] to set */ ){ @@ -176571,7 +194713,9 @@ static void fts5MultiIterAdvanced( for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){ int iEq; if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){ - fts5SegIterNext(p, &pIter->aSeg[iEq], 0); + Fts5SegIter *pSeg = &pIter->aSeg[iEq]; + assert( p->rc==SQLITE_OK ); + pSeg->xNext(p, pSeg, 0); i = pIter->nSeg + iEq; } } @@ -176588,9 +194732,9 @@ static void fts5MultiIterAdvanced( ** that it deals with more complicated cases as well. */ static int fts5MultiIterAdvanceRowid( - Fts5Index *p, /* FTS5 backend to iterate within */ - Fts5IndexIter *pIter, /* Iterator to update aFirst[] array for */ - int iChanged /* Index of sub-iterator just advanced */ + Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ + int iChanged, /* Index of sub-iterator just advanced */ + Fts5SegIter **ppFirst ){ Fts5SegIter *pNew = &pIter->aSeg[iChanged]; @@ -176623,15 +194767,16 @@ static int fts5MultiIterAdvanceRowid( } } + *ppFirst = pNew; return 0; } /* ** Set the pIter->bEof variable based on the state of the sub-iterators. */ -static void fts5MultiIterSetEof(Fts5IndexIter *pIter){ +static void fts5MultiIterSetEof(Fts5Iter *pIter){ Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; - pIter->bEof = pSeg->pLeaf==0; + pIter->base.bEof = pSeg->pLeaf==0; pIter->iSwitchRowid = pSeg->iRowid; } @@ -176644,57 +194789,63 @@ static void fts5MultiIterSetEof(Fts5IndexIter *pIter){ */ static void fts5MultiIterNext( Fts5Index *p, - Fts5IndexIter *pIter, + Fts5Iter *pIter, int bFrom, /* True if argument iFrom is valid */ i64 iFrom /* Advance at least as far as this */ ){ - if( p->rc==SQLITE_OK ){ - int bUseFrom = bFrom; - do { - int iFirst = pIter->aFirst[1].iFirst; - int bNewTerm = 0; - Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; - assert( p->rc==SQLITE_OK ); - if( bUseFrom && pSeg->pDlidx ){ - fts5SegIterNextFrom(p, pSeg, iFrom); - }else{ - fts5SegIterNext(p, pSeg, &bNewTerm); - } + int bUseFrom = bFrom; + assert( pIter->base.bEof==0 ); + while( p->rc==SQLITE_OK ){ + int iFirst = pIter->aFirst[1].iFirst; + int bNewTerm = 0; + Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; + assert( p->rc==SQLITE_OK ); + if( bUseFrom && pSeg->pDlidx ){ + fts5SegIterNextFrom(p, pSeg, iFrom); + }else{ + pSeg->xNext(p, pSeg, &bNewTerm); + } - if( pSeg->pLeaf==0 || bNewTerm - || fts5MultiIterAdvanceRowid(p, pIter, iFirst) - ){ - fts5MultiIterAdvanced(p, pIter, iFirst, 1); - fts5MultiIterSetEof(pIter); - } - fts5AssertMultiIterSetup(p, pIter); + if( pSeg->pLeaf==0 || bNewTerm + || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) + ){ + fts5MultiIterAdvanced(p, pIter, iFirst, 1); + fts5MultiIterSetEof(pIter); + pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; + if( pSeg->pLeaf==0 ) return; + } - bUseFrom = 0; - }while( pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter) ); + fts5AssertMultiIterSetup(p, pIter); + assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf ); + if( pIter->bSkipEmpty==0 || pSeg->nPos ){ + pIter->xSetOutputs(pIter, pSeg); + return; + } + bUseFrom = 0; } } static void fts5MultiIterNext2( Fts5Index *p, - Fts5IndexIter *pIter, + Fts5Iter *pIter, int *pbNewTerm /* OUT: True if *might* be new term */ ){ assert( pIter->bSkipEmpty ); if( p->rc==SQLITE_OK ){ - do { + *pbNewTerm = 0; + do{ int iFirst = pIter->aFirst[1].iFirst; Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; int bNewTerm = 0; - fts5SegIterNext(p, pSeg, &bNewTerm); + assert( p->rc==SQLITE_OK ); + pSeg->xNext(p, pSeg, &bNewTerm); if( pSeg->pLeaf==0 || bNewTerm - || fts5MultiIterAdvanceRowid(p, pIter, iFirst) + || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) ){ fts5MultiIterAdvanced(p, pIter, iFirst, 1); fts5MultiIterSetEof(pIter); *pbNewTerm = 1; - }else{ - *pbNewTerm = 0; } fts5AssertMultiIterSetup(p, pIter); @@ -176702,17 +194853,20 @@ static void fts5MultiIterNext2( } } +static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){ + UNUSED_PARAM2(pUnused1, pUnused2); +} -static Fts5IndexIter *fts5MultiIterAlloc( +static Fts5Iter *fts5MultiIterAlloc( Fts5Index *p, /* FTS5 backend to iterate within */ int nSeg ){ - Fts5IndexIter *pNew; + Fts5Iter *pNew; int nSlot; /* Power of two >= nSeg */ for(nSlot=2; nSlotaSeg[] */ sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ ); @@ -176720,12 +194874,434 @@ static Fts5IndexIter *fts5MultiIterAlloc( pNew->nSeg = nSlot; pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot]; pNew->pIndex = p; + pNew->xSetOutputs = fts5IterSetOutputs_Noop; } return pNew; } +static void fts5PoslistCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk); + } +} + +typedef struct PoslistCallbackCtx PoslistCallbackCtx; +struct PoslistCallbackCtx { + Fts5Buffer *pBuf; /* Append to this buffer */ + Fts5Colset *pColset; /* Restrict matches to this column */ + int eState; /* See above */ +}; + +typedef struct PoslistOffsetsCtx PoslistOffsetsCtx; +struct PoslistOffsetsCtx { + Fts5Buffer *pBuf; /* Append to this buffer */ + Fts5Colset *pColset; /* Restrict matches to this column */ + int iRead; + int iWrite; +}; + /* -** Allocate a new Fts5IndexIter object. +** TODO: Make this more efficient! +*/ +static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ + int i; + for(i=0; inCol; i++){ + if( pColset->aiCol[i]==iCol ) return 1; + } + return 0; +} + +static void fts5PoslistOffsetsCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext; + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + int i = 0; + while( iiRead - 2; + pCtx->iRead = iVal; + if( fts5IndexColsetTest(pCtx->pColset, iVal) ){ + fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite); + pCtx->iWrite = iVal; + } + } + } +} + +static void fts5PoslistFilterCallback( + Fts5Index *pUnused, + void *pContext, + const u8 *pChunk, int nChunk +){ + PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext; + UNUSED_PARAM(pUnused); + assert_nc( nChunk>=0 ); + if( nChunk>0 ){ + /* Search through to find the first varint with value 1. This is the + ** start of the next columns hits. */ + int i = 0; + int iStart = 0; + + if( pCtx->eState==2 ){ + int iCol; + fts5FastGetVarint32(pChunk, i, iCol); + if( fts5IndexColsetTest(pCtx->pColset, iCol) ){ + pCtx->eState = 1; + fts5BufferSafeAppendVarint(pCtx->pBuf, 1); + }else{ + pCtx->eState = 0; + } + } + + do { + while( ieState ){ + fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); + } + if( i=nChunk ){ + pCtx->eState = 2; + }else{ + fts5FastGetVarint32(pChunk, i, iCol); + pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol); + if( pCtx->eState ){ + fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); + iStart = i; + } + } + } + }while( inPos; /* Number of bytes still to come */ + Fts5Data *pData = 0; + u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); + int pgno = pSeg->iLeafPgno; + int pgnoSave = 0; + + /* This function does notmwork with detail=none databases. */ + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); + + if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ + pgnoSave = pgno+1; + } + + while( 1 ){ + xChunk(p, pCtx, pChunk, nChunk); + nRem -= nChunk; + fts5DataRelease(pData); + if( nRem<=0 ){ + break; + }else{ + pgno++; + pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); + if( pData==0 ) break; + pChunk = &pData->p[4]; + nChunk = MIN(nRem, pData->szLeaf - 4); + if( pgno==pgnoSave ){ + assert( pSeg->pNextLeaf==0 ); + pSeg->pNextLeaf = pData; + pData = 0; + } + } + } +} + +/* +** Iterator pIter currently points to a valid entry (not EOF). This +** function appends the position list data for the current entry to +** buffer pBuf. It does not make a copy of the position-list size +** field. +*/ +static void fts5SegiterPoslist( + Fts5Index *p, + Fts5SegIter *pSeg, + Fts5Colset *pColset, + Fts5Buffer *pBuf +){ + if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){ + if( pColset==0 ){ + fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); + }else{ + if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){ + PoslistCallbackCtx sCtx; + sCtx.pBuf = pBuf; + sCtx.pColset = pColset; + sCtx.eState = fts5IndexColsetTest(pColset, 0); + assert( sCtx.eState==0 || sCtx.eState==1 ); + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); + }else{ + PoslistOffsetsCtx sCtx; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.pBuf = pBuf; + sCtx.pColset = pColset; + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); + } + } + } +} + +/* +** IN/OUT parameter (*pa) points to a position list n bytes in size. If +** the position list contains entries for column iCol, then (*pa) is set +** to point to the sub-position-list for that column and the number of +** bytes in it returned. Or, if the argument position list does not +** contain any entries for column iCol, return 0. +*/ +static int fts5IndexExtractCol( + const u8 **pa, /* IN/OUT: Pointer to poslist */ + int n, /* IN: Size of poslist in bytes */ + int iCol /* Column to extract from poslist */ +){ + int iCurrent = 0; /* Anything before the first 0x01 is col 0 */ + const u8 *p = *pa; + const u8 *pEnd = &p[n]; /* One byte past end of position list */ + + while( iCol>iCurrent ){ + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint. Note that it is not possible for a negative + ** or extremely large varint to occur within an uncorrupted position + ** list. So the last byte of each varint may be assumed to have a clear + ** 0x80 bit. */ + while( *p!=0x01 ){ + while( *p++ & 0x80 ); + if( p>=pEnd ) return 0; + } + *pa = p++; + iCurrent = *p++; + if( iCurrent & 0x80 ){ + p--; + p += fts5GetVarint32(p, iCurrent); + } + } + if( iCol!=iCurrent ) return 0; + + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint */ + while( pnCol; i++){ + const u8 *pSub = pPos; + int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]); + if( nSub ){ + fts5BufferAppendBlob(pRc, pBuf, nSub, pSub); + } + } + } +} + +/* +** xSetOutputs callback used by detail=none tables. +*/ +static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){ + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE ); + pIter->base.iRowid = pSeg->iRowid; + pIter->base.nData = pSeg->nPos; +} + +/* +** xSetOutputs callback used by detail=full and detail=col tables when no +** column filters are specified. +*/ +static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){ + pIter->base.iRowid = pSeg->iRowid; + pIter->base.nData = pSeg->nPos; + + assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE ); + assert( pIter->pColset==0 ); + + if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ + /* All data is stored on the current page. Populate the output + ** variables to point into the body of the page object. */ + pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + }else{ + /* The data is distributed over two or more pages. Copy it into the + ** Fts5Iter.poslist buffer and then set the output pointer to point + ** to this buffer. */ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + } +} + +/* +** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match +** against no columns at all). +*/ +static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){ + UNUSED_PARAM(pSeg); + pIter->base.nData = 0; +} + +/* +** xSetOutputs callback used by detail=col when there is a column filter +** and there are 100 or more columns. Also called as a fallback from +** fts5IterSetOutputs_Col100 if the column-list spans more than one page. +*/ +static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, pIter->pColset, &pIter->poslist); + pIter->base.iRowid = pSeg->iRowid; + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; +} + +/* +** xSetOutputs callback used when: +** +** * detail=col, +** * there is a column filter, and +** * the table contains 100 or fewer columns. +** +** The last point is to ensure all column numbers are stored as +** single-byte varints. +*/ +static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){ + + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + assert( pIter->pColset ); + + if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){ + fts5IterSetOutputs_Col(pIter, pSeg); + }else{ + u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset]; + u8 *pEnd = (u8*)&a[pSeg->nPos]; + int iPrev = 0; + int *aiCol = pIter->pColset->aiCol; + int *aiColEnd = &aiCol[pIter->pColset->nCol]; + + u8 *aOut = pIter->poslist.p; + int iPrevOut = 0; + + pIter->base.iRowid = pSeg->iRowid; + + while( abase.pData = pIter->poslist.p; + pIter->base.nData = aOut - pIter->poslist.p; + } +} + +/* +** xSetOutputs callback used by detail=full when there is a column filter. +*/ +static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){ + Fts5Colset *pColset = pIter->pColset; + pIter->base.iRowid = pSeg->iRowid; + + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL ); + assert( pColset ); + + if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ + /* All data is stored on the current page. Populate the output + ** variables to point into the body of the page object. */ + const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset]; + if( pColset->nCol==1 ){ + pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]); + pIter->base.pData = a; + }else{ + int *pRc = &pIter->pIndex->rc; + fts5BufferZero(&pIter->poslist); + fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + } + }else{ + /* The data is distributed over two or more pages. Copy it into the + ** Fts5Iter.poslist buffer and then set the output pointer to point + ** to this buffer. */ + fts5BufferZero(&pIter->poslist); + fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist); + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + } +} + +static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ + if( *pRc==SQLITE_OK ){ + Fts5Config *pConfig = pIter->pIndex->pConfig; + if( pConfig->eDetail==FTS5_DETAIL_NONE ){ + pIter->xSetOutputs = fts5IterSetOutputs_None; + } + + else if( pIter->pColset==0 ){ + pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; + } + + else if( pIter->pColset->nCol==0 ){ + pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset; + } + + else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ + pIter->xSetOutputs = fts5IterSetOutputs_Full; + } + + else{ + assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS ); + if( pConfig->nCol<=100 ){ + pIter->xSetOutputs = fts5IterSetOutputs_Col100; + sqlite3Fts5BufferSize(pRc, &pIter->poslist, pConfig->nCol); + }else{ + pIter->xSetOutputs = fts5IterSetOutputs_Col; + } + } + } +} + + +/* +** Allocate a new Fts5Iter object. ** ** The new object will be used to iterate through data in structure pStruct. ** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel @@ -176738,19 +195314,18 @@ static Fts5IndexIter *fts5MultiIterAlloc( static void fts5MultiIterNew( Fts5Index *p, /* FTS5 backend to iterate within */ Fts5Structure *pStruct, /* Structure of specific index */ - int bSkipEmpty, /* True to ignore delete-keys */ int flags, /* FTS5INDEX_QUERY_XXX flags */ + Fts5Colset *pColset, /* Colset to filter on (or NULL) */ const u8 *pTerm, int nTerm, /* Term to seek to (or NULL/0) */ int iLevel, /* Level to iterate (-1 for all) */ int nSegment, /* Number of segments to merge (iLevel>=0) */ - Fts5IndexIter **ppOut /* New object */ + Fts5Iter **ppOut /* New object */ ){ int nSeg = 0; /* Number of segment-iters in use */ int iIter = 0; /* */ int iSeg; /* Used to iterate through segments */ - Fts5Buffer buf = {0,0,0}; /* Buffer used by fts5SegIterSeekInit() */ Fts5StructureLevel *pLvl; - Fts5IndexIter *pNew; + Fts5Iter *pNew; assert( (pTerm==0 && nTerm==0) || iLevel<0 ); @@ -176767,36 +195342,42 @@ static void fts5MultiIterNew( *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); if( pNew==0 ) return; pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); - pNew->bSkipEmpty = (u8)bSkipEmpty; + 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); + } /* Initialize each of the component segment iterators. */ - if( iLevel<0 ){ - Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; - if( p->pHash ){ - /* Add a segment iterator for the current contents of the hash table. */ - Fts5SegIter *pIter = &pNew->aSeg[iIter++]; - fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter); - } - for(pLvl=&pStruct->aLevel[0]; pLvlnSeg-1; iSeg>=0; iSeg--){ - Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; + if( p->rc==SQLITE_OK ){ + if( iLevel<0 ){ + Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; + if( p->pHash ){ + /* Add a segment iterator for the current contents of the hash table. */ Fts5SegIter *pIter = &pNew->aSeg[iIter++]; - if( pTerm==0 ){ - fts5SegIterInit(p, pSeg, pIter); - }else{ - fts5SegIterSeekInit(p, &buf, pTerm, nTerm, flags, pSeg, pIter); + fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter); + } + for(pLvl=&pStruct->aLevel[0]; pLvlnSeg-1; iSeg>=0; iSeg--){ + Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; + Fts5SegIter *pIter = &pNew->aSeg[iIter++]; + if( pTerm==0 ){ + fts5SegIterInit(p, pSeg, pIter); + }else{ + fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter); + } } } + }else{ + pLvl = &pStruct->aLevel[iLevel]; + for(iSeg=nSeg-1; iSeg>=0; iSeg--){ + fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]); + } } - }else{ - pLvl = &pStruct->aLevel[iLevel]; - for(iSeg=nSeg-1; iSeg>=0; iSeg--){ - fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]); - } + assert( iIter==nSeg ); } - assert( iIter==nSeg ); /* If the above was successful, each component iterators now points ** to the first entry in its segment. In this case initialize the @@ -176806,7 +195387,8 @@ static void fts5MultiIterNew( for(iIter=pNew->nSeg-1; iIter>0; iIter--){ int iEq; if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ - fts5SegIterNext(p, &pNew->aSeg[iEq], 0); + Fts5SegIter *pSeg = &pNew->aSeg[iEq]; + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); fts5MultiIterAdvanced(p, pNew, iEq, iIter); } } @@ -176815,30 +195397,32 @@ static void fts5MultiIterNew( if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){ fts5MultiIterNext(p, pNew, 0, 0); + }else if( pNew->base.bEof==0 ){ + Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst]; + pNew->xSetOutputs(pNew, pSeg); } + }else{ - fts5MultiIterFree(p, pNew); + fts5MultiIterFree(pNew); *ppOut = 0; } - fts5BufferFree(&buf); } /* -** Create an Fts5IndexIter that iterates through the doclist provided +** Create an Fts5Iter that iterates through the doclist provided ** as the second argument. */ static void fts5MultiIterNew2( Fts5Index *p, /* FTS5 backend to iterate within */ Fts5Data *pData, /* Doclist to iterate through */ int bDesc, /* True for descending rowid order */ - Fts5IndexIter **ppOut /* New object */ + Fts5Iter **ppOut /* New object */ ){ - Fts5IndexIter *pNew; + Fts5Iter *pNew; pNew = fts5MultiIterAlloc(p, 2); if( pNew ){ Fts5SegIter *pIter = &pNew->aSeg[1]; - pNew->bFiltered = 1; pIter->flags = FTS5_SEGITER_ONETERM; if( pData->szLeaf>0 ){ pIter->pLeaf = pData; @@ -176854,8 +195438,9 @@ static void fts5MultiIterNew2( } pData = 0; }else{ - pNew->bEof = 1; + pNew->base.bEof = 1; } + fts5SegIterSetNext(p, pIter); *ppOut = pNew; } @@ -176867,11 +195452,11 @@ static void fts5MultiIterNew2( ** Return true if the iterator is at EOF or if an error has occurred. ** False otherwise. */ -static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){ +static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ assert( p->rc - || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->bEof + || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof ); - return (p->rc || pIter->bEof); + return (p->rc || pIter->base.bEof); } /* @@ -176879,7 +195464,7 @@ static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){ ** to. If the iterator points to EOF when this function is called the ** results are undefined. */ -static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){ +static i64 fts5MultiIterRowid(Fts5Iter *pIter){ assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf ); return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid; } @@ -176889,7 +195474,7 @@ static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){ */ static void fts5MultiIterNextFrom( Fts5Index *p, - Fts5IndexIter *pIter, + Fts5Iter *pIter, i64 iMatch ){ while( 1 ){ @@ -176906,52 +195491,12 @@ static void fts5MultiIterNextFrom( ** Return a pointer to a buffer containing the term associated with the ** entry that the iterator currently points to. */ -static const u8 *fts5MultiIterTerm(Fts5IndexIter *pIter, int *pn){ +static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){ Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; *pn = p->term.n; return p->term.p; } -static void fts5ChunkIterate( - Fts5Index *p, /* Index object */ - Fts5SegIter *pSeg, /* Poslist of this iterator */ - void *pCtx, /* Context pointer for xChunk callback */ - void (*xChunk)(Fts5Index*, void*, const u8*, int) -){ - int nRem = pSeg->nPos; /* Number of bytes still to come */ - Fts5Data *pData = 0; - u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; - int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); - int pgno = pSeg->iLeafPgno; - int pgnoSave = 0; - - if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ - pgnoSave = pgno+1; - } - - while( 1 ){ - xChunk(p, pCtx, pChunk, nChunk); - nRem -= nChunk; - fts5DataRelease(pData); - if( nRem<=0 ){ - break; - }else{ - pgno++; - pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); - if( pData==0 ) break; - pChunk = &pData->p[4]; - nChunk = MIN(nRem, pData->szLeaf - 4); - if( pgno==pgnoSave ){ - assert( pSeg->pNextLeaf==0 ); - pSeg->pNextLeaf = pData; - pData = 0; - } - } - } -} - - - /* ** Allocate a new segment-id for the structure pStruct. The new segment ** id must be between 1 and 65335 inclusive, and must not be used by @@ -176968,18 +195513,46 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){ p->rc = SQLITE_FULL; }else{ - while( iSegid==0 ){ - int iLvl, iSeg; - sqlite3_randomness(sizeof(u32), (void*)&iSegid); - iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1); - for(iLvl=0; iLvlnLevel; iLvl++){ - for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ - if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){ - iSegid = 0; - } + /* FTS5_MAX_SEGMENT is currently defined as 2000. So the following + ** array is 63 elements, or 252 bytes, in size. */ + u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32]; + int iLvl, iSeg; + int i; + u32 mask; + memset(aUsed, 0, sizeof(aUsed)); + 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); } } } + + for(i=0; aUsed[i]==0xFFFFFFFF; i++); + mask = aUsed[i]; + for(iSegid=0; mask & (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( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); + + { + sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); + if( p->rc==SQLITE_OK ){ + 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 ); + p->rc = sqlite3_reset(pIdxSelect); + } + } +#endif } } @@ -176998,15 +195571,14 @@ static void fts5IndexDiscardData(Fts5Index *p){ } /* -** Return the size of the prefix, in bytes, that buffer (nNew/pNew) shares -** with buffer (nOld/pOld). +** Return the size of the prefix, in bytes, that buffer +** (pNew/) shares with buffer (pOld/nOld). +** +** Buffer (pNew/) is guaranteed to be greater +** than buffer (pOld/nOld). */ -static int fts5PrefixCompress( - int nOld, const u8 *pOld, - int nNew, const u8 *pNew -){ +static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){ int i; - assert( fts5BlobCompare(pOld, nOld, pNew, nNew)<0 ); for(i=0; iterm.n ){ - n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm); + n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); } fts5WriteBtreeTerm(p, pWriter, n, pTerm); pPage = &pWriter->writer; } }else{ - nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm); + nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix); } @@ -177348,8 +195920,7 @@ static void fts5WriteAppendTerm( static void fts5WriteAppendRowid( Fts5Index *p, Fts5SegWriter *pWriter, - i64 iRowid, - int nPos + i64 iRowid ){ if( p->rc==SQLITE_OK ){ Fts5PageWriter *pPage = &pWriter->writer; @@ -177376,8 +195947,6 @@ static void fts5WriteAppendRowid( pWriter->iPrevRowid = iRowid; pWriter->bFirstRowidInDoclist = 0; pWriter->bFirstRowidInPage = 0; - - fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos); } } @@ -177428,7 +195997,9 @@ static void fts5WriteFinish( fts5WriteFlushLeaf(p, pWriter); } *pnLeaf = pLeaf->pgno-1; - fts5WriteFlushBtree(p, pWriter); + if( pLeaf->pgno>1 ){ + fts5WriteFlushBtree(p, pWriter); + } } fts5BufferFree(&pLeaf->term); fts5BufferFree(&pLeaf->buf); @@ -177488,7 +196059,7 @@ static void fts5WriteInit( ** incremental merge operation. This function is called if the incremental ** merge step has finished but the input has not been completely exhausted. */ -static void fts5TrimSegments(Fts5Index *p, Fts5IndexIter *pIter){ +static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ int i; Fts5Buffer buf; memset(&buf, 0, sizeof(Fts5Buffer)); @@ -177566,13 +196137,16 @@ static void fts5IndexMergeLevel( Fts5Structure *pStruct = *ppStruct; Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; Fts5StructureLevel *pLvlOut; - Fts5IndexIter *pIter = 0; /* Iterator to read input data */ + Fts5Iter *pIter = 0; /* Iterator to read input data */ int nRem = pnRem ? *pnRem : 0; /* Output leaf pages left to write */ int nInput; /* Number of input segments */ Fts5SegWriter writer; /* Writer object */ Fts5StructureSegment *pSeg; /* Output segment */ Fts5Buffer term; int bOldest; /* True if the output segment is the oldest */ + int eDetail = p->pConfig->eDetail; + const int flags = FTS5INDEX_QUERY_NOOUTPUT; + int bTermWritten = 0; /* True if current term already output */ assert( iLvlnLevel ); assert( pLvl->nMerge<=pLvl->nSeg ); @@ -177617,7 +196191,7 @@ static void fts5IndexMergeLevel( bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2); assert( iLvl>=0 ); - for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, iLvl, nInput, &pIter); + for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, iLvl, nInput, &pIter); fts5MultiIterEof(p, pIter)==0; fts5MultiIterNext(p, pIter, 0, 0) ){ @@ -177626,27 +196200,41 @@ static void fts5IndexMergeLevel( int nTerm; const u8 *pTerm; - /* Check for key annihilation. */ - if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; - pTerm = fts5MultiIterTerm(pIter, &nTerm); if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){ if( pnRem && writer.nLeafWritten>nRem ){ break; } + fts5BufferSet(&p->rc, &term, nTerm, pTerm); + bTermWritten =0; + } + /* Check for key annihilation. */ + if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; + + if( p->rc==SQLITE_OK && bTermWritten==0 ){ /* This is a new term. Append a term to the output segment. */ fts5WriteAppendTerm(p, &writer, nTerm, pTerm); - fts5BufferSet(&p->rc, &term, nTerm, pTerm); + bTermWritten = 1; } /* Append the rowid to the output */ /* WRITEPOSLISTSIZE */ - nPos = pSegIter->nPos*2 + pSegIter->bDel; - fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos); + fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter)); - /* Append the position-list data to the output */ - fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback); + if( eDetail==FTS5_DETAIL_NONE ){ + if( pSegIter->bDel ){ + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); + if( pSegIter->nPos>0 ){ + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); + } + } + }else{ + /* Append the position-list data to the output */ + nPos = pSegIter->nPos*2 + pSegIter->bDel; + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos); + fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback); + } } /* Flush the last leaf page to disk. Set the output segment b-tree height @@ -177679,20 +196267,24 @@ static void fts5IndexMergeLevel( pLvl->nMerge = nInput; } - fts5MultiIterFree(p, pIter); + fts5MultiIterFree(pIter); fts5BufferFree(&term); if( pnRem ) *pnRem -= writer.nLeafWritten; } /* ** Do up to nPg pages of automerge work on the index. +** +** Return true if any changes were actually made, or false otherwise. */ -static void fts5IndexMerge( +static int fts5IndexMerge( Fts5Index *p, /* FTS5 backend object */ Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ - int nPg /* Pages of work to do */ + int nPg, /* Pages of work to do */ + int nMin /* Minimum number of segments to merge */ ){ int nRem = nPg; + int bRet = 0; Fts5Structure *pStruct = *ppStruct; while( nRem>0 && p->rc==SQLITE_OK ){ int iLvl; /* To iterate through levels */ @@ -177723,17 +196315,17 @@ static void fts5IndexMerge( } #endif - if( nBestpConfig->nAutomerge - && pStruct->aLevel[iBestLvl].nMerge==0 - ){ + if( nBestaLevel[iBestLvl].nMerge==0 ){ break; } + bRet = 1; fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem); if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){ fts5StructurePromote(p, iBestLvl+1, pStruct); } } *ppStruct = pStruct; + return bRet; } /* @@ -177761,7 +196353,7 @@ static void fts5IndexAutomerge( pStruct->nWriteCounter += nLeaf; nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel); - fts5IndexMerge(p, ppStruct, nRem); + fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge); } } @@ -177831,10 +196423,11 @@ static void fts5FlushOneHash(Fts5Index *p){ ** for the new level-0 segment. */ pStruct = fts5StructureRead(p); iSegid = fts5AllocateSegid(p, pStruct); + fts5StructureInvalidate(p); if( iSegid ){ const int pgsz = p->pConfig->pgsz; - + int eDetail = p->pConfig->eDetail; Fts5StructureSegment *pSeg; /* New segment within pStruct */ Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */ Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */ @@ -177877,12 +196470,7 @@ static void fts5FlushOneHash(Fts5Index *p){ ** loop iterates through the poslists that make up the current ** doclist. */ while( p->rc==SQLITE_OK && iOffn<=pBuf->nSpace ); - if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ - /* The entire poslist will fit on the current leaf. So copy - ** it in one go. */ - fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy); - }else{ - /* The entire poslist will not fit on this leaf. So it needs - ** to be broken into sections. The only qualification being - ** that each varint must be stored contiguously. */ - const u8 *pPoslist = &pDoclist[iOff]; - int iPos = 0; - while( p->rc==SQLITE_OK ){ - int nSpace = pgsz - pBuf->n - pPgidx->n; - int n = 0; - if( (nCopy - iPos)<=nSpace ){ - n = nCopy - iPos; - }else{ - n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); + if( eDetail==FTS5_DETAIL_NONE ){ + if( iOffp[pBuf->n++] = 0; + iOff++; + if( iOffp[pBuf->n++] = 0; + iOff++; } - assert( n>0 ); - fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); - iPos += n; - if( (pBuf->n + pPgidx->n)>=pgsz ){ - fts5WriteFlushLeaf(p, &writer); - } - if( iPos>=nCopy ) break; } + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + }else{ + int bDummy; + int nPos; + int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy); + nCopy += nPos; + if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ + /* The entire poslist will fit on the current leaf. So copy + ** it in one go. */ + fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy); + }else{ + /* The entire poslist will not fit on this leaf. So it needs + ** to be broken into sections. The only qualification being + ** that each varint must be stored contiguously. */ + const u8 *pPoslist = &pDoclist[iOff]; + int iPos = 0; + while( p->rc==SQLITE_OK ){ + int nSpace = pgsz - pBuf->n - pPgidx->n; + int n = 0; + if( (nCopy - iPos)<=nSpace ){ + n = nCopy - iPos; + }else{ + n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); + } + assert( n>0 ); + fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); + iPos += n; + if( (pBuf->n + pPgidx->n)>=pgsz ){ + fts5WriteFlushLeaf(p, &writer); + } + if( iPos>=nCopy ) break; + } + } + iOff += nCopy; } - iOff += nCopy; } } @@ -177968,28 +196574,41 @@ static void fts5IndexFlush(Fts5Index *p){ } } - -static int sqlite3Fts5IndexOptimize(Fts5Index *p){ - Fts5Structure *pStruct; +static Fts5Structure *fts5IndexOptimizeStruct( + Fts5Index *p, + Fts5Structure *pStruct +){ Fts5Structure *pNew = 0; - int nSeg = 0; + int nByte = sizeof(Fts5Structure); + int nSeg = pStruct->nSegment; + int i; - assert( p->rc==SQLITE_OK ); - fts5IndexFlush(p); - pStruct = fts5StructureRead(p); - - if( pStruct ){ - assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); - nSeg = pStruct->nSegment; - if( nSeg>1 ){ - int nByte = sizeof(Fts5Structure); - nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); - pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); + /* Figure out if this structure requires optimization. A structure does + ** not require optimization if either: + ** + ** + it consists of fewer than two segments, or + ** + all segments are on the same level, or + ** + all segments except one are currently inputs to a merge operation. + ** + ** In the first case, return NULL. In the second, increment the ref-count + ** on *pStruct and return a copy of the pointer to it. + */ + if( nSeg<2 ) return 0; + for(i=0; inLevel; i++){ + int nThis = pStruct->aLevel[i].nSeg; + if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){ + fts5StructureRef(pStruct); + return pStruct; } + assert( pStruct->aLevel[i].nMerge<=nThis ); } + + nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); + pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); + if( pNew ){ Fts5StructureLevel *pLvl; - int nByte = nSeg * sizeof(Fts5StructureSegment); + nByte = nSeg * sizeof(Fts5StructureSegment); pNew->nLevel = pStruct->nLevel+1; pNew->nRef = 1; pNew->nWriteCounter = pStruct->nWriteCounter; @@ -177998,7 +196617,10 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){ if( pLvl->aSeg ){ int iLvl, iSeg; int iSegOut = 0; - for(iLvl=0; iLvlnLevel; iLvl++){ + /* Iterate through all segments, from oldest to newest. Add them to + ** the new Fts5Level object so that pLvl->aSeg[0] is the oldest + ** segment in the data structure. */ + for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){ for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg]; iSegOut++; @@ -178011,8 +196633,27 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){ } } + return pNew; +} + +static int sqlite3Fts5IndexOptimize(Fts5Index *p){ + Fts5Structure *pStruct; + Fts5Structure *pNew = 0; + + assert( p->rc==SQLITE_OK ); + fts5IndexFlush(p); + pStruct = fts5StructureRead(p); + fts5StructureInvalidate(p); + + if( pStruct ){ + pNew = fts5IndexOptimizeStruct(p, pStruct); + } + fts5StructureRelease(pStruct); + + assert( pNew==0 || pNew->nSegment>0 ); if( pNew ){ - int iLvl = pNew->nLevel-1; + int iLvl; + for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){} while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){ int nRem = FTS5_OPT_WORK_UNIT; fts5IndexMergeLevel(p, &pNew, iLvl, &nRem); @@ -178022,247 +196663,61 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){ fts5StructureRelease(pNew); } - fts5StructureRelease(pStruct); return fts5IndexReturn(p); } +/* +** This is called to implement the special "VALUES('merge', $nMerge)" +** INSERT command. +*/ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){ - Fts5Structure *pStruct; - - pStruct = fts5StructureRead(p); - if( pStruct && pStruct->nLevel ){ - fts5IndexMerge(p, &pStruct, nMerge); - fts5StructureWrite(p, pStruct); + Fts5Structure *pStruct = fts5StructureRead(p); + if( pStruct ){ + int nMin = p->pConfig->nUsermerge; + fts5StructureInvalidate(p); + if( nMerge<0 ){ + Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct); + fts5StructureRelease(pStruct); + pStruct = pNew; + nMin = 2; + nMerge = nMerge*-1; + } + if( pStruct && pStruct->nLevel ){ + if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){ + fts5StructureWrite(p, pStruct); + } + } + fts5StructureRelease(pStruct); } - fts5StructureRelease(pStruct); - return fts5IndexReturn(p); } -static void fts5PoslistCallback( - Fts5Index *p, - void *pContext, - const u8 *pChunk, int nChunk -){ - assert_nc( nChunk>=0 ); - if( nChunk>0 ){ - fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk); - } -} - -typedef struct PoslistCallbackCtx PoslistCallbackCtx; -struct PoslistCallbackCtx { - Fts5Buffer *pBuf; /* Append to this buffer */ - Fts5Colset *pColset; /* Restrict matches to this column */ - int eState; /* See above */ -}; - -/* -** TODO: Make this more efficient! -*/ -static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ - int i; - for(i=0; inCol; i++){ - if( pColset->aiCol[i]==iCol ) return 1; - } - return 0; -} - -static void fts5PoslistFilterCallback( - Fts5Index *p, - void *pContext, - const u8 *pChunk, int nChunk -){ - PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext; - assert_nc( nChunk>=0 ); - if( nChunk>0 ){ - /* Search through to find the first varint with value 1. This is the - ** start of the next columns hits. */ - int i = 0; - int iStart = 0; - - if( pCtx->eState==2 ){ - int iCol; - fts5FastGetVarint32(pChunk, i, iCol); - if( fts5IndexColsetTest(pCtx->pColset, iCol) ){ - pCtx->eState = 1; - fts5BufferSafeAppendVarint(pCtx->pBuf, 1); - }else{ - pCtx->eState = 0; - } - } - - do { - while( ieState ){ - fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); - } - if( i=nChunk ){ - pCtx->eState = 2; - }else{ - fts5FastGetVarint32(pChunk, i, iCol); - pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol); - if( pCtx->eState ){ - fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); - iStart = i; - } - } - } - }while( irc, pBuf, pSeg->nPos) ){ - if( pColset==0 ){ - fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); - }else{ - PoslistCallbackCtx sCtx; - sCtx.pBuf = pBuf; - sCtx.pColset = pColset; - sCtx.eState = fts5IndexColsetTest(pColset, 0); - assert( sCtx.eState==0 || sCtx.eState==1 ); - fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); - } - } -} - -/* -** IN/OUT parameter (*pa) points to a position list n bytes in size. If -** the position list contains entries for column iCol, then (*pa) is set -** to point to the sub-position-list for that column and the number of -** bytes in it returned. Or, if the argument position list does not -** contain any entries for column iCol, return 0. -*/ -static int fts5IndexExtractCol( - const u8 **pa, /* IN/OUT: Pointer to poslist */ - int n, /* IN: Size of poslist in bytes */ - int iCol /* Column to extract from poslist */ -){ - int iCurrent = 0; /* Anything before the first 0x01 is col 0 */ - const u8 *p = *pa; - const u8 *pEnd = &p[n]; /* One byte past end of position list */ - u8 prev = 0; - - while( iCol>iCurrent ){ - /* Advance pointer p until it points to pEnd or an 0x01 byte that is - ** not part of a varint */ - while( (prev & 0x80) || *p!=0x01 ){ - prev = *p++; - if( p==pEnd ) return 0; - } - *pa = p++; - p += fts5GetVarint32(p, iCurrent); - } - if( iCol!=iCurrent ) return 0; - - /* Advance pointer p until it points to pEnd or an 0x01 byte that is - ** not part of a varint */ - assert( (prev & 0x80)==0 ); - while( prc. -*/ -static int fts5AppendPoslist( +static void fts5AppendRowid( Fts5Index *p, i64 iDelta, - Fts5IndexIter *pMulti, - Fts5Colset *pColset, + Fts5Iter *pUnused, Fts5Buffer *pBuf ){ - if( p->rc==SQLITE_OK ){ - Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ]; - assert( fts5MultiIterEof(p, pMulti)==0 ); - assert( pSeg->nPos>0 ); - if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){ - - if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf - && (pColset==0 || pColset->nCol==1) - ){ - const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset]; - int nPos; - if( pColset ){ - nPos = fts5IndexExtractCol(&pPos, pSeg->nPos, pColset->aiCol[0]); - if( nPos==0 ) return 1; - }else{ - nPos = pSeg->nPos; - } - assert( nPos>0 ); - fts5BufferSafeAppendVarint(pBuf, iDelta); - fts5BufferSafeAppendVarint(pBuf, nPos*2); - fts5BufferSafeAppendBlob(pBuf, pPos, nPos); - }else{ - int iSv1; - int iSv2; - int iData; - - /* Append iDelta */ - iSv1 = pBuf->n; - fts5BufferSafeAppendVarint(pBuf, iDelta); - - /* WRITEPOSLISTSIZE */ - iSv2 = pBuf->n; - fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2); - iData = pBuf->n; - - fts5SegiterPoslist(p, pSeg, pColset, pBuf); - - if( pColset ){ - int nActual = pBuf->n - iData; - if( nActual!=pSeg->nPos ){ - if( nActual==0 ){ - pBuf->n = iSv1; - return 1; - }else{ - int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2)); - while( iSv2<(iData-nReq) ){ pBuf->p[iSv2++] = 0x80; } - sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2); - } - } - } - } - - } - } - - return 0; + UNUSED_PARAM(pUnused); + fts5BufferAppendVarint(&p->rc, pBuf, iDelta); } +static void fts5AppendPoslist( + Fts5Index *p, + i64 iDelta, + Fts5Iter *pMulti, + Fts5Buffer *pBuf +){ + int nData = pMulti->base.nData; + assert( nData>0 ); + if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){ + fts5BufferSafeAppendVarint(pBuf, iDelta); + fts5BufferSafeAppendVarint(pBuf, nData*2); + fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData); + } +} + + static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; @@ -178323,6 +196778,69 @@ static void fts5MergeAppendDocid( (iLastRowid) = (iRowid); \ } +/* +** Swap the contents of buffer *p1 with that of *p2. +*/ +static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ + Fts5Buffer tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){ + int i = *piOff; + if( i>=pBuf->n ){ + *piOff = -1; + }else{ + u64 iVal; + *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal); + *piRowid += iVal; + } +} + +/* +** This is the equivalent of fts5MergePrefixLists() for detail=none mode. +** In this case the buffers consist of a delta-encoded list of rowids only. +*/ +static void fts5MergeRowidLists( + Fts5Index *p, /* FTS5 backend object */ + Fts5Buffer *p1, /* First list to merge */ + Fts5Buffer *p2 /* Second list to merge */ +){ + int i1 = 0; + int i2 = 0; + i64 iRowid1 = 0; + i64 iRowid2 = 0; + i64 iOut = 0; + + Fts5Buffer out; + memset(&out, 0, sizeof(out)); + sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); + if( p->rc ) return; + + fts5NextRowid(p1, &i1, &iRowid1); + fts5NextRowid(p2, &i2, &iRowid2); + while( i1>=0 || i2>=0 ){ + if( i1>=0 && (i2<0 || iRowid1iOut ); + fts5BufferSafeAppendVarint(&out, iRowid1 - iOut); + iOut = iRowid1; + fts5NextRowid(p1, &i1, &iRowid1); + }else{ + assert( iOut==0 || iRowid2>iOut ); + fts5BufferSafeAppendVarint(&out, iRowid2 - iOut); + iOut = iRowid2; + if( i1>=0 && iRowid1==iRowid2 ){ + fts5NextRowid(p1, &i1, &iRowid1); + } + fts5NextRowid(p2, &i2, &iRowid2); + } + } + + fts5BufferSwap(&out, p1); + fts5BufferFree(&out); +} + /* ** Buffers p1 and p2 contain doclists. This function merges the content ** of the two doclists together and sets buffer p1 to the result before @@ -178340,28 +196858,30 @@ static void fts5MergePrefixLists( i64 iLastRowid = 0; Fts5DoclistIter i1; Fts5DoclistIter i2; - Fts5Buffer out; - Fts5Buffer tmp; - memset(&out, 0, sizeof(out)); - memset(&tmp, 0, sizeof(tmp)); + Fts5Buffer out = {0, 0, 0}; + Fts5Buffer tmp = {0, 0, 0}; - sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); + if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return; fts5DoclistIterInit(p1, &i1); fts5DoclistIterInit(p2, &i2); - while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){ - if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowidrc, &tmp, i1.nPoslist + i2.nPoslist); + if( p->rc ) break; sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); + assert( iPos1>=0 && iPos2>=0 ); - while( p->rc==SQLITE_OK && (iPos1>=0 || iPos2>=0) ){ - i64 iNew; - if( iPos2<0 || (iPos1>=0 && iPos1=0 && iPos2>=0 ){ + while( 1 ){ + if( iPos1rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew); + } + + if( iPos1>=0 ){ + if( iPos1!=iPrev ){ + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); + } + fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1); + }else{ + assert( iPos2>=0 && iPos2!=iPrev ); + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); + fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2); } /* WRITEPOSLISTSIZE */ @@ -178399,90 +196943,111 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); fts5DoclistIterNext(&i1); fts5DoclistIterNext(&i2); + if( i1.aPoslist==0 || i2.aPoslist==0 ) break; } } + if( i1.aPoslist ){ + fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); + fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist); + } + else if( i2.aPoslist ){ + fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); + fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); + } + fts5BufferSet(&p->rc, p1, out.n, out.p); fts5BufferFree(&tmp); fts5BufferFree(&out); } } -static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ - Fts5Buffer tmp = *p1; - *p1 = *p2; - *p2 = tmp; -} - static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ const u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5Colset *pColset, /* Restrict matches to these columns */ - Fts5IndexIter **ppIter /* OUT: New iterator */ + Fts5Iter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; Fts5Buffer *aBuf; const int nBuf = 32; + void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*); + void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*); + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ + xMerge = fts5MergeRowidLists; + xAppend = fts5AppendRowid; + }else{ + xMerge = fts5MergePrefixLists; + xAppend = fts5AppendPoslist; + } + aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); pStruct = fts5StructureRead(p); if( aBuf && pStruct ){ - const int flags = FTS5INDEX_QUERY_SCAN; + const int flags = FTS5INDEX_QUERY_SCAN + | FTS5INDEX_QUERY_SKIPEMPTY + | FTS5INDEX_QUERY_NOOUTPUT; int i; i64 iLastRowid = 0; - Fts5IndexIter *p1 = 0; /* Iterator used to gather data from index */ + Fts5Iter *p1 = 0; /* Iterator used to gather data from index */ Fts5Data *pData; Fts5Buffer doclist; int bNewTerm = 1; memset(&doclist, 0, sizeof(doclist)); - for(fts5MultiIterNew(p, pStruct, 1, flags, pToken, nToken, -1, 0, &p1); + fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); + fts5IterSetOutputCb(&p->rc, p1); + for( /* no-op */ ; fts5MultiIterEof(p, p1)==0; fts5MultiIterNext2(p, p1, &bNewTerm) ){ - i64 iRowid = fts5MultiIterRowid(p1); - int nTerm; - const u8 *pTerm = fts5MultiIterTerm(p1, &nTerm); + Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; + int nTerm = pSeg->term.n; + const u8 *pTerm = pSeg->term.p; + p1->xSetOutputs(p1, pSeg); + assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 ); if( bNewTerm ){ if( nTerm0 && iRowid<=iLastRowid ){ + if( p1->base.nData==0 ) continue; + + if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ assert( ibase.iRowid-iLastRowid, p1, &doclist); + iLastRowid = p1->base.iRowid; } for(i=0; irc==SQLITE_OK ){ - fts5MergePrefixLists(p, &doclist, &aBuf[i]); + xMerge(p, &doclist, &aBuf[i]); } fts5BufferFree(&aBuf[i]); } - fts5MultiIterFree(p, p1); + fts5MultiIterFree(p1); pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n); if( pData ){ pData->p = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; - memcpy(pData->p, doclist.p, doclist.n); + if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n); fts5MultiIterNew2(p, pData, bDesc, ppIter); } fts5BufferFree(&doclist); @@ -178502,7 +197067,7 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ /* Allocate the hash table if it has not already been allocated */ if( p->pHash==0 ){ - p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData); + p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData); } /* Flush the hash table to disk if required */ @@ -178521,10 +197086,10 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ /* ** Commit data to disk. */ -static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ +static int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); - if( bCommit ) fts5CloseReader(p); + fts5CloseReader(p); return fts5IndexReturn(p); } @@ -178537,7 +197102,8 @@ static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ static int sqlite3Fts5IndexRollback(Fts5Index *p){ fts5CloseReader(p); fts5IndexDiscardData(p); - assert( p->rc==SQLITE_OK ); + fts5StructureInvalidate(p); + /* assert( p->rc==SQLITE_OK ); */ return SQLITE_OK; } @@ -178548,6 +197114,7 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){ */ static int sqlite3Fts5IndexReinit(Fts5Index *p){ Fts5Structure s; + fts5StructureInvalidate(p); memset(&s, 0, sizeof(Fts5Structure)); fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); fts5StructureWrite(p, &s); @@ -178606,11 +197173,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){ int rc = SQLITE_OK; if( p ){ assert( p->pReader==0 ); + fts5StructureInvalidate(p); sqlite3_finalize(p->pWriter); sqlite3_finalize(p->pDeleter); sqlite3_finalize(p->pIdxWriter); sqlite3_finalize(p->pIdxDeleter); sqlite3_finalize(p->pIdxSelect); + sqlite3_finalize(p->pDataVersion); sqlite3Fts5HashFree(p->pHash); sqlite3_free(p->zDataTbl); sqlite3_free(p); @@ -178623,7 +197192,11 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){ ** size. Return the number of bytes in the nChar character prefix of the ** buffer, or 0 if there are less than nChar characters in total. */ -static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){ +static int sqlite3Fts5IndexCharlenToBytelen( + const char *p, + int nByte, + int nChar +){ int n = 0; int i; for(i=0; inPrefix && rc==SQLITE_OK; i++){ - int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]); + const int nChar = pConfig->aPrefix[i]; + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); if( nByte ){ rc = sqlite3Fts5HashWrite(p->pHash, p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken, @@ -178704,22 +197278,27 @@ static int sqlite3Fts5IndexQuery( Fts5IndexIter **ppIter /* OUT: New iterator object */ ){ Fts5Config *pConfig = p->pConfig; - Fts5IndexIter *pRet = 0; - int iIdx = 0; + Fts5Iter *pRet = 0; Fts5Buffer buf = {0, 0, 0}; /* If the QUERY_SCAN flag is set, all other flags must be clear. */ assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ - memcpy(&buf.p[1], pToken, nToken); + int iIdx = 0; /* Index to search */ + if( nToken ) memcpy(&buf.p[1], pToken, nToken); -#ifdef SQLITE_DEBUG - /* If the QUERY_TEST_NOIDX flag was specified, then this must be a + /* Figure out which index to search and set iIdx accordingly. If this + ** is a prefix query for which there is no prefix index, set iIdx to + ** greater than pConfig->nPrefix to indicate that the query will be + ** satisfied by scanning multiple terms in the main index. + ** + ** If the QUERY_TEST_NOIDX flag was specified, then this must be a ** prefix-query. Instead of using a prefix-index (if one exists), ** evaluate the prefix query using the main FTS index. This is used ** for internal sanity checking by the integrity-check in debug ** mode only. */ +#ifdef SQLITE_DEBUG if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){ assert( flags & FTS5INDEX_QUERY_PREFIX ); iIdx = 1+pConfig->nPrefix; @@ -178733,24 +197312,35 @@ static int sqlite3Fts5IndexQuery( } if( iIdx<=pConfig->nPrefix ){ + /* Straight index lookup */ Fts5Structure *pStruct = fts5StructureRead(p); buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); if( pStruct ){ - fts5MultiIterNew(p, pStruct, 1, flags, buf.p, nToken+1, -1, 0, &pRet); + fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, + pColset, buf.p, nToken+1, -1, 0, &pRet + ); fts5StructureRelease(pStruct); } }else{ + /* Scan multiple terms in the main index */ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; buf.p[0] = FTS5_MAIN_PREFIX; fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet); + assert( p->rc!=SQLITE_OK || pRet->pColset==0 ); + fts5IterSetOutputCb(&p->rc, pRet); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; + if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + } } if( p->rc ){ - sqlite3Fts5IterClose(pRet); + sqlite3Fts5IterClose((Fts5IndexIter*)pRet); pRet = 0; fts5CloseReader(p); } - *ppIter = pRet; + + *ppIter = &pRet->base; sqlite3Fts5BufferFree(&buf); } return fts5IndexReturn(p); @@ -178759,15 +197349,11 @@ static int sqlite3Fts5IndexQuery( /* ** Return true if the iterator passed as the only argument is at EOF. */ -static int sqlite3Fts5IterEof(Fts5IndexIter *pIter){ - assert( pIter->pIndex->rc==SQLITE_OK ); - return pIter->bEof; -} - /* ** Move to the next matching rowid. */ -static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){ +static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; assert( pIter->pIndex->rc==SQLITE_OK ); fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); return fts5IndexReturn(pIter->pIndex); @@ -178776,7 +197362,8 @@ static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){ /* ** Move to the next matching term/rowid. Used by the fts5vocab module. */ -static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){ +static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5Index *p = pIter->pIndex; assert( pIter->pIndex->rc==SQLITE_OK ); @@ -178787,7 +197374,7 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){ if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){ fts5DataRelease(pSeg->pLeaf); pSeg->pLeaf = 0; - pIter->bEof = 1; + pIter->base.bEof = 1; } } @@ -178799,111 +197386,30 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){ ** definition of "at or after" depends on whether this iterator iterates ** in ascending or descending rowid order. */ -static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIter, i64 iMatch){ +static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); return fts5IndexReturn(pIter->pIndex); } -/* -** Return the current rowid. -*/ -static i64 sqlite3Fts5IterRowid(Fts5IndexIter *pIter){ - return fts5MultiIterRowid(pIter); -} - /* ** Return the current term. */ -static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){ +static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ int n; - const char *z = (const char*)fts5MultiIterTerm(pIter, &n); + const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); *pn = n-1; return &z[1]; } - -static int fts5IndexExtractColset ( - Fts5Colset *pColset, /* Colset to filter on */ - const u8 *pPos, int nPos, /* Position list */ - Fts5Buffer *pBuf /* Output buffer */ -){ - int rc = SQLITE_OK; - int i; - - fts5BufferZero(pBuf); - for(i=0; inCol; i++){ - const u8 *pSub = pPos; - int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]); - if( nSub ){ - fts5BufferAppendBlob(&rc, pBuf, nSub, pSub); - } - } - return rc; -} - - -/* -** Return a pointer to a buffer containing a copy of the position list for -** the current entry. Output variable *pn is set to the size of the buffer -** in bytes before returning. -** -** The returned position list does not include the "number of bytes" varint -** field that starts the position list on disk. -*/ -static int sqlite3Fts5IterPoslist( - Fts5IndexIter *pIter, - Fts5Colset *pColset, /* Column filter (or NULL) */ - const u8 **pp, /* OUT: Pointer to position-list data */ - int *pn, /* OUT: Size of position-list in bytes */ - i64 *piRowid /* OUT: Current rowid */ -){ - Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; - assert( pIter->pIndex->rc==SQLITE_OK ); - *piRowid = pSeg->iRowid; - if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ - u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset]; - if( pColset==0 || pIter->bFiltered ){ - *pn = pSeg->nPos; - *pp = pPos; - }else if( pColset->nCol==1 ){ - *pp = pPos; - *pn = fts5IndexExtractCol(pp, pSeg->nPos, pColset->aiCol[0]); - }else{ - fts5BufferZero(&pIter->poslist); - fts5IndexExtractColset(pColset, pPos, pSeg->nPos, &pIter->poslist); - *pp = pIter->poslist.p; - *pn = pIter->poslist.n; - } - }else{ - fts5BufferZero(&pIter->poslist); - fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist); - *pp = pIter->poslist.p; - *pn = pIter->poslist.n; - } - return fts5IndexReturn(pIter->pIndex); -} - -/* -** This function is similar to sqlite3Fts5IterPoslist(), except that it -** copies the position list into the buffer supplied as the second -** argument. -*/ -static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){ - Fts5Index *p = pIter->pIndex; - Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; - assert( p->rc==SQLITE_OK ); - fts5BufferZero(pBuf); - fts5SegiterPoslist(p, pSeg, 0, pBuf); - return fts5IndexReturn(p); -} - /* ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). */ -static void sqlite3Fts5IterClose(Fts5IndexIter *pIter){ - if( pIter ){ +static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ + if( pIndexIter ){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5Index *pIndex = pIter->pIndex; - fts5MultiIterFree(pIter->pIndex, pIter); + fts5MultiIterFree(pIter); fts5CloseReader(pIndex); } } @@ -178996,7 +197502,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){ /* ** Return a simple checksum value based on the arguments. */ -static u64 fts5IndexEntryCksum( +static u64 sqlite3Fts5IndexEntryCksum( i64 iRowid, int iCol, int iPos, @@ -179066,30 +197572,32 @@ static int fts5QueryCksum( int flags, /* Flags for Fts5IndexQuery */ u64 *pCksum /* IN/OUT: Checksum value */ ){ + int eDetail = p->pConfig->eDetail; u64 cksum = *pCksum; - Fts5IndexIter *pIdxIter = 0; - int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter); + Fts5IndexIter *pIter = 0; + int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); - while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){ - i64 dummy; - const u8 *pPos; - int nPos; - i64 rowid = sqlite3Fts5IterRowid(pIdxIter); - rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy); - if( rc==SQLITE_OK ){ + while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){ + i64 rowid = pIter->iRowid; + + if( eDetail==FTS5_DETAIL_NONE ){ + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n); + }else{ Fts5PoslistReader sReader; - for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader); + for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader); sReader.bEof==0; sqlite3Fts5PoslistReaderNext(&sReader) ){ int iCol = FTS5_POS2COLUMN(sReader.iPos); int iOff = FTS5_POS2OFFSET(sReader.iPos); - cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n); + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n); } - rc = sqlite3Fts5IterNext(pIdxIter); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IterNext(pIter); } } - sqlite3Fts5IterClose(pIdxIter); + sqlite3Fts5IterClose(pIter); *pCksum = cksum; return rc; @@ -179277,7 +197785,7 @@ static void fts5IndexIntegrityCheckSegment( ** ignore this b-tree entry. Otherwise, load it into memory. */ if( iIdxLeafpgnoFirst ) continue; iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf); - pLeaf = fts5DataRead(p, iRow); + pLeaf = fts5LeafRead(p, iRow); if( pLeaf==0 ) break; /* Check that the leaf contains at least one term, and that it is equal @@ -179383,7 +197891,7 @@ static void fts5IndexIntegrityCheckSegment( /* ** Run internal checks to ensure that the FTS index (a) is internally ** consistent and (b) contains entries for which the XOR of the checksums -** as calculated by fts5IndexEntryCksum() is cksum. +** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. ** ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the ** checksum does not match. Return SQLITE_OK if all checks pass without @@ -179391,9 +197899,10 @@ static void fts5IndexIntegrityCheckSegment( ** occurs. */ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ + int eDetail = p->pConfig->eDetail; u64 cksum2 = 0; /* Checksum based on contents of indexes */ Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ - Fts5IndexIter *pIter; /* Used to iterate through entire index */ + Fts5Iter *pIter; /* Used to iterate through entire index */ Fts5Structure *pStruct; /* Index structure */ #ifdef SQLITE_DEBUG @@ -179401,6 +197910,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ u64 cksum3 = 0; /* Checksum based on contents of indexes */ Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */ #endif + const int flags = FTS5INDEX_QUERY_NOOUTPUT; /* Load the FTS index structure */ pStruct = fts5StructureRead(p); @@ -179429,7 +197939,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ ** same term is performed. cksum3 is calculated based on the entries ** extracted by these queries. */ - for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, -1, 0, &pIter); + for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, -1, 0, &pIter); fts5MultiIterEof(p, pIter)==0; fts5MultiIterNext(p, pIter, 0, 0) ){ @@ -179442,17 +197952,23 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ /* If this is a new term, query for it. Update cksum3 with the results. */ fts5TestTerm(p, &term, z, n, cksum2, &cksum3); - poslist.n = 0; - fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist); - while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ - int iCol = FTS5_POS2COLUMN(iPos); - int iTokOff = FTS5_POS2OFFSET(iPos); - cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); + if( eDetail==FTS5_DETAIL_NONE ){ + if( 0==fts5MultiIterIsEmpty(p, pIter) ){ + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n); + } + }else{ + poslist.n = 0; + fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); + while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ + int iCol = FTS5_POS2COLUMN(iPos); + int iTokOff = FTS5_POS2OFFSET(iPos); + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); + } } } fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); - fts5MultiIterFree(p, pIter); + fts5MultiIterFree(pIter); if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; fts5StructureRelease(pStruct); @@ -179463,34 +197979,6 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ return fts5IndexReturn(p); } - -/* -** Calculate and return a checksum that is the XOR of the index entry -** checksum of all entries that would be generated by the token specified -** by the final 5 arguments. -*/ -static u64 sqlite3Fts5IndexCksum( - Fts5Config *pConfig, /* Configuration object */ - i64 iRowid, /* Document term appears in */ - int iCol, /* Column term appears in */ - int iPos, /* Position term appears in */ - const char *pTerm, int nTerm /* Term at iPos */ -){ - u64 ret = 0; /* Return value */ - int iIdx; /* For iterating through indexes */ - - ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm); - - for(iIdx=0; iIdxnPrefix; iIdx++){ - int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]); - if( nByte ){ - ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte); - } - } - - return ret; -} - /************************************************************************* ************************************************************************** ** Below this point is the implementation of the fts5_decode() scalar @@ -179658,6 +198146,47 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ return iOff; } +/* +** This function is part of the fts5_decode() debugging function. It is +** only ever used with detail=none tables. +** +** Buffer (pData/nData) contains a doclist in the format used by detail=none +** tables. This function appends a human-readable version of that list to +** buffer pBuf. +** +** If *pRc is other than SQLITE_OK when this function is called, it is a +** no-op. If an OOM or other error occurs within this function, *pRc is +** set to an SQLite error code before returning. The final state of buffer +** pBuf is undefined in this case. +*/ +static void fts5DecodeRowidList( + int *pRc, /* IN/OUT: Error code */ + Fts5Buffer *pBuf, /* Buffer to append text to */ + const u8 *pData, int nData /* Data to decode list-of-rowids from */ +){ + int i = 0; + i64 iRowid = 0; + + while( ipStruct==0 || p->iStructVersion!=0 ); + if( fts5IndexDataVersion(p)!=p->iStructVersion ){ + fts5StructureInvalidate(p); + } + return fts5IndexReturn(p); +} + /* ** 2014 Jun 09 ** @@ -180072,12 +198667,13 @@ struct Fts5Cursor { /* ** Values for Fts5Cursor.csrflags */ -#define FTS5CSR_REQUIRE_CONTENT 0x01 -#define FTS5CSR_REQUIRE_DOCSIZE 0x02 -#define FTS5CSR_REQUIRE_INST 0x04 -#define FTS5CSR_EOF 0x08 +#define FTS5CSR_EOF 0x01 +#define FTS5CSR_REQUIRE_CONTENT 0x02 +#define FTS5CSR_REQUIRE_DOCSIZE 0x04 +#define FTS5CSR_REQUIRE_INST 0x08 #define FTS5CSR_FREE_ZRANK 0x10 #define FTS5CSR_REQUIRE_RESEEK 0x20 +#define FTS5CSR_REQUIRE_POSLIST 0x40 #define BitFlagAllTest(x,y) (((x) & (y))==(y)) #define BitFlagTest(x,y) (((x) & (y))!=0) @@ -180357,6 +198953,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts5Table *pTab = (Fts5Table*)pVTab; Fts5Config *pConfig = pTab->pConfig; + const int nCol = pConfig->nCol; int idxFlags = 0; /* Parameter passed through to xFilter() */ int bHasMatch; int iNext; @@ -180382,24 +198979,34 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ int aColMap[3]; aColMap[0] = -1; - aColMap[1] = pConfig->nCol; - aColMap[2] = pConfig->nCol+1; + aColMap[1] = nCol; + aColMap[2] = nCol+1; /* Set idxFlags flags for all WHERE clause terms that will be used. */ for(i=0; inConstraint; i++){ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; - int j; - for(j=0; j<(int)ArraySize(aConstraint); j++){ - struct Constraint *pC = &aConstraint[j]; - if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){ - if( p->usable ){ + int iCol = p->iColumn; + + if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol) + || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol) + ){ + /* A MATCH operator or equivalent */ + if( p->usable ){ + idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16); + aConstraint[0].iConsIndex = i; + }else{ + /* As there exists an unusable MATCH constraint this is an + ** unusable plan. Set a prohibitively high cost. */ + pInfo->estimatedCost = 1e50; + return SQLITE_OK; + } + }else{ + int j; + for(j=1; jiCol] && p->op & pC->op && p->usable ){ pC->iConsIndex = i; idxFlags |= pC->fts5op; - }else if( j==0 ){ - /* As there exists an unusable MATCH constraint this is an - ** unusable plan. Set a prohibitively high cost. */ - pInfo->estimatedCost = 1e50; - return SQLITE_OK; } } } @@ -180436,7 +199043,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ /* Assign argvIndex values to each constraint in use. */ iNext = 1; - for(i=0; i<(int)ArraySize(aConstraint); i++){ + for(i=0; iiConsIndex>=0 ){ pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; @@ -180448,27 +199055,38 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ return SQLITE_OK; } +static int fts5NewTransaction(Fts5Table *pTab){ + Fts5Cursor *pCsr; + for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ + if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK; + } + return sqlite3Fts5StorageReset(pTab->pStorage); +} + /* ** Implementation of xOpen method. */ static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts5Table *pTab = (Fts5Table*)pVTab; Fts5Config *pConfig = pTab->pConfig; - Fts5Cursor *pCsr; /* New cursor object */ + Fts5Cursor *pCsr = 0; /* New cursor object */ int nByte; /* Bytes of space to allocate */ - int rc = SQLITE_OK; /* Return code */ + int rc; /* Return code */ - nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); - pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); - if( pCsr ){ - Fts5Global *pGlobal = pTab->pGlobal; - memset(pCsr, 0, nByte); - pCsr->aColumnSize = (int*)&pCsr[1]; - pCsr->pNext = pGlobal->pCsr; - pGlobal->pCsr = pCsr; - pCsr->iCsrId = ++pGlobal->iNextId; - }else{ - rc = SQLITE_NOMEM; + rc = fts5NewTransaction(pTab); + if( rc==SQLITE_OK ){ + nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); + pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); + if( pCsr ){ + Fts5Global *pGlobal = pTab->pGlobal; + memset(pCsr, 0, nByte); + pCsr->aColumnSize = (int*)&pCsr[1]; + pCsr->pNext = pGlobal->pCsr; + pGlobal->pCsr = pCsr; + pCsr->iCsrId = ++pGlobal->iNextId; + }else{ + rc = SQLITE_NOMEM; + } } *ppCsr = (sqlite3_vtab_cursor*)pCsr; return rc; @@ -180491,6 +199109,7 @@ static void fts5CsrNewrow(Fts5Cursor *pCsr){ FTS5CSR_REQUIRE_CONTENT | FTS5CSR_REQUIRE_DOCSIZE | FTS5CSR_REQUIRE_INST + | FTS5CSR_REQUIRE_POSLIST ); } @@ -180573,15 +199192,18 @@ static int fts5SorterNext(Fts5Cursor *pCsr){ nBlob = sqlite3_column_bytes(pSorter->pStmt, 1); aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1); - for(i=0; i<(pSorter->nIdx-1); i++){ - int iVal; - a += fts5GetVarint32(a, iVal); - iOff += iVal; - pSorter->aIdx[i] = iOff; + /* nBlob==0 in detail=none mode. */ + if( nBlob>0 ){ + for(i=0; i<(pSorter->nIdx-1); i++){ + int iVal; + a += fts5GetVarint32(a, iVal); + iOff += iVal; + pSorter->aIdx[i] = iOff; + } + pSorter->aIdx[i] = &aBlob[nBlob] - a; + pSorter->aPoslist = a; } - pSorter->aIdx[i] = &aBlob[nBlob] - a; - pSorter->aPoslist = a; fts5CsrNewrow(pCsr); } @@ -180625,7 +199247,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); - if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ + if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ *pbSkip = 1; } @@ -180633,6 +199255,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ fts5CsrNewrow(pCsr); if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ CsrFlagSet(pCsr, FTS5CSR_EOF); + *pbSkip = 1; } } return rc; @@ -180649,24 +199272,24 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ */ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; - int rc = SQLITE_OK; + int rc; assert( (pCsr->ePlan<3)== (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) ); + assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); if( pCsr->ePlan<3 ){ int bSkip = 0; if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); - if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ - CsrFlagSet(pCsr, FTS5CSR_EOF); - } + CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr)); fts5CsrNewrow(pCsr); }else{ switch( pCsr->ePlan ){ case FTS5_PLAN_SPECIAL: { CsrFlagSet(pCsr, FTS5CSR_EOF); + rc = SQLITE_OK; break; } @@ -180691,33 +199314,33 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ } -static sqlite3_stmt *fts5PrepareStatement( - int *pRc, +static int fts5PrepareStatement( + sqlite3_stmt **ppStmt, Fts5Config *pConfig, const char *zFmt, ... ){ sqlite3_stmt *pRet = 0; + int rc; + char *zSql; va_list ap; - va_start(ap, zFmt); - if( *pRc==SQLITE_OK ){ - int rc; - char *zSql = sqlite3_vmprintf(zFmt, ap); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); - if( rc!=SQLITE_OK ){ - *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); - } - sqlite3_free(zSql); + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &pRet, 0); + if( rc!=SQLITE_OK ){ + *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); } - *pRc = rc; + sqlite3_free(zSql); } va_end(ap); - return pRet; + *ppStmt = pRet; + return rc; } static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ @@ -180725,7 +199348,7 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ Fts5Sorter *pSorter; int nPhrase; int nByte; - int rc = SQLITE_OK; + int rc; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; @@ -180743,7 +199366,7 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ ** table, saving it creates a circular reference. ** ** If SQLite a built-in statement cache, this wouldn't be a problem. */ - pSorter->pStmt = fts5PrepareStatement(&rc, pConfig, + rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", pConfig->zDb, pConfig->zName, zRank, pConfig->zName, (zRankArgs ? ", " : ""), @@ -180844,7 +199467,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); if( zSql ){ sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &pStmt, 0); sqlite3_free(zSql); assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); if( rc==SQLITE_OK ){ @@ -180943,7 +199567,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ static int fts5FilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ - const char *idxStr, /* Unused */ + const char *zUnused, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ @@ -180959,8 +199583,12 @@ static int fts5FilterMethod( sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ + int iCol; /* Column on LHS of MATCH operator */ char **pzErrmsg = pConfig->pzErrmsg; + UNUSED_PARAM(zUnused); + UNUSED_PARAM(nVal); + if( pCsr->ePlan ){ fts5FreeCursorComponents(pCsr); memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); @@ -180986,6 +199614,8 @@ static int fts5FilterMethod( if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++]; if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++]; if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++]; + iCol = (idxNum>>16); + assert( iCol>=0 && iCol<=pConfig->nCol ); assert( iVal==nVal ); bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0); pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0); @@ -181032,7 +199662,7 @@ static int fts5FilterMethod( rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]); }else{ char **pzErr = &pTab->base.zErrMsg; - rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr); + rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr); if( rc==SQLITE_OK ){ if( bOrderByRank ){ pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; @@ -181244,14 +199874,13 @@ static int fts5SpecialInsert( static int fts5SpecialDelete( Fts5Table *pTab, - sqlite3_value **apVal, - sqlite3_int64 *piRowid + sqlite3_value **apVal ){ int rc = SQLITE_OK; int eType1 = sqlite3_value_type(apVal[1]); if( eType1==SQLITE_INTEGER ){ sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); - rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); } return rc; } @@ -181321,7 +199950,7 @@ static int fts5UpdateMethod( if( pConfig->eContent!=FTS5_CONTENT_NORMAL && 0==sqlite3_stricmp("delete", z) ){ - rc = fts5SpecialDelete(pTab, apVal, pRowid); + rc = fts5SpecialDelete(pTab, apVal); }else{ rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); } @@ -181355,46 +199984,46 @@ static int fts5UpdateMethod( rc = SQLITE_ERROR; } - /* Case 1: DELETE */ + /* DELETE */ else if( nArg==1 ){ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); } - /* Case 2: INSERT */ + /* 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); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); } fts5StorageInsert(&rc, pTab, apVal, pRowid); } - /* Case 2: UPDATE */ + /* 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); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); + 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); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); } } }else{ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); fts5StorageInsert(&rc, pTab, apVal, pRowid); } } @@ -181413,7 +200042,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ fts5CheckTransactionState(pTab, FTS5_SYNC, 0); pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; fts5TripCursors(pTab); - rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); + rc = sqlite3Fts5StorageSync(pTab->pStorage); pTab->pConfig->pzErrmsg = 0; return rc; } @@ -181423,6 +200052,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); + fts5NewTransaction((Fts5Table*)pVtab); return SQLITE_OK; } @@ -181432,6 +200062,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){ ** by fts5SyncMethod(). */ static int fts5CommitMethod(sqlite3_vtab *pVtab){ + UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); return SQLITE_OK; } @@ -181448,6 +200079,8 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){ return rc; } +static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*); + static void *fts5ApiUserData(Fts5Context *pCtx){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; return pCsr->pAux->pUserData; @@ -181497,17 +200130,72 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); } -static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){ - int n; - if( pCsr->pSorter ){ +static int fts5ApiColumnText( + Fts5Context *pCtx, + int iCol, + const char **pz, + int *pn +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ + *pz = 0; + *pn = 0; + }else{ + rc = fts5SeekCursor(pCsr, 0); + if( rc==SQLITE_OK ){ + *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); + *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); + } + } + return rc; +} + +static int fts5CsrPoslist( + Fts5Cursor *pCsr, + int iPhrase, + const u8 **pa, + int *pn +){ + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + int rc = SQLITE_OK; + int bLive = (pCsr->pSorter==0); + + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5PoslistPopulator *aPopulator; + int i; + aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); + if( aPopulator==0 ) rc = SQLITE_NOMEM; + for(i=0; inCol && rc==SQLITE_OK; i++){ + int n; const char *z; + rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ExprPopulatePoslists( + pConfig, pCsr->pExpr, aPopulator, i, z, n + ); + } + } + sqlite3_free(aPopulator); + + if( pCsr->pSorter ){ + sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid); + } + } + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); + } + + if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ Fts5Sorter *pSorter = pCsr->pSorter; int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); - n = pSorter->aIdx[iPhrase] - i1; + *pn = pSorter->aIdx[iPhrase] - i1; *pa = &pSorter->aPoslist[i1]; }else{ - n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); } - return n; + + return rc; } /* @@ -181532,43 +200220,48 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ int i; /* Initialize all iterators */ - for(i=0; i=pCsr->nInstAlloc ){ - pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; - aInst = (int*)sqlite3_realloc( - pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 - ); - if( aInst ){ - pCsr->aInst = aInst; - }else{ - rc = SQLITE_NOMEM; - break; + nInst++; + if( nInst>=pCsr->nInstAlloc ){ + pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; + aInst = (int*)sqlite3_realloc( + pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 + ); + if( aInst ){ + pCsr->aInst = aInst; + }else{ + rc = SQLITE_NOMEM; + break; + } } - } - aInst = &pCsr->aInst[3 * (nInst-1)]; - aInst[0] = iBest; - aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); - aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); - sqlite3Fts5PoslistReaderNext(&aIter[iBest]); + aInst = &pCsr->aInst[3 * (nInst-1)]; + aInst[0] = iBest; + aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); + aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); + sqlite3Fts5PoslistReaderNext(&aIter[iBest]); + } } pCsr->nInstCount = nInst; @@ -181601,6 +200294,12 @@ static int fts5ApiInst( ){ if( iIdx<0 || iIdx>=pCsr->nInstCount ){ rc = SQLITE_RANGE; +#if 0 + }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ + *piPhrase = pCsr->aInst[iIdx*3]; + *piCol = pCsr->aInst[iIdx*3 + 2]; + *piOff = -1; +#endif }else{ *piPhrase = pCsr->aInst[iIdx*3]; *piCol = pCsr->aInst[iIdx*3 + 1]; @@ -181614,36 +200313,17 @@ static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){ return fts5CursorRowid((Fts5Cursor*)pCtx); } -static int fts5ApiColumnText( - Fts5Context *pCtx, - int iCol, - const char **pz, - int *pn -){ - int rc = SQLITE_OK; - Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ - *pz = 0; - *pn = 0; - }else{ - rc = fts5SeekCursor(pCsr, 0); - if( rc==SQLITE_OK ){ - *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); - *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); - } - } - return rc; -} - static int fts5ColumnSizeCb( void *pContext, /* Pointer to int */ int tflags, - const char *pToken, /* Buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStart, /* Start offset of token */ - int iEnd /* End offset of token */ + const char *pUnused, /* Buffer containing token */ + int nUnused, /* Size of token in bytes */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ ){ int *pCnt = (int*)pContext; + UNUSED_PARAM2(pUnused, nUnused); + UNUSED_PARAM2(iUnused1, iUnused2); if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){ (*pCnt)++; } @@ -181759,10 +200439,11 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){ } static void fts5ApiPhraseNext( - Fts5Context *pCtx, + Fts5Context *pUnused, Fts5PhraseIter *pIter, int *piCol, int *piOff ){ + UNUSED_PARAM(pUnused); if( pIter->a>=pIter->b ){ *piCol = -1; *piOff = -1; @@ -181779,20 +200460,98 @@ static void fts5ApiPhraseNext( } } -static void fts5ApiPhraseFirst( +static int fts5ApiPhraseFirst( Fts5Context *pCtx, int iPhrase, Fts5PhraseIter *pIter, int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a); - pIter->b = &pIter->a[n]; - *piCol = 0; - *piOff = 0; - fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); + int n; + int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + *piCol = 0; + *piOff = 0; + fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); + } + return rc; } +static void fts5ApiPhraseNextColumn( + Fts5Context *pCtx, + Fts5PhraseIter *pIter, + int *piCol +){ + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + if( pIter->a>=pIter->b ){ + *piCol = -1; + }else{ + int iIncr; + pIter->a += fts5GetVarint32(&pIter->a[0], iIncr); + *piCol += (iIncr-2); + } + }else{ + while( 1 ){ + int dummy; + if( pIter->a>=pIter->b ){ + *piCol = -1; + return; + } + if( pIter->a[0]==0x01 ) break; + pIter->a += fts5GetVarint32(pIter->a, dummy); + } + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); + } +} + +static int fts5ApiPhraseFirstColumn( + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, + int *piCol +){ + int rc = SQLITE_OK; + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; + + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + Fts5Sorter *pSorter = pCsr->pSorter; + int n; + if( pSorter ){ + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + n = pSorter->aIdx[iPhrase] - i1; + pIter->a = &pSorter->aPoslist[i1]; + }else{ + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); + } + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + *piCol = 0; + fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + } + }else{ + int n; + rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); + if( rc==SQLITE_OK ){ + pIter->b = &pIter->a[n]; + if( n<=0 ){ + *piCol = -1; + }else if( pIter->a[0]==0x01 ){ + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); + }else{ + *piCol = 0; + } + } + } + + return rc; +} + + static int fts5ApiQueryPhrase(Fts5Context*, int, void*, int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) ); @@ -181816,9 +200575,10 @@ static const Fts5ExtensionApi sFts5Api = { fts5ApiGetAuxdata, fts5ApiPhraseFirst, fts5ApiPhraseNext, + fts5ApiPhraseFirstColumn, + fts5ApiPhraseNextColumn, }; - /* ** Implementation of API function xQueryPhrase(). */ @@ -181835,12 +200595,11 @@ static int fts5ApiQueryPhrase( rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew); if( rc==SQLITE_OK ){ - Fts5Config *pConf = pTab->pConfig; pNew->ePlan = FTS5_PLAN_MATCH; pNew->iFirstRowid = SMALLEST_INT64; pNew->iLastRowid = LARGEST_INT64; pNew->base.pVtab = (sqlite3_vtab*)pTab; - rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr); + rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr); } if( rc==SQLITE_OK ){ @@ -181950,20 +200709,46 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ Fts5Buffer val; memset(&val, 0, sizeof(Fts5Buffer)); + switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: - /* Append the varints */ - for(i=0; i<(nPhrase-1); i++){ - const u8 *dummy; - int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); - sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); - } + /* Append the varints */ + for(i=0; i<(nPhrase-1); i++){ + const u8 *dummy; + int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); + } - /* Append the position lists */ - for(i=0; ipExpr, i, &pPoslist); - sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + /* Append the position lists */ + for(i=0; ipExpr, i, &pPoslist); + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + } + break; + + case FTS5_DETAIL_COLUMNS: + + /* Append the varints */ + for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){ + const u8 *dummy; + int nByte; + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte); + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); + } + + /* Append the position lists */ + for(i=0; rc==SQLITE_OK && ipExpr, i, &pPoslist, &nPoslist); + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); + } + break; + + default: + break; } sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); @@ -182027,7 +200812,7 @@ static int fts5ColumnMethod( */ static int fts5FindFunctionMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ - int nArg, /* Number of SQL function arguments */ + int nUnused, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ @@ -182035,6 +200820,7 @@ static int fts5FindFunctionMethod( Fts5Table *pTab = (Fts5Table*)pVtab; Fts5Auxiliary *pAux; + UNUSED_PARAM(nUnused); pAux = fts5FindAuxiliary(pTab, zName); if( pAux ){ *pxFunc = fts5ApiCallback; @@ -182064,9 +200850,10 @@ static int fts5RenameMethod( */ 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, 0); + return sqlite3Fts5StorageSync(pTab->pStorage); } /* @@ -182076,9 +200863,10 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ */ 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, 0); + return sqlite3Fts5StorageSync(pTab->pStorage); } /* @@ -182088,6 +200876,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5Table *pTab = (Fts5Table*)pVtab; + UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); return sqlite3Fts5StorageRollback(pTab->pStorage); @@ -182267,14 +201056,14 @@ static void fts5ModuleDestroy(void *pCtx){ static void fts5Fts5Func( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ - sqlite3_value **apVal /* Function arguments */ + sqlite3_value **apArg /* Function arguments */ ){ Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); - char buf[8]; - assert( nArg==0 ); - assert( sizeof(buf)>=sizeof(pGlobal) ); - memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); - sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); + fts5_api **ppApi; + UNUSED_PARAM(nArg); + assert( nArg==1 ); + ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr"); + if( ppApi ) *ppApi = &pGlobal->api; } /* @@ -182283,10 +201072,11 @@ static void fts5Fts5Func( static void fts5SourceIdFunc( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ - sqlite3_value **apVal /* Function arguments */ + sqlite3_value **apUnused /* Function arguments */ ){ assert( nArg==0 ); - sqlite3_result_text(pCtx, "fts5: 2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9", -1, SQLITE_TRANSIENT); + UNUSED_PARAM2(nArg, apUnused); + sqlite3_result_text(pCtx, "fts5: 2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827", -1, SQLITE_TRANSIENT); } static int fts5Init(sqlite3 *db){ @@ -182338,7 +201128,7 @@ static int fts5Init(sqlite3 *db){ if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db); if( rc==SQLITE_OK ){ rc = sqlite3_create_function( - db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 + db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 ); } if( rc==SQLITE_OK ){ @@ -182347,6 +201137,17 @@ static int fts5Init(sqlite3 *db){ ); } } + + /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file + ** fts5_test_mi.c is compiled and linked into the executable. And call + ** its entry point to enable the matchinfo() demo. */ +#ifdef SQLITE_FTS5_ENABLE_TEST_MI + if( rc==SQLITE_OK ){ + extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); + rc = sqlite3Fts5TestRegisterMatchinfo(db); + } +#endif + return rc; } @@ -182363,7 +201164,7 @@ static int fts5Init(sqlite3 *db){ #ifdef _WIN32 __declspec(dllexport) #endif -SQLITE_API int SQLITE_STDCALL sqlite3_fts_init( +SQLITE_API int sqlite3_fts_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -182376,7 +201177,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_fts_init( #ifdef _WIN32 __declspec(dllexport) #endif -SQLITE_API int SQLITE_STDCALL sqlite3_fts5_init( +SQLITE_API int sqlite3_fts5_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -182529,7 +201330,8 @@ static int fts5StorageGetStmt( if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0); + rc = sqlite3_prepare_v3(pC->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0); sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); @@ -182538,6 +201340,7 @@ static int fts5StorageGetStmt( } *ppStmt = p->aStmt[eStmt]; + sqlite3_reset(*ppStmt); return rc; } @@ -182610,7 +201413,7 @@ static void fts5StorageRenameOne( static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){ Fts5Config *pConfig = pStorage->pConfig; - int rc = sqlite3Fts5StorageSync(pStorage, 1); + int rc = sqlite3Fts5StorageSync(pStorage); fts5StorageRenameOne(pConfig, &rc, "data", zName); fts5StorageRenameOne(pConfig, &rc, "idx", zName); @@ -182639,7 +201442,11 @@ static int sqlite3Fts5CreateTable( char *zErr = 0; rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", - pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":"" + pConfig->zDb, pConfig->zName, zPost, zDefn, +#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID + bWithout?" WITHOUT ROWID": +#endif + "" ); if( zErr ){ *pzErr = sqlite3_mprintf( @@ -182731,7 +201538,7 @@ static int sqlite3Fts5StorageClose(Fts5Storage *p){ int i; /* Finalize all SQL statements */ - for(i=0; i<(int)ArraySize(p->aStmt); i++){ + for(i=0; iaStmt); i++){ sqlite3_finalize(p->aStmt[i]); } @@ -182755,11 +201562,13 @@ static int fts5StorageInsertCallback( int tflags, const char *pToken, /* Buffer containing token */ int nToken, /* Size of token in bytes */ - int iStart, /* Start offset of token */ - int iEnd /* End offset of token */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ ){ Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext; Fts5Index *pIdx = pCtx->pStorage->pIndex; + UNUSED_PARAM2(iUnused1, iUnused2); + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ pCtx->szCol++; } @@ -182771,39 +201580,52 @@ static int fts5StorageInsertCallback( ** delete-markers to the FTS index necessary to delete it. Do not actually ** remove the %_content row at this time though. */ -static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){ +static int fts5StorageDeleteFromIndex( + Fts5Storage *p, + i64 iDel, + sqlite3_value **apVal +){ Fts5Config *pConfig = p->pConfig; - sqlite3_stmt *pSeek; /* SELECT to read row iDel from %_data */ + sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ int rc; /* Return code */ + int rc2; /* sqlite3_reset() return code */ + int iCol; + Fts5InsertCtx ctx; - rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); - if( rc==SQLITE_OK ){ - int rc2; + if( apVal==0 ){ + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); + if( rc!=SQLITE_OK ) return rc; sqlite3_bind_int64(pSeek, 1, iDel); - if( sqlite3_step(pSeek)==SQLITE_ROW ){ - int iCol; - Fts5InsertCtx ctx; - ctx.pStorage = p; - ctx.iCol = -1; - rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); - for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ - if( pConfig->abUnindexed[iCol-1] ) continue; - ctx.szCol = 0; - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - (const char*)sqlite3_column_text(pSeek, iCol), - sqlite3_column_bytes(pSeek, iCol), - (void*)&ctx, - fts5StorageInsertCallback - ); - p->aTotalSize[iCol-1] -= (i64)ctx.szCol; - } - p->nTotalRow--; + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ + return sqlite3_reset(pSeek); } - rc2 = sqlite3_reset(pSeek); - if( rc==SQLITE_OK ) rc = rc2; } + ctx.pStorage = p; + ctx.iCol = -1; + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); + for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ + if( pConfig->abUnindexed[iCol-1]==0 ){ + const char *zText; + int nText; + if( pSeek ){ + zText = (const char*)sqlite3_column_text(pSeek, iCol); + nText = sqlite3_column_bytes(pSeek, iCol); + }else{ + zText = (const char*)sqlite3_value_text(apVal[iCol-1]); + nText = sqlite3_value_bytes(apVal[iCol-1]); + } + ctx.szCol = 0; + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, + zText, nText, (void*)&ctx, fts5StorageInsertCallback + ); + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + } + } + p->nTotalRow--; + + rc2 = sqlite3_reset(pSeek); + if( rc==SQLITE_OK ) rc = rc2; return rc; } @@ -182883,16 +201705,17 @@ static int fts5StorageSaveTotals(Fts5Storage *p){ /* ** Remove a row from the FTS table. */ -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){ +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ Fts5Config *pConfig = p->pConfig; int rc; sqlite3_stmt *pDel = 0; + assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 ); rc = fts5StorageLoadTotals(p, 1); /* Delete the index records */ if( rc==SQLITE_OK ){ - rc = fts5StorageDeleteFromIndex(p, iDel); + rc = fts5StorageDeleteFromIndex(p, iDel, apVal); } /* Delete the %_docsize record */ @@ -182917,66 +201740,6 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){ } } - /* Write the averages record */ - if( rc==SQLITE_OK ){ - rc = fts5StorageSaveTotals(p); - } - - return rc; -} - -static int sqlite3Fts5StorageSpecialDelete( - Fts5Storage *p, - i64 iDel, - sqlite3_value **apVal -){ - Fts5Config *pConfig = p->pConfig; - int rc; - sqlite3_stmt *pDel = 0; - - assert( pConfig->eContent!=FTS5_CONTENT_NORMAL ); - rc = fts5StorageLoadTotals(p, 1); - - /* Delete the index records */ - if( rc==SQLITE_OK ){ - int iCol; - Fts5InsertCtx ctx; - ctx.pStorage = p; - ctx.iCol = -1; - - rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); - for(iCol=0; rc==SQLITE_OK && iColnCol; iCol++){ - if( pConfig->abUnindexed[iCol] ) continue; - ctx.szCol = 0; - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - (const char*)sqlite3_value_text(apVal[iCol]), - sqlite3_value_bytes(apVal[iCol]), - (void*)&ctx, - fts5StorageInsertCallback - ); - p->aTotalSize[iCol] -= (i64)ctx.szCol; - } - p->nTotalRow--; - } - - /* Delete the %_docsize record */ - if( pConfig->bColumnsize ){ - if( rc==SQLITE_OK ){ - rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); - } - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pDel, 1, iDel); - sqlite3_step(pDel); - rc = sqlite3_reset(pDel); - } - } - - /* Write the averages record */ - if( rc==SQLITE_OK ){ - rc = fts5StorageSaveTotals(p); - } - return rc; } @@ -183072,6 +201835,10 @@ static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){ return sqlite3Fts5IndexMerge(p->pIndex, nMerge); } +static int sqlite3Fts5StorageReset(Fts5Storage *p){ + return sqlite3Fts5IndexReset(p->pIndex); +} + /* ** Allocate a new rowid. This is used for "external content" tables when ** a NULL value is inserted into the rowid column. The new rowid is allocated @@ -183176,11 +201943,6 @@ static int sqlite3Fts5StorageIndexInsert( } sqlite3_free(buf.p); - /* Write the averages record */ - if( rc==SQLITE_OK ){ - rc = fts5StorageSaveTotals(p); - } - return rc; } @@ -183218,28 +201980,76 @@ struct Fts5IntegrityCtx { int iCol; int szCol; u64 cksum; + Fts5Termset *pTermset; Fts5Config *pConfig; }; + /* ** Tokenization callback used by integrity check. */ static int fts5StorageIntegrityCallback( - void *pContext, /* Pointer to Fts5InsertCtx object */ + void *pContext, /* Pointer to Fts5IntegrityCtx object */ int tflags, const char *pToken, /* Buffer containing token */ int nToken, /* Size of token in bytes */ - int iStart, /* Start offset of token */ - int iEnd /* End offset of token */ + int iUnused1, /* Start offset of token */ + int iUnused2 /* End offset of token */ ){ Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext; + Fts5Termset *pTermset = pCtx->pTermset; + int bPresent; + int ii; + int rc = SQLITE_OK; + int iPos; + int iCol; + + UNUSED_PARAM2(iUnused1, iUnused2); + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; + if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ pCtx->szCol++; } - pCtx->cksum ^= sqlite3Fts5IndexCksum( - pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken - ); - return SQLITE_OK; + + switch( pCtx->pConfig->eDetail ){ + case FTS5_DETAIL_FULL: + iPos = pCtx->szCol-1; + iCol = pCtx->iCol; + break; + + case FTS5_DETAIL_COLUMNS: + iPos = pCtx->iCol; + iCol = 0; + break; + + default: + assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE ); + iPos = 0; + iCol = 0; + break; + } + + rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent); + if( rc==SQLITE_OK && bPresent==0 ){ + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( + pCtx->iRowid, iCol, iPos, 0, pToken, nToken + ); + } + + for(ii=0; rc==SQLITE_OK && iipConfig->nPrefix; ii++){ + const int nChar = pCtx->pConfig->aPrefix[ii]; + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); + if( nByte ){ + rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent); + if( bPresent==0 ){ + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( + pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte + ); + } + } + } + + return rc; } /* @@ -183275,22 +202085,37 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ if( pConfig->bColumnsize ){ rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); } + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } for(i=0; rc==SQLITE_OK && inCol; i++){ if( pConfig->abUnindexed[i] ) continue; ctx.iCol = i; ctx.szCol = 0; - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - (const char*)sqlite3_column_text(pScan, i+1), - sqlite3_column_bytes(pScan, i+1), - (void*)&ctx, - fts5StorageIntegrityCallback - ); - if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + (const char*)sqlite3_column_text(pScan, i+1), + sqlite3_column_bytes(pScan, i+1), + (void*)&ctx, + fts5StorageIntegrityCallback + ); + } + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ rc = FTS5_CORRUPT; } aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } } + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + if( rc!=SQLITE_OK ) break; } rc2 = sqlite3_reset(pScan); @@ -183451,13 +202276,18 @@ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ /* ** Flush any data currently held in-memory to disk. */ -static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){ - if( bCommit && p->bTotalsValid ){ - int rc = fts5StorageSaveTotals(p); +static int sqlite3Fts5StorageSync(Fts5Storage *p){ + int rc = SQLITE_OK; + i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db); + if( p->bTotalsValid ){ + rc = fts5StorageSaveTotals(p); p->bTotalsValid = 0; - if( rc!=SQLITE_OK ) return rc; } - return sqlite3Fts5IndexSync(p->pIndex, bCommit); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexSync(p->pIndex); + } + sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid); + return rc; } static int sqlite3Fts5StorageRollback(Fts5Storage *p){ @@ -183493,8 +202323,6 @@ static int sqlite3Fts5StorageConfigValue( return rc; } - - /* ** 2014 May 31 ** @@ -183559,12 +202387,13 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){ ** Create an "ascii" tokenizer. */ static int fts5AsciiCreate( - void *pCtx, + void *pUnused, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; AsciiTokenizer *p = 0; + UNUSED_PARAM(pUnused); if( nArg%2 ){ rc = SQLITE_ERROR; }else{ @@ -183613,7 +202442,7 @@ static void asciiFold(char *aOut, const char *aIn, int nByte){ static int fts5AsciiTokenize( Fts5Tokenizer *pTokenizer, void *pCtx, - int flags, + int iUnused, const char *pText, int nText, int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) ){ @@ -183627,6 +202456,8 @@ static int fts5AsciiTokenize( char *pFold = aFold; unsigned char *a = p->aTokenChar; + UNUSED_PARAM(iUnused); + while( isnFold; const char *pEnd = &aFold[nFold-6]; + UNUSED_PARAM(iUnused); + /* Each iteration of this loop gobbles up a contiguous run of separators, ** then the next token. */ while( rc==SQLITE_OK ){ @@ -184717,7 +203552,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ - for(i=0; rc==SQLITE_OK && i<(int)ArraySize(aBuiltin); i++){ + for(i=0; rc==SQLITE_OK && ixCreateTokenizer(pApi, aBuiltin[i].zName, (void*)pApi, @@ -184858,9 +203693,9 @@ static int sqlite3Fts5UnicodeIsalnum(int c){ 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, }; - if( c<128 ){ + if( (unsigned int)c<128 ){ return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); - }else if( c<(1<<22) ){ + }else if( (unsigned int)c<(1<<22) ){ unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; int iRes = 0; int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; @@ -185427,7 +204262,10 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){ static int sqlite3Fts5GetVarintLen(u32 iVal){ +#if 0 if( iVal<(1 << 7 ) ) return 1; +#endif + assert( iVal>=(1 << 7) ); if( iVal<(1 << 14) ) return 2; if( iVal<(1 << 21) ) return 3; if( iVal<(1 << 28) ) return 4; @@ -185466,6 +204304,11 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){ ** the number of fts5 rows that contain at least one instance of term ** $term. Field $cnt is set to the total number of instances of term ** $term in the database. +** +** instance: +** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY()); +** +** One row for each term instance in the database. */ @@ -185481,7 +204324,7 @@ struct Fts5VocabTable { char *zFts5Db; /* Db containing fts5 table */ sqlite3 *db; /* Database handle */ Fts5Global *pGlobal; /* FTS5 global object for this database */ - int eType; /* FTS5_VOCAB_COL or ROW */ + int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */ }; struct Fts5VocabCursor { @@ -185501,16 +204344,22 @@ struct Fts5VocabCursor { i64 *aCnt; i64 *aDoc; - /* Output values used by 'row' and 'col' tables */ + /* Output values used by all tables. */ i64 rowid; /* This table's current rowid value */ Fts5Buffer term; /* Current value of 'term' column */ + + /* Output values Used by 'instance' tables only */ + i64 iInstPos; + int iInstOff; }; -#define FTS5_VOCAB_COL 0 -#define FTS5_VOCAB_ROW 1 +#define FTS5_VOCAB_COL 0 +#define FTS5_VOCAB_ROW 1 +#define FTS5_VOCAB_INSTANCE 2 #define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt" #define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt" +#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset" /* ** Bits for the mask used as the idxNum value by xBestIndex/xFilter. @@ -185538,6 +204387,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){ if( sqlite3_stricmp(zCopy, "row")==0 ){ *peType = FTS5_VOCAB_ROW; }else + if( sqlite3_stricmp(zCopy, "instance")==0 ){ + *peType = FTS5_VOCAB_INSTANCE; + }else { *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy); rc = SQLITE_ERROR; @@ -185598,7 +204450,8 @@ static int fts5VocabInitVtab( ){ const char *azSchema[] = { "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")", - "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")" + "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")", + "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")" }; Fts5VocabTable *pRet = 0; @@ -185621,7 +204474,7 @@ static int fts5VocabInitVtab( rc = fts5VocabTableType(zType, pzErr, &eType); if( rc==SQLITE_OK ){ - assert( eType>=0 && eType=0 && eType= ? +** +** are interpreted. Less-than and less-than-or-equal are treated +** identically, as are greater-than and greater-than-or-equal. */ static int fts5VocabBestIndexMethod( - sqlite3_vtab *pVTab, + sqlite3_vtab *pUnused, sqlite3_index_info *pInfo ){ int i; @@ -185684,6 +204546,8 @@ static int fts5VocabBestIndexMethod( int idxNum = 0; int nArg = 0; + UNUSED_PARAM(pUnused); + for(i=0; inConstraint; i++){ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; if( p->usable==0 ) continue; @@ -185714,8 +204578,19 @@ static int fts5VocabBestIndexMethod( } } - pInfo->idxNum = idxNum; + /* This virtual table always delivers results in ascending order of + ** the "term" column (column 0). So if the user has requested this + ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the + ** sqlite3_index_info.orderByConsumed flag to tell the core the results + ** are already in sorted order. */ + if( pInfo->nOrderBy==1 + && pInfo->aOrderBy[0].iColumn==0 + && pInfo->aOrderBy[0].desc==0 + ){ + pInfo->orderByConsumed = 1; + } + pInfo->idxNum = idxNum; return SQLITE_OK; } @@ -185802,6 +204677,54 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ return SQLITE_OK; } +static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){ + int rc = SQLITE_OK; + + if( sqlite3Fts5IterEof(pCsr->pIter) ){ + pCsr->bEof = 1; + }else{ + const char *zTerm; + int nTerm; + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( pCsr->nLeTerm>=0 ){ + int nCmp = MIN(nTerm, pCsr->nLeTerm); + int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); + if( bCmp<0 || (bCmp==0 && pCsr->nLeTermbEof = 1; + } + } + + sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); + } + return rc; +} + +static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ + int eDetail = pCsr->pConfig->eDetail; + int rc = SQLITE_OK; + Fts5IndexIter *pIter = pCsr->pIter; + i64 *pp = &pCsr->iInstPos; + int *po = &pCsr->iInstOff; + + while( eDetail==FTS5_DETAIL_NONE + || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) + ){ + pCsr->iInstPos = 0; + pCsr->iInstOff = 0; + + rc = sqlite3Fts5IterNextScan(pCsr->pIter); + if( rc==SQLITE_OK ){ + rc = fts5VocabInstanceNewTerm(pCsr); + if( eDetail==FTS5_DETAIL_NONE ) break; + } + if( rc ){ + pCsr->bEof = 1; + break; + } + } + + return rc; +} /* ** Advance the cursor to the next row in the table. @@ -185814,13 +204737,17 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ pCsr->rowid++; + if( pTab->eType==FTS5_VOCAB_INSTANCE ){ + return fts5VocabInstanceNext(pCsr); + } + if( pTab->eType==FTS5_VOCAB_COL ){ for(pCsr->iCol++; pCsr->iColiCol++){ - if( pCsr->aCnt[pCsr->iCol] ) break; + if( pCsr->aDoc[pCsr->iCol] ) break; } } - if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ + if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){ if( sqlite3Fts5IterEof(pCsr->pIter) ){ pCsr->bEof = 1; }else{ @@ -185844,31 +204771,63 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); while( rc==SQLITE_OK ){ - i64 dummy; + int eDetail = pCsr->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 */ - rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy); - if( rc==SQLITE_OK ){ - if( pTab->eType==FTS5_VOCAB_ROW ){ - while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ - pCsr->aCnt[0]++; - } - pCsr->aDoc[0]++; - }else{ - int iCol = -1; - while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ - int ii = FTS5_POS2COLUMN(iPos); - pCsr->aCnt[ii]++; - if( iCol!=ii ){ - pCsr->aDoc[ii]++; - iCol = ii; + pPos = pCsr->pIter->pData; + nPos = pCsr->pIter->nData; + + switch( pTab->eType ){ + case FTS5_VOCAB_ROW: + if( eDetail==FTS5_DETAIL_FULL ){ + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ + pCsr->aCnt[0]++; } } - } + pCsr->aDoc[0]++; + break; + + case FTS5_VOCAB_COL: + if( eDetail==FTS5_DETAIL_FULL ){ + 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; + break; + } + pCsr->aDoc[ii]++; + iCol = ii; + } + } + }else if( eDetail==FTS5_DETAIL_COLUMNS ){ + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ + assert_nc( iPos>=0 && iPos=nCol ){ + rc = FTS5_CORRUPT; + break; + } + pCsr->aDoc[iPos]++; + } + }else{ + assert( eDetail==FTS5_DETAIL_NONE ); + pCsr->aDoc[0]++; + } + break; + + default: + assert( pTab->eType==FTS5_VOCAB_INSTANCE ); + break; + } + + if( rc==SQLITE_OK ){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); } + if( pTab->eType==FTS5_VOCAB_INSTANCE ) break; if( rc==SQLITE_OK ){ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); @@ -185881,8 +204840,8 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ } } - if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ - while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++; + if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ + while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; assert( pCsr->iColpConfig->nCol ); } return rc; @@ -185894,11 +204853,13 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ static int fts5VocabFilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ - const char *idxStr, /* Unused */ - int nVal, /* Number of elements in apVal */ + const char *zUnused, /* Unused */ + int nUnused, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int eType = pTab->eType; int rc = SQLITE_OK; int iVal = 0; @@ -185910,6 +204871,8 @@ static int fts5VocabFilterMethod( sqlite3_value *pGe = 0; sqlite3_value *pLe = 0; + UNUSED_PARAM2(zUnused, nUnused); + fts5VocabResetCursor(pCsr); if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; @@ -185936,11 +204899,16 @@ static int fts5VocabFilterMethod( } } - if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); } - if( rc==SQLITE_OK ){ + 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) + ){ rc = fts5VocabNextMethod(pCursor); } @@ -185962,30 +204930,64 @@ static int fts5VocabColumnMethod( int iCol /* Index of column to read value from */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int eDetail = pCsr->pConfig->eDetail; + int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; + i64 iVal = 0; if( iCol==0 ){ sqlite3_result_text( pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT ); - } - else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){ + }else if( eType==FTS5_VOCAB_COL ){ assert( iCol==1 || iCol==2 || iCol==3 ); if( iCol==1 ){ - const char *z = pCsr->pConfig->azCol[pCsr->iCol]; - sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + if( eDetail!=FTS5_DETAIL_NONE ){ + const char *z = pCsr->pConfig->azCol[pCsr->iCol]; + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + } }else if( iCol==2 ){ - sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]); + iVal = pCsr->aDoc[pCsr->iCol]; }else{ - sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]); + iVal = pCsr->aCnt[pCsr->iCol]; } - }else{ + }else if( eType==FTS5_VOCAB_ROW ){ assert( iCol==1 || iCol==2 ); if( iCol==1 ){ - sqlite3_result_int64(pCtx, pCsr->aDoc[0]); + iVal = pCsr->aDoc[0]; }else{ - sqlite3_result_int64(pCtx, pCsr->aCnt[0]); + iVal = pCsr->aCnt[0]; + } + }else{ + assert( eType==FTS5_VOCAB_INSTANCE ); + switch( iCol ){ + case 1: + sqlite3_result_int64(pCtx, pCsr->pIter->iRowid); + break; + case 2: { + int ii = -1; + if( eDetail==FTS5_DETAIL_FULL ){ + ii = FTS5_POS2COLUMN(pCsr->iInstPos); + }else if( eDetail==FTS5_DETAIL_COLUMNS ){ + ii = (int)pCsr->iInstPos; + } + if( ii>=0 && iipConfig->nCol ){ + const char *z = pCsr->pConfig->azCol[ii]; + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + } + break; + } + default: { + assert( iCol==3 ); + if( eDetail==FTS5_DETAIL_FULL ){ + int ii = FTS5_POS2OFFSET(pCsr->iInstPos); + sqlite3_result_int(pCtx, ii); + } + break; + } } } + + if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); return SQLITE_OK; } @@ -186041,3 +205043,315 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ /************** End of fts5.c ************************************************/ +/************** Begin file stmt.c ********************************************/ +/* +** 2017-05-31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file demonstrates an eponymous virtual table that returns information +** about all prepared statements for the database connection. +** +** Usage example: +** +** .load ./stmt +** .mode line +** .header on +** SELECT * FROM stmt; +*/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) +#if !defined(SQLITEINT_H) +/* #include "sqlite3ext.h" */ +#endif +SQLITE_EXTENSION_INIT1 +/* #include */ +/* #include */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +/* stmt_vtab is a subclass of sqlite3_vtab which will +** serve as the underlying representation of a stmt virtual table +*/ +typedef struct stmt_vtab stmt_vtab; +struct stmt_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this stmt vtab */ +}; + +/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct stmt_cursor stmt_cursor; +struct stmt_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this cursor */ + sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */ + sqlite3_int64 iRowid; /* The rowid */ +}; + +/* +** The stmtConnect() method is invoked to create a new +** stmt_vtab that describes the stmt virtual table. +** +** Think of this routine as the constructor for stmt_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the stmt_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against stmt will look like. +*/ +static int stmtConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + stmt_vtab *pNew; + int rc; + +/* Column numbers */ +#define STMT_COLUMN_SQL 0 /* SQL for the statement */ +#define STMT_COLUMN_NCOL 1 /* Number of result columns */ +#define STMT_COLUMN_RO 2 /* True if read-only */ +#define STMT_COLUMN_BUSY 3 /* True if currently busy */ +#define STMT_COLUMN_NSCAN 4 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */ +#define STMT_COLUMN_NSORT 5 /* SQLITE_STMTSTATUS_SORT */ +#define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ +#define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ +#define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ +#define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ +#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ + + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," + "reprep,run,mem)"); + if( rc==SQLITE_OK ){ + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + pNew->db = db; + } + return rc; +} + +/* +** This method is the destructor for stmt_cursor objects. +*/ +static int stmtDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** Constructor for a new stmt_cursor object. +*/ +static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + stmt_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + pCur->db = ((stmt_vtab*)p)->db; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a stmt_cursor. +*/ +static int stmtClose(sqlite3_vtab_cursor *cur){ + sqlite3_free(cur); + return SQLITE_OK; +} + + +/* +** Advance a stmt_cursor to its next row of output. +*/ +static int stmtNext(sqlite3_vtab_cursor *cur){ + stmt_cursor *pCur = (stmt_cursor*)cur; + pCur->iRowid++; + pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt); + return SQLITE_OK; +} + +/* +** Return values of columns for the row at which the stmt_cursor +** is currently pointing. +*/ +static int stmtColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + stmt_cursor *pCur = (stmt_cursor*)cur; + switch( i ){ + case STMT_COLUMN_SQL: { + sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT); + break; + } + case STMT_COLUMN_NCOL: { + sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt)); + break; + } + case STMT_COLUMN_RO: { + sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt)); + break; + } + case STMT_COLUMN_BUSY: { + sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt)); + break; + } + case STMT_COLUMN_MEM: { + i = SQLITE_STMTSTATUS_MEMUSED + + STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP; + /* Fall thru */ + } + case STMT_COLUMN_NSCAN: + case STMT_COLUMN_NSORT: + case STMT_COLUMN_NAIDX: + case STMT_COLUMN_NSTEP: + case STMT_COLUMN_REPREP: + case STMT_COLUMN_RUN: { + sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt, + i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0)); + break; + } + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + stmt_cursor *pCur = (stmt_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int stmtEof(sqlite3_vtab_cursor *cur){ + stmt_cursor *pCur = (stmt_cursor*)cur; + return pCur->pStmt==0; +} + +/* +** This method is called to "rewind" the stmt_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to stmtColumn() or stmtRowid() or +** stmtEof(). +*/ +static int stmtFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + stmt_cursor *pCur = (stmt_cursor *)pVtabCursor; + pCur->pStmt = 0; + pCur->iRowid = 0; + return stmtNext(pVtabCursor); +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the stmt virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int stmtBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)500; + pIdxInfo->estimatedRows = 500; + return SQLITE_OK; +} + +/* +** This following structure defines all the methods for the +** stmt virtual table. +*/ +static sqlite3_module stmtModule = { + 0, /* iVersion */ + 0, /* xCreate */ + stmtConnect, /* xConnect */ + stmtBestIndex, /* xBestIndex */ + stmtDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + stmtOpen, /* xOpen - open a cursor */ + stmtClose, /* xClose - close a cursor */ + stmtFilter, /* xFilter - configure scan constraints */ + stmtNext, /* xNext - advance a cursor */ + stmtEof, /* xEof - check for end of scan */ + stmtColumn, /* xColumn - read data */ + stmtRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ +}; + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0); +#endif + return rc; +} + +#ifndef SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_stmt_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3StmtVtabInit(db); +#endif + return rc; +} +#endif /* SQLITE_CORE */ +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ + +/************** End of stmt.c ************************************************/ +#if __LINE__!=205346 +#undef SQLITE_SOURCE_ID +#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de4alt2" +#endif +/* Return the source-id for this library */ +SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +/************************** End of sqlite3.c ******************************/ +#else // USE_LIBSQLITE3 + // If users really want to link against the system sqlite3 we +// need to make this file a noop. + #endif \ No newline at end of file diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h index c6d1e0f233b..76a72872c4a 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h @@ -1,5 +1,6 @@ +#ifndef USE_LIBSQLITE3 /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -30,8 +31,8 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ -#ifndef _SQLITE3_H_ -#define _SQLITE3_H_ +#ifndef SQLITE3_H +#define SQLITE3_H #include /* Needed for the definition of va_list */ /* @@ -54,8 +55,17 @@ extern "C" { #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif +#ifndef SQLITE_APICALL +# define SQLITE_APICALL +#endif #ifndef SQLITE_STDCALL -# define SQLITE_STDCALL +# define SQLITE_STDCALL SQLITE_APICALL +#endif +#ifndef SQLITE_CALLBACK +# define SQLITE_CALLBACK +#endif +#ifndef SQLITE_SYSAPI +# define SQLITE_SYSAPI #endif /* @@ -99,25 +109,28 @@ extern "C" { ** be held constant and Z will be incremented or else Y will be incremented ** and Z will be reset to zero. ** -** Since version 3.6.18, SQLite source code has been stored in the +** Since [version 3.6.18] ([dateof:3.6.18]), +** SQLite source code has been stored in the ** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID -** string contains the date and time of the check-in (UTC) and an SHA1 -** hash of the entire source tree. +** string contains the date and time of the check-in (UTC) and a SHA1 +** or SHA3-256 hash of the entire source tree. If the source code has +** been edited in any way since it was last checked in, then the last +** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.10.2" -#define SQLITE_VERSION_NUMBER 3010002 -#define SQLITE_SOURCE_ID "2016-01-20 15:27:19 17efb4209f97fb4971656086b138599a91a75ff9" +#define SQLITE_VERSION "3.21.0" +#define SQLITE_VERSION_NUMBER 3021000 +#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827" /* ** CAPI3REF: Run-Time Library Version Numbers -** KEYWORDS: sqlite3_version, sqlite3_sourceid +** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros @@ -129,7 +142,7 @@ extern "C" { ** **
     ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
    -** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
    +** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
     ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
     ** 
    )^ ** @@ -139,16 +152,18 @@ extern "C" { ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. +** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built +** using an edited copy of [the amalgamation], then the last four characters +** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ SQLITE_API SQLITE_EXTERN const char sqlite3_version[]; -SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void); -SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void); -SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void); +SQLITE_API const char *sqlite3_libversion(void); +SQLITE_API const char *sqlite3_sourceid(void); +SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics @@ -173,8 +188,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void); ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS -SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName); -SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N); +SQLITE_API int sqlite3_compileoption_used(const char *zOptName); +SQLITE_API const char *sqlite3_compileoption_get(int N); #endif /* @@ -213,7 +228,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N); ** ** See the [threading mode] documentation for additional information. */ -SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void); +SQLITE_API int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle @@ -249,7 +264,11 @@ typedef struct sqlite3 sqlite3; */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; - typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +# ifdef SQLITE_UINT64_TYPE + typedef SQLITE_UINT64_TYPE sqlite_uint64; +# else + typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +# endif #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 sqlite_int64; typedef unsigned __int64 sqlite_uint64; @@ -310,8 +329,8 @@ typedef sqlite_uint64 sqlite3_uint64; ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer ** argument is a harmless no-op. */ -SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*); -SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*); +SQLITE_API int sqlite3_close(sqlite3*); +SQLITE_API int sqlite3_close_v2(sqlite3*); /* ** The type for a callback function. @@ -347,7 +366,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** from [sqlite3_malloc()] and passed back through the 5th parameter. ** To avoid memory leaks, the application should invoke [sqlite3_free()] ** on error message strings returned through the 5th parameter of -** of sqlite3_exec() after the error message string is no longer needed. +** sqlite3_exec() after the error message string is no longer needed. ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to ** NULL before returning. @@ -382,7 +401,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. ** */ -SQLITE_API int SQLITE_STDCALL sqlite3_exec( +SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ @@ -403,7 +422,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ @@ -418,7 +437,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -426,7 +445,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ @@ -443,7 +462,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( ** [result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to -** address this, newer versions of SQLite (version 3.3.8 and later) include +** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] +** and later) include ** support for additional result codes that provide more detailed information ** about errors. These [extended result codes] are enabled or disabled ** on a per database connection basis using the @@ -479,6 +499,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) @@ -506,6 +529,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations @@ -560,10 +584,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN -** flag indicate that a file cannot be deleted when open. The +** flag indicates that a file cannot be deleted when open. The ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. +** +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying +** filesystem supports doing multiple write operations atomically when those +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -579,6 +608,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec( #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -710,6 +740,10 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_ATOMIC64K] **
  • [SQLITE_IOCAP_SAFE_APPEND] **
  • [SQLITE_IOCAP_SEQUENTIAL] +**
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] +**
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] +**
  • [SQLITE_IOCAP_IMMUTABLE] +**
  • [SQLITE_IOCAP_BATCH_ATOMIC] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -838,7 +872,7 @@ struct sqlite3_io_methods { ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two -** integers where the first integer i the new retry count and the second +** integers where the first integer is the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be @@ -966,6 +1000,12 @@ struct sqlite3_io_methods { ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** +**
  • [[SQLITE_FCNTL_WIN32_GET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the +** underlying native file handle associated with a file handle. This file +** control interprets its argument as a pointer to a native file handle and +** writes the resulting value there. +** **
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] ** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This ** opcode causes the xFileControl method to swap the file handle with the one @@ -987,6 +1027,40 @@ struct sqlite3_io_methods { ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for ** this opcode. +** +**
  • [[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then +** the file descriptor is placed in "batch write mode", which +** means all subsequent write operations will be deferred and done +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems +** that do not support batch atomic writes will return SQLITE_NOTFOUND. +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make +** no VFS interface calls on the same [sqlite3_file] file descriptor +** except for calls to the xWrite method and the xFileControl method +** with [SQLITE_FCNTL_SIZE_HINT]. +** +**
  • [[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. +** This file control returns [SQLITE_OK] if and only if the writes were +** all performed successfully and have been committed to persistent storage. +** ^Regardless of whether or not it is successful, this file control takes +** the file descriptor out of batch write mode so that all subsequent +** write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +**
  • [[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. +** ^This file control takes the file descriptor out of batch write mode +** so that all subsequent write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1016,6 +1090,11 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_RBU 26 #define SQLITE_FCNTL_VFS_POINTER 27 #define SQLITE_FCNTL_JOURNAL_POINTER 28 +#define SQLITE_FCNTL_WIN32_GET_HANDLE 29 +#define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1035,6 +1114,16 @@ struct sqlite3_io_methods { */ typedef struct sqlite3_mutex sqlite3_mutex; +/* +** CAPI3REF: Loadable Extension Thunk +** +** A pointer to the opaque sqlite3_api_routines structure is passed as +** the third parameter to entry points of [loadable extensions]. This +** structure must be typedefed in order to work around compiler warnings +** on some platforms. +*/ +typedef struct sqlite3_api_routines sqlite3_api_routines; + /* ** CAPI3REF: OS Interface Object ** @@ -1228,7 +1317,7 @@ struct sqlite3_vfs { const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. - ** New fields may be appended in figure versions. The iVersion + ** New fields may be appended in future versions. The iVersion ** value will increment whenever this happens. */ }; @@ -1370,10 +1459,10 @@ struct sqlite3_vfs { ** must return [SQLITE_OK] on success and some other [error code] upon ** failure. */ -SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void); -SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void); -SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void); -SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void); +SQLITE_API int sqlite3_initialize(void); +SQLITE_API int sqlite3_shutdown(void); +SQLITE_API int sqlite3_os_init(void); +SQLITE_API int sqlite3_os_end(void); /* ** CAPI3REF: Configuring The SQLite Library @@ -1406,7 +1495,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void); ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. */ -SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...); +SQLITE_API int sqlite3_config(int, ...); /* ** CAPI3REF: Configure database connections @@ -1425,7 +1514,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...); ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if ** the call is considered successful. */ -SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...); +SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); /* ** CAPI3REF: Memory Allocation Routines @@ -1576,6 +1665,16 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example. ** +** [[SQLITE_CONFIG_SMALL_MALLOC]]
    SQLITE_CONFIG_SMALL_MALLOC
    +**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +** type int, interpreted as a boolean, which if true provides a hint to +** SQLite that it should avoid large memory allocations if possible. +** SQLite will run faster if it is free to make large memory allocations, +** but some application might prefer to run slower in exchange for +** guarantees about memory fragmentation that are possible if large +** allocations are avoided. This hint is normally off. +**
    +** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    **
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of @@ -1593,25 +1692,7 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_CONFIG_SCRATCH]]
    SQLITE_CONFIG_SCRATCH
    -**
    ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte -** aligned memory buffer from which the scratch allocations will be -** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ -** The first argument must be a pointer to an 8-byte aligned buffer -** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional -** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.

    -** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. +**

    The SQLITE_CONFIG_SCRATCH option is no longer used. **
    ** ** [[SQLITE_CONFIG_PAGECACHE]]
    SQLITE_CONFIG_PAGECACHE
    @@ -1647,8 +1728,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_CONFIG_HEAP]]
    SQLITE_CONFIG_HEAP
    **
    ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and -** [SQLITE_CONFIG_PAGECACHE]. +** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. @@ -1820,6 +1900,20 @@ struct sqlite3_mem_methods { ** is enabled (using the [PRAGMA threads] command) and the amount of content ** to be sorted exceeds the page size times the minimum of the ** [PRAGMA cache_size] setting and this value. +** +** [[SQLITE_CONFIG_STMTJRNL_SPILL]] +**
    SQLITE_CONFIG_STMTJRNL_SPILL +**
    ^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which +** becomes the [statement journal] spill-to-disk threshold. +** [Statement journals] are held in memory until their size (in bytes) +** exceeds this threshold, at which point they are written to disk. +** Or if the threshold is -1, statement journals are always held +** exclusively in memory. +** Since many statement journals never become large, setting the spill +** threshold to a value such as 64KiB can greatly reduce the amount of +** I/O required to support statement rollback. +** The default value for this setting is controlled by the +** [SQLITE_STMTJRNL_SPILL] compile-time option. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -1827,7 +1921,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ @@ -1847,6 +1941,8 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ +#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options @@ -1904,11 +2000,78 @@ 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
    +**
    ^This option is used to enable or disable the two-argument +** version of 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 +** positive to enable fts3_tokenizer() 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 fts3_tokenizer is disabled or enabled +** 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
    +**
    ^This option is used to enable or disable the [sqlite3_load_extension()] +** interface independently of the [load_extension()] SQL function. +** The [sqlite3_enable_load_extension()] API enables or disables both the +** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. +** There should be two additional arguments. +** When the first argument to this interface is 1, then only the C-API is +** enabled and the SQL function remains disabled. If the first argument to +** this interface is 0, then both the C-API and the SQL function are disabled. +** If the first argument is -1, then no changes are made to state of either the +** C-API or the SQL function. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface +** is disabled or enabled following this call. The second parameter may +** be a NULL pointer, in which case the new setting is not reported back. +**
    +** +**
    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 +** does not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into this DBCONFIG option is unchanged +** until after the database connection closes. +**
    +** +**
    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 +** connections at all to the database. If so, it performs a checkpoint +** operation before closing the connection. This option may be used to +** override this behaviour. The first parameter passed to this operation +** is an integer - non-zero to disable checkpoints-on-close, or zero (the +** default) to enable them. The second parameter is a pointer to an integer +** into which is written 0 or 1 to indicate whether checkpoints-on-close +** have been disabled - 0 if they are not disabled, 1 if they are. +**
    +** +**
    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 +** of values of [bound parameters].)^ The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +**
    +** ** */ -#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ -#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ -#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ +#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ /* @@ -1919,7 +2082,7 @@ struct sqlite3_mem_methods { ** [extended result codes] feature of SQLite. ^The extended result ** codes are disabled by default for historical compatibility. */ -SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff); +SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid @@ -1933,20 +2096,30 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff) ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** -** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the -** most recent successful [INSERT] into a rowid table or [virtual table] -** on database connection D. -** ^Inserts into [WITHOUT ROWID] tables are not recorded. -** ^If no successful [INSERT]s into rowid tables -** have ever occurred on the database connection D, -** then sqlite3_last_insert_rowid(D) returns zero. +** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of +** the most recent successful [INSERT] into a rowid table or [virtual table] +** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not +** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred +** on the database connection D, then sqlite3_last_insert_rowid(D) returns +** zero. ** -** ^(If an [INSERT] occurs within a trigger or within a [virtual table] -** method, then this routine will return the [rowid] of the inserted -** row as long as the trigger or virtual table method is running. -** But once the trigger or virtual table method ends, the value returned -** by this routine reverts to what it was before the trigger or virtual -** table method began.)^ +** As well as being set automatically as rows are inserted into database +** tables, the value returned by this function may be set explicitly by +** [sqlite3_set_last_insert_rowid()] +** +** Some virtual table implementations may INSERT rows into rowid tables as +** part of committing a transaction (e.g. to flush data accumulated in memory +** to disk). In this case subsequent calls to this function return the rowid +** associated with these internal INSERT operations, which leads to +** unintuitive results. Virtual table implementations that do write to rowid +** tables in this way can avoid this problem by restoring the original +** rowid value using [sqlite3_set_last_insert_rowid()] before returning +** control to the user. +** +** ^(If an [INSERT] occurs within a trigger then this routine will +** return the [rowid] of the inserted row as long as the trigger is +** running. Once the trigger program ends, the value returned +** by this routine reverts to what it was before the trigger was fired.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this @@ -1971,7 +2144,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff) ** unpredictable and might not equal either the old or the new ** last insert [rowid]. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + +/* +** CAPI3REF: Set the Last Insert Rowid value. +** METHOD: sqlite3 +** +** The sqlite3_set_last_insert_rowid(D, R) method allows the application to +** set the value returned by calling sqlite3_last_insert_rowid(D) to R +** without inserting a row into the database. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified @@ -2024,7 +2207,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*); ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. */ -SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*); +SQLITE_API int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified @@ -2048,7 +2231,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*); ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. */ -SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*); +SQLITE_API int sqlite3_total_changes(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query @@ -2084,11 +2267,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*); ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. -** -** If the database connection closes while [sqlite3_interrupt()] -** is running then bad things will likely happen. */ -SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*); +SQLITE_API void sqlite3_interrupt(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete @@ -2123,8 +2303,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*); ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ -SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql); -SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql); +SQLITE_API int sqlite3_complete(const char *sql); +SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors @@ -2185,7 +2365,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql); ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); +SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); /* ** CAPI3REF: Set A Busy Timeout @@ -2208,7 +2388,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), ** ** See also: [PRAGMA busy_timeout] */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms); +SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries @@ -2283,7 +2463,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms); ** reflected in subsequent calls to [sqlite3_errcode()] or ** [sqlite3_errmsg()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_get_table( +SQLITE_API int sqlite3_get_table( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ char ***pazResult, /* Results of the query */ @@ -2291,7 +2471,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table( int *pnColumn, /* Number of result columns written here */ char **pzErrmsg /* Error msg written here */ ); -SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result); +SQLITE_API void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions @@ -2397,10 +2577,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result); ** addition that after the string has been read and copied into ** the result, [sqlite3_free()] is called on the input string.)^ */ -SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...); -SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list); -SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...); -SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list); +SQLITE_API char *sqlite3_mprintf(const char*,...); +SQLITE_API char *sqlite3_vmprintf(const char*, va_list); +SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); +SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* ** CAPI3REF: Memory Allocation Subsystem @@ -2490,12 +2670,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list ** a block of memory after it has been released using ** [sqlite3_free()] or [sqlite3_realloc()]. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int); -SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64); -SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int); -SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64); -SQLITE_API void SQLITE_STDCALL sqlite3_free(void*); -SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*); +SQLITE_API void *sqlite3_malloc(int); +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); +SQLITE_API void *sqlite3_realloc(void*, int); +SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); +SQLITE_API void sqlite3_free(void*); +SQLITE_API sqlite3_uint64 sqlite3_msize(void*); /* ** CAPI3REF: Memory Allocator Statistics @@ -2520,8 +2700,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*); ** by [sqlite3_memory_highwater(1)] is the high-water mark ** prior to the reset. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag); +SQLITE_API sqlite3_int64 sqlite3_memory_used(void); +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); /* ** CAPI3REF: Pseudo-Random Number Generator @@ -2544,17 +2724,19 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag); ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ -SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); +SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** METHOD: sqlite3 +** KEYWORDS: {authorizer callback} ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], +** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should @@ -2576,8 +2758,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters -** to the callback are zero-terminated strings that contain additional -** details about the action to be authorized. +** to the callback are either NULL pointers or zero-terminated strings +** that contain additional details about the action to be authorized. +** Applications must always be prepared to encounter a NULL pointer in any +** of the third through the sixth parameters of the authorization callback. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the @@ -2586,6 +2770,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. +** ^When a table is referenced by a [SELECT] but no column values are +** extracted from that table (for example in a query like +** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback +** is invoked once for that table with a column name that is an empty string. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. @@ -2627,7 +2815,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P); ** as stated in the previous paragraph, sqlite3_step() invokes ** sqlite3_prepare_v2() to reprepare a statement after a schema change. */ -SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( +SQLITE_API int sqlite3_set_authorizer( sqlite3*, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pUserData @@ -2707,6 +2895,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 ** +** These routines are deprecated. Use the [sqlite3_trace_v2()] interface +** instead of the routines described here. +** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** @@ -2732,10 +2923,104 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer( ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); -SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*, +SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); +/* +** CAPI3REF: SQL Trace Event Codes +** KEYWORDS: SQLITE_TRACE +** +** These constants identify classes of events that can be monitored +** using the [sqlite3_trace_v2()] tracing logic. The third argument +** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** the following constants. ^The first argument to the trace callback +** is one of the following constants. +** +** New tracing constants may be added in future releases. +** +** ^A trace callback has four arguments: xCallback(T,C,P,X). +** ^The T argument is one of the integer type codes above. +** ^The C argument is a copy of the context pointer passed in as the +** fourth argument to [sqlite3_trace_v2()]. +** The P and X arguments are pointers whose meanings depend on T. +** +**
    +** [[SQLITE_TRACE_STMT]]
    SQLITE_TRACE_STMT
    +**
    ^An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. ^The P argument is a pointer to the +** [prepared statement]. ^The X argument is a pointer to a string which +** is the unexpanded SQL text of the prepared statement or an SQL comment +** that indicates the invocation of a trigger. ^The callback can compute +** the same text that would have been returned by the legacy [sqlite3_trace()] +** interface by using the X argument when X begins with "--" and invoking +** [sqlite3_expanded_sql(P)] otherwise. +** +** [[SQLITE_TRACE_PROFILE]]
    SQLITE_TRACE_PROFILE
    +**
    ^An SQLITE_TRACE_PROFILE callback provides approximately the same +** information as is provided by the [sqlite3_profile()] callback. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. +** +** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    +**
    ^An SQLITE_TRACE_ROW callback is invoked whenever a prepared +** statement generates a single row of result. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument is unused. +** +** [[SQLITE_TRACE_CLOSE]]
    SQLITE_TRACE_CLOSE
    +**
    ^An SQLITE_TRACE_CLOSE callback is invoked when a database +** connection closes. +** ^The P argument is a pointer to the [database connection] object +** and the X argument is unused. +**
    +*/ +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + +/* +** CAPI3REF: SQL Trace Hook +** METHOD: sqlite3 +** +** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback +** function X against [database connection] D, using property mask M +** and context pointer P. ^If the X callback is +** NULL or if the M mask is zero, then tracing is disabled. The +** M argument should be the bitwise OR-ed combination of +** zero or more [SQLITE_TRACE] constants. +** +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). +** +** ^The X callback is invoked whenever any of the events identified by +** mask M occur. ^The integer return value from the callback is currently +** ignored, though this may change in future releases. Callback +** implementations should return zero to ensure future compatibility. +** +** ^A trace callback is invoked with four arguments: callback(T,C,P,X). +** ^The T argument is one of the [SQLITE_TRACE] +** constants to indicate why the callback was invoked. +** ^The C argument is a copy of the context pointer. +** The P and X arguments are pointers whose meanings depend on T. +** +** The sqlite3_trace_v2() interface is intended to replace the legacy +** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which +** are deprecated. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); + /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 @@ -2768,7 +3053,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*, ** database connections for the meaning of "modify" in this paragraph. ** */ -SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); +SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection @@ -2858,10 +3143,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the fourth argument to sqlite3_open_v2(), or if it has +** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** As of SQLite version 3.7.7, URI filename interpretation is turned off +** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. @@ -2997,15 +3282,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo ** ** See also: [sqlite3_temp_directory] */ -SQLITE_API int SQLITE_STDCALL sqlite3_open( +SQLITE_API int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_open16( +SQLITE_API int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_open_v2( +SQLITE_API int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ @@ -3051,9 +3336,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2( ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam); -SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64); +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); +SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); /* @@ -3097,11 +3382,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha ** was invoked incorrectly by the application. In that case, the ** error code and message may or may not be set. */ -SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db); -SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db); -SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*); -SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int); +SQLITE_API int sqlite3_errcode(sqlite3 *db); +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); +SQLITE_API const char *sqlite3_errmsg(sqlite3*); +SQLITE_API const void *sqlite3_errmsg16(sqlite3*); +SQLITE_API const char *sqlite3_errstr(int); /* ** CAPI3REF: Prepared Statement Object @@ -3169,7 +3454,7 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** ** New run-time limit categories may be added in future releases. */ -SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); +SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories @@ -3200,9 +3485,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_VDBE_OP]] ^(
    SQLITE_LIMIT_VDBE_OP
    **
    The maximum number of instructions in a virtual machine program -** used to implement an SQL statement. This limit is not currently -** enforced, though that might be added in some future release of -** SQLite.
    )^ +** used to implement an SQL statement. If [sqlite3_prepare_v2()] or +** the equivalent tries to allocate space for more than this many opcodes +** in a single prepared statement, an SQLITE_NOMEM error is returned.)^ ** ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
    SQLITE_LIMIT_FUNCTION_ARG
    **
    The maximum number of arguments on a function.
    )^ @@ -3240,23 +3525,59 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +/* +** CAPI3REF: Prepare Flags +** +** These constants define various flags that can be passed into +** "prepFlags" parameter of the [sqlite3_prepare_v3()] and +** [sqlite3_prepare16_v3()] interfaces. +** +** New flags may be added in future releases of SQLite. +** +**
    +** [[SQLITE_PREPARE_PERSISTENT]] ^(
    SQLITE_PREPARE_PERSISTENT
    +**
    The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner +** that the prepared statement will be retained for a long time and +** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] +** and [sqlite3_prepare16_v3()] assume that the prepared statement will +** be used just once or at most a few times and then destroyed using +** [sqlite3_finalize()] relatively soon. The current implementation acts +** 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. +**
    +*/ +#define SQLITE_PREPARE_PERSISTENT 0x01 + /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** -** To execute an SQL query, it must first be compiled into a byte-code -** program using one of these routines. +** To execute an SQL statement, it must first be compiled into a byte-code +** program using one of these routines. Or, in other words, these routines +** are constructors for the [prepared statement] object. +** +** The preferred routine to use is [sqlite3_prepare_v2()]. The +** [sqlite3_prepare()] interface is legacy and should be avoided. +** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used +** for special purposes. +** +** The use of the UTF-8 interfaces is preferred, as SQLite currently +** does all parsing using UTF-8. The UTF-16 interfaces are provided +** as a convenience. The UTF-16 interfaces work by converting the +** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() -** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() -** use UTF-16. +** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), +** and sqlite3_prepare_v3() +** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the @@ -3283,10 +3604,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** -** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are -** recommended for all new programs. The two older interfaces are retained -** for backwards compatibility, but their use is discouraged. -** ^In the "v2" interfaces, the prepared statement +** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. +** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) +** are retained for backwards compatibility, but their use is discouraged. +** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: @@ -3319,46 +3641,93 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal); ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. **
  • +** +**

    ^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having +** the extra prepFlags parameter, which is a bit array consisting of zero or +** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The +** sqlite3_prepare_v2() interface works exactly the same as +** sqlite3_prepare_v3() with a zero prepFlags parameter. ** */ -SQLITE_API int SQLITE_STDCALL sqlite3_prepare( +SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2( +SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_prepare16( +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2( +SQLITE_API int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** -** ^This interface can be used to retrieve a saved copy of the original -** SQL text used to create a [prepared statement] if that statement was -** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], +** [sqlite3_prepare16_v2()], or [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. +** +** ^(For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL".)^ +** +** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory +** is available to hold the result, or if the result would exceed the +** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** +** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of +** 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 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 *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -3389,8 +3758,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt); ** sqlite3_stmt_readonly() to return true since, while those statements ** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. +** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since +** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and +** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so +** sqlite3_stmt_readonly() returns false for those commands. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset @@ -3411,7 +3784,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt); ** for example, in diagnostic routines to search for prepared ** statements that are holding a transaction open. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*); +SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); /* ** CAPI3REF: Dynamically Typed Value Object @@ -3447,12 +3820,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*); ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used with -** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** Unprotected sqlite3_value objects may only be used as arguments +** to [sqlite3_result_value()], [sqlite3_bind_value()], and +** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ -typedef struct Mem sqlite3_value; +typedef struct sqlite3_value sqlite3_value; /* ** CAPI3REF: SQL Function Context Object @@ -3554,6 +3928,15 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** +** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in +** [prepared statement] S to have an SQL value of NULL, but to also be +** associated with the pointer P of type T. ^D is either a NULL pointer or +** a pointer to a destructor function for P. ^SQLite will invoke the +** destructor D with a single argument of P when it is finished using +** P. The T parameter should be a static string, preferably a string +** literal. The sqlite3_bind_pointer() routine is part of the +** [pointer passing interface] added for SQLite 3.20.0. +** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], @@ -3575,20 +3958,21 @@ typedef struct sqlite3_context sqlite3_context; ** See also: [sqlite3_bind_parameter_count()], ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, +SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, +SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); +SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); +SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); +SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); -SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); +SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); +SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); /* ** CAPI3REF: Number Of SQL Parameters @@ -3609,7 +3993,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite ** [sqlite3_bind_parameter_name()], and ** [sqlite3_bind_parameter_index()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*); +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); /* ** CAPI3REF: Name Of A Host Parameter @@ -3630,14 +4014,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*); ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()] or -** [sqlite3_prepare16_v2()]. +** originally specified as UTF-16 in [sqlite3_prepare16()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_index()]. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int); +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); /* ** CAPI3REF: Index Of A Parameter With A Given Name @@ -3648,13 +4032,14 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or +** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_name()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /* ** CAPI3REF: Reset All Bindings On A Prepared Statement @@ -3664,19 +4049,23 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const ** the [sqlite3_bind_blob | bindings] on a [prepared statement]. ** ^Use this routine to reset all host parameters to NULL. */ -SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*); +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); /* ** CAPI3REF: Number Of Columns In A Result Set ** METHOD: sqlite3_stmt ** ** ^Return the number of columns in the result set returned by the -** [prepared statement]. ^This routine returns 0 if pStmt is an SQL -** statement that does not return data (for example an [UPDATE]). +** [prepared statement]. ^If this routine returns 0, that means the +** [prepared statement] returns no data (for example an [UPDATE]). +** ^However, just because this routine returns a positive number does not +** mean that one or more rows of data will be returned. ^A SELECT statement +** will always have a positive sqlite3_column_count() but depending on the +** WHERE clause constraints and the table content, it might return no rows. ** ** See also: [sqlite3_data_count()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Column Names In A Result Set @@ -3705,8 +4094,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt); ** then the name of the column is unspecified and may change from ** one release of SQLite to the next. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N); +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); /* ** CAPI3REF: Source Of Data In A Query Result @@ -3754,12 +4143,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N ** for the same [prepared statement] and result column ** at the same time then the results are undefined. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int); -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int); -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); /* ** CAPI3REF: Declared Datatype Of A Query Result @@ -3791,23 +4180,25 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt* ** is associated with individual values, not with the containers ** used to hold those values. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); /* ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** -** After a [prepared statement] has been prepared using either -** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** After a [prepared statement] has been prepared using any of +** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], +** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "v2" interface -** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy -** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "v2" interface is recommended for new applications but the legacy +** on whether the statement was prepared using the newer "vX" interfaces +** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], +** [sqlite3_prepare16_v2()] or the older legacy +** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], @@ -3853,7 +4244,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility ** break because any application that ever receives an SQLITE_MISUSE error @@ -3867,12 +4259,13 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements -** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] +** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "v2" interface is recommended. +** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ -SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*); +SQLITE_API int sqlite3_step(sqlite3_stmt*); /* ** CAPI3REF: Number of columns in a result set @@ -3893,7 +4286,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*); ** ** See also: [sqlite3_column_count()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Fundamental Datatypes @@ -3932,6 +4325,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** +** Summary: +**

    +**
    sqlite3_column_blob→BLOB result +**
    sqlite3_column_double→REAL result +**
    sqlite3_column_int→32-bit INTEGER result +**
    sqlite3_column_int64→64-bit INTEGER result +**
    sqlite3_column_text→UTF-8 TEXT result +**
    sqlite3_column_text16→UTF-16 TEXT result +**
    sqlite3_column_value→The result as an +** [sqlite3_value|unprotected sqlite3_value] object. +**
        +**
    sqlite3_column_bytes→Size of a BLOB +** or a UTF-8 TEXT result in bytes +**
    sqlite3_column_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_column_type→Default +** datatype of the result +**
    +** +** Details: +** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] @@ -3953,16 +4368,29 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** +** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) +** each return the value of a result column in a specific data format. If +** the result column is not initially in the requested format (for example, +** if the query returns an integer but the sqlite3_column_text() interface +** is used to extract the value) then an automatic type conversion is performed. +** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value -** returned by sqlite3_column_type() is only meaningful if no type -** conversions have occurred as described below. After a type conversion, -** the value returned by sqlite3_column_type() is undefined. Future +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. +** The return value of sqlite3_column_type() can be used to decide which +** of the first six interface should be used to extract the column value. +** The value returned by sqlite3_column_type() is only meaningful if no +** automatic type conversions have occurred for the value in question. +** After a type conversion, the result of calling sqlite3_column_type() +** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** +** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() +** or sqlite3_column_bytes16() interfaces can be used to determine the size +** of that BLOB or string. +** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts @@ -3999,9 +4427,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** Hence, the sqlite3_column_value() interface +** is normally only useful within the implementation of +** [application-defined SQL functions] or [virtual tables], not within +** top-level application code. ** -** These routines attempt to convert the value where appropriate. ^For -** example, if the internal representation is FLOAT and a text result +** The these routines may attempt to convert the datatype of the result. +** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: @@ -4073,7 +4505,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do not pass the pointers returned +** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** @@ -4083,16 +4515,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt); ** pointer. Subsequent calls to [sqlite3_errcode()] will return ** [SQLITE_NOMEM].)^ */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol); -SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol); -SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol); -SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol); -SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); +SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object @@ -4120,7 +4552,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int ** statement after it has been finalized can result in undefined and ** undesirable behavior such as segfaults and heap corruption. */ -SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); /* ** CAPI3REF: Reset A Prepared Statement Object @@ -4147,7 +4579,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt); ** ^The [sqlite3_reset(S)] interface does not change the values ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ -SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt); +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions @@ -4247,7 +4679,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt); ** close the database connection nor finalize or reset the prepared ** statement in which the function is running. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_function( +SQLITE_API int sqlite3_create_function( sqlite3 *db, const char *zFunctionName, int nArg, @@ -4257,7 +4689,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function( void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( +SQLITE_API int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, @@ -4267,7 +4699,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16( void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( +SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunctionName, int nArg, @@ -4313,12 +4745,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( ** these functions, we will not explain what they do. */ #ifndef SQLITE_OMIT_DEPRECATED -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void); -SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void); -SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), +SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); +SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), void*,sqlite3_int64); #endif @@ -4326,21 +4758,40 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** -** The C-language implementation of SQL functions and aggregates uses -** this set of interface routines to access the parameter values on -** the function or aggregate. +** Summary: +**
    +**
    sqlite3_value_blob→BLOB value +**
    sqlite3_value_double→REAL value +**
    sqlite3_value_int→32-bit INTEGER value +**
    sqlite3_value_int64→64-bit INTEGER value +**
    sqlite3_value_pointer→Pointer value +**
    sqlite3_value_text→UTF-8 TEXT value +**
    sqlite3_value_text16→UTF-16 TEXT value in +** the native byteorder +**
    sqlite3_value_text16be→UTF-16be TEXT value +**
    sqlite3_value_text16le→UTF-16le TEXT value +**
        +**
    sqlite3_value_bytes→Size of a BLOB +** or a UTF-8 TEXT in bytes +**
    sqlite3_value_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_value_type→Default +** datatype of the value +**
    sqlite3_value_numeric_type   +** →  Best numeric datatype of the value +**
    ** -** The xFunc (for scalar functions) or xStep (for aggregates) parameters -** to [sqlite3_create_function()] and [sqlite3_create_function16()] -** define callbacks that implement the SQL functions and aggregates. -** The 3rd parameter to these callbacks is an array of pointers to -** [protected sqlite3_value] objects. There is one [sqlite3_value] object for -** each parameter to the SQL function. These routines are used to -** extract values from the [sqlite3_value] objects. +** Details: +** +** These routines extract type, size, and content information from +** [protected sqlite3_value] objects. Protected sqlite3_value objects +** are used to pass parameter information into implementation of +** [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] -** object results in undefined behavior. +** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object @@ -4351,6 +4802,24 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** +** ^If [sqlite3_value] object V was initialized +** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] +** and if X and Y are strings that compare equal according to strcmp(X,Y), +** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, +** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** +** ^(The sqlite3_value_type(V) interface returns the +** [SQLITE_INTEGER | datatype code] for the initial datatype of the +** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ +** Other interfaces might change the datatype for an sqlite3_value object. +** For example, if the datatype is initially SQLITE_INTEGER and +** sqlite3_value_text(V) is called to extract a text value for that +** integer, then subsequent calls to sqlite3_value_type(V) might return +** SQLITE_TEXT. Whether or not a persistent internal datatype conversion +** occurs is undefined and may change from one release of SQLite to the next. +** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If @@ -4368,18 +4837,19 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. */ -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*); -SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*); -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*); -SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*); -SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*); -SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*); +SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); +SQLITE_API double sqlite3_value_double(sqlite3_value*); +SQLITE_API int sqlite3_value_int(sqlite3_value*); +SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +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*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -4390,12 +4860,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** SQLite makes no use of subtype itself. It merely passes the subtype -** from the result of one [application-defined SQL function] into the -** input of another. */ -SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*); +SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values @@ -4411,8 +4877,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*); ** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer ** then sqlite3_value_free(V) is a harmless no-op. */ -SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*); -SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*); +SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*); +SQLITE_API void sqlite3_value_free(sqlite3_value*); /* ** CAPI3REF: Obtain Aggregate Function Context @@ -4457,7 +4923,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*); ** This routine must be called from the same thread in which ** the aggregate SQL function is running. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes); +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /* ** CAPI3REF: User Data For Functions @@ -4472,7 +4938,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int ** This routine must be called from the same thread in which ** the application-defined function is running. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*); +SQLITE_API void *sqlite3_user_data(sqlite3_context*); /* ** CAPI3REF: Database Connection For Functions @@ -4484,7 +4950,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*); ** and [sqlite3_create_function16()] routines that originally ** registered the application defined function. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data @@ -4501,10 +4967,11 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata -** associated by the sqlite3_set_auxdata() function with the Nth argument -** value to the application-defined function. ^If there is no metadata -** associated with the function argument, this sqlite3_get_auxdata() interface +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument +** value to the application-defined function. ^N is zero for the left-most +** function argument. ^If there is no metadata +** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th @@ -4516,12 +4983,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including:
      -**
    • when the corresponding function parameter changes, or -**
    • when [sqlite3_reset()] or [sqlite3_finalize()] is called for the -** SQL statement, or -**
    • when sqlite3_set_auxdata() is invoked again on the same parameter, or -**
    • during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.
    )^ +**
  • ^(when the corresponding function parameter changes)^, or +**
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement)^, or +**
  • ^(when sqlite3_set_auxdata() is invoked again on the same +** parameter)^, or +**
  • ^(during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs.)^ ** ** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the @@ -4534,11 +5002,15 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*); ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** +** The value of the N parameter to these interfaces should be non-negative. +** Future enhancements may make use of negative N values to define new +** kinds of function caching behavior. +** ** These routines must be called from the same thread in which ** the SQL function is running. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N); -SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); +SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); /* @@ -4657,7 +5129,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained from +** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^The sqlite3_result_value() interface sets the result of @@ -4670,31 +5142,43 @@ typedef void (*sqlite3_destructor_type)(void*); ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** +** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an +** SQL NULL value, just like [sqlite3_result_null(C)], except that it +** also associates the host-language pointer P or type T with that +** NULL value such that the pointer can be retrieved within an +** [application-defined SQL function] using [sqlite3_value_pointer()]. +** ^If the D parameter is not NULL, then it is a pointer to a destructor +** for the P parameter. ^SQLite invokes D with P as its only argument +** when SQLite is finished with P. The T parameter should be a static +** string and preferably a string literal. The sqlite3_result_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*, +SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, sqlite3_uint64,void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int); -SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64); -SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_double(sqlite3_context*, double); +SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); +SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); +SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); +SQLITE_API void sqlite3_result_null(sqlite3_context*); +SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, void(*)(void*), unsigned char encoding); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); -SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*); -SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n); -SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); +SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); +SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); /* @@ -4709,7 +5193,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. */ -SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int); +SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences @@ -4791,14 +5275,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned ** ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_create_collation( +SQLITE_API int sqlite3_create_collation( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2( +SQLITE_API int sqlite3_create_collation_v2( sqlite3*, const char *zName, int eTextRep, @@ -4806,7 +5290,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2( int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16( +SQLITE_API int sqlite3_create_collation16( sqlite3*, const void *zName, int eTextRep, @@ -4841,12 +5325,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16( ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or ** [sqlite3_create_collation_v2()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed( +SQLITE_API int sqlite3_collation_needed( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); -SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16( +SQLITE_API int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) @@ -4860,11 +5344,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16( ** The code to implement this API is not available in the public release ** of SQLite. */ -SQLITE_API int SQLITE_STDCALL sqlite3_key( +SQLITE_API int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_key_v2( +SQLITE_API int sqlite3_key_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The key */ @@ -4878,11 +5362,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2( ** The code to implement this API is not available in the public release ** of SQLite. */ -SQLITE_API int SQLITE_STDCALL sqlite3_rekey( +SQLITE_API int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2( +SQLITE_API int sqlite3_rekey_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The new key */ @@ -4892,7 +5376,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2( ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ -SQLITE_API void SQLITE_STDCALL sqlite3_activate_see( +SQLITE_API void sqlite3_activate_see( const char *zPassPhrase /* Activation phrase */ ); #endif @@ -4902,7 +5386,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see( ** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ -SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod( +SQLITE_API void sqlite3_activate_cerod( const char *zPassPhrase /* Activation phrase */ ); #endif @@ -4924,7 +5408,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod( ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. */ -SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int); +SQLITE_API int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files @@ -5043,7 +5527,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory; ** connection while this routine is running, then the return value ** is undefined. */ -SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*); +SQLITE_API int sqlite3_get_autocommit(sqlite3*); /* ** CAPI3REF: Find The Database Handle Of A Prepared Statement @@ -5056,7 +5540,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*); ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to ** create the statement in the first place. */ -SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*); +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Return The Filename For A Database Connection @@ -5073,7 +5557,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*); ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. */ -SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName); +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only @@ -5083,7 +5567,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha ** of connection D is read-only, 0 if it is read/write, or -1 if N is not ** the name of a database on connection D. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Find the next prepared statement @@ -5099,7 +5583,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa ** [sqlite3_next_stmt(D,S)] must refer to an open database ** connection and in particular must not be a NULL pointer. */ -SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); /* ** CAPI3REF: Commit And Rollback Notification Callbacks @@ -5148,8 +5632,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_ ** ** See also the [sqlite3_update_hook()] interface. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); -SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); +SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks @@ -5158,7 +5642,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument ** to be invoked whenever a row is updated, inserted or deleted in -** a rowid table. +** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** @@ -5179,7 +5663,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook -** is not invoked when duplication rows are deleted because of an +** is not invoked when conflicting rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future @@ -5197,10 +5681,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), ** on the same [database connection] D, or NULL for ** the first call on D. ** -** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()] -** interfaces. +** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], +** and [sqlite3_preupdate_hook()] interfaces. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( +SQLITE_API void *sqlite3_update_hook( sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* @@ -5215,7 +5699,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. -** This is a change as of SQLite version 3.5.0. In prior versions of SQLite, +** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). +** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent @@ -5240,7 +5725,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook( ** ** See Also: [SQLite Shared-Cache Mode] */ -SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int); +SQLITE_API int sqlite3_enable_shared_cache(int); /* ** CAPI3REF: Attempt To Free Heap Memory @@ -5256,7 +5741,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int); ** ** See also: [sqlite3_db_release_memory()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int); +SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection @@ -5270,7 +5755,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int); ** ** See also: [sqlite3_release_memory()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*); +SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size @@ -5309,7 +5794,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*); ** from the heap. ** )^ ** -** Beginning with SQLite version 3.7.3, the soft heap limit is enforced +** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), +** the soft heap limit is enforced ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] ** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], ** the soft heap limit is enforced on every memory allocation. Without @@ -5322,7 +5808,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*); ** The circumstances under which SQLite will enforce the soft heap limit may ** changes in future releases of SQLite. */ -SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N); +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface @@ -5333,7 +5819,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 ** only. All new applications should use the ** [sqlite3_soft_heap_limit64()] interface rather than this one. */ -SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N); +SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* @@ -5348,9 +5834,11 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N); ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a -** NULL pointer, then this routine simply checks for the existance of the +** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. +** does not. If the table name parameter T in a call to +** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is +** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -5403,7 +5891,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N); ** parsed, if that has not already been done, and returns an error if ** any errors are encountered while loading the schema. */ -SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata( +SQLITE_API int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ const char *zTableName, /* Table name */ @@ -5445,12 +5933,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata( ** should free this memory by calling [sqlite3_free()]. ** ** ^Extension loading must be enabled using -** [sqlite3_enable_load_extension()] prior to calling this API, +** [sqlite3_enable_load_extension()] or +** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) +** prior to calling this API, ** otherwise an error will be returned. ** +** Security warning: It is recommended that the +** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this +** interface. The use of the [sqlite3_enable_load_extension()] interface +** should be avoided. This will keep the SQL function [load_extension()] +** disabled and prevent SQL injections from giving attackers +** access to extension loading capabilities. +** ** See also the [load_extension() SQL function]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_load_extension( +SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Derived from zFile if 0 */ @@ -5470,8 +5967,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension( ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. +** +** ^This interface enables or disables both the C-API +** [sqlite3_load_extension()] and the SQL function [load_extension()]. +** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) +** to enable or disable only the C-API.)^ +** +** Security warning: It is recommended that extension loading +** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method +** rather than this interface, so the [load_extension()] SQL function +** remains disabled. This will prevent SQL injections from giving attackers +** access to extension loading capabilities. */ -SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff); +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* ** CAPI3REF: Automatically Load Statically Linked Extensions @@ -5483,7 +5991,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three -** arguments and expects and integer result as if the signature of the +** arguments and expects an integer result as if the signature of the ** entry point where as follows: ** **
    @@ -5509,7 +6017,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
     ** See also: [sqlite3_reset_auto_extension()]
     ** and [sqlite3_cancel_auto_extension()]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Cancel Automatic Extension Loading
    @@ -5521,7 +6029,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
     ** unregistered and it returns 0 if X was not on the list of initialization
     ** routines.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Reset Automatic Extension Loading
    @@ -5529,7 +6037,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
     ** ^This interface disables all automatic extensions previously
     ** registered using [sqlite3_auto_extension()].
     */
    -SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
    +SQLITE_API void sqlite3_reset_auto_extension(void);
     
     /*
     ** The interface to the virtual-table mechanism is currently considered
    @@ -5683,13 +6191,15 @@ struct sqlite3_module {
     ** the xUpdate method are automatically rolled back by SQLite.
     **
     ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
    -** structure for SQLite version 3.8.2. If a virtual table extension is
    +** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). 
    +** If a virtual table extension is
     ** used with an SQLite version earlier than 3.8.2, the results of attempting 
     ** to read or write the estimatedRows field are undefined (but are likely 
     ** to included crashing the application). The estimatedRows field should
     ** therefore only be used if [sqlite3_libversion_number()] returns a
     ** value greater than or equal to 3008002. Similarly, the idxFlags field
    -** was added for version 3.9.0. It may therefore only be used if
    +** was added for [version 3.9.0] ([dateof:3.9.0]). 
    +** It may therefore only be used if
     ** sqlite3_libversion_number() returns a value greater than or equal to
     ** 3009000.
     */
    @@ -5697,7 +6207,7 @@ struct sqlite3_index_info {
       /* Inputs */
       int nConstraint;           /* Number of entries in aConstraint */
       struct sqlite3_index_constraint {
    -     int iColumn;              /* Column on left-hand side of constraint */
    +     int iColumn;              /* Column constrained.  -1 for ROWID */
          unsigned char op;         /* Constraint operator */
          unsigned char usable;     /* True if this constraint is usable */
          int iTermOffset;          /* Used internally - xBestIndex should ignore */
    @@ -5738,15 +6248,20 @@ struct sqlite3_index_info {
     ** an operator that is part of a constraint term in the wHERE clause of
     ** a query that uses a [virtual table].
     */
    -#define SQLITE_INDEX_CONSTRAINT_EQ      2
    -#define SQLITE_INDEX_CONSTRAINT_GT      4
    -#define SQLITE_INDEX_CONSTRAINT_LE      8
    -#define SQLITE_INDEX_CONSTRAINT_LT     16
    -#define SQLITE_INDEX_CONSTRAINT_GE     32
    -#define SQLITE_INDEX_CONSTRAINT_MATCH  64
    -#define SQLITE_INDEX_CONSTRAINT_LIKE   65
    -#define SQLITE_INDEX_CONSTRAINT_GLOB   66
    -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
    +#define SQLITE_INDEX_CONSTRAINT_EQ         2
    +#define SQLITE_INDEX_CONSTRAINT_GT         4
    +#define SQLITE_INDEX_CONSTRAINT_LE         8
    +#define SQLITE_INDEX_CONSTRAINT_LT        16
    +#define SQLITE_INDEX_CONSTRAINT_GE        32
    +#define SQLITE_INDEX_CONSTRAINT_MATCH     64
    +#define SQLITE_INDEX_CONSTRAINT_LIKE      65
    +#define SQLITE_INDEX_CONSTRAINT_GLOB      66
    +#define SQLITE_INDEX_CONSTRAINT_REGEXP    67
    +#define SQLITE_INDEX_CONSTRAINT_NE        68
    +#define SQLITE_INDEX_CONSTRAINT_ISNOT     69
    +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
    +#define SQLITE_INDEX_CONSTRAINT_ISNULL    71
    +#define SQLITE_INDEX_CONSTRAINT_IS        72
     
     /*
     ** CAPI3REF: Register A Virtual Table Implementation
    @@ -5774,13 +6289,13 @@ struct sqlite3_index_info {
     ** interface is equivalent to sqlite3_create_module_v2() with a NULL
     ** destructor.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
    +SQLITE_API int sqlite3_create_module(
       sqlite3 *db,               /* SQLite connection to register module with */
       const char *zName,         /* Name of the module */
       const sqlite3_module *p,   /* Methods for the module */
       void *pClientData          /* Client data for xCreate/xConnect */
     );
    -SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
    +SQLITE_API int sqlite3_create_module_v2(
       sqlite3 *db,               /* SQLite connection to register module with */
       const char *zName,         /* Name of the module */
       const sqlite3_module *p,   /* Methods for the module */
    @@ -5843,7 +6358,7 @@ struct sqlite3_vtab_cursor {
     ** to declare the format (the names and datatypes of the columns) of
     ** the virtual tables they implement.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
    +SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
     
     /*
     ** CAPI3REF: Overload A Function For A Virtual Table
    @@ -5862,7 +6377,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
     ** purpose is to be a placeholder function that can be overloaded
     ** by a [virtual table].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
    +SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
     
     /*
     ** The interface to the virtual-table mechanism defined above (back up
    @@ -5937,6 +6452,12 @@ typedef struct sqlite3_blob sqlite3_blob;
     ** [database connection] error code and message accessible via 
     ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
     **
    +** A BLOB referenced by sqlite3_blob_open() may be read using the
    +** [sqlite3_blob_read()] interface and modified by using
    +** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
    +** different row of the same table using the [sqlite3_blob_reopen()]
    +** interface.  However, the column, table, or database of a [BLOB handle]
    +** cannot be changed after the [BLOB handle] is opened.
     **
     ** ^(If the row that a BLOB handle points to is modified by an
     ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
    @@ -5960,8 +6481,12 @@ typedef struct sqlite3_blob sqlite3_blob;
     **
     ** To avoid a resource leak, every open [BLOB handle] should eventually
     ** be released by a call to [sqlite3_blob_close()].
    +**
    +** See also: [sqlite3_blob_close()],
    +** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
    +** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
    +SQLITE_API int sqlite3_blob_open(
       sqlite3*,
       const char *zDb,
       const char *zTable,
    @@ -5975,11 +6500,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
     ** CAPI3REF: Move a BLOB Handle to a New Row
     ** METHOD: sqlite3_blob
     **
    -** ^This function is used to move an existing blob handle so that it points
    +** ^This function is used to move an existing [BLOB handle] so that it points
     ** to a different row of the same database table. ^The new row is identified
     ** by the rowid value passed as the second argument. Only the row can be
     ** changed. ^The database, table and column on which the blob handle is open
    -** remain the same. Moving an existing blob handle to a new row can be
    +** remain the same. Moving an existing [BLOB handle] to a new row is
     ** faster than closing the existing handle and opening a new one.
     **
     ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
    @@ -5994,7 +6519,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
     **
     ** ^This function sets the database handle error code and message.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
    +SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
     
     /*
     ** CAPI3REF: Close A BLOB Handle
    @@ -6017,7 +6542,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
     ** is passed a valid open blob handle, the values returned by the 
     ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
    +SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
     
     /*
     ** CAPI3REF: Return The Size Of An Open BLOB
    @@ -6033,7 +6558,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
     ** been closed by [sqlite3_blob_close()].  Passing any other pointer in
     ** to this routine results in undefined and probably undesirable behavior.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
    +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
     
     /*
     ** CAPI3REF: Read Data From A BLOB Incrementally
    @@ -6062,7 +6587,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
     **
     ** See also: [sqlite3_blob_write()].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
    +SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
     
     /*
     ** CAPI3REF: Write Data Into A BLOB Incrementally
    @@ -6104,7 +6629,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
     **
     ** See also: [sqlite3_blob_read()].
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
    +SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
     
     /*
     ** CAPI3REF: Virtual File System Objects
    @@ -6135,9 +6660,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
     ** ^(If the default VFS is unregistered, another VFS is chosen as
     ** the default.  The choice for the new VFS is arbitrary.)^
     */
    -SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
    -SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    -SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
    +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
    +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
    +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
     
     /*
     ** CAPI3REF: Mutexes
    @@ -6253,11 +6778,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
     **
     ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
     */
    -SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
    -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
    -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
    -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
    -SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
    +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
    +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
    +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
    +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
    +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
     
     /*
     ** CAPI3REF: Mutex Methods Object
    @@ -6367,8 +6892,8 @@ struct sqlite3_mutex_methods {
     ** interface should also return 1 when given a NULL pointer.
     */
     #ifndef NDEBUG
    -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
    -SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
    +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
    +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
     #endif
     
     /*
    @@ -6387,7 +6912,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
     #define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
     #define SQLITE_MUTEX_STATIC_MEM2      4  /* NOT USED */
     #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
    -#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
    +#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_randomness() */
     #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
     #define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
     #define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
    @@ -6408,7 +6933,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
     ** ^If the [threading mode] is Single-thread or Multi-thread then this
     ** routine returns a NULL pointer.
     */
    -SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
    +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
     
     /*
     ** CAPI3REF: Low-Level Control Of Database Files
    @@ -6443,7 +6968,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
     **
     ** See also: [SQLITE_FCNTL_LOCKSTATE]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
    +SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
     
     /*
     ** CAPI3REF: Testing Interface
    @@ -6462,7 +6987,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
     ** Unlike most of the SQLite API, this function is not guaranteed to
     ** operate consistently from one release to the next.
     */
    -SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
    +SQLITE_API int sqlite3_test_control(int op, ...);
     
     /*
     ** CAPI3REF: Testing Interface Operation Codes
    @@ -6488,9 +7013,10 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
     #define SQLITE_TESTCTRL_RESERVE                 14
     #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
     #define SQLITE_TESTCTRL_ISKEYWORD               16
    -#define SQLITE_TESTCTRL_SCRATCHMALLOC           17
    +#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
     #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
     #define SQLITE_TESTCTRL_EXPLAIN_STMT            19  /* NOT USED */
    +#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD    19
     #define SQLITE_TESTCTRL_NEVER_CORRUPT           20
     #define SQLITE_TESTCTRL_VDBE_COVERAGE           21
     #define SQLITE_TESTCTRL_BYTEORDER               22
    @@ -6525,8 +7051,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
     **
     ** See also: [sqlite3_db_status()]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    -SQLITE_API int SQLITE_STDCALL sqlite3_status64(
    +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
    +SQLITE_API int sqlite3_status64(
       int op,
       sqlite3_int64 *pCurrent,
       sqlite3_int64 *pHighwater,
    @@ -6546,8 +7072,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
     ** 
    This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application -** and internal memory usage by the SQLite library. Scratch memory -** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
    )^ @@ -6585,29 +7110,14 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.)^ ** -** [[SQLITE_STATUS_SCRATCH_USED]] ^(
    SQLITE_STATUS_SCRATCH_USED
    -**
    This parameter returns the number of allocations used out of the -** [scratch memory allocator] configured using -** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not -** in bytes. Since a single thread may only have one scratch allocation -** outstanding at time, this parameter also reports the number of threads -** using scratch memory at the same time.
    )^ +** [[SQLITE_STATUS_SCRATCH_USED]]
    SQLITE_STATUS_SCRATCH_USED
    +**
    No longer used.
    ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
    SQLITE_STATUS_SCRATCH_OVERFLOW
    -**
    This parameter returns the number of bytes of scratch memory -** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] -** buffer and where forced to overflow to [sqlite3_malloc()]. The values -** returned include overflows because the requested allocation was too -** larger (that is, because the requested allocation was larger than the -** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer -** slots were available. -**
    )^ +**
    No longer used.
    ** -** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
    SQLITE_STATUS_SCRATCH_SIZE
    -**
    This parameter records the largest memory allocation request -** handed to [scratch memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. -** The value written into the *pCurrent parameter is undefined.
    )^ +** [[SQLITE_STATUS_SCRATCH_SIZE]]
    SQLITE_STATUS_SCRATCH_SIZE
    +**
    No longer used.
    ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(
    SQLITE_STATUS_PARSER_STACK
    **
    The *pHighwater parameter records the deepest parser stack. @@ -6620,12 +7130,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* @@ -6651,7 +7161,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64( ** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); +SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections @@ -6697,6 +7207,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** ^(
    SQLITE_DBSTATUS_CACHE_USED_SHARED
    +**
    This parameter is similar to DBSTATUS_CACHE_USED, except that if a +** pager cache is shared between two or more connections the bytes of heap +** memory used by that pager cache is divided evenly between the attached +** connections.)^ In other words, if none of the pager caches associated +** with the database connection are shared, this request returns the same +** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** shared, the value returned by this call will be smaller than that returned +** by DBSTATUS_CACHE_USED. ^The highwater mark associated with +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated @@ -6754,7 +7276,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 -#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ /* @@ -6781,7 +7304,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int ** ** See also: [sqlite3_status()] and [sqlite3_db_status()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements @@ -6817,6 +7340,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. +** +** [[SQLITE_STMTSTATUS_REPREPARE]]
    SQLITE_STMTSTATUS_REPREPARE
    +**
    ^This is the number of times that the prepare statement has been +** automatically regenerated due to schema changes or change to +** [bound parameters] that might affect the query plan. +** +** [[SQLITE_STMTSTATUS_RUN]]
    SQLITE_STMTSTATUS_RUN
    +**
    ^This is the number of times that the prepared statement has +** been run. A single "run" for the purposes of this counter is one +** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. +** The counter is incremented on the first [sqlite3_step()] call of each +** cycle. +** +** [[SQLITE_STMTSTATUS_MEMUSED]]
    SQLITE_STMTSTATUS_MEMUSED
    +**
    ^This is the approximate number of bytes of heap memory +** used to store the prepared statement. ^This value is not actually +** a counter, and so the resetFlg parameter to sqlite3_stmt_status() +** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. **
    ** */ @@ -6824,6 +7365,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int rese #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object @@ -7108,7 +7652,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** -** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if +** ^A call to sqlite3_backup_init() will fail, returning NULL, if ** there is already a read or read-write transaction open on the ** destination database. ** @@ -7250,16 +7794,16 @@ typedef struct sqlite3_backup sqlite3_backup; ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. */ -SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init( +SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ const char *zDestName, /* Destination database name */ sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p); -SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** CAPI3REF: Unlock Notification @@ -7376,7 +7920,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p); ** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED.)^ */ -SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify( +SQLITE_API int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ @@ -7391,8 +7935,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify( ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ -SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *); -SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int); +SQLITE_API int sqlite3_stricmp(const char *, const char *); +SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: String Globbing @@ -7409,7 +7953,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int); ** ** See also: [sqlite3_strlike()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr); +SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); /* ** CAPI3REF: String LIKE Matching @@ -7432,7 +7976,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt ** ** See also: [sqlite3_strglob()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); +SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); /* ** CAPI3REF: Error Logging Interface @@ -7455,7 +7999,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zSt ** a few hundred characters, it will be truncated to the length of the ** buffer. */ -SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...); +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); /* ** CAPI3REF: Write-Ahead Log Commit Hook @@ -7489,9 +8033,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...) ** previously registered write-ahead log callback. ^Note that the ** [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will -** those overwrite any prior [sqlite3_wal_hook()] settings. +** overwrite any prior [sqlite3_wal_hook()] settings. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook( +SQLITE_API void *sqlite3_wal_hook( sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* @@ -7526,7 +8070,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook( ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N); +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database @@ -7548,7 +8092,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** start a callback but which do not need the full power (and corresponding ** complication) of [sqlite3_wal_checkpoint_v2()]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Checkpoint a database @@ -7642,7 +8186,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD ** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface ** from SQL. */ -SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( +SQLITE_API int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of attached database (or NULL) */ int eMode, /* SQLITE_CHECKPOINT_* value */ @@ -7678,7 +8222,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2( ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options ** may be added in the future. */ -SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...); +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options @@ -7731,7 +8275,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...); ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ -SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *); +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes @@ -7836,7 +8380,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *); ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ -SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus( +SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ @@ -7852,7 +8396,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus( ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ -SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); +SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction @@ -7884,11 +8428,125 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); ** ^This function does not set the database handle error code or message ** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. */ -SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*); +SQLITE_API int sqlite3_db_cacheflush(sqlite3*); + +/* +** CAPI3REF: The pre-update hook. +** +** ^These interfaces are only available if SQLite is compiled using the +** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. +** +** ^The [sqlite3_preupdate_hook()] interface registers a callback function +** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation +** on a database table. +** ^At most one preupdate hook may be registered at a time on a single +** [database connection]; each call to [sqlite3_preupdate_hook()] overrides +** the previous setting. +** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] +** with a NULL pointer as the second parameter. +** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as +** the first parameter to callbacks. +** +** ^The preupdate hook only fires for changes to real database tables; the +** preupdate hook is not invoked for changes to [virtual tables] or to +** system tables like sqlite_master or sqlite_stat1. +** +** ^The second parameter to the preupdate callback is a pointer to +** the [database connection] that registered the preupdate hook. +** ^The third parameter to the preupdate callback is one of the constants +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the +** kind of update operation that is about to occur. +** ^(The fourth parameter to the preupdate callback is the name of the +** database within the database connection that is being modified. This +** will be "main" for the main database or "temp" for TEMP tables or +** the name given after the AS keyword in the [ATTACH] statement for attached +** databases.)^ +** ^The fifth parameter to the preupdate callback is the name of the +** table that is being modified. +** +** For an UPDATE or DELETE operation on a [rowid table], the sixth +** parameter passed to the preupdate callback is the initial [rowid] of the +** row being modified or deleted. For an INSERT operation on a rowid table, +** or any operation on a WITHOUT ROWID table, the value of the sixth +** parameter is undefined. For an INSERT or UPDATE on a rowid table the +** seventh parameter is the final rowid value of the row being inserted +** or updated. The value of the seventh parameter passed to the callback +** function is not defined for operations on WITHOUT ROWID tables, or for +** INSERT operations on rowid tables. +** +** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], +** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces +** provide additional information about a preupdate event. These routines +** may only be called from within a preupdate callback. Invoking any of +** these routines from outside of a preupdate callback or with a +** [database connection] pointer that is different from the one supplied +** to the preupdate callback results in undefined and probably undesirable +** behavior. +** +** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns +** in the row that is being inserted, updated, or deleted. +** +** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row before it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE +** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row after it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE +** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate +** callback was invoked as a result of a direct insert, update, or delete +** operation; or 1 for inserts, updates, or deletes invoked by top-level +** triggers; or 2 for changes resulting from triggers called by top-level +** triggers; and so forth. +** +** See also: [sqlite3_update_hook()] +*/ +#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void* +); +SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_count(sqlite3 *); +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); +SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +#endif + +/* +** CAPI3REF: Low-level system error code +** +** ^Attempt to return the underlying operating system error code or error +** number that caused the most recent I/O error or failure to open a file. +** The return value is OS-dependent. For example, on unix systems, after +** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be +** called to get back the underlying "errno" that caused the problem, such +** as ENOSPC, EAUTH, EISDIR, and so forth. +*/ +SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot -** KEYWORDS: {snapshot} +** KEYWORDS: {snapshot} {sqlite3_snapshot} ** EXPERIMENTAL ** ** An instance of the snapshot object records the state of a [WAL mode] @@ -7912,7 +8570,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*); ** to an historical snapshot (if possible). The destructor for ** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. */ -typedef struct sqlite3_snapshot sqlite3_snapshot; +typedef struct sqlite3_snapshot { + unsigned char hidden[48]; +} sqlite3_snapshot; /* ** CAPI3REF: Record A Database Snapshot @@ -7923,9 +8583,32 @@ typedef struct sqlite3_snapshot sqlite3_snapshot; ** schema S in database connection D. ^On success, the ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. -** ^If schema S of [database connection] D is not a [WAL mode] database -** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)] -** leaves the *P value unchanged and returns an appropriate [error code]. +** If there is not already a read-transaction open on schema S when +** this function is called, one is opened automatically. +** +** The following must be true for this function to succeed. If any of +** the following statements are false when sqlite3_snapshot_get() is +** called, SQLITE_ERROR is returned. The final value of *P is undefined +** in this case. +** +**
      +**
    • The database handle must be in [autocommit mode]. +** +**
    • Schema S of [database connection] D must be a [WAL mode] database. +** +**
    • There must not be a write transaction open on schema S of database +** connection D. +** +**
    • One or more transactions must have been written to the current wal +** file since it was created on disk (by any connection). This means +** that a snapshot cannot be taken on a wal mode database with no wal +** file immediately after it is first opened. At least one transaction +** must be written to it first. +**
    +** +** This function may also return SQLITE_NOMEM. If it is called with the +** database handle in autocommit mode but fails for some other reason, +** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] @@ -7934,7 +8617,7 @@ typedef struct sqlite3_snapshot sqlite3_snapshot; ** The [sqlite3_snapshot_get()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get( +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot @@ -7944,22 +8627,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get( ** CAPI3REF: Start a read transaction on an historical snapshot ** EXPERIMENTAL ** -** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the -** read transaction that is currently open on schema S of -** [database connection] D so that it refers to historical [snapshot] P. +** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a +** read transaction for schema S of +** [database connection] D such that the read transaction +** refers to historical [snapshot] P, rather than the most +** recent change to the database. ** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success ** or an appropriate [error code] if it fails. ** ** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be -** the first operation, apart from other sqlite3_snapshot_open() calls, -** following the [BEGIN] that starts a new read transaction. -** ^A [snapshot] will fail to open if it has been overwritten by a -** [checkpoint]. +** the first operation following the [BEGIN] that takes the schema S +** out of [autocommit mode]. +** ^In other words, schema S must not currently be in +** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the +** database connection D must be out of [autocommit mode]. +** ^A [snapshot] will fail to open if it has been overwritten by a +** [checkpoint]. +** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the +** database connection D does not know that the database file for +** schema S is in [WAL mode]. A database connection might not know +** that the database file is in [WAL mode] if there has been no prior +** I/O on that database connection, or if the database entered [WAL mode] +** after the most recent I/O on the database connection.)^ +** (Hint: Run "[PRAGMA application_id]" against a newly opened +** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open( +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot @@ -7976,7 +8672,56 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open( ** The [sqlite3_snapshot_free()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*); +SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); + +/* +** CAPI3REF: Compare the ages of two snapshot handles. +** EXPERIMENTAL +** +** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages +** of two valid snapshot handles. +** +** If the two snapshot handles are not associated with the same database +** file, the result of the comparison is undefined. +** +** Additionally, the result of the comparison is only valid if both of the +** snapshot handles were obtained by calling sqlite3_snapshot_get() since the +** last time the wal file was deleted. The wal file is deleted when the +** database is changed back to rollback mode or when the number of database +** clients drops to zero. If either snapshot handle was obtained before the +** wal file was last deleted, the value returned by this function +** is undefined. +** +** Otherwise, this API returns a negative value if P1 refers to an older +** snapshot than P2, zero if the two handles refer to the same database +** snapshot, and a positive value if P1 is a newer snapshot than P2. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 +); + +/* +** CAPI3REF: Recover snapshots from a wal file +** EXPERIMENTAL +** +** If all connections disconnect from a database file but do not perform +** a checkpoint, the existing wal file is opened along with the database +** file the next time the database is opened. At this point it is only +** possible to successfully call sqlite3_snapshot_open() to open the most +** recent snapshot of the database (the one at the head of the wal file), +** even though the wal file may contain other valid snapshots for which +** clients have sqlite3_snapshot handles. +** +** This function attempts to scan the wal file associated with database zDb +** of database handle db and make all valid snapshots available to +** sqlite3_snapshot_open(). It is an error if there is already a read +** transaction open on the database, or if the database is not a wal mode +** database. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** Undo the hack that converts floating point types to integer for @@ -7989,8 +8734,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3 #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif -#endif /* _SQLITE3_H_ */ +#endif /* SQLITE3_H */ +/******** Begin file sqlite3rtree.h *********/ /* ** 2010 August 30 ** @@ -8030,7 +8776,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; ** ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback( +SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), @@ -8056,7 +8802,7 @@ struct sqlite3_rtree_geometry { ** ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) */ -SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback( +SQLITE_API int sqlite3_rtree_query_callback( sqlite3 *db, const char *zQueryFunc, int (*xQueryFunc)(sqlite3_rtree_query_info*), @@ -8108,6 +8854,1298 @@ struct sqlite3_rtree_query_info { #endif /* ifndef _SQLITE3RTREE_H_ */ +/******** End of sqlite3rtree.h *********/ +/******** Begin file sqlite3session.h *********/ + +#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) +#define __SQLITESESSION_H_ 1 + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + + +/* +** CAPI3REF: Session Object Handle +*/ +typedef struct sqlite3_session sqlite3_session; + +/* +** CAPI3REF: Changeset Iterator Handle +*/ +typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; + +/* +** CAPI3REF: Create A New Session Object +** +** Create a new session object attached to database handle db. If successful, +** a pointer to the new object is written to *ppSession and SQLITE_OK is +** returned. If an error occurs, *ppSession is set to NULL and an SQLite +** error code (e.g. SQLITE_NOMEM) is returned. +** +** It is possible to create multiple session objects attached to a single +** database handle. +** +** Session objects created using this function should be deleted using the +** [sqlite3session_delete()] function before the database handle that they +** are attached to is itself closed. If the database handle is closed before +** the session object is deleted, then the results of calling any session +** module function, including [sqlite3session_delete()] on the session object +** are undefined. +** +** Because the session module uses the [sqlite3_preupdate_hook()] API, it +** is not possible for an application to register a pre-update hook on a +** database handle that has one or more session objects attached. Nor is +** it possible to create a session object attached to a database handle for +** which a pre-update hook is already defined. The results of attempting +** either of these things are undefined. +** +** The session object will be used to create changesets for tables in +** database zDb, where zDb is either "main", or "temp", or the name of an +** attached database. It is not an error if database zDb is not attached +** to the database when the session object is created. +*/ +SQLITE_API int sqlite3session_create( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (e.g. "main") */ + sqlite3_session **ppSession /* OUT: New session object */ +); + +/* +** CAPI3REF: Delete A Session Object +** +** Delete a session object previously allocated using +** [sqlite3session_create()]. Once a session object has been deleted, the +** results of attempting to use pSession with any other session module +** function are undefined. +** +** Session objects must be deleted before the database handle to which they +** are attached is closed. Refer to the documentation for +** [sqlite3session_create()] for details. +*/ +SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); + + +/* +** CAPI3REF: Enable Or Disable A Session Object +** +** Enable or disable the recording of changes by a session object. When +** enabled, a session object records changes made to the database. When +** disabled - it does not. A newly created session object is enabled. +** Refer to the documentation for [sqlite3session_changeset()] for further +** details regarding how enabling and disabling a session object affects +** the eventual changesets. +** +** Passing zero to this function disables the session. Passing a value +** greater than zero enables it. Passing a value less than zero is a +** no-op, and may be used to query the current state of the session. +** +** The return value indicates the final state of the session object: 0 if +** the session is disabled, or 1 if it is enabled. +*/ +SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); + +/* +** CAPI3REF: Set Or Clear the Indirect Change Flag +** +** Each change recorded by a session object is marked as either direct or +** indirect. A change is marked as indirect if either: +** +**
      +**
    • The session object "indirect" flag is set when the change is +** made, or +**
    • The change is made by an SQL trigger or foreign key action +** instead of directly as a result of a users SQL statement. +**
    +** +** If a single row is affected by more than one operation within a session, +** then the change is considered indirect if all operations meet the criteria +** for an indirect change above, or direct otherwise. +** +** This function is used to set, clear or query the session object indirect +** flag. If the second argument passed to this function is zero, then the +** indirect flag is cleared. If it is greater than zero, the indirect flag +** is set. Passing a value less than zero does not modify the current value +** of the indirect flag, and may be used to query the current state of the +** indirect flag for the specified session object. +** +** The return value indicates the final state of the indirect flag: 0 if +** it is clear, or 1 if it is set. +*/ +SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); + +/* +** CAPI3REF: Attach A Table To A Session Object +** +** If argument zTab is not NULL, then it is the name of a table to attach +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See +** documentation for [sqlite3session_changeset()] for further details. +** +** Or, if argument zTab is NULL, then changes are recorded for all tables +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for +** the new tables are also recorded. +** +** Changes can only be recorded for tables that have a PRIMARY KEY explicitly +** defined as part of their CREATE TABLE statement. It does not matter if the +** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY +** KEY may consist of a single column, or may be a composite key. +** +** It is not an error if the named table does not exist in the database. Nor +** is it an error if the named table does not have a PRIMARY KEY. However, +** no changes will be recorded in either of these scenarios. +** +** Changes are not recorded for individual rows that have NULL values stored +** in one or more of their PRIMARY KEY columns. +** +** SQLITE_OK is returned if the call completes without error. Or, if an error +** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. +*/ +SQLITE_API int sqlite3session_attach( + sqlite3_session *pSession, /* Session object */ + const char *zTab /* Table name */ +); + +/* +** CAPI3REF: Set a table filter on a Session Object. +** +** The second argument (xFilter) is the "filter callback". For changes to rows +** in tables that are not attached to the Session object, the filter is called +** to determine whether changes to the table's rows should be tracked or not. +** If xFilter returns 0, changes is not tracked. Note that once a table is +** attached, xFilter will not be called again. +*/ +SQLITE_API void sqlite3session_table_filter( + sqlite3_session *pSession, /* Session object */ + int(*xFilter)( + void *pCtx, /* Copy of third arg to _filter_table() */ + const char *zTab /* Table name */ + ), + void *pCtx /* First argument passed to xFilter */ +); + +/* +** CAPI3REF: Generate A Changeset From A Session Object +** +** Obtain a changeset containing changes to the tables attached to the +** session object passed as the first argument. If successful, +** set *ppChangeset to point to a buffer containing the changeset +** and *pnChangeset to the size of the changeset in bytes before returning +** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to +** zero and return an SQLite error code. +** +** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, +** each representing a change to a single row of an attached table. An INSERT +** change contains the values of each field of a new database row. A DELETE +** contains the original values of each field of a deleted database row. An +** UPDATE change contains the original values of each field of an updated +** database row along with the updated values for each updated non-primary-key +** column. It is not possible for an UPDATE change to represent a change that +** modifies the values of primary key columns. If such a change is made, it +** is represented in a changeset as a DELETE followed by an INSERT. +** +** Changes are not recorded for rows that have NULL values stored in one or +** more of their PRIMARY KEY columns. If such a row is inserted or deleted, +** no corresponding change is present in the changesets returned by this +** function. If an existing row with one or more NULL values stored in +** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, +** only an INSERT is appears in the changeset. Similarly, if an existing row +** with non-NULL PRIMARY KEY values is updated so that one or more of its +** PRIMARY KEY columns are set to NULL, the resulting changeset contains a +** DELETE change only. +** +** The contents of a changeset may be traversed using an iterator created +** using the [sqlite3changeset_start()] API. A changeset may be applied to +** a database with a compatible schema using the [sqlite3changeset_apply()] +** API. +** +** Within a changeset generated by this function, all changes related to a +** single table are grouped together. In other words, when iterating through +** a changeset or when applying a changeset to a database, all changes related +** to a single table are processed before moving on to the next table. Tables +** are sorted in the same order in which they were attached (or auto-attached) +** to the sqlite3_session object. The order in which the changes related to +** a single table are stored is undefined. +** +** Following a successful call to this function, it is the responsibility of +** the caller to eventually free the buffer that *ppChangeset points to using +** [sqlite3_free()]. +** +**

    Changeset Generation

    +** +** Once a table has been attached to a session object, the session object +** records the primary key values of all new rows inserted into the table. +** It also records the original primary key and other column values of any +** deleted or updated rows. For each unique primary key value, data is only +** recorded once - the first time a row with said primary key is inserted, +** updated or deleted in the lifetime of the session. +** +** There is one exception to the previous paragraph: when a row is inserted, +** updated or deleted, if one or more of its primary key columns contain a +** NULL value, no record of the change is made. +** +** The session object therefore accumulates two types of records - those +** that consist of primary key values only (created when the user inserts +** a new record) and those that consist of the primary key values and the +** original values of other table columns (created when the users deletes +** or updates a record). +** +** When this function is called, the requested changeset is created using +** both the accumulated records and the current contents of the database +** file. Specifically: +** +**
      +**
    • For each record generated by an insert, the database is queried +** for a row with a matching primary key. If one is found, an INSERT +** change is added to the changeset. If no such row is found, no change +** is added to the changeset. +** +**
    • For each record generated by an update or delete, the database is +** queried for a row with a matching primary key. If such a row is +** found and one or more of the non-primary key fields have been +** modified from their original values, an UPDATE change is added to +** the changeset. Or, if no such row is found in the table, a DELETE +** change is added to the changeset. If there is a row with a matching +** primary key in the database, but all fields contain their original +** values, no change is added to the changeset. +**
    +** +** This means, amongst other things, that if a row is inserted and then later +** deleted while a session object is active, neither the insert nor the delete +** will be present in the changeset. Or if a row is deleted and then later a +** row with the same primary key values inserted while a session object is +** active, the resulting changeset will contain an UPDATE change instead of +** a DELETE and an INSERT. +** +** When a session object is disabled (see the [sqlite3session_enable()] API), +** it does not accumulate records when rows are inserted, updated or deleted. +** This may appear to have some counter-intuitive effects if a single row +** is written to more than once during a session. For example, if a row +** is inserted while a session object is enabled, then later deleted while +** the same session object is disabled, no INSERT record will appear in the +** changeset, even though the delete took place while the session was disabled. +** Or, if one field of a row is updated while a session is disabled, and +** another field of the same row is updated while the session is enabled, the +** resulting changeset will contain an UPDATE change that updates both fields. +*/ +SQLITE_API int sqlite3session_changeset( + sqlite3_session *pSession, /* Session object */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ +); + +/* +** CAPI3REF: Load The Difference Between Tables Into A Session +** +** If it is not already attached to the session object passed as the first +** argument, this function attaches table zTbl in the same manner as the +** [sqlite3session_attach()] function. If zTbl does not exist, or if it +** does not have a primary key, this function is a no-op (but does not return +** an error). +** +** Argument zFromDb must be the name of a database ("main", "temp" etc.) +** attached to the same database handle as the session object that contains +** a table compatible with the table attached to the session by this function. +** A table is considered compatible if it: +** +**
      +**
    • Has the same name, +**
    • Has the same set of columns declared in the same order, and +**
    • Has the same PRIMARY KEY definition. +**
    +** +** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables +** are compatible but do not have any PRIMARY KEY columns, it is not an error +** but no changes are added to the session object. As with other session +** APIs, tables without PRIMARY KEYs are simply ignored. +** +** This function adds a set of changes to the session object that could be +** used to update the table in database zFrom (call this the "from-table") +** so that its content is the same as the table attached to the session +** object (call this the "to-table"). Specifically: +** +**
      +**
    • For each row (primary key) that exists in the to-table but not in +** the from-table, an INSERT record is added to the session object. +** +**
    • For each row (primary key) that exists in the to-table but not in +** the from-table, a DELETE record is added to the session object. +** +**
    • For each row (primary key) that exists in both tables, but features +** different non-PK values in each, an UPDATE record is added to the +** session. +**
    +** +** To clarify, if this function is called and then a changeset constructed +** using [sqlite3session_changeset()], then after applying that changeset to +** database zFrom the contents of the two compatible tables would be +** identical. +** +** It an error if database zFrom does not exist or does not contain the +** required compatible table. +** +** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite +** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to free this buffer using +** sqlite3_free(). +*/ +SQLITE_API int sqlite3session_diff( + sqlite3_session *pSession, + const char *zFromDb, + const char *zTbl, + char **pzErrMsg +); + + +/* +** CAPI3REF: Generate A Patchset From A Session Object +** +** The differences between a patchset and a changeset are that: +** +**
      +**
    • DELETE records consist of the primary key fields only. The +** original values of other fields are omitted. +**
    • The original values of any modified fields are omitted from +** UPDATE records. +**
    +** +** A patchset blob may be used with up to date versions of all +** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), +** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, +** attempting to use a patchset blob with old versions of the +** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. +** +** Because the non-primary key "old.*" fields are omitted, no +** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset +** is passed to the sqlite3changeset_apply() API. Other conflict types work +** in the same way as for changesets. +** +** Changes within a patchset are ordered in the same way as for changesets +** generated by the sqlite3session_changeset() function (i.e. all changes for +** a single table are grouped together, tables appear in the order in which +** they were attached to the session object). +*/ +SQLITE_API int sqlite3session_patchset( + sqlite3_session *pSession, /* Session object */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ +); + +/* +** CAPI3REF: Test if a changeset has recorded any changes. +** +** Return non-zero if no changes to attached tables have been recorded by +** the session object passed as the first argument. Otherwise, if one or +** more changes have been recorded, return zero. +** +** Even if this function returns zero, it is possible that calling +** [sqlite3session_changeset()] on the session handle may still return a +** changeset that contains no changes. This can happen when a row in +** an attached table is modified and then later on the original values +** are restored. However, if this function returns non-zero, then it is +** guaranteed that a call to sqlite3session_changeset() will return a +** changeset containing zero changes. +*/ +SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); + +/* +** CAPI3REF: Create An Iterator To Traverse A Changeset +** +** Create an iterator used to iterate through the contents of a changeset. +** If successful, *pp is set to point to the iterator handle and SQLITE_OK +** is returned. Otherwise, if an error occurs, *pp is set to zero and an +** SQLite error code is returned. +** +** The following functions can be used to advance and query a changeset +** iterator created by this function: +** +**
      +**
    • [sqlite3changeset_next()] +**
    • [sqlite3changeset_op()] +**
    • [sqlite3changeset_new()] +**
    • [sqlite3changeset_old()] +**
    +** +** It is the responsibility of the caller to eventually destroy the iterator +** by passing it to [sqlite3changeset_finalize()]. The buffer containing the +** changeset (pChangeset) must remain valid until after the iterator is +** destroyed. +** +** Assuming the changeset blob was created by one of the +** [sqlite3session_changeset()], [sqlite3changeset_concat()] or +** [sqlite3changeset_invert()] functions, all changes within the changeset +** that apply to a single table are grouped together. This means that when +** an application iterates through a changeset using an iterator created by +** this function, all changes that relate to a single table are visited +** 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. +*/ +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 */ +); + + +/* +** CAPI3REF: Advance A Changeset Iterator +** +** This function may only be used with iterators created by function +** [sqlite3changeset_start()]. If it is called on an iterator passed to +** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE +** is returned and the call has no effect. +** +** Immediately after an iterator is created by sqlite3changeset_start(), it +** does not point to any change in the changeset. Assuming the changeset +** is not empty, the first call to this function advances the iterator to +** point to the first change in the changeset. Each subsequent call advances +** the iterator to point to the next change in the changeset (if any). If +** no error occurs and the iterator points to a valid change after a call +** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. +** Otherwise, if all changes in the changeset have already been visited, +** SQLITE_DONE is returned. +** +** If an error occurs, an SQLite error code is returned. Possible error +** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or +** SQLITE_NOMEM. +*/ +SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Obtain The Current Operation From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this +** is not the case, this function returns [SQLITE_MISUSE]. +** +** If argument pzTab is not NULL, then *pzTab is set to point to a +** nul-terminated utf-8 encoded string containing the name of the table +** affected by the current change. The buffer remains valid until either +** 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 +** 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 +** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the +** type of change that the iterator currently points to. +** +** If no error occurs, SQLITE_OK is returned. If an error does occur, an +** SQLite error code is returned. The values of the output variables may not +** be trusted in this case. +*/ +SQLITE_API int sqlite3changeset_op( + sqlite3_changeset_iter *pIter, /* Iterator object */ + const char **pzTab, /* OUT: Pointer to table name */ + int *pnCol, /* OUT: Number of columns in table */ + int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int *pbIndirect /* OUT: True for an 'indirect' change */ +); + +/* +** CAPI3REF: Obtain The Primary Key Definition Of A Table +** +** For each modified table, a changeset includes the following: +** +**
      +**
    • The number of columns in the table, and +**
    • Which of those columns make up the tables PRIMARY KEY. +**
    +** +** This function is used to find which columns comprise the PRIMARY KEY of +** the table modified by the change that iterator pIter currently points to. +** If successful, *pabPK is set to point to an array of nCol entries, where +** nCol is the number of columns in the table. Elements of *pabPK are set to +** 0x01 if the corresponding column is part of the tables primary key, or +** 0x00 if it is not. +** +** If argument pnCol is not NULL, then *pnCol is set to the number of columns +** in the table. +** +** If this function is called when the iterator does not point to a valid +** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, +** SQLITE_OK is returned and the output variables populated as described +** above. +*/ +SQLITE_API int sqlite3changeset_pk( + sqlite3_changeset_iter *pIter, /* Iterator object */ + unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ + int *pnCol /* OUT: Number of entries in output array */ +); + +/* +** CAPI3REF: Obtain old.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** original row values stored as part of the UPDATE or DELETE change and +** returns SQLITE_OK. The name of the function comes from the fact that this +** is similar to the "old.*" columns available to update or delete triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_old( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain new.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** new row values stored as part of the UPDATE or INSERT change and +** returns SQLITE_OK. If the change is an UPDATE and does not include +** a new value for the requested column, *ppValue is set to NULL and +** SQLITE_OK returned. The name of the function comes from the fact that +** this is similar to the "new.*" columns available to update or delete +** triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_new( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator +** +** This function should only be used with iterator objects passed to a +** conflict-handler callback by [sqlite3changeset_apply()] with either +** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function +** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue +** is set to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the +** "conflicting row" associated with the current conflict-handler callback +** and returns SQLITE_OK. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_conflict( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Value from conflicting row */ +); + +/* +** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations +** +** This function may only be called with an iterator passed to an +** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case +** it sets the output variable to the total number of known foreign key +** violations in the destination database and returns SQLITE_OK. +** +** In all other cases this function returns SQLITE_MISUSE. +*/ +SQLITE_API int sqlite3changeset_fk_conflicts( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int *pnOut /* OUT: Number of FK violations */ +); + + +/* +** CAPI3REF: Finalize A Changeset Iterator +** +** This function is used to finalize an iterator allocated with +** [sqlite3changeset_start()]. +** +** This function should only be called on iterators created using the +** [sqlite3changeset_start()] function. If an application calls this +** function with an iterator passed to a conflict-handler by +** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the +** call has no effect. +** +** If an error was encountered within a call to an sqlite3changeset_xxx() +** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an +** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding +** to that error is returned by this function. Otherwise, SQLITE_OK is +** returned. This is to allow the following pattern (pseudo-code): +** +** sqlite3changeset_start(); +** while( SQLITE_ROW==sqlite3changeset_next() ){ +** // Do something with change. +** } +** rc = sqlite3changeset_finalize(); +** if( rc!=SQLITE_OK ){ +** // An error has occurred +** } +*/ +SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Invert A Changeset +** +** This function is used to "invert" a changeset object. Applying an inverted +** changeset to a database reverses the effects of applying the uninverted +** changeset. Specifically: +** +**
      +**
    • Each DELETE change is changed to an INSERT, and +**
    • Each INSERT change is changed to a DELETE, and +**
    • For each UPDATE change, the old.* and new.* values are exchanged. +**
    +** +** This function does not change the order in which changes appear within +** the changeset. It merely reverses the sense of each individual change. +** +** If successful, a pointer to a buffer containing the inverted changeset +** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and +** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are +** zeroed and an SQLite error code returned. +** +** It is the responsibility of the caller to eventually call sqlite3_free() +** on the *ppOut pointer to free the buffer allocation following a successful +** call to this function. +** +** WARNING/TODO: This function currently assumes that the input is a valid +** changeset. If it is not, the results are undefined. +*/ +SQLITE_API int sqlite3changeset_invert( + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ +); + +/* +** CAPI3REF: Concatenate Two Changeset Objects +** +** This function is used to concatenate two changesets, A and B, into a +** single changeset. The result is a changeset equivalent to applying +** changeset A followed by changeset B. +** +** This function combines the two input changesets using an +** sqlite3_changegroup object. Calling it produces similar results as the +** following code fragment: +** +** sqlite3_changegroup *pGrp; +** rc = sqlite3_changegroup_new(&pGrp); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB); +** if( rc==SQLITE_OK ){ +** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); +** }else{ +** *ppOut = 0; +** *pnOut = 0; +** } +** +** Refer to the sqlite3_changegroup documentation below for details. +*/ +SQLITE_API int sqlite3changeset_concat( + int nA, /* Number of bytes in buffer pA */ + void *pA, /* Pointer to buffer containing changeset A */ + int nB, /* Number of bytes in buffer pB */ + void *pB, /* Pointer to buffer containing changeset B */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: Buffer containing output changeset */ +); + + +/* +** CAPI3REF: Changegroup Handle +*/ +typedef struct sqlite3_changegroup sqlite3_changegroup; + +/* +** CAPI3REF: Create A New Changegroup Object +** +** An sqlite3_changegroup object is used to combine two or more changesets +** (or patchsets) into a single changeset (or patchset). A single changegroup +** object may combine changesets or patchsets, but not both. The output is +** always in the same format as the input. +** +** If successful, this function returns SQLITE_OK and populates (*pp) with +** a pointer to a new sqlite3_changegroup object before returning. The caller +** should eventually free the returned object using a call to +** sqlite3changegroup_delete(). If an error occurs, an SQLite error code +** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. +** +** The usual usage pattern for an sqlite3_changegroup object is as follows: +** +**
      +**
    • It is created using a call to sqlite3changegroup_new(). +** +**
    • Zero or more changesets (or patchsets) are added to the object +** by calling sqlite3changegroup_add(). +** +**
    • The result of combining all input changesets together is obtained +** by the application via a call to sqlite3changegroup_output(). +** +**
    • The object is deleted using a call to sqlite3changegroup_delete(). +**
    +** +** Any number of calls to add() and output() may be made between the calls to +** new() and delete(), and in any order. +** +** As well as the regular sqlite3changegroup_add() and +** sqlite3changegroup_output() functions, also available are the streaming +** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). +*/ +SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); + +/* +** CAPI3REF: Add A Changeset To A Changegroup +** +** Add all changes within the changeset (or patchset) in buffer pData (size +** nData bytes) to the changegroup. +** +** If the buffer contains a patchset, then all prior calls to this function +** on the same changegroup object must also have specified patchsets. Or, if +** the buffer contains a changeset, so must have the earlier calls to this +** function. Otherwise, SQLITE_ERROR is returned and no changes are added +** to the changegroup. +** +** Rows within the changeset and changegroup are identified by the values in +** their PRIMARY KEY columns. A change in the changeset is considered to +** apply to the same row as a change already present in the changegroup if +** the two rows have the same primary key. +** +** Changes to rows that do not already appear in the changegroup are +** simply copied into it. Or, if both the new changeset and the changegroup +** contain changes that apply to a single row, the final contents of the +** changegroup depends on the type of each change, as follows: +** +** +** +** +**
    Existing Change New Change Output Change +**
    INSERT INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    INSERT UPDATE +** The INSERT change remains in the changegroup. The values in the +** INSERT change are modified as if the row was inserted by the +** existing change and then updated according to the new change. +**
    INSERT DELETE +** The existing INSERT is removed from the changegroup. The DELETE is +** not added. +**
    UPDATE INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    UPDATE UPDATE +** The existing UPDATE remains within the changegroup. It is amended +** so that the accompanying values are as if the row was updated once +** by the existing change and then again by the new change. +**
    UPDATE DELETE +** The existing UPDATE is replaced by the new DELETE within the +** changegroup. +**
    DELETE INSERT +** If one or more of the column values in the row inserted by the +** new change differ from those in the row deleted by the existing +** change, the existing DELETE is replaced by an UPDATE within the +** changegroup. Otherwise, if the inserted row is exactly the same +** as the deleted row, the existing DELETE is simply discarded. +**
    DELETE UPDATE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    DELETE DELETE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
    +** +** If the new changeset contains changes to a table that is already present +** in the changegroup, then the number of columns and the position of the +** primary key columns for the table must be consistent. If this is not the +** case, this function fails with SQLITE_SCHEMA. If the input changeset +** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is +** returned. Or, if an out-of-memory condition occurs during processing, this +** function returns SQLITE_NOMEM. In all cases, if an error occurs the +** final contents of the changegroup is undefined. +** +** If no error occurs, SQLITE_OK is returned. +*/ +SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); + +/* +** CAPI3REF: Obtain A Composite Changeset From A Changegroup +** +** Obtain a buffer containing a changeset (or patchset) representing the +** current contents of the changegroup. If the inputs to the changegroup +** were themselves changesets, the output is a changeset. Or, if the +** inputs were patchsets, the output is also a patchset. +** +** As with the output of the sqlite3session_changeset() and +** sqlite3session_patchset() functions, all changes related to a single +** table are grouped together in the output of this function. Tables appear +** in the same order as for the very first changeset added to the changegroup. +** If the second or subsequent changesets added to the changegroup contain +** changes for tables that do not appear in the first changeset, they are +** appended onto the end of the output changeset, again in the order in +** which they are first encountered. +** +** If an error occurs, an SQLite error code is returned and the output +** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK +** is returned and the output variables are set to the size of and a +** pointer to the output buffer, respectively. In this case it is the +** responsibility of the caller to eventually free the buffer using a +** call to sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_output( + sqlite3_changegroup*, + int *pnData, /* OUT: Size of output buffer in bytes */ + void **ppData /* OUT: Pointer to output buffer */ +); + +/* +** CAPI3REF: Delete A Changegroup Object +*/ +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); + +/* +** CAPI3REF: Apply A Changeset To A Database +** +** Apply a changeset to a database. This function attempts to update the +** "main" database attached to handle db with the changes found in the +** changeset passed via the second and third arguments. +** +** The fourth argument (xFilter) passed to this function is the "filter +** callback". If it is not NULL, then for each table affected by at least one +** change in the changeset, the filter callback is invoked with +** the table name as the second argument, and a copy of the context pointer +** passed as the sixth argument to this function as the first. If the "filter +** callback" returns zero, then no attempt is made to apply any changes to +** the table. Otherwise, if the return value is non-zero or the xFilter +** argument to this function is NULL, all changes related to the table are +** attempted. +** +** For each table that is not excluded by the filter callback, this function +** tests that the target database contains a compatible table. A table is +** considered compatible if all of the following are true: +** +**
      +**
    • The table has the same name as the name recorded in the +** changeset, and +**
    • The table has at least as many columns as recorded in the +** changeset, and +**
    • The table has primary key columns in the same position as +** recorded in the changeset. +**
    +** +** If there is no compatible table, it is not an error, but none of the +** changes associated with the table are applied. A warning message is issued +** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most +** one such warning is issued for each table in the changeset. +** +** For each change for which there is a compatible table, an attempt is made +** to modify the table contents according to the UPDATE, INSERT or DELETE +** change. If a change cannot be applied cleanly, the conflict handler +** function passed as the fifth argument to sqlite3changeset_apply() may be +** invoked. A description of exactly when the conflict handler is invoked for +** each type of change is below. +** +** Unlike the xFilter argument, xConflict may not be passed NULL. The results +** of passing anything other than a valid function pointer as the xConflict +** argument are undefined. +** +** Each time the conflict handler function is invoked, it must return one +** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or +** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned +** if the second argument passed to the conflict handler is either +** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler +** returns an illegal value, any changes already made are rolled back and +** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different +** actions are taken by sqlite3changeset_apply() depending on the value +** returned by each invocation of the conflict-handler function. Refer to +** the documentation for the three +** [SQLITE_CHANGESET_OMIT|available return values] for details. +** +**
    +**
    DELETE Changes
    +** For each DELETE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in +** the changeset the row is deleted from the target database. +** +** If a row with matching primary key values is found, but one or more of +** the non-primary key fields contains a value different from the original +** row value stored in the changeset, the conflict-handler function is +** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the +** database table has more columns than are recorded in the changeset, +** only the values of those non-primary key fields are compared against +** the current database contents - any trailing database table columns +** are ignored. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT +** (which can only happen if a foreign key constraint is violated), the +** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] +** passed as the second argument. This includes the case where the DELETE +** operation is attempted because an earlier call to the conflict handler +** function returned [SQLITE_CHANGESET_REPLACE]. +** +**
    INSERT Changes
    +** For each INSERT change, an attempt is made to insert the new row into +** the database. If the changeset row contains fewer fields than the +** database table, the trailing fields are populated with their default +** values. +** +** If the attempt to insert the row fails because the database already +** contains a row with the same primary key values, the conflict handler +** function is invoked with the second argument set to +** [SQLITE_CHANGESET_CONFLICT]. +** +** If the attempt to insert the row fails because of some other constraint +** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is +** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. +** This includes the case where the INSERT operation is re-attempted because +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +** +**
    UPDATE Changes
    +** For each UPDATE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all modified non-primary key columns also match the values +** stored in the changeset the row is updated within the target database. +** +** If a row with matching primary key values is found, but one or more of +** the modified non-primary key fields contains a value different from an +** original row value stored in the changeset, the conflict-handler function +** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since +** UPDATE changes only contain values for non-primary key fields that are +** to be modified, only those fields need to match the original values to +** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the UPDATE operation is attempted, but SQLite returns +** SQLITE_CONSTRAINT, the conflict-handler function is invoked with +** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. +** This includes the case where the UPDATE operation is attempted after +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +**
    +** +** It is safe to execute SQL statements, including those that write to the +** table that the callback related to, from within the xConflict callback. +** This can be used to further customize the applications conflict +** resolution strategy. +** +** All changes made by this function are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. +*/ +SQLITE_API int sqlite3changeset_apply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); + +/* +** CAPI3REF: Constants Passed To The Conflict Handler +** +** Values that may be passed as the second argument to a conflict-handler. +** +**
    +**
    SQLITE_CHANGESET_DATA
    +** The conflict handler is invoked with CHANGESET_DATA as the second argument +** when processing a DELETE or UPDATE change if a row with the required +** PRIMARY KEY fields is present in the database, but one or more other +** (non primary-key) fields modified by the update do not contain the +** expected "before" values. +** +** The conflicting row, in this case, is the database row with the matching +** primary key. +** +**
    SQLITE_CHANGESET_NOTFOUND
    +** The conflict handler is invoked with CHANGESET_NOTFOUND as the second +** argument when processing a DELETE or UPDATE change if a row with the +** required PRIMARY KEY fields is not present in the database. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
    SQLITE_CHANGESET_CONFLICT
    +** CHANGESET_CONFLICT is passed as the second argument to the conflict +** handler while processing an INSERT change if the operation would result +** in duplicate primary key values. +** +** The conflicting row in this case is the database row with the matching +** primary key. +** +**
    SQLITE_CHANGESET_FOREIGN_KEY
    +** If foreign key handling is enabled, and applying a changeset leaves the +** database in a state containing foreign key violations, the conflict +** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument +** exactly once before the changeset is committed. If the conflict handler +** returns CHANGESET_OMIT, the changes, including those that caused the +** foreign key constraint violation, are committed. Or, if it returns +** CHANGESET_ABORT, the changeset is rolled back. +** +** No current or conflicting row information is provided. The only function +** it is possible to call on the supplied sqlite3_changeset_iter handle +** is sqlite3changeset_fk_conflicts(). +** +**
    SQLITE_CHANGESET_CONSTRAINT
    +** If any other constraint violation occurs while applying a change (i.e. +** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is +** invoked with CHANGESET_CONSTRAINT as the second argument. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
    +*/ +#define SQLITE_CHANGESET_DATA 1 +#define SQLITE_CHANGESET_NOTFOUND 2 +#define SQLITE_CHANGESET_CONFLICT 3 +#define SQLITE_CHANGESET_CONSTRAINT 4 +#define SQLITE_CHANGESET_FOREIGN_KEY 5 + +/* +** CAPI3REF: Constants Returned By The Conflict Handler +** +** A conflict handler callback must return one of the following three values. +** +**
    +**
    SQLITE_CHANGESET_OMIT
    +** If a conflict handler returns this value no special action is taken. The +** change that caused the conflict is not applied. The session module +** continues to the next change in the changeset. +** +**
    SQLITE_CHANGESET_REPLACE
    +** This value may only be returned if the second argument to the conflict +** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this +** is not the case, any changes applied so far are rolled back and the +** call to sqlite3changeset_apply() returns SQLITE_MISUSE. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict +** handler, then the conflicting row is either updated or deleted, depending +** on the type of change. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict +** handler, then the conflicting row is removed from the database and a +** second attempt to apply the change is made. If this second attempt fails, +** the original row is restored to the database before continuing. +** +**
    SQLITE_CHANGESET_ABORT
    +** If this value is returned, any changes applied so far are rolled back +** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. +**
    +*/ +#define SQLITE_CHANGESET_OMIT 0 +#define SQLITE_CHANGESET_REPLACE 1 +#define SQLITE_CHANGESET_ABORT 2 + +/* +** CAPI3REF: Streaming Versions of API functions. +** +** The six streaming API xxx_strm() functions serve similar purposes to the +** corresponding non-streaming API functions: +** +** +** +**
    Streaming functionNon-streaming equivalent
    sqlite3changeset_apply_strm[sqlite3changeset_apply] +**
    sqlite3changeset_concat_strm[sqlite3changeset_concat] +**
    sqlite3changeset_invert_strm[sqlite3changeset_invert] +**
    sqlite3changeset_start_strm[sqlite3changeset_start] +**
    sqlite3session_changeset_strm[sqlite3session_changeset] +**
    sqlite3session_patchset_strm[sqlite3session_patchset] +**
    +** +** Non-streaming functions that accept changesets (or patchsets) as input +** require that the entire changeset be stored in a single buffer in memory. +** Similarly, those that return a changeset or patchset do so by returning +** a pointer to a single large buffer allocated using sqlite3_malloc(). +** Normally this is convenient. However, if an application running in a +** low-memory environment is required to handle very large changesets, the +** large contiguous memory allocations required can become onerous. +** +** In order to avoid this problem, instead of a single large buffer, input +** is passed to a streaming API functions by way of a callback function that +** the sessions module invokes to incrementally request input data as it is +** required. In all cases, a pair of API function parameters such as +** +**
    +**        int nChangeset,
    +**        void *pChangeset,
    +**  
    +** +** Is replaced by: +** +**
    +**        int (*xInput)(void *pIn, void *pData, int *pnData),
    +**        void *pIn,
    +**  
    +** +** Each time the xInput callback is invoked by the sessions module, the first +** argument passed is a copy of the supplied pIn context pointer. The second +** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no +** error occurs the xInput method should copy up to (*pnData) bytes of data +** into the buffer and set (*pnData) to the actual number of bytes copied +** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) +** should be set to zero to indicate this. Or, if an error occurs, an SQLite +** error code should be returned. In all cases, if an xInput callback returns +** an error, all processing is abandoned and the streaming API function +** returns a copy of the error code to the caller. +** +** In the case of sqlite3changeset_start_strm(), the xInput callback may be +** invoked by the sessions module at any point during the lifetime of the +** iterator. If such an xInput callback returns an error, the iterator enters +** an error state, whereby all subsequent calls to iterator functions +** immediately fail with the same error code as returned by xInput. +** +** Similarly, streaming API functions that return changesets (or patchsets) +** return them in chunks by way of a callback function instead of via a +** pointer to a single large buffer. In this case, a pair of parameters such +** as: +** +**
    +**        int *pnChangeset,
    +**        void **ppChangeset,
    +**  
    +** +** Is replaced by: +** +**
    +**        int (*xOutput)(void *pOut, const void *pData, int nData),
    +**        void *pOut
    +**  
    +** +** The xOutput callback is invoked zero or more times to return data to +** the application. The first parameter passed to each call is a copy of the +** pOut pointer supplied by the application. The second parameter, pData, +** points to a buffer nData bytes in size containing the chunk of output +** data being returned. If the xOutput callback successfully processes the +** supplied data, it should return SQLITE_OK to indicate success. Otherwise, +** it should return some other SQLite error code. In this case processing +** is immediately abandoned and the streaming API function returns a copy +** of the xOutput error code to the application. +** +** The sessions module never invokes an xOutput callback with the third +** parameter set to a value less than or equal to zero. Other than this, +** no guarantees are made as to the size of the chunks of data returned. +*/ +SQLITE_API int sqlite3changeset_apply_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); +SQLITE_API int sqlite3changeset_concat_strm( + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changeset_invert_strm( + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changeset_start_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +SQLITE_API int sqlite3session_changeset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3session_patchset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); + + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ + +/******** End of sqlite3session.h *********/ +/******** Begin file fts5.h *********/ /* ** 2014 May 31 ** @@ -8193,6 +10231,9 @@ struct Fts5PhraseIter { ** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** ** xColumnText: ** This function attempts to retrieve the text of column iCol of the ** current document. If successful, (*pz) is set to point to a buffer @@ -8213,15 +10254,29 @@ struct Fts5PhraseIter { ** the query within the current row. Return 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. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). ** +** 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. ** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** ** xRowid: ** Returns the rowid of the current row. ** @@ -8235,11 +10290,13 @@ struct Fts5PhraseIter { ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid ** ** with $p set to a phrase equivalent to the phrase iPhrase of the -** current query is executed. For each row visited, the callback function -** passed as the fourth argument is invoked. The context and API objects -** passed to the callback function may be used to access the properties of -** each matched row. Invoking Api.xUserData() returns a copy of the pointer -** passed as the third argument to pUserData. +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. @@ -8305,7 +10362,7 @@ struct Fts5PhraseIter { ** Fts5PhraseIter iter; ** int iCol, iOff; ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); -** iOff>=0; +** iCol>=0; ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) ** ){ ** // An instance of phrase iPhrase at offset iOff of column iCol @@ -8313,13 +10370,51 @@ struct Fts5PhraseIter { ** ** The Fts5PhraseIter structure is defined above. Applications should not ** modify this structure directly - it should only be used as shown above -** with the xPhraseFirst() and xPhraseNext() API methods. +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** ** xPhraseNext() ** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 1 */ + int iVersion; /* Currently always set to 3 */ void *(*xUserData)(Fts5Context*); @@ -8349,8 +10444,11 @@ struct Fts5ExtensionApi { int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); void *(*xGetAuxdata)(Fts5Context*, int bClear); - void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; /* @@ -8367,7 +10465,7 @@ struct Fts5ExtensionApi { ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: -** This function is used to allocate and inititalize a tokenizer instance. +** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) @@ -8627,4 +10725,8 @@ struct fts5_api { #endif /* _FTS5_H */ - +/******** End of fts5.h *********/ +#else // USE_LIBSQLITE3 + // If users really want to link against the system sqlite3 we +// need to make this file a noop. + #endif \ No newline at end of file diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3.go b/vendor/github.com/mattn/go-sqlite3/sqlite3.go index 852c29986d8..739f91dd0e4 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3.go @@ -7,8 +7,11 @@ package sqlite3 /* #cgo CFLAGS: -std=gnu99 -#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE +#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE=1 #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61 +#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15 +#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC +#cgo CFLAGS: -Wno-deprecated-declarations #ifndef USE_LIBSQLITE3 #include #else @@ -99,9 +102,41 @@ int _sqlite3_create_function( void callbackTrampoline(sqlite3_context*, int, sqlite3_value**); void stepTrampoline(sqlite3_context*, int, sqlite3_value**); void doneTrampoline(sqlite3_context*); + +int compareTrampoline(void*, int, char*, int, char*); +int commitHookTrampoline(void*); +void rollbackHookTrampoline(void*); +void updateHookTrampoline(void*, int, char*, char*, sqlite3_int64); + +#ifdef SQLITE_LIMIT_WORKER_THREADS +# define _SQLITE_HAS_LIMIT +# define SQLITE_LIMIT_LENGTH 0 +# define SQLITE_LIMIT_SQL_LENGTH 1 +# define SQLITE_LIMIT_COLUMN 2 +# define SQLITE_LIMIT_EXPR_DEPTH 3 +# define SQLITE_LIMIT_COMPOUND_SELECT 4 +# define SQLITE_LIMIT_VDBE_OP 5 +# define SQLITE_LIMIT_FUNCTION_ARG 6 +# define SQLITE_LIMIT_ATTACHED 7 +# define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 +# define SQLITE_LIMIT_VARIABLE_NUMBER 9 +# define SQLITE_LIMIT_TRIGGER_DEPTH 10 +# define SQLITE_LIMIT_WORKER_THREADS 11 +# else +# define SQLITE_LIMIT_WORKER_THREADS 11 +#endif + +static int _sqlite3_limit(sqlite3* db, int limitId, int newLimit) { +#ifndef _SQLITE_HAS_LIMIT + return -1; +#else + return sqlite3_limit(db, limitId, newLimit); +#endif +} */ import "C" import ( + "context" "database/sql" "database/sql/driver" "errors" @@ -112,14 +147,15 @@ import ( "runtime" "strconv" "strings" + "sync" "time" "unsafe" ) -// Timestamp formats understood by both this module and SQLite. -// The first format in the slice will be used when saving time values -// into the database. When parsing a string from a timestamp or -// datetime column, the formats are tried in order. +// SQLiteTimestampFormats is timestamp formats understood by both this module +// and SQLite. The first format in the slice will be used when saving time +// values into the database. When parsing a string from a timestamp or datetime +// column, the formats are tried in order. var SQLiteTimestampFormats = []string{ // By default, store timestamps with whatever timezone they come with. // When parsed, they will be returned with the same timezone. @@ -139,21 +175,28 @@ func init() { } // Version returns SQLite library version information. -func Version() (libVersion string, libVersionNumber int, sourceId string) { +func Version() (libVersion string, libVersionNumber int, sourceID string) { libVersion = C.GoString(C.sqlite3_libversion()) libVersionNumber = int(C.sqlite3_libversion_number()) - sourceId = C.GoString(C.sqlite3_sourceid()) - return libVersion, libVersionNumber, sourceId + sourceID = C.GoString(C.sqlite3_sourceid()) + return libVersion, libVersionNumber, sourceID } -// Driver struct. +const ( + SQLITE_DELETE = C.SQLITE_DELETE + SQLITE_INSERT = C.SQLITE_INSERT + SQLITE_UPDATE = C.SQLITE_UPDATE +) + +// SQLiteDriver implement sql.Driver. type SQLiteDriver struct { Extensions []string ConnectHook func(*SQLiteConn) error } -// Conn struct. +// SQLiteConn implement sql.Conn. type SQLiteConn struct { + mu sync.Mutex db *C.sqlite3 loc *time.Location txlock string @@ -161,35 +204,36 @@ type SQLiteConn struct { aggregators []*aggInfo } -// Tx struct. +// SQLiteTx implemen sql.Tx. type SQLiteTx struct { c *SQLiteConn } -// Stmt struct. +// SQLiteStmt implement sql.Stmt. type SQLiteStmt struct { + mu sync.Mutex c *SQLiteConn s *C.sqlite3_stmt - nv int - nn []string t string closed bool cls bool } -// Result struct. +// SQLiteResult implement sql.Result. type SQLiteResult struct { id int64 changes int64 } -// Rows struct. +// SQLiteRows implement sql.Rows. type SQLiteRows struct { s *SQLiteStmt nc int cols []string decltype []string cls bool + closed bool + done chan struct{} } type functionInfo struct { @@ -295,16 +339,90 @@ func (ai *aggInfo) Done(ctx *C.sqlite3_context) { // Commit transaction. func (tx *SQLiteTx) Commit() error { - _, err := tx.c.exec("COMMIT") + _, err := tx.c.exec(context.Background(), "COMMIT", nil) + if err != nil && err.(Error).Code == C.SQLITE_BUSY { + // sqlite3 will leave the transaction open in this scenario. + // However, database/sql considers the transaction complete once we + // return from Commit() - we must clean up to honour its semantics. + tx.c.exec(context.Background(), "ROLLBACK", nil) + } return err } // Rollback transaction. func (tx *SQLiteTx) Rollback() error { - _, err := tx.c.exec("ROLLBACK") + _, err := tx.c.exec(context.Background(), "ROLLBACK", nil) return err } +// RegisterCollation makes a Go function available as a collation. +// +// cmp receives two UTF-8 strings, a and b. The result should be 0 if +// a==b, -1 if a < b, and +1 if a > b. +// +// cmp must always return the same result given the same +// inputs. Additionally, it must have the following properties for all +// strings A, B and C: if A==B then B==A; if A==B and B==C then A==C; +// if AA; if A= 1 { params, err := url.ParseQuery(dsn[pos+1:]) @@ -652,7 +815,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { if err != nil { return nil, fmt.Errorf("Invalid _busy_timeout: %v: %v", val, err) } - busy_timeout = int(iv) + busyTimeout = int(iv) } // _txlock @@ -669,6 +832,30 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { } } + // _foreign_keys + if val := params.Get("_foreign_keys"); val != "" { + switch val { + case "1": + foreignKeys = 1 + case "0": + foreignKeys = 0 + default: + return nil, fmt.Errorf("Invalid _foreign_keys: %v", val) + } + } + + // _recursive_triggers + if val := params.Get("_recursive_triggers"); val != "" { + switch val { + case "1": + recursiveTriggers = 1 + case "0": + recursiveTriggers = 0 + default: + return nil, fmt.Errorf("Invalid _recursive_triggers: %v", val) + } + } + if !strings.HasPrefix(dsn, "file:") { dsn = dsn[:pos] } @@ -689,21 +876,56 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { return nil, errors.New("sqlite succeeded without returning a database") } - rv = C.sqlite3_busy_timeout(db, C.int(busy_timeout)) + rv = C.sqlite3_busy_timeout(db, C.int(busyTimeout)) if rv != C.SQLITE_OK { + C.sqlite3_close_v2(db) return nil, Error{Code: ErrNo(rv)} } + exec := func(s string) error { + cs := C.CString(s) + rv := C.sqlite3_exec(db, cs, nil, nil, nil) + C.free(unsafe.Pointer(cs)) + if rv != C.SQLITE_OK { + return lastError(db) + } + return nil + } + if foreignKeys == 0 { + if err := exec("PRAGMA foreign_keys = OFF;"); err != nil { + C.sqlite3_close_v2(db) + return nil, err + } + } else if foreignKeys == 1 { + if err := exec("PRAGMA foreign_keys = ON;"); err != nil { + C.sqlite3_close_v2(db) + return nil, err + } + } + if recursiveTriggers == 0 { + if err := exec("PRAGMA recursive_triggers = OFF;"); err != nil { + C.sqlite3_close_v2(db) + return nil, err + } + } else if recursiveTriggers == 1 { + if err := exec("PRAGMA recursive_triggers = ON;"); err != nil { + C.sqlite3_close_v2(db) + return nil, err + } + } + conn := &SQLiteConn{db: db, loc: loc, txlock: txlock} if len(d.Extensions) > 0 { if err := conn.loadExtensions(d.Extensions); err != nil { + conn.Close() return nil, err } } if d.ConnectHook != nil { if err := d.ConnectHook(conn); err != nil { + conn.Close() return nil, err } } @@ -713,18 +935,33 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // Close the connection. func (c *SQLiteConn) Close() error { - deleteHandles(c) rv := C.sqlite3_close_v2(c.db) if rv != C.SQLITE_OK { return c.lastError() } + deleteHandles(c) + c.mu.Lock() c.db = nil + c.mu.Unlock() runtime.SetFinalizer(c, nil) return nil } +func (c *SQLiteConn) dbConnOpen() bool { + if c == nil { + return false + } + c.mu.Lock() + defer c.mu.Unlock() + return c.db != nil +} + // Prepare the query string. Return a new statement. func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) { + return c.prepare(context.Background(), query) +} + +func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, error) { pquery := C.CString(query) defer C.free(unsafe.Pointer(pquery)) var s *C.sqlite3_stmt @@ -737,29 +974,54 @@ func (c *SQLiteConn) Prepare(query string) (driver.Stmt, error) { if tail != nil && *tail != '\000' { t = strings.TrimSpace(C.GoString(tail)) } - nv := int(C.sqlite3_bind_parameter_count(s)) - var nn []string - for i := 0; i < nv; i++ { - pn := C.GoString(C.sqlite3_bind_parameter_name(s, C.int(i+1))) - if len(pn) > 1 && pn[0] == '$' && 48 <= pn[1] && pn[1] <= 57 { - nn = append(nn, C.GoString(C.sqlite3_bind_parameter_name(s, C.int(i+1)))) - } - } - ss := &SQLiteStmt{c: c, s: s, nv: nv, nn: nn, t: t} + ss := &SQLiteStmt{c: c, s: s, t: t} runtime.SetFinalizer(ss, (*SQLiteStmt).Close) return ss, nil } +// Run-Time Limit Categories. +// See: http://www.sqlite.org/c3ref/c_limit_attached.html +const ( + SQLITE_LIMIT_LENGTH = C.SQLITE_LIMIT_LENGTH + SQLITE_LIMIT_SQL_LENGTH = C.SQLITE_LIMIT_SQL_LENGTH + SQLITE_LIMIT_COLUMN = C.SQLITE_LIMIT_COLUMN + SQLITE_LIMIT_EXPR_DEPTH = C.SQLITE_LIMIT_EXPR_DEPTH + SQLITE_LIMIT_COMPOUND_SELECT = C.SQLITE_LIMIT_COMPOUND_SELECT + SQLITE_LIMIT_VDBE_OP = C.SQLITE_LIMIT_VDBE_OP + SQLITE_LIMIT_FUNCTION_ARG = C.SQLITE_LIMIT_FUNCTION_ARG + SQLITE_LIMIT_ATTACHED = C.SQLITE_LIMIT_ATTACHED + SQLITE_LIMIT_LIKE_PATTERN_LENGTH = C.SQLITE_LIMIT_LIKE_PATTERN_LENGTH + SQLITE_LIMIT_VARIABLE_NUMBER = C.SQLITE_LIMIT_VARIABLE_NUMBER + SQLITE_LIMIT_TRIGGER_DEPTH = C.SQLITE_LIMIT_TRIGGER_DEPTH + SQLITE_LIMIT_WORKER_THREADS = C.SQLITE_LIMIT_WORKER_THREADS +) + +// 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)) +} + +// SetLimit changes the value of a run-time limits. +// Then this method returns the prior value of the limit. +// See: sqlite3_limit, http://www.sqlite.org/c3ref/limit.html +func (c *SQLiteConn) SetLimit(id int, newVal int) int { + return int(C._sqlite3_limit(c.db, C.int(id), C.int(newVal))) +} + // Close the statement. func (s *SQLiteStmt) Close() error { + s.mu.Lock() + defer s.mu.Unlock() if s.closed { return nil } s.closed = true - if s.c == nil || s.c.db == nil { + if !s.c.dbConnOpen() { return errors.New("sqlite statement with already closed database connection") } rv := C.sqlite3_finalize(s.s) + s.s = nil if rv != C.SQLITE_OK { return s.c.lastError() } @@ -767,9 +1029,9 @@ func (s *SQLiteStmt) Close() error { return nil } -// Return a number of parameters. +// NumInput return a number of parameters. func (s *SQLiteStmt) NumInput() int { - return s.nv + return int(C.sqlite3_bind_parameter_count(s.s)) } type bindArg struct { @@ -777,37 +1039,30 @@ type bindArg struct { v driver.Value } -func (s *SQLiteStmt) bind(args []driver.Value) error { +var placeHolder = []byte{0} + +func (s *SQLiteStmt) bind(args []namedValue) error { rv := C.sqlite3_reset(s.s) if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE { return s.c.lastError() } - var vargs []bindArg - narg := len(args) - vargs = make([]bindArg, narg) - if len(s.nn) > 0 { - for i, v := range s.nn { - if pi, err := strconv.Atoi(v[1:]); err == nil { - vargs[i] = bindArg{pi, args[i]} - } - } - } else { - for i, v := range args { - vargs[i] = bindArg{i + 1, v} + for i, v := range args { + if v.Name != "" { + cname := C.CString(":" + v.Name) + args[i].Ordinal = int(C.sqlite3_bind_parameter_index(s.s, cname)) + C.free(unsafe.Pointer(cname)) } } - for _, varg := range vargs { - n := C.int(varg.n) - v := varg.v - switch v := v.(type) { + for _, arg := range args { + n := C.int(arg.Ordinal) + switch v := arg.Value.(type) { case nil: rv = C.sqlite3_bind_null(s.s, n) case string: if len(v) == 0 { - b := []byte{0} - rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(0)) + rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&placeHolder[0])), C.int(0)) } else { b := []byte(v) rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b))) @@ -823,11 +1078,11 @@ func (s *SQLiteStmt) bind(args []driver.Value) error { case float64: rv = C.sqlite3_bind_double(s.s, n, C.double(v)) case []byte: - if len(v) == 0 { - rv = C._sqlite3_bind_blob(s.s, n, nil, 0) - } else { - rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(len(v))) + ln := len(v) + if ln == 0 { + v = placeHolder } + rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(ln)) case time.Time: b := []byte(v.Format(SQLiteTimestampFormats[0])) rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b))) @@ -841,29 +1096,90 @@ func (s *SQLiteStmt) bind(args []driver.Value) error { // Query the statement with arguments. Return records. func (s *SQLiteStmt) Query(args []driver.Value) (driver.Rows, error) { + list := make([]namedValue, len(args)) + for i, v := range args { + list[i] = namedValue{ + Ordinal: i + 1, + Value: v, + } + } + return s.query(context.Background(), list) +} + +func (s *SQLiteStmt) query(ctx context.Context, args []namedValue) (driver.Rows, error) { if err := s.bind(args); err != nil { return nil, err } - return &SQLiteRows{s, int(C.sqlite3_column_count(s.s)), nil, nil, s.cls}, nil + + rows := &SQLiteRows{ + s: s, + nc: int(C.sqlite3_column_count(s.s)), + cols: nil, + decltype: nil, + cls: s.cls, + closed: false, + done: make(chan struct{}), + } + + go func(db *C.sqlite3) { + select { + case <-ctx.Done(): + select { + case <-rows.done: + default: + C.sqlite3_interrupt(db) + rows.Close() + } + case <-rows.done: + } + }(s.c.db) + + return rows, nil } -// Return last inserted ID. +// LastInsertId teturn last inserted ID. func (r *SQLiteResult) LastInsertId() (int64, error) { return r.id, nil } -// Return how many rows affected. +// RowsAffected return how many rows affected. func (r *SQLiteResult) RowsAffected() (int64, error) { return r.changes, nil } -// Execute the statement with arguments. Return result object. +// Exec execute the statement with arguments. Return result object. func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) { + list := make([]namedValue, len(args)) + for i, v := range args { + list[i] = namedValue{ + Ordinal: i + 1, + Value: v, + } + } + return s.exec(context.Background(), list) +} + +func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result, error) { if err := s.bind(args); err != nil { C.sqlite3_reset(s.s) C.sqlite3_clear_bindings(s.s) return nil, err } + + done := make(chan struct{}) + defer close(done) + go func(db *C.sqlite3) { + select { + case <-done: + case <-ctx.Done(): + select { + case <-done: + default: + C.sqlite3_interrupt(db) + } + } + }(s.c.db) + var rowid, changes C.longlong rv := C._sqlite3_step(s.s, &rowid, &changes) if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE { @@ -872,27 +1188,39 @@ func (s *SQLiteStmt) Exec(args []driver.Value) (driver.Result, error) { C.sqlite3_clear_bindings(s.s) return nil, err } - return &SQLiteResult{int64(rowid), int64(changes)}, nil + + return &SQLiteResult{id: int64(rowid), changes: int64(changes)}, nil } // Close the rows. func (rc *SQLiteRows) Close() error { - if rc.s.closed { + rc.s.mu.Lock() + if rc.s.closed || rc.closed { + rc.s.mu.Unlock() return nil } + rc.closed = true + if rc.done != nil { + close(rc.done) + } if rc.cls { + rc.s.mu.Unlock() return rc.s.Close() } rv := C.sqlite3_reset(rc.s.s) if rv != C.SQLITE_OK { + rc.s.mu.Unlock() return rc.s.c.lastError() } + rc.s.mu.Unlock() return nil } -// Return column names. +// Columns return column names. func (rc *SQLiteRows) Columns() []string { - if rc.nc != len(rc.cols) { + rc.s.mu.Lock() + defer rc.s.mu.Unlock() + if rc.s.s != nil && rc.nc != len(rc.cols) { rc.cols = make([]string, rc.nc) for i := 0; i < rc.nc; i++ { rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i))) @@ -901,9 +1229,8 @@ func (rc *SQLiteRows) Columns() []string { return rc.cols } -// Return column types. -func (rc *SQLiteRows) DeclTypes() []string { - if rc.decltype == nil { +func (rc *SQLiteRows) declTypes() []string { + if rc.s.s != nil && rc.decltype == nil { rc.decltype = make([]string, rc.nc) for i := 0; i < rc.nc; i++ { rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))) @@ -912,8 +1239,20 @@ func (rc *SQLiteRows) DeclTypes() []string { return rc.decltype } -// Move cursor to next. +// DeclTypes return column types. +func (rc *SQLiteRows) DeclTypes() []string { + rc.s.mu.Lock() + defer rc.s.mu.Unlock() + return rc.declTypes() +} + +// Next move cursor to next. func (rc *SQLiteRows) Next(dest []driver.Value) error { + if rc.s.closed { + return io.EOF + } + rc.s.mu.Lock() + defer rc.s.mu.Unlock() rv := C.sqlite3_step(rc.s.s) if rv == C.SQLITE_DONE { return io.EOF @@ -926,7 +1265,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error { return nil } - rc.DeclTypes() + rc.declTypes() for i := range dest { switch C.sqlite3_column_type(rc.s.s, C.int(i)) { @@ -939,10 +1278,11 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error { // large to be a reasonable timestamp in seconds. if val > 1e12 || val < -1e12 { val *= int64(time.Millisecond) // convert ms to nsec + t = time.Unix(0, val) } else { - val *= int64(time.Second) // convert sec to nsec + t = time.Unix(val, 0) } - t = time.Unix(0, val).UTC() + t = t.UTC() if rc.s.c.loc != nil { t = t.In(rc.s.c.loc) } diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go new file mode 100644 index 00000000000..78ced188fb4 --- /dev/null +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go @@ -0,0 +1,103 @@ +// Copyright (C) 2014 Yasuhiro Matsumoto . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package sqlite3 + +/* + +#ifndef USE_LIBSQLITE3 +#include +#else +#include +#endif +#include +// These wrappers are necessary because SQLITE_TRANSIENT +// is a pointer constant, and cgo doesn't translate them correctly. + +static inline void my_result_text(sqlite3_context *ctx, char *p, int np) { + sqlite3_result_text(ctx, p, np, SQLITE_TRANSIENT); +} + +static inline void my_result_blob(sqlite3_context *ctx, void *p, int np) { + sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT); +} +*/ +import "C" + +import ( + "math" + "reflect" + "unsafe" +) + +const i64 = unsafe.Sizeof(int(0)) > 4 + +// SQLiteContext behave sqlite3_context +type SQLiteContext C.sqlite3_context + +// ResultBool sets the result of an SQL function. +func (c *SQLiteContext) ResultBool(b bool) { + if b { + c.ResultInt(1) + } else { + c.ResultInt(0) + } +} + +// ResultBlob sets the result of an SQL function. +// See: sqlite3_result_blob, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultBlob(b []byte) { + if i64 && len(b) > math.MaxInt32 { + C.sqlite3_result_error_toobig((*C.sqlite3_context)(c)) + return + } + var p *byte + if len(b) > 0 { + p = &b[0] + } + C.my_result_blob((*C.sqlite3_context)(c), unsafe.Pointer(p), C.int(len(b))) +} + +// ResultDouble sets the result of an SQL function. +// See: sqlite3_result_double, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultDouble(d float64) { + C.sqlite3_result_double((*C.sqlite3_context)(c), C.double(d)) +} + +// ResultInt sets the result of an SQL function. +// See: sqlite3_result_int, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultInt(i int) { + if i64 && (i > math.MaxInt32 || i < math.MinInt32) { + C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) + } else { + C.sqlite3_result_int((*C.sqlite3_context)(c), C.int(i)) + } +} + +// ResultInt64 sets the result of an SQL function. +// See: sqlite3_result_int64, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultInt64(i int64) { + C.sqlite3_result_int64((*C.sqlite3_context)(c), C.sqlite3_int64(i)) +} + +// ResultNull sets the result of an SQL function. +// See: sqlite3_result_null, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultNull() { + C.sqlite3_result_null((*C.sqlite3_context)(c)) +} + +// ResultText sets the result of an SQL function. +// See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultText(s string) { + h := (*reflect.StringHeader)(unsafe.Pointer(&s)) + cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len) + C.my_result_text((*C.sqlite3_context)(c), cs, l) +} + +// ResultZeroblob sets the result of an SQL function. +// See: sqlite3_result_zeroblob, http://sqlite.org/c3ref/result_blob.html +func (c *SQLiteContext) ResultZeroblob(n int) { + C.sqlite3_result_zeroblob((*C.sqlite3_context)(c), C.int(n)) +} diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go new file mode 100644 index 00000000000..f9e08e142a2 --- /dev/null +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go @@ -0,0 +1,69 @@ +// Copyright (C) 2014 Yasuhiro Matsumoto . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +// +build go1.8 + +package sqlite3 + +import ( + "database/sql/driver" + "errors" + + "context" +) + +// Ping implement Pinger. +func (c *SQLiteConn) Ping(ctx context.Context) error { + if c.db == nil { + return errors.New("Connection was closed") + } + return nil +} + +// QueryContext implement QueryerContext. +func (c *SQLiteConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return c.query(ctx, query, list) +} + +// ExecContext implement ExecerContext. +func (c *SQLiteConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return c.exec(ctx, query, list) +} + +// PrepareContext implement ConnPrepareContext. +func (c *SQLiteConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + return c.prepare(ctx, query) +} + +// BeginTx implement ConnBeginTx. +func (c *SQLiteConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + return c.begin(ctx) +} + +// QueryContext implement QueryerContext. +func (s *SQLiteStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.query(ctx, list) +} + +// ExecContext implement ExecerContext. +func (s *SQLiteStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.exec(ctx, list) +} diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go index 4c5492bc238..e960626dcac 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_icu.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. -// +build icu +// +build icu package sqlite3 diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go index 135863e01b1..e4557e64f07 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go @@ -10,5 +10,6 @@ package sqlite3 #cgo CFLAGS: -DUSE_LIBSQLITE3 #cgo linux LDFLAGS: -lsqlite3 #cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3 +#cgo solaris LDFLAGS: -lsqlite3 */ import "C" diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go index 55c8ad733c4..bb7e25f535d 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go @@ -7,7 +7,11 @@ package sqlite3 /* +#ifndef USE_LIBSQLITE3 #include +#else +#include +#endif #include */ import "C" @@ -27,6 +31,7 @@ func (c *SQLiteConn) loadExtensions(extensions []string) error { defer C.free(unsafe.Pointer(cext)) rv = C.sqlite3_load_extension(c.db, cext, nil, nil) if rv != C.SQLITE_OK { + C.sqlite3_enable_load_extension(c.db, 0) return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } } @@ -38,6 +43,7 @@ func (c *SQLiteConn) loadExtensions(extensions []string) error { return nil } +// LoadExtension load the sqlite3 extension. func (c *SQLiteConn) LoadExtension(lib string, entry string) error { rv := C.sqlite3_enable_load_extension(c.db, 1) if rv != C.SQLITE_OK { diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_other.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_other.go index a20d02c3539..f721b5e21c2 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_other.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_other.go @@ -9,5 +9,6 @@ package sqlite3 /* #cgo CFLAGS: -I. #cgo linux LDFLAGS: -ldl +#cgo solaris LDFLAGS: -lc */ import "C" diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go deleted file mode 100644 index 84b65d93d5c..00000000000 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_test/sqltest.go +++ /dev/null @@ -1,409 +0,0 @@ -package sqlite3_test - -import ( - "database/sql" - "fmt" - "math/rand" - "regexp" - "strconv" - "sync" - "testing" - "time" -) - -type Dialect int - -const ( - SQLITE Dialect = iota - POSTGRESQL - MYSQL -) - -type DB struct { - *testing.T - *sql.DB - dialect Dialect - once sync.Once -} - -var db *DB - -// the following tables will be created and dropped during the test -var testTables = []string{"foo", "bar", "t", "bench"} - -var tests = []testing.InternalTest{ - {"TestBlobs", TestBlobs}, - {"TestManyQueryRow", TestManyQueryRow}, - {"TestTxQuery", TestTxQuery}, - {"TestPreparedStmt", TestPreparedStmt}, -} - -var benchmarks = []testing.InternalBenchmark{ - {"BenchmarkExec", BenchmarkExec}, - {"BenchmarkQuery", BenchmarkQuery}, - {"BenchmarkParams", BenchmarkParams}, - {"BenchmarkStmt", BenchmarkStmt}, - {"BenchmarkRows", BenchmarkRows}, - {"BenchmarkStmtRows", BenchmarkStmtRows}, -} - -// RunTests runs the SQL test suite -func RunTests(t *testing.T, d *sql.DB, dialect Dialect) { - db = &DB{t, d, dialect, sync.Once{}} - testing.RunTests(func(string, string) (bool, error) { return true, nil }, tests) - - if !testing.Short() { - for _, b := range benchmarks { - fmt.Printf("%-20s", b.Name) - r := testing.Benchmark(b.F) - fmt.Printf("%10d %10.0f req/s\n", r.N, float64(r.N)/r.T.Seconds()) - } - } - db.tearDown() -} - -func (db *DB) mustExec(sql string, args ...interface{}) sql.Result { - res, err := db.Exec(sql, args...) - if err != nil { - db.Fatalf("Error running %q: %v", sql, err) - } - return res -} - -func (db *DB) tearDown() { - for _, tbl := range testTables { - switch db.dialect { - case SQLITE: - db.mustExec("drop table if exists " + tbl) - case MYSQL, POSTGRESQL: - db.mustExec("drop table if exists " + tbl) - default: - db.Fatal("unkown dialect") - } - } -} - -// q replaces ? parameters if needed -func (db *DB) q(sql string) string { - switch db.dialect { - case POSTGRESQL: // repace with $1, $2, .. - qrx := regexp.MustCompile(`\?`) - n := 0 - return qrx.ReplaceAllStringFunc(sql, func(string) string { - n++ - return "$" + strconv.Itoa(n) - }) - } - return sql -} - -func (db *DB) blobType(size int) string { - switch db.dialect { - case SQLITE: - return fmt.Sprintf("blob[%d]", size) - case POSTGRESQL: - return "bytea" - case MYSQL: - return fmt.Sprintf("VARBINARY(%d)", size) - } - panic("unkown dialect") -} - -func (db *DB) serialPK() string { - switch db.dialect { - case SQLITE: - return "integer primary key autoincrement" - case POSTGRESQL: - return "serial primary key" - case MYSQL: - return "integer primary key auto_increment" - } - panic("unkown dialect") -} - -func (db *DB) now() string { - switch db.dialect { - case SQLITE: - return "datetime('now')" - case POSTGRESQL: - return "now()" - case MYSQL: - return "now()" - } - panic("unkown dialect") -} - -func makeBench() { - if _, err := db.Exec("create table bench (n varchar(32), i integer, d double, s varchar(32), t datetime)"); err != nil { - panic(err) - } - st, err := db.Prepare("insert into bench values (?, ?, ?, ?, ?)") - if err != nil { - panic(err) - } - defer st.Close() - for i := 0; i < 100; i++ { - if _, err = st.Exec(nil, i, float64(i), fmt.Sprintf("%d", i), time.Now()); err != nil { - panic(err) - } - } -} - -func TestResult(t *testing.T) { - db.tearDown() - db.mustExec("create temporary table test (id " + db.serialPK() + ", name varchar(10))") - - for i := 1; i < 3; i++ { - r := db.mustExec(db.q("insert into test (name) values (?)"), fmt.Sprintf("row %d", i)) - n, err := r.RowsAffected() - if err != nil { - t.Fatal(err) - } - if n != 1 { - t.Errorf("got %v, want %v", n, 1) - } - n, err = r.LastInsertId() - if err != nil { - t.Fatal(err) - } - if n != int64(i) { - t.Errorf("got %v, want %v", n, i) - } - } - if _, err := db.Exec("error!"); err == nil { - t.Fatalf("expected error") - } -} - -func TestBlobs(t *testing.T) { - db.tearDown() - var blob = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - db.mustExec("create table foo (id integer primary key, bar " + db.blobType(16) + ")") - db.mustExec(db.q("insert into foo (id, bar) values(?,?)"), 0, blob) - - want := fmt.Sprintf("%x", blob) - - b := make([]byte, 16) - err := db.QueryRow(db.q("select bar from foo where id = ?"), 0).Scan(&b) - got := fmt.Sprintf("%x", b) - if err != nil { - t.Errorf("[]byte scan: %v", err) - } else if got != want { - t.Errorf("for []byte, got %q; want %q", got, want) - } - - err = db.QueryRow(db.q("select bar from foo where id = ?"), 0).Scan(&got) - want = string(blob) - if err != nil { - t.Errorf("string scan: %v", err) - } else if got != want { - t.Errorf("for string, got %q; want %q", got, want) - } -} - -func TestManyQueryRow(t *testing.T) { - if testing.Short() { - t.Log("skipping in short mode") - return - } - db.tearDown() - db.mustExec("create table foo (id integer primary key, name varchar(50))") - db.mustExec(db.q("insert into foo (id, name) values(?,?)"), 1, "bob") - var name string - for i := 0; i < 10000; i++ { - err := db.QueryRow(db.q("select name from foo where id = ?"), 1).Scan(&name) - if err != nil || name != "bob" { - t.Fatalf("on query %d: err=%v, name=%q", i, err, name) - } - } -} - -func TestTxQuery(t *testing.T) { - db.tearDown() - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer tx.Rollback() - - _, err = tx.Exec("create table foo (id integer primary key, name varchar(50))") - if err != nil { - t.Fatal(err) - } - - _, err = tx.Exec(db.q("insert into foo (id, name) values(?,?)"), 1, "bob") - if err != nil { - t.Fatal(err) - } - - r, err := tx.Query(db.q("select name from foo where id = ?"), 1) - if err != nil { - t.Fatal(err) - } - defer r.Close() - - if !r.Next() { - if r.Err() != nil { - t.Fatal(err) - } - t.Fatal("expected one rows") - } - - var name string - err = r.Scan(&name) - if err != nil { - t.Fatal(err) - } -} - -func TestPreparedStmt(t *testing.T) { - db.tearDown() - db.mustExec("CREATE TABLE t (count INT)") - sel, err := db.Prepare("SELECT count FROM t ORDER BY count DESC") - if err != nil { - t.Fatalf("prepare 1: %v", err) - } - ins, err := db.Prepare(db.q("INSERT INTO t (count) VALUES (?)")) - if err != nil { - t.Fatalf("prepare 2: %v", err) - } - - for n := 1; n <= 3; n++ { - if _, err := ins.Exec(n); err != nil { - t.Fatalf("insert(%d) = %v", n, err) - } - } - - const nRuns = 10 - var wg sync.WaitGroup - for i := 0; i < nRuns; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < 10; j++ { - count := 0 - if err := sel.QueryRow().Scan(&count); err != nil && err != sql.ErrNoRows { - t.Errorf("Query: %v", err) - return - } - if _, err := ins.Exec(rand.Intn(100)); err != nil { - t.Errorf("Insert: %v", err) - return - } - } - }() - } - wg.Wait() -} - -// Benchmarks need to use panic() since b.Error errors are lost when -// running via testing.Benchmark() I would like to run these via go -// test -bench but calling Benchmark() from a benchmark test -// currently hangs go. - -func BenchmarkExec(b *testing.B) { - for i := 0; i < b.N; i++ { - if _, err := db.Exec("select 1"); err != nil { - panic(err) - } - } -} - -func BenchmarkQuery(b *testing.B) { - for i := 0; i < b.N; i++ { - var n sql.NullString - var i int - var f float64 - var s string - // var t time.Time - if err := db.QueryRow("select null, 1, 1.1, 'foo'").Scan(&n, &i, &f, &s); err != nil { - panic(err) - } - } -} - -func BenchmarkParams(b *testing.B) { - for i := 0; i < b.N; i++ { - var n sql.NullString - var i int - var f float64 - var s string - // var t time.Time - if err := db.QueryRow("select ?, ?, ?, ?", nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil { - panic(err) - } - } -} - -func BenchmarkStmt(b *testing.B) { - st, err := db.Prepare("select ?, ?, ?, ?") - if err != nil { - panic(err) - } - defer st.Close() - - for n := 0; n < b.N; n++ { - var n sql.NullString - var i int - var f float64 - var s string - // var t time.Time - if err := st.QueryRow(nil, 1, 1.1, "foo").Scan(&n, &i, &f, &s); err != nil { - panic(err) - } - } -} - -func BenchmarkRows(b *testing.B) { - db.once.Do(makeBench) - - for n := 0; n < b.N; n++ { - var n sql.NullString - var i int - var f float64 - var s string - var t time.Time - r, err := db.Query("select * from bench") - if err != nil { - panic(err) - } - for r.Next() { - if err = r.Scan(&n, &i, &f, &s, &t); err != nil { - panic(err) - } - } - if err = r.Err(); err != nil { - panic(err) - } - } -} - -func BenchmarkStmtRows(b *testing.B) { - db.once.Do(makeBench) - - st, err := db.Prepare("select * from bench") - if err != nil { - panic(err) - } - defer st.Close() - - for n := 0; n < b.N; n++ { - var n sql.NullString - var i int - var f float64 - var s string - var t time.Time - r, err := st.Query() - if err != nil { - panic(err) - } - for r.Next() { - if err = r.Scan(&n, &i, &f, &s, &t); err != nil { - panic(err) - } - } - if err = r.Err(); err != nil { - panic(err) - } - } -} diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go new file mode 100644 index 00000000000..ece60355eaa --- /dev/null +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go @@ -0,0 +1,285 @@ +// Copyright (C) 2016 Yasuhiro Matsumoto . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. +// +build trace + +package sqlite3 + +/* +#ifndef USE_LIBSQLITE3 +#include +#else +#include +#endif +#include + +int traceCallbackTrampoline(unsigned int traceEventCode, void *ctx, void *p, void *x); +*/ +import "C" + +import ( + "fmt" + "strings" + "sync" + "unsafe" +) + +// Trace... constants identify the possible events causing callback invocation. +// Values are same as the corresponding SQLite Trace Event Codes. +const ( + TraceStmt = C.SQLITE_TRACE_STMT + TraceProfile = C.SQLITE_TRACE_PROFILE + TraceRow = C.SQLITE_TRACE_ROW + TraceClose = C.SQLITE_TRACE_CLOSE +) + +type TraceInfo struct { + // Pack together the shorter fields, to keep the struct smaller. + // On a 64-bit machine there would be padding + // between EventCode and ConnHandle; having AutoCommit here is "free": + EventCode uint32 + AutoCommit bool + ConnHandle uintptr + + // Usually filled, unless EventCode = TraceClose = SQLITE_TRACE_CLOSE: + // identifier for a prepared statement: + StmtHandle uintptr + + // Two strings filled when EventCode = TraceStmt = SQLITE_TRACE_STMT: + // (1) either the unexpanded SQL text of the prepared statement, or + // an SQL comment that indicates the invocation of a trigger; + // (2) expanded SQL, if requested and if (1) is not an SQL comment. + StmtOrTrigger string + ExpandedSQL string // only if requested (TraceConfig.WantExpandedSQL = true) + + // filled when EventCode = TraceProfile = SQLITE_TRACE_PROFILE: + // estimated number of nanoseconds that the prepared statement took to run: + RunTimeNanosec int64 + + DBError Error +} + +// TraceUserCallback gives the signature for a trace function +// provided by the user (Go application programmer). +// SQLite 3.14 documentation (as of September 2, 2016) +// for SQL Trace Hook = sqlite3_trace_v2(): +// The integer return value from the callback is currently ignored, +// though this may change in future releases. Callback implementations +// should return zero to ensure future compatibility. +type TraceUserCallback func(TraceInfo) int + +type TraceConfig struct { + Callback TraceUserCallback + EventMask C.uint + WantExpandedSQL bool +} + +func fillDBError(dbErr *Error, db *C.sqlite3) { + // See SQLiteConn.lastError(), in file 'sqlite3.go' at the time of writing (Sept 5, 2016) + dbErr.Code = ErrNo(C.sqlite3_errcode(db)) + dbErr.ExtendedCode = ErrNoExtended(C.sqlite3_extended_errcode(db)) + dbErr.err = C.GoString(C.sqlite3_errmsg(db)) +} + +func fillExpandedSQL(info *TraceInfo, db *C.sqlite3, pStmt unsafe.Pointer) { + if pStmt == nil { + panic("No SQLite statement pointer in P arg of trace_v2 callback") + } + + expSQLiteCStr := C.sqlite3_expanded_sql((*C.sqlite3_stmt)(pStmt)) + if expSQLiteCStr == nil { + fillDBError(&info.DBError, db) + return + } + info.ExpandedSQL = C.GoString(expSQLiteCStr) +} + +//export traceCallbackTrampoline +func traceCallbackTrampoline( + traceEventCode C.uint, + // Parameter named 'C' in SQLite docs = Context given at registration: + ctx unsafe.Pointer, + // Parameter named 'P' in SQLite docs (Primary event data?): + p unsafe.Pointer, + // Parameter named 'X' in SQLite docs (eXtra event data?): + xValue unsafe.Pointer) C.int { + + if ctx == nil { + panic(fmt.Sprintf("No context (ev 0x%x)", traceEventCode)) + } + + contextDB := (*C.sqlite3)(ctx) + connHandle := uintptr(ctx) + + var traceConf TraceConfig + var found bool + if traceEventCode == TraceClose { + // clean up traceMap: 'pop' means get and delete + traceConf, found = popTraceMapping(connHandle) + } else { + traceConf, found = lookupTraceMapping(connHandle) + } + + if !found { + panic(fmt.Sprintf("Mapping not found for handle 0x%x (ev 0x%x)", + connHandle, traceEventCode)) + } + + var info TraceInfo + + info.EventCode = uint32(traceEventCode) + info.AutoCommit = (int(C.sqlite3_get_autocommit(contextDB)) != 0) + info.ConnHandle = connHandle + + switch traceEventCode { + case TraceStmt: + info.StmtHandle = uintptr(p) + + var xStr string + if xValue != nil { + xStr = C.GoString((*C.char)(xValue)) + } + info.StmtOrTrigger = xStr + if !strings.HasPrefix(xStr, "--") { + // Not SQL comment, therefore the current event + // is not related to a trigger. + // The user might want to receive the expanded SQL; + // let's check: + if traceConf.WantExpandedSQL { + fillExpandedSQL(&info, contextDB, p) + } + } + + case TraceProfile: + info.StmtHandle = uintptr(p) + + if xValue == nil { + panic("NULL pointer in X arg of trace_v2 callback for SQLITE_TRACE_PROFILE event") + } + + info.RunTimeNanosec = *(*int64)(xValue) + + // sample the error //TODO: is it safe? is it useful? + fillDBError(&info.DBError, contextDB) + + case TraceRow: + info.StmtHandle = uintptr(p) + + case TraceClose: + handle := uintptr(p) + if handle != info.ConnHandle { + panic(fmt.Sprintf("Different conn handle 0x%x (expected 0x%x) in SQLITE_TRACE_CLOSE event.", + handle, info.ConnHandle)) + } + + default: + // Pass unsupported events to the user callback (if configured); + // let the user callback decide whether to panic or ignore them. + } + + // Do not execute user callback when the event was not requested by user! + // Remember that the Close event is always selected when + // registering this callback trampoline with SQLite --- for cleanup. + // In the future there may be more events forced to "selected" in SQLite + // for the driver's needs. + if traceConf.EventMask&traceEventCode == 0 { + return 0 + } + + r := 0 + if traceConf.Callback != nil { + r = traceConf.Callback(info) + } + return C.int(r) +} + +type traceMapEntry struct { + config TraceConfig +} + +var traceMapLock sync.Mutex +var traceMap = make(map[uintptr]traceMapEntry) + +func addTraceMapping(connHandle uintptr, traceConf TraceConfig) { + traceMapLock.Lock() + defer traceMapLock.Unlock() + + oldEntryCopy, found := traceMap[connHandle] + if found { + panic(fmt.Sprintf("Adding trace config %v: handle 0x%x already registered (%v).", + traceConf, connHandle, oldEntryCopy.config)) + } + traceMap[connHandle] = traceMapEntry{config: traceConf} + fmt.Printf("Added trace config %v: handle 0x%x.\n", traceConf, connHandle) +} + +func lookupTraceMapping(connHandle uintptr) (TraceConfig, bool) { + traceMapLock.Lock() + defer traceMapLock.Unlock() + + entryCopy, found := traceMap[connHandle] + return entryCopy.config, found +} + +// 'pop' = get and delete from map before returning the value to the caller +func popTraceMapping(connHandle uintptr) (TraceConfig, bool) { + traceMapLock.Lock() + defer traceMapLock.Unlock() + + entryCopy, found := traceMap[connHandle] + if found { + delete(traceMap, connHandle) + fmt.Printf("Pop handle 0x%x: deleted trace config %v.\n", connHandle, entryCopy.config) + } + return entryCopy.config, found +} + +// SetTrace installs or removes the trace callback for the given database connection. +// It's not named 'RegisterTrace' because only one callback can be kept and called. +// Calling SetTrace a second time on same database connection +// overrides (cancels) any prior callback and all its settings: +// event mask, etc. +func (c *SQLiteConn) SetTrace(requested *TraceConfig) error { + connHandle := uintptr(unsafe.Pointer(c.db)) + + _, _ = popTraceMapping(connHandle) + + if requested == nil { + // The traceMap entry was deleted already by popTraceMapping(): + // can disable all events now, no need to watch for TraceClose. + err := c.setSQLiteTrace(0) + return err + } + + reqCopy := *requested + + // Disable potentially expensive operations + // if their result will not be used. We are doing this + // just in case the caller provided nonsensical input. + if reqCopy.EventMask&TraceStmt == 0 { + reqCopy.WantExpandedSQL = false + } + + addTraceMapping(connHandle, reqCopy) + + // The callback trampoline function does cleanup on Close event, + // regardless of the presence or absence of the user callback. + // Therefore it needs the Close event to be selected: + actualEventMask := uint(reqCopy.EventMask | TraceClose) + err := c.setSQLiteTrace(actualEventMask) + return err +} + +func (c *SQLiteConn) setSQLiteTrace(sqliteEventMask uint) error { + rv := C.sqlite3_trace_v2(c.db, + C.uint(sqliteEventMask), + (*[0]byte)(unsafe.Pointer(C.traceCallbackTrampoline)), + unsafe.Pointer(c.db)) // Fourth arg is same as first: we are + // passing the database connection handle as callback context. + + if rv != C.SQLITE_OK { + return c.lastError() + } + return nil +} diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_type.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_type.go new file mode 100644 index 00000000000..200d071cd07 --- /dev/null +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_type.go @@ -0,0 +1,57 @@ +package sqlite3 + +/* +#ifndef USE_LIBSQLITE3 +#include +#else +#include +#endif +*/ +import "C" +import ( + "reflect" + "time" +) + +// ColumnTypeDatabaseTypeName implement RowsColumnTypeDatabaseTypeName. +func (rc *SQLiteRows) ColumnTypeDatabaseTypeName(i int) string { + return C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))) +} + +/* +func (rc *SQLiteRows) ColumnTypeLength(index int) (length int64, ok bool) { + return 0, false +} + +func (rc *SQLiteRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + return 0, 0, false +} +*/ + +// ColumnTypeNullable implement RowsColumnTypeNullable. +func (rc *SQLiteRows) ColumnTypeNullable(i int) (nullable, ok bool) { + return true, true +} + +// ColumnTypeScanType implement RowsColumnTypeScanType. +func (rc *SQLiteRows) ColumnTypeScanType(i int) reflect.Type { + switch C.sqlite3_column_type(rc.s.s, C.int(i)) { + case C.SQLITE_INTEGER: + switch C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))) { + case "timestamp", "datetime", "date": + return reflect.TypeOf(time.Time{}) + case "boolean": + return reflect.TypeOf(false) + } + return reflect.TypeOf(int64(0)) + case C.SQLITE_FLOAT: + return reflect.TypeOf(float64(0)) + case C.SQLITE_BLOB: + return reflect.SliceOf(reflect.TypeOf(byte(0))) + case C.SQLITE_NULL: + return reflect.TypeOf(nil) + case C.SQLITE_TEXT: + return reflect.TypeOf("") + } + return reflect.SliceOf(reflect.TypeOf(byte(0))) +} diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_vtable.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_vtable.go new file mode 100644 index 00000000000..8bef291d472 --- /dev/null +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_vtable.go @@ -0,0 +1,646 @@ +// Copyright (C) 2014 Yasuhiro Matsumoto . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. +// +build vtable + +package sqlite3 + +/* +#cgo CFLAGS: -std=gnu99 +#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE +#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61 +#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15 +#cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA=1 +#cgo CFLAGS: -Wno-deprecated-declarations + +#ifndef USE_LIBSQLITE3 +#include +#else +#include +#endif +#include +#include +#include + +static inline char *_sqlite3_mprintf(char *zFormat, char *arg) { + return sqlite3_mprintf(zFormat, arg); +} + +typedef struct goVTab goVTab; + +struct goVTab { + sqlite3_vtab base; + void *vTab; +}; + +uintptr_t goMInit(void *db, void *pAux, int argc, char **argv, char **pzErr, int isCreate); + +static int cXInit(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr, int isCreate) { + void *vTab = (void *)goMInit(db, pAux, argc, (char**)argv, pzErr, isCreate); + if (!vTab || *pzErr) { + return SQLITE_ERROR; + } + goVTab *pvTab = (goVTab *)sqlite3_malloc(sizeof(goVTab)); + if (!pvTab) { + *pzErr = sqlite3_mprintf("%s", "Out of memory"); + return SQLITE_NOMEM; + } + memset(pvTab, 0, sizeof(goVTab)); + pvTab->vTab = vTab; + + *ppVTab = (sqlite3_vtab *)pvTab; + *pzErr = 0; + return SQLITE_OK; +} + +static inline int cXCreate(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { + return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 1); +} +static inline int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { + return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 0); +} + +char* goVBestIndex(void *pVTab, void *icp); + +static inline int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) { + char *pzErr = goVBestIndex(((goVTab*)pVTab)->vTab, info); + if (pzErr) { + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = pzErr; + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +char* goVRelease(void *pVTab, int isDestroy); + +static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) { + char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy); + if (pzErr) { + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = pzErr; + return SQLITE_ERROR; + } + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + sqlite3_free(pVTab); + return SQLITE_OK; +} + +static inline int cXDisconnect(sqlite3_vtab *pVTab) { + return cXRelease(pVTab, 0); +} +static inline int cXDestroy(sqlite3_vtab *pVTab) { + return cXRelease(pVTab, 1); +} + +typedef struct goVTabCursor goVTabCursor; + +struct goVTabCursor { + sqlite3_vtab_cursor base; + void *vTabCursor; +}; + +uintptr_t goVOpen(void *pVTab, char **pzErr); + +static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) { + void *vTabCursor = (void *)goVOpen(((goVTab*)pVTab)->vTab, &(pVTab->zErrMsg)); + goVTabCursor *pCursor = (goVTabCursor *)sqlite3_malloc(sizeof(goVTabCursor)); + if (!pCursor) { + return SQLITE_NOMEM; + } + memset(pCursor, 0, sizeof(goVTabCursor)); + pCursor->vTabCursor = vTabCursor; + *ppCursor = (sqlite3_vtab_cursor *)pCursor; + return SQLITE_OK; +} + +static int setErrMsg(sqlite3_vtab_cursor *pCursor, char *pzErr) { + if (pCursor->pVtab->zErrMsg) + sqlite3_free(pCursor->pVtab->zErrMsg); + pCursor->pVtab->zErrMsg = pzErr; + return SQLITE_ERROR; +} + +char* goVClose(void *pCursor); + +static int cXClose(sqlite3_vtab_cursor *pCursor) { + char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + sqlite3_free(pCursor); + return SQLITE_OK; +} + +char* goVFilter(void *pCursor, int idxNum, char* idxName, int argc, sqlite3_value **argv); + +static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) { + char *pzErr = goVFilter(((goVTabCursor*)pCursor)->vTabCursor, idxNum, (char*)idxStr, argc, argv); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +char* goVNext(void *pCursor); + +static int cXNext(sqlite3_vtab_cursor *pCursor) { + char *pzErr = goVNext(((goVTabCursor*)pCursor)->vTabCursor); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +int goVEof(void *pCursor); + +static inline int cXEof(sqlite3_vtab_cursor *pCursor) { + return goVEof(((goVTabCursor*)pCursor)->vTabCursor); +} + +char* goVColumn(void *pCursor, void *cp, int col); + +static int cXColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i) { + char *pzErr = goVColumn(((goVTabCursor*)pCursor)->vTabCursor, ctx, i); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +char* goVRowid(void *pCursor, sqlite3_int64 *pRowid); + +static int cXRowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid) { + char *pzErr = goVRowid(((goVTabCursor*)pCursor)->vTabCursor, pRowid); + if (pzErr) { + return setErrMsg(pCursor, pzErr); + } + return SQLITE_OK; +} + +char* goVUpdate(void *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid); + +static int cXUpdate(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid) { + char *pzErr = goVUpdate(((goVTab*)pVTab)->vTab, argc, argv, pRowid); + if (pzErr) { + if (pVTab->zErrMsg) + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = pzErr; + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +static sqlite3_module goModule = { + 0, // iVersion + cXCreate, // xCreate - create a table + cXConnect, // xConnect - connect to an existing table + cXBestIndex, // xBestIndex - Determine search strategy + cXDisconnect, // xDisconnect - Disconnect from a table + cXDestroy, // xDestroy - Drop a table + cXOpen, // xOpen - open a cursor + cXClose, // xClose - close a cursor + cXFilter, // xFilter - configure scan constraints + cXNext, // xNext - advance a cursor + cXEof, // xEof + cXColumn, // xColumn - read data + cXRowid, // xRowid - read data + cXUpdate, // xUpdate - write data +// Not implemented + 0, // xBegin - begin transaction + 0, // xSync - sync transaction + 0, // xCommit - commit transaction + 0, // xRollback - rollback transaction + 0, // xFindFunction - function overloading + 0, // xRename - rename the table + 0, // xSavepoint + 0, // xRelease + 0 // xRollbackTo +}; + +void goMDestroy(void*); + +static int _sqlite3_create_module(sqlite3 *db, const char *zName, uintptr_t pClientData) { + return sqlite3_create_module_v2(db, zName, &goModule, (void*) pClientData, goMDestroy); +} +*/ +import "C" + +import ( + "fmt" + "math" + "reflect" + "unsafe" +) + +type sqliteModule struct { + c *SQLiteConn + name string + module Module +} + +type sqliteVTab struct { + module *sqliteModule + vTab VTab +} + +type sqliteVTabCursor struct { + vTab *sqliteVTab + vTabCursor VTabCursor +} + +// Op is type of operations. +type Op uint8 + +// Op mean identity of operations. +const ( + OpEQ Op = 2 + OpGT = 4 + OpLE = 8 + OpLT = 16 + OpGE = 32 + OpMATCH = 64 + OpLIKE = 65 /* 3.10.0 and later only */ + OpGLOB = 66 /* 3.10.0 and later only */ + OpREGEXP = 67 /* 3.10.0 and later only */ + OpScanUnique = 1 /* Scan visits at most 1 row */ +) + +// InfoConstraint give information of constraint. +type InfoConstraint struct { + Column int + Op Op + Usable bool +} + +// InfoOrderBy give information of order-by. +type InfoOrderBy struct { + Column int + Desc bool +} + +func constraints(info *C.sqlite3_index_info) []InfoConstraint { + l := info.nConstraint + slice := (*[1 << 30]C.struct_sqlite3_index_constraint)(unsafe.Pointer(info.aConstraint))[:l:l] + + cst := make([]InfoConstraint, 0, l) + for _, c := range slice { + var usable bool + if c.usable > 0 { + usable = true + } + cst = append(cst, InfoConstraint{ + Column: int(c.iColumn), + Op: Op(c.op), + Usable: usable, + }) + } + return cst +} + +func orderBys(info *C.sqlite3_index_info) []InfoOrderBy { + l := info.nOrderBy + slice := (*[1 << 30]C.struct_sqlite3_index_orderby)(unsafe.Pointer(info.aOrderBy))[:l:l] + + ob := make([]InfoOrderBy, 0, l) + for _, c := range slice { + var desc bool + if c.desc > 0 { + desc = true + } + ob = append(ob, InfoOrderBy{ + Column: int(c.iColumn), + Desc: desc, + }) + } + return ob +} + +// IndexResult is a Go struct representation of what eventually ends up in the +// output fields for `sqlite3_index_info` +// See: https://www.sqlite.org/c3ref/index_info.html +type IndexResult struct { + Used []bool // aConstraintUsage + IdxNum int + IdxStr string + AlreadyOrdered bool // orderByConsumed + EstimatedCost float64 + EstimatedRows float64 +} + +// mPrintf is a utility wrapper around sqlite3_mprintf +func mPrintf(format, arg string) *C.char { + cf := C.CString(format) + defer C.free(unsafe.Pointer(cf)) + ca := C.CString(arg) + defer C.free(unsafe.Pointer(ca)) + return C._sqlite3_mprintf(cf, ca) +} + +//export goMInit +func goMInit(db, pClientData unsafe.Pointer, argc C.int, argv **C.char, pzErr **C.char, isCreate C.int) C.uintptr_t { + m := lookupHandle(uintptr(pClientData)).(*sqliteModule) + if m.c.db != (*C.sqlite3)(db) { + *pzErr = mPrintf("%s", "Inconsistent db handles") + return 0 + } + args := make([]string, argc) + var A []*C.char + slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: int(argc), Cap: int(argc)} + a := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&slice)).Elem().Interface() + for i, s := range a.([]*C.char) { + args[i] = C.GoString(s) + } + var vTab VTab + var err error + if isCreate == 1 { + vTab, err = m.module.Create(m.c, args) + } else { + vTab, err = m.module.Connect(m.c, args) + } + + if err != nil { + *pzErr = mPrintf("%s", err.Error()) + return 0 + } + vt := sqliteVTab{m, vTab} + *pzErr = nil + return C.uintptr_t(newHandle(m.c, &vt)) +} + +//export goVRelease +func goVRelease(pVTab unsafe.Pointer, isDestroy C.int) *C.char { + vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) + var err error + if isDestroy == 1 { + err = vt.vTab.Destroy() + } else { + err = vt.vTab.Disconnect() + } + if err != nil { + return mPrintf("%s", err.Error()) + } + return nil +} + +//export goVOpen +func goVOpen(pVTab unsafe.Pointer, pzErr **C.char) C.uintptr_t { + vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) + vTabCursor, err := vt.vTab.Open() + if err != nil { + *pzErr = mPrintf("%s", err.Error()) + return 0 + } + vtc := sqliteVTabCursor{vt, vTabCursor} + *pzErr = nil + return C.uintptr_t(newHandle(vt.module.c, &vtc)) +} + +//export goVBestIndex +func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { + vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) + info := (*C.sqlite3_index_info)(icp) + csts := constraints(info) + res, err := vt.vTab.BestIndex(csts, orderBys(info)) + if err != nil { + return mPrintf("%s", err.Error()) + } + if len(res.Used) != len(csts) { + return mPrintf("Result.Used != expected value", "") + } + + // Get a pointer to constraint_usage struct so we can update in place. + l := info.nConstraint + s := (*[1 << 30]C.struct_sqlite3_index_constraint_usage)(unsafe.Pointer(info.aConstraintUsage))[:l:l] + index := 1 + for i := C.int(0); i < info.nConstraint; i++ { + if res.Used[i] { + s[i].argvIndex = C.int(index) + s[i].omit = C.uchar(1) + index++ + } + } + + info.idxNum = C.int(res.IdxNum) + idxStr := C.CString(res.IdxStr) + defer C.free(unsafe.Pointer(idxStr)) + info.idxStr = idxStr + info.needToFreeIdxStr = C.int(0) + if res.AlreadyOrdered { + info.orderByConsumed = C.int(1) + } + info.estimatedCost = C.double(res.EstimatedCost) + info.estimatedRows = C.sqlite3_int64(res.EstimatedRows) + + return nil +} + +//export goVClose +func goVClose(pCursor unsafe.Pointer) *C.char { + vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) + err := vtc.vTabCursor.Close() + if err != nil { + return mPrintf("%s", err.Error()) + } + return nil +} + +//export goMDestroy +func goMDestroy(pClientData unsafe.Pointer) { + m := lookupHandle(uintptr(pClientData)).(*sqliteModule) + m.module.DestroyModule() +} + +//export goVFilter +func goVFilter(pCursor unsafe.Pointer, idxNum C.int, idxName *C.char, argc C.int, argv **C.sqlite3_value) *C.char { + vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) + args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] + vals := make([]interface{}, 0, argc) + for _, v := range args { + conv, err := callbackArgGeneric(v) + if err != nil { + return mPrintf("%s", err.Error()) + } + vals = append(vals, conv.Interface()) + } + err := vtc.vTabCursor.Filter(int(idxNum), C.GoString(idxName), vals) + if err != nil { + return mPrintf("%s", err.Error()) + } + return nil +} + +//export goVNext +func goVNext(pCursor unsafe.Pointer) *C.char { + vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) + err := vtc.vTabCursor.Next() + if err != nil { + return mPrintf("%s", err.Error()) + } + return nil +} + +//export goVEof +func goVEof(pCursor unsafe.Pointer) C.int { + vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) + err := vtc.vTabCursor.EOF() + if err { + return 1 + } + return 0 +} + +//export goVColumn +func goVColumn(pCursor, cp unsafe.Pointer, col C.int) *C.char { + vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) + c := (*SQLiteContext)(cp) + err := vtc.vTabCursor.Column(c, int(col)) + if err != nil { + return mPrintf("%s", err.Error()) + } + return nil +} + +//export goVRowid +func goVRowid(pCursor unsafe.Pointer, pRowid *C.sqlite3_int64) *C.char { + vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor) + rowid, err := vtc.vTabCursor.Rowid() + if err != nil { + return mPrintf("%s", err.Error()) + } + *pRowid = C.sqlite3_int64(rowid) + return nil +} + +//export goVUpdate +func goVUpdate(pVTab unsafe.Pointer, argc C.int, argv **C.sqlite3_value, pRowid *C.sqlite3_int64) *C.char { + vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab) + + var tname string + if n, ok := vt.vTab.(interface { + TableName() string + }); ok { + tname = n.TableName() + " " + } + + err := fmt.Errorf("virtual %s table %sis read-only", vt.module.name, tname) + if v, ok := vt.vTab.(VTabUpdater); ok { + // convert argv + args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc] + vals := make([]interface{}, 0, argc) + for _, v := range args { + conv, err := callbackArgGeneric(v) + if err != nil { + return mPrintf("%s", err.Error()) + } + + // work around for SQLITE_NULL + x := conv.Interface() + if z, ok := x.([]byte); ok && z == nil { + x = nil + } + + vals = append(vals, x) + } + + switch { + case argc == 1: + err = v.Delete(vals[0]) + + case argc > 1 && vals[0] == nil: + var id int64 + id, err = v.Insert(vals[1], vals[2:]) + if err == nil { + *pRowid = C.sqlite3_int64(id) + } + + case argc > 1: + err = v.Update(vals[1], vals[2:]) + } + } + + if err != nil { + return mPrintf("%s", err.Error()) + } + + return nil +} + +// Module is a "virtual table module", it defines the implementation of a +// virtual tables. See: http://sqlite.org/c3ref/module.html +type Module interface { + // http://sqlite.org/vtab.html#xcreate + Create(c *SQLiteConn, args []string) (VTab, error) + // http://sqlite.org/vtab.html#xconnect + Connect(c *SQLiteConn, args []string) (VTab, error) + // http://sqlite.org/c3ref/create_module.html + DestroyModule() +} + +// VTab describes a particular instance of the virtual table. +// See: http://sqlite.org/c3ref/vtab.html +type VTab interface { + // http://sqlite.org/vtab.html#xbestindex + BestIndex([]InfoConstraint, []InfoOrderBy) (*IndexResult, error) + // http://sqlite.org/vtab.html#xdisconnect + Disconnect() error + // http://sqlite.org/vtab.html#sqlite3_module.xDestroy + Destroy() error + // http://sqlite.org/vtab.html#xopen + Open() (VTabCursor, error) +} + +// VTabUpdater is a type that allows a VTab to be inserted, updated, or +// deleted. +// See: https://sqlite.org/vtab.html#xupdate +type VTabUpdater interface { + Delete(interface{}) error + Insert(interface{}, []interface{}) (int64, error) + Update(interface{}, []interface{}) error +} + +// VTabCursor describes cursors that point into the virtual table and are used +// to loop through the virtual table. See: http://sqlite.org/c3ref/vtab_cursor.html +type VTabCursor interface { + // http://sqlite.org/vtab.html#xclose + Close() error + // http://sqlite.org/vtab.html#xfilter + Filter(idxNum int, idxStr string, vals []interface{}) error + // http://sqlite.org/vtab.html#xnext + Next() error + // http://sqlite.org/vtab.html#xeof + EOF() bool + // http://sqlite.org/vtab.html#xcolumn + Column(c *SQLiteContext, col int) error + // http://sqlite.org/vtab.html#xrowid + Rowid() (int64, error) +} + +// DeclareVTab declares the Schema of a virtual table. +// See: http://sqlite.org/c3ref/declare_vtab.html +func (c *SQLiteConn) DeclareVTab(sql string) error { + zSQL := C.CString(sql) + defer C.free(unsafe.Pointer(zSQL)) + rv := C.sqlite3_declare_vtab(c.db, zSQL) + if rv != C.SQLITE_OK { + return c.lastError() + } + return nil +} + +// CreateModule registers a virtual table implementation. +// See: http://sqlite.org/c3ref/create_module.html +func (c *SQLiteConn) CreateModule(moduleName string, module Module) error { + mname := C.CString(moduleName) + defer C.free(unsafe.Pointer(mname)) + udm := sqliteModule{c, moduleName, module} + rv := C._sqlite3_create_module(c.db, mname, C.uintptr_t(newHandle(c, &udm))) + if rv != C.SQLITE_OK { + return c.lastError() + } + return nil +} diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h b/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h index afb689a5d44..d5fd90519e7 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h @@ -1,3 +1,4 @@ +#ifndef USE_LIBSQLITE3 /* ** 2006 June 7 ** @@ -15,12 +16,10 @@ ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ -#ifndef _SQLITE3EXT_H_ -#define _SQLITE3EXT_H_ +#ifndef SQLITE3EXT_H +#define SQLITE3EXT_H #include "sqlite3-binding.h" -typedef struct sqlite3_api_routines sqlite3_api_routines; - /* ** The following structure holds pointers to all of the SQLite API ** routines. @@ -136,7 +135,7 @@ struct sqlite3_api_routines { int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*snprintf)(int,char*,const char*,...); + char * (*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -248,7 +247,7 @@ struct sqlite3_api_routines { int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); - char *(*vsnprintf)(int,char*,const char*,va_list); + char *(*xvsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); /* Version 3.8.7 and later */ int (*auto_extension)(void(*)(void)); @@ -279,8 +278,33 @@ struct sqlite3_api_routines { int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); int (*strlike)(const char*,const char*,unsigned int); int (*db_cacheflush)(sqlite3*); + /* Version 3.12.0 and later */ + int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); }; +/* +** This is the function signature used for all extension entry points. It +** is also defined in the file "loadext.c". +*/ +typedef int (*sqlite3_loadext_entry)( + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ +); + /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. @@ -395,7 +419,7 @@ struct sqlite3_api_routines { #define sqlite3_rollback_hook sqlite3_api->rollback_hook #define sqlite3_set_authorizer sqlite3_api->set_authorizer #define sqlite3_set_auxdata sqlite3_api->set_auxdata -#define sqlite3_snprintf sqlite3_api->snprintf +#define sqlite3_snprintf sqlite3_api->xsnprintf #define sqlite3_step sqlite3_api->step #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup @@ -419,7 +443,7 @@ struct sqlite3_api_routines { #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf -#define sqlite3_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 @@ -495,7 +519,7 @@ struct sqlite3_api_routines { #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 /* Version 3.8.7 and later */ #define sqlite3_auto_extension sqlite3_api->auto_extension @@ -522,6 +546,19 @@ struct sqlite3_api_routines { #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush +/* Version 3.12.0 and later */ +#define sqlite3_system_errno sqlite3_api->system_errno +/* Version 3.14.0 and later */ +#define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql +/* Version 3.18.0 and later */ +#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +/* Version 3.20.0 and later */ +#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 +#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 +#define sqlite3_bind_pointer sqlite3_api->bind_pointer +#define sqlite3_result_pointer sqlite3_api->result_pointer +#define sqlite3_value_pointer sqlite3_api->value_pointer #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -539,4 +576,8 @@ struct sqlite3_api_routines { # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif -#endif /* _SQLITE3EXT_H_ */ +#endif /* SQLITE3EXT_H */ +#else // USE_LIBSQLITE3 + // If users really want to link against the system sqlite3 we +// need to make this file a noop. + #endif \ No newline at end of file diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile deleted file mode 100644 index 81be214370d..00000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: - -cover: - go test -cover -v -coverprofile=cover.dat ./... - go tool cover -func cover.dat - -.PHONY: cover diff --git a/vendor/github.com/mitchellh/go-testing-interface/LICENSE b/vendor/github.com/mitchellh/go-testing-interface/LICENSE new file mode 100644 index 00000000000..a3866a291fd --- /dev/null +++ b/vendor/github.com/mitchellh/go-testing-interface/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-testing-interface/testing.go b/vendor/github.com/mitchellh/go-testing-interface/testing.go new file mode 100644 index 00000000000..204afb42005 --- /dev/null +++ b/vendor/github.com/mitchellh/go-testing-interface/testing.go @@ -0,0 +1,84 @@ +// +build !go1.9 + +package testing + +import ( + "fmt" + "log" +) + +// T is the interface that mimics the standard library *testing.T. +// +// In unit tests you can just pass a *testing.T struct. At runtime, outside +// of tests, you can pass in a RuntimeT struct from this package. +type T interface { + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Fail() + FailNow() + Failed() bool + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Log(args ...interface{}) + Logf(format string, args ...interface{}) + Name() string + Skip(args ...interface{}) + SkipNow() + Skipf(format string, args ...interface{}) + Skipped() bool +} + +// RuntimeT implements T and can be instantiated and run at runtime to +// mimic *testing.T behavior. Unlike *testing.T, this will simply panic +// for calls to Fatal. For calls to Error, you'll have to check the errors +// list to determine whether to exit yourself. Name and Skip methods are +// unimplemented noops. +type RuntimeT struct { + failed bool +} + +func (t *RuntimeT) Error(args ...interface{}) { + log.Println(fmt.Sprintln(args...)) + t.Fail() +} + +func (t *RuntimeT) Errorf(format string, args ...interface{}) { + log.Println(fmt.Sprintf(format, args...)) + t.Fail() +} + +func (t *RuntimeT) Fatal(args ...interface{}) { + log.Println(fmt.Sprintln(args...)) + t.FailNow() +} + +func (t *RuntimeT) Fatalf(format string, args ...interface{}) { + log.Println(fmt.Sprintf(format, args...)) + t.FailNow() +} + +func (t *RuntimeT) Fail() { + t.failed = true +} + +func (t *RuntimeT) FailNow() { + panic("testing.T failed, see logs for output (if any)") +} + +func (t *RuntimeT) Failed() bool { + return t.failed +} + +func (t *RuntimeT) Log(args ...interface{}) { + log.Println(fmt.Sprintln(args...)) +} + +func (t *RuntimeT) Logf(format string, args ...interface{}) { + log.Println(fmt.Sprintf(format, args...)) +} + +func (t *RuntimeT) Name() string { return "" } +func (t *RuntimeT) Skip(args ...interface{}) {} +func (t *RuntimeT) SkipNow() {} +func (t *RuntimeT) Skipf(format string, args ...interface{}) {} +func (t *RuntimeT) Skipped() bool { return false } diff --git a/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go b/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go new file mode 100644 index 00000000000..31b42cadf8d --- /dev/null +++ b/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go @@ -0,0 +1,108 @@ +// +build go1.9 + +// NOTE: This is a temporary copy of testing.go for Go 1.9 with the addition +// of "Helper" to the T interface. Go 1.9 at the time of typing is in RC +// and is set for release shortly. We'll support this on master as the default +// as soon as 1.9 is released. + +package testing + +import ( + "fmt" + "log" +) + +// T is the interface that mimics the standard library *testing.T. +// +// In unit tests you can just pass a *testing.T struct. At runtime, outside +// of tests, you can pass in a RuntimeT struct from this package. +type T interface { + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Fail() + FailNow() + Failed() bool + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Log(args ...interface{}) + Logf(format string, args ...interface{}) + Name() string + Skip(args ...interface{}) + SkipNow() + Skipf(format string, args ...interface{}) + Skipped() bool + Helper() +} + +// RuntimeT implements T and can be instantiated and run at runtime to +// mimic *testing.T behavior. Unlike *testing.T, this will simply panic +// for calls to Fatal. For calls to Error, you'll have to check the errors +// list to determine whether to exit yourself. +type RuntimeT struct { + skipped bool + failed bool +} + +func (t *RuntimeT) Error(args ...interface{}) { + log.Println(fmt.Sprintln(args...)) + t.Fail() +} + +func (t *RuntimeT) Errorf(format string, args ...interface{}) { + log.Printf(format, args...) + t.Fail() +} + +func (t *RuntimeT) Fail() { + t.failed = true +} + +func (t *RuntimeT) FailNow() { + panic("testing.T failed, see logs for output (if any)") +} + +func (t *RuntimeT) Failed() bool { + return t.failed +} + +func (t *RuntimeT) Fatal(args ...interface{}) { + log.Print(args...) + t.FailNow() +} + +func (t *RuntimeT) Fatalf(format string, args ...interface{}) { + log.Printf(format, args...) + t.FailNow() +} + +func (t *RuntimeT) Log(args ...interface{}) { + log.Println(fmt.Sprintln(args...)) +} + +func (t *RuntimeT) Logf(format string, args ...interface{}) { + log.Println(fmt.Sprintf(format, args...)) +} + +func (t *RuntimeT) Name() string { + return "" +} + +func (t *RuntimeT) Skip(args ...interface{}) { + log.Print(args...) + t.SkipNow() +} + +func (t *RuntimeT) SkipNow() { + t.skipped = true +} + +func (t *RuntimeT) Skipf(format string, args ...interface{}) { + log.Printf(format, args...) + t.SkipNow() +} + +func (t *RuntimeT) Skipped() bool { + return t.skipped +} + +func (t *RuntimeT) Helper() {} diff --git a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md deleted file mode 100644 index 1fc9fdf7f36..00000000000 --- a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md +++ /dev/null @@ -1,14 +0,0 @@ -Changes by Version -================== - -1.1.0 (unreleased) -------------------- - -- Deprecate InitGlobalTracer() in favor of SetGlobalTracer() - - -1.0.0 (2016-09-26) -------------------- - -- This release implements OpenTracing Specification 1.0 (http://opentracing.io/spec) - diff --git a/vendor/github.com/opentracing/opentracing-go/Makefile b/vendor/github.com/opentracing/opentracing-go/Makefile deleted file mode 100644 index 2f491f1574f..00000000000 --- a/vendor/github.com/opentracing/opentracing-go/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -PACKAGES := . ./mocktracer/... ./ext/... - -.DEFAULT_GOAL := test-and-lint - -.PHONE: test-and-lint - -test-and-lint: test lint - -.PHONY: test -test: - go test -v -cover ./... - -cover: - @rm -rf cover-all.out - $(foreach pkg, $(PACKAGES), $(MAKE) cover-pkg PKG=$(pkg) || true;) - @grep mode: cover.out > coverage.out - @cat cover-all.out >> coverage.out - go tool cover -html=coverage.out -o cover.html - @rm -rf cover.out cover-all.out coverage.out - -cover-pkg: - go test -coverprofile cover.out $(PKG) - @grep -v mode: cover.out >> cover-all.out - -.PHONY: lint -lint: - go fmt ./... - golint ./... - @# Run again with magic to exit non-zero if golint outputs anything. - @! (golint ./... | read dummy) - go vet ./... - diff --git a/vendor/github.com/opentracing/opentracing-go/README.md b/vendor/github.com/opentracing/opentracing-go/README.md deleted file mode 100644 index 19a541c2c59..00000000000 --- a/vendor/github.com/opentracing/opentracing-go/README.md +++ /dev/null @@ -1,163 +0,0 @@ -[![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/opentracing/public) [![Build Status](https://travis-ci.org/opentracing/opentracing-go.svg?branch=master)](https://travis-ci.org/opentracing/opentracing-go) [![GoDoc](https://godoc.org/github.com/opentracing/opentracing-go?status.svg)](http://godoc.org/github.com/opentracing/opentracing-go) -[![Sourcegraph Badge](https://sourcegraph.com/github.com/opentracing/opentracing-go/-/badge.svg)](https://sourcegraph.com/github.com/opentracing/opentracing-go?badge) - -# OpenTracing API for Go - -This package is a Go platform API for OpenTracing. - -## Required Reading - -In order to understand the Go platform API, one must first be familiar with the -[OpenTracing project](http://opentracing.io) and -[terminology](http://opentracing.io/documentation/pages/spec.html) more specifically. - -## API overview for those adding instrumentation - -Everyday consumers of this `opentracing` package really only need to worry -about a couple of key abstractions: the `StartSpan` function, the `Span` -interface, and binding a `Tracer` at `main()`-time. Here are code snippets -demonstrating some important use cases. - -#### Singleton initialization - -The simplest starting point is `./default_tracer.go`. As early as possible, call - -```go - import "github.com/opentracing/opentracing-go" - import ".../some_tracing_impl" - - func main() { - opentracing.InitGlobalTracer( - // tracing impl specific: - some_tracing_impl.New(...), - ) - ... - } -``` - -##### Non-Singleton initialization - -If you prefer direct control to singletons, manage ownership of the -`opentracing.Tracer` implementation explicitly. - -#### Creating a Span given an existing Go `context.Context` - -If you use `context.Context` in your application, OpenTracing's Go library will -happily rely on it for `Span` propagation. To start a new (blocking child) -`Span`, you can use `StartSpanFromContext`. - -```go - func xyz(ctx context.Context, ...) { - ... - span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name") - defer span.Finish() - span.LogFields( - log.String("event", "soft error"), - log.String("type", "cache timeout"), - log.Int("waited.millis", 1500)) - ... - } -``` - -#### Starting an empty trace by creating a "root span" - -It's always possible to create a "root" `Span` with no parent or other causal -reference. - -```go - func xyz() { - ... - sp := opentracing.StartSpan("operation_name") - defer sp.Finish() - ... - } -``` - -#### Creating a (child) Span given an existing (parent) Span - -```go - func xyz(parentSpan opentracing.Span, ...) { - ... - sp := opentracing.StartSpan( - "operation_name", - opentracing.ChildOf(parentSpan.Context())) - defer sp.Finish() - ... - } -``` - -#### Serializing to the wire - -```go - func makeSomeRequest(ctx context.Context) ... { - if span := opentracing.SpanFromContext(ctx); span != nil { - httpClient := &http.Client{} - httpReq, _ := http.NewRequest("GET", "http://myservice/", nil) - - // Transmit the span's TraceContext as HTTP headers on our - // outbound request. - opentracing.GlobalTracer().Inject( - span.Context(), - opentracing.HTTPHeaders, - opentracing.HTTPHeadersCarrier(httpReq.Header)) - - resp, err := httpClient.Do(httpReq) - ... - } - ... - } -``` - -#### Deserializing from the wire - -```go - http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - var serverSpan opentracing.Span - appSpecificOperationName := ... - wireContext, err := opentracing.GlobalTracer().Extract( - opentracing.HTTPHeaders, - opentracing.HTTPHeadersCarrier(req.Header)) - if err != nil { - // Optionally record something about err here - } - - // Create the span referring to the RPC client if available. - // If wireContext == nil, a root span will be created. - serverSpan = opentracing.StartSpan( - appSpecificOperationName, - ext.RPCServerOption(wireContext)) - - defer serverSpan.Finish() - - ctx := opentracing.ContextWithSpan(context.Background(), serverSpan) - ... - } -``` - -#### Conditionally capture a field using `log.Noop` - -In some situations, you may want to dynamically decide whether or not -to log a field. For example, you may want to capture additional data, -such as a customer ID, in non-production environments: - -```go - func Customer(order *Order) log.Field { - if os.Getenv("ENVIRONMENT") == "dev" { - return log.String("customer", order.Customer.ID) - } - return log.Noop() - } -``` - -#### Goroutine-safety - -The entire public API is goroutine-safe and does not require external -synchronization. - -## API pointers for those implementing a tracing system - -Tracing system implementors may be able to reuse or copy-paste-modify the `basictracer` package, found [here](https://github.com/opentracing/basictracer-go). In particular, see `basictracer.New(...)`. - -## API compatibility - -For the time being, "mild" backwards-incompatible changes may be made without changing the major version number. As OpenTracing and `opentracing-go` mature, backwards compatibility will become more of a priority. diff --git a/vendor/github.com/opentracing/opentracing-go/ext/tags.go b/vendor/github.com/opentracing/opentracing-go/ext/tags.go index 8800129a237..c67ab5eef55 100644 --- a/vendor/github.com/opentracing/opentracing-go/ext/tags.go +++ b/vendor/github.com/opentracing/opentracing-go/ext/tags.go @@ -74,7 +74,7 @@ var ( PeerHostname = stringTagName("peer.hostname") // PeerHostIPv4 records IP v4 host address of the peer - PeerHostIPv4 = ipv4Tag("peer.ipv4") + PeerHostIPv4 = uint32TagName("peer.ipv4") // PeerHostIPv6 records IP v6 host address of the peer PeerHostIPv6 = stringTagName("peer.ipv6") @@ -196,15 +196,3 @@ type boolTagName string func (tag boolTagName) Set(span opentracing.Span, value bool) { span.SetTag(string(tag), value) } - -type ipv4Tag string - -// Set adds IP v4 host address of the peer as an uint32 value to the `span`, keep this for backward and zipkin compatibility -func (tag ipv4Tag) Set(span opentracing.Span, value uint32) { - span.SetTag(string(tag), value) -} - -// SetString records IP v4 host address of the peer as a .-separated tuple to the `span`. E.g., "127.0.0.1" -func (tag ipv4Tag) SetString(span opentracing.Span, value string) { - span.SetTag(string(tag), value) -} diff --git a/vendor/github.com/opentracing/opentracing-go/log/field.go b/vendor/github.com/opentracing/opentracing-go/log/field.go index 50feea341a7..d2cd39a16ef 100644 --- a/vendor/github.com/opentracing/opentracing-go/log/field.go +++ b/vendor/github.com/opentracing/opentracing-go/log/field.go @@ -20,7 +20,6 @@ const ( errorType objectType lazyLoggerType - noopType ) // Field instances are constructed via LogBool, LogString, and so on. @@ -153,25 +152,6 @@ func Lazy(ll LazyLogger) Field { } } -// Noop creates a no-op log field that should be ignored by the tracer. -// It can be used to capture optional fields, for example those that should -// only be logged in non-production environment: -// -// func customerField(order *Order) log.Field { -// if os.Getenv("ENVIRONMENT") == "dev" { -// return log.String("customer", order.Customer.ID) -// } -// return log.Noop() -// } -// -// span.LogFields(log.String("event", "purchase"), customerField(order)) -// -func Noop() Field { - return Field{ - fieldType: noopType, - } -} - // Encoder allows access to the contents of a Field (via a call to // Field.Marshal). // @@ -223,8 +203,6 @@ func (lf Field) Marshal(visitor Encoder) { visitor.EmitObject(lf.key, lf.interfaceVal) case lazyLoggerType: visitor.EmitLazyLogger(lf.interfaceVal.(LazyLogger)) - case noopType: - // intentionally left blank } } @@ -256,8 +234,6 @@ func (lf Field) Value() interface{} { return math.Float64frombits(uint64(lf.numericVal)) case errorType, objectType, lazyLoggerType: return lf.interfaceVal - case noopType: - return nil default: return nil } diff --git a/vendor/github.com/opentracing/opentracing-go/propagation.go b/vendor/github.com/opentracing/opentracing-go/propagation.go index 0dd466a373e..9583fc53abf 100644 --- a/vendor/github.com/opentracing/opentracing-go/propagation.go +++ b/vendor/github.com/opentracing/opentracing-go/propagation.go @@ -72,18 +72,18 @@ const ( // // For Tracer.Extract(): the carrier must be a `TextMapReader`. // - // See HTTPHeadersCarrier for an implementation of both TextMapWriter + // See HTTPHeaderCarrier for an implementation of both TextMapWriter // and TextMapReader that defers to an http.Header instance for storage. // For example, Inject(): // // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) // err := span.Tracer().Inject( - // span.Context(), opentracing.HTTPHeaders, carrier) + // span, opentracing.HTTPHeaders, carrier) // // Or Extract(): // // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) - // clientContext, err := tracer.Extract( + // span, err := tracer.Extract( // opentracing.HTTPHeaders, carrier) // HTTPHeaders @@ -144,15 +144,15 @@ func (c TextMapCarrier) Set(key, val string) { // // Example usage for server side: // -// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) -// clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier) +// carrier := opentracing.HttpHeadersCarrier(httpReq.Header) +// spanContext, err := tracer.Extract(opentracing.HttpHeaders, carrier) // // Example usage for client side: // // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) // err := tracer.Inject( // span.Context(), -// opentracing.HTTPHeaders, +// opentracing.HttpHeaders, // carrier) // type HTTPHeadersCarrier http.Header diff --git a/vendor/github.com/opentracing/opentracing-go/tracer.go b/vendor/github.com/opentracing/opentracing-go/tracer.go index 7bca1f73676..fd77c1df327 100644 --- a/vendor/github.com/opentracing/opentracing-go/tracer.go +++ b/vendor/github.com/opentracing/opentracing-go/tracer.go @@ -30,7 +30,7 @@ type Tracer interface { // sp := tracer.StartSpan( // "GetFeed", // opentracing.ChildOf(parentSpan.Context()), - // opentracing.Tag{"user_agent", loggedReq.UserAgent}, + // opentracing.Tag("user_agent", loggedReq.UserAgent), // opentracing.StartTime(loggedReq.Timestamp), // ) // diff --git a/vendor/github.com/patrickmn/go-cache/README.md b/vendor/github.com/patrickmn/go-cache/README.md deleted file mode 100644 index c5789cc66cc..00000000000 --- a/vendor/github.com/patrickmn/go-cache/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# go-cache - -go-cache is an in-memory key:value store/cache similar to memcached that is -suitable for applications running on a single machine. Its major advantage is -that, being essentially a thread-safe `map[string]interface{}` with expiration -times, it doesn't need to serialize or transmit its contents over the network. - -Any object can be stored, for a given duration or forever, and the cache can be -safely used by multiple goroutines. - -Although go-cache isn't meant to be used as a persistent datastore, the entire -cache can be saved to and loaded from a file (using `c.Items()` to retrieve the -items map to serialize, and `NewFrom()` to create a cache from a deserialized -one) to recover from downtime quickly. (See the docs for `NewFrom()` for caveats.) - -### Installation - -`go get github.com/patrickmn/go-cache` - -### Usage - -```go -import ( - "fmt" - "github.com/patrickmn/go-cache" - "time" -) - -func main() { - // Create a cache with a default expiration time of 5 minutes, and which - // purges expired items every 10 minutes - c := cache.New(5*time.Minute, 10*time.Minute) - - // Set the value of the key "foo" to "bar", with the default expiration time - c.Set("foo", "bar", cache.DefaultExpiration) - - // Set the value of the key "baz" to 42, with no expiration time - // (the item won't be removed until it is re-set, or removed using - // c.Delete("baz") - c.Set("baz", 42, cache.NoExpiration) - - // Get the string associated with the key "foo" from the cache - foo, found := c.Get("foo") - if found { - fmt.Println(foo) - } - - // Since Go is statically typed, and cache values can be anything, type - // assertion is needed when values are being passed to functions that don't - // take arbitrary types, (i.e. interface{}). The simplest way to do this for - // values which will only be used once--e.g. for passing to another - // function--is: - foo, found := c.Get("foo") - if found { - MyFunction(foo.(string)) - } - - // This gets tedious if the value is used several times in the same function. - // You might do either of the following instead: - if x, found := c.Get("foo"); found { - foo := x.(string) - // ... - } - // or - var foo string - if x, found := c.Get("foo"); found { - foo = x.(string) - } - // ... - // foo can then be passed around freely as a string - - // Want performance? Store pointers! - c.Set("foo", &MyStruct, cache.DefaultExpiration) - if x, found := c.Get("foo"); found { - foo := x.(*MyStruct) - // ... - } -} -``` - -### Reference - -`godoc` or [http://godoc.org/github.com/patrickmn/go-cache](http://godoc.org/github.com/patrickmn/go-cache) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/README.md b/vendor/github.com/prometheus/client_golang/prometheus/README.md deleted file mode 100644 index 44986bff06b..00000000000 --- a/vendor/github.com/prometheus/client_golang/prometheus/README.md +++ /dev/null @@ -1 +0,0 @@ -See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus). diff --git a/vendor/github.com/prometheus/client_model/ruby/LICENSE b/vendor/github.com/prometheus/client_model/ruby/LICENSE new file mode 100644 index 00000000000..11069edd790 --- /dev/null +++ b/vendor/github.com/prometheus/client_model/ruby/LICENSE @@ -0,0 +1,201 @@ + 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. diff --git a/vendor/github.com/prometheus/common/CONTRIBUTING.md b/vendor/github.com/prometheus/common/CONTRIBUTING.md deleted file mode 100644 index 40503edbf18..00000000000 --- a/vendor/github.com/prometheus/common/CONTRIBUTING.md +++ /dev/null @@ -1,18 +0,0 @@ -# Contributing - -Prometheus uses GitHub to manage reviews of pull requests. - -* If you have a trivial fix or improvement, go ahead and create a pull request, - addressing (with `@...`) the maintainer of this repository (see - [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. - -* If you plan to do something more involved, first discuss your ideas - on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). - This will avoid unnecessary work and surely give you and us a good deal - of inspiration. - -* Relevant coding style guidelines are the [Go Code Review - Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) - and the _Formatting and style_ section of Peter Bourgon's [Go: Best - Practices for Production - Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/common/MAINTAINERS.md b/vendor/github.com/prometheus/common/MAINTAINERS.md deleted file mode 100644 index 1b315216165..00000000000 --- a/vendor/github.com/prometheus/common/MAINTAINERS.md +++ /dev/null @@ -1 +0,0 @@ -* Fabian Reinartz diff --git a/vendor/github.com/prometheus/common/README.md b/vendor/github.com/prometheus/common/README.md deleted file mode 100644 index 11a584945d5..00000000000 --- a/vendor/github.com/prometheus/common/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Common -[![Build Status](https://travis-ci.org/prometheus/common.svg)](https://travis-ci.org/prometheus/common) - -This repository contains Go libraries that are shared across Prometheus -components and libraries. - -* **config**: Common configuration structures -* **expfmt**: Decoding and encoding for the exposition format -* **log**: A logging wrapper around [logrus](https://github.com/sirupsen/logrus) -* **model**: Shared data structures -* **route**: A routing wrapper around [httprouter](https://github.com/julienschmidt/httprouter) using `context.Context` -* **version**: Version informations and metric diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt deleted file mode 100644 index 7723656d58d..00000000000 --- a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt +++ /dev/null @@ -1,67 +0,0 @@ -PACKAGE - -package goautoneg -import "bitbucket.org/ww/goautoneg" - -HTTP Content-Type Autonegotiation. - -The functions in this package implement the behaviour specified in -http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - -Copyright (c) 2011, Open Knowledge Foundation Ltd. -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 the Open Knowledge Foundation Ltd. 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 -HOLDER 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. - - -FUNCTIONS - -func Negotiate(header string, alternatives []string) (content_type string) -Negotiate the most appropriate content_type given the accept header -and a list of alternatives. - -func ParseAccept(header string) (accept []Accept) -Parse an Accept Header string returning a sorted list -of clauses - - -TYPES - -type Accept struct { - Type, SubType string - Q float32 - Params map[string]string -} -Structure to represent a clause in an HTTP Accept Header - - -SUBDIRECTORIES - - .hg diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go index 7e87f1ac634..74ed5a9f7e9 100644 --- a/vendor/github.com/prometheus/common/model/time.go +++ b/vendor/github.com/prometheus/common/model/time.go @@ -214,6 +214,9 @@ func (d Duration) String() string { ms = int64(time.Duration(d) / time.Millisecond) unit = "ms" ) + if ms == 0 { + return "0s" + } factors := map[string]int64{ "y": 1000 * 60 * 60 * 24 * 365, "w": 1000 * 60 * 60 * 24 * 7, diff --git a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md deleted file mode 100644 index 40503edbf18..00000000000 --- a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md +++ /dev/null @@ -1,18 +0,0 @@ -# Contributing - -Prometheus uses GitHub to manage reviews of pull requests. - -* If you have a trivial fix or improvement, go ahead and create a pull request, - addressing (with `@...`) the maintainer of this repository (see - [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. - -* If you plan to do something more involved, first discuss your ideas - on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). - This will avoid unnecessary work and surely give you and us a good deal - of inspiration. - -* Relevant coding style guidelines are the [Go Code Review - Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) - and the _Formatting and style_ section of Peter Bourgon's [Go: Best - Practices for Production - Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md deleted file mode 100644 index 35993c41c27..00000000000 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ /dev/null @@ -1 +0,0 @@ -* Tobias Schmidt diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile deleted file mode 100644 index dd48afdcd45..00000000000 --- a/vendor/github.com/prometheus/procfs/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -ci: fmt lint test - -fmt: - ! gofmt -l *.go | read nothing - go vet - -lint: - go get github.com/golang/lint/golint - golint *.go - -test: sysfs/fixtures/.unpacked - go test -v ./... - -sysfs/fixtures/.unpacked: sysfs/fixtures.ttar - ./ttar -C sysfs -x -f sysfs/fixtures.ttar - touch $@ - -.PHONY: fmt lint test ci diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md deleted file mode 100644 index 2095494719b..00000000000 --- a/vendor/github.com/prometheus/procfs/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# procfs - -This procfs package provides functions to retrieve system, kernel and process -metrics from the pseudo-filesystem proc. - -*WARNING*: This package is a work in progress. Its API may still break in -backwards-incompatible ways without warnings. Use it at your own risk. - -[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs) -[![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs) -[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs) diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go index 680a9842a43..d3a8268078c 100644 --- a/vendor/github.com/prometheus/procfs/buddyinfo.go +++ b/vendor/github.com/prometheus/procfs/buddyinfo.go @@ -62,7 +62,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { for scanner.Scan() { var err error line := scanner.Text() - parts := strings.Fields(string(line)) + parts := strings.Fields(line) if len(parts) < 4 { return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo") diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/exe b/vendor/github.com/prometheus/procfs/fixtures/26231/exe new file mode 120000 index 00000000000..a91bec4dac3 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/exe @@ -0,0 +1 @@ +/usr/bin/vim \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 new file mode 120000 index 00000000000..da9c5dff3e0 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/0 @@ -0,0 +1 @@ +../../symlinktargets/abc \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 new file mode 120000 index 00000000000..ca47b50ca5e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/1 @@ -0,0 +1 @@ +../../symlinktargets/def \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 new file mode 120000 index 00000000000..c086831683e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/10 @@ -0,0 +1 @@ +../../symlinktargets/xyz \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 new file mode 120000 index 00000000000..66731c06890 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/2 @@ -0,0 +1 @@ +../../symlinktargets/ghi \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 new file mode 120000 index 00000000000..0135dce35f9 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/fd/3 @@ -0,0 +1 @@ +../../symlinktargets/uvw \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt b/vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt new file mode 120000 index 00000000000..9c52ca21160 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/ns/mnt @@ -0,0 +1 @@ +mnt:[4026531840] \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/ns/net b/vendor/github.com/prometheus/procfs/fixtures/26231/ns/net new file mode 120000 index 00000000000..1f0f795941d --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26231/ns/net @@ -0,0 +1 @@ +net:[4026531993] \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 new file mode 120000 index 00000000000..da9c5dff3e0 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/0 @@ -0,0 +1 @@ +../../symlinktargets/abc \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 new file mode 120000 index 00000000000..ca47b50ca5e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/1 @@ -0,0 +1 @@ +../../symlinktargets/def \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 new file mode 120000 index 00000000000..66731c06890 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/2 @@ -0,0 +1 @@ +../../symlinktargets/ghi \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 new file mode 120000 index 00000000000..0135dce35f9 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/3 @@ -0,0 +1 @@ +../../symlinktargets/uvw \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 new file mode 120000 index 00000000000..c086831683e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/26232/fd/4 @@ -0,0 +1 @@ +../../symlinktargets/xyz \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fixtures/self b/vendor/github.com/prometheus/procfs/fixtures/self new file mode 120000 index 00000000000..1eeedea3d22 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures/self @@ -0,0 +1 @@ +26231 \ No newline at end of file diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go index 17546756b33..d0bcb78b1b7 100644 --- a/vendor/github.com/prometheus/procfs/fs.go +++ b/vendor/github.com/prometheus/procfs/fs.go @@ -5,6 +5,7 @@ import ( "os" "path" + "github.com/prometheus/procfs/nfsd" "github.com/prometheus/procfs/xfs" ) @@ -44,3 +45,14 @@ func (fs FS) XFSStats() (*xfs.Stats, error) { return xfs.ParseStats(f) } + +// NFSdRPCStats retrieves NFS daemon RPC statistics. +func (fs FS) NFSdRPCStats() (*nfsd.RPCStats, error) { + f, err := os.Open(fs.Path("net/rpc/nfsd")) + if err != nil { + return nil, err + } + defer f.Close() + + return nfsd.ParseRPCStats(f) +} diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go new file mode 100644 index 00000000000..1ad21c91a33 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/internal/util/parse.go @@ -0,0 +1,46 @@ +// Copyright 2018 The Prometheus 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 util + +import "strconv" + +// ParseUint32s parses a slice of strings into a slice of uint32s. +func ParseUint32s(ss []string) ([]uint32, error) { + us := make([]uint32, 0, len(ss)) + for _, s := range ss { + u, err := strconv.ParseUint(s, 10, 32) + if err != nil { + return nil, err + } + + us = append(us, uint32(u)) + } + + return us, nil +} + +// ParseUint64s parses a slice of strings into a slice of uint64s. +func ParseUint64s(ss []string) ([]uint64, error) { + us := make([]uint64, 0, len(ss)) + for _, s := range ss { + u, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return nil, err + } + + us = append(us, u) + } + + return us, nil +} diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index 696d114e73e..5761b4570fe 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -31,16 +31,16 @@ type IPVSStats struct { type IPVSBackendStatus struct { // The local (virtual) IP address. LocalAddress net.IP + // The remote (real) IP address. + RemoteAddress net.IP // The local (virtual) port. LocalPort uint16 + // The remote (real) port. + RemotePort uint16 // The local firewall mark LocalMark string // The transport protocol (TCP, UDP). Proto string - // The remote (real) IP address. - RemoteAddress net.IP - // The remote (real) port. - RemotePort uint16 // The current number of active connections for this virtual/real address pair. ActiveConn uint64 // The current number of inactive connections for this virtual/real address pair. @@ -151,7 +151,7 @@ func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) { ) for scanner.Scan() { - fields := strings.Fields(string(scanner.Text())) + fields := strings.Fields(scanner.Text()) if len(fields) == 0 { continue } diff --git a/vendor/github.com/prometheus/procfs/net_dev.go b/vendor/github.com/prometheus/procfs/net_dev.go new file mode 100644 index 00000000000..f8c184efe1b --- /dev/null +++ b/vendor/github.com/prometheus/procfs/net_dev.go @@ -0,0 +1,203 @@ +package procfs + +import ( + "bufio" + "errors" + "os" + "sort" + "strconv" + "strings" +) + +// NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev. +type NetDevLine struct { + Name string `json:"name"` // The name of the interface. + RxBytes uint64 `json:"rx_bytes"` // Cumulative count of bytes received. + RxPackets uint64 `json:"rx_packets"` // Cumulative count of packets received. + RxErrors uint64 `json:"rx_errors"` // Cumulative count of receive errors encountered. + RxDropped uint64 `json:"rx_dropped"` // Cumulative count of packets dropped while receiving. + RxFIFO uint64 `json:"rx_fifo"` // Cumulative count of FIFO buffer errors. + RxFrame uint64 `json:"rx_frame"` // Cumulative count of packet framing errors. + RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver. + RxMulticast uint64 `json:"rx_multicast"` // Cumulative count of multicast frames received by the device driver. + TxBytes uint64 `json:"tx_bytes"` // Cumulative count of bytes transmitted. + TxPackets uint64 `json:"tx_packets"` // Cumulative count of packets transmitted. + TxErrors uint64 `json:"tx_errors"` // Cumulative count of transmit errors encountered. + TxDropped uint64 `json:"tx_dropped"` // Cumulative count of packets dropped while transmitting. + TxFIFO uint64 `json:"tx_fifo"` // Cumulative count of FIFO buffer errors. + TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface. + TxCarrier uint64 `json:"tx_carrier"` // Cumulative count of carrier losses detected by the device driver. + TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver. +} + +// NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys +// are interface names. +type NetDev map[string]NetDevLine + +// NewNetDev returns kernel/system statistics read from /proc/net/dev. +func NewNetDev() (NetDev, error) { + fs, err := NewFS(DefaultMountPoint) + if err != nil { + return nil, err + } + + return fs.NewNetDev() +} + +// NewNetDev returns kernel/system statistics read from /proc/net/dev. +func (fs FS) NewNetDev() (NetDev, error) { + return newNetDev(fs.Path("net/dev")) +} + +// NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev. +func (p Proc) NewNetDev() (NetDev, error) { + return newNetDev(p.path("net/dev")) +} + +// newNetDev creates a new NetDev from the contents of the given file. +func newNetDev(file string) (NetDev, error) { + f, err := os.Open(file) + if err != nil { + return NetDev{}, err + } + defer f.Close() + + nd := NetDev{} + s := bufio.NewScanner(f) + for n := 0; s.Scan(); n++ { + // Skip the 2 header lines. + if n < 2 { + continue + } + + line, err := nd.parseLine(s.Text()) + if err != nil { + return nd, err + } + + nd[line.Name] = *line + } + + return nd, s.Err() +} + +// parseLine parses a single line from the /proc/net/dev file. Header lines +// must be filtered prior to calling this method. +func (nd NetDev) parseLine(rawLine string) (*NetDevLine, error) { + parts := strings.SplitN(rawLine, ":", 2) + if len(parts) != 2 { + return nil, errors.New("invalid net/dev line, missing colon") + } + fields := strings.Fields(strings.TrimSpace(parts[1])) + + var err error + line := &NetDevLine{} + + // Interface Name + line.Name = strings.TrimSpace(parts[0]) + if line.Name == "" { + return nil, errors.New("invalid net/dev line, empty interface name") + } + + // RX + line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64) + if err != nil { + return nil, err + } + line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64) + if err != nil { + return nil, err + } + line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64) + if err != nil { + return nil, err + } + line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64) + if err != nil { + return nil, err + } + line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64) + if err != nil { + return nil, err + } + line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64) + if err != nil { + return nil, err + } + line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64) + if err != nil { + return nil, err + } + line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64) + if err != nil { + return nil, err + } + + // TX + line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64) + if err != nil { + return nil, err + } + line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64) + if err != nil { + return nil, err + } + line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64) + if err != nil { + return nil, err + } + line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64) + if err != nil { + return nil, err + } + line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64) + if err != nil { + return nil, err + } + line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64) + if err != nil { + return nil, err + } + line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64) + if err != nil { + return nil, err + } + line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64) + if err != nil { + return nil, err + } + + return line, nil +} + +// Total aggregates the values across interfaces and returns a new NetDevLine. +// The Name field will be a sorted comma seperated list of interface names. +func (nd NetDev) Total() NetDevLine { + total := NetDevLine{} + + names := make([]string, 0, len(nd)) + for _, ifc := range nd { + names = append(names, ifc.Name) + total.RxBytes += ifc.RxBytes + total.RxPackets += ifc.RxPackets + total.RxPackets += ifc.RxPackets + total.RxErrors += ifc.RxErrors + total.RxDropped += ifc.RxDropped + total.RxFIFO += ifc.RxFIFO + total.RxFrame += ifc.RxFrame + total.RxCompressed += ifc.RxCompressed + total.RxMulticast += ifc.RxMulticast + total.TxBytes += ifc.TxBytes + total.TxPackets += ifc.TxPackets + total.TxErrors += ifc.TxErrors + total.TxDropped += ifc.TxDropped + total.TxFIFO += ifc.TxFIFO + total.TxCollisions += ifc.TxCollisions + total.TxCarrier += ifc.TxCarrier + total.TxCompressed += ifc.TxCompressed + } + sort.Strings(names) + total.Name = strings.Join(names, ", ") + + return total +} diff --git a/vendor/github.com/prometheus/procfs/nfsd/nfsd.go b/vendor/github.com/prometheus/procfs/nfsd/nfsd.go new file mode 100644 index 00000000000..7b5ec11cfbf --- /dev/null +++ b/vendor/github.com/prometheus/procfs/nfsd/nfsd.go @@ -0,0 +1,184 @@ +// Copyright 2018 The Prometheus 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 nfsd implements parsing of /proc/net/rpc/nfsd. +// Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/ +package nfsd + +// ReplyCache models the "rc" line. +type ReplyCache struct { + Hits uint64 + Misses uint64 + NoCache uint64 +} + +// FileHandles models the "fh" line. +type FileHandles struct { + Stale uint64 + TotalLookups uint64 + AnonLookups uint64 + DirNoCache uint64 + NoDirNoCache uint64 +} + +// InputOutput models the "io" line. +type InputOutput struct { + Read uint64 + Write uint64 +} + +// Threads models the "th" line. +type Threads struct { + Threads uint64 + FullCnt uint64 +} + +// ReadAheadCache models the "ra" line. +type ReadAheadCache struct { + CacheSize uint64 + CacheHistogram []uint64 + NotFound uint64 +} + +// Network models the "net" line. +type Network struct { + NetCount uint64 + UDPCount uint64 + TCPCount uint64 + TCPConnect uint64 +} + +// RPC models the "rpc" line. +type RPC struct { + RPCCount uint64 + BadCnt uint64 + BadFmt uint64 + BadAuth uint64 + BadcInt uint64 +} + +// V2Stats models the "proc2" line. +type V2Stats struct { + Null uint64 + GetAttr uint64 + SetAttr uint64 + Root uint64 + Lookup uint64 + ReadLink uint64 + Read uint64 + WrCache uint64 + Write uint64 + Create uint64 + Remove uint64 + Rename uint64 + Link uint64 + SymLink uint64 + MkDir uint64 + RmDir uint64 + ReadDir uint64 + FsStat uint64 +} + +// V3Stats models the "proc3" line. +type V3Stats struct { + Null uint64 + GetAttr uint64 + SetAttr uint64 + Lookup uint64 + Access uint64 + ReadLink uint64 + Read uint64 + Write uint64 + Create uint64 + MkDir uint64 + SymLink uint64 + MkNod uint64 + Remove uint64 + RmDir uint64 + Rename uint64 + Link uint64 + ReadDir uint64 + ReadDirPlus uint64 + FsStat uint64 + FsInfo uint64 + PathConf uint64 + Commit uint64 +} + +// V4Stats models the "proc4" line. +type V4Stats struct { + Null uint64 + Compound uint64 +} + +// V4Ops models the "proc4ops" line: NFSv4 operations +// Variable list, see: +// v4.0 https://tools.ietf.org/html/rfc3010 (38 operations) +// v4.1 https://tools.ietf.org/html/rfc5661 (58 operations) +// v4.2 https://tools.ietf.org/html/draft-ietf-nfsv4-minorversion2-41 (71 operations) +type V4Ops struct { + //Values uint64 // Variable depending on v4.x sub-version. TODO: Will this always at least include the fields in this struct? + Op0Unused uint64 + Op1Unused uint64 + Op2Future uint64 + Access uint64 + Close uint64 + Commit uint64 + Create uint64 + DelegPurge uint64 + DelegReturn uint64 + GetAttr uint64 + GetFH uint64 + Link uint64 + Lock uint64 + Lockt uint64 + Locku uint64 + Lookup uint64 + LookupRoot uint64 + Nverify uint64 + Open uint64 + OpenAttr uint64 + OpenConfirm uint64 + OpenDgrd uint64 + PutFH uint64 + PutPubFH uint64 + PutRootFH uint64 + Read uint64 + ReadDir uint64 + ReadLink uint64 + Remove uint64 + Rename uint64 + Renew uint64 + RestoreFH uint64 + SaveFH uint64 + SecInfo uint64 + SetAttr uint64 + Verify uint64 + Write uint64 + RelLockOwner uint64 +} + +// RPCStats models all stats from /proc/net/rpc/nfsd. +type RPCStats struct { + ReplyCache ReplyCache + FileHandles FileHandles + InputOutput InputOutput + Threads Threads + ReadAheadCache ReadAheadCache + Network Network + RPC RPC + V2Stats V2Stats + V3Stats V3Stats + V4Stats V4Stats + V4Ops V4Ops +} diff --git a/vendor/github.com/prometheus/procfs/nfsd/parse_nfsd.go b/vendor/github.com/prometheus/procfs/nfsd/parse_nfsd.go new file mode 100644 index 00000000000..991d7cedba5 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/nfsd/parse_nfsd.go @@ -0,0 +1,298 @@ +// Copyright 2018 The Prometheus 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 nfsd + +import ( + "bufio" + "fmt" + "io" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// ParseRPCStats returns stats read from /proc/net/rpc/nfsd +func ParseRPCStats(r io.Reader) (*RPCStats, error) { + stats := &RPCStats{} + + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := scanner.Text() + parts := strings.Fields(scanner.Text()) + // require at least + if len(parts) < 2 { + return nil, fmt.Errorf("invalid NFSd metric line %q", line) + } + label := parts[0] + + var values []uint64 + var err error + if label == "th" { + if len(parts) < 3 { + return nil, fmt.Errorf("invalid NFSd th metric line %q", line) + } + values, err = util.ParseUint64s(parts[1:3]) + } else { + values, err = util.ParseUint64s(parts[1:]) + } + if err != nil { + return nil, fmt.Errorf("error parsing NFSd metric line: %s", err) + } + + switch metricLine := parts[0]; metricLine { + case "rc": + stats.ReplyCache, err = parseReplyCache(values) + case "fh": + stats.FileHandles, err = parseFileHandles(values) + case "io": + stats.InputOutput, err = parseInputOutput(values) + case "th": + stats.Threads, err = parseThreads(values) + case "ra": + stats.ReadAheadCache, err = parseReadAheadCache(values) + case "net": + stats.Network, err = parseNetwork(values) + case "rpc": + stats.RPC, err = parseRPC(values) + case "proc2": + stats.V2Stats, err = parseV2Stats(values) + case "proc3": + stats.V3Stats, err = parseV3Stats(values) + case "proc4": + stats.V4Stats, err = parseV4Stats(values) + case "proc4ops": + stats.V4Ops, err = parseV4Ops(values) + default: + return nil, fmt.Errorf("unknown NFSd metric line %q", metricLine) + } + if err != nil { + return nil, fmt.Errorf("errors parsing NFSd metric line: %s", err) + } + } + + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("error scanning NFSd file: %s", err) + } + + return stats, nil +} + +func parseReplyCache(v []uint64) (ReplyCache, error) { + if len(v) != 3 { + return ReplyCache{}, fmt.Errorf("invalid ReplyCache line %q", v) + } + + return ReplyCache{ + Hits: v[0], + Misses: v[1], + NoCache: v[2], + }, nil +} + +func parseFileHandles(v []uint64) (FileHandles, error) { + if len(v) != 5 { + return FileHandles{}, fmt.Errorf("invalid FileHandles, line %q", v) + } + + return FileHandles{ + Stale: v[0], + TotalLookups: v[1], + AnonLookups: v[2], + DirNoCache: v[3], + NoDirNoCache: v[4], + }, nil +} + +func parseInputOutput(v []uint64) (InputOutput, error) { + if len(v) != 2 { + return InputOutput{}, fmt.Errorf("invalid InputOutput line %q", v) + } + + return InputOutput{ + Read: v[0], + Write: v[1], + }, nil +} + +func parseThreads(v []uint64) (Threads, error) { + if len(v) != 2 { + return Threads{}, fmt.Errorf("invalid Threads line %q", v) + } + + return Threads{ + Threads: v[0], + FullCnt: v[1], + }, nil +} + +func parseReadAheadCache(v []uint64) (ReadAheadCache, error) { + if len(v) != 12 { + return ReadAheadCache{}, fmt.Errorf("invalid ReadAheadCache line %q", v) + } + + return ReadAheadCache{ + CacheSize: v[0], + CacheHistogram: v[1:11], + NotFound: v[11], + }, nil +} + +func parseNetwork(v []uint64) (Network, error) { + if len(v) != 4 { + return Network{}, fmt.Errorf("invalid Network line %q", v) + } + + return Network{ + NetCount: v[0], + UDPCount: v[1], + TCPCount: v[2], + TCPConnect: v[3], + }, nil +} + +func parseRPC(v []uint64) (RPC, error) { + if len(v) != 5 { + return RPC{}, fmt.Errorf("invalid RPC line %q", v) + } + + return RPC{ + RPCCount: v[0], + BadCnt: v[1], + BadFmt: v[2], + BadAuth: v[3], + BadcInt: v[4], + }, nil +} + +func parseV2Stats(v []uint64) (V2Stats, error) { + values := int(v[0]) + if len(v[1:]) != values || values != 18 { + return V2Stats{}, fmt.Errorf("invalid V2Stats line %q", v) + } + + return V2Stats{ + Null: v[1], + GetAttr: v[2], + SetAttr: v[3], + Root: v[4], + Lookup: v[5], + ReadLink: v[6], + Read: v[7], + WrCache: v[8], + Write: v[9], + Create: v[10], + Remove: v[11], + Rename: v[12], + Link: v[13], + SymLink: v[14], + MkDir: v[15], + RmDir: v[16], + ReadDir: v[17], + FsStat: v[18], + }, nil +} + +func parseV3Stats(v []uint64) (V3Stats, error) { + values := int(v[0]) + if len(v[1:]) != values || values != 22 { + return V3Stats{}, fmt.Errorf("invalid V3Stats line %q", v) + } + + return V3Stats{ + Null: v[1], + GetAttr: v[2], + SetAttr: v[3], + Lookup: v[4], + Access: v[5], + ReadLink: v[6], + Read: v[7], + Write: v[8], + Create: v[9], + MkDir: v[10], + SymLink: v[11], + MkNod: v[12], + Remove: v[13], + RmDir: v[14], + Rename: v[15], + Link: v[16], + ReadDir: v[17], + ReadDirPlus: v[18], + FsStat: v[19], + FsInfo: v[20], + PathConf: v[21], + Commit: v[22], + }, nil +} + +func parseV4Stats(v []uint64) (V4Stats, error) { + values := int(v[0]) + if len(v[1:]) != values || values != 2 { + return V4Stats{}, fmt.Errorf("invalid V4Stats line %q", v) + } + + return V4Stats{ + Null: v[1], + Compound: v[2], + }, nil +} + +func parseV4Ops(v []uint64) (V4Ops, error) { + values := int(v[0]) + if len(v[1:]) != values || values < 39 { + return V4Ops{}, fmt.Errorf("invalid V4Ops line %q", v) + } + + stats := V4Ops{ + Op0Unused: v[1], + Op1Unused: v[2], + Op2Future: v[3], + Access: v[4], + Close: v[5], + Commit: v[6], + Create: v[7], + DelegPurge: v[8], + DelegReturn: v[9], + GetAttr: v[10], + GetFH: v[11], + Link: v[12], + Lock: v[13], + Lockt: v[14], + Locku: v[15], + Lookup: v[16], + LookupRoot: v[17], + Nverify: v[18], + Open: v[19], + OpenAttr: v[20], + OpenConfirm: v[21], + OpenDgrd: v[22], + PutFH: v[23], + PutPubFH: v[24], + PutRootFH: v[25], + Read: v[26], + ReadDir: v[27], + ReadLink: v[28], + Remove: v[29], + Rename: v[30], + Renew: v[31], + RestoreFH: v[32], + SaveFH: v[33], + SecInfo: v[34], + SetAttr: v[35], + Verify: v[36], + Write: v[37], + RelLockOwner: v[38], + } + + return stats, nil +} diff --git a/vendor/github.com/prometheus/procfs/proc_io.go b/vendor/github.com/prometheus/procfs/proc_io.go index b4e31d7ba39..e7f6674d022 100644 --- a/vendor/github.com/prometheus/procfs/proc_io.go +++ b/vendor/github.com/prometheus/procfs/proc_io.go @@ -47,9 +47,6 @@ func (p Proc) NewIO() (ProcIO, error) { _, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR, &pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes) - if err != nil { - return pio, err - } - return pio, nil + return pio, err } diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go index 2df997ce11f..b684a5b55a1 100644 --- a/vendor/github.com/prometheus/procfs/proc_limits.go +++ b/vendor/github.com/prometheus/procfs/proc_limits.go @@ -13,46 +13,46 @@ import ( // http://man7.org/linux/man-pages/man2/getrlimit.2.html. type ProcLimits struct { // CPU time limit in seconds. - CPUTime int + CPUTime int64 // Maximum size of files that the process may create. - FileSize int + FileSize int64 // Maximum size of the process's data segment (initialized data, // uninitialized data, and heap). - DataSize int + DataSize int64 // Maximum size of the process stack in bytes. - StackSize int + StackSize int64 // Maximum size of a core file. - CoreFileSize int + CoreFileSize int64 // Limit of the process's resident set in pages. - ResidentSet int + ResidentSet int64 // Maximum number of processes that can be created for the real user ID of // the calling process. - Processes int + Processes int64 // Value one greater than the maximum file descriptor number that can be // opened by this process. - OpenFiles int + OpenFiles int64 // Maximum number of bytes of memory that may be locked into RAM. - LockedMemory int + LockedMemory int64 // Maximum size of the process's virtual memory address space in bytes. - AddressSpace int + AddressSpace int64 // Limit on the combined number of flock(2) locks and fcntl(2) leases that // this process may establish. - FileLocks int + FileLocks int64 // Limit of signals that may be queued for the real user ID of the calling // process. - PendingSignals int + PendingSignals int64 // Limit on the number of bytes that can be allocated for POSIX message // queues for the real user ID of the calling process. - MsqqueueSize int + MsqqueueSize int64 // Limit of the nice priority set using setpriority(2) or nice(2). - NicePriority int + NicePriority int64 // Limit of the real-time priority set using sched_setscheduler(2) or // sched_setparam(2). - RealtimePriority int + RealtimePriority int64 // Limit (in microseconds) on the amount of CPU time that a process // scheduled under a real-time scheduling policy may consume without making // a blocking system call. - RealtimeTimeout int + RealtimeTimeout int64 } const ( @@ -125,13 +125,13 @@ func (p Proc) NewLimits() (ProcLimits, error) { return l, s.Err() } -func parseInt(s string) (int, error) { +func parseInt(s string) (int64, error) { if s == limitsUnlimited { return -1, nil } - i, err := strconv.ParseInt(s, 10, 32) + i, err := strconv.ParseInt(s, 10, 64) if err != nil { return 0, fmt.Errorf("couldn't parse value %s: %s", s, err) } - return int(i), nil + return i, nil } diff --git a/vendor/github.com/prometheus/procfs/proc_ns.go b/vendor/github.com/prometheus/procfs/proc_ns.go new file mode 100644 index 00000000000..befdd2690c8 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_ns.go @@ -0,0 +1,55 @@ +package procfs + +import ( + "fmt" + "os" + "strconv" + "strings" +) + +// Namespace represents a single namespace of a process. +type Namespace struct { + Type string // Namespace type. + Inode uint32 // Inode number of the namespace. If two processes are in the same namespace their inodes will match. +} + +// Namespaces contains all of the namespaces that the process is contained in. +type Namespaces map[string]Namespace + +// NewNamespaces reads from /proc/[pid/ns/* to get the namespaces of which the +// process is a member. +func (p Proc) NewNamespaces() (Namespaces, error) { + d, err := os.Open(p.path("ns")) + if err != nil { + return nil, err + } + defer d.Close() + + names, err := d.Readdirnames(-1) + if err != nil { + return nil, fmt.Errorf("failed to read contents of ns dir: %v", err) + } + + ns := make(Namespaces, len(names)) + for _, name := range names { + target, err := os.Readlink(p.path("ns", name)) + if err != nil { + return nil, err + } + + fields := strings.SplitN(target, ":", 2) + if len(fields) != 2 { + return nil, fmt.Errorf("failed to parse namespace type and inode from '%v'", target) + } + + typ := fields[0] + inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32) + if err != nil { + return nil, fmt.Errorf("failed to parse inode from '%v': %v", fields[1], err) + } + + ns[name] = Namespace{typ, uint32(inode)} + } + + return ns, nil +} diff --git a/vendor/github.com/prometheus/procfs/ttar b/vendor/github.com/prometheus/procfs/ttar deleted file mode 100755 index 8227a4a376c..00000000000 --- a/vendor/github.com/prometheus/procfs/ttar +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/env bash -# Purpose: plain text tar format -# Limitations: - only suitable for text files, directories, and symlinks -# - stores only filename, content, and mode -# - not designed for untrusted input - -# Note: must work with bash version 3.2 (macOS) - -set -o errexit -o nounset - -# Sanitize environment (for instance, standard sorting of glob matches) -export LC_ALL=C - -path="" -CMD="" - -function usage { - bname=$(basename "$0") - cat << USAGE -Usage: $bname [-C ] -c -f (create archive) - $bname -t -f (list archive contents) - $bname [-C ] -x -f (extract archive) - -Options: - -C (change directory) - -Example: Change to sysfs directory, create ttar file from fixtures directory - $bname -C sysfs -c -f sysfs/fixtures.ttar fixtures/ -USAGE -exit "$1" -} - -function vecho { - if [ "${VERBOSE:-}" == "yes" ]; then - echo >&7 "$@" - fi -} - -function set_cmd { - if [ -n "$CMD" ]; then - echo "ERROR: more than one command given" - echo - usage 2 - fi - CMD=$1 -} - -while getopts :cf:htxvC: opt; do - case $opt in - c) - set_cmd "create" - ;; - f) - ARCHIVE=$OPTARG - ;; - h) - usage 0 - ;; - t) - set_cmd "list" - ;; - x) - set_cmd "extract" - ;; - v) - VERBOSE=yes - exec 7>&1 - ;; - C) - CDIR=$OPTARG - ;; - *) - echo >&2 "ERROR: invalid option -$OPTARG" - echo - usage 1 - ;; - esac -done - -# Remove processed options from arguments -shift $(( OPTIND - 1 )); - -if [ "${CMD:-}" == "" ]; then - echo >&2 "ERROR: no command given" - echo - usage 1 -elif [ "${ARCHIVE:-}" == "" ]; then - echo >&2 "ERROR: no archive name given" - echo - usage 1 -fi - -function list { - local path="" - local size=0 - local line_no=0 - local ttar_file=$1 - if [ -n "${2:-}" ]; then - echo >&2 "ERROR: too many arguments." - echo - usage 1 - fi - if [ ! -e "$ttar_file" ]; then - echo >&2 "ERROR: file not found ($ttar_file)" - echo - usage 1 - fi - while read -r line; do - line_no=$(( line_no + 1 )) - if [ $size -gt 0 ]; then - size=$(( size - 1 )) - continue - fi - if [[ $line =~ ^Path:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - elif [[ $line =~ ^Lines:\ (.*)$ ]]; then - size=${BASH_REMATCH[1]} - echo "$path" - elif [[ $line =~ ^Directory:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - echo "$path/" - elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then - echo "$path -> ${BASH_REMATCH[1]}" - fi - done < "$ttar_file" -} - -function extract { - local path="" - local size=0 - local line_no=0 - local ttar_file=$1 - if [ -n "${2:-}" ]; then - echo >&2 "ERROR: too many arguments." - echo - usage 1 - fi - if [ ! -e "$ttar_file" ]; then - echo >&2 "ERROR: file not found ($ttar_file)" - echo - usage 1 - fi - while IFS= read -r line; do - line_no=$(( line_no + 1 )) - if [ "$size" -gt 0 ]; then - echo "$line" >> "$path" - size=$(( size - 1 )) - continue - fi - if [[ $line =~ ^Path:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - if [ -e "$path" ] || [ -L "$path" ]; then - rm "$path" - fi - elif [[ $line =~ ^Lines:\ (.*)$ ]]; then - size=${BASH_REMATCH[1]} - # Create file even if it is zero-length. - touch "$path" - vecho " $path" - elif [[ $line =~ ^Mode:\ (.*)$ ]]; then - mode=${BASH_REMATCH[1]} - chmod "$mode" "$path" - vecho "$mode" - elif [[ $line =~ ^Directory:\ (.*)$ ]]; then - path=${BASH_REMATCH[1]} - mkdir -p "$path" - vecho " $path/" - elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then - ln -s "${BASH_REMATCH[1]}" "$path" - vecho " $path -> ${BASH_REMATCH[1]}" - elif [[ $line =~ ^# ]]; then - # Ignore comments between files - continue - else - echo >&2 "ERROR: Unknown keyword on line $line_no: $line" - exit 1 - fi - done < "$ttar_file" -} - -function div { - echo "# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" \ - "- - - - - -" -} - -function get_mode { - local mfile=$1 - if [ -z "${STAT_OPTION:-}" ]; then - if stat -c '%a' "$mfile" >/dev/null 2>&1; then - STAT_OPTION='-c' - STAT_FORMAT='%a' - else - STAT_OPTION='-f' - STAT_FORMAT='%A' - fi - fi - stat "${STAT_OPTION}" "${STAT_FORMAT}" "$mfile" -} - -function _create { - shopt -s nullglob - local mode - while (( "$#" )); do - file=$1 - if [ -L "$file" ]; then - echo "Path: $file" - symlinkTo=$(readlink "$file") - echo "SymlinkTo: $symlinkTo" - vecho " $file -> $symlinkTo" - div - elif [ -d "$file" ]; then - # Strip trailing slash (if there is one) - file=${file%/} - echo "Directory: $file" - mode=$(get_mode "$file") - echo "Mode: $mode" - vecho "$mode $file/" - div - # Find all files and dirs, including hidden/dot files - for x in "$file/"{*,.[^.]*}; do - _create "$x" - done - elif [ -f "$file" ]; then - echo "Path: $file" - lines=$(wc -l "$file"|awk '{print $1}') - echo "Lines: $lines" - cat "$file" - mode=$(get_mode "$file") - echo "Mode: $mode" - vecho "$mode $file" - div - else - echo >&2 "ERROR: file not found ($file in $(pwd))" - exit 2 - fi - shift - done -} - -function create { - ttar_file=$1 - shift - if [ -z "${1:-}" ]; then - echo >&2 "ERROR: missing arguments." - echo - usage 1 - fi - if [ -e "$ttar_file" ]; then - rm "$ttar_file" - fi - exec > "$ttar_file" - _create "$@" -} - -if [ -n "${CDIR:-}" ]; then - if [[ "$ARCHIVE" != /* ]]; then - # Relative path: preserve the archive's location before changing - # directory - ARCHIVE="$(pwd)/$ARCHIVE" - fi - cd "$CDIR" -fi - -"$CMD" "$ARCHIVE" "$@" diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go index c8f6279f39f..2bc0ef3427d 100644 --- a/vendor/github.com/prometheus/procfs/xfs/parse.go +++ b/vendor/github.com/prometheus/procfs/xfs/parse.go @@ -17,8 +17,9 @@ import ( "bufio" "fmt" "io" - "strconv" "strings" + + "github.com/prometheus/procfs/internal/util" ) // ParseStats parses a Stats from an input io.Reader, using the format @@ -68,7 +69,7 @@ func ParseStats(r io.Reader) (*Stats, error) { // Extended precision counters are uint64 values. if label == fieldXpc { - us, err := parseUint64s(ss[1:]) + us, err := util.ParseUint64s(ss[1:]) if err != nil { return nil, err } @@ -82,7 +83,7 @@ func ParseStats(r io.Reader) (*Stats, error) { } // All other counters are uint32 values. - us, err := parseUint32s(ss[1:]) + us, err := util.ParseUint32s(ss[1:]) if err != nil { return nil, err } @@ -327,33 +328,3 @@ func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) { ReadBytes: us[2], }, nil } - -// parseUint32s parses a slice of strings into a slice of uint32s. -func parseUint32s(ss []string) ([]uint32, error) { - us := make([]uint32, 0, len(ss)) - for _, s := range ss { - u, err := strconv.ParseUint(s, 10, 32) - if err != nil { - return nil, err - } - - us = append(us, uint32(u)) - } - - return us, nil -} - -// parseUint64s parses a slice of strings into a slice of uint64s. -func parseUint64s(ss []string) ([]uint64, error) { - us := make([]uint64, 0, len(ss)) - for _, s := range ss { - u, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return nil, err - } - - us = append(us, u) - } - - return us, nil -} diff --git a/vendor/github.com/rainycape/unidecode/.gitignore b/vendor/github.com/rainycape/unidecode/.gitignore deleted file mode 100644 index 836562412fe..00000000000 --- a/vendor/github.com/rainycape/unidecode/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test diff --git a/vendor/github.com/rainycape/unidecode/LICENSE b/vendor/github.com/rainycape/unidecode/LICENSE index ad410e11302..50802eabef7 100644 --- a/vendor/github.com/rainycape/unidecode/LICENSE +++ b/vendor/github.com/rainycape/unidecode/LICENSE @@ -1,3 +1,5 @@ +Copyright 2014 Rainy Cape S.L. + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -198,4 +200,4 @@ Apache License 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 + limitations under the License. diff --git a/vendor/github.com/rainycape/unidecode/README.md b/vendor/github.com/rainycape/unidecode/README.md deleted file mode 100644 index 9a109bcfdb2..00000000000 --- a/vendor/github.com/rainycape/unidecode/README.md +++ /dev/null @@ -1,6 +0,0 @@ -unidecode -========= - -Unicode transliterator in Golang - Replaces non-ASCII characters with their ASCII approximations. - -[![GoDoc](https://godoc.org/github.com/rainycape/unidecode?status.svg)](https://godoc.org/github.com/rainycape/unidecode) diff --git a/vendor/github.com/rainycape/unidecode/table.txt b/vendor/github.com/rainycape/unidecode/table.txt deleted file mode 100644 index 9f5d59fe15d..00000000000 --- a/vendor/github.com/rainycape/unidecode/table.txt +++ /dev/null @@ -1,46731 +0,0 @@ -/* x000 */ -0x0000: "\x00" -0x0001: "\x01" -0x0002: "\x02" -0x0003: "\x03" -0x0004: "\x04" -0x0005: "\x05" -0x0006: "\x06" -0x0007: "\x07" -0x0008: "\x08" -0x0009: "\t" -0x000a: "\n" -0x000b: "\x0b" -0x000c: "\x0c" -0x000d: "\r" -0x000e: "\x0e" -0x000f: "\x0f" -0x0010: "\x10" -0x0011: "\x11" -0x0012: "\x12" -0x0013: "\x13" -0x0014: "\x14" -0x0015: "\x15" -0x0016: "\x16" -0x0017: "\x17" -0x0018: "\x18" -0x0019: "\x19" -0x001a: "\x1a" -0x001b: "\x1b" -0x001c: "\x1c" -0x001d: "\x1d" -0x001e: "\x1e" -0x001f: "\x1f" -0x0020: " " -0x0021: "!" -0x0022: "\"" -0x0023: "#" -0x0024: "$" -0x0025: "%" -0x0026: "&" -0x0027: "'" -0x0028: "(" -0x0029: ")" -0x002a: "*" -0x002b: "+" -0x002c: "," -0x002d: "-" -0x002e: "." -0x002f: "/" -0x0030: "0" -0x0031: "1" -0x0032: "2" -0x0033: "3" -0x0034: "4" -0x0035: "5" -0x0036: "6" -0x0037: "7" -0x0038: "8" -0x0039: "9" -0x003a: ":" -0x003b: ";" -0x003c: "<" -0x003d: "=" -0x003e: ">" -0x003f: "?" -0x0040: "@" -0x0041: "A" -0x0042: "B" -0x0043: "C" -0x0044: "D" -0x0045: "E" -0x0046: "F" -0x0047: "G" -0x0048: "H" -0x0049: "I" -0x004a: "J" -0x004b: "K" -0x004c: "L" -0x004d: "M" -0x004e: "N" -0x004f: "O" -0x0050: "P" -0x0051: "Q" -0x0052: "R" -0x0053: "S" -0x0054: "T" -0x0055: "U" -0x0056: "V" -0x0057: "W" -0x0058: "X" -0x0059: "Y" -0x005a: "Z" -0x005b: "]" -0x005c: "\\" -0x005d: "]" -0x005e: "^" -0x005f: "_" -0x0060: "`" -0x0061: "a" -0x0062: "b" -0x0063: "c" -0x0064: "d" -0x0065: "e" -0x0066: "f" -0x0067: "g" -0x0068: "h" -0x0069: "i" -0x006a: "j" -0x006b: "k" -0x006c: "l" -0x006d: "m" -0x006e: "n" -0x006f: "o" -0x0070: "p" -0x0071: "q" -0x0072: "r" -0x0073: "s" -0x0074: "t" -0x0075: "u" -0x0076: "v" -0x0077: "w" -0x0078: "x" -0x0079: "y" -0x007a: "z" -0x007b: "{" -0x007c: "|" -0x007d: "}" -0x007e: "~" -0x007f: "\x7f" -0x0080: "" -0x0081: "" -0x0082: "" -0x0083: "" -0x0084: "" -0x0085: "" -0x0086: "" -0x0087: "" -0x0088: "" -0x0089: "" -0x008a: "" -0x008b: "" -0x008c: "" -0x008d: "" -0x008e: "" -0x008f: "" -0x0090: "" -0x0091: "" -0x0092: "" -0x0093: "" -0x0094: "" -0x0095: "" -0x0096: "" -0x0097: "" -0x0098: "" -0x0099: "" -0x009a: "" -0x009b: "" -0x009c: "" -0x009d: "" -0x009e: "" -0x009f: "" -0x00a0: " " -0x00a1: "!" -0x00a2: "C/" -0x00a3: "PS" -0x00a4: "$?" -0x00a5: "Y=" -0x00a6: "|" -0x00a7: "SS" -0x00a8: "\"" -0x00a9: "(c)" -0x00aa: "a" -0x00ab: "<<" -0x00ac: "!" -0x00ad: "" -0x00ae: "(r)" -0x00af: "-" -0x00b0: "deg" -0x00b1: "+-" -0x00b2: "2" -0x00b3: "3" -0x00b4: "'" -0x00b5: "u" -0x00b6: "P" -0x00b7: "*" -0x00b8: "," -0x00b9: "1" -0x00ba: "o" -0x00bb: ">>" -0x00bc: "1/4" -0x00bd: "1/2" -0x00be: "3/4" -0x00bf: "?" -0x00c0: "A" -0x00c1: "A" -0x00c2: "A" -0x00c3: "A" -0x00c4: "A" -0x00c5: "A" -0x00c6: "AE" -0x00c7: "C" -0x00c8: "E" -0x00c9: "E" -0x00ca: "E" -0x00cb: "E" -0x00cc: "I" -0x00cd: "I" -0x00ce: "I" -0x00cf: "I" -0x00d0: "D" -0x00d1: "N" -0x00d2: "O" -0x00d3: "O" -0x00d4: "O" -0x00d5: "O" -0x00d6: "O" -0x00d7: "x" -0x00d8: "O" -0x00d9: "U" -0x00da: "U" -0x00db: "U" -0x00dc: "U" -0x00dd: "Y" -0x00de: "Th" -0x00df: "ss" -0x00e0: "a" -0x00e1: "a" -0x00e2: "a" -0x00e3: "a" -0x00e4: "a" -0x00e5: "a" -0x00e6: "ae" -0x00e7: "c" -0x00e8: "e" -0x00e9: "e" -0x00ea: "e" -0x00eb: "e" -0x00ec: "i" -0x00ed: "i" -0x00ee: "i" -0x00ef: "i" -0x00f0: "d" -0x00f1: "n" -0x00f2: "o" -0x00f3: "o" -0x00f4: "o" -0x00f5: "o" -0x00f6: "o" -0x00f7: "/" -0x00f8: "o" -0x00f9: "u" -0x00fa: "u" -0x00fb: "u" -0x00fc: "u" -0x00fd: "y" -0x00fe: "th" -0x00ff: "y" -/* x001 */ -0x0100: "A" -0x0101: "a" -0x0102: "A" -0x0103: "a" -0x0104: "A" -0x0105: "a" -0x0106: "C" -0x0107: "c" -0x0108: "C" -0x0109: "c" -0x010a: "C" -0x010b: "c" -0x010c: "C" -0x010d: "c" -0x010e: "D" -0x010f: "d" -0x0110: "D" -0x0111: "d" -0x0112: "E" -0x0113: "e" -0x0114: "E" -0x0115: "e" -0x0116: "E" -0x0117: "e" -0x0118: "E" -0x0119: "e" -0x011a: "E" -0x011b: "e" -0x011c: "G" -0x011d: "g" -0x011e: "G" -0x011f: "g" -0x0120: "G" -0x0121: "g" -0x0122: "G" -0x0123: "g" -0x0124: "H" -0x0125: "h" -0x0126: "H" -0x0127: "h" -0x0128: "I" -0x0129: "i" -0x012a: "I" -0x012b: "i" -0x012c: "I" -0x012d: "i" -0x012e: "I" -0x012f: "i" -0x0130: "I" -0x0131: "i" -0x0132: "IJ" -0x0133: "ij" -0x0134: "J" -0x0135: "j" -0x0136: "K" -0x0137: "k" -0x0138: "k" -0x0139: "L" -0x013a: "l" -0x013b: "L" -0x013c: "l" -0x013d: "L" -0x013e: "l" -0x013f: "L" -0x0140: "l" -0x0141: "L" -0x0142: "l" -0x0143: "N" -0x0144: "n" -0x0145: "N" -0x0146: "n" -0x0147: "N" -0x0148: "n" -0x0149: "'n" -0x014a: "ng" -0x014b: "NG" -0x014c: "O" -0x014d: "o" -0x014e: "O" -0x014f: "o" -0x0150: "O" -0x0151: "o" -0x0152: "OE" -0x0153: "oe" -0x0154: "R" -0x0155: "r" -0x0156: "R" -0x0157: "r" -0x0158: "R" -0x0159: "r" -0x015a: "S" -0x015b: "s" -0x015c: "S" -0x015d: "s" -0x015e: "S" -0x015f: "s" -0x0160: "S" -0x0161: "s" -0x0162: "T" -0x0163: "t" -0x0164: "T" -0x0165: "t" -0x0166: "T" -0x0167: "t" -0x0168: "U" -0x0169: "u" -0x016a: "U" -0x016b: "u" -0x016c: "U" -0x016d: "u" -0x016e: "U" -0x016f: "u" -0x0170: "U" -0x0171: "u" -0x0172: "U" -0x0173: "u" -0x0174: "W" -0x0175: "w" -0x0176: "Y" -0x0177: "y" -0x0178: "Y" -0x0179: "Z" -0x017a: "z" -0x017b: "Z" -0x017c: "z" -0x017d: "Z" -0x017e: "z" -0x017f: "s" -0x0180: "b" -0x0181: "B" -0x0182: "B" -0x0183: "b" -0x0184: "6" -0x0185: "6" -0x0186: "O" -0x0187: "C" -0x0188: "c" -0x0189: "D" -0x018a: "D" -0x018b: "D" -0x018c: "d" -0x018d: "d" -0x018e: "3" -0x018f: "@" -0x0190: "E" -0x0191: "F" -0x0192: "f" -0x0193: "G" -0x0194: "G" -0x0195: "hv" -0x0196: "I" -0x0197: "I" -0x0198: "K" -0x0199: "k" -0x019a: "l" -0x019b: "l" -0x019c: "W" -0x019d: "N" -0x019e: "n" -0x019f: "O" -0x01a0: "O" -0x01a1: "o" -0x01a2: "OI" -0x01a3: "oi" -0x01a4: "P" -0x01a5: "p" -0x01a6: "YR" -0x01a7: "2" -0x01a8: "2" -0x01a9: "SH" -0x01aa: "sh" -0x01ab: "t" -0x01ac: "T" -0x01ad: "t" -0x01ae: "T" -0x01af: "U" -0x01b0: "u" -0x01b1: "Y" -0x01b2: "V" -0x01b3: "Y" -0x01b4: "y" -0x01b5: "Z" -0x01b6: "z" -0x01b7: "ZH" -0x01b8: "ZH" -0x01b9: "zh" -0x01ba: "zh" -0x01bb: "2" -0x01bc: "5" -0x01bd: "5" -0x01be: "ts" -0x01bf: "w" -0x01c0: "|" -0x01c1: "||" -0x01c2: "|=" -0x01c3: "!" -0x01c4: "DZ" -0x01c5: "Dz" -0x01c6: "dz" -0x01c7: "LJ" -0x01c8: "Lj" -0x01c9: "lj" -0x01ca: "NJ" -0x01cb: "Nj" -0x01cc: "nj" -0x01cd: "A" -0x01ce: "a" -0x01cf: "I" -0x01d0: "i" -0x01d1: "O" -0x01d2: "o" -0x01d3: "U" -0x01d4: "u" -0x01d5: "U" -0x01d6: "u" -0x01d7: "U" -0x01d8: "u" -0x01d9: "U" -0x01da: "u" -0x01db: "U" -0x01dc: "u" -0x01dd: "@" -0x01de: "A" -0x01df: "a" -0x01e0: "A" -0x01e1: "a" -0x01e2: "AE" -0x01e3: "ae" -0x01e4: "G" -0x01e5: "g" -0x01e6: "G" -0x01e7: "g" -0x01e8: "K" -0x01e9: "k" -0x01ea: "O" -0x01eb: "o" -0x01ec: "O" -0x01ed: "o" -0x01ee: "ZH" -0x01ef: "zh" -0x01f0: "j" -0x01f1: "DZ" -0x01f2: "Dz" -0x01f3: "dz" -0x01f4: "G" -0x01f5: "g" -0x01f6: "HV" -0x01f7: "W" -0x01f8: "N" -0x01f9: "n" -0x01fa: "A" -0x01fb: "a" -0x01fc: "AE" -0x01fd: "ae" -0x01fe: "O" -0x01ff: "o" -/* x002 */ -0x0200: "A" -0x0201: "a" -0x0202: "A" -0x0203: "a" -0x0204: "E" -0x0205: "e" -0x0206: "E" -0x0207: "e" -0x0208: "I" -0x0209: "i" -0x020a: "I" -0x020b: "i" -0x020c: "O" -0x020d: "o" -0x020e: "O" -0x020f: "o" -0x0210: "R" -0x0211: "r" -0x0212: "R" -0x0213: "r" -0x0214: "U" -0x0215: "u" -0x0216: "U" -0x0217: "u" -0x0218: "S" -0x0219: "s" -0x021a: "T" -0x021b: "t" -0x021c: "Y" -0x021d: "y" -0x021e: "H" -0x021f: "h" -0x0220: "N" -0x0221: "d" -0x0222: "OU" -0x0223: "ou" -0x0224: "Z" -0x0225: "z" -0x0226: "A" -0x0227: "a" -0x0228: "E" -0x0229: "e" -0x022a: "O" -0x022b: "o" -0x022c: "O" -0x022d: "o" -0x022e: "O" -0x022f: "o" -0x0230: "O" -0x0231: "o" -0x0232: "Y" -0x0233: "y" -0x0234: "l" -0x0235: "n" -0x0236: "t" -0x0237: "j" -0x0238: "db" -0x0239: "qp" -0x023a: "A" -0x023b: "C" -0x023c: "c" -0x023d: "L" -0x023e: "T" -0x023f: "s" -0x0240: "z" -0x0241: "[?]" -0x0242: "[?]" -0x0243: "B" -0x0244: "U" -0x0245: "^" -0x0246: "E" -0x0247: "e" -0x0248: "J" -0x0249: "j" -0x024a: "q" -0x024b: "q" -0x024c: "R" -0x024d: "r" -0x024e: "Y" -0x024f: "y" -0x0250: "a" -0x0251: "a" -0x0252: "a" -0x0253: "b" -0x0254: "o" -0x0255: "c" -0x0256: "d" -0x0257: "d" -0x0258: "e" -0x0259: "@" -0x025a: "@" -0x025b: "e" -0x025c: "e" -0x025d: "e" -0x025e: "e" -0x025f: "j" -0x0260: "g" -0x0261: "g" -0x0262: "g" -0x0263: "g" -0x0264: "u" -0x0265: "Y" -0x0266: "h" -0x0267: "h" -0x0268: "i" -0x0269: "i" -0x026a: "I" -0x026b: "l" -0x026c: "l" -0x026d: "l" -0x026e: "lZ" -0x026f: "W" -0x0270: "W" -0x0271: "m" -0x0272: "n" -0x0273: "n" -0x0274: "n" -0x0275: "o" -0x0276: "OE" -0x0277: "O" -0x0278: "F" -0x0279: "r" -0x027a: "r" -0x027b: "r" -0x027c: "r" -0x027d: "r" -0x027e: "r" -0x027f: "r" -0x0280: "R" -0x0281: "R" -0x0282: "s" -0x0283: "S" -0x0284: "j" -0x0285: "S" -0x0286: "S" -0x0287: "t" -0x0288: "t" -0x0289: "u" -0x028a: "U" -0x028b: "v" -0x028c: "^" -0x028d: "w" -0x028e: "y" -0x028f: "Y" -0x0290: "z" -0x0291: "z" -0x0292: "Z" -0x0293: "Z" -0x0294: "?" -0x0295: "?" -0x0296: "?" -0x0297: "C" -0x0298: "@" -0x0299: "B" -0x029a: "E" -0x029b: "G" -0x029c: "H" -0x029d: "j" -0x029e: "k" -0x029f: "L" -0x02a0: "q" -0x02a1: "?" -0x02a2: "?" -0x02a3: "dz" -0x02a4: "dZ" -0x02a5: "dz" -0x02a6: "ts" -0x02a7: "tS" -0x02a8: "tC" -0x02a9: "fN" -0x02aa: "ls" -0x02ab: "lz" -0x02ac: "WW" -0x02ad: "]]" -0x02ae: "h" -0x02af: "h" -0x02b0: "k" -0x02b1: "h" -0x02b2: "j" -0x02b3: "r" -0x02b4: "r" -0x02b5: "r" -0x02b6: "r" -0x02b7: "w" -0x02b8: "y" -0x02b9: "'" -0x02ba: "\"" -0x02bb: "`" -0x02bc: "'" -0x02bd: "`" -0x02be: "`" -0x02bf: "'" -0x02c0: "?" -0x02c1: "?" -0x02c2: "<" -0x02c3: ">" -0x02c4: "^" -0x02c5: "V" -0x02c6: "^" -0x02c7: "V" -0x02c8: "'" -0x02c9: "-" -0x02ca: "/" -0x02cb: "\\" -0x02cc: "," -0x02cd: "_" -0x02ce: "\\" -0x02cf: "/" -0x02d0: ":" -0x02d1: "." -0x02d2: "`" -0x02d3: "'" -0x02d4: "^" -0x02d5: "V" -0x02d6: "+" -0x02d7: "-" -0x02d8: "V" -0x02d9: "." -0x02da: "@" -0x02db: "," -0x02dc: "~" -0x02dd: "\"" -0x02de: "R" -0x02df: "X" -0x02e0: "G" -0x02e1: "l" -0x02e2: "s" -0x02e3: "x" -0x02e4: "?" -0x02e5: "" -0x02e6: "" -0x02e7: "" -0x02e8: "" -0x02e9: "" -0x02ea: "" -0x02eb: "" -0x02ec: "V" -0x02ed: "=" -0x02ee: "\"" -0x02ef: "[?]" -0x02f0: "[?]" -0x02f1: "[?]" -0x02f2: "[?]" -0x02f3: "[?]" -0x02f4: "[?]" -0x02f5: "[?]" -0x02f6: "[?]" -0x02f7: "[?]" -0x02f8: "[?]" -0x02f9: "[?]" -0x02fa: "[?]" -0x02fb: "[?]" -0x02fc: "[?]" -0x02fd: "[?]" -0x02fe: "[?]" -/* x003 */ -0x0300: "" -0x0301: "" -0x0302: "" -0x0303: "" -0x0304: "" -0x0305: "" -0x0306: "" -0x0307: "" -0x0308: "" -0x0309: "" -0x030a: "" -0x030b: "" -0x030c: "" -0x030d: "" -0x030e: "" -0x030f: "" -0x0310: "" -0x0311: "" -0x0312: "" -0x0313: "" -0x0314: "" -0x0315: "" -0x0316: "" -0x0317: "" -0x0318: "" -0x0319: "" -0x031a: "" -0x031b: "" -0x031c: "" -0x031d: "" -0x031e: "" -0x031f: "" -0x0320: "" -0x0321: "" -0x0322: "" -0x0323: "" -0x0324: "" -0x0325: "" -0x0326: "" -0x0327: "" -0x0328: "" -0x0329: "" -0x032a: "" -0x032b: "" -0x032c: "" -0x032d: "" -0x032e: "" -0x032f: "" -0x0330: "" -0x0331: "" -0x0332: "" -0x0333: "" -0x0334: "" -0x0335: "" -0x0336: "" -0x0337: "" -0x0338: "" -0x0339: "" -0x033a: "" -0x033b: "" -0x033c: "" -0x033d: "" -0x033e: "" -0x033f: "" -0x0340: "" -0x0341: "" -0x0342: "" -0x0343: "" -0x0344: "" -0x0345: "" -0x0346: "" -0x0347: "" -0x0348: "" -0x0349: "" -0x034a: "" -0x034b: "" -0x034c: "" -0x034d: "" -0x034e: "" -0x034f: "[?]" -0x0350: "[?]" -0x0351: "[?]" -0x0352: "[?]" -0x0353: "[?]" -0x0354: "[?]" -0x0355: "[?]" -0x0356: "[?]" -0x0357: "[?]" -0x0358: "[?]" -0x0359: "[?]" -0x035a: "[?]" -0x035b: "[?]" -0x035c: "[?]" -0x035d: "[?]" -0x035e: "[?]" -0x035f: "[?]" -0x0360: "" -0x0361: "" -0x0362: "" -0x0363: "a" -0x0364: "e" -0x0365: "i" -0x0366: "o" -0x0367: "u" -0x0368: "c" -0x0369: "d" -0x036a: "h" -0x036b: "m" -0x036c: "r" -0x036d: "t" -0x036e: "v" -0x036f: "x" -0x0370: "[?]" -0x0371: "[?]" -0x0372: "[?]" -0x0373: "[?]" -0x0374: "'" -0x0375: "," -0x0376: "[?]" -0x0377: "[?]" -0x0378: "[?]" -0x0379: "[?]" -0x037a: "" -0x037b: "[?]" -0x037c: "[?]" -0x037d: "[?]" -0x037e: "?" -0x037f: "[?]" -0x0380: "[?]" -0x0381: "[?]" -0x0382: "[?]" -0x0383: "[?]" -0x0384: "" -0x0385: "" -0x0386: "A" -0x0387: ";" -0x0388: "E" -0x0389: "E" -0x038a: "I" -0x038b: "[?]" -0x038c: "O" -0x038d: "[?]" -0x038e: "U" -0x038f: "O" -0x0390: "I" -0x0391: "A" -0x0392: "B" -0x0393: "G" -0x0394: "D" -0x0395: "E" -0x0396: "Z" -0x0397: "E" -0x0398: "Th" -0x0399: "I" -0x039a: "K" -0x039b: "L" -0x039c: "M" -0x039d: "N" -0x039e: "Ks" -0x039f: "O" -0x03a0: "P" -0x03a1: "R" -0x03a2: "[?]" -0x03a3: "S" -0x03a4: "T" -0x03a5: "U" -0x03a6: "Ph" -0x03a7: "Kh" -0x03a8: "Ps" -0x03a9: "O" -0x03aa: "I" -0x03ab: "U" -0x03ac: "a" -0x03ad: "e" -0x03ae: "e" -0x03af: "i" -0x03b0: "u" -0x03b1: "a" -0x03b2: "b" -0x03b3: "g" -0x03b4: "d" -0x03b5: "e" -0x03b6: "z" -0x03b7: "e" -0x03b8: "th" -0x03b9: "i" -0x03ba: "k" -0x03bb: "l" -0x03bc: "m" -0x03bd: "n" -0x03be: "x" -0x03bf: "o" -0x03c0: "p" -0x03c1: "r" -0x03c2: "s" -0x03c3: "s" -0x03c4: "t" -0x03c5: "u" -0x03c6: "ph" -0x03c7: "kh" -0x03c8: "ps" -0x03c9: "o" -0x03ca: "i" -0x03cb: "u" -0x03cc: "o" -0x03cd: "u" -0x03ce: "o" -0x03cf: "[?]" -0x03d0: "b" -0x03d1: "th" -0x03d2: "U" -0x03d3: "U" -0x03d4: "U" -0x03d5: "ph" -0x03d6: "p" -0x03d7: "&" -0x03d8: "[?]" -0x03d9: "[?]" -0x03da: "St" -0x03db: "st" -0x03dc: "W" -0x03dd: "w" -0x03de: "Q" -0x03df: "q" -0x03e0: "Sp" -0x03e1: "sp" -0x03e2: "Sh" -0x03e3: "sh" -0x03e4: "F" -0x03e5: "f" -0x03e6: "Kh" -0x03e7: "kh" -0x03e8: "H" -0x03e9: "h" -0x03ea: "G" -0x03eb: "g" -0x03ec: "CH" -0x03ed: "ch" -0x03ee: "Ti" -0x03ef: "ti" -0x03f0: "k" -0x03f1: "r" -0x03f2: "c" -0x03f3: "j" -0x03f4: "[?]" -0x03f5: "[?]" -0x03f6: "[?]" -0x03f7: "[?]" -0x03f8: "[?]" -0x03f9: "[?]" -0x03fa: "[?]" -0x03fb: "[?]" -0x03fc: "[?]" -0x03fd: "[?]" -0x03fe: "[?]" -/* x004 */ -0x0400: "Ie" -0x0401: "Io" -0x0402: "Dj" -0x0403: "Gj" -0x0404: "Ie" -0x0405: "Dz" -0x0406: "I" -0x0407: "Yi" -0x0408: "J" -0x0409: "Lj" -0x040a: "Nj" -0x040b: "Tsh" -0x040c: "Kj" -0x040d: "I" -0x040e: "U" -0x040f: "Dzh" -0x0410: "A" -0x0411: "B" -0x0412: "V" -0x0413: "G" -0x0414: "D" -0x0415: "E" -0x0416: "Zh" -0x0417: "Z" -0x0418: "I" -0x0419: "I" -0x041a: "K" -0x041b: "L" -0x041c: "M" -0x041d: "N" -0x041e: "O" -0x041f: "P" -0x0420: "R" -0x0421: "S" -0x0422: "T" -0x0423: "U" -0x0424: "F" -0x0425: "Kh" -0x0426: "Ts" -0x0427: "Ch" -0x0428: "Sh" -0x0429: "Shch" -0x042a: "'" -0x042b: "Y" -0x042c: "'" -0x042d: "E" -0x042e: "Iu" -0x042f: "Ia" -0x0430: "a" -0x0431: "b" -0x0432: "v" -0x0433: "g" -0x0434: "d" -0x0435: "e" -0x0436: "zh" -0x0437: "z" -0x0438: "i" -0x0439: "i" -0x043a: "k" -0x043b: "l" -0x043c: "m" -0x043d: "n" -0x043e: "o" -0x043f: "p" -0x0440: "r" -0x0441: "s" -0x0442: "t" -0x0443: "u" -0x0444: "f" -0x0445: "kh" -0x0446: "ts" -0x0447: "ch" -0x0448: "sh" -0x0449: "shch" -0x044a: "'" -0x044b: "y" -0x044c: "'" -0x044d: "e" -0x044e: "iu" -0x044f: "ia" -0x0450: "ie" -0x0451: "io" -0x0452: "dj" -0x0453: "gj" -0x0454: "ie" -0x0455: "dz" -0x0456: "i" -0x0457: "yi" -0x0458: "j" -0x0459: "lj" -0x045a: "nj" -0x045b: "tsh" -0x045c: "kj" -0x045d: "i" -0x045e: "u" -0x045f: "dzh" -0x0460: "O" -0x0461: "o" -0x0462: "E" -0x0463: "e" -0x0464: "Ie" -0x0465: "ie" -0x0466: "E" -0x0467: "e" -0x0468: "Ie" -0x0469: "ie" -0x046a: "O" -0x046b: "o" -0x046c: "Io" -0x046d: "io" -0x046e: "Ks" -0x046f: "ks" -0x0470: "Ps" -0x0471: "ps" -0x0472: "F" -0x0473: "f" -0x0474: "Y" -0x0475: "y" -0x0476: "Y" -0x0477: "y" -0x0478: "u" -0x0479: "u" -0x047a: "O" -0x047b: "o" -0x047c: "O" -0x047d: "o" -0x047e: "Ot" -0x047f: "ot" -0x0480: "Q" -0x0481: "q" -0x0482: "*1000*" -0x0483: "" -0x0484: "" -0x0485: "" -0x0486: "" -0x0487: "[?]" -0x0488: "*100.000*" -0x0489: "*1.000.000*" -0x048a: "[?]" -0x048b: "[?]" -0x048c: "\"" -0x048d: "\"" -0x048e: "R'" -0x048f: "r'" -0x0490: "G'" -0x0491: "g'" -0x0492: "G'" -0x0493: "g'" -0x0494: "G'" -0x0495: "g'" -0x0496: "Zh'" -0x0497: "zh'" -0x0498: "Z'" -0x0499: "z'" -0x049a: "K'" -0x049b: "k'" -0x049c: "K'" -0x049d: "k'" -0x049e: "K'" -0x049f: "k'" -0x04a0: "K'" -0x04a1: "k'" -0x04a2: "N'" -0x04a3: "n'" -0x04a4: "Ng" -0x04a5: "ng" -0x04a6: "P'" -0x04a7: "p'" -0x04a8: "Kh" -0x04a9: "kh" -0x04aa: "S'" -0x04ab: "s'" -0x04ac: "T'" -0x04ad: "t'" -0x04ae: "U" -0x04af: "u" -0x04b0: "U'" -0x04b1: "u'" -0x04b2: "Kh'" -0x04b3: "kh'" -0x04b4: "Tts" -0x04b5: "tts" -0x04b6: "Ch'" -0x04b7: "ch'" -0x04b8: "Ch'" -0x04b9: "ch'" -0x04ba: "H" -0x04bb: "h" -0x04bc: "Ch" -0x04bd: "ch" -0x04be: "Ch'" -0x04bf: "ch'" -0x04c0: "`" -0x04c1: "Zh" -0x04c2: "zh" -0x04c3: "K'" -0x04c4: "k'" -0x04c5: "[?]" -0x04c6: "[?]" -0x04c7: "N'" -0x04c8: "n'" -0x04c9: "[?]" -0x04ca: "[?]" -0x04cb: "Ch" -0x04cc: "ch" -0x04cd: "[?]" -0x04ce: "[?]" -0x04cf: "[?]" -0x04d0: "a" -0x04d1: "a" -0x04d2: "A" -0x04d3: "a" -0x04d4: "Ae" -0x04d5: "ae" -0x04d6: "Ie" -0x04d7: "ie" -0x04d8: "@" -0x04d9: "@" -0x04da: "@" -0x04db: "@" -0x04dc: "Zh" -0x04dd: "zh" -0x04de: "Z" -0x04df: "z" -0x04e0: "Dz" -0x04e1: "dz" -0x04e2: "I" -0x04e3: "i" -0x04e4: "I" -0x04e5: "i" -0x04e6: "O" -0x04e7: "o" -0x04e8: "O" -0x04e9: "o" -0x04ea: "O" -0x04eb: "o" -0x04ec: "E" -0x04ed: "e" -0x04ee: "U" -0x04ef: "u" -0x04f0: "U" -0x04f1: "u" -0x04f2: "U" -0x04f3: "u" -0x04f4: "Ch" -0x04f5: "ch" -0x04f6: "[?]" -0x04f7: "[?]" -0x04f8: "Y" -0x04f9: "y" -0x04fa: "[?]" -0x04fb: "[?]" -0x04fc: "[?]" -0x04fd: "[?]" -0x04fe: "[?]" -/* x005 */ -0x0500: "[?]" -0x0501: "[?]" -0x0502: "[?]" -0x0503: "[?]" -0x0504: "[?]" -0x0505: "[?]" -0x0506: "[?]" -0x0507: "[?]" -0x0508: "[?]" -0x0509: "[?]" -0x050a: "[?]" -0x050b: "[?]" -0x050c: "[?]" -0x050d: "[?]" -0x050e: "[?]" -0x050f: "[?]" -0x0510: "[?]" -0x0511: "[?]" -0x0512: "[?]" -0x0513: "[?]" -0x0514: "[?]" -0x0515: "[?]" -0x0516: "[?]" -0x0517: "[?]" -0x0518: "[?]" -0x0519: "[?]" -0x051a: "[?]" -0x051b: "[?]" -0x051c: "[?]" -0x051d: "[?]" -0x051e: "[?]" -0x051f: "[?]" -0x0520: "[?]" -0x0521: "[?]" -0x0522: "[?]" -0x0523: "[?]" -0x0524: "[?]" -0x0525: "[?]" -0x0526: "[?]" -0x0527: "[?]" -0x0528: "[?]" -0x0529: "[?]" -0x052a: "[?]" -0x052b: "[?]" -0x052c: "[?]" -0x052d: "[?]" -0x052e: "[?]" -0x052f: "[?]" -0x0530: "[?]" -0x0531: "A" -0x0532: "B" -0x0533: "G" -0x0534: "D" -0x0535: "E" -0x0536: "Z" -0x0537: "E" -0x0538: "E" -0x0539: "T`" -0x053a: "Zh" -0x053b: "I" -0x053c: "L" -0x053d: "Kh" -0x053e: "Ts" -0x053f: "K" -0x0540: "H" -0x0541: "Dz" -0x0542: "Gh" -0x0543: "Ch" -0x0544: "M" -0x0545: "Y" -0x0546: "N" -0x0547: "Sh" -0x0548: "O" -0x0549: "Ch`" -0x054a: "P" -0x054b: "J" -0x054c: "Rh" -0x054d: "S" -0x054e: "V" -0x054f: "T" -0x0550: "R" -0x0551: "Ts`" -0x0552: "W" -0x0553: "P`" -0x0554: "K`" -0x0555: "O" -0x0556: "F" -0x0557: "[?]" -0x0558: "[?]" -0x0559: "<" -0x055a: "'" -0x055b: "/" -0x055c: "!" -0x055d: "," -0x055e: "?" -0x055f: "." -0x0560: "[?]" -0x0561: "a" -0x0562: "b" -0x0563: "g" -0x0564: "d" -0x0565: "e" -0x0566: "z" -0x0567: "e" -0x0568: "e" -0x0569: "t`" -0x056a: "zh" -0x056b: "i" -0x056c: "l" -0x056d: "kh" -0x056e: "ts" -0x056f: "k" -0x0570: "h" -0x0571: "dz" -0x0572: "gh" -0x0573: "ch" -0x0574: "m" -0x0575: "y" -0x0576: "n" -0x0577: "sh" -0x0578: "o" -0x0579: "ch`" -0x057a: "p" -0x057b: "j" -0x057c: "rh" -0x057d: "s" -0x057e: "v" -0x057f: "t" -0x0580: "r" -0x0581: "ts`" -0x0582: "w" -0x0583: "p`" -0x0584: "k`" -0x0585: "o" -0x0586: "f" -0x0587: "ew" -0x0588: "[?]" -0x0589: "." -0x058a: "-" -0x058b: "[?]" -0x058c: "[?]" -0x058d: "[?]" -0x058e: "[?]" -0x058f: "[?]" -0x0590: "[?]" -0x0591: "" -0x0592: "" -0x0593: "" -0x0594: "" -0x0595: "" -0x0596: "" -0x0597: "" -0x0598: "" -0x0599: "" -0x059a: "" -0x059b: "" -0x059c: "" -0x059d: "" -0x059e: "" -0x059f: "" -0x05a0: "" -0x05a1: "" -0x05a2: "[?]" -0x05a3: "" -0x05a4: "" -0x05a5: "" -0x05a6: "" -0x05a7: "" -0x05a8: "" -0x05a9: "" -0x05aa: "" -0x05ab: "" -0x05ac: "" -0x05ad: "" -0x05ae: "" -0x05af: "" -0x05b0: "@" -0x05b1: "e" -0x05b2: "a" -0x05b3: "o" -0x05b4: "i" -0x05b5: "e" -0x05b6: "e" -0x05b7: "a" -0x05b8: "a" -0x05b9: "o" -0x05ba: "[?]" -0x05bb: "u" -0x05bc: "'" -0x05bd: "" -0x05be: "" -0x05bf: "" -0x05c0: "" -0x05c1: "" -0x05c2: "" -0x05c3: ":" -0x05c4: "" -0x05c5: "[?]" -0x05c6: "[?]" -0x05c7: "[?]" -0x05c8: "[?]" -0x05c9: "[?]" -0x05ca: "[?]" -0x05cb: "[?]" -0x05cc: "[?]" -0x05cd: "[?]" -0x05ce: "[?]" -0x05cf: "[?]" -0x05d0: "" -0x05d1: "b" -0x05d2: "g" -0x05d3: "d" -0x05d4: "h" -0x05d5: "v" -0x05d6: "z" -0x05d7: "kh" -0x05d8: "t" -0x05d9: "y" -0x05da: "k" -0x05db: "k" -0x05dc: "l" -0x05dd: "m" -0x05de: "m" -0x05df: "n" -0x05e0: "n" -0x05e1: "s" -0x05e2: "`" -0x05e3: "p" -0x05e4: "p" -0x05e5: "ts" -0x05e6: "ts" -0x05e7: "q" -0x05e8: "r" -0x05e9: "sh" -0x05ea: "t" -0x05eb: "[?]" -0x05ec: "[?]" -0x05ed: "[?]" -0x05ee: "[?]" -0x05ef: "[?]" -0x05f0: "V" -0x05f1: "oy" -0x05f2: "i" -0x05f3: "'" -0x05f4: "\"" -0x05f5: "[?]" -0x05f6: "[?]" -0x05f7: "[?]" -0x05f8: "[?]" -0x05f9: "[?]" -0x05fa: "[?]" -0x05fb: "[?]" -0x05fc: "[?]" -0x05fd: "[?]" -0x05fe: "[?]" -/* x006 */ -0x0600: "[?]" -0x0601: "[?]" -0x0602: "[?]" -0x0603: "[?]" -0x0604: "[?]" -0x0605: "[?]" -0x0606: "[?]" -0x0607: "[?]" -0x0608: "[?]" -0x0609: "[?]" -0x060a: "[?]" -0x060b: "[?]" -0x060c: "," -0x060d: "[?]" -0x060e: "[?]" -0x060f: "[?]" -0x0610: "[?]" -0x0611: "[?]" -0x0612: "[?]" -0x0613: "[?]" -0x0614: "[?]" -0x0615: "[?]" -0x0616: "[?]" -0x0617: "[?]" -0x0618: "[?]" -0x0619: "[?]" -0x061a: "[?]" -0x061b: ";" -0x061c: "[?]" -0x061d: "[?]" -0x061e: "[?]" -0x061f: "?" -0x0620: "[?]" -0x0621: "" -0x0622: "a" -0x0623: "'" -0x0624: "w'" -0x0625: "" -0x0626: "y'" -0x0627: "" -0x0628: "b" -0x0629: "@" -0x062a: "t" -0x062b: "th" -0x062c: "j" -0x062d: "H" -0x062e: "kh" -0x062f: "d" -0x0630: "dh" -0x0631: "r" -0x0632: "z" -0x0633: "s" -0x0634: "sh" -0x0635: "S" -0x0636: "D" -0x0637: "T" -0x0638: "Z" -0x0639: "`" -0x063a: "G" -0x063b: "[?]" -0x063c: "[?]" -0x063d: "[?]" -0x063e: "[?]" -0x063f: "[?]" -0x0640: "" -0x0641: "f" -0x0642: "q" -0x0643: "k" -0x0644: "l" -0x0645: "m" -0x0646: "n" -0x0647: "h" -0x0648: "w" -0x0649: "~" -0x064a: "y" -0x064b: "an" -0x064c: "un" -0x064d: "in" -0x064e: "a" -0x064f: "u" -0x0650: "i" -0x0651: "W" -0x0652: "" -0x0653: "" -0x0654: "'" -0x0655: "'" -0x0656: "[?]" -0x0657: "[?]" -0x0658: "[?]" -0x0659: "[?]" -0x065a: "[?]" -0x065b: "[?]" -0x065c: "[?]" -0x065d: "[?]" -0x065e: "[?]" -0x065f: "[?]" -0x0660: "0" -0x0661: "1" -0x0662: "2" -0x0663: "3" -0x0664: "4" -0x0665: "5" -0x0666: "6" -0x0667: "7" -0x0668: "8" -0x0669: "9" -0x066a: "%" -0x066b: "." -0x066c: "," -0x066d: "*" -0x066e: "[?]" -0x066f: "[?]" -0x0670: "" -0x0671: "'" -0x0672: "'" -0x0673: "'" -0x0674: "" -0x0675: "'" -0x0676: "'w" -0x0677: "'u" -0x0678: "'y" -0x0679: "tt" -0x067a: "tth" -0x067b: "b" -0x067c: "t" -0x067d: "T" -0x067e: "p" -0x067f: "th" -0x0680: "bh" -0x0681: "'h" -0x0682: "H" -0x0683: "ny" -0x0684: "dy" -0x0685: "H" -0x0686: "ch" -0x0687: "cch" -0x0688: "dd" -0x0689: "D" -0x068a: "D" -0x068b: "Dt" -0x068c: "dh" -0x068d: "ddh" -0x068e: "d" -0x068f: "D" -0x0690: "D" -0x0691: "rr" -0x0692: "R" -0x0693: "R" -0x0694: "R" -0x0695: "R" -0x0696: "R" -0x0697: "R" -0x0698: "j" -0x0699: "R" -0x069a: "S" -0x069b: "S" -0x069c: "S" -0x069d: "S" -0x069e: "S" -0x069f: "T" -0x06a0: "GH" -0x06a1: "F" -0x06a2: "F" -0x06a3: "F" -0x06a4: "v" -0x06a5: "f" -0x06a6: "ph" -0x06a7: "Q" -0x06a8: "Q" -0x06a9: "kh" -0x06aa: "k" -0x06ab: "K" -0x06ac: "K" -0x06ad: "ng" -0x06ae: "K" -0x06af: "g" -0x06b0: "G" -0x06b1: "N" -0x06b2: "G" -0x06b3: "G" -0x06b4: "G" -0x06b5: "L" -0x06b6: "L" -0x06b7: "L" -0x06b8: "L" -0x06b9: "N" -0x06ba: "N" -0x06bb: "N" -0x06bc: "N" -0x06bd: "N" -0x06be: "h" -0x06bf: "Ch" -0x06c0: "hy" -0x06c1: "h" -0x06c2: "H" -0x06c3: "@" -0x06c4: "W" -0x06c5: "oe" -0x06c6: "oe" -0x06c7: "u" -0x06c8: "yu" -0x06c9: "yu" -0x06ca: "W" -0x06cb: "v" -0x06cc: "y" -0x06cd: "Y" -0x06ce: "Y" -0x06cf: "W" -0x06d0: "" -0x06d1: "" -0x06d2: "y" -0x06d3: "y'" -0x06d4: "." -0x06d5: "ae" -0x06d6: "" -0x06d7: "" -0x06d8: "" -0x06d9: "" -0x06da: "" -0x06db: "" -0x06dc: "" -0x06dd: "@" -0x06de: "#" -0x06df: "" -0x06e0: "" -0x06e1: "" -0x06e2: "" -0x06e3: "" -0x06e4: "" -0x06e5: "" -0x06e6: "" -0x06e7: "" -0x06e8: "" -0x06e9: "^" -0x06ea: "" -0x06eb: "" -0x06ec: "" -0x06ed: "" -0x06ee: "[?]" -0x06ef: "[?]" -0x06f0: "0" -0x06f1: "1" -0x06f2: "2" -0x06f3: "3" -0x06f4: "4" -0x06f5: "5" -0x06f6: "6" -0x06f7: "7" -0x06f8: "8" -0x06f9: "9" -0x06fa: "Sh" -0x06fb: "D" -0x06fc: "Gh" -0x06fd: "&" -0x06fe: "+m" -/* x007 */ -0x0700: "//" -0x0701: "/" -0x0702: "," -0x0703: "!" -0x0704: "!" -0x0705: "-" -0x0706: "," -0x0707: "," -0x0708: ";" -0x0709: "?" -0x070a: "~" -0x070b: "{" -0x070c: "}" -0x070d: "*" -0x070e: "[?]" -0x070f: "" -0x0710: "'" -0x0711: "" -0x0712: "b" -0x0713: "g" -0x0714: "g" -0x0715: "d" -0x0716: "d" -0x0717: "h" -0x0718: "w" -0x0719: "z" -0x071a: "H" -0x071b: "t" -0x071c: "t" -0x071d: "y" -0x071e: "yh" -0x071f: "k" -0x0720: "l" -0x0721: "m" -0x0722: "n" -0x0723: "s" -0x0724: "s" -0x0725: "`" -0x0726: "p" -0x0727: "p" -0x0728: "S" -0x0729: "q" -0x072a: "r" -0x072b: "sh" -0x072c: "t" -0x072d: "[?]" -0x072e: "[?]" -0x072f: "[?]" -0x0730: "a" -0x0731: "a" -0x0732: "a" -0x0733: "A" -0x0734: "A" -0x0735: "A" -0x0736: "e" -0x0737: "e" -0x0738: "e" -0x0739: "E" -0x073a: "i" -0x073b: "i" -0x073c: "u" -0x073d: "u" -0x073e: "u" -0x073f: "o" -0x0740: "" -0x0741: "`" -0x0742: "'" -0x0743: "" -0x0744: "" -0x0745: "X" -0x0746: "Q" -0x0747: "@" -0x0748: "@" -0x0749: "|" -0x074a: "+" -0x074b: "[?]" -0x074c: "[?]" -0x074d: "[?]" -0x074e: "[?]" -0x074f: "[?]" -0x0750: "[?]" -0x0751: "[?]" -0x0752: "[?]" -0x0753: "[?]" -0x0754: "[?]" -0x0755: "[?]" -0x0756: "[?]" -0x0757: "[?]" -0x0758: "[?]" -0x0759: "[?]" -0x075a: "[?]" -0x075b: "[?]" -0x075c: "[?]" -0x075d: "[?]" -0x075e: "[?]" -0x075f: "[?]" -0x0760: "[?]" -0x0761: "[?]" -0x0762: "[?]" -0x0763: "[?]" -0x0764: "[?]" -0x0765: "[?]" -0x0766: "[?]" -0x0767: "[?]" -0x0768: "[?]" -0x0769: "[?]" -0x076a: "[?]" -0x076b: "[?]" -0x076c: "[?]" -0x076d: "[?]" -0x076e: "[?]" -0x076f: "[?]" -0x0770: "[?]" -0x0771: "[?]" -0x0772: "[?]" -0x0773: "[?]" -0x0774: "[?]" -0x0775: "[?]" -0x0776: "[?]" -0x0777: "[?]" -0x0778: "[?]" -0x0779: "[?]" -0x077a: "[?]" -0x077b: "[?]" -0x077c: "[?]" -0x077d: "[?]" -0x077e: "[?]" -0x077f: "[?]" -0x0780: "h" -0x0781: "sh" -0x0782: "n" -0x0783: "r" -0x0784: "b" -0x0785: "L" -0x0786: "k" -0x0787: "'" -0x0788: "v" -0x0789: "m" -0x078a: "f" -0x078b: "dh" -0x078c: "th" -0x078d: "l" -0x078e: "g" -0x078f: "ny" -0x0790: "s" -0x0791: "d" -0x0792: "z" -0x0793: "t" -0x0794: "y" -0x0795: "p" -0x0796: "j" -0x0797: "ch" -0x0798: "tt" -0x0799: "hh" -0x079a: "kh" -0x079b: "th" -0x079c: "z" -0x079d: "sh" -0x079e: "s" -0x079f: "d" -0x07a0: "t" -0x07a1: "z" -0x07a2: "`" -0x07a3: "gh" -0x07a4: "q" -0x07a5: "w" -0x07a6: "a" -0x07a7: "aa" -0x07a8: "i" -0x07a9: "ee" -0x07aa: "u" -0x07ab: "oo" -0x07ac: "e" -0x07ad: "ey" -0x07ae: "o" -0x07af: "oa" -0x07b0: "" -0x07b1: "[?]" -0x07b2: "[?]" -0x07b3: "[?]" -0x07b4: "[?]" -0x07b5: "[?]" -0x07b6: "[?]" -0x07b7: "[?]" -0x07b8: "[?]" -0x07b9: "[?]" -0x07ba: "[?]" -0x07bb: "[?]" -0x07bc: "[?]" -0x07bd: "[?]" -0x07be: "[?]" -0x07bf: "[?]" -0x07c0: "[?]" -0x07c1: "[?]" -0x07c2: "[?]" -0x07c3: "[?]" -0x07c4: "[?]" -0x07c5: "[?]" -0x07c6: "[?]" -0x07c7: "[?]" -0x07c8: "[?]" -0x07c9: "[?]" -0x07ca: "[?]" -0x07cb: "[?]" -0x07cc: "[?]" -0x07cd: "[?]" -0x07ce: "[?]" -0x07cf: "[?]" -0x07d0: "[?]" -0x07d1: "[?]" -0x07d2: "[?]" -0x07d3: "[?]" -0x07d4: "[?]" -0x07d5: "[?]" -0x07d6: "[?]" -0x07d7: "[?]" -0x07d8: "[?]" -0x07d9: "[?]" -0x07da: "[?]" -0x07db: "[?]" -0x07dc: "[?]" -0x07dd: "[?]" -0x07de: "[?]" -0x07df: "[?]" -0x07e0: "[?]" -0x07e1: "[?]" -0x07e2: "[?]" -0x07e3: "[?]" -0x07e4: "[?]" -0x07e5: "[?]" -0x07e6: "[?]" -0x07e7: "[?]" -0x07e8: "[?]" -0x07e9: "[?]" -0x07ea: "[?]" -0x07eb: "[?]" -0x07ec: "[?]" -0x07ed: "[?]" -0x07ee: "[?]" -0x07ef: "[?]" -0x07f0: "[?]" -0x07f1: "[?]" -0x07f2: "[?]" -0x07f3: "[?]" -0x07f4: "[?]" -0x07f5: "[?]" -0x07f6: "[?]" -0x07f7: "[?]" -0x07f8: "[?]" -0x07f9: "[?]" -0x07fa: "[?]" -0x07fb: "[?]" -0x07fc: "[?]" -0x07fd: "[?]" -0x07fe: "[?]" -/* x009 */ -0x0900: "[?]" -0x0901: "N" -0x0902: "N" -0x0903: "H" -0x0904: "[?]" -0x0905: "a" -0x0906: "aa" -0x0907: "i" -0x0908: "ii" -0x0909: "u" -0x090a: "uu" -0x090b: "R" -0x090c: "L" -0x090d: "eN" -0x090e: "e" -0x090f: "e" -0x0910: "ai" -0x0911: "oN" -0x0912: "o" -0x0913: "o" -0x0914: "au" -0x0915: "k" -0x0916: "kh" -0x0917: "g" -0x0918: "gh" -0x0919: "ng" -0x091a: "c" -0x091b: "ch" -0x091c: "j" -0x091d: "jh" -0x091e: "ny" -0x091f: "tt" -0x0920: "tth" -0x0921: "dd" -0x0922: "ddh" -0x0923: "nn" -0x0924: "t" -0x0925: "th" -0x0926: "d" -0x0927: "dh" -0x0928: "n" -0x0929: "nnn" -0x092a: "p" -0x092b: "ph" -0x092c: "b" -0x092d: "bh" -0x092e: "m" -0x092f: "y" -0x0930: "r" -0x0931: "rr" -0x0932: "l" -0x0933: "l" -0x0934: "lll" -0x0935: "v" -0x0936: "sh" -0x0937: "ss" -0x0938: "s" -0x0939: "h" -0x093a: "[?]" -0x093b: "[?]" -0x093c: "'" -0x093d: "'" -0x093e: "aa" -0x093f: "i" -0x0940: "ii" -0x0941: "u" -0x0942: "uu" -0x0943: "R" -0x0944: "RR" -0x0945: "eN" -0x0946: "e" -0x0947: "e" -0x0948: "ai" -0x0949: "oN" -0x094a: "o" -0x094b: "o" -0x094c: "au" -0x094d: "" -0x094e: "[?]" -0x094f: "[?]" -0x0950: "AUM" -0x0951: "'" -0x0952: "'" -0x0953: "`" -0x0954: "'" -0x0955: "[?]" -0x0956: "[?]" -0x0957: "[?]" -0x0958: "q" -0x0959: "khh" -0x095a: "ghh" -0x095b: "z" -0x095c: "dddh" -0x095d: "rh" -0x095e: "f" -0x095f: "yy" -0x0960: "RR" -0x0961: "LL" -0x0962: "L" -0x0963: "LL" -0x0964: " / " -0x0965: " // " -0x0966: "0" -0x0967: "1" -0x0968: "2" -0x0969: "3" -0x096a: "4" -0x096b: "5" -0x096c: "6" -0x096d: "7" -0x096e: "8" -0x096f: "9" -0x0970: "." -0x0971: "[?]" -0x0972: "[?]" -0x0973: "[?]" -0x0974: "[?]" -0x0975: "[?]" -0x0976: "[?]" -0x0977: "[?]" -0x0978: "[?]" -0x0979: "[?]" -0x097a: "[?]" -0x097b: "[?]" -0x097c: "[?]" -0x097d: "[?]" -0x097e: "[?]" -0x097f: "[?]" -0x0980: "[?]" -0x0981: "N" -0x0982: "N" -0x0983: "H" -0x0984: "[?]" -0x0985: "a" -0x0986: "aa" -0x0987: "i" -0x0988: "ii" -0x0989: "u" -0x098a: "uu" -0x098b: "R" -0x098c: "RR" -0x098d: "[?]" -0x098e: "[?]" -0x098f: "e" -0x0990: "ai" -0x0991: "[?]" -0x0992: "[?]" -0x0993: "o" -0x0994: "au" -0x0995: "k" -0x0996: "kh" -0x0997: "g" -0x0998: "gh" -0x0999: "ng" -0x099a: "c" -0x099b: "ch" -0x099c: "j" -0x099d: "jh" -0x099e: "ny" -0x099f: "tt" -0x09a0: "tth" -0x09a1: "dd" -0x09a2: "ddh" -0x09a3: "nn" -0x09a4: "t" -0x09a5: "th" -0x09a6: "d" -0x09a7: "dh" -0x09a8: "n" -0x09a9: "[?]" -0x09aa: "p" -0x09ab: "ph" -0x09ac: "b" -0x09ad: "bh" -0x09ae: "m" -0x09af: "y" -0x09b0: "r" -0x09b1: "[?]" -0x09b2: "l" -0x09b3: "[?]" -0x09b4: "[?]" -0x09b5: "[?]" -0x09b6: "sh" -0x09b7: "ss" -0x09b8: "s" -0x09b9: "h" -0x09ba: "[?]" -0x09bb: "[?]" -0x09bc: "'" -0x09bd: "[?]" -0x09be: "aa" -0x09bf: "i" -0x09c0: "ii" -0x09c1: "u" -0x09c2: "uu" -0x09c3: "R" -0x09c4: "RR" -0x09c5: "[?]" -0x09c6: "[?]" -0x09c7: "e" -0x09c8: "ai" -0x09c9: "[?]" -0x09ca: "[?]" -0x09cb: "o" -0x09cc: "au" -0x09cd: "" -0x09ce: "[?]" -0x09cf: "[?]" -0x09d0: "[?]" -0x09d1: "[?]" -0x09d2: "[?]" -0x09d3: "[?]" -0x09d4: "[?]" -0x09d5: "[?]" -0x09d6: "[?]" -0x09d7: "+" -0x09d8: "[?]" -0x09d9: "[?]" -0x09da: "[?]" -0x09db: "[?]" -0x09dc: "rr" -0x09dd: "rh" -0x09de: "[?]" -0x09df: "yy" -0x09e0: "RR" -0x09e1: "LL" -0x09e2: "L" -0x09e3: "LL" -0x09e4: "[?]" -0x09e5: "[?]" -0x09e6: "0" -0x09e7: "1" -0x09e8: "2" -0x09e9: "3" -0x09ea: "4" -0x09eb: "5" -0x09ec: "6" -0x09ed: "7" -0x09ee: "8" -0x09ef: "9" -0x09f0: "r'" -0x09f1: "r`" -0x09f2: "Rs" -0x09f3: "Rs" -0x09f4: "1/" -0x09f5: "2/" -0x09f6: "3/" -0x09f7: "4/" -0x09f8: " 1 - 1/" -0x09f9: "/16" -0x09fa: "" -0x09fb: "[?]" -0x09fc: "[?]" -0x09fd: "[?]" -0x09fe: "[?]" -/* x00a */ -0x0a00: "[?]" -0x0a01: "[?]" -0x0a02: "N" -0x0a03: "[?]" -0x0a04: "[?]" -0x0a05: "a" -0x0a06: "aa" -0x0a07: "i" -0x0a08: "ii" -0x0a09: "u" -0x0a0a: "uu" -0x0a0b: "[?]" -0x0a0c: "[?]" -0x0a0d: "[?]" -0x0a0e: "[?]" -0x0a0f: "ee" -0x0a10: "ai" -0x0a11: "[?]" -0x0a12: "[?]" -0x0a13: "oo" -0x0a14: "au" -0x0a15: "k" -0x0a16: "kh" -0x0a17: "g" -0x0a18: "gh" -0x0a19: "ng" -0x0a1a: "c" -0x0a1b: "ch" -0x0a1c: "j" -0x0a1d: "jh" -0x0a1e: "ny" -0x0a1f: "tt" -0x0a20: "tth" -0x0a21: "dd" -0x0a22: "ddh" -0x0a23: "nn" -0x0a24: "t" -0x0a25: "th" -0x0a26: "d" -0x0a27: "dh" -0x0a28: "n" -0x0a29: "[?]" -0x0a2a: "p" -0x0a2b: "ph" -0x0a2c: "b" -0x0a2d: "bb" -0x0a2e: "m" -0x0a2f: "y" -0x0a30: "r" -0x0a31: "[?]" -0x0a32: "l" -0x0a33: "ll" -0x0a34: "[?]" -0x0a35: "v" -0x0a36: "sh" -0x0a37: "[?]" -0x0a38: "s" -0x0a39: "h" -0x0a3a: "[?]" -0x0a3b: "[?]" -0x0a3c: "'" -0x0a3d: "[?]" -0x0a3e: "aa" -0x0a3f: "i" -0x0a40: "ii" -0x0a41: "u" -0x0a42: "uu" -0x0a43: "[?]" -0x0a44: "[?]" -0x0a45: "[?]" -0x0a46: "[?]" -0x0a47: "ee" -0x0a48: "ai" -0x0a49: "[?]" -0x0a4a: "[?]" -0x0a4b: "oo" -0x0a4c: "au" -0x0a4d: "" -0x0a4e: "[?]" -0x0a4f: "[?]" -0x0a50: "[?]" -0x0a51: "[?]" -0x0a52: "[?]" -0x0a53: "[?]" -0x0a54: "[?]" -0x0a55: "[?]" -0x0a56: "[?]" -0x0a57: "[?]" -0x0a58: "[?]" -0x0a59: "khh" -0x0a5a: "ghh" -0x0a5b: "z" -0x0a5c: "rr" -0x0a5d: "[?]" -0x0a5e: "f" -0x0a5f: "[?]" -0x0a60: "[?]" -0x0a61: "[?]" -0x0a62: "[?]" -0x0a63: "[?]" -0x0a64: "[?]" -0x0a65: "[?]" -0x0a66: "0" -0x0a67: "1" -0x0a68: "2" -0x0a69: "3" -0x0a6a: "4" -0x0a6b: "5" -0x0a6c: "6" -0x0a6d: "7" -0x0a6e: "8" -0x0a6f: "9" -0x0a70: "N" -0x0a71: "H" -0x0a72: "" -0x0a73: "" -0x0a74: "G.E.O." -0x0a75: "[?]" -0x0a76: "[?]" -0x0a77: "[?]" -0x0a78: "[?]" -0x0a79: "[?]" -0x0a7a: "[?]" -0x0a7b: "[?]" -0x0a7c: "[?]" -0x0a7d: "[?]" -0x0a7e: "[?]" -0x0a7f: "[?]" -0x0a80: "[?]" -0x0a81: "N" -0x0a82: "N" -0x0a83: "H" -0x0a84: "[?]" -0x0a85: "a" -0x0a86: "aa" -0x0a87: "i" -0x0a88: "ii" -0x0a89: "u" -0x0a8a: "uu" -0x0a8b: "R" -0x0a8c: "[?]" -0x0a8d: "eN" -0x0a8e: "[?]" -0x0a8f: "e" -0x0a90: "ai" -0x0a91: "oN" -0x0a92: "[?]" -0x0a93: "o" -0x0a94: "au" -0x0a95: "k" -0x0a96: "kh" -0x0a97: "g" -0x0a98: "gh" -0x0a99: "ng" -0x0a9a: "c" -0x0a9b: "ch" -0x0a9c: "j" -0x0a9d: "jh" -0x0a9e: "ny" -0x0a9f: "tt" -0x0aa0: "tth" -0x0aa1: "dd" -0x0aa2: "ddh" -0x0aa3: "nn" -0x0aa4: "t" -0x0aa5: "th" -0x0aa6: "d" -0x0aa7: "dh" -0x0aa8: "n" -0x0aa9: "[?]" -0x0aaa: "p" -0x0aab: "ph" -0x0aac: "b" -0x0aad: "bh" -0x0aae: "m" -0x0aaf: "ya" -0x0ab0: "r" -0x0ab1: "[?]" -0x0ab2: "l" -0x0ab3: "ll" -0x0ab4: "[?]" -0x0ab5: "v" -0x0ab6: "sh" -0x0ab7: "ss" -0x0ab8: "s" -0x0ab9: "h" -0x0aba: "[?]" -0x0abb: "[?]" -0x0abc: "'" -0x0abd: "'" -0x0abe: "aa" -0x0abf: "i" -0x0ac0: "ii" -0x0ac1: "u" -0x0ac2: "uu" -0x0ac3: "R" -0x0ac4: "RR" -0x0ac5: "eN" -0x0ac6: "[?]" -0x0ac7: "e" -0x0ac8: "ai" -0x0ac9: "oN" -0x0aca: "[?]" -0x0acb: "o" -0x0acc: "au" -0x0acd: "" -0x0ace: "[?]" -0x0acf: "[?]" -0x0ad0: "AUM" -0x0ad1: "[?]" -0x0ad2: "[?]" -0x0ad3: "[?]" -0x0ad4: "[?]" -0x0ad5: "[?]" -0x0ad6: "[?]" -0x0ad7: "[?]" -0x0ad8: "[?]" -0x0ad9: "[?]" -0x0ada: "[?]" -0x0adb: "[?]" -0x0adc: "[?]" -0x0add: "[?]" -0x0ade: "[?]" -0x0adf: "[?]" -0x0ae0: "RR" -0x0ae1: "[?]" -0x0ae2: "[?]" -0x0ae3: "[?]" -0x0ae4: "[?]" -0x0ae5: "[?]" -0x0ae6: "0" -0x0ae7: "1" -0x0ae8: "2" -0x0ae9: "3" -0x0aea: "4" -0x0aeb: "5" -0x0aec: "6" -0x0aed: "7" -0x0aee: "8" -0x0aef: "9" -0x0af0: "[?]" -0x0af1: "[?]" -0x0af2: "[?]" -0x0af3: "[?]" -0x0af4: "[?]" -0x0af5: "[?]" -0x0af6: "[?]" -0x0af7: "[?]" -0x0af8: "[?]" -0x0af9: "[?]" -0x0afa: "[?]" -0x0afb: "[?]" -0x0afc: "[?]" -0x0afd: "[?]" -0x0afe: "[?]" -/* x00b */ -0x0b00: "[?]" -0x0b01: "N" -0x0b02: "N" -0x0b03: "H" -0x0b04: "[?]" -0x0b05: "a" -0x0b06: "aa" -0x0b07: "i" -0x0b08: "ii" -0x0b09: "u" -0x0b0a: "uu" -0x0b0b: "R" -0x0b0c: "L" -0x0b0d: "[?]" -0x0b0e: "[?]" -0x0b0f: "e" -0x0b10: "ai" -0x0b11: "[?]" -0x0b12: "[?]" -0x0b13: "o" -0x0b14: "au" -0x0b15: "k" -0x0b16: "kh" -0x0b17: "g" -0x0b18: "gh" -0x0b19: "ng" -0x0b1a: "c" -0x0b1b: "ch" -0x0b1c: "j" -0x0b1d: "jh" -0x0b1e: "ny" -0x0b1f: "tt" -0x0b20: "tth" -0x0b21: "dd" -0x0b22: "ddh" -0x0b23: "nn" -0x0b24: "t" -0x0b25: "th" -0x0b26: "d" -0x0b27: "dh" -0x0b28: "n" -0x0b29: "[?]" -0x0b2a: "p" -0x0b2b: "ph" -0x0b2c: "b" -0x0b2d: "bh" -0x0b2e: "m" -0x0b2f: "y" -0x0b30: "r" -0x0b31: "[?]" -0x0b32: "l" -0x0b33: "ll" -0x0b34: "[?]" -0x0b35: "" -0x0b36: "sh" -0x0b37: "ss" -0x0b38: "s" -0x0b39: "h" -0x0b3a: "[?]" -0x0b3b: "[?]" -0x0b3c: "'" -0x0b3d: "'" -0x0b3e: "aa" -0x0b3f: "i" -0x0b40: "ii" -0x0b41: "u" -0x0b42: "uu" -0x0b43: "R" -0x0b44: "[?]" -0x0b45: "[?]" -0x0b46: "[?]" -0x0b47: "e" -0x0b48: "ai" -0x0b49: "[?]" -0x0b4a: "[?]" -0x0b4b: "o" -0x0b4c: "au" -0x0b4d: "" -0x0b4e: "[?]" -0x0b4f: "[?]" -0x0b50: "[?]" -0x0b51: "[?]" -0x0b52: "[?]" -0x0b53: "[?]" -0x0b54: "[?]" -0x0b55: "[?]" -0x0b56: "+" -0x0b57: "+" -0x0b58: "[?]" -0x0b59: "[?]" -0x0b5a: "[?]" -0x0b5b: "[?]" -0x0b5c: "rr" -0x0b5d: "rh" -0x0b5e: "[?]" -0x0b5f: "yy" -0x0b60: "RR" -0x0b61: "LL" -0x0b62: "[?]" -0x0b63: "[?]" -0x0b64: "[?]" -0x0b65: "[?]" -0x0b66: "0" -0x0b67: "1" -0x0b68: "2" -0x0b69: "3" -0x0b6a: "4" -0x0b6b: "5" -0x0b6c: "6" -0x0b6d: "7" -0x0b6e: "8" -0x0b6f: "9" -0x0b70: "" -0x0b71: "[?]" -0x0b72: "[?]" -0x0b73: "[?]" -0x0b74: "[?]" -0x0b75: "[?]" -0x0b76: "[?]" -0x0b77: "[?]" -0x0b78: "[?]" -0x0b79: "[?]" -0x0b7a: "[?]" -0x0b7b: "[?]" -0x0b7c: "[?]" -0x0b7d: "[?]" -0x0b7e: "[?]" -0x0b7f: "[?]" -0x0b80: "[?]" -0x0b81: "[?]" -0x0b82: "N" -0x0b83: "H" -0x0b84: "[?]" -0x0b85: "a" -0x0b86: "aa" -0x0b87: "i" -0x0b88: "ii" -0x0b89: "u" -0x0b8a: "uu" -0x0b8b: "[?]" -0x0b8c: "[?]" -0x0b8d: "[?]" -0x0b8e: "e" -0x0b8f: "ee" -0x0b90: "ai" -0x0b91: "[?]" -0x0b92: "o" -0x0b93: "oo" -0x0b94: "au" -0x0b95: "k" -0x0b96: "[?]" -0x0b97: "[?]" -0x0b98: "[?]" -0x0b99: "ng" -0x0b9a: "c" -0x0b9b: "[?]" -0x0b9c: "j" -0x0b9d: "[?]" -0x0b9e: "ny" -0x0b9f: "tt" -0x0ba0: "[?]" -0x0ba1: "[?]" -0x0ba2: "[?]" -0x0ba3: "nn" -0x0ba4: "t" -0x0ba5: "[?]" -0x0ba6: "[?]" -0x0ba7: "[?]" -0x0ba8: "n" -0x0ba9: "nnn" -0x0baa: "p" -0x0bab: "[?]" -0x0bac: "[?]" -0x0bad: "[?]" -0x0bae: "m" -0x0baf: "y" -0x0bb0: "r" -0x0bb1: "rr" -0x0bb2: "l" -0x0bb3: "ll" -0x0bb4: "lll" -0x0bb5: "v" -0x0bb6: "[?]" -0x0bb7: "ss" -0x0bb8: "s" -0x0bb9: "h" -0x0bba: "[?]" -0x0bbb: "[?]" -0x0bbc: "[?]" -0x0bbd: "[?]" -0x0bbe: "aa" -0x0bbf: "i" -0x0bc0: "ii" -0x0bc1: "u" -0x0bc2: "uu" -0x0bc3: "[?]" -0x0bc4: "[?]" -0x0bc5: "[?]" -0x0bc6: "e" -0x0bc7: "ee" -0x0bc8: "ai" -0x0bc9: "[?]" -0x0bca: "o" -0x0bcb: "oo" -0x0bcc: "au" -0x0bcd: "" -0x0bce: "[?]" -0x0bcf: "[?]" -0x0bd0: "[?]" -0x0bd1: "[?]" -0x0bd2: "[?]" -0x0bd3: "[?]" -0x0bd4: "[?]" -0x0bd5: "[?]" -0x0bd6: "[?]" -0x0bd7: "+" -0x0bd8: "[?]" -0x0bd9: "[?]" -0x0bda: "[?]" -0x0bdb: "[?]" -0x0bdc: "[?]" -0x0bdd: "[?]" -0x0bde: "[?]" -0x0bdf: "[?]" -0x0be0: "[?]" -0x0be1: "[?]" -0x0be2: "[?]" -0x0be3: "[?]" -0x0be4: "[?]" -0x0be5: "[?]" -0x0be6: "0" -0x0be7: "1" -0x0be8: "2" -0x0be9: "3" -0x0bea: "4" -0x0beb: "5" -0x0bec: "6" -0x0bed: "7" -0x0bee: "8" -0x0bef: "9" -0x0bf0: "+10+" -0x0bf1: "+100+" -0x0bf2: "+1000+" -0x0bf3: "[?]" -0x0bf4: "[?]" -0x0bf5: "[?]" -0x0bf6: "[?]" -0x0bf7: "[?]" -0x0bf8: "[?]" -0x0bf9: "[?]" -0x0bfa: "[?]" -0x0bfb: "[?]" -0x0bfc: "[?]" -0x0bfd: "[?]" -0x0bfe: "[?]" -/* x00c */ -0x0c00: "[?]" -0x0c01: "N" -0x0c02: "N" -0x0c03: "H" -0x0c04: "[?]" -0x0c05: "a" -0x0c06: "aa" -0x0c07: "i" -0x0c08: "ii" -0x0c09: "u" -0x0c0a: "uu" -0x0c0b: "R" -0x0c0c: "L" -0x0c0d: "[?]" -0x0c0e: "e" -0x0c0f: "ee" -0x0c10: "ai" -0x0c11: "[?]" -0x0c12: "o" -0x0c13: "oo" -0x0c14: "au" -0x0c15: "k" -0x0c16: "kh" -0x0c17: "g" -0x0c18: "gh" -0x0c19: "ng" -0x0c1a: "c" -0x0c1b: "ch" -0x0c1c: "j" -0x0c1d: "jh" -0x0c1e: "ny" -0x0c1f: "tt" -0x0c20: "tth" -0x0c21: "dd" -0x0c22: "ddh" -0x0c23: "nn" -0x0c24: "t" -0x0c25: "th" -0x0c26: "d" -0x0c27: "dh" -0x0c28: "n" -0x0c29: "[?]" -0x0c2a: "p" -0x0c2b: "ph" -0x0c2c: "b" -0x0c2d: "bh" -0x0c2e: "m" -0x0c2f: "y" -0x0c30: "r" -0x0c31: "rr" -0x0c32: "l" -0x0c33: "ll" -0x0c34: "[?]" -0x0c35: "v" -0x0c36: "sh" -0x0c37: "ss" -0x0c38: "s" -0x0c39: "h" -0x0c3a: "[?]" -0x0c3b: "[?]" -0x0c3c: "[?]" -0x0c3d: "[?]" -0x0c3e: "aa" -0x0c3f: "i" -0x0c40: "ii" -0x0c41: "u" -0x0c42: "uu" -0x0c43: "R" -0x0c44: "RR" -0x0c45: "[?]" -0x0c46: "e" -0x0c47: "ee" -0x0c48: "ai" -0x0c49: "[?]" -0x0c4a: "o" -0x0c4b: "oo" -0x0c4c: "au" -0x0c4d: "" -0x0c4e: "[?]" -0x0c4f: "[?]" -0x0c50: "[?]" -0x0c51: "[?]" -0x0c52: "[?]" -0x0c53: "[?]" -0x0c54: "[?]" -0x0c55: "+" -0x0c56: "+" -0x0c57: "[?]" -0x0c58: "[?]" -0x0c59: "[?]" -0x0c5a: "[?]" -0x0c5b: "[?]" -0x0c5c: "[?]" -0x0c5d: "[?]" -0x0c5e: "[?]" -0x0c5f: "[?]" -0x0c60: "RR" -0x0c61: "LL" -0x0c62: "[?]" -0x0c63: "[?]" -0x0c64: "[?]" -0x0c65: "[?]" -0x0c66: "0" -0x0c67: "1" -0x0c68: "2" -0x0c69: "3" -0x0c6a: "4" -0x0c6b: "5" -0x0c6c: "6" -0x0c6d: "7" -0x0c6e: "8" -0x0c6f: "9" -0x0c70: "[?]" -0x0c71: "[?]" -0x0c72: "[?]" -0x0c73: "[?]" -0x0c74: "[?]" -0x0c75: "[?]" -0x0c76: "[?]" -0x0c77: "[?]" -0x0c78: "[?]" -0x0c79: "[?]" -0x0c7a: "[?]" -0x0c7b: "[?]" -0x0c7c: "[?]" -0x0c7d: "[?]" -0x0c7e: "[?]" -0x0c7f: "[?]" -0x0c80: "[?]" -0x0c81: "[?]" -0x0c82: "N" -0x0c83: "H" -0x0c84: "[?]" -0x0c85: "a" -0x0c86: "aa" -0x0c87: "i" -0x0c88: "ii" -0x0c89: "u" -0x0c8a: "uu" -0x0c8b: "R" -0x0c8c: "L" -0x0c8d: "[?]" -0x0c8e: "e" -0x0c8f: "ee" -0x0c90: "ai" -0x0c91: "[?]" -0x0c92: "o" -0x0c93: "oo" -0x0c94: "au" -0x0c95: "k" -0x0c96: "kh" -0x0c97: "g" -0x0c98: "gh" -0x0c99: "ng" -0x0c9a: "c" -0x0c9b: "ch" -0x0c9c: "j" -0x0c9d: "jh" -0x0c9e: "ny" -0x0c9f: "tt" -0x0ca0: "tth" -0x0ca1: "dd" -0x0ca2: "ddh" -0x0ca3: "nn" -0x0ca4: "t" -0x0ca5: "th" -0x0ca6: "d" -0x0ca7: "dh" -0x0ca8: "n" -0x0ca9: "[?]" -0x0caa: "p" -0x0cab: "ph" -0x0cac: "b" -0x0cad: "bh" -0x0cae: "m" -0x0caf: "y" -0x0cb0: "r" -0x0cb1: "rr" -0x0cb2: "l" -0x0cb3: "ll" -0x0cb4: "[?]" -0x0cb5: "v" -0x0cb6: "sh" -0x0cb7: "ss" -0x0cb8: "s" -0x0cb9: "h" -0x0cba: "[?]" -0x0cbb: "[?]" -0x0cbc: "[?]" -0x0cbd: "[?]" -0x0cbe: "aa" -0x0cbf: "i" -0x0cc0: "ii" -0x0cc1: "u" -0x0cc2: "uu" -0x0cc3: "R" -0x0cc4: "RR" -0x0cc5: "[?]" -0x0cc6: "e" -0x0cc7: "ee" -0x0cc8: "ai" -0x0cc9: "[?]" -0x0cca: "o" -0x0ccb: "oo" -0x0ccc: "au" -0x0ccd: "" -0x0cce: "[?]" -0x0ccf: "[?]" -0x0cd0: "[?]" -0x0cd1: "[?]" -0x0cd2: "[?]" -0x0cd3: "[?]" -0x0cd4: "[?]" -0x0cd5: "+" -0x0cd6: "+" -0x0cd7: "[?]" -0x0cd8: "[?]" -0x0cd9: "[?]" -0x0cda: "[?]" -0x0cdb: "[?]" -0x0cdc: "[?]" -0x0cdd: "[?]" -0x0cde: "lll" -0x0cdf: "[?]" -0x0ce0: "RR" -0x0ce1: "LL" -0x0ce2: "[?]" -0x0ce3: "[?]" -0x0ce4: "[?]" -0x0ce5: "[?]" -0x0ce6: "0" -0x0ce7: "1" -0x0ce8: "2" -0x0ce9: "3" -0x0cea: "4" -0x0ceb: "5" -0x0cec: "6" -0x0ced: "7" -0x0cee: "8" -0x0cef: "9" -0x0cf0: "[?]" -0x0cf1: "[?]" -0x0cf2: "[?]" -0x0cf3: "[?]" -0x0cf4: "[?]" -0x0cf5: "[?]" -0x0cf6: "[?]" -0x0cf7: "[?]" -0x0cf8: "[?]" -0x0cf9: "[?]" -0x0cfa: "[?]" -0x0cfb: "[?]" -0x0cfc: "[?]" -0x0cfd: "[?]" -0x0cfe: "[?]" -/* x00d */ -0x0d00: "[?]" -0x0d01: "[?]" -0x0d02: "N" -0x0d03: "H" -0x0d04: "[?]" -0x0d05: "a" -0x0d06: "aa" -0x0d07: "i" -0x0d08: "ii" -0x0d09: "u" -0x0d0a: "uu" -0x0d0b: "R" -0x0d0c: "L" -0x0d0d: "[?]" -0x0d0e: "e" -0x0d0f: "ee" -0x0d10: "ai" -0x0d11: "[?]" -0x0d12: "o" -0x0d13: "oo" -0x0d14: "au" -0x0d15: "k" -0x0d16: "kh" -0x0d17: "g" -0x0d18: "gh" -0x0d19: "ng" -0x0d1a: "c" -0x0d1b: "ch" -0x0d1c: "j" -0x0d1d: "jh" -0x0d1e: "ny" -0x0d1f: "tt" -0x0d20: "tth" -0x0d21: "dd" -0x0d22: "ddh" -0x0d23: "nn" -0x0d24: "t" -0x0d25: "th" -0x0d26: "d" -0x0d27: "dh" -0x0d28: "n" -0x0d29: "[?]" -0x0d2a: "p" -0x0d2b: "ph" -0x0d2c: "b" -0x0d2d: "bh" -0x0d2e: "m" -0x0d2f: "y" -0x0d30: "r" -0x0d31: "rr" -0x0d32: "l" -0x0d33: "ll" -0x0d34: "lll" -0x0d35: "v" -0x0d36: "sh" -0x0d37: "ss" -0x0d38: "s" -0x0d39: "h" -0x0d3a: "[?]" -0x0d3b: "[?]" -0x0d3c: "[?]" -0x0d3d: "[?]" -0x0d3e: "aa" -0x0d3f: "i" -0x0d40: "ii" -0x0d41: "u" -0x0d42: "uu" -0x0d43: "R" -0x0d44: "[?]" -0x0d45: "[?]" -0x0d46: "e" -0x0d47: "ee" -0x0d48: "ai" -0x0d49: "" -0x0d4a: "o" -0x0d4b: "oo" -0x0d4c: "au" -0x0d4d: "" -0x0d4e: "[?]" -0x0d4f: "[?]" -0x0d50: "[?]" -0x0d51: "[?]" -0x0d52: "[?]" -0x0d53: "[?]" -0x0d54: "[?]" -0x0d55: "[?]" -0x0d56: "[?]" -0x0d57: "+" -0x0d58: "[?]" -0x0d59: "[?]" -0x0d5a: "[?]" -0x0d5b: "[?]" -0x0d5c: "[?]" -0x0d5d: "[?]" -0x0d5e: "[?]" -0x0d5f: "[?]" -0x0d60: "RR" -0x0d61: "LL" -0x0d62: "[?]" -0x0d63: "[?]" -0x0d64: "[?]" -0x0d65: "[?]" -0x0d66: "0" -0x0d67: "1" -0x0d68: "2" -0x0d69: "3" -0x0d6a: "4" -0x0d6b: "5" -0x0d6c: "6" -0x0d6d: "7" -0x0d6e: "8" -0x0d6f: "9" -0x0d70: "[?]" -0x0d71: "[?]" -0x0d72: "[?]" -0x0d73: "[?]" -0x0d74: "[?]" -0x0d75: "[?]" -0x0d76: "[?]" -0x0d77: "[?]" -0x0d78: "[?]" -0x0d79: "[?]" -0x0d7a: "[?]" -0x0d7b: "[?]" -0x0d7c: "[?]" -0x0d7d: "[?]" -0x0d7e: "[?]" -0x0d7f: "[?]" -0x0d80: "[?]" -0x0d81: "[?]" -0x0d82: "N" -0x0d83: "H" -0x0d84: "[?]" -0x0d85: "a" -0x0d86: "aa" -0x0d87: "ae" -0x0d88: "aae" -0x0d89: "i" -0x0d8a: "ii" -0x0d8b: "u" -0x0d8c: "uu" -0x0d8d: "R" -0x0d8e: "RR" -0x0d8f: "L" -0x0d90: "LL" -0x0d91: "e" -0x0d92: "ee" -0x0d93: "ai" -0x0d94: "o" -0x0d95: "oo" -0x0d96: "au" -0x0d97: "[?]" -0x0d98: "[?]" -0x0d99: "[?]" -0x0d9a: "k" -0x0d9b: "kh" -0x0d9c: "g" -0x0d9d: "gh" -0x0d9e: "ng" -0x0d9f: "nng" -0x0da0: "c" -0x0da1: "ch" -0x0da2: "j" -0x0da3: "jh" -0x0da4: "ny" -0x0da5: "jny" -0x0da6: "nyj" -0x0da7: "tt" -0x0da8: "tth" -0x0da9: "dd" -0x0daa: "ddh" -0x0dab: "nn" -0x0dac: "nndd" -0x0dad: "t" -0x0dae: "th" -0x0daf: "d" -0x0db0: "dh" -0x0db1: "n" -0x0db2: "[?]" -0x0db3: "nd" -0x0db4: "p" -0x0db5: "ph" -0x0db6: "b" -0x0db7: "bh" -0x0db8: "m" -0x0db9: "mb" -0x0dba: "y" -0x0dbb: "r" -0x0dbc: "[?]" -0x0dbd: "l" -0x0dbe: "[?]" -0x0dbf: "[?]" -0x0dc0: "v" -0x0dc1: "sh" -0x0dc2: "ss" -0x0dc3: "s" -0x0dc4: "h" -0x0dc5: "ll" -0x0dc6: "f" -0x0dc7: "[?]" -0x0dc8: "[?]" -0x0dc9: "[?]" -0x0dca: "" -0x0dcb: "[?]" -0x0dcc: "[?]" -0x0dcd: "[?]" -0x0dce: "[?]" -0x0dcf: "aa" -0x0dd0: "ae" -0x0dd1: "aae" -0x0dd2: "i" -0x0dd3: "ii" -0x0dd4: "u" -0x0dd5: "[?]" -0x0dd6: "uu" -0x0dd7: "[?]" -0x0dd8: "R" -0x0dd9: "e" -0x0dda: "ee" -0x0ddb: "ai" -0x0ddc: "o" -0x0ddd: "oo" -0x0dde: "au" -0x0ddf: "L" -0x0de0: "[?]" -0x0de1: "[?]" -0x0de2: "[?]" -0x0de3: "[?]" -0x0de4: "[?]" -0x0de5: "[?]" -0x0de6: "[?]" -0x0de7: "[?]" -0x0de8: "[?]" -0x0de9: "[?]" -0x0dea: "[?]" -0x0deb: "[?]" -0x0dec: "[?]" -0x0ded: "[?]" -0x0dee: "[?]" -0x0def: "[?]" -0x0df0: "[?]" -0x0df1: "[?]" -0x0df2: "RR" -0x0df3: "LL" -0x0df4: " . " -0x0df5: "[?]" -0x0df6: "[?]" -0x0df7: "[?]" -0x0df8: "[?]" -0x0df9: "[?]" -0x0dfa: "[?]" -0x0dfb: "[?]" -0x0dfc: "[?]" -0x0dfd: "[?]" -0x0dfe: "[?]" -/* x00e */ -0x0e00: "[?]" -0x0e01: "k" -0x0e02: "kh" -0x0e03: "kh" -0x0e04: "kh" -0x0e05: "kh" -0x0e06: "kh" -0x0e07: "ng" -0x0e08: "cch" -0x0e09: "ch" -0x0e0a: "ch" -0x0e0b: "ch" -0x0e0c: "ch" -0x0e0d: "y" -0x0e0e: "d" -0x0e0f: "t" -0x0e10: "th" -0x0e11: "th" -0x0e12: "th" -0x0e13: "n" -0x0e14: "d" -0x0e15: "t" -0x0e16: "th" -0x0e17: "th" -0x0e18: "th" -0x0e19: "n" -0x0e1a: "b" -0x0e1b: "p" -0x0e1c: "ph" -0x0e1d: "f" -0x0e1e: "ph" -0x0e1f: "f" -0x0e20: "ph" -0x0e21: "m" -0x0e22: "y" -0x0e23: "r" -0x0e24: "R" -0x0e25: "l" -0x0e26: "L" -0x0e27: "w" -0x0e28: "s" -0x0e29: "s" -0x0e2a: "s" -0x0e2b: "h" -0x0e2c: "l" -0x0e2d: "`" -0x0e2e: "h" -0x0e2f: "~" -0x0e30: "a" -0x0e31: "a" -0x0e32: "aa" -0x0e33: "am" -0x0e34: "i" -0x0e35: "ii" -0x0e36: "ue" -0x0e37: "uue" -0x0e38: "u" -0x0e39: "uu" -0x0e3a: "'" -0x0e3b: "[?]" -0x0e3c: "[?]" -0x0e3d: "[?]" -0x0e3e: "[?]" -0x0e3f: "Bh." -0x0e40: "e" -0x0e41: "ae" -0x0e42: "o" -0x0e43: "ai" -0x0e44: "ai" -0x0e45: "ao" -0x0e46: "+" -0x0e47: "" -0x0e48: "" -0x0e49: "" -0x0e4a: "" -0x0e4b: "" -0x0e4c: "" -0x0e4d: "M" -0x0e4e: "" -0x0e4f: " * " -0x0e50: "0" -0x0e51: "1" -0x0e52: "2" -0x0e53: "3" -0x0e54: "4" -0x0e55: "5" -0x0e56: "6" -0x0e57: "7" -0x0e58: "8" -0x0e59: "9" -0x0e5a: " // " -0x0e5b: " /// " -0x0e5c: "[?]" -0x0e5d: "[?]" -0x0e5e: "[?]" -0x0e5f: "[?]" -0x0e60: "[?]" -0x0e61: "[?]" -0x0e62: "[?]" -0x0e63: "[?]" -0x0e64: "[?]" -0x0e65: "[?]" -0x0e66: "[?]" -0x0e67: "[?]" -0x0e68: "[?]" -0x0e69: "[?]" -0x0e6a: "[?]" -0x0e6b: "[?]" -0x0e6c: "[?]" -0x0e6d: "[?]" -0x0e6e: "[?]" -0x0e6f: "[?]" -0x0e70: "[?]" -0x0e71: "[?]" -0x0e72: "[?]" -0x0e73: "[?]" -0x0e74: "[?]" -0x0e75: "[?]" -0x0e76: "[?]" -0x0e77: "[?]" -0x0e78: "[?]" -0x0e79: "[?]" -0x0e7a: "[?]" -0x0e7b: "[?]" -0x0e7c: "[?]" -0x0e7d: "[?]" -0x0e7e: "[?]" -0x0e7f: "[?]" -0x0e80: "[?]" -0x0e81: "k" -0x0e82: "kh" -0x0e83: "[?]" -0x0e84: "kh" -0x0e85: "[?]" -0x0e86: "[?]" -0x0e87: "ng" -0x0e88: "ch" -0x0e89: "[?]" -0x0e8a: "s" -0x0e8b: "[?]" -0x0e8c: "[?]" -0x0e8d: "ny" -0x0e8e: "[?]" -0x0e8f: "[?]" -0x0e90: "[?]" -0x0e91: "[?]" -0x0e92: "[?]" -0x0e93: "[?]" -0x0e94: "d" -0x0e95: "h" -0x0e96: "th" -0x0e97: "th" -0x0e98: "[?]" -0x0e99: "n" -0x0e9a: "b" -0x0e9b: "p" -0x0e9c: "ph" -0x0e9d: "f" -0x0e9e: "ph" -0x0e9f: "f" -0x0ea0: "[?]" -0x0ea1: "m" -0x0ea2: "y" -0x0ea3: "r" -0x0ea4: "[?]" -0x0ea5: "l" -0x0ea6: "[?]" -0x0ea7: "w" -0x0ea8: "[?]" -0x0ea9: "[?]" -0x0eaa: "s" -0x0eab: "h" -0x0eac: "[?]" -0x0ead: "`" -0x0eae: "" -0x0eaf: "~" -0x0eb0: "a" -0x0eb1: "" -0x0eb2: "aa" -0x0eb3: "am" -0x0eb4: "i" -0x0eb5: "ii" -0x0eb6: "y" -0x0eb7: "yy" -0x0eb8: "u" -0x0eb9: "uu" -0x0eba: "[?]" -0x0ebb: "o" -0x0ebc: "l" -0x0ebd: "ny" -0x0ebe: "[?]" -0x0ebf: "[?]" -0x0ec0: "e" -0x0ec1: "ei" -0x0ec2: "o" -0x0ec3: "ay" -0x0ec4: "ai" -0x0ec5: "[?]" -0x0ec6: "+" -0x0ec7: "[?]" -0x0ec8: "" -0x0ec9: "" -0x0eca: "" -0x0ecb: "" -0x0ecc: "" -0x0ecd: "M" -0x0ece: "[?]" -0x0ecf: "[?]" -0x0ed0: "0" -0x0ed1: "1" -0x0ed2: "2" -0x0ed3: "3" -0x0ed4: "4" -0x0ed5: "5" -0x0ed6: "6" -0x0ed7: "7" -0x0ed8: "8" -0x0ed9: "9" -0x0eda: "[?]" -0x0edb: "[?]" -0x0edc: "hn" -0x0edd: "hm" -0x0ede: "[?]" -0x0edf: "[?]" -0x0ee0: "[?]" -0x0ee1: "[?]" -0x0ee2: "[?]" -0x0ee3: "[?]" -0x0ee4: "[?]" -0x0ee5: "[?]" -0x0ee6: "[?]" -0x0ee7: "[?]" -0x0ee8: "[?]" -0x0ee9: "[?]" -0x0eea: "[?]" -0x0eeb: "[?]" -0x0eec: "[?]" -0x0eed: "[?]" -0x0eee: "[?]" -0x0eef: "[?]" -0x0ef0: "[?]" -0x0ef1: "[?]" -0x0ef2: "[?]" -0x0ef3: "[?]" -0x0ef4: "[?]" -0x0ef5: "[?]" -0x0ef6: "[?]" -0x0ef7: "[?]" -0x0ef8: "[?]" -0x0ef9: "[?]" -0x0efa: "[?]" -0x0efb: "[?]" -0x0efc: "[?]" -0x0efd: "[?]" -0x0efe: "[?]" -/* x00f */ -0x0f00: "AUM" -0x0f01: "" -0x0f02: "" -0x0f03: "" -0x0f04: "" -0x0f05: "" -0x0f06: "" -0x0f07: "" -0x0f08: " // " -0x0f09: " * " -0x0f0a: "" -0x0f0b: "-" -0x0f0c: " / " -0x0f0d: " / " -0x0f0e: " // " -0x0f0f: " -/ " -0x0f10: " +/ " -0x0f11: " X/ " -0x0f12: " /XX/ " -0x0f13: " /X/ " -0x0f14: ", " -0x0f15: "" -0x0f16: "" -0x0f17: "" -0x0f18: "" -0x0f19: "" -0x0f1a: "" -0x0f1b: "" -0x0f1c: "" -0x0f1d: "" -0x0f1e: "" -0x0f1f: "" -0x0f20: "0" -0x0f21: "1" -0x0f22: "2" -0x0f23: "3" -0x0f24: "4" -0x0f25: "5" -0x0f26: "6" -0x0f27: "7" -0x0f28: "8" -0x0f29: "9" -0x0f2a: ".5" -0x0f2b: "1.5" -0x0f2c: "2.5" -0x0f2d: "3.5" -0x0f2e: "4.5" -0x0f2f: "5.5" -0x0f30: "6.5" -0x0f31: "7.5" -0x0f32: "8.5" -0x0f33: "-.5" -0x0f34: "+" -0x0f35: "*" -0x0f36: "^" -0x0f37: "_" -0x0f38: "" -0x0f39: "~" -0x0f3a: "[?]" -0x0f3b: "]" -0x0f3c: "[[" -0x0f3d: "]]" -0x0f3e: "" -0x0f3f: "" -0x0f40: "k" -0x0f41: "kh" -0x0f42: "g" -0x0f43: "gh" -0x0f44: "ng" -0x0f45: "c" -0x0f46: "ch" -0x0f47: "j" -0x0f48: "[?]" -0x0f49: "ny" -0x0f4a: "tt" -0x0f4b: "tth" -0x0f4c: "dd" -0x0f4d: "ddh" -0x0f4e: "nn" -0x0f4f: "t" -0x0f50: "th" -0x0f51: "d" -0x0f52: "dh" -0x0f53: "n" -0x0f54: "p" -0x0f55: "ph" -0x0f56: "b" -0x0f57: "bh" -0x0f58: "m" -0x0f59: "ts" -0x0f5a: "tsh" -0x0f5b: "dz" -0x0f5c: "dzh" -0x0f5d: "w" -0x0f5e: "zh" -0x0f5f: "z" -0x0f60: "'" -0x0f61: "y" -0x0f62: "r" -0x0f63: "l" -0x0f64: "sh" -0x0f65: "ssh" -0x0f66: "s" -0x0f67: "h" -0x0f68: "a" -0x0f69: "kss" -0x0f6a: "r" -0x0f6b: "[?]" -0x0f6c: "[?]" -0x0f6d: "[?]" -0x0f6e: "[?]" -0x0f6f: "[?]" -0x0f70: "[?]" -0x0f71: "aa" -0x0f72: "i" -0x0f73: "ii" -0x0f74: "u" -0x0f75: "uu" -0x0f76: "R" -0x0f77: "RR" -0x0f78: "L" -0x0f79: "LL" -0x0f7a: "e" -0x0f7b: "ee" -0x0f7c: "o" -0x0f7d: "oo" -0x0f7e: "M" -0x0f7f: "H" -0x0f80: "i" -0x0f81: "ii" -0x0f82: "" -0x0f83: "" -0x0f84: "" -0x0f85: "" -0x0f86: "" -0x0f87: "" -0x0f88: "" -0x0f89: "" -0x0f8a: "" -0x0f8b: "" -0x0f8c: "[?]" -0x0f8d: "[?]" -0x0f8e: "[?]" -0x0f8f: "[?]" -0x0f90: "k" -0x0f91: "kh" -0x0f92: "g" -0x0f93: "gh" -0x0f94: "ng" -0x0f95: "c" -0x0f96: "ch" -0x0f97: "j" -0x0f98: "[?]" -0x0f99: "ny" -0x0f9a: "tt" -0x0f9b: "tth" -0x0f9c: "dd" -0x0f9d: "ddh" -0x0f9e: "nn" -0x0f9f: "t" -0x0fa0: "th" -0x0fa1: "d" -0x0fa2: "dh" -0x0fa3: "n" -0x0fa4: "p" -0x0fa5: "ph" -0x0fa6: "b" -0x0fa7: "bh" -0x0fa8: "m" -0x0fa9: "ts" -0x0faa: "tsh" -0x0fab: "dz" -0x0fac: "dzh" -0x0fad: "w" -0x0fae: "zh" -0x0faf: "z" -0x0fb0: "'" -0x0fb1: "y" -0x0fb2: "r" -0x0fb3: "l" -0x0fb4: "sh" -0x0fb5: "ss" -0x0fb6: "s" -0x0fb7: "h" -0x0fb8: "a" -0x0fb9: "kss" -0x0fba: "w" -0x0fbb: "y" -0x0fbc: "r" -0x0fbd: "[?]" -0x0fbe: "X" -0x0fbf: " :X: " -0x0fc0: " /O/ " -0x0fc1: " /o/ " -0x0fc2: " \\o\\ " -0x0fc3: " (O) " -0x0fc4: "" -0x0fc5: "" -0x0fc6: "" -0x0fc7: "" -0x0fc8: "" -0x0fc9: "" -0x0fca: "" -0x0fcb: "" -0x0fcc: "" -0x0fcd: "[?]" -0x0fce: "[?]" -0x0fcf: "" -0x0fd0: "[?]" -0x0fd1: "[?]" -0x0fd2: "[?]" -0x0fd3: "[?]" -0x0fd4: "[?]" -0x0fd5: "[?]" -0x0fd6: "[?]" -0x0fd7: "[?]" -0x0fd8: "[?]" -0x0fd9: "[?]" -0x0fda: "[?]" -0x0fdb: "[?]" -0x0fdc: "[?]" -0x0fdd: "[?]" -0x0fde: "[?]" -0x0fdf: "[?]" -0x0fe0: "[?]" -0x0fe1: "[?]" -0x0fe2: "[?]" -0x0fe3: "[?]" -0x0fe4: "[?]" -0x0fe5: "[?]" -0x0fe6: "[?]" -0x0fe7: "[?]" -0x0fe8: "[?]" -0x0fe9: "[?]" -0x0fea: "[?]" -0x0feb: "[?]" -0x0fec: "[?]" -0x0fed: "[?]" -0x0fee: "[?]" -0x0fef: "[?]" -0x0ff0: "[?]" -0x0ff1: "[?]" -0x0ff2: "[?]" -0x0ff3: "[?]" -0x0ff4: "[?]" -0x0ff5: "[?]" -0x0ff6: "[?]" -0x0ff7: "[?]" -0x0ff8: "[?]" -0x0ff9: "[?]" -0x0ffa: "[?]" -0x0ffb: "[?]" -0x0ffc: "[?]" -0x0ffd: "[?]" -0x0ffe: "[?]" -/* x010 */ -0x1000: "k" -0x1001: "kh" -0x1002: "g" -0x1003: "gh" -0x1004: "ng" -0x1005: "c" -0x1006: "ch" -0x1007: "j" -0x1008: "jh" -0x1009: "ny" -0x100a: "nny" -0x100b: "tt" -0x100c: "tth" -0x100d: "dd" -0x100e: "ddh" -0x100f: "nn" -0x1010: "tt" -0x1011: "th" -0x1012: "d" -0x1013: "dh" -0x1014: "n" -0x1015: "p" -0x1016: "ph" -0x1017: "b" -0x1018: "bh" -0x1019: "m" -0x101a: "y" -0x101b: "r" -0x101c: "l" -0x101d: "w" -0x101e: "s" -0x101f: "h" -0x1020: "ll" -0x1021: "a" -0x1022: "[?]" -0x1023: "i" -0x1024: "ii" -0x1025: "u" -0x1026: "uu" -0x1027: "e" -0x1028: "[?]" -0x1029: "o" -0x102a: "au" -0x102b: "[?]" -0x102c: "aa" -0x102d: "i" -0x102e: "ii" -0x102f: "u" -0x1030: "uu" -0x1031: "e" -0x1032: "ai" -0x1033: "[?]" -0x1034: "[?]" -0x1035: "[?]" -0x1036: "N" -0x1037: "'" -0x1038: ":" -0x1039: "" -0x103a: "[?]" -0x103b: "[?]" -0x103c: "[?]" -0x103d: "[?]" -0x103e: "[?]" -0x103f: "[?]" -0x1040: "0" -0x1041: "1" -0x1042: "2" -0x1043: "3" -0x1044: "4" -0x1045: "5" -0x1046: "6" -0x1047: "7" -0x1048: "8" -0x1049: "9" -0x104a: " / " -0x104b: " // " -0x104c: "n*" -0x104d: "r*" -0x104e: "l*" -0x104f: "e*" -0x1050: "sh" -0x1051: "ss" -0x1052: "R" -0x1053: "RR" -0x1054: "L" -0x1055: "LL" -0x1056: "R" -0x1057: "RR" -0x1058: "L" -0x1059: "LL" -0x105a: "[?]" -0x105b: "[?]" -0x105c: "[?]" -0x105d: "[?]" -0x105e: "[?]" -0x105f: "[?]" -0x1060: "[?]" -0x1061: "[?]" -0x1062: "[?]" -0x1063: "[?]" -0x1064: "[?]" -0x1065: "[?]" -0x1066: "[?]" -0x1067: "[?]" -0x1068: "[?]" -0x1069: "[?]" -0x106a: "[?]" -0x106b: "[?]" -0x106c: "[?]" -0x106d: "[?]" -0x106e: "[?]" -0x106f: "[?]" -0x1070: "[?]" -0x1071: "[?]" -0x1072: "[?]" -0x1073: "[?]" -0x1074: "[?]" -0x1075: "[?]" -0x1076: "[?]" -0x1077: "[?]" -0x1078: "[?]" -0x1079: "[?]" -0x107a: "[?]" -0x107b: "[?]" -0x107c: "[?]" -0x107d: "[?]" -0x107e: "[?]" -0x107f: "[?]" -0x1080: "[?]" -0x1081: "[?]" -0x1082: "[?]" -0x1083: "[?]" -0x1084: "[?]" -0x1085: "[?]" -0x1086: "[?]" -0x1087: "[?]" -0x1088: "[?]" -0x1089: "[?]" -0x108a: "[?]" -0x108b: "[?]" -0x108c: "[?]" -0x108d: "[?]" -0x108e: "[?]" -0x108f: "[?]" -0x1090: "[?]" -0x1091: "[?]" -0x1092: "[?]" -0x1093: "[?]" -0x1094: "[?]" -0x1095: "[?]" -0x1096: "[?]" -0x1097: "[?]" -0x1098: "[?]" -0x1099: "[?]" -0x109a: "[?]" -0x109b: "[?]" -0x109c: "[?]" -0x109d: "[?]" -0x109e: "[?]" -0x109f: "[?]" -0x10a0: "A" -0x10a1: "B" -0x10a2: "G" -0x10a3: "D" -0x10a4: "E" -0x10a5: "V" -0x10a6: "Z" -0x10a7: "T`" -0x10a8: "I" -0x10a9: "K" -0x10aa: "L" -0x10ab: "M" -0x10ac: "N" -0x10ad: "O" -0x10ae: "P" -0x10af: "Zh" -0x10b0: "R" -0x10b1: "S" -0x10b2: "T" -0x10b3: "U" -0x10b4: "P`" -0x10b5: "K`" -0x10b6: "G'" -0x10b7: "Q" -0x10b8: "Sh" -0x10b9: "Ch`" -0x10ba: "C`" -0x10bb: "Z'" -0x10bc: "C" -0x10bd: "Ch" -0x10be: "X" -0x10bf: "J" -0x10c0: "H" -0x10c1: "E" -0x10c2: "Y" -0x10c3: "W" -0x10c4: "Xh" -0x10c5: "OE" -0x10c6: "[?]" -0x10c7: "[?]" -0x10c8: "[?]" -0x10c9: "[?]" -0x10ca: "[?]" -0x10cb: "[?]" -0x10cc: "[?]" -0x10cd: "[?]" -0x10ce: "[?]" -0x10cf: "[?]" -0x10d0: "a" -0x10d1: "b" -0x10d2: "g" -0x10d3: "d" -0x10d4: "e" -0x10d5: "v" -0x10d6: "z" -0x10d7: "t`" -0x10d8: "i" -0x10d9: "k" -0x10da: "l" -0x10db: "m" -0x10dc: "n" -0x10dd: "o" -0x10de: "p" -0x10df: "zh" -0x10e0: "r" -0x10e1: "s" -0x10e2: "t" -0x10e3: "u" -0x10e4: "p`" -0x10e5: "k`" -0x10e6: "g'" -0x10e7: "q" -0x10e8: "sh" -0x10e9: "ch`" -0x10ea: "c`" -0x10eb: "z'" -0x10ec: "c" -0x10ed: "ch" -0x10ee: "x" -0x10ef: "j" -0x10f0: "h" -0x10f1: "e" -0x10f2: "y" -0x10f3: "w" -0x10f4: "xh" -0x10f5: "oe" -0x10f6: "f" -0x10f7: "[?]" -0x10f8: "[?]" -0x10f9: "[?]" -0x10fa: "[?]" -0x10fb: " // " -0x10fc: "[?]" -0x10fd: "[?]" -0x10fe: "[?]" -/* x011 */ -0x1100: "g" -0x1101: "gg" -0x1102: "n" -0x1103: "d" -0x1104: "dd" -0x1105: "r" -0x1106: "m" -0x1107: "b" -0x1108: "bb" -0x1109: "s" -0x110a: "ss" -0x110b: "" -0x110c: "j" -0x110d: "jj" -0x110e: "c" -0x110f: "k" -0x1110: "t" -0x1111: "p" -0x1112: "h" -0x1113: "ng" -0x1114: "nn" -0x1115: "nd" -0x1116: "nb" -0x1117: "dg" -0x1118: "rn" -0x1119: "rr" -0x111a: "rh" -0x111b: "rN" -0x111c: "mb" -0x111d: "mN" -0x111e: "bg" -0x111f: "bn" -0x1120: "" -0x1121: "bs" -0x1122: "bsg" -0x1123: "bst" -0x1124: "bsb" -0x1125: "bss" -0x1126: "bsj" -0x1127: "bj" -0x1128: "bc" -0x1129: "bt" -0x112a: "bp" -0x112b: "bN" -0x112c: "bbN" -0x112d: "sg" -0x112e: "sn" -0x112f: "sd" -0x1130: "sr" -0x1131: "sm" -0x1132: "sb" -0x1133: "sbg" -0x1134: "sss" -0x1135: "s" -0x1136: "sj" -0x1137: "sc" -0x1138: "sk" -0x1139: "st" -0x113a: "sp" -0x113b: "sh" -0x113c: "" -0x113d: "" -0x113e: "" -0x113f: "" -0x1140: "Z" -0x1141: "g" -0x1142: "d" -0x1143: "m" -0x1144: "b" -0x1145: "s" -0x1146: "Z" -0x1147: "" -0x1148: "j" -0x1149: "c" -0x114a: "t" -0x114b: "p" -0x114c: "N" -0x114d: "j" -0x114e: "" -0x114f: "" -0x1150: "" -0x1151: "" -0x1152: "ck" -0x1153: "ch" -0x1154: "" -0x1155: "" -0x1156: "pb" -0x1157: "pN" -0x1158: "hh" -0x1159: "Q" -0x115a: "[?]" -0x115b: "[?]" -0x115c: "[?]" -0x115d: "[?]" -0x115e: "[?]" -0x115f: "" -0x1160: "" -0x1161: "a" -0x1162: "ae" -0x1163: "ya" -0x1164: "yae" -0x1165: "eo" -0x1166: "e" -0x1167: "yeo" -0x1168: "ye" -0x1169: "o" -0x116a: "wa" -0x116b: "wae" -0x116c: "oe" -0x116d: "yo" -0x116e: "u" -0x116f: "weo" -0x1170: "we" -0x1171: "wi" -0x1172: "yu" -0x1173: "eu" -0x1174: "yi" -0x1175: "i" -0x1176: "a-o" -0x1177: "a-u" -0x1178: "ya-o" -0x1179: "ya-yo" -0x117a: "eo-o" -0x117b: "eo-u" -0x117c: "eo-eu" -0x117d: "yeo-o" -0x117e: "yeo-u" -0x117f: "o-eo" -0x1180: "o-e" -0x1181: "o-ye" -0x1182: "o-o" -0x1183: "o-u" -0x1184: "yo-ya" -0x1185: "yo-yae" -0x1186: "yo-yeo" -0x1187: "yo-o" -0x1188: "yo-i" -0x1189: "u-a" -0x118a: "u-ae" -0x118b: "u-eo-eu" -0x118c: "u-ye" -0x118d: "u-u" -0x118e: "yu-a" -0x118f: "yu-eo" -0x1190: "yu-e" -0x1191: "yu-yeo" -0x1192: "yu-ye" -0x1193: "yu-u" -0x1194: "yu-i" -0x1195: "eu-u" -0x1196: "eu-eu" -0x1197: "yi-u" -0x1198: "i-a" -0x1199: "i-ya" -0x119a: "i-o" -0x119b: "i-u" -0x119c: "i-eu" -0x119d: "i-U" -0x119e: "U" -0x119f: "U-eo" -0x11a0: "U-u" -0x11a1: "U-i" -0x11a2: "UU" -0x11a3: "[?]" -0x11a4: "[?]" -0x11a5: "[?]" -0x11a6: "[?]" -0x11a7: "[?]" -0x11a8: "g" -0x11a9: "gg" -0x11aa: "gs" -0x11ab: "n" -0x11ac: "nj" -0x11ad: "nh" -0x11ae: "d" -0x11af: "l" -0x11b0: "lg" -0x11b1: "lm" -0x11b2: "lb" -0x11b3: "ls" -0x11b4: "lt" -0x11b5: "lp" -0x11b6: "lh" -0x11b7: "m" -0x11b8: "b" -0x11b9: "bs" -0x11ba: "s" -0x11bb: "ss" -0x11bc: "ng" -0x11bd: "j" -0x11be: "c" -0x11bf: "k" -0x11c0: "t" -0x11c1: "p" -0x11c2: "h" -0x11c3: "gl" -0x11c4: "gsg" -0x11c5: "ng" -0x11c6: "nd" -0x11c7: "ns" -0x11c8: "nZ" -0x11c9: "nt" -0x11ca: "dg" -0x11cb: "tl" -0x11cc: "lgs" -0x11cd: "ln" -0x11ce: "ld" -0x11cf: "lth" -0x11d0: "ll" -0x11d1: "lmg" -0x11d2: "lms" -0x11d3: "lbs" -0x11d4: "lbh" -0x11d5: "rNp" -0x11d6: "lss" -0x11d7: "lZ" -0x11d8: "lk" -0x11d9: "lQ" -0x11da: "mg" -0x11db: "ml" -0x11dc: "mb" -0x11dd: "ms" -0x11de: "mss" -0x11df: "mZ" -0x11e0: "mc" -0x11e1: "mh" -0x11e2: "mN" -0x11e3: "bl" -0x11e4: "bp" -0x11e5: "ph" -0x11e6: "pN" -0x11e7: "sg" -0x11e8: "sd" -0x11e9: "sl" -0x11ea: "sb" -0x11eb: "Z" -0x11ec: "g" -0x11ed: "ss" -0x11ee: "" -0x11ef: "kh" -0x11f0: "N" -0x11f1: "Ns" -0x11f2: "NZ" -0x11f3: "pb" -0x11f4: "pN" -0x11f5: "hn" -0x11f6: "hl" -0x11f7: "hm" -0x11f8: "hb" -0x11f9: "Q" -0x11fa: "[?]" -0x11fb: "[?]" -0x11fc: "[?]" -0x11fd: "[?]" -0x11fe: "[?]" -/* x012 */ -0x1200: "ha" -0x1201: "hu" -0x1202: "hi" -0x1203: "haa" -0x1204: "hee" -0x1205: "he" -0x1206: "ho" -0x1207: "[?]" -0x1208: "la" -0x1209: "lu" -0x120a: "li" -0x120b: "laa" -0x120c: "lee" -0x120d: "le" -0x120e: "lo" -0x120f: "lwa" -0x1210: "hha" -0x1211: "hhu" -0x1212: "hhi" -0x1213: "hhaa" -0x1214: "hhee" -0x1215: "hhe" -0x1216: "hho" -0x1217: "hhwa" -0x1218: "ma" -0x1219: "mu" -0x121a: "mi" -0x121b: "maa" -0x121c: "mee" -0x121d: "me" -0x121e: "mo" -0x121f: "mwa" -0x1220: "sza" -0x1221: "szu" -0x1222: "szi" -0x1223: "szaa" -0x1224: "szee" -0x1225: "sze" -0x1226: "szo" -0x1227: "szwa" -0x1228: "ra" -0x1229: "ru" -0x122a: "ri" -0x122b: "raa" -0x122c: "ree" -0x122d: "re" -0x122e: "ro" -0x122f: "rwa" -0x1230: "sa" -0x1231: "su" -0x1232: "si" -0x1233: "saa" -0x1234: "see" -0x1235: "se" -0x1236: "so" -0x1237: "swa" -0x1238: "sha" -0x1239: "shu" -0x123a: "shi" -0x123b: "shaa" -0x123c: "shee" -0x123d: "she" -0x123e: "sho" -0x123f: "shwa" -0x1240: "qa" -0x1241: "qu" -0x1242: "qi" -0x1243: "qaa" -0x1244: "qee" -0x1245: "qe" -0x1246: "qo" -0x1247: "[?]" -0x1248: "qwa" -0x1249: "[?]" -0x124a: "qwi" -0x124b: "qwaa" -0x124c: "qwee" -0x124d: "qwe" -0x124e: "[?]" -0x124f: "[?]" -0x1250: "qha" -0x1251: "qhu" -0x1252: "qhi" -0x1253: "qhaa" -0x1254: "qhee" -0x1255: "qhe" -0x1256: "qho" -0x1257: "[?]" -0x1258: "qhwa" -0x1259: "[?]" -0x125a: "qhwi" -0x125b: "qhwaa" -0x125c: "qhwee" -0x125d: "qhwe" -0x125e: "[?]" -0x125f: "[?]" -0x1260: "ba" -0x1261: "bu" -0x1262: "bi" -0x1263: "baa" -0x1264: "bee" -0x1265: "be" -0x1266: "bo" -0x1267: "bwa" -0x1268: "va" -0x1269: "vu" -0x126a: "vi" -0x126b: "vaa" -0x126c: "vee" -0x126d: "ve" -0x126e: "vo" -0x126f: "vwa" -0x1270: "ta" -0x1271: "tu" -0x1272: "ti" -0x1273: "taa" -0x1274: "tee" -0x1275: "te" -0x1276: "to" -0x1277: "twa" -0x1278: "ca" -0x1279: "cu" -0x127a: "ci" -0x127b: "caa" -0x127c: "cee" -0x127d: "ce" -0x127e: "co" -0x127f: "cwa" -0x1280: "xa" -0x1281: "xu" -0x1282: "xi" -0x1283: "xaa" -0x1284: "xee" -0x1285: "xe" -0x1286: "xo" -0x1287: "[?]" -0x1288: "xwa" -0x1289: "[?]" -0x128a: "xwi" -0x128b: "xwaa" -0x128c: "xwee" -0x128d: "xwe" -0x128e: "[?]" -0x128f: "[?]" -0x1290: "na" -0x1291: "nu" -0x1292: "ni" -0x1293: "naa" -0x1294: "nee" -0x1295: "ne" -0x1296: "no" -0x1297: "nwa" -0x1298: "nya" -0x1299: "nyu" -0x129a: "nyi" -0x129b: "nyaa" -0x129c: "nyee" -0x129d: "nye" -0x129e: "nyo" -0x129f: "nywa" -0x12a0: "'a" -0x12a1: "'u" -0x12a2: "[?]" -0x12a3: "'aa" -0x12a4: "'ee" -0x12a5: "'e" -0x12a6: "'o" -0x12a7: "'wa" -0x12a8: "ka" -0x12a9: "ku" -0x12aa: "ki" -0x12ab: "kaa" -0x12ac: "kee" -0x12ad: "ke" -0x12ae: "ko" -0x12af: "[?]" -0x12b0: "kwa" -0x12b1: "[?]" -0x12b2: "kwi" -0x12b3: "kwaa" -0x12b4: "kwee" -0x12b5: "kwe" -0x12b6: "[?]" -0x12b7: "[?]" -0x12b8: "kxa" -0x12b9: "kxu" -0x12ba: "kxi" -0x12bb: "kxaa" -0x12bc: "kxee" -0x12bd: "kxe" -0x12be: "kxo" -0x12bf: "[?]" -0x12c0: "kxwa" -0x12c1: "[?]" -0x12c2: "kxwi" -0x12c3: "kxwaa" -0x12c4: "kxwee" -0x12c5: "kxwe" -0x12c6: "[?]" -0x12c7: "[?]" -0x12c8: "wa" -0x12c9: "wu" -0x12ca: "wi" -0x12cb: "waa" -0x12cc: "wee" -0x12cd: "we" -0x12ce: "wo" -0x12cf: "[?]" -0x12d0: "`a" -0x12d1: "`u" -0x12d2: "`i" -0x12d3: "`aa" -0x12d4: "`ee" -0x12d5: "`e" -0x12d6: "`o" -0x12d7: "[?]" -0x12d8: "za" -0x12d9: "zu" -0x12da: "zi" -0x12db: "zaa" -0x12dc: "zee" -0x12dd: "ze" -0x12de: "zo" -0x12df: "zwa" -0x12e0: "zha" -0x12e1: "zhu" -0x12e2: "zhi" -0x12e3: "zhaa" -0x12e4: "zhee" -0x12e5: "zhe" -0x12e6: "zho" -0x12e7: "zhwa" -0x12e8: "ya" -0x12e9: "yu" -0x12ea: "yi" -0x12eb: "yaa" -0x12ec: "yee" -0x12ed: "ye" -0x12ee: "yo" -0x12ef: "[?]" -0x12f0: "da" -0x12f1: "du" -0x12f2: "di" -0x12f3: "daa" -0x12f4: "dee" -0x12f5: "de" -0x12f6: "do" -0x12f7: "dwa" -0x12f8: "dda" -0x12f9: "ddu" -0x12fa: "ddi" -0x12fb: "ddaa" -0x12fc: "ddee" -0x12fd: "dde" -0x12fe: "ddo" -0x12ff: "ddwa" -/* x013 */ -0x1300: "ja" -0x1301: "ju" -0x1302: "ji" -0x1303: "jaa" -0x1304: "jee" -0x1305: "je" -0x1306: "jo" -0x1307: "jwa" -0x1308: "ga" -0x1309: "gu" -0x130a: "gi" -0x130b: "gaa" -0x130c: "gee" -0x130d: "ge" -0x130e: "go" -0x130f: "[?]" -0x1310: "gwa" -0x1311: "[?]" -0x1312: "gwi" -0x1313: "gwaa" -0x1314: "gwee" -0x1315: "gwe" -0x1316: "[?]" -0x1317: "[?]" -0x1318: "gga" -0x1319: "ggu" -0x131a: "ggi" -0x131b: "ggaa" -0x131c: "ggee" -0x131d: "gge" -0x131e: "ggo" -0x131f: "[?]" -0x1320: "tha" -0x1321: "thu" -0x1322: "thi" -0x1323: "thaa" -0x1324: "thee" -0x1325: "the" -0x1326: "tho" -0x1327: "thwa" -0x1328: "cha" -0x1329: "chu" -0x132a: "chi" -0x132b: "chaa" -0x132c: "chee" -0x132d: "che" -0x132e: "cho" -0x132f: "chwa" -0x1330: "pha" -0x1331: "phu" -0x1332: "phi" -0x1333: "phaa" -0x1334: "phee" -0x1335: "phe" -0x1336: "pho" -0x1337: "phwa" -0x1338: "tsa" -0x1339: "tsu" -0x133a: "tsi" -0x133b: "tsaa" -0x133c: "tsee" -0x133d: "tse" -0x133e: "tso" -0x133f: "tswa" -0x1340: "tza" -0x1341: "tzu" -0x1342: "tzi" -0x1343: "tzaa" -0x1344: "tzee" -0x1345: "tze" -0x1346: "tzo" -0x1347: "[?]" -0x1348: "fa" -0x1349: "fu" -0x134a: "fi" -0x134b: "faa" -0x134c: "fee" -0x134d: "fe" -0x134e: "fo" -0x134f: "fwa" -0x1350: "pa" -0x1351: "pu" -0x1352: "pi" -0x1353: "paa" -0x1354: "pee" -0x1355: "pe" -0x1356: "po" -0x1357: "pwa" -0x1358: "rya" -0x1359: "mya" -0x135a: "fya" -0x135b: "[?]" -0x135c: "[?]" -0x135d: "[?]" -0x135e: "[?]" -0x135f: "[?]" -0x1360: "[?]" -0x1361: " " -0x1362: "." -0x1363: "," -0x1364: ";" -0x1365: ":" -0x1366: ":: " -0x1367: "?" -0x1368: "//" -0x1369: "1" -0x136a: "2" -0x136b: "3" -0x136c: "4" -0x136d: "5" -0x136e: "6" -0x136f: "7" -0x1370: "8" -0x1371: "9" -0x1372: "10+" -0x1373: "20+" -0x1374: "30+" -0x1375: "40+" -0x1376: "50+" -0x1377: "60+" -0x1378: "70+" -0x1379: "80+" -0x137a: "90+" -0x137b: "100+" -0x137c: "10,000+" -0x137d: "[?]" -0x137e: "[?]" -0x137f: "[?]" -0x1380: "[?]" -0x1381: "[?]" -0x1382: "[?]" -0x1383: "[?]" -0x1384: "[?]" -0x1385: "[?]" -0x1386: "[?]" -0x1387: "[?]" -0x1388: "[?]" -0x1389: "[?]" -0x138a: "[?]" -0x138b: "[?]" -0x138c: "[?]" -0x138d: "[?]" -0x138e: "[?]" -0x138f: "[?]" -0x1390: "[?]" -0x1391: "[?]" -0x1392: "[?]" -0x1393: "[?]" -0x1394: "[?]" -0x1395: "[?]" -0x1396: "[?]" -0x1397: "[?]" -0x1398: "[?]" -0x1399: "[?]" -0x139a: "[?]" -0x139b: "[?]" -0x139c: "[?]" -0x139d: "[?]" -0x139e: "[?]" -0x139f: "[?]" -0x13a0: "a" -0x13a1: "e" -0x13a2: "i" -0x13a3: "o" -0x13a4: "u" -0x13a5: "v" -0x13a6: "ga" -0x13a7: "ka" -0x13a8: "ge" -0x13a9: "gi" -0x13aa: "go" -0x13ab: "gu" -0x13ac: "gv" -0x13ad: "ha" -0x13ae: "he" -0x13af: "hi" -0x13b0: "ho" -0x13b1: "hu" -0x13b2: "hv" -0x13b3: "la" -0x13b4: "le" -0x13b5: "li" -0x13b6: "lo" -0x13b7: "lu" -0x13b8: "lv" -0x13b9: "ma" -0x13ba: "me" -0x13bb: "mi" -0x13bc: "mo" -0x13bd: "mu" -0x13be: "na" -0x13bf: "hna" -0x13c0: "nah" -0x13c1: "ne" -0x13c2: "ni" -0x13c3: "no" -0x13c4: "nu" -0x13c5: "nv" -0x13c6: "qua" -0x13c7: "que" -0x13c8: "qui" -0x13c9: "quo" -0x13ca: "quu" -0x13cb: "quv" -0x13cc: "sa" -0x13cd: "s" -0x13ce: "se" -0x13cf: "si" -0x13d0: "so" -0x13d1: "su" -0x13d2: "sv" -0x13d3: "da" -0x13d4: "ta" -0x13d5: "de" -0x13d6: "te" -0x13d7: "di" -0x13d8: "ti" -0x13d9: "do" -0x13da: "du" -0x13db: "dv" -0x13dc: "dla" -0x13dd: "tla" -0x13de: "tle" -0x13df: "tli" -0x13e0: "tlo" -0x13e1: "tlu" -0x13e2: "tlv" -0x13e3: "tsa" -0x13e4: "tse" -0x13e5: "tsi" -0x13e6: "tso" -0x13e7: "tsu" -0x13e8: "tsv" -0x13e9: "wa" -0x13ea: "we" -0x13eb: "wi" -0x13ec: "wo" -0x13ed: "wu" -0x13ee: "wv" -0x13ef: "ya" -0x13f0: "ye" -0x13f1: "yi" -0x13f2: "yo" -0x13f3: "yu" -0x13f4: "yv" -0x13f5: "[?]" -0x13f6: "[?]" -0x13f7: "[?]" -0x13f8: "[?]" -0x13f9: "[?]" -0x13fa: "[?]" -0x13fb: "[?]" -0x13fc: "[?]" -0x13fd: "[?]" -0x13fe: "[?]" -/* x014 */ -0x1400: "[?]" -0x1401: "e" -0x1402: "aai" -0x1403: "i" -0x1404: "ii" -0x1405: "o" -0x1406: "oo" -0x1407: "oo" -0x1408: "ee" -0x1409: "i" -0x140a: "a" -0x140b: "aa" -0x140c: "we" -0x140d: "we" -0x140e: "wi" -0x140f: "wi" -0x1410: "wii" -0x1411: "wii" -0x1412: "wo" -0x1413: "wo" -0x1414: "woo" -0x1415: "woo" -0x1416: "woo" -0x1417: "wa" -0x1418: "wa" -0x1419: "waa" -0x141a: "waa" -0x141b: "waa" -0x141c: "ai" -0x141d: "w" -0x141e: "'" -0x141f: "t" -0x1420: "k" -0x1421: "sh" -0x1422: "s" -0x1423: "n" -0x1424: "w" -0x1425: "n" -0x1426: "[?]" -0x1427: "w" -0x1428: "c" -0x1429: "?" -0x142a: "l" -0x142b: "en" -0x142c: "in" -0x142d: "on" -0x142e: "an" -0x142f: "pe" -0x1430: "paai" -0x1431: "pi" -0x1432: "pii" -0x1433: "po" -0x1434: "poo" -0x1435: "poo" -0x1436: "hee" -0x1437: "hi" -0x1438: "pa" -0x1439: "paa" -0x143a: "pwe" -0x143b: "pwe" -0x143c: "pwi" -0x143d: "pwi" -0x143e: "pwii" -0x143f: "pwii" -0x1440: "pwo" -0x1441: "pwo" -0x1442: "pwoo" -0x1443: "pwoo" -0x1444: "pwa" -0x1445: "pwa" -0x1446: "pwaa" -0x1447: "pwaa" -0x1448: "pwaa" -0x1449: "p" -0x144a: "p" -0x144b: "h" -0x144c: "te" -0x144d: "taai" -0x144e: "ti" -0x144f: "tii" -0x1450: "to" -0x1451: "too" -0x1452: "too" -0x1453: "dee" -0x1454: "di" -0x1455: "ta" -0x1456: "taa" -0x1457: "twe" -0x1458: "twe" -0x1459: "twi" -0x145a: "twi" -0x145b: "twii" -0x145c: "twii" -0x145d: "two" -0x145e: "two" -0x145f: "twoo" -0x1460: "twoo" -0x1461: "twa" -0x1462: "twa" -0x1463: "twaa" -0x1464: "twaa" -0x1465: "twaa" -0x1466: "t" -0x1467: "tte" -0x1468: "tti" -0x1469: "tto" -0x146a: "tta" -0x146b: "ke" -0x146c: "kaai" -0x146d: "ki" -0x146e: "kii" -0x146f: "ko" -0x1470: "koo" -0x1471: "koo" -0x1472: "ka" -0x1473: "kaa" -0x1474: "kwe" -0x1475: "kwe" -0x1476: "kwi" -0x1477: "kwi" -0x1478: "kwii" -0x1479: "kwii" -0x147a: "kwo" -0x147b: "kwo" -0x147c: "kwoo" -0x147d: "kwoo" -0x147e: "kwa" -0x147f: "kwa" -0x1480: "kwaa" -0x1481: "kwaa" -0x1482: "kwaa" -0x1483: "k" -0x1484: "kw" -0x1485: "keh" -0x1486: "kih" -0x1487: "koh" -0x1488: "kah" -0x1489: "ce" -0x148a: "caai" -0x148b: "ci" -0x148c: "cii" -0x148d: "co" -0x148e: "coo" -0x148f: "coo" -0x1490: "ca" -0x1491: "caa" -0x1492: "cwe" -0x1493: "cwe" -0x1494: "cwi" -0x1495: "cwi" -0x1496: "cwii" -0x1497: "cwii" -0x1498: "cwo" -0x1499: "cwo" -0x149a: "cwoo" -0x149b: "cwoo" -0x149c: "cwa" -0x149d: "cwa" -0x149e: "cwaa" -0x149f: "cwaa" -0x14a0: "cwaa" -0x14a1: "c" -0x14a2: "th" -0x14a3: "me" -0x14a4: "maai" -0x14a5: "mi" -0x14a6: "mii" -0x14a7: "mo" -0x14a8: "moo" -0x14a9: "moo" -0x14aa: "ma" -0x14ab: "maa" -0x14ac: "mwe" -0x14ad: "mwe" -0x14ae: "mwi" -0x14af: "mwi" -0x14b0: "mwii" -0x14b1: "mwii" -0x14b2: "mwo" -0x14b3: "mwo" -0x14b4: "mwoo" -0x14b5: "mwoo" -0x14b6: "mwa" -0x14b7: "mwa" -0x14b8: "mwaa" -0x14b9: "mwaa" -0x14ba: "mwaa" -0x14bb: "m" -0x14bc: "m" -0x14bd: "mh" -0x14be: "m" -0x14bf: "m" -0x14c0: "ne" -0x14c1: "naai" -0x14c2: "ni" -0x14c3: "nii" -0x14c4: "no" -0x14c5: "noo" -0x14c6: "noo" -0x14c7: "na" -0x14c8: "naa" -0x14c9: "nwe" -0x14ca: "nwe" -0x14cb: "nwa" -0x14cc: "nwa" -0x14cd: "nwaa" -0x14ce: "nwaa" -0x14cf: "nwaa" -0x14d0: "n" -0x14d1: "ng" -0x14d2: "nh" -0x14d3: "le" -0x14d4: "laai" -0x14d5: "li" -0x14d6: "lii" -0x14d7: "lo" -0x14d8: "loo" -0x14d9: "loo" -0x14da: "la" -0x14db: "laa" -0x14dc: "lwe" -0x14dd: "lwe" -0x14de: "lwi" -0x14df: "lwi" -0x14e0: "lwii" -0x14e1: "lwii" -0x14e2: "lwo" -0x14e3: "lwo" -0x14e4: "lwoo" -0x14e5: "lwoo" -0x14e6: "lwa" -0x14e7: "lwa" -0x14e8: "lwaa" -0x14e9: "lwaa" -0x14ea: "l" -0x14eb: "l" -0x14ec: "l" -0x14ed: "se" -0x14ee: "saai" -0x14ef: "si" -0x14f0: "sii" -0x14f1: "so" -0x14f2: "soo" -0x14f3: "soo" -0x14f4: "sa" -0x14f5: "saa" -0x14f6: "swe" -0x14f7: "swe" -0x14f8: "swi" -0x14f9: "swi" -0x14fa: "swii" -0x14fb: "swii" -0x14fc: "swo" -0x14fd: "swo" -0x14fe: "swoo" -0x14ff: "swoo" -/* x015 */ -0x1500: "swa" -0x1501: "swa" -0x1502: "swaa" -0x1503: "swaa" -0x1504: "swaa" -0x1505: "s" -0x1506: "s" -0x1507: "sw" -0x1508: "s" -0x1509: "sk" -0x150a: "skw" -0x150b: "sW" -0x150c: "spwa" -0x150d: "stwa" -0x150e: "skwa" -0x150f: "scwa" -0x1510: "she" -0x1511: "shi" -0x1512: "shii" -0x1513: "sho" -0x1514: "shoo" -0x1515: "sha" -0x1516: "shaa" -0x1517: "shwe" -0x1518: "shwe" -0x1519: "shwi" -0x151a: "shwi" -0x151b: "shwii" -0x151c: "shwii" -0x151d: "shwo" -0x151e: "shwo" -0x151f: "shwoo" -0x1520: "shwoo" -0x1521: "shwa" -0x1522: "shwa" -0x1523: "shwaa" -0x1524: "shwaa" -0x1525: "sh" -0x1526: "ye" -0x1527: "yaai" -0x1528: "yi" -0x1529: "yii" -0x152a: "yo" -0x152b: "yoo" -0x152c: "yoo" -0x152d: "ya" -0x152e: "yaa" -0x152f: "ywe" -0x1530: "ywe" -0x1531: "ywi" -0x1532: "ywi" -0x1533: "ywii" -0x1534: "ywii" -0x1535: "ywo" -0x1536: "ywo" -0x1537: "ywoo" -0x1538: "ywoo" -0x1539: "ywa" -0x153a: "ywa" -0x153b: "ywaa" -0x153c: "ywaa" -0x153d: "ywaa" -0x153e: "y" -0x153f: "y" -0x1540: "y" -0x1541: "yi" -0x1542: "re" -0x1543: "re" -0x1544: "le" -0x1545: "raai" -0x1546: "ri" -0x1547: "rii" -0x1548: "ro" -0x1549: "roo" -0x154a: "lo" -0x154b: "ra" -0x154c: "raa" -0x154d: "la" -0x154e: "rwaa" -0x154f: "rwaa" -0x1550: "r" -0x1551: "r" -0x1552: "r" -0x1553: "fe" -0x1554: "faai" -0x1555: "fi" -0x1556: "fii" -0x1557: "fo" -0x1558: "foo" -0x1559: "fa" -0x155a: "faa" -0x155b: "fwaa" -0x155c: "fwaa" -0x155d: "f" -0x155e: "the" -0x155f: "the" -0x1560: "thi" -0x1561: "thi" -0x1562: "thii" -0x1563: "thii" -0x1564: "tho" -0x1565: "thoo" -0x1566: "tha" -0x1567: "thaa" -0x1568: "thwaa" -0x1569: "thwaa" -0x156a: "th" -0x156b: "tthe" -0x156c: "tthi" -0x156d: "ttho" -0x156e: "ttha" -0x156f: "tth" -0x1570: "tye" -0x1571: "tyi" -0x1572: "tyo" -0x1573: "tya" -0x1574: "he" -0x1575: "hi" -0x1576: "hii" -0x1577: "ho" -0x1578: "hoo" -0x1579: "ha" -0x157a: "haa" -0x157b: "h" -0x157c: "h" -0x157d: "hk" -0x157e: "qaai" -0x157f: "qi" -0x1580: "qii" -0x1581: "qo" -0x1582: "qoo" -0x1583: "qa" -0x1584: "qaa" -0x1585: "q" -0x1586: "tlhe" -0x1587: "tlhi" -0x1588: "tlho" -0x1589: "tlha" -0x158a: "re" -0x158b: "ri" -0x158c: "ro" -0x158d: "ra" -0x158e: "ngaai" -0x158f: "ngi" -0x1590: "ngii" -0x1591: "ngo" -0x1592: "ngoo" -0x1593: "nga" -0x1594: "ngaa" -0x1595: "ng" -0x1596: "nng" -0x1597: "she" -0x1598: "shi" -0x1599: "sho" -0x159a: "sha" -0x159b: "the" -0x159c: "thi" -0x159d: "tho" -0x159e: "tha" -0x159f: "th" -0x15a0: "lhi" -0x15a1: "lhii" -0x15a2: "lho" -0x15a3: "lhoo" -0x15a4: "lha" -0x15a5: "lhaa" -0x15a6: "lh" -0x15a7: "the" -0x15a8: "thi" -0x15a9: "thii" -0x15aa: "tho" -0x15ab: "thoo" -0x15ac: "tha" -0x15ad: "thaa" -0x15ae: "th" -0x15af: "b" -0x15b0: "e" -0x15b1: "i" -0x15b2: "o" -0x15b3: "a" -0x15b4: "we" -0x15b5: "wi" -0x15b6: "wo" -0x15b7: "wa" -0x15b8: "ne" -0x15b9: "ni" -0x15ba: "no" -0x15bb: "na" -0x15bc: "ke" -0x15bd: "ki" -0x15be: "ko" -0x15bf: "ka" -0x15c0: "he" -0x15c1: "hi" -0x15c2: "ho" -0x15c3: "ha" -0x15c4: "ghu" -0x15c5: "gho" -0x15c6: "ghe" -0x15c7: "ghee" -0x15c8: "ghi" -0x15c9: "gha" -0x15ca: "ru" -0x15cb: "ro" -0x15cc: "re" -0x15cd: "ree" -0x15ce: "ri" -0x15cf: "ra" -0x15d0: "wu" -0x15d1: "wo" -0x15d2: "we" -0x15d3: "wee" -0x15d4: "wi" -0x15d5: "wa" -0x15d6: "hwu" -0x15d7: "hwo" -0x15d8: "hwe" -0x15d9: "hwee" -0x15da: "hwi" -0x15db: "hwa" -0x15dc: "thu" -0x15dd: "tho" -0x15de: "the" -0x15df: "thee" -0x15e0: "thi" -0x15e1: "tha" -0x15e2: "ttu" -0x15e3: "tto" -0x15e4: "tte" -0x15e5: "ttee" -0x15e6: "tti" -0x15e7: "tta" -0x15e8: "pu" -0x15e9: "po" -0x15ea: "pe" -0x15eb: "pee" -0x15ec: "pi" -0x15ed: "pa" -0x15ee: "p" -0x15ef: "gu" -0x15f0: "go" -0x15f1: "ge" -0x15f2: "gee" -0x15f3: "gi" -0x15f4: "ga" -0x15f5: "khu" -0x15f6: "kho" -0x15f7: "khe" -0x15f8: "khee" -0x15f9: "khi" -0x15fa: "kha" -0x15fb: "kku" -0x15fc: "kko" -0x15fd: "kke" -0x15fe: "kkee" -0x15ff: "kki" -/* x016 */ -0x1600: "kka" -0x1601: "kk" -0x1602: "nu" -0x1603: "no" -0x1604: "ne" -0x1605: "nee" -0x1606: "ni" -0x1607: "na" -0x1608: "mu" -0x1609: "mo" -0x160a: "me" -0x160b: "mee" -0x160c: "mi" -0x160d: "ma" -0x160e: "yu" -0x160f: "yo" -0x1610: "ye" -0x1611: "yee" -0x1612: "yi" -0x1613: "ya" -0x1614: "ju" -0x1615: "ju" -0x1616: "jo" -0x1617: "je" -0x1618: "jee" -0x1619: "ji" -0x161a: "ji" -0x161b: "ja" -0x161c: "jju" -0x161d: "jjo" -0x161e: "jje" -0x161f: "jjee" -0x1620: "jji" -0x1621: "jja" -0x1622: "lu" -0x1623: "lo" -0x1624: "le" -0x1625: "lee" -0x1626: "li" -0x1627: "la" -0x1628: "dlu" -0x1629: "dlo" -0x162a: "dle" -0x162b: "dlee" -0x162c: "dli" -0x162d: "dla" -0x162e: "lhu" -0x162f: "lho" -0x1630: "lhe" -0x1631: "lhee" -0x1632: "lhi" -0x1633: "lha" -0x1634: "tlhu" -0x1635: "tlho" -0x1636: "tlhe" -0x1637: "tlhee" -0x1638: "tlhi" -0x1639: "tlha" -0x163a: "tlu" -0x163b: "tlo" -0x163c: "tle" -0x163d: "tlee" -0x163e: "tli" -0x163f: "tla" -0x1640: "zu" -0x1641: "zo" -0x1642: "ze" -0x1643: "zee" -0x1644: "zi" -0x1645: "za" -0x1646: "z" -0x1647: "z" -0x1648: "dzu" -0x1649: "dzo" -0x164a: "dze" -0x164b: "dzee" -0x164c: "dzi" -0x164d: "dza" -0x164e: "su" -0x164f: "so" -0x1650: "se" -0x1651: "see" -0x1652: "si" -0x1653: "sa" -0x1654: "shu" -0x1655: "sho" -0x1656: "she" -0x1657: "shee" -0x1658: "shi" -0x1659: "sha" -0x165a: "sh" -0x165b: "tsu" -0x165c: "tso" -0x165d: "tse" -0x165e: "tsee" -0x165f: "tsi" -0x1660: "tsa" -0x1661: "chu" -0x1662: "cho" -0x1663: "che" -0x1664: "chee" -0x1665: "chi" -0x1666: "cha" -0x1667: "ttsu" -0x1668: "ttso" -0x1669: "ttse" -0x166a: "ttsee" -0x166b: "ttsi" -0x166c: "ttsa" -0x166d: "X" -0x166e: "." -0x166f: "qai" -0x1670: "ngai" -0x1671: "nngi" -0x1672: "nngii" -0x1673: "nngo" -0x1674: "nngoo" -0x1675: "nnga" -0x1676: "nngaa" -0x1677: "[?]" -0x1678: "[?]" -0x1679: "[?]" -0x167a: "[?]" -0x167b: "[?]" -0x167c: "[?]" -0x167d: "[?]" -0x167e: "[?]" -0x167f: "[?]" -0x1680: " " -0x1681: "b" -0x1682: "l" -0x1683: "f" -0x1684: "s" -0x1685: "n" -0x1686: "h" -0x1687: "d" -0x1688: "t" -0x1689: "c" -0x168a: "q" -0x168b: "m" -0x168c: "g" -0x168d: "ng" -0x168e: "z" -0x168f: "r" -0x1690: "a" -0x1691: "o" -0x1692: "u" -0x1693: "e" -0x1694: "i" -0x1695: "ch" -0x1696: "th" -0x1697: "ph" -0x1698: "p" -0x1699: "x" -0x169a: "p" -0x169b: "<" -0x169c: ">" -0x169d: "[?]" -0x169e: "[?]" -0x169f: "[?]" -0x16a0: "f" -0x16a1: "v" -0x16a2: "u" -0x16a3: "yr" -0x16a4: "y" -0x16a5: "w" -0x16a6: "th" -0x16a7: "th" -0x16a8: "a" -0x16a9: "o" -0x16aa: "ac" -0x16ab: "ae" -0x16ac: "o" -0x16ad: "o" -0x16ae: "o" -0x16af: "oe" -0x16b0: "on" -0x16b1: "r" -0x16b2: "k" -0x16b3: "c" -0x16b4: "k" -0x16b5: "g" -0x16b6: "ng" -0x16b7: "g" -0x16b8: "g" -0x16b9: "w" -0x16ba: "h" -0x16bb: "h" -0x16bc: "h" -0x16bd: "h" -0x16be: "n" -0x16bf: "n" -0x16c0: "n" -0x16c1: "i" -0x16c2: "e" -0x16c3: "j" -0x16c4: "g" -0x16c5: "ae" -0x16c6: "a" -0x16c7: "eo" -0x16c8: "p" -0x16c9: "z" -0x16ca: "s" -0x16cb: "s" -0x16cc: "s" -0x16cd: "c" -0x16ce: "z" -0x16cf: "t" -0x16d0: "t" -0x16d1: "d" -0x16d2: "b" -0x16d3: "b" -0x16d4: "p" -0x16d5: "p" -0x16d6: "e" -0x16d7: "m" -0x16d8: "m" -0x16d9: "m" -0x16da: "l" -0x16db: "l" -0x16dc: "ng" -0x16dd: "ng" -0x16de: "d" -0x16df: "o" -0x16e0: "ear" -0x16e1: "ior" -0x16e2: "qu" -0x16e3: "qu" -0x16e4: "qu" -0x16e5: "s" -0x16e6: "yr" -0x16e7: "yr" -0x16e8: "yr" -0x16e9: "q" -0x16ea: "x" -0x16eb: "." -0x16ec: ":" -0x16ed: "+" -0x16ee: "17" -0x16ef: "18" -0x16f0: "19" -0x16f1: "[?]" -0x16f2: "[?]" -0x16f3: "[?]" -0x16f4: "[?]" -0x16f5: "[?]" -0x16f6: "[?]" -0x16f7: "[?]" -0x16f8: "[?]" -0x16f9: "[?]" -0x16fa: "[?]" -0x16fb: "[?]" -0x16fc: "[?]" -0x16fd: "[?]" -0x16fe: "[?]" -/* x017 */ -0x1700: "[?]" -0x1701: "[?]" -0x1702: "[?]" -0x1703: "[?]" -0x1704: "[?]" -0x1705: "[?]" -0x1706: "[?]" -0x1707: "[?]" -0x1708: "[?]" -0x1709: "[?]" -0x170a: "[?]" -0x170b: "[?]" -0x170c: "[?]" -0x170d: "[?]" -0x170e: "[?]" -0x170f: "[?]" -0x1710: "[?]" -0x1711: "[?]" -0x1712: "[?]" -0x1713: "[?]" -0x1714: "[?]" -0x1715: "[?]" -0x1716: "[?]" -0x1717: "[?]" -0x1718: "[?]" -0x1719: "[?]" -0x171a: "[?]" -0x171b: "[?]" -0x171c: "[?]" -0x171d: "[?]" -0x171e: "[?]" -0x171f: "[?]" -0x1720: "[?]" -0x1721: "[?]" -0x1722: "[?]" -0x1723: "[?]" -0x1724: "[?]" -0x1725: "[?]" -0x1726: "[?]" -0x1727: "[?]" -0x1728: "[?]" -0x1729: "[?]" -0x172a: "[?]" -0x172b: "[?]" -0x172c: "[?]" -0x172d: "[?]" -0x172e: "[?]" -0x172f: "[?]" -0x1730: "[?]" -0x1731: "[?]" -0x1732: "[?]" -0x1733: "[?]" -0x1734: "[?]" -0x1735: "[?]" -0x1736: "[?]" -0x1737: "[?]" -0x1738: "[?]" -0x1739: "[?]" -0x173a: "[?]" -0x173b: "[?]" -0x173c: "[?]" -0x173d: "[?]" -0x173e: "[?]" -0x173f: "[?]" -0x1740: "[?]" -0x1741: "[?]" -0x1742: "[?]" -0x1743: "[?]" -0x1744: "[?]" -0x1745: "[?]" -0x1746: "[?]" -0x1747: "[?]" -0x1748: "[?]" -0x1749: "[?]" -0x174a: "[?]" -0x174b: "[?]" -0x174c: "[?]" -0x174d: "[?]" -0x174e: "[?]" -0x174f: "[?]" -0x1750: "[?]" -0x1751: "[?]" -0x1752: "[?]" -0x1753: "[?]" -0x1754: "[?]" -0x1755: "[?]" -0x1756: "[?]" -0x1757: "[?]" -0x1758: "[?]" -0x1759: "[?]" -0x175a: "[?]" -0x175b: "[?]" -0x175c: "[?]" -0x175d: "[?]" -0x175e: "[?]" -0x175f: "[?]" -0x1760: "[?]" -0x1761: "[?]" -0x1762: "[?]" -0x1763: "[?]" -0x1764: "[?]" -0x1765: "[?]" -0x1766: "[?]" -0x1767: "[?]" -0x1768: "[?]" -0x1769: "[?]" -0x176a: "[?]" -0x176b: "[?]" -0x176c: "[?]" -0x176d: "[?]" -0x176e: "[?]" -0x176f: "[?]" -0x1770: "[?]" -0x1771: "[?]" -0x1772: "[?]" -0x1773: "[?]" -0x1774: "[?]" -0x1775: "[?]" -0x1776: "[?]" -0x1777: "[?]" -0x1778: "[?]" -0x1779: "[?]" -0x177a: "[?]" -0x177b: "[?]" -0x177c: "[?]" -0x177d: "[?]" -0x177e: "[?]" -0x177f: "[?]" -0x1780: "k" -0x1781: "kh" -0x1782: "g" -0x1783: "gh" -0x1784: "ng" -0x1785: "c" -0x1786: "ch" -0x1787: "j" -0x1788: "jh" -0x1789: "ny" -0x178a: "t" -0x178b: "tth" -0x178c: "d" -0x178d: "ddh" -0x178e: "nn" -0x178f: "t" -0x1790: "th" -0x1791: "d" -0x1792: "dh" -0x1793: "n" -0x1794: "p" -0x1795: "ph" -0x1796: "b" -0x1797: "bh" -0x1798: "m" -0x1799: "y" -0x179a: "r" -0x179b: "l" -0x179c: "v" -0x179d: "sh" -0x179e: "ss" -0x179f: "s" -0x17a0: "h" -0x17a1: "l" -0x17a2: "q" -0x17a3: "a" -0x17a4: "aa" -0x17a5: "i" -0x17a6: "ii" -0x17a7: "u" -0x17a8: "uk" -0x17a9: "uu" -0x17aa: "uuv" -0x17ab: "ry" -0x17ac: "ryy" -0x17ad: "ly" -0x17ae: "lyy" -0x17af: "e" -0x17b0: "ai" -0x17b1: "oo" -0x17b2: "oo" -0x17b3: "au" -0x17b4: "a" -0x17b5: "aa" -0x17b6: "aa" -0x17b7: "i" -0x17b8: "ii" -0x17b9: "y" -0x17ba: "yy" -0x17bb: "u" -0x17bc: "uu" -0x17bd: "ua" -0x17be: "oe" -0x17bf: "ya" -0x17c0: "ie" -0x17c1: "e" -0x17c2: "ae" -0x17c3: "ai" -0x17c4: "oo" -0x17c5: "au" -0x17c6: "M" -0x17c7: "H" -0x17c8: "a`" -0x17c9: "" -0x17ca: "" -0x17cb: "" -0x17cc: "r" -0x17cd: "" -0x17ce: "!" -0x17cf: "" -0x17d0: "" -0x17d1: "" -0x17d2: "" -0x17d3: "" -0x17d4: "." -0x17d5: " // " -0x17d6: ":" -0x17d7: "+" -0x17d8: "++" -0x17d9: " * " -0x17da: " /// " -0x17db: "KR" -0x17dc: "'" -0x17dd: "[?]" -0x17de: "[?]" -0x17df: "[?]" -0x17e0: "0" -0x17e1: "1" -0x17e2: "2" -0x17e3: "3" -0x17e4: "4" -0x17e5: "5" -0x17e6: "6" -0x17e7: "7" -0x17e8: "8" -0x17e9: "9" -0x17ea: "[?]" -0x17eb: "[?]" -0x17ec: "[?]" -0x17ed: "[?]" -0x17ee: "[?]" -0x17ef: "[?]" -0x17f0: "[?]" -0x17f1: "[?]" -0x17f2: "[?]" -0x17f3: "[?]" -0x17f4: "[?]" -0x17f5: "[?]" -0x17f6: "[?]" -0x17f7: "[?]" -0x17f8: "[?]" -0x17f9: "[?]" -0x17fa: "[?]" -0x17fb: "[?]" -0x17fc: "[?]" -0x17fd: "[?]" -0x17fe: "[?]" -/* x018 */ -0x1800: " @ " -0x1801: " ... " -0x1802: ", " -0x1803: ". " -0x1804: ": " -0x1805: " // " -0x1806: "" -0x1807: "-" -0x1808: ", " -0x1809: ". " -0x180a: "" -0x180b: "" -0x180c: "" -0x180d: "" -0x180e: "" -0x180f: "[?]" -0x1810: "0" -0x1811: "1" -0x1812: "2" -0x1813: "3" -0x1814: "4" -0x1815: "5" -0x1816: "6" -0x1817: "7" -0x1818: "8" -0x1819: "9" -0x181a: "[?]" -0x181b: "[?]" -0x181c: "[?]" -0x181d: "[?]" -0x181e: "[?]" -0x181f: "[?]" -0x1820: "a" -0x1821: "e" -0x1822: "i" -0x1823: "o" -0x1824: "u" -0x1825: "O" -0x1826: "U" -0x1827: "ee" -0x1828: "n" -0x1829: "ng" -0x182a: "b" -0x182b: "p" -0x182c: "q" -0x182d: "g" -0x182e: "m" -0x182f: "l" -0x1830: "s" -0x1831: "sh" -0x1832: "t" -0x1833: "d" -0x1834: "ch" -0x1835: "j" -0x1836: "y" -0x1837: "r" -0x1838: "w" -0x1839: "f" -0x183a: "k" -0x183b: "kha" -0x183c: "ts" -0x183d: "z" -0x183e: "h" -0x183f: "zr" -0x1840: "lh" -0x1841: "zh" -0x1842: "ch" -0x1843: "-" -0x1844: "e" -0x1845: "i" -0x1846: "o" -0x1847: "u" -0x1848: "O" -0x1849: "U" -0x184a: "ng" -0x184b: "b" -0x184c: "p" -0x184d: "q" -0x184e: "g" -0x184f: "m" -0x1850: "t" -0x1851: "d" -0x1852: "ch" -0x1853: "j" -0x1854: "ts" -0x1855: "y" -0x1856: "w" -0x1857: "k" -0x1858: "g" -0x1859: "h" -0x185a: "jy" -0x185b: "ny" -0x185c: "dz" -0x185d: "e" -0x185e: "i" -0x185f: "iy" -0x1860: "U" -0x1861: "u" -0x1862: "ng" -0x1863: "k" -0x1864: "g" -0x1865: "h" -0x1866: "p" -0x1867: "sh" -0x1868: "t" -0x1869: "d" -0x186a: "j" -0x186b: "f" -0x186c: "g" -0x186d: "h" -0x186e: "ts" -0x186f: "z" -0x1870: "r" -0x1871: "ch" -0x1872: "zh" -0x1873: "i" -0x1874: "k" -0x1875: "r" -0x1876: "f" -0x1877: "zh" -0x1878: "[?]" -0x1879: "[?]" -0x187a: "[?]" -0x187b: "[?]" -0x187c: "[?]" -0x187d: "[?]" -0x187e: "[?]" -0x187f: "[?]" -0x1880: "[?]" -0x1881: "H" -0x1882: "X" -0x1883: "W" -0x1884: "M" -0x1885: " 3 " -0x1886: " 333 " -0x1887: "a" -0x1888: "i" -0x1889: "k" -0x188a: "ng" -0x188b: "c" -0x188c: "tt" -0x188d: "tth" -0x188e: "dd" -0x188f: "nn" -0x1890: "t" -0x1891: "d" -0x1892: "p" -0x1893: "ph" -0x1894: "ss" -0x1895: "zh" -0x1896: "z" -0x1897: "a" -0x1898: "t" -0x1899: "zh" -0x189a: "gh" -0x189b: "ng" -0x189c: "c" -0x189d: "jh" -0x189e: "tta" -0x189f: "ddh" -0x18a0: "t" -0x18a1: "dh" -0x18a2: "ss" -0x18a3: "cy" -0x18a4: "zh" -0x18a5: "z" -0x18a6: "u" -0x18a7: "y" -0x18a8: "bh" -0x18a9: "'" -0x18aa: "[?]" -0x18ab: "[?]" -0x18ac: "[?]" -0x18ad: "[?]" -0x18ae: "[?]" -0x18af: "[?]" -0x18b0: "[?]" -0x18b1: "[?]" -0x18b2: "[?]" -0x18b3: "[?]" -0x18b4: "[?]" -0x18b5: "[?]" -0x18b6: "[?]" -0x18b7: "[?]" -0x18b8: "[?]" -0x18b9: "[?]" -0x18ba: "[?]" -0x18bb: "[?]" -0x18bc: "[?]" -0x18bd: "[?]" -0x18be: "[?]" -0x18bf: "[?]" -0x18c0: "[?]" -0x18c1: "[?]" -0x18c2: "[?]" -0x18c3: "[?]" -0x18c4: "[?]" -0x18c5: "[?]" -0x18c6: "[?]" -0x18c7: "[?]" -0x18c8: "[?]" -0x18c9: "[?]" -0x18ca: "[?]" -0x18cb: "[?]" -0x18cc: "[?]" -0x18cd: "[?]" -0x18ce: "[?]" -0x18cf: "[?]" -0x18d0: "[?]" -0x18d1: "[?]" -0x18d2: "[?]" -0x18d3: "[?]" -0x18d4: "[?]" -0x18d5: "[?]" -0x18d6: "[?]" -0x18d7: "[?]" -0x18d8: "[?]" -0x18d9: "[?]" -0x18da: "[?]" -0x18db: "[?]" -0x18dc: "[?]" -0x18dd: "[?]" -0x18de: "[?]" -0x18df: "[?]" -0x18e0: "[?]" -0x18e1: "[?]" -0x18e2: "[?]" -0x18e3: "[?]" -0x18e4: "[?]" -0x18e5: "[?]" -0x18e6: "[?]" -0x18e7: "[?]" -0x18e8: "[?]" -0x18e9: "[?]" -0x18ea: "[?]" -0x18eb: "[?]" -0x18ec: "[?]" -0x18ed: "[?]" -0x18ee: "[?]" -0x18ef: "[?]" -0x18f0: "[?]" -0x18f1: "[?]" -0x18f2: "[?]" -0x18f3: "[?]" -0x18f4: "[?]" -0x18f5: "[?]" -0x18f6: "[?]" -0x18f7: "[?]" -0x18f8: "[?]" -0x18f9: "[?]" -0x18fa: "[?]" -0x18fb: "[?]" -0x18fc: "[?]" -0x18fd: "[?]" -0x18fe: "[?]" -/* x01d */ -0x1d00: "" -0x1d01: "" -0x1d02: "" -0x1d03: "" -0x1d04: "" -0x1d05: "" -0x1d06: "" -0x1d07: "" -0x1d08: "" -0x1d09: "" -0x1d0a: "" -0x1d0b: "" -0x1d0c: "" -0x1d0d: "" -0x1d0e: "" -0x1d0f: "" -0x1d10: "" -0x1d11: "" -0x1d12: "" -0x1d13: "" -0x1d14: "" -0x1d15: "" -0x1d16: "" -0x1d17: "" -0x1d18: "" -0x1d19: "" -0x1d1a: "" -0x1d1b: "" -0x1d1c: "" -0x1d1d: "" -0x1d1e: "" -0x1d1f: "" -0x1d20: "" -0x1d21: "" -0x1d22: "" -0x1d23: "" -0x1d24: "" -0x1d25: "" -0x1d26: "" -0x1d27: "" -0x1d28: "" -0x1d29: "" -0x1d2a: "" -0x1d2b: "" -0x1d2c: "" -0x1d2d: "" -0x1d2e: "" -0x1d2f: "" -0x1d30: "" -0x1d31: "" -0x1d32: "" -0x1d33: "" -0x1d34: "" -0x1d35: "" -0x1d36: "" -0x1d37: "" -0x1d38: "" -0x1d39: "" -0x1d3a: "" -0x1d3b: "" -0x1d3c: "" -0x1d3d: "" -0x1d3e: "" -0x1d3f: "" -0x1d40: "" -0x1d41: "" -0x1d42: "" -0x1d43: "" -0x1d44: "" -0x1d45: "" -0x1d46: "" -0x1d47: "" -0x1d48: "" -0x1d49: "" -0x1d4a: "" -0x1d4b: "" -0x1d4c: "" -0x1d4d: "" -0x1d4e: "" -0x1d4f: "" -0x1d50: "" -0x1d51: "" -0x1d52: "" -0x1d53: "" -0x1d54: "" -0x1d55: "" -0x1d56: "" -0x1d57: "" -0x1d58: "" -0x1d59: "" -0x1d5a: "" -0x1d5b: "" -0x1d5c: "" -0x1d5d: "" -0x1d5e: "" -0x1d5f: "" -0x1d60: "" -0x1d61: "" -0x1d62: "" -0x1d63: "" -0x1d64: "" -0x1d65: "" -0x1d66: "" -0x1d67: "" -0x1d68: "" -0x1d69: "" -0x1d6a: "" -0x1d6b: "" -0x1d6c: "b" -0x1d6d: "d" -0x1d6e: "f" -0x1d6f: "m" -0x1d70: "n" -0x1d71: "p" -0x1d72: "r" -0x1d73: "r" -0x1d74: "s" -0x1d75: "t" -0x1d76: "z" -0x1d77: "g" -0x1d78: "" -0x1d79: "" -0x1d7a: "" -0x1d7b: "" -0x1d7c: "" -0x1d7d: "p" -0x1d7e: "" -0x1d7f: "" -0x1d80: "b" -0x1d81: "d" -0x1d82: "f" -0x1d83: "g" -0x1d84: "k" -0x1d85: "l" -0x1d86: "m" -0x1d87: "n" -0x1d88: "p" -0x1d89: "r" -0x1d8a: "s" -0x1d8b: "" -0x1d8c: "v" -0x1d8d: "x" -0x1d8e: "z" -0x1d8f: "" -0x1d90: "" -0x1d91: "" -0x1d92: "" -0x1d93: "" -0x1d94: "" -0x1d95: "" -0x1d96: "" -0x1d97: "" -0x1d98: "" -0x1d99: "" -0x1d9a: "" -0x1d9b: "" -0x1d9c: "" -0x1d9d: "" -0x1d9e: "" -0x1d9f: "" -0x1da0: "" -0x1da1: "" -0x1da2: "" -0x1da3: "" -0x1da4: "" -0x1da5: "" -0x1da6: "" -0x1da7: "" -0x1da8: "" -0x1da9: "" -0x1daa: "" -0x1dab: "" -0x1dac: "" -0x1dad: "" -0x1dae: "" -0x1daf: "" -0x1db0: "" -0x1db1: "" -0x1db2: "" -0x1db3: "" -0x1db4: "" -0x1db5: "" -0x1db6: "" -0x1db7: "" -0x1db8: "" -0x1db9: "" -0x1dba: "" -0x1dbb: "" -0x1dbc: "" -0x1dbd: "" -0x1dbe: "" -0x1dbf: "" -0x1dc0: "" -0x1dc1: "" -0x1dc2: "" -0x1dc3: "" -0x1dc4: "" -0x1dc5: "" -0x1dc6: "" -0x1dc7: "" -0x1dc8: "" -0x1dc9: "" -0x1dca: "" -0x1dcb: "" -0x1dcc: "" -0x1dcd: "" -0x1dce: "" -0x1dcf: "" -0x1dd0: "" -0x1dd1: "" -0x1dd2: "" -0x1dd3: "" -0x1dd4: "" -0x1dd5: "" -0x1dd6: "" -0x1dd7: "" -0x1dd8: "" -0x1dd9: "" -0x1dda: "" -0x1ddb: "" -0x1ddc: "" -0x1ddd: "" -0x1dde: "" -0x1ddf: "" -0x1de0: "" -0x1de1: "" -0x1de2: "" -0x1de3: "" -0x1de4: "" -0x1de5: "" -0x1de6: "" -0x1de7: "" -0x1de8: "" -0x1de9: "" -0x1dea: "" -0x1deb: "" -0x1dec: "" -0x1ded: "" -0x1dee: "" -0x1def: "" -0x1df0: "" -0x1df1: "" -0x1df2: "" -0x1df3: "" -0x1df4: "" -0x1df5: "" -0x1df6: "" -0x1df7: "" -0x1df8: "" -0x1df9: "" -0x1dfa: "" -0x1dfb: "" -0x1dfc: "" -0x1dfd: "" -0x1dfe: "" -/* x01e */ -0x1e00: "A" -0x1e01: "a" -0x1e02: "B" -0x1e03: "b" -0x1e04: "B" -0x1e05: "b" -0x1e06: "B" -0x1e07: "b" -0x1e08: "C" -0x1e09: "c" -0x1e0a: "D" -0x1e0b: "d" -0x1e0c: "D" -0x1e0d: "d" -0x1e0e: "D" -0x1e0f: "d" -0x1e10: "D" -0x1e11: "d" -0x1e12: "D" -0x1e13: "d" -0x1e14: "E" -0x1e15: "e" -0x1e16: "E" -0x1e17: "e" -0x1e18: "E" -0x1e19: "e" -0x1e1a: "E" -0x1e1b: "e" -0x1e1c: "E" -0x1e1d: "e" -0x1e1e: "F" -0x1e1f: "f" -0x1e20: "G" -0x1e21: "g" -0x1e22: "H" -0x1e23: "h" -0x1e24: "H" -0x1e25: "h" -0x1e26: "H" -0x1e27: "h" -0x1e28: "H" -0x1e29: "h" -0x1e2a: "H" -0x1e2b: "h" -0x1e2c: "I" -0x1e2d: "i" -0x1e2e: "I" -0x1e2f: "i" -0x1e30: "K" -0x1e31: "k" -0x1e32: "K" -0x1e33: "k" -0x1e34: "K" -0x1e35: "k" -0x1e36: "L" -0x1e37: "l" -0x1e38: "L" -0x1e39: "l" -0x1e3a: "L" -0x1e3b: "l" -0x1e3c: "L" -0x1e3d: "l" -0x1e3e: "M" -0x1e3f: "m" -0x1e40: "M" -0x1e41: "m" -0x1e42: "M" -0x1e43: "m" -0x1e44: "N" -0x1e45: "n" -0x1e46: "N" -0x1e47: "n" -0x1e48: "N" -0x1e49: "n" -0x1e4a: "N" -0x1e4b: "n" -0x1e4c: "O" -0x1e4d: "o" -0x1e4e: "O" -0x1e4f: "o" -0x1e50: "O" -0x1e51: "o" -0x1e52: "O" -0x1e53: "o" -0x1e54: "P" -0x1e55: "p" -0x1e56: "P" -0x1e57: "p" -0x1e58: "R" -0x1e59: "r" -0x1e5a: "R" -0x1e5b: "r" -0x1e5c: "R" -0x1e5d: "r" -0x1e5e: "R" -0x1e5f: "r" -0x1e60: "S" -0x1e61: "s" -0x1e62: "S" -0x1e63: "s" -0x1e64: "S" -0x1e65: "s" -0x1e66: "S" -0x1e67: "s" -0x1e68: "S" -0x1e69: "s" -0x1e6a: "T" -0x1e6b: "t" -0x1e6c: "T" -0x1e6d: "t" -0x1e6e: "T" -0x1e6f: "t" -0x1e70: "T" -0x1e71: "t" -0x1e72: "U" -0x1e73: "u" -0x1e74: "U" -0x1e75: "u" -0x1e76: "U" -0x1e77: "u" -0x1e78: "U" -0x1e79: "u" -0x1e7a: "U" -0x1e7b: "u" -0x1e7c: "V" -0x1e7d: "v" -0x1e7e: "V" -0x1e7f: "v" -0x1e80: "W" -0x1e81: "w" -0x1e82: "W" -0x1e83: "w" -0x1e84: "W" -0x1e85: "w" -0x1e86: "W" -0x1e87: "w" -0x1e88: "W" -0x1e89: "w" -0x1e8a: "X" -0x1e8b: "x" -0x1e8c: "X" -0x1e8d: "x" -0x1e8e: "Y" -0x1e8f: "y" -0x1e90: "Z" -0x1e91: "z" -0x1e92: "Z" -0x1e93: "z" -0x1e94: "Z" -0x1e95: "z" -0x1e96: "h" -0x1e97: "t" -0x1e98: "w" -0x1e99: "y" -0x1e9a: "a" -0x1e9b: "S" -0x1e9c: "[?]" -0x1e9d: "[?]" -0x1e9e: "Ss" -0x1e9f: "[?]" -0x1ea0: "A" -0x1ea1: "a" -0x1ea2: "A" -0x1ea3: "a" -0x1ea4: "A" -0x1ea5: "a" -0x1ea6: "A" -0x1ea7: "a" -0x1ea8: "A" -0x1ea9: "a" -0x1eaa: "A" -0x1eab: "a" -0x1eac: "A" -0x1ead: "a" -0x1eae: "A" -0x1eaf: "a" -0x1eb0: "A" -0x1eb1: "a" -0x1eb2: "A" -0x1eb3: "a" -0x1eb4: "A" -0x1eb5: "a" -0x1eb6: "A" -0x1eb7: "a" -0x1eb8: "E" -0x1eb9: "e" -0x1eba: "E" -0x1ebb: "e" -0x1ebc: "E" -0x1ebd: "e" -0x1ebe: "E" -0x1ebf: "e" -0x1ec0: "E" -0x1ec1: "e" -0x1ec2: "E" -0x1ec3: "e" -0x1ec4: "E" -0x1ec5: "e" -0x1ec6: "E" -0x1ec7: "e" -0x1ec8: "I" -0x1ec9: "i" -0x1eca: "I" -0x1ecb: "i" -0x1ecc: "O" -0x1ecd: "o" -0x1ece: "O" -0x1ecf: "o" -0x1ed0: "O" -0x1ed1: "o" -0x1ed2: "O" -0x1ed3: "o" -0x1ed4: "O" -0x1ed5: "o" -0x1ed6: "O" -0x1ed7: "o" -0x1ed8: "O" -0x1ed9: "o" -0x1eda: "O" -0x1edb: "o" -0x1edc: "O" -0x1edd: "o" -0x1ede: "O" -0x1edf: "o" -0x1ee0: "O" -0x1ee1: "o" -0x1ee2: "O" -0x1ee3: "o" -0x1ee4: "U" -0x1ee5: "u" -0x1ee6: "U" -0x1ee7: "u" -0x1ee8: "U" -0x1ee9: "u" -0x1eea: "U" -0x1eeb: "u" -0x1eec: "U" -0x1eed: "u" -0x1eee: "U" -0x1eef: "u" -0x1ef0: "U" -0x1ef1: "u" -0x1ef2: "Y" -0x1ef3: "y" -0x1ef4: "Y" -0x1ef5: "y" -0x1ef6: "Y" -0x1ef7: "y" -0x1ef8: "Y" -0x1ef9: "y" -0x1efa: "[?]" -0x1efb: "[?]" -0x1efc: "[?]" -0x1efd: "[?]" -0x1efe: "[?]" -/* x01f */ -0x1f00: "a" -0x1f01: "a" -0x1f02: "a" -0x1f03: "a" -0x1f04: "a" -0x1f05: "a" -0x1f06: "a" -0x1f07: "a" -0x1f08: "A" -0x1f09: "A" -0x1f0a: "A" -0x1f0b: "A" -0x1f0c: "A" -0x1f0d: "A" -0x1f0e: "A" -0x1f0f: "A" -0x1f10: "e" -0x1f11: "e" -0x1f12: "e" -0x1f13: "e" -0x1f14: "e" -0x1f15: "e" -0x1f16: "[?]" -0x1f17: "[?]" -0x1f18: "E" -0x1f19: "E" -0x1f1a: "E" -0x1f1b: "E" -0x1f1c: "E" -0x1f1d: "E" -0x1f1e: "[?]" -0x1f1f: "[?]" -0x1f20: "e" -0x1f21: "e" -0x1f22: "e" -0x1f23: "e" -0x1f24: "e" -0x1f25: "e" -0x1f26: "e" -0x1f27: "e" -0x1f28: "E" -0x1f29: "E" -0x1f2a: "E" -0x1f2b: "E" -0x1f2c: "E" -0x1f2d: "E" -0x1f2e: "E" -0x1f2f: "E" -0x1f30: "i" -0x1f31: "i" -0x1f32: "i" -0x1f33: "i" -0x1f34: "i" -0x1f35: "i" -0x1f36: "i" -0x1f37: "i" -0x1f38: "I" -0x1f39: "I" -0x1f3a: "I" -0x1f3b: "I" -0x1f3c: "I" -0x1f3d: "I" -0x1f3e: "I" -0x1f3f: "I" -0x1f40: "o" -0x1f41: "o" -0x1f42: "o" -0x1f43: "o" -0x1f44: "o" -0x1f45: "o" -0x1f46: "[?]" -0x1f47: "[?]" -0x1f48: "O" -0x1f49: "O" -0x1f4a: "O" -0x1f4b: "O" -0x1f4c: "O" -0x1f4d: "O" -0x1f4e: "[?]" -0x1f4f: "[?]" -0x1f50: "u" -0x1f51: "u" -0x1f52: "u" -0x1f53: "u" -0x1f54: "u" -0x1f55: "u" -0x1f56: "u" -0x1f57: "u" -0x1f58: "[?]" -0x1f59: "U" -0x1f5a: "[?]" -0x1f5b: "U" -0x1f5c: "[?]" -0x1f5d: "U" -0x1f5e: "[?]" -0x1f5f: "U" -0x1f60: "o" -0x1f61: "o" -0x1f62: "o" -0x1f63: "o" -0x1f64: "o" -0x1f65: "o" -0x1f66: "o" -0x1f67: "o" -0x1f68: "O" -0x1f69: "O" -0x1f6a: "O" -0x1f6b: "O" -0x1f6c: "O" -0x1f6d: "O" -0x1f6e: "O" -0x1f6f: "O" -0x1f70: "a" -0x1f71: "a" -0x1f72: "e" -0x1f73: "e" -0x1f74: "e" -0x1f75: "e" -0x1f76: "i" -0x1f77: "i" -0x1f78: "o" -0x1f79: "o" -0x1f7a: "u" -0x1f7b: "u" -0x1f7c: "o" -0x1f7d: "o" -0x1f7e: "[?]" -0x1f7f: "[?]" -0x1f80: "a" -0x1f81: "a" -0x1f82: "a" -0x1f83: "a" -0x1f84: "a" -0x1f85: "a" -0x1f86: "a" -0x1f87: "a" -0x1f88: "A" -0x1f89: "A" -0x1f8a: "A" -0x1f8b: "A" -0x1f8c: "A" -0x1f8d: "A" -0x1f8e: "A" -0x1f8f: "A" -0x1f90: "e" -0x1f91: "e" -0x1f92: "e" -0x1f93: "e" -0x1f94: "e" -0x1f95: "e" -0x1f96: "e" -0x1f97: "e" -0x1f98: "E" -0x1f99: "E" -0x1f9a: "E" -0x1f9b: "E" -0x1f9c: "E" -0x1f9d: "E" -0x1f9e: "E" -0x1f9f: "E" -0x1fa0: "o" -0x1fa1: "o" -0x1fa2: "o" -0x1fa3: "o" -0x1fa4: "o" -0x1fa5: "o" -0x1fa6: "o" -0x1fa7: "o" -0x1fa8: "O" -0x1fa9: "O" -0x1faa: "O" -0x1fab: "O" -0x1fac: "O" -0x1fad: "O" -0x1fae: "O" -0x1faf: "O" -0x1fb0: "a" -0x1fb1: "a" -0x1fb2: "a" -0x1fb3: "a" -0x1fb4: "a" -0x1fb5: "[?]" -0x1fb6: "a" -0x1fb7: "a" -0x1fb8: "A" -0x1fb9: "A" -0x1fba: "A" -0x1fbb: "A" -0x1fbc: "A" -0x1fbd: "'" -0x1fbe: "i" -0x1fbf: "'" -0x1fc0: "~" -0x1fc1: "\"~" -0x1fc2: "e" -0x1fc3: "e" -0x1fc4: "e" -0x1fc5: "[?]" -0x1fc6: "e" -0x1fc7: "e" -0x1fc8: "E" -0x1fc9: "E" -0x1fca: "E" -0x1fcb: "E" -0x1fcc: "E" -0x1fcd: "'`" -0x1fce: "''" -0x1fcf: "'~" -0x1fd0: "i" -0x1fd1: "i" -0x1fd2: "i" -0x1fd3: "i" -0x1fd4: "[?]" -0x1fd5: "[?]" -0x1fd6: "i" -0x1fd7: "i" -0x1fd8: "I" -0x1fd9: "I" -0x1fda: "I" -0x1fdb: "I" -0x1fdc: "[?]" -0x1fdd: "`'" -0x1fde: "`'" -0x1fdf: "`~" -0x1fe0: "u" -0x1fe1: "u" -0x1fe2: "u" -0x1fe3: "u" -0x1fe4: "R" -0x1fe5: "R" -0x1fe6: "u" -0x1fe7: "u" -0x1fe8: "U" -0x1fe9: "U" -0x1fea: "U" -0x1feb: "U" -0x1fec: "R" -0x1fed: "\"`" -0x1fee: "\"'" -0x1fef: "`" -0x1ff0: "[?]" -0x1ff1: "[?]" -0x1ff2: "o" -0x1ff3: "o" -0x1ff4: "o" -0x1ff5: "[?]" -0x1ff6: "o" -0x1ff7: "o" -0x1ff8: "O" -0x1ff9: "O" -0x1ffa: "O" -0x1ffb: "O" -0x1ffc: "O" -0x1ffd: "'" -0x1ffe: "`" -/* x020 */ -0x2000: " " -0x2001: " " -0x2002: " " -0x2003: " " -0x2004: " " -0x2005: " " -0x2006: " " -0x2007: " " -0x2008: " " -0x2009: " " -0x200a: " " -0x200b: " " -0x200c: "" -0x200d: "" -0x200e: "" -0x200f: "" -0x2010: "-" -0x2011: "-" -0x2012: "-" -0x2013: "-" -0x2014: "--" -0x2015: "--" -0x2016: "||" -0x2017: "_" -0x2018: "'" -0x2019: "'" -0x201a: "," -0x201b: "'" -0x201c: "\"" -0x201d: "\"" -0x201e: ",," -0x201f: "\"" -0x2020: "+" -0x2021: "++" -0x2022: "*" -0x2023: "*>" -0x2024: "." -0x2025: ".." -0x2026: "..." -0x2027: "." -0x2028: "\n" -0x2029: "\n\n" -0x202a: "" -0x202b: "" -0x202c: "" -0x202d: "" -0x202e: "" -0x202f: " " -0x2030: "%0" -0x2031: "%00" -0x2032: "'" -0x2033: "''" -0x2034: "'''" -0x2035: "`" -0x2036: "``" -0x2037: "```" -0x2038: "^" -0x2039: "<" -0x203a: ">" -0x203b: "*" -0x203c: "!!" -0x203d: "!?" -0x203e: "-" -0x203f: "_" -0x2040: "-" -0x2041: "^" -0x2042: "***" -0x2043: "--" -0x2044: "/" -0x2045: "-[" -0x2046: "]-" -0x2047: "[?]" -0x2048: "?!" -0x2049: "!?" -0x204a: "7" -0x204b: "PP" -0x204c: "(]" -0x204d: "[)" -0x204e: "[?]" -0x204f: "[?]" -0x2050: "[?]" -0x2051: "[?]" -0x2052: "[?]" -0x2053: "[?]" -0x2054: "[?]" -0x2055: "[?]" -0x2056: "[?]" -0x2057: "[?]" -0x2058: "[?]" -0x2059: "[?]" -0x205a: "[?]" -0x205b: "[?]" -0x205c: "[?]" -0x205d: "[?]" -0x205e: "[?]" -0x205f: "[?]" -0x2060: "[?]" -0x2061: "[?]" -0x2062: "[?]" -0x2063: "[?]" -0x2064: "[?]" -0x2065: "[?]" -0x2066: "[?]" -0x2067: "[?]" -0x2068: "[?]" -0x2069: "[?]" -0x206a: "" -0x206b: "" -0x206c: "" -0x206d: "" -0x206e: "" -0x206f: "" -0x2070: "0" -0x2071: "" -0x2072: "" -0x2073: "" -0x2074: "4" -0x2075: "5" -0x2076: "6" -0x2077: "7" -0x2078: "8" -0x2079: "9" -0x207a: "+" -0x207b: "-" -0x207c: "=" -0x207d: "(" -0x207e: ")" -0x207f: "n" -0x2080: "0" -0x2081: "1" -0x2082: "2" -0x2083: "3" -0x2084: "4" -0x2085: "5" -0x2086: "6" -0x2087: "7" -0x2088: "8" -0x2089: "9" -0x208a: "+" -0x208b: "-" -0x208c: "=" -0x208d: "(" -0x208e: ")" -0x208f: "[?]" -0x2090: "[?]" -0x2091: "[?]" -0x2092: "[?]" -0x2093: "[?]" -0x2094: "[?]" -0x2095: "[?]" -0x2096: "[?]" -0x2097: "[?]" -0x2098: "[?]" -0x2099: "[?]" -0x209a: "[?]" -0x209b: "[?]" -0x209c: "[?]" -0x209d: "[?]" -0x209e: "[?]" -0x209f: "[?]" -0x20a0: "ECU" -0x20a1: "CL" -0x20a2: "Cr" -0x20a3: "FF" -0x20a4: "L" -0x20a5: "mil" -0x20a6: "N" -0x20a7: "Pts" -0x20a8: "Rs" -0x20a9: "W" -0x20aa: "NS" -0x20ab: "D" -0x20ac: "EU" -0x20ad: "K" -0x20ae: "T" -0x20af: "Dr" -0x20b0: "[?]" -0x20b1: "[?]" -0x20b2: "[?]" -0x20b3: "[?]" -0x20b4: "[?]" -0x20b5: "[?]" -0x20b6: "[?]" -0x20b7: "[?]" -0x20b8: "[?]" -0x20b9: "[?]" -0x20ba: "[?]" -0x20bb: "[?]" -0x20bc: "[?]" -0x20bd: "[?]" -0x20be: "[?]" -0x20bf: "[?]" -0x20c0: "[?]" -0x20c1: "[?]" -0x20c2: "[?]" -0x20c3: "[?]" -0x20c4: "[?]" -0x20c5: "[?]" -0x20c6: "[?]" -0x20c7: "[?]" -0x20c8: "[?]" -0x20c9: "[?]" -0x20ca: "[?]" -0x20cb: "[?]" -0x20cc: "[?]" -0x20cd: "[?]" -0x20ce: "[?]" -0x20cf: "[?]" -0x20d0: "" -0x20d1: "" -0x20d2: "" -0x20d3: "" -0x20d4: "" -0x20d5: "" -0x20d6: "" -0x20d7: "" -0x20d8: "" -0x20d9: "" -0x20da: "" -0x20db: "" -0x20dc: "" -0x20dd: "" -0x20de: "" -0x20df: "" -0x20e0: "" -0x20e1: "" -0x20e2: "" -0x20e3: "" -0x20e4: "[?]" -0x20e5: "[?]" -0x20e6: "[?]" -0x20e7: "[?]" -0x20e8: "[?]" -0x20e9: "[?]" -0x20ea: "[?]" -0x20eb: "[?]" -0x20ec: "[?]" -0x20ed: "[?]" -0x20ee: "[?]" -0x20ef: "[?]" -0x20f0: "[?]" -0x20f1: "[?]" -0x20f2: "[?]" -0x20f3: "[?]" -0x20f4: "[?]" -0x20f5: "[?]" -0x20f6: "[?]" -0x20f7: "[?]" -0x20f8: "[?]" -0x20f9: "[?]" -0x20fa: "[?]" -0x20fb: "[?]" -0x20fc: "[?]" -0x20fd: "[?]" -0x20fe: "[?]" -/* x021 */ -0x2100: "" -0x2101: "" -0x2102: "" -0x2103: "" -0x2104: "" -0x2105: "" -0x2106: "" -0x2107: "" -0x2108: "" -0x2109: "" -0x210a: "" -0x210b: "" -0x210c: "" -0x210d: "" -0x210e: "" -0x210f: "" -0x2110: "" -0x2111: "" -0x2112: "" -0x2113: "" -0x2114: "" -0x2115: "" -0x2116: "" -0x2117: "" -0x2118: "" -0x2119: "" -0x211a: "" -0x211b: "" -0x211c: "" -0x211d: "" -0x211e: "" -0x211f: "" -0x2120: "" -0x2121: "" -0x2122: "" -0x2123: "" -0x2124: "" -0x2125: "" -0x2126: "" -0x2127: "" -0x2128: "" -0x2129: "" -0x212a: "K" -0x212b: "A" -0x212c: "" -0x212d: "" -0x212e: "" -0x212f: "" -0x2130: "" -0x2131: "" -0x2132: "F" -0x2133: "" -0x2134: "" -0x2135: "" -0x2136: "" -0x2137: "" -0x2138: "" -0x2139: "" -0x213a: "" -0x213b: "[?]" -0x213c: "[?]" -0x213d: "[?]" -0x213e: "[?]" -0x213f: "[?]" -0x2140: "[?]" -0x2141: "[?]" -0x2142: "[?]" -0x2143: "[?]" -0x2144: "[?]" -0x2145: "[?]" -0x2146: "[?]" -0x2147: "[?]" -0x2148: "[?]" -0x2149: "[?]" -0x214a: "[?]" -0x214b: "[?]" -0x214c: "[?]" -0x214d: "[?]" -0x214e: "F" -0x214f: "[?]" -0x2150: "[?]" -0x2151: "[?]" -0x2152: "[?]" -0x2153: " 1/3 " -0x2154: " 2/3 " -0x2155: " 1/5 " -0x2156: " 2/5 " -0x2157: " 3/5 " -0x2158: " 4/5 " -0x2159: " 1/6 " -0x215a: " 5/6 " -0x215b: " 1/8 " -0x215c: " 3/8 " -0x215d: " 5/8 " -0x215e: " 7/8 " -0x215f: " 1/" -0x2160: "I" -0x2161: "II" -0x2162: "III" -0x2163: "IV" -0x2164: "V" -0x2165: "VI" -0x2166: "VII" -0x2167: "VIII" -0x2168: "IX" -0x2169: "X" -0x216a: "XI" -0x216b: "XII" -0x216c: "L" -0x216d: "C" -0x216e: "D" -0x216f: "M" -0x2170: "i" -0x2171: "ii" -0x2172: "iii" -0x2173: "iv" -0x2174: "v" -0x2175: "vi" -0x2176: "vii" -0x2177: "viii" -0x2178: "ix" -0x2179: "x" -0x217a: "xi" -0x217b: "xii" -0x217c: "l" -0x217d: "c" -0x217e: "d" -0x217f: "m" -0x2180: "(D" -0x2181: "D)" -0x2182: "((|))" -0x2183: ")" -0x2184: "[?]" -0x2185: "[?]" -0x2186: "[?]" -0x2187: "[?]" -0x2188: "[?]" -0x2189: "[?]" -0x218a: "[?]" -0x218b: "[?]" -0x218c: "[?]" -0x218d: "[?]" -0x218e: "[?]" -0x218f: "[?]" -0x2190: "-" -0x2191: "|" -0x2192: "-" -0x2193: "|" -0x2194: "-" -0x2195: "|" -0x2196: "\\" -0x2197: "/" -0x2198: "\\" -0x2199: "/" -0x219a: "-" -0x219b: "-" -0x219c: "~" -0x219d: "~" -0x219e: "-" -0x219f: "|" -0x21a0: "-" -0x21a1: "|" -0x21a2: "-" -0x21a3: "-" -0x21a4: "-" -0x21a5: "|" -0x21a6: "-" -0x21a7: "|" -0x21a8: "|" -0x21a9: "-" -0x21aa: "-" -0x21ab: "-" -0x21ac: "-" -0x21ad: "-" -0x21ae: "-" -0x21af: "|" -0x21b0: "|" -0x21b1: "|" -0x21b2: "|" -0x21b3: "|" -0x21b4: "|" -0x21b5: "|" -0x21b6: "^" -0x21b7: "V" -0x21b8: "\\" -0x21b9: "=" -0x21ba: "V" -0x21bb: "^" -0x21bc: "-" -0x21bd: "-" -0x21be: "|" -0x21bf: "|" -0x21c0: "-" -0x21c1: "-" -0x21c2: "|" -0x21c3: "|" -0x21c4: "=" -0x21c5: "|" -0x21c6: "=" -0x21c7: "=" -0x21c8: "|" -0x21c9: "=" -0x21ca: "|" -0x21cb: "=" -0x21cc: "=" -0x21cd: "=" -0x21ce: "=" -0x21cf: "=" -0x21d0: "=" -0x21d1: "|" -0x21d2: "=" -0x21d3: "|" -0x21d4: "=" -0x21d5: "|" -0x21d6: "\\" -0x21d7: "/" -0x21d8: "\\" -0x21d9: "/" -0x21da: "=" -0x21db: "=" -0x21dc: "~" -0x21dd: "~" -0x21de: "|" -0x21df: "|" -0x21e0: "-" -0x21e1: "|" -0x21e2: "-" -0x21e3: "|" -0x21e4: "-" -0x21e5: "-" -0x21e6: "-" -0x21e7: "|" -0x21e8: "-" -0x21e9: "|" -0x21ea: "|" -0x21eb: "|" -0x21ec: "|" -0x21ed: "|" -0x21ee: "|" -0x21ef: "|" -0x21f0: "-" -0x21f1: "\\" -0x21f2: "\\" -0x21f3: "|" -0x21f4: "[?]" -0x21f5: "[?]" -0x21f6: "[?]" -0x21f7: "[?]" -0x21f8: "[?]" -0x21f9: "[?]" -0x21fa: "[?]" -0x21fb: "[?]" -0x21fc: "[?]" -0x21fd: "[?]" -0x21fe: "[?]" -/* x022 */ -0x2200: "[?]" -0x2201: "[?]" -0x2202: "[?]" -0x2203: "[?]" -0x2204: "[?]" -0x2205: "[?]" -0x2206: "[?]" -0x2207: "[?]" -0x2208: "[?]" -0x2209: "[?]" -0x220a: "[?]" -0x220b: "[?]" -0x220c: "[?]" -0x220d: "[?]" -0x220e: "[?]" -0x220f: "[?]" -0x2210: "[?]" -0x2211: "[?]" -0x2212: "[?]" -0x2213: "[?]" -0x2214: "[?]" -0x2215: "[?]" -0x2216: "[?]" -0x2217: "[?]" -0x2218: "[?]" -0x2219: "[?]" -0x221a: "[?]" -0x221b: "[?]" -0x221c: "[?]" -0x221d: "[?]" -0x221e: "[?]" -0x221f: "[?]" -0x2220: "[?]" -0x2221: "[?]" -0x2222: "[?]" -0x2223: "[?]" -0x2224: "[?]" -0x2225: "[?]" -0x2226: "[?]" -0x2227: "[?]" -0x2228: "[?]" -0x2229: "[?]" -0x222a: "[?]" -0x222b: "[?]" -0x222c: "[?]" -0x222d: "[?]" -0x222e: "[?]" -0x222f: "[?]" -0x2230: "[?]" -0x2231: "[?]" -0x2232: "[?]" -0x2233: "[?]" -0x2234: "[?]" -0x2235: "[?]" -0x2236: "[?]" -0x2237: "[?]" -0x2238: "[?]" -0x2239: "[?]" -0x223a: "[?]" -0x223b: "[?]" -0x223c: "[?]" -0x223d: "[?]" -0x223e: "[?]" -0x223f: "[?]" -0x2240: "[?]" -0x2241: "[?]" -0x2242: "[?]" -0x2243: "[?]" -0x2244: "[?]" -0x2245: "[?]" -0x2246: "[?]" -0x2247: "[?]" -0x2248: "[?]" -0x2249: "[?]" -0x224a: "[?]" -0x224b: "[?]" -0x224c: "[?]" -0x224d: "[?]" -0x224e: "[?]" -0x224f: "[?]" -0x2250: "[?]" -0x2251: "[?]" -0x2252: "[?]" -0x2253: "[?]" -0x2254: "[?]" -0x2255: "[?]" -0x2256: "[?]" -0x2257: "[?]" -0x2258: "[?]" -0x2259: "[?]" -0x225a: "[?]" -0x225b: "[?]" -0x225c: "[?]" -0x225d: "[?]" -0x225e: "[?]" -0x225f: "[?]" -0x2260: "[?]" -0x2261: "[?]" -0x2262: "[?]" -0x2263: "[?]" -0x2264: "[?]" -0x2265: "[?]" -0x2266: "[?]" -0x2267: "[?]" -0x2268: "[?]" -0x2269: "[?]" -0x226a: "[?]" -0x226b: "[?]" -0x226c: "[?]" -0x226d: "[?]" -0x226e: "[?]" -0x226f: "[?]" -0x2270: "[?]" -0x2271: "[?]" -0x2272: "[?]" -0x2273: "[?]" -0x2274: "[?]" -0x2275: "[?]" -0x2276: "[?]" -0x2277: "[?]" -0x2278: "[?]" -0x2279: "[?]" -0x227a: "[?]" -0x227b: "[?]" -0x227c: "[?]" -0x227d: "[?]" -0x227e: "[?]" -0x227f: "[?]" -0x2280: "[?]" -0x2281: "[?]" -0x2282: "[?]" -0x2283: "[?]" -0x2284: "[?]" -0x2285: "[?]" -0x2286: "[?]" -0x2287: "[?]" -0x2288: "[?]" -0x2289: "[?]" -0x228a: "[?]" -0x228b: "[?]" -0x228c: "[?]" -0x228d: "[?]" -0x228e: "[?]" -0x228f: "[?]" -0x2290: "[?]" -0x2291: "[?]" -0x2292: "[?]" -0x2293: "[?]" -0x2294: "[?]" -0x2295: "[?]" -0x2296: "[?]" -0x2297: "[?]" -0x2298: "[?]" -0x2299: "[?]" -0x229a: "[?]" -0x229b: "[?]" -0x229c: "[?]" -0x229d: "[?]" -0x229e: "[?]" -0x229f: "[?]" -0x22a0: "[?]" -0x22a1: "[?]" -0x22a2: "[?]" -0x22a3: "[?]" -0x22a4: "[?]" -0x22a5: "[?]" -0x22a6: "[?]" -0x22a7: "[?]" -0x22a8: "[?]" -0x22a9: "[?]" -0x22aa: "[?]" -0x22ab: "[?]" -0x22ac: "[?]" -0x22ad: "[?]" -0x22ae: "[?]" -0x22af: "[?]" -0x22b0: "[?]" -0x22b1: "[?]" -0x22b2: "[?]" -0x22b3: "[?]" -0x22b4: "[?]" -0x22b5: "[?]" -0x22b6: "[?]" -0x22b7: "[?]" -0x22b8: "[?]" -0x22b9: "[?]" -0x22ba: "[?]" -0x22bb: "[?]" -0x22bc: "[?]" -0x22bd: "[?]" -0x22be: "[?]" -0x22bf: "[?]" -0x22c0: "[?]" -0x22c1: "[?]" -0x22c2: "[?]" -0x22c3: "[?]" -0x22c4: "[?]" -0x22c5: "[?]" -0x22c6: "[?]" -0x22c7: "[?]" -0x22c8: "[?]" -0x22c9: "[?]" -0x22ca: "[?]" -0x22cb: "[?]" -0x22cc: "[?]" -0x22cd: "[?]" -0x22ce: "[?]" -0x22cf: "[?]" -0x22d0: "[?]" -0x22d1: "[?]" -0x22d2: "[?]" -0x22d3: "[?]" -0x22d4: "[?]" -0x22d5: "[?]" -0x22d6: "[?]" -0x22d7: "[?]" -0x22d8: "[?]" -0x22d9: "[?]" -0x22da: "[?]" -0x22db: "[?]" -0x22dc: "[?]" -0x22dd: "[?]" -0x22de: "[?]" -0x22df: "[?]" -0x22e0: "[?]" -0x22e1: "[?]" -0x22e2: "[?]" -0x22e3: "[?]" -0x22e4: "[?]" -0x22e5: "[?]" -0x22e6: "[?]" -0x22e7: "[?]" -0x22e8: "[?]" -0x22e9: "[?]" -0x22ea: "[?]" -0x22eb: "[?]" -0x22ec: "[?]" -0x22ed: "[?]" -0x22ee: "[?]" -0x22ef: "[?]" -0x22f0: "[?]" -0x22f1: "[?]" -0x22f2: "[?]" -0x22f3: "[?]" -0x22f4: "[?]" -0x22f5: "[?]" -0x22f6: "[?]" -0x22f7: "[?]" -0x22f8: "[?]" -0x22f9: "[?]" -0x22fa: "[?]" -0x22fb: "[?]" -0x22fc: "[?]" -0x22fd: "[?]" -0x22fe: "[?]" -/* x023 */ -0x2300: "[?]" -0x2301: "[?]" -0x2302: "[?]" -0x2303: "[?]" -0x2304: "[?]" -0x2305: "[?]" -0x2306: "[?]" -0x2307: "[?]" -0x2308: "[?]" -0x2309: "[?]" -0x230a: "[?]" -0x230b: "[?]" -0x230c: "[?]" -0x230d: "[?]" -0x230e: "[?]" -0x230f: "[?]" -0x2310: "[?]" -0x2311: "[?]" -0x2312: "[?]" -0x2313: "[?]" -0x2314: "[?]" -0x2315: "[?]" -0x2316: "[?]" -0x2317: "[?]" -0x2318: "[?]" -0x2319: "[?]" -0x231a: "[?]" -0x231b: "[?]" -0x231c: "[?]" -0x231d: "[?]" -0x231e: "[?]" -0x231f: "[?]" -0x2320: "[?]" -0x2321: "[?]" -0x2322: "[?]" -0x2323: "[?]" -0x2324: "[?]" -0x2325: "[?]" -0x2326: "[?]" -0x2327: "[?]" -0x2328: "[?]" -0x2329: "[?]" -0x232a: "[?]" -0x232b: "[?]" -0x232c: "[?]" -0x232d: "[?]" -0x232e: "[?]" -0x232f: "[?]" -0x2330: "[?]" -0x2331: "[?]" -0x2332: "[?]" -0x2333: "[?]" -0x2334: "[?]" -0x2335: "[?]" -0x2336: "[?]" -0x2337: "[?]" -0x2338: "[?]" -0x2339: "[?]" -0x233a: "[?]" -0x233b: "[?]" -0x233c: "[?]" -0x233d: "[?]" -0x233e: "[?]" -0x233f: "[?]" -0x2340: "[?]" -0x2341: "[?]" -0x2342: "[?]" -0x2343: "[?]" -0x2344: "[?]" -0x2345: "[?]" -0x2346: "[?]" -0x2347: "[?]" -0x2348: "[?]" -0x2349: "[?]" -0x234a: "[?]" -0x234b: "[?]" -0x234c: "[?]" -0x234d: "[?]" -0x234e: "[?]" -0x234f: "[?]" -0x2350: "[?]" -0x2351: "[?]" -0x2352: "[?]" -0x2353: "[?]" -0x2354: "[?]" -0x2355: "[?]" -0x2356: "[?]" -0x2357: "[?]" -0x2358: "[?]" -0x2359: "[?]" -0x235a: "[?]" -0x235b: "[?]" -0x235c: "[?]" -0x235d: "[?]" -0x235e: "[?]" -0x235f: "[?]" -0x2360: "[?]" -0x2361: "[?]" -0x2362: "[?]" -0x2363: "[?]" -0x2364: "[?]" -0x2365: "[?]" -0x2366: "[?]" -0x2367: "[?]" -0x2368: "[?]" -0x2369: "[?]" -0x236a: "[?]" -0x236b: "[?]" -0x236c: "[?]" -0x236d: "[?]" -0x236e: "[?]" -0x236f: "[?]" -0x2370: "[?]" -0x2371: "[?]" -0x2372: "[?]" -0x2373: "[?]" -0x2374: "[?]" -0x2375: "[?]" -0x2376: "[?]" -0x2377: "[?]" -0x2378: "[?]" -0x2379: "[?]" -0x237a: "[?]" -0x237b: "[?]" -0x237c: "[?]" -0x237d: "[?]" -0x237e: "[?]" -0x237f: "[?]" -0x2380: "[?]" -0x2381: "[?]" -0x2382: "[?]" -0x2383: "[?]" -0x2384: "[?]" -0x2385: "[?]" -0x2386: "[?]" -0x2387: "[?]" -0x2388: "[?]" -0x2389: "[?]" -0x238a: "[?]" -0x238b: "[?]" -0x238c: "[?]" -0x238d: "[?]" -0x238e: "[?]" -0x238f: "[?]" -0x2390: "[?]" -0x2391: "[?]" -0x2392: "[?]" -0x2393: "[?]" -0x2394: "[?]" -0x2395: "[?]" -0x2396: "[?]" -0x2397: "[?]" -0x2398: "[?]" -0x2399: "[?]" -0x239a: "[?]" -0x239b: "[?]" -0x239c: "[?]" -0x239d: "[?]" -0x239e: "[?]" -0x239f: "[?]" -0x23a0: "[?]" -0x23a1: "[?]" -0x23a2: "[?]" -0x23a3: "[?]" -0x23a4: "[?]" -0x23a5: "[?]" -0x23a6: "[?]" -0x23a7: "[?]" -0x23a8: "[?]" -0x23a9: "[?]" -0x23aa: "[?]" -0x23ab: "[?]" -0x23ac: "[?]" -0x23ad: "[?]" -0x23ae: "[?]" -0x23af: "[?]" -0x23b0: "[?]" -0x23b1: "[?]" -0x23b2: "[?]" -0x23b3: "[?]" -0x23b4: "[?]" -0x23b5: "[?]" -0x23b6: "[?]" -0x23b7: "[?]" -0x23b8: "[?]" -0x23b9: "[?]" -0x23ba: "[?]" -0x23bb: "[?]" -0x23bc: "[?]" -0x23bd: "[?]" -0x23be: "[?]" -0x23bf: "[?]" -0x23c0: "[?]" -0x23c1: "[?]" -0x23c2: "[?]" -0x23c3: "[?]" -0x23c4: "[?]" -0x23c5: "[?]" -0x23c6: "[?]" -0x23c7: "[?]" -0x23c8: "[?]" -0x23c9: "[?]" -0x23ca: "[?]" -0x23cb: "[?]" -0x23cc: "[?]" -0x23cd: "[?]" -0x23ce: "[?]" -0x23cf: "[?]" -0x23d0: "[?]" -0x23d1: "[?]" -0x23d2: "[?]" -0x23d3: "[?]" -0x23d4: "[?]" -0x23d5: "[?]" -0x23d6: "[?]" -0x23d7: "[?]" -0x23d8: "[?]" -0x23d9: "[?]" -0x23da: "[?]" -0x23db: "[?]" -0x23dc: "[?]" -0x23dd: "[?]" -0x23de: "[?]" -0x23df: "[?]" -0x23e0: "[?]" -0x23e1: "[?]" -0x23e2: "[?]" -0x23e3: "[?]" -0x23e4: "[?]" -0x23e5: "[?]" -0x23e6: "[?]" -0x23e7: "[?]" -0x23e8: "[?]" -0x23e9: "[?]" -0x23ea: "[?]" -0x23eb: "[?]" -0x23ec: "[?]" -0x23ed: "[?]" -0x23ee: "[?]" -0x23ef: "[?]" -0x23f0: "[?]" -0x23f1: "[?]" -0x23f2: "[?]" -0x23f3: "[?]" -0x23f4: "[?]" -0x23f5: "[?]" -0x23f6: "[?]" -0x23f7: "[?]" -0x23f8: "[?]" -0x23f9: "[?]" -0x23fa: "[?]" -0x23fb: "[?]" -0x23fc: "[?]" -0x23fd: "[?]" -0x23fe: "[?]" -/* x024 */ -0x2400: "" -0x2401: "" -0x2402: "" -0x2403: "" -0x2404: "" -0x2405: "" -0x2406: "" -0x2407: "" -0x2408: "" -0x2409: "" -0x240a: "" -0x240b: "" -0x240c: "" -0x240d: "" -0x240e: "" -0x240f: "" -0x2410: "" -0x2411: "" -0x2412: "" -0x2413: "" -0x2414: "" -0x2415: "" -0x2416: "" -0x2417: "" -0x2418: "" -0x2419: "" -0x241a: "" -0x241b: "" -0x241c: "" -0x241d: "" -0x241e: "" -0x241f: "" -0x2420: "" -0x2421: "" -0x2422: "" -0x2423: "" -0x2424: "" -0x2425: "" -0x2426: "" -0x2427: "[?]" -0x2428: "[?]" -0x2429: "[?]" -0x242a: "[?]" -0x242b: "[?]" -0x242c: "[?]" -0x242d: "[?]" -0x242e: "[?]" -0x242f: "[?]" -0x2430: "[?]" -0x2431: "[?]" -0x2432: "[?]" -0x2433: "[?]" -0x2434: "[?]" -0x2435: "[?]" -0x2436: "[?]" -0x2437: "[?]" -0x2438: "[?]" -0x2439: "[?]" -0x243a: "[?]" -0x243b: "[?]" -0x243c: "[?]" -0x243d: "[?]" -0x243e: "[?]" -0x243f: "[?]" -0x2440: "" -0x2441: "" -0x2442: "" -0x2443: "" -0x2444: "" -0x2445: "" -0x2446: "" -0x2447: "" -0x2448: "" -0x2449: "" -0x244a: "" -0x244b: "[?]" -0x244c: "[?]" -0x244d: "[?]" -0x244e: "[?]" -0x244f: "[?]" -0x2450: "[?]" -0x2451: "[?]" -0x2452: "[?]" -0x2453: "[?]" -0x2454: "[?]" -0x2455: "[?]" -0x2456: "[?]" -0x2457: "[?]" -0x2458: "[?]" -0x2459: "[?]" -0x245a: "[?]" -0x245b: "[?]" -0x245c: "[?]" -0x245d: "[?]" -0x245e: "[?]" -0x245f: "[?]" -0x2460: "" -0x2461: "" -0x2462: "" -0x2463: "" -0x2464: "" -0x2465: "" -0x2466: "" -0x2467: "" -0x2468: "" -0x2469: "" -0x246a: "" -0x246b: "" -0x246c: "" -0x246d: "" -0x246e: "" -0x246f: "" -0x2470: "" -0x2471: "" -0x2472: "" -0x2473: "" -0x2474: "" -0x2475: "" -0x2476: "" -0x2477: "" -0x2478: "" -0x2479: "" -0x247a: "" -0x247b: "" -0x247c: "" -0x247d: "" -0x247e: "" -0x247f: "" -0x2480: "" -0x2481: "" -0x2482: "" -0x2483: "" -0x2484: "" -0x2485: "" -0x2486: "" -0x2487: "" -0x2488: "" -0x2489: "" -0x248a: "" -0x248b: "" -0x248c: "" -0x248d: "" -0x248e: "" -0x248f: "" -0x2490: "" -0x2491: "" -0x2492: "" -0x2493: "" -0x2494: "" -0x2495: "" -0x2496: "" -0x2497: "" -0x2498: "" -0x2499: "" -0x249a: "" -0x249b: "" -0x249c: "" -0x249d: "" -0x249e: "" -0x249f: "" -0x24a0: "" -0x24a1: "" -0x24a2: "" -0x24a3: "" -0x24a4: "" -0x24a5: "" -0x24a6: "" -0x24a7: "" -0x24a8: "" -0x24a9: "" -0x24aa: "" -0x24ab: "" -0x24ac: "" -0x24ad: "" -0x24ae: "" -0x24af: "" -0x24b0: "" -0x24b1: "" -0x24b2: "" -0x24b3: "" -0x24b4: "" -0x24b5: "" -0x24b6: "" -0x24b7: "" -0x24b8: "" -0x24b9: "" -0x24ba: "" -0x24bb: "" -0x24bc: "" -0x24bd: "" -0x24be: "" -0x24bf: "" -0x24c0: "" -0x24c1: "" -0x24c2: "" -0x24c3: "" -0x24c4: "" -0x24c5: "" -0x24c6: "" -0x24c7: "" -0x24c8: "" -0x24c9: "" -0x24ca: "" -0x24cb: "" -0x24cc: "" -0x24cd: "" -0x24ce: "" -0x24cf: "" -0x24d0: "a" -0x24d1: "b" -0x24d2: "c" -0x24d3: "d" -0x24d4: "e" -0x24d5: "f" -0x24d6: "g" -0x24d7: "h" -0x24d8: "i" -0x24d9: "j" -0x24da: "k" -0x24db: "l" -0x24dc: "m" -0x24dd: "n" -0x24de: "o" -0x24df: "p" -0x24e0: "q" -0x24e1: "r" -0x24e2: "s" -0x24e3: "t" -0x24e4: "u" -0x24e5: "v" -0x24e6: "w" -0x24e7: "x" -0x24e8: "y" -0x24e9: "z" -0x24ea: "0" -0x24eb: "[?]" -0x24ec: "[?]" -0x24ed: "[?]" -0x24ee: "[?]" -0x24ef: "[?]" -0x24f0: "[?]" -0x24f1: "[?]" -0x24f2: "[?]" -0x24f3: "[?]" -0x24f4: "[?]" -0x24f5: "[?]" -0x24f6: "[?]" -0x24f7: "[?]" -0x24f8: "[?]" -0x24f9: "[?]" -0x24fa: "[?]" -0x24fb: "[?]" -0x24fc: "[?]" -0x24fd: "[?]" -0x24fe: "[?]" -/* x025 */ -0x2500: "-" -0x2501: "-" -0x2502: "|" -0x2503: "|" -0x2504: "-" -0x2505: "-" -0x2506: "|" -0x2507: "|" -0x2508: "-" -0x2509: "-" -0x250a: "|" -0x250b: "|" -0x250c: "+" -0x250d: "+" -0x250e: "+" -0x250f: "+" -0x2510: "+" -0x2511: "+" -0x2512: "+" -0x2513: "+" -0x2514: "+" -0x2515: "+" -0x2516: "+" -0x2517: "+" -0x2518: "+" -0x2519: "+" -0x251a: "+" -0x251b: "+" -0x251c: "+" -0x251d: "+" -0x251e: "+" -0x251f: "+" -0x2520: "+" -0x2521: "+" -0x2522: "+" -0x2523: "+" -0x2524: "+" -0x2525: "+" -0x2526: "+" -0x2527: "+" -0x2528: "+" -0x2529: "+" -0x252a: "+" -0x252b: "+" -0x252c: "+" -0x252d: "+" -0x252e: "+" -0x252f: "+" -0x2530: "+" -0x2531: "+" -0x2532: "+" -0x2533: "+" -0x2534: "+" -0x2535: "+" -0x2536: "+" -0x2537: "+" -0x2538: "+" -0x2539: "+" -0x253a: "+" -0x253b: "+" -0x253c: "+" -0x253d: "+" -0x253e: "+" -0x253f: "+" -0x2540: "+" -0x2541: "+" -0x2542: "+" -0x2543: "+" -0x2544: "+" -0x2545: "+" -0x2546: "+" -0x2547: "+" -0x2548: "+" -0x2549: "+" -0x254a: "+" -0x254b: "+" -0x254c: "-" -0x254d: "-" -0x254e: "|" -0x254f: "|" -0x2550: "-" -0x2551: "|" -0x2552: "+" -0x2553: "+" -0x2554: "+" -0x2555: "+" -0x2556: "+" -0x2557: "+" -0x2558: "+" -0x2559: "+" -0x255a: "+" -0x255b: "+" -0x255c: "+" -0x255d: "+" -0x255e: "+" -0x255f: "+" -0x2560: "+" -0x2561: "+" -0x2562: "+" -0x2563: "+" -0x2564: "+" -0x2565: "+" -0x2566: "+" -0x2567: "+" -0x2568: "+" -0x2569: "+" -0x256a: "+" -0x256b: "+" -0x256c: "+" -0x256d: "+" -0x256e: "+" -0x256f: "+" -0x2570: "+" -0x2571: "/" -0x2572: "\\" -0x2573: "X" -0x2574: "-" -0x2575: "|" -0x2576: "-" -0x2577: "|" -0x2578: "-" -0x2579: "|" -0x257a: "-" -0x257b: "|" -0x257c: "-" -0x257d: "|" -0x257e: "-" -0x257f: "|" -0x2580: "#" -0x2581: "#" -0x2582: "#" -0x2583: "#" -0x2584: "#" -0x2585: "#" -0x2586: "#" -0x2587: "#" -0x2588: "#" -0x2589: "#" -0x258a: "#" -0x258b: "#" -0x258c: "#" -0x258d: "#" -0x258e: "#" -0x258f: "#" -0x2590: "#" -0x2591: "#" -0x2592: "#" -0x2593: "#" -0x2594: "-" -0x2595: "|" -0x2596: "[?]" -0x2597: "[?]" -0x2598: "[?]" -0x2599: "[?]" -0x259a: "[?]" -0x259b: "[?]" -0x259c: "[?]" -0x259d: "[?]" -0x259e: "[?]" -0x259f: "[?]" -0x25a0: "#" -0x25a1: "#" -0x25a2: "#" -0x25a3: "#" -0x25a4: "#" -0x25a5: "#" -0x25a6: "#" -0x25a7: "#" -0x25a8: "#" -0x25a9: "#" -0x25aa: "#" -0x25ab: "#" -0x25ac: "#" -0x25ad: "#" -0x25ae: "#" -0x25af: "#" -0x25b0: "#" -0x25b1: "#" -0x25b2: "^" -0x25b3: "^" -0x25b4: "^" -0x25b5: "^" -0x25b6: ">" -0x25b7: ">" -0x25b8: ">" -0x25b9: ">" -0x25ba: ">" -0x25bb: ">" -0x25bc: "V" -0x25bd: "V" -0x25be: "V" -0x25bf: "V" -0x25c0: "<" -0x25c1: "<" -0x25c2: "<" -0x25c3: "<" -0x25c4: "<" -0x25c5: "<" -0x25c6: "*" -0x25c7: "*" -0x25c8: "*" -0x25c9: "*" -0x25ca: "*" -0x25cb: "*" -0x25cc: "*" -0x25cd: "*" -0x25ce: "*" -0x25cf: "*" -0x25d0: "*" -0x25d1: "*" -0x25d2: "*" -0x25d3: "*" -0x25d4: "*" -0x25d5: "*" -0x25d6: "*" -0x25d7: "*" -0x25d8: "*" -0x25d9: "*" -0x25da: "*" -0x25db: "*" -0x25dc: "*" -0x25dd: "*" -0x25de: "*" -0x25df: "*" -0x25e0: "*" -0x25e1: "*" -0x25e2: "*" -0x25e3: "*" -0x25e4: "*" -0x25e5: "*" -0x25e6: "*" -0x25e7: "#" -0x25e8: "#" -0x25e9: "#" -0x25ea: "#" -0x25eb: "#" -0x25ec: "^" -0x25ed: "^" -0x25ee: "^" -0x25ef: "O" -0x25f0: "#" -0x25f1: "#" -0x25f2: "#" -0x25f3: "#" -0x25f4: "#" -0x25f5: "#" -0x25f6: "#" -0x25f7: "#" -0x25f8: "[?]" -0x25f9: "[?]" -0x25fa: "[?]" -0x25fb: "[?]" -0x25fc: "[?]" -0x25fd: "[?]" -0x25fe: "[?]" -/* x026 */ -0x2600: "" -0x2601: "" -0x2602: "" -0x2603: "" -0x2604: "" -0x2605: "" -0x2606: "" -0x2607: "" -0x2608: "" -0x2609: "" -0x260a: "" -0x260b: "" -0x260c: "" -0x260d: "" -0x260e: "" -0x260f: "" -0x2610: "" -0x2611: "" -0x2612: "" -0x2613: "" -0x2614: "[?]" -0x2615: "[?]" -0x2616: "[?]" -0x2617: "[?]" -0x2618: "[?]" -0x2619: "" -0x261a: "" -0x261b: "" -0x261c: "" -0x261d: "" -0x261e: "" -0x261f: "" -0x2620: "" -0x2621: "" -0x2622: "" -0x2623: "" -0x2624: "" -0x2625: "" -0x2626: "" -0x2627: "" -0x2628: "" -0x2629: "" -0x262a: "" -0x262b: "" -0x262c: "" -0x262d: "" -0x262e: "" -0x262f: "" -0x2630: "" -0x2631: "" -0x2632: "" -0x2633: "" -0x2634: "" -0x2635: "" -0x2636: "" -0x2637: "" -0x2638: "" -0x2639: "" -0x263a: "" -0x263b: "" -0x263c: "" -0x263d: "" -0x263e: "" -0x263f: "" -0x2640: "" -0x2641: "" -0x2642: "" -0x2643: "" -0x2644: "" -0x2645: "" -0x2646: "" -0x2647: "" -0x2648: "" -0x2649: "" -0x264a: "" -0x264b: "" -0x264c: "" -0x264d: "" -0x264e: "" -0x264f: "" -0x2650: "" -0x2651: "" -0x2652: "" -0x2653: "" -0x2654: "" -0x2655: "" -0x2656: "" -0x2657: "" -0x2658: "" -0x2659: "" -0x265a: "" -0x265b: "" -0x265c: "" -0x265d: "" -0x265e: "" -0x265f: "" -0x2660: "" -0x2661: "" -0x2662: "" -0x2663: "" -0x2664: "" -0x2665: "" -0x2666: "" -0x2667: "" -0x2668: "" -0x2669: "" -0x266a: "" -0x266b: "" -0x266c: "" -0x266d: "" -0x266e: "" -0x266f: "" -0x2670: "" -0x2671: "" -0x2672: "[?]" -0x2673: "[?]" -0x2674: "[?]" -0x2675: "[?]" -0x2676: "[?]" -0x2677: "[?]" -0x2678: "[?]" -0x2679: "[?]" -0x267a: "[?]" -0x267b: "[?]" -0x267c: "[?]" -0x267d: "[?]" -0x267e: "[?]" -0x267f: "[?]" -0x2680: "[?]" -0x2681: "[?]" -0x2682: "[?]" -0x2683: "[?]" -0x2684: "[?]" -0x2685: "[?]" -0x2686: "[?]" -0x2687: "[?]" -0x2688: "[?]" -0x2689: "[?]" -0x268a: "[?]" -0x268b: "[?]" -0x268c: "[?]" -0x268d: "[?]" -0x268e: "[?]" -0x268f: "[?]" -0x2690: "[?]" -0x2691: "[?]" -0x2692: "[?]" -0x2693: "[?]" -0x2694: "[?]" -0x2695: "[?]" -0x2696: "[?]" -0x2697: "[?]" -0x2698: "[?]" -0x2699: "[?]" -0x269a: "[?]" -0x269b: "[?]" -0x269c: "[?]" -0x269d: "[?]" -0x269e: "[?]" -0x269f: "[?]" -0x26a0: "[?]" -0x26a1: "[?]" -0x26a2: "[?]" -0x26a3: "[?]" -0x26a4: "[?]" -0x26a5: "[?]" -0x26a6: "[?]" -0x26a7: "[?]" -0x26a8: "[?]" -0x26a9: "[?]" -0x26aa: "[?]" -0x26ab: "[?]" -0x26ac: "[?]" -0x26ad: "[?]" -0x26ae: "[?]" -0x26af: "[?]" -0x26b0: "[?]" -0x26b1: "[?]" -0x26b2: "[?]" -0x26b3: "[?]" -0x26b4: "[?]" -0x26b5: "[?]" -0x26b6: "[?]" -0x26b7: "[?]" -0x26b8: "[?]" -0x26b9: "[?]" -0x26ba: "[?]" -0x26bb: "[?]" -0x26bc: "[?]" -0x26bd: "[?]" -0x26be: "[?]" -0x26bf: "[?]" -0x26c0: "[?]" -0x26c1: "[?]" -0x26c2: "[?]" -0x26c3: "[?]" -0x26c4: "[?]" -0x26c5: "[?]" -0x26c6: "[?]" -0x26c7: "[?]" -0x26c8: "[?]" -0x26c9: "[?]" -0x26ca: "[?]" -0x26cb: "[?]" -0x26cc: "[?]" -0x26cd: "[?]" -0x26ce: "[?]" -0x26cf: "[?]" -0x26d0: "[?]" -0x26d1: "[?]" -0x26d2: "[?]" -0x26d3: "[?]" -0x26d4: "[?]" -0x26d5: "[?]" -0x26d6: "[?]" -0x26d7: "[?]" -0x26d8: "[?]" -0x26d9: "[?]" -0x26da: "[?]" -0x26db: "[?]" -0x26dc: "[?]" -0x26dd: "[?]" -0x26de: "[?]" -0x26df: "[?]" -0x26e0: "[?]" -0x26e1: "[?]" -0x26e2: "[?]" -0x26e3: "[?]" -0x26e4: "[?]" -0x26e5: "[?]" -0x26e6: "[?]" -0x26e7: "[?]" -0x26e8: "[?]" -0x26e9: "[?]" -0x26ea: "[?]" -0x26eb: "[?]" -0x26ec: "[?]" -0x26ed: "[?]" -0x26ee: "[?]" -0x26ef: "[?]" -0x26f0: "[?]" -0x26f1: "[?]" -0x26f2: "[?]" -0x26f3: "[?]" -0x26f4: "[?]" -0x26f5: "[?]" -0x26f6: "[?]" -0x26f7: "[?]" -0x26f8: "[?]" -0x26f9: "[?]" -0x26fa: "[?]" -0x26fb: "[?]" -0x26fc: "[?]" -0x26fd: "[?]" -0x26fe: "[?]" -/* x027 */ -0x2700: "[?]" -0x2701: "" -0x2702: "" -0x2703: "" -0x2704: "" -0x2705: "" -0x2706: "" -0x2707: "" -0x2708: "" -0x2709: "" -0x270a: "" -0x270b: "" -0x270c: "" -0x270d: "" -0x270e: "" -0x270f: "" -0x2710: "" -0x2711: "" -0x2712: "" -0x2713: "" -0x2714: "" -0x2715: "" -0x2716: "" -0x2717: "" -0x2718: "" -0x2719: "" -0x271a: "" -0x271b: "" -0x271c: "" -0x271d: "" -0x271e: "" -0x271f: "" -0x2720: "" -0x2721: "" -0x2722: "" -0x2723: "" -0x2724: "" -0x2725: "" -0x2726: "" -0x2727: "" -0x2728: "" -0x2729: "" -0x272a: "" -0x272b: "" -0x272c: "" -0x272d: "" -0x272e: "" -0x272f: "" -0x2730: "" -0x2731: "" -0x2732: "" -0x2733: "" -0x2734: "" -0x2735: "" -0x2736: "" -0x2737: "" -0x2738: "" -0x2739: "" -0x273a: "" -0x273b: "" -0x273c: "" -0x273d: "" -0x273e: "" -0x273f: "" -0x2740: "" -0x2741: "" -0x2742: "" -0x2743: "" -0x2744: "" -0x2745: "" -0x2746: "" -0x2747: "" -0x2748: "" -0x2749: "" -0x274a: "" -0x274b: "" -0x274c: "" -0x274d: "" -0x274e: "" -0x274f: "" -0x2750: "" -0x2751: "" -0x2752: "" -0x2753: "" -0x2754: "" -0x2755: "" -0x2756: "" -0x2757: "" -0x2758: "" -0x2759: "" -0x275a: "" -0x275b: "" -0x275c: "" -0x275d: "" -0x275e: "" -0x275f: "[?]" -0x2760: "[?]" -0x2761: "" -0x2762: "" -0x2763: "" -0x2764: "" -0x2765: "" -0x2766: "" -0x2767: "" -0x2768: "" -0x2769: "" -0x276a: "" -0x276b: "" -0x276c: "" -0x276d: "" -0x276e: "" -0x276f: "" -0x2770: "" -0x2771: "" -0x2772: "" -0x2773: "" -0x2774: "" -0x2775: "" -0x2776: "" -0x2777: "" -0x2778: "" -0x2779: "" -0x277a: "" -0x277b: "" -0x277c: "" -0x277d: "" -0x277e: "" -0x277f: "" -0x2780: "" -0x2781: "" -0x2782: "" -0x2783: "" -0x2784: "" -0x2785: "" -0x2786: "" -0x2787: "" -0x2788: "" -0x2789: "" -0x278a: "" -0x278b: "" -0x278c: "" -0x278d: "" -0x278e: "" -0x278f: "" -0x2790: "" -0x2791: "" -0x2792: "" -0x2793: "" -0x2794: "" -0x2795: "" -0x2796: "" -0x2797: "" -0x2798: "" -0x2799: "" -0x279a: "" -0x279b: "" -0x279c: "" -0x279d: "" -0x279e: "" -0x279f: "" -0x27a0: "" -0x27a1: "" -0x27a2: "" -0x27a3: "" -0x27a4: "" -0x27a5: "" -0x27a6: "" -0x27a7: "" -0x27a8: "" -0x27a9: "" -0x27aa: "" -0x27ab: "" -0x27ac: "" -0x27ad: "" -0x27ae: "" -0x27af: "" -0x27b0: "[?]" -0x27b1: "" -0x27b2: "" -0x27b3: "" -0x27b4: "" -0x27b5: "" -0x27b6: "" -0x27b7: "" -0x27b8: "" -0x27b9: "" -0x27ba: "" -0x27bb: "" -0x27bc: "" -0x27bd: "" -0x27be: "" -0x27bf: "[?]" -0x27c0: "[?]" -0x27c1: "[?]" -0x27c2: "[?]" -0x27c3: "[?]" -0x27c4: "[?]" -0x27c5: "[?]" -0x27c6: "[?]" -0x27c7: "[?]" -0x27c8: "[?]" -0x27c9: "[?]" -0x27ca: "[?]" -0x27cb: "[?]" -0x27cc: "[?]" -0x27cd: "[?]" -0x27ce: "[?]" -0x27cf: "[?]" -0x27d0: "[?]" -0x27d1: "[?]" -0x27d2: "[?]" -0x27d3: "[?]" -0x27d4: "[?]" -0x27d5: "[?]" -0x27d6: "[?]" -0x27d7: "[?]" -0x27d8: "[?]" -0x27d9: "[?]" -0x27da: "[?]" -0x27db: "[?]" -0x27dc: "[?]" -0x27dd: "[?]" -0x27de: "[?]" -0x27df: "[?]" -0x27e0: "[?]" -0x27e1: "[?]" -0x27e2: "[?]" -0x27e3: "[?]" -0x27e4: "[?]" -0x27e5: "[?]" -0x27e6: "[?]" -0x27e7: "[?]" -0x27e8: "[?]" -0x27e9: "[?]" -0x27ea: "[?]" -0x27eb: "[?]" -0x27ec: "[?]" -0x27ed: "[?]" -0x27ee: "[?]" -0x27ef: "[?]" -0x27f0: "[?]" -0x27f1: "[?]" -0x27f2: "[?]" -0x27f3: "[?]" -0x27f4: "[?]" -0x27f5: "[?]" -0x27f6: "[?]" -0x27f7: "[?]" -0x27f8: "[?]" -0x27f9: "[?]" -0x27fa: "[?]" -0x27fb: "[?]" -0x27fc: "[?]" -0x27fd: "[?]" -0x27fe: "[?]" -/* x028 */ -0x2800: " " -0x2801: "a" -0x2802: "1" -0x2803: "b" -0x2804: "'" -0x2805: "k" -0x2806: "2" -0x2807: "l" -0x2808: "@" -0x2809: "c" -0x280a: "i" -0x280b: "f" -0x280c: "/" -0x280d: "m" -0x280e: "s" -0x280f: "p" -0x2810: "\"" -0x2811: "e" -0x2812: "3" -0x2813: "h" -0x2814: "9" -0x2815: "o" -0x2816: "6" -0x2817: "r" -0x2818: "^" -0x2819: "d" -0x281a: "j" -0x281b: "g" -0x281c: ">" -0x281d: "n" -0x281e: "t" -0x281f: "q" -0x2820: "," -0x2821: "*" -0x2822: "5" -0x2823: "<" -0x2824: "-" -0x2825: "u" -0x2826: "8" -0x2827: "v" -0x2828: "." -0x2829: "%" -0x282a: "[" -0x282b: "$" -0x282c: "+" -0x282d: "x" -0x282e: "!" -0x282f: "&" -0x2830: ";" -0x2831: ":" -0x2832: "4" -0x2833: "\\" -0x2834: "0" -0x2835: "z" -0x2836: "7" -0x2837: "(" -0x2838: "_" -0x2839: "?" -0x283a: "w" -0x283b: "]" -0x283c: "#" -0x283d: "y" -0x283e: ")" -0x283f: "=" -0x2840: "[d7]" -0x2841: "[d17]" -0x2842: "[d27]" -0x2843: "[d127]" -0x2844: "[d37]" -0x2845: "[d137]" -0x2846: "[d237]" -0x2847: "[d1237]" -0x2848: "[d47]" -0x2849: "[d147]" -0x284a: "[d247]" -0x284b: "[d1247]" -0x284c: "[d347]" -0x284d: "[d1347]" -0x284e: "[d2347]" -0x284f: "[d12347]" -0x2850: "[d57]" -0x2851: "[d157]" -0x2852: "[d257]" -0x2853: "[d1257]" -0x2854: "[d357]" -0x2855: "[d1357]" -0x2856: "[d2357]" -0x2857: "[d12357]" -0x2858: "[d457]" -0x2859: "[d1457]" -0x285a: "[d2457]" -0x285b: "[d12457]" -0x285c: "[d3457]" -0x285d: "[d13457]" -0x285e: "[d23457]" -0x285f: "[d123457]" -0x2860: "[d67]" -0x2861: "[d167]" -0x2862: "[d267]" -0x2863: "[d1267]" -0x2864: "[d367]" -0x2865: "[d1367]" -0x2866: "[d2367]" -0x2867: "[d12367]" -0x2868: "[d467]" -0x2869: "[d1467]" -0x286a: "[d2467]" -0x286b: "[d12467]" -0x286c: "[d3467]" -0x286d: "[d13467]" -0x286e: "[d23467]" -0x286f: "[d123467]" -0x2870: "[d567]" -0x2871: "[d1567]" -0x2872: "[d2567]" -0x2873: "[d12567]" -0x2874: "[d3567]" -0x2875: "[d13567]" -0x2876: "[d23567]" -0x2877: "[d123567]" -0x2878: "[d4567]" -0x2879: "[d14567]" -0x287a: "[d24567]" -0x287b: "[d124567]" -0x287c: "[d34567]" -0x287d: "[d134567]" -0x287e: "[d234567]" -0x287f: "[d1234567]" -0x2880: "[d8]" -0x2881: "[d18]" -0x2882: "[d28]" -0x2883: "[d128]" -0x2884: "[d38]" -0x2885: "[d138]" -0x2886: "[d238]" -0x2887: "[d1238]" -0x2888: "[d48]" -0x2889: "[d148]" -0x288a: "[d248]" -0x288b: "[d1248]" -0x288c: "[d348]" -0x288d: "[d1348]" -0x288e: "[d2348]" -0x288f: "[d12348]" -0x2890: "[d58]" -0x2891: "[d158]" -0x2892: "[d258]" -0x2893: "[d1258]" -0x2894: "[d358]" -0x2895: "[d1358]" -0x2896: "[d2358]" -0x2897: "[d12358]" -0x2898: "[d458]" -0x2899: "[d1458]" -0x289a: "[d2458]" -0x289b: "[d12458]" -0x289c: "[d3458]" -0x289d: "[d13458]" -0x289e: "[d23458]" -0x289f: "[d123458]" -0x28a0: "[d68]" -0x28a1: "[d168]" -0x28a2: "[d268]" -0x28a3: "[d1268]" -0x28a4: "[d368]" -0x28a5: "[d1368]" -0x28a6: "[d2368]" -0x28a7: "[d12368]" -0x28a8: "[d468]" -0x28a9: "[d1468]" -0x28aa: "[d2468]" -0x28ab: "[d12468]" -0x28ac: "[d3468]" -0x28ad: "[d13468]" -0x28ae: "[d23468]" -0x28af: "[d123468]" -0x28b0: "[d568]" -0x28b1: "[d1568]" -0x28b2: "[d2568]" -0x28b3: "[d12568]" -0x28b4: "[d3568]" -0x28b5: "[d13568]" -0x28b6: "[d23568]" -0x28b7: "[d123568]" -0x28b8: "[d4568]" -0x28b9: "[d14568]" -0x28ba: "[d24568]" -0x28bb: "[d124568]" -0x28bc: "[d34568]" -0x28bd: "[d134568]" -0x28be: "[d234568]" -0x28bf: "[d1234568]" -0x28c0: "[d78]" -0x28c1: "[d178]" -0x28c2: "[d278]" -0x28c3: "[d1278]" -0x28c4: "[d378]" -0x28c5: "[d1378]" -0x28c6: "[d2378]" -0x28c7: "[d12378]" -0x28c8: "[d478]" -0x28c9: "[d1478]" -0x28ca: "[d2478]" -0x28cb: "[d12478]" -0x28cc: "[d3478]" -0x28cd: "[d13478]" -0x28ce: "[d23478]" -0x28cf: "[d123478]" -0x28d0: "[d578]" -0x28d1: "[d1578]" -0x28d2: "[d2578]" -0x28d3: "[d12578]" -0x28d4: "[d3578]" -0x28d5: "[d13578]" -0x28d6: "[d23578]" -0x28d7: "[d123578]" -0x28d8: "[d4578]" -0x28d9: "[d14578]" -0x28da: "[d24578]" -0x28db: "[d124578]" -0x28dc: "[d34578]" -0x28dd: "[d134578]" -0x28de: "[d234578]" -0x28df: "[d1234578]" -0x28e0: "[d678]" -0x28e1: "[d1678]" -0x28e2: "[d2678]" -0x28e3: "[d12678]" -0x28e4: "[d3678]" -0x28e5: "[d13678]" -0x28e6: "[d23678]" -0x28e7: "[d123678]" -0x28e8: "[d4678]" -0x28e9: "[d14678]" -0x28ea: "[d24678]" -0x28eb: "[d124678]" -0x28ec: "[d34678]" -0x28ed: "[d134678]" -0x28ee: "[d234678]" -0x28ef: "[d1234678]" -0x28f0: "[d5678]" -0x28f1: "[d15678]" -0x28f2: "[d25678]" -0x28f3: "[d125678]" -0x28f4: "[d35678]" -0x28f5: "[d135678]" -0x28f6: "[d235678]" -0x28f7: "[d1235678]" -0x28f8: "[d45678]" -0x28f9: "[d145678]" -0x28fa: "[d245678]" -0x28fb: "[d1245678]" -0x28fc: "[d345678]" -0x28fd: "[d1345678]" -0x28fe: "[d2345678]" -0x28ff: "[d12345678]" -/* x02c */ -0x2c00: "" -0x2c01: "" -0x2c02: "" -0x2c03: "" -0x2c04: "" -0x2c05: "" -0x2c06: "" -0x2c07: "" -0x2c08: "" -0x2c09: "" -0x2c0a: "" -0x2c0b: "" -0x2c0c: "" -0x2c0d: "" -0x2c0e: "" -0x2c0f: "" -0x2c10: "" -0x2c11: "" -0x2c12: "" -0x2c13: "" -0x2c14: "" -0x2c15: "" -0x2c16: "" -0x2c17: "" -0x2c18: "" -0x2c19: "" -0x2c1a: "" -0x2c1b: "" -0x2c1c: "" -0x2c1d: "" -0x2c1e: "" -0x2c1f: "" -0x2c20: "" -0x2c21: "" -0x2c22: "" -0x2c23: "" -0x2c24: "" -0x2c25: "" -0x2c26: "" -0x2c27: "" -0x2c28: "" -0x2c29: "" -0x2c2a: "" -0x2c2b: "" -0x2c2c: "" -0x2c2d: "" -0x2c2e: "" -0x2c2f: "" -0x2c30: "" -0x2c31: "" -0x2c32: "" -0x2c33: "" -0x2c34: "" -0x2c35: "" -0x2c36: "" -0x2c37: "" -0x2c38: "" -0x2c39: "" -0x2c3a: "" -0x2c3b: "" -0x2c3c: "" -0x2c3d: "" -0x2c3e: "" -0x2c3f: "" -0x2c40: "" -0x2c41: "" -0x2c42: "" -0x2c43: "" -0x2c44: "" -0x2c45: "" -0x2c46: "" -0x2c47: "" -0x2c48: "" -0x2c49: "" -0x2c4a: "" -0x2c4b: "" -0x2c4c: "" -0x2c4d: "" -0x2c4e: "" -0x2c4f: "" -0x2c50: "" -0x2c51: "" -0x2c52: "" -0x2c53: "" -0x2c54: "" -0x2c55: "" -0x2c56: "" -0x2c57: "" -0x2c58: "" -0x2c59: "" -0x2c5a: "" -0x2c5b: "" -0x2c5c: "" -0x2c5d: "" -0x2c5e: "" -0x2c5f: "" -0x2c60: "L" -0x2c61: "l" -0x2c62: "L" -0x2c63: "P" -0x2c64: "R" -0x2c65: "a" -0x2c66: "t" -0x2c67: "H" -0x2c68: "h" -0x2c69: "K" -0x2c6a: "k" -0x2c6b: "Z" -0x2c6c: "z" -0x2c6d: "" -0x2c6e: "M" -0x2c6f: "A" -0x2c70: "" -0x2c71: "" -0x2c72: "" -0x2c73: "" -0x2c74: "" -0x2c75: "" -0x2c76: "" -0x2c77: "" -0x2c78: "" -0x2c79: "" -0x2c7a: "" -0x2c7b: "" -0x2c7c: "" -0x2c7d: "" -0x2c7e: "" -0x2c7f: "" -0x2c80: "" -0x2c81: "" -0x2c82: "" -0x2c83: "" -0x2c84: "" -0x2c85: "" -0x2c86: "" -0x2c87: "" -0x2c88: "" -0x2c89: "" -0x2c8a: "" -0x2c8b: "" -0x2c8c: "" -0x2c8d: "" -0x2c8e: "" -0x2c8f: "" -0x2c90: "" -0x2c91: "" -0x2c92: "" -0x2c93: "" -0x2c94: "" -0x2c95: "" -0x2c96: "" -0x2c97: "" -0x2c98: "" -0x2c99: "" -0x2c9a: "" -0x2c9b: "" -0x2c9c: "" -0x2c9d: "" -0x2c9e: "" -0x2c9f: "" -0x2ca0: "" -0x2ca1: "" -0x2ca2: "" -0x2ca3: "" -0x2ca4: "" -0x2ca5: "" -0x2ca6: "" -0x2ca7: "" -0x2ca8: "" -0x2ca9: "" -0x2caa: "" -0x2cab: "" -0x2cac: "" -0x2cad: "" -0x2cae: "" -0x2caf: "" -0x2cb0: "" -0x2cb1: "" -0x2cb2: "" -0x2cb3: "" -0x2cb4: "" -0x2cb5: "" -0x2cb6: "" -0x2cb7: "" -0x2cb8: "" -0x2cb9: "" -0x2cba: "" -0x2cbb: "" -0x2cbc: "" -0x2cbd: "" -0x2cbe: "" -0x2cbf: "" -0x2cc0: "" -0x2cc1: "" -0x2cc2: "" -0x2cc3: "" -0x2cc4: "" -0x2cc5: "" -0x2cc6: "" -0x2cc7: "" -0x2cc8: "" -0x2cc9: "" -0x2cca: "" -0x2ccb: "" -0x2ccc: "" -0x2ccd: "" -0x2cce: "" -0x2ccf: "" -0x2cd0: "" -0x2cd1: "" -0x2cd2: "" -0x2cd3: "" -0x2cd4: "" -0x2cd5: "" -0x2cd6: "" -0x2cd7: "" -0x2cd8: "" -0x2cd9: "" -0x2cda: "" -0x2cdb: "" -0x2cdc: "" -0x2cdd: "" -0x2cde: "" -0x2cdf: "" -0x2ce0: "" -0x2ce1: "" -0x2ce2: "" -0x2ce3: "" -0x2ce4: "" -0x2ce5: "" -0x2ce6: "" -0x2ce7: "" -0x2ce8: "" -0x2ce9: "" -0x2cea: "" -0x2ceb: "" -0x2cec: "" -0x2ced: "" -0x2cee: "" -0x2cef: "" -0x2cf0: "" -0x2cf1: "" -0x2cf2: "" -0x2cf3: "" -0x2cf4: "" -0x2cf5: "" -0x2cf6: "" -0x2cf7: "" -0x2cf8: "" -0x2cf9: "" -0x2cfa: "" -0x2cfb: "" -0x2cfc: "" -0x2cfd: "" -0x2cfe: "" -/* x02e */ -0x2e00: "[?]" -0x2e01: "[?]" -0x2e02: "[?]" -0x2e03: "[?]" -0x2e04: "[?]" -0x2e05: "[?]" -0x2e06: "[?]" -0x2e07: "[?]" -0x2e08: "[?]" -0x2e09: "[?]" -0x2e0a: "[?]" -0x2e0b: "[?]" -0x2e0c: "[?]" -0x2e0d: "[?]" -0x2e0e: "[?]" -0x2e0f: "[?]" -0x2e10: "[?]" -0x2e11: "[?]" -0x2e12: "[?]" -0x2e13: "[?]" -0x2e14: "[?]" -0x2e15: "[?]" -0x2e16: "[?]" -0x2e17: "[?]" -0x2e18: "[?]" -0x2e19: "[?]" -0x2e1a: "[?]" -0x2e1b: "[?]" -0x2e1c: "[?]" -0x2e1d: "[?]" -0x2e1e: "[?]" -0x2e1f: "[?]" -0x2e20: "[?]" -0x2e21: "[?]" -0x2e22: "[?]" -0x2e23: "[?]" -0x2e24: "[?]" -0x2e25: "[?]" -0x2e26: "[?]" -0x2e27: "[?]" -0x2e28: "[?]" -0x2e29: "[?]" -0x2e2a: "[?]" -0x2e2b: "[?]" -0x2e2c: "[?]" -0x2e2d: "[?]" -0x2e2e: "[?]" -0x2e2f: "[?]" -0x2e30: "[?]" -0x2e31: "[?]" -0x2e32: "[?]" -0x2e33: "[?]" -0x2e34: "[?]" -0x2e35: "[?]" -0x2e36: "[?]" -0x2e37: "[?]" -0x2e38: "[?]" -0x2e39: "[?]" -0x2e3a: "[?]" -0x2e3b: "[?]" -0x2e3c: "[?]" -0x2e3d: "[?]" -0x2e3e: "[?]" -0x2e3f: "[?]" -0x2e40: "[?]" -0x2e41: "[?]" -0x2e42: "[?]" -0x2e43: "[?]" -0x2e44: "[?]" -0x2e45: "[?]" -0x2e46: "[?]" -0x2e47: "[?]" -0x2e48: "[?]" -0x2e49: "[?]" -0x2e4a: "[?]" -0x2e4b: "[?]" -0x2e4c: "[?]" -0x2e4d: "[?]" -0x2e4e: "[?]" -0x2e4f: "[?]" -0x2e50: "[?]" -0x2e51: "[?]" -0x2e52: "[?]" -0x2e53: "[?]" -0x2e54: "[?]" -0x2e55: "[?]" -0x2e56: "[?]" -0x2e57: "[?]" -0x2e58: "[?]" -0x2e59: "[?]" -0x2e5a: "[?]" -0x2e5b: "[?]" -0x2e5c: "[?]" -0x2e5d: "[?]" -0x2e5e: "[?]" -0x2e5f: "[?]" -0x2e60: "[?]" -0x2e61: "[?]" -0x2e62: "[?]" -0x2e63: "[?]" -0x2e64: "[?]" -0x2e65: "[?]" -0x2e66: "[?]" -0x2e67: "[?]" -0x2e68: "[?]" -0x2e69: "[?]" -0x2e6a: "[?]" -0x2e6b: "[?]" -0x2e6c: "[?]" -0x2e6d: "[?]" -0x2e6e: "[?]" -0x2e6f: "[?]" -0x2e70: "[?]" -0x2e71: "[?]" -0x2e72: "[?]" -0x2e73: "[?]" -0x2e74: "[?]" -0x2e75: "[?]" -0x2e76: "[?]" -0x2e77: "[?]" -0x2e78: "[?]" -0x2e79: "[?]" -0x2e7a: "[?]" -0x2e7b: "[?]" -0x2e7c: "[?]" -0x2e7d: "[?]" -0x2e7e: "[?]" -0x2e7f: "[?]" -0x2e80: "[?] " -0x2e81: "[?] " -0x2e82: "[?] " -0x2e83: "[?] " -0x2e84: "[?] " -0x2e85: "[?] " -0x2e86: "[?] " -0x2e87: "[?] " -0x2e88: "[?] " -0x2e89: "[?] " -0x2e8a: "[?] " -0x2e8b: "[?] " -0x2e8c: "[?] " -0x2e8d: "[?] " -0x2e8e: "[?] " -0x2e8f: "[?] " -0x2e90: "[?] " -0x2e91: "[?] " -0x2e92: "[?] " -0x2e93: "[?] " -0x2e94: "[?] " -0x2e95: "[?] " -0x2e96: "[?] " -0x2e97: "[?] " -0x2e98: "[?] " -0x2e99: "[?] " -0x2e9a: "[?]" -0x2e9b: "[?] " -0x2e9c: "[?] " -0x2e9d: "[?] " -0x2e9e: "[?] " -0x2e9f: "[?] " -0x2ea0: "[?] " -0x2ea1: "[?] " -0x2ea2: "[?] " -0x2ea3: "[?] " -0x2ea4: "[?] " -0x2ea5: "[?] " -0x2ea6: "[?] " -0x2ea7: "[?] " -0x2ea8: "[?] " -0x2ea9: "[?] " -0x2eaa: "[?] " -0x2eab: "[?] " -0x2eac: "[?] " -0x2ead: "[?] " -0x2eae: "[?] " -0x2eaf: "[?] " -0x2eb0: "[?] " -0x2eb1: "[?] " -0x2eb2: "[?] " -0x2eb3: "[?] " -0x2eb4: "[?] " -0x2eb5: "[?] " -0x2eb6: "[?] " -0x2eb7: "[?] " -0x2eb8: "[?] " -0x2eb9: "[?] " -0x2eba: "[?] " -0x2ebb: "[?] " -0x2ebc: "[?] " -0x2ebd: "[?] " -0x2ebe: "[?] " -0x2ebf: "[?] " -0x2ec0: "[?] " -0x2ec1: "[?] " -0x2ec2: "[?] " -0x2ec3: "[?] " -0x2ec4: "[?] " -0x2ec5: "[?] " -0x2ec6: "[?] " -0x2ec7: "[?] " -0x2ec8: "[?] " -0x2ec9: "[?] " -0x2eca: "[?] " -0x2ecb: "[?] " -0x2ecc: "[?] " -0x2ecd: "[?] " -0x2ece: "[?] " -0x2ecf: "[?] " -0x2ed0: "[?] " -0x2ed1: "[?] " -0x2ed2: "[?] " -0x2ed3: "[?] " -0x2ed4: "[?] " -0x2ed5: "[?] " -0x2ed6: "[?] " -0x2ed7: "[?] " -0x2ed8: "[?] " -0x2ed9: "[?] " -0x2eda: "[?] " -0x2edb: "[?] " -0x2edc: "[?] " -0x2edd: "[?] " -0x2ede: "[?] " -0x2edf: "[?] " -0x2ee0: "[?] " -0x2ee1: "[?] " -0x2ee2: "[?] " -0x2ee3: "[?] " -0x2ee4: "[?] " -0x2ee5: "[?] " -0x2ee6: "[?] " -0x2ee7: "[?] " -0x2ee8: "[?] " -0x2ee9: "[?] " -0x2eea: "[?] " -0x2eeb: "[?] " -0x2eec: "[?] " -0x2eed: "[?] " -0x2eee: "[?] " -0x2eef: "[?] " -0x2ef0: "[?] " -0x2ef1: "[?] " -0x2ef2: "[?] " -0x2ef3: "[?] " -0x2ef4: "[?]" -0x2ef5: "[?]" -0x2ef6: "[?]" -0x2ef7: "[?]" -0x2ef8: "[?]" -0x2ef9: "[?]" -0x2efa: "[?]" -0x2efb: "[?]" -0x2efc: "[?]" -0x2efd: "[?]" -0x2efe: "[?]" -/* x02f */ -0x2f00: "[?] " -0x2f01: "[?] " -0x2f02: "[?] " -0x2f03: "[?] " -0x2f04: "[?] " -0x2f05: "[?] " -0x2f06: "[?] " -0x2f07: "[?] " -0x2f08: "[?] " -0x2f09: "[?] " -0x2f0a: "[?] " -0x2f0b: "[?] " -0x2f0c: "[?] " -0x2f0d: "[?] " -0x2f0e: "[?] " -0x2f0f: "[?] " -0x2f10: "[?] " -0x2f11: "[?] " -0x2f12: "[?] " -0x2f13: "[?] " -0x2f14: "[?] " -0x2f15: "[?] " -0x2f16: "[?] " -0x2f17: "[?] " -0x2f18: "[?] " -0x2f19: "[?] " -0x2f1a: "[?] " -0x2f1b: "[?] " -0x2f1c: "[?] " -0x2f1d: "[?] " -0x2f1e: "[?] " -0x2f1f: "[?] " -0x2f20: "[?] " -0x2f21: "[?] " -0x2f22: "[?] " -0x2f23: "[?] " -0x2f24: "[?] " -0x2f25: "[?] " -0x2f26: "[?] " -0x2f27: "[?] " -0x2f28: "[?] " -0x2f29: "[?] " -0x2f2a: "[?] " -0x2f2b: "[?] " -0x2f2c: "[?] " -0x2f2d: "[?] " -0x2f2e: "[?] " -0x2f2f: "[?] " -0x2f30: "[?] " -0x2f31: "[?] " -0x2f32: "[?] " -0x2f33: "[?] " -0x2f34: "[?] " -0x2f35: "[?] " -0x2f36: "[?] " -0x2f37: "[?] " -0x2f38: "[?] " -0x2f39: "[?] " -0x2f3a: "[?] " -0x2f3b: "[?] " -0x2f3c: "[?] " -0x2f3d: "[?] " -0x2f3e: "[?] " -0x2f3f: "[?] " -0x2f40: "[?] " -0x2f41: "[?] " -0x2f42: "[?] " -0x2f43: "[?] " -0x2f44: "[?] " -0x2f45: "[?] " -0x2f46: "[?] " -0x2f47: "[?] " -0x2f48: "[?] " -0x2f49: "[?] " -0x2f4a: "[?] " -0x2f4b: "[?] " -0x2f4c: "[?] " -0x2f4d: "[?] " -0x2f4e: "[?] " -0x2f4f: "[?] " -0x2f50: "[?] " -0x2f51: "[?] " -0x2f52: "[?] " -0x2f53: "[?] " -0x2f54: "[?] " -0x2f55: "[?] " -0x2f56: "[?] " -0x2f57: "[?] " -0x2f58: "[?] " -0x2f59: "[?] " -0x2f5a: "[?] " -0x2f5b: "[?] " -0x2f5c: "[?] " -0x2f5d: "[?] " -0x2f5e: "[?] " -0x2f5f: "[?] " -0x2f60: "[?] " -0x2f61: "[?] " -0x2f62: "[?] " -0x2f63: "[?] " -0x2f64: "[?] " -0x2f65: "[?] " -0x2f66: "[?] " -0x2f67: "[?] " -0x2f68: "[?] " -0x2f69: "[?] " -0x2f6a: "[?] " -0x2f6b: "[?] " -0x2f6c: "[?] " -0x2f6d: "[?] " -0x2f6e: "[?] " -0x2f6f: "[?] " -0x2f70: "[?] " -0x2f71: "[?] " -0x2f72: "[?] " -0x2f73: "[?] " -0x2f74: "[?] " -0x2f75: "[?] " -0x2f76: "[?] " -0x2f77: "[?] " -0x2f78: "[?] " -0x2f79: "[?] " -0x2f7a: "[?] " -0x2f7b: "[?] " -0x2f7c: "[?] " -0x2f7d: "[?] " -0x2f7e: "[?] " -0x2f7f: "[?] " -0x2f80: "[?] " -0x2f81: "[?] " -0x2f82: "[?] " -0x2f83: "[?] " -0x2f84: "[?] " -0x2f85: "[?] " -0x2f86: "[?] " -0x2f87: "[?] " -0x2f88: "[?] " -0x2f89: "[?] " -0x2f8a: "[?] " -0x2f8b: "[?] " -0x2f8c: "[?] " -0x2f8d: "[?] " -0x2f8e: "[?] " -0x2f8f: "[?] " -0x2f90: "[?] " -0x2f91: "[?] " -0x2f92: "[?] " -0x2f93: "[?] " -0x2f94: "[?] " -0x2f95: "[?] " -0x2f96: "[?] " -0x2f97: "[?] " -0x2f98: "[?] " -0x2f99: "[?] " -0x2f9a: "[?] " -0x2f9b: "[?] " -0x2f9c: "[?] " -0x2f9d: "[?] " -0x2f9e: "[?] " -0x2f9f: "[?] " -0x2fa0: "[?] " -0x2fa1: "[?] " -0x2fa2: "[?] " -0x2fa3: "[?] " -0x2fa4: "[?] " -0x2fa5: "[?] " -0x2fa6: "[?] " -0x2fa7: "[?] " -0x2fa8: "[?] " -0x2fa9: "[?] " -0x2faa: "[?] " -0x2fab: "[?] " -0x2fac: "[?] " -0x2fad: "[?] " -0x2fae: "[?] " -0x2faf: "[?] " -0x2fb0: "[?] " -0x2fb1: "[?] " -0x2fb2: "[?] " -0x2fb3: "[?] " -0x2fb4: "[?] " -0x2fb5: "[?] " -0x2fb6: "[?] " -0x2fb7: "[?] " -0x2fb8: "[?] " -0x2fb9: "[?] " -0x2fba: "[?] " -0x2fbb: "[?] " -0x2fbc: "[?] " -0x2fbd: "[?] " -0x2fbe: "[?] " -0x2fbf: "[?] " -0x2fc0: "[?] " -0x2fc1: "[?] " -0x2fc2: "[?] " -0x2fc3: "[?] " -0x2fc4: "[?] " -0x2fc5: "[?] " -0x2fc6: "[?] " -0x2fc7: "[?] " -0x2fc8: "[?] " -0x2fc9: "[?] " -0x2fca: "[?] " -0x2fcb: "[?] " -0x2fcc: "[?] " -0x2fcd: "[?] " -0x2fce: "[?] " -0x2fcf: "[?] " -0x2fd0: "[?] " -0x2fd1: "[?] " -0x2fd2: "[?] " -0x2fd3: "[?] " -0x2fd4: "[?] " -0x2fd5: "[?] " -0x2fd6: "[?]" -0x2fd7: "[?]" -0x2fd8: "[?]" -0x2fd9: "[?]" -0x2fda: "[?]" -0x2fdb: "[?]" -0x2fdc: "[?]" -0x2fdd: "[?]" -0x2fde: "[?]" -0x2fdf: "[?]" -0x2fe0: "[?]" -0x2fe1: "[?]" -0x2fe2: "[?]" -0x2fe3: "[?]" -0x2fe4: "[?]" -0x2fe5: "[?]" -0x2fe6: "[?]" -0x2fe7: "[?]" -0x2fe8: "[?]" -0x2fe9: "[?]" -0x2fea: "[?]" -0x2feb: "[?]" -0x2fec: "[?]" -0x2fed: "[?]" -0x2fee: "[?]" -0x2fef: "[?]" -0x2ff0: "[?] " -0x2ff1: "[?] " -0x2ff2: "[?] " -0x2ff3: "[?] " -0x2ff4: "[?] " -0x2ff5: "[?] " -0x2ff6: "[?] " -0x2ff7: "[?] " -0x2ff8: "[?] " -0x2ff9: "[?] " -0x2ffa: "[?] " -0x2ffb: "[?] " -0x2ffc: "[?]" -0x2ffd: "[?]" -0x2ffe: "[?]" -/* x030 */ -0x3000: " " -0x3001: ", " -0x3002: ". " -0x3003: "\"" -0x3004: "[JIS]" -0x3005: "\"" -0x3006: "/" -0x3007: "0" -0x3008: "<" -0x3009: "> " -0x300a: "<<" -0x300b: ">> " -0x300c: "[" -0x300d: "] " -0x300e: "{" -0x300f: "} " -0x3010: "[(" -0x3011: ")] " -0x3012: "@" -0x3013: "X " -0x3014: "[" -0x3015: "] " -0x3016: "[[" -0x3017: "]] " -0x3018: "((" -0x3019: ")) " -0x301a: "[[" -0x301b: "]] " -0x301c: "~ " -0x301d: "``" -0x301e: "''" -0x301f: ",," -0x3020: "@" -0x3021: "1" -0x3022: "2" -0x3023: "3" -0x3024: "4" -0x3025: "5" -0x3026: "6" -0x3027: "7" -0x3028: "8" -0x3029: "9" -0x302a: "" -0x302b: "" -0x302c: "" -0x302d: "" -0x302e: "" -0x302f: "" -0x3030: "~" -0x3031: "+" -0x3032: "+" -0x3033: "+" -0x3034: "+" -0x3035: "" -0x3036: "@" -0x3037: " // " -0x3038: "+10+" -0x3039: "+20+" -0x303a: "+30+" -0x303b: "[?]" -0x303c: "[?]" -0x303d: "[?]" -0x303e: "" -0x303f: "" -0x3040: "[?]" -0x3041: "a" -0x3042: "a" -0x3043: "i" -0x3044: "i" -0x3045: "u" -0x3046: "u" -0x3047: "e" -0x3048: "e" -0x3049: "o" -0x304a: "o" -0x304b: "ka" -0x304c: "ga" -0x304d: "ki" -0x304e: "gi" -0x304f: "ku" -0x3050: "gu" -0x3051: "ke" -0x3052: "ge" -0x3053: "ko" -0x3054: "go" -0x3055: "sa" -0x3056: "za" -0x3057: "shi" -0x3058: "zi" -0x3059: "su" -0x305a: "zu" -0x305b: "se" -0x305c: "ze" -0x305d: "so" -0x305e: "zo" -0x305f: "ta" -0x3060: "da" -0x3061: "chi" -0x3062: "di" -0x3063: "tsu" -0x3064: "tsu" -0x3065: "du" -0x3066: "te" -0x3067: "de" -0x3068: "to" -0x3069: "do" -0x306a: "na" -0x306b: "ni" -0x306c: "nu" -0x306d: "ne" -0x306e: "no" -0x306f: "ha" -0x3070: "ba" -0x3071: "pa" -0x3072: "hi" -0x3073: "bi" -0x3074: "pi" -0x3075: "hu" -0x3076: "bu" -0x3077: "pu" -0x3078: "he" -0x3079: "be" -0x307a: "pe" -0x307b: "ho" -0x307c: "bo" -0x307d: "po" -0x307e: "ma" -0x307f: "mi" -0x3080: "mu" -0x3081: "me" -0x3082: "mo" -0x3083: "ya" -0x3084: "ya" -0x3085: "yu" -0x3086: "yu" -0x3087: "yo" -0x3088: "yo" -0x3089: "ra" -0x308a: "ri" -0x308b: "ru" -0x308c: "re" -0x308d: "ro" -0x308e: "wa" -0x308f: "wa" -0x3090: "wi" -0x3091: "we" -0x3092: "wo" -0x3093: "n" -0x3094: "vu" -0x3095: "[?]" -0x3096: "[?]" -0x3097: "[?]" -0x3098: "[?]" -0x3099: "" -0x309a: "" -0x309b: "" -0x309c: "" -0x309d: "\"" -0x309e: "\"" -0x309f: "[?]" -0x30a0: "[?]" -0x30a1: "a" -0x30a2: "a" -0x30a3: "i" -0x30a4: "i" -0x30a5: "u" -0x30a6: "u" -0x30a7: "e" -0x30a8: "e" -0x30a9: "o" -0x30aa: "o" -0x30ab: "ka" -0x30ac: "ga" -0x30ad: "ki" -0x30ae: "gi" -0x30af: "ku" -0x30b0: "gu" -0x30b1: "ke" -0x30b2: "ge" -0x30b3: "ko" -0x30b4: "go" -0x30b5: "sa" -0x30b6: "za" -0x30b7: "shi" -0x30b8: "zi" -0x30b9: "su" -0x30ba: "zu" -0x30bb: "se" -0x30bc: "ze" -0x30bd: "so" -0x30be: "zo" -0x30bf: "ta" -0x30c0: "da" -0x30c1: "chi" -0x30c2: "di" -0x30c3: "tsu" -0x30c4: "tsu" -0x30c5: "du" -0x30c6: "te" -0x30c7: "de" -0x30c8: "to" -0x30c9: "do" -0x30ca: "na" -0x30cb: "ni" -0x30cc: "nu" -0x30cd: "ne" -0x30ce: "no" -0x30cf: "ha" -0x30d0: "ba" -0x30d1: "pa" -0x30d2: "hi" -0x30d3: "bi" -0x30d4: "pi" -0x30d5: "hu" -0x30d6: "bu" -0x30d7: "pu" -0x30d8: "he" -0x30d9: "be" -0x30da: "pe" -0x30db: "ho" -0x30dc: "bo" -0x30dd: "po" -0x30de: "ma" -0x30df: "mi" -0x30e0: "mu" -0x30e1: "me" -0x30e2: "mo" -0x30e3: "ya" -0x30e4: "ya" -0x30e5: "yu" -0x30e6: "yu" -0x30e7: "yo" -0x30e8: "yo" -0x30e9: "ra" -0x30ea: "ri" -0x30eb: "ru" -0x30ec: "re" -0x30ed: "ro" -0x30ee: "wa" -0x30ef: "wa" -0x30f0: "wi" -0x30f1: "we" -0x30f2: "wo" -0x30f3: "n" -0x30f4: "vu" -0x30f5: "ka" -0x30f6: "ke" -0x30f7: "va" -0x30f8: "vi" -0x30f9: "ve" -0x30fa: "vo" -0x30fb: "" -0x30fc: "" -0x30fd: "\"" -0x30fe: "\"" -/* x031 */ -0x3100: "[?]" -0x3101: "[?]" -0x3102: "[?]" -0x3103: "[?]" -0x3104: "[?]" -0x3105: "B" -0x3106: "P" -0x3107: "M" -0x3108: "F" -0x3109: "D" -0x310a: "T" -0x310b: "N" -0x310c: "L" -0x310d: "G" -0x310e: "K" -0x310f: "H" -0x3110: "J" -0x3111: "Q" -0x3112: "X" -0x3113: "ZH" -0x3114: "CH" -0x3115: "SH" -0x3116: "R" -0x3117: "Z" -0x3118: "C" -0x3119: "S" -0x311a: "A" -0x311b: "O" -0x311c: "E" -0x311d: "EH" -0x311e: "AI" -0x311f: "EI" -0x3120: "AU" -0x3121: "OU" -0x3122: "AN" -0x3123: "EN" -0x3124: "ANG" -0x3125: "ENG" -0x3126: "ER" -0x3127: "I" -0x3128: "U" -0x3129: "IU" -0x312a: "V" -0x312b: "NG" -0x312c: "GN" -0x312d: "[?]" -0x312e: "[?]" -0x312f: "[?]" -0x3130: "[?]" -0x3131: "g" -0x3132: "gg" -0x3133: "gs" -0x3134: "n" -0x3135: "nj" -0x3136: "nh" -0x3137: "d" -0x3138: "dd" -0x3139: "r" -0x313a: "lg" -0x313b: "lm" -0x313c: "lb" -0x313d: "ls" -0x313e: "lt" -0x313f: "lp" -0x3140: "rh" -0x3141: "m" -0x3142: "b" -0x3143: "bb" -0x3144: "bs" -0x3145: "s" -0x3146: "ss" -0x3147: "" -0x3148: "j" -0x3149: "jj" -0x314a: "c" -0x314b: "k" -0x314c: "t" -0x314d: "p" -0x314e: "h" -0x314f: "a" -0x3150: "ae" -0x3151: "ya" -0x3152: "yae" -0x3153: "eo" -0x3154: "e" -0x3155: "yeo" -0x3156: "ye" -0x3157: "o" -0x3158: "wa" -0x3159: "wae" -0x315a: "oe" -0x315b: "yo" -0x315c: "u" -0x315d: "weo" -0x315e: "we" -0x315f: "wi" -0x3160: "yu" -0x3161: "eu" -0x3162: "yi" -0x3163: "i" -0x3164: "" -0x3165: "nn" -0x3166: "nd" -0x3167: "ns" -0x3168: "nZ" -0x3169: "lgs" -0x316a: "ld" -0x316b: "lbs" -0x316c: "lZ" -0x316d: "lQ" -0x316e: "mb" -0x316f: "ms" -0x3170: "mZ" -0x3171: "mN" -0x3172: "bg" -0x3173: "" -0x3174: "bsg" -0x3175: "bst" -0x3176: "bj" -0x3177: "bt" -0x3178: "bN" -0x3179: "bbN" -0x317a: "sg" -0x317b: "sn" -0x317c: "sd" -0x317d: "sb" -0x317e: "sj" -0x317f: "Z" -0x3180: "" -0x3181: "N" -0x3182: "Ns" -0x3183: "NZ" -0x3184: "pN" -0x3185: "hh" -0x3186: "Q" -0x3187: "yo-ya" -0x3188: "yo-yae" -0x3189: "yo-i" -0x318a: "yu-yeo" -0x318b: "yu-ye" -0x318c: "yu-i" -0x318d: "U" -0x318e: "U-i" -0x318f: "[?]" -0x3190: "" -0x3191: "" -0x3192: "" -0x3193: "" -0x3194: "" -0x3195: "" -0x3196: "" -0x3197: "" -0x3198: "" -0x3199: "" -0x319a: "" -0x319b: "" -0x319c: "" -0x319d: "" -0x319e: "" -0x319f: "" -0x31a0: "BU" -0x31a1: "ZI" -0x31a2: "JI" -0x31a3: "GU" -0x31a4: "EE" -0x31a5: "ENN" -0x31a6: "OO" -0x31a7: "ONN" -0x31a8: "IR" -0x31a9: "ANN" -0x31aa: "INN" -0x31ab: "UNN" -0x31ac: "IM" -0x31ad: "NGG" -0x31ae: "AINN" -0x31af: "AUNN" -0x31b0: "AM" -0x31b1: "OM" -0x31b2: "ONG" -0x31b3: "INNN" -0x31b4: "P" -0x31b5: "T" -0x31b6: "K" -0x31b7: "H" -0x31b8: "[?]" -0x31b9: "[?]" -0x31ba: "[?]" -0x31bb: "[?]" -0x31bc: "[?]" -0x31bd: "[?]" -0x31be: "[?]" -0x31bf: "[?]" -0x31c0: "[?]" -0x31c1: "[?]" -0x31c2: "[?]" -0x31c3: "[?]" -0x31c4: "[?]" -0x31c5: "[?]" -0x31c6: "[?]" -0x31c7: "[?]" -0x31c8: "[?]" -0x31c9: "[?]" -0x31ca: "[?]" -0x31cb: "[?]" -0x31cc: "[?]" -0x31cd: "[?]" -0x31ce: "[?]" -0x31cf: "[?]" -0x31d0: "[?]" -0x31d1: "[?]" -0x31d2: "[?]" -0x31d3: "[?]" -0x31d4: "[?]" -0x31d5: "[?]" -0x31d6: "[?]" -0x31d7: "[?]" -0x31d8: "[?]" -0x31d9: "[?]" -0x31da: "[?]" -0x31db: "[?]" -0x31dc: "[?]" -0x31dd: "[?]" -0x31de: "[?]" -0x31df: "[?]" -0x31e0: "[?]" -0x31e1: "[?]" -0x31e2: "[?]" -0x31e3: "[?]" -0x31e4: "[?]" -0x31e5: "[?]" -0x31e6: "[?]" -0x31e7: "[?]" -0x31e8: "[?]" -0x31e9: "[?]" -0x31ea: "[?]" -0x31eb: "[?]" -0x31ec: "[?]" -0x31ed: "[?]" -0x31ee: "[?]" -0x31ef: "[?]" -0x31f0: "[?]" -0x31f1: "[?]" -0x31f2: "[?]" -0x31f3: "[?]" -0x31f4: "[?]" -0x31f5: "[?]" -0x31f6: "[?]" -0x31f7: "[?]" -0x31f8: "[?]" -0x31f9: "[?]" -0x31fa: "[?]" -0x31fb: "[?]" -0x31fc: "[?]" -0x31fd: "[?]" -0x31fe: "[?]" -/* x032 */ -0x3200: "(g)" -0x3201: "(n)" -0x3202: "(d)" -0x3203: "(r)" -0x3204: "(m)" -0x3205: "(b)" -0x3206: "(s)" -0x3207: "()" -0x3208: "(j)" -0x3209: "(c)" -0x320a: "(k)" -0x320b: "(t)" -0x320c: "(p)" -0x320d: "(h)" -0x320e: "(ga)" -0x320f: "(na)" -0x3210: "(da)" -0x3211: "(ra)" -0x3212: "(ma)" -0x3213: "(ba)" -0x3214: "(sa)" -0x3215: "(a)" -0x3216: "(ja)" -0x3217: "(ca)" -0x3218: "(ka)" -0x3219: "(ta)" -0x321a: "(pa)" -0x321b: "(ha)" -0x321c: "(ju)" -0x321d: "[?]" -0x321e: "[?]" -0x321f: "[?]" -0x3220: "(1) " -0x3221: "(2) " -0x3222: "(3) " -0x3223: "(4) " -0x3224: "(5) " -0x3225: "(6) " -0x3226: "(7) " -0x3227: "(8) " -0x3228: "(9) " -0x3229: "(10) " -0x322a: "(Yue) " -0x322b: "(Huo) " -0x322c: "(Shui) " -0x322d: "(Mu) " -0x322e: "(Jin) " -0x322f: "(Tu) " -0x3230: "(Ri) " -0x3231: "(Zhu) " -0x3232: "(You) " -0x3233: "(She) " -0x3234: "(Ming) " -0x3235: "(Te) " -0x3236: "(Cai) " -0x3237: "(Zhu) " -0x3238: "(Lao) " -0x3239: "(Dai) " -0x323a: "(Hu) " -0x323b: "(Xue) " -0x323c: "(Jian) " -0x323d: "(Qi) " -0x323e: "(Zi) " -0x323f: "(Xie) " -0x3240: "(Ji) " -0x3241: "(Xiu) " -0x3242: "<<" -0x3243: ">>" -0x3244: "[?]" -0x3245: "[?]" -0x3246: "[?]" -0x3247: "[?]" -0x3248: "[?]" -0x3249: "[?]" -0x324a: "[?]" -0x324b: "[?]" -0x324c: "[?]" -0x324d: "[?]" -0x324e: "[?]" -0x324f: "[?]" -0x3250: "[?]" -0x3251: "[?]" -0x3252: "[?]" -0x3253: "[?]" -0x3254: "[?]" -0x3255: "[?]" -0x3256: "[?]" -0x3257: "[?]" -0x3258: "[?]" -0x3259: "[?]" -0x325a: "[?]" -0x325b: "[?]" -0x325c: "[?]" -0x325d: "[?]" -0x325e: "[?]" -0x325f: "[?]" -0x3260: "(g)" -0x3261: "(n)" -0x3262: "(d)" -0x3263: "(r)" -0x3264: "(m)" -0x3265: "(b)" -0x3266: "(s)" -0x3267: "()" -0x3268: "(j)" -0x3269: "(c)" -0x326a: "(k)" -0x326b: "(t)" -0x326c: "(p)" -0x326d: "(h)" -0x326e: "(ga)" -0x326f: "(na)" -0x3270: "(da)" -0x3271: "(ra)" -0x3272: "(ma)" -0x3273: "(ba)" -0x3274: "(sa)" -0x3275: "(a)" -0x3276: "(ja)" -0x3277: "(ca)" -0x3278: "(ka)" -0x3279: "(ta)" -0x327a: "(pa)" -0x327b: "(ha)" -0x327c: "[?]" -0x327d: "[?]" -0x327e: "[?]" -0x327f: "KIS " -0x3280: "(1) " -0x3281: "(2) " -0x3282: "(3) " -0x3283: "(4) " -0x3284: "(5) " -0x3285: "(6) " -0x3286: "(7) " -0x3287: "(8) " -0x3288: "(9) " -0x3289: "(10) " -0x328a: "(Yue) " -0x328b: "(Huo) " -0x328c: "(Shui) " -0x328d: "(Mu) " -0x328e: "(Jin) " -0x328f: "(Tu) " -0x3290: "(Ri) " -0x3291: "(Zhu) " -0x3292: "(You) " -0x3293: "(She) " -0x3294: "(Ming) " -0x3295: "(Te) " -0x3296: "(Cai) " -0x3297: "(Zhu) " -0x3298: "(Lao) " -0x3299: "(Mi) " -0x329a: "(Nan) " -0x329b: "(Nu) " -0x329c: "(Shi) " -0x329d: "(You) " -0x329e: "(Yin) " -0x329f: "(Zhu) " -0x32a0: "(Xiang) " -0x32a1: "(Xiu) " -0x32a2: "(Xie) " -0x32a3: "(Zheng) " -0x32a4: "(Shang) " -0x32a5: "(Zhong) " -0x32a6: "(Xia) " -0x32a7: "(Zuo) " -0x32a8: "(You) " -0x32a9: "(Yi) " -0x32aa: "(Zong) " -0x32ab: "(Xue) " -0x32ac: "(Jian) " -0x32ad: "(Qi) " -0x32ae: "(Zi) " -0x32af: "(Xie) " -0x32b0: "(Ye) " -0x32b1: "[?]" -0x32b2: "[?]" -0x32b3: "[?]" -0x32b4: "[?]" -0x32b5: "[?]" -0x32b6: "[?]" -0x32b7: "[?]" -0x32b8: "[?]" -0x32b9: "[?]" -0x32ba: "[?]" -0x32bb: "[?]" -0x32bc: "[?]" -0x32bd: "[?]" -0x32be: "[?]" -0x32bf: "[?]" -0x32c0: "1M" -0x32c1: "2M" -0x32c2: "3M" -0x32c3: "4M" -0x32c4: "5M" -0x32c5: "6M" -0x32c6: "7M" -0x32c7: "8M" -0x32c8: "9M" -0x32c9: "10M" -0x32ca: "11M" -0x32cb: "12M" -0x32cc: "[?]" -0x32cd: "[?]" -0x32ce: "[?]" -0x32cf: "[?]" -0x32d0: "a" -0x32d1: "i" -0x32d2: "u" -0x32d3: "u" -0x32d4: "o" -0x32d5: "ka" -0x32d6: "ki" -0x32d7: "ku" -0x32d8: "ke" -0x32d9: "ko" -0x32da: "sa" -0x32db: "si" -0x32dc: "su" -0x32dd: "se" -0x32de: "so" -0x32df: "ta" -0x32e0: "ti" -0x32e1: "tu" -0x32e2: "te" -0x32e3: "to" -0x32e4: "na" -0x32e5: "ni" -0x32e6: "nu" -0x32e7: "ne" -0x32e8: "no" -0x32e9: "ha" -0x32ea: "hi" -0x32eb: "hu" -0x32ec: "he" -0x32ed: "ho" -0x32ee: "ma" -0x32ef: "mi" -0x32f0: "mu" -0x32f1: "me" -0x32f2: "mo" -0x32f3: "ya" -0x32f4: "yu" -0x32f5: "yo" -0x32f6: "ra" -0x32f7: "ri" -0x32f8: "ru" -0x32f9: "re" -0x32fa: "ro" -0x32fb: "wa" -0x32fc: "wi" -0x32fd: "we" -0x32fe: "wo" -/* x033 */ -0x3300: "apartment" -0x3301: "alpha" -0x3302: "ampere" -0x3303: "are" -0x3304: "inning" -0x3305: "inch" -0x3306: "won" -0x3307: "escudo" -0x3308: "acre" -0x3309: "ounce" -0x330a: "ohm" -0x330b: "kai-ri" -0x330c: "carat" -0x330d: "calorie" -0x330e: "gallon" -0x330f: "gamma" -0x3310: "giga" -0x3311: "guinea" -0x3312: "curie" -0x3313: "guilder" -0x3314: "kilo" -0x3315: "kilogram" -0x3316: "kilometer" -0x3317: "kilowatt" -0x3318: "gram" -0x3319: "gram ton" -0x331a: "cruzeiro" -0x331b: "krone" -0x331c: "case" -0x331d: "koruna" -0x331e: "co-op" -0x331f: "cycle" -0x3320: "centime" -0x3321: "shilling" -0x3322: "centi" -0x3323: "cent" -0x3324: "dozen" -0x3325: "desi" -0x3326: "dollar" -0x3327: "ton" -0x3328: "nano" -0x3329: "knot" -0x332a: "heights" -0x332b: "percent" -0x332c: "parts" -0x332d: "barrel" -0x332e: "piaster" -0x332f: "picul" -0x3330: "pico" -0x3331: "building" -0x3332: "farad" -0x3333: "feet" -0x3334: "bushel" -0x3335: "franc" -0x3336: "hectare" -0x3337: "peso" -0x3338: "pfennig" -0x3339: "hertz" -0x333a: "pence" -0x333b: "page" -0x333c: "beta" -0x333d: "point" -0x333e: "volt" -0x333f: "hon" -0x3340: "pound" -0x3341: "hall" -0x3342: "horn" -0x3343: "micro" -0x3344: "mile" -0x3345: "mach" -0x3346: "mark" -0x3347: "mansion" -0x3348: "micron" -0x3349: "milli" -0x334a: "millibar" -0x334b: "mega" -0x334c: "megaton" -0x334d: "meter" -0x334e: "yard" -0x334f: "yard" -0x3350: "yuan" -0x3351: "liter" -0x3352: "lira" -0x3353: "rupee" -0x3354: "ruble" -0x3355: "rem" -0x3356: "roentgen" -0x3357: "watt" -0x3358: "0h" -0x3359: "1h" -0x335a: "2h" -0x335b: "3h" -0x335c: "4h" -0x335d: "5h" -0x335e: "6h" -0x335f: "7h" -0x3360: "8h" -0x3361: "9h" -0x3362: "10h" -0x3363: "11h" -0x3364: "12h" -0x3365: "13h" -0x3366: "14h" -0x3367: "15h" -0x3368: "16h" -0x3369: "17h" -0x336a: "18h" -0x336b: "19h" -0x336c: "20h" -0x336d: "21h" -0x336e: "22h" -0x336f: "23h" -0x3370: "24h" -0x3371: "HPA" -0x3372: "da" -0x3373: "AU" -0x3374: "bar" -0x3375: "oV" -0x3376: "pc" -0x3377: "[?]" -0x3378: "[?]" -0x3379: "[?]" -0x337a: "[?]" -0x337b: "Heisei" -0x337c: "Syouwa" -0x337d: "Taisyou" -0x337e: "Meiji" -0x337f: "Inc." -0x3380: "pA" -0x3381: "nA" -0x3382: "microamp" -0x3383: "mA" -0x3384: "kA" -0x3385: "kB" -0x3386: "MB" -0x3387: "GB" -0x3388: "cal" -0x3389: "kcal" -0x338a: "pF" -0x338b: "nF" -0x338c: "microFarad" -0x338d: "microgram" -0x338e: "mg" -0x338f: "kg" -0x3390: "Hz" -0x3391: "kHz" -0x3392: "MHz" -0x3393: "GHz" -0x3394: "THz" -0x3395: "microliter" -0x3396: "ml" -0x3397: "dl" -0x3398: "kl" -0x3399: "fm" -0x339a: "nm" -0x339b: "micrometer" -0x339c: "mm" -0x339d: "cm" -0x339e: "km" -0x339f: "mm^2" -0x33a0: "cm^2" -0x33a1: "m^2" -0x33a2: "km^2" -0x33a3: "mm^4" -0x33a4: "cm^3" -0x33a5: "m^3" -0x33a6: "km^3" -0x33a7: "m/s" -0x33a8: "m/s^2" -0x33a9: "Pa" -0x33aa: "kPa" -0x33ab: "MPa" -0x33ac: "GPa" -0x33ad: "rad" -0x33ae: "rad/s" -0x33af: "rad/s^2" -0x33b0: "ps" -0x33b1: "ns" -0x33b2: "microsecond" -0x33b3: "ms" -0x33b4: "pV" -0x33b5: "nV" -0x33b6: "microvolt" -0x33b7: "mV" -0x33b8: "kV" -0x33b9: "MV" -0x33ba: "pW" -0x33bb: "nW" -0x33bc: "microwatt" -0x33bd: "mW" -0x33be: "kW" -0x33bf: "MW" -0x33c0: "kOhm" -0x33c1: "MOhm" -0x33c2: "a.m." -0x33c3: "Bq" -0x33c4: "cc" -0x33c5: "cd" -0x33c6: "C/kg" -0x33c7: "Co." -0x33c8: "dB" -0x33c9: "Gy" -0x33ca: "ha" -0x33cb: "HP" -0x33cc: "in" -0x33cd: "K.K." -0x33ce: "KM" -0x33cf: "kt" -0x33d0: "lm" -0x33d1: "ln" -0x33d2: "log" -0x33d3: "lx" -0x33d4: "mb" -0x33d5: "mil" -0x33d6: "mol" -0x33d7: "pH" -0x33d8: "p.m." -0x33d9: "PPM" -0x33da: "PR" -0x33db: "sr" -0x33dc: "Sv" -0x33dd: "Wb" -0x33de: "[?]" -0x33df: "[?]" -0x33e0: "1d" -0x33e1: "2d" -0x33e2: "3d" -0x33e3: "4d" -0x33e4: "5d" -0x33e5: "6d" -0x33e6: "7d" -0x33e7: "8d" -0x33e8: "9d" -0x33e9: "10d" -0x33ea: "11d" -0x33eb: "12d" -0x33ec: "13d" -0x33ed: "14d" -0x33ee: "15d" -0x33ef: "16d" -0x33f0: "17d" -0x33f1: "18d" -0x33f2: "19d" -0x33f3: "20d" -0x33f4: "21d" -0x33f5: "22d" -0x33f6: "23d" -0x33f7: "24d" -0x33f8: "25d" -0x33f9: "26d" -0x33fa: "27d" -0x33fb: "28d" -0x33fc: "29d" -0x33fd: "30d" -0x33fe: "31d" -/* x04d */ -0x4d00: "[?] " -0x4d01: "[?] " -0x4d02: "[?] " -0x4d03: "[?] " -0x4d04: "[?] " -0x4d05: "[?] " -0x4d06: "[?] " -0x4d07: "[?] " -0x4d08: "[?] " -0x4d09: "[?] " -0x4d0a: "[?] " -0x4d0b: "[?] " -0x4d0c: "[?] " -0x4d0d: "[?] " -0x4d0e: "[?] " -0x4d0f: "[?] " -0x4d10: "[?] " -0x4d11: "[?] " -0x4d12: "[?] " -0x4d13: "[?] " -0x4d14: "[?] " -0x4d15: "[?] " -0x4d16: "[?] " -0x4d17: "[?] " -0x4d18: "[?] " -0x4d19: "[?] " -0x4d1a: "[?] " -0x4d1b: "[?] " -0x4d1c: "[?] " -0x4d1d: "[?] " -0x4d1e: "[?] " -0x4d1f: "[?] " -0x4d20: "[?] " -0x4d21: "[?] " -0x4d22: "[?] " -0x4d23: "[?] " -0x4d24: "[?] " -0x4d25: "[?] " -0x4d26: "[?] " -0x4d27: "[?] " -0x4d28: "[?] " -0x4d29: "[?] " -0x4d2a: "[?] " -0x4d2b: "[?] " -0x4d2c: "[?] " -0x4d2d: "[?] " -0x4d2e: "[?] " -0x4d2f: "[?] " -0x4d30: "[?] " -0x4d31: "[?] " -0x4d32: "[?] " -0x4d33: "[?] " -0x4d34: "[?] " -0x4d35: "[?] " -0x4d36: "[?] " -0x4d37: "[?] " -0x4d38: "[?] " -0x4d39: "[?] " -0x4d3a: "[?] " -0x4d3b: "[?] " -0x4d3c: "[?] " -0x4d3d: "[?] " -0x4d3e: "[?] " -0x4d3f: "[?] " -0x4d40: "[?] " -0x4d41: "[?] " -0x4d42: "[?] " -0x4d43: "[?] " -0x4d44: "[?] " -0x4d45: "[?] " -0x4d46: "[?] " -0x4d47: "[?] " -0x4d48: "[?] " -0x4d49: "[?] " -0x4d4a: "[?] " -0x4d4b: "[?] " -0x4d4c: "[?] " -0x4d4d: "[?] " -0x4d4e: "[?] " -0x4d4f: "[?] " -0x4d50: "[?] " -0x4d51: "[?] " -0x4d52: "[?] " -0x4d53: "[?] " -0x4d54: "[?] " -0x4d55: "[?] " -0x4d56: "[?] " -0x4d57: "[?] " -0x4d58: "[?] " -0x4d59: "[?] " -0x4d5a: "[?] " -0x4d5b: "[?] " -0x4d5c: "[?] " -0x4d5d: "[?] " -0x4d5e: "[?] " -0x4d5f: "[?] " -0x4d60: "[?] " -0x4d61: "[?] " -0x4d62: "[?] " -0x4d63: "[?] " -0x4d64: "[?] " -0x4d65: "[?] " -0x4d66: "[?] " -0x4d67: "[?] " -0x4d68: "[?] " -0x4d69: "[?] " -0x4d6a: "[?] " -0x4d6b: "[?] " -0x4d6c: "[?] " -0x4d6d: "[?] " -0x4d6e: "[?] " -0x4d6f: "[?] " -0x4d70: "[?] " -0x4d71: "[?] " -0x4d72: "[?] " -0x4d73: "[?] " -0x4d74: "[?] " -0x4d75: "[?] " -0x4d76: "[?] " -0x4d77: "[?] " -0x4d78: "[?] " -0x4d79: "[?] " -0x4d7a: "[?] " -0x4d7b: "[?] " -0x4d7c: "[?] " -0x4d7d: "[?] " -0x4d7e: "[?] " -0x4d7f: "[?] " -0x4d80: "[?] " -0x4d81: "[?] " -0x4d82: "[?] " -0x4d83: "[?] " -0x4d84: "[?] " -0x4d85: "[?] " -0x4d86: "[?] " -0x4d87: "[?] " -0x4d88: "[?] " -0x4d89: "[?] " -0x4d8a: "[?] " -0x4d8b: "[?] " -0x4d8c: "[?] " -0x4d8d: "[?] " -0x4d8e: "[?] " -0x4d8f: "[?] " -0x4d90: "[?] " -0x4d91: "[?] " -0x4d92: "[?] " -0x4d93: "[?] " -0x4d94: "[?] " -0x4d95: "[?] " -0x4d96: "[?] " -0x4d97: "[?] " -0x4d98: "[?] " -0x4d99: "[?] " -0x4d9a: "[?] " -0x4d9b: "[?] " -0x4d9c: "[?] " -0x4d9d: "[?] " -0x4d9e: "[?] " -0x4d9f: "[?] " -0x4da0: "[?] " -0x4da1: "[?] " -0x4da2: "[?] " -0x4da3: "[?] " -0x4da4: "[?] " -0x4da5: "[?] " -0x4da6: "[?] " -0x4da7: "[?] " -0x4da8: "[?] " -0x4da9: "[?] " -0x4daa: "[?] " -0x4dab: "[?] " -0x4dac: "[?] " -0x4dad: "[?] " -0x4dae: "[?] " -0x4daf: "[?] " -0x4db0: "[?] " -0x4db1: "[?] " -0x4db2: "[?] " -0x4db3: "[?] " -0x4db4: "[?] " -0x4db5: "[?] " -0x4db6: "[?]" -0x4db7: "[?]" -0x4db8: "[?]" -0x4db9: "[?]" -0x4dba: "[?]" -0x4dbb: "[?]" -0x4dbc: "[?]" -0x4dbd: "[?]" -0x4dbe: "[?]" -0x4dbf: "[?]" -0x4dc0: "[?]" -0x4dc1: "[?]" -0x4dc2: "[?]" -0x4dc3: "[?]" -0x4dc4: "[?]" -0x4dc5: "[?]" -0x4dc6: "[?]" -0x4dc7: "[?]" -0x4dc8: "[?]" -0x4dc9: "[?]" -0x4dca: "[?]" -0x4dcb: "[?]" -0x4dcc: "[?]" -0x4dcd: "[?]" -0x4dce: "[?]" -0x4dcf: "[?]" -0x4dd0: "[?]" -0x4dd1: "[?]" -0x4dd2: "[?]" -0x4dd3: "[?]" -0x4dd4: "[?]" -0x4dd5: "[?]" -0x4dd6: "[?]" -0x4dd7: "[?]" -0x4dd8: "[?]" -0x4dd9: "[?]" -0x4dda: "[?]" -0x4ddb: "[?]" -0x4ddc: "[?]" -0x4ddd: "[?]" -0x4dde: "[?]" -0x4ddf: "[?]" -0x4de0: "[?]" -0x4de1: "[?]" -0x4de2: "[?]" -0x4de3: "[?]" -0x4de4: "[?]" -0x4de5: "[?]" -0x4de6: "[?]" -0x4de7: "[?]" -0x4de8: "[?]" -0x4de9: "[?]" -0x4dea: "[?]" -0x4deb: "[?]" -0x4dec: "[?]" -0x4ded: "[?]" -0x4dee: "[?]" -0x4def: "[?]" -0x4df0: "[?]" -0x4df1: "[?]" -0x4df2: "[?]" -0x4df3: "[?]" -0x4df4: "[?]" -0x4df5: "[?]" -0x4df6: "[?]" -0x4df7: "[?]" -0x4df8: "[?]" -0x4df9: "[?]" -0x4dfa: "[?]" -0x4dfb: "[?]" -0x4dfc: "[?]" -0x4dfd: "[?]" -0x4dfe: "[?]" -/* x04e */ -0x4e00: "[?] " -0x4e01: "Ding " -0x4e02: "Kao " -0x4e03: "Qi " -0x4e04: "Shang " -0x4e05: "Xia " -0x4e06: "[?] " -0x4e07: "Mo " -0x4e08: "Zhang " -0x4e09: "San " -0x4e0a: "Shang " -0x4e0b: "Xia " -0x4e0c: "Ji " -0x4e0d: "Bu " -0x4e0e: "Yu " -0x4e0f: "Mian " -0x4e10: "Gai " -0x4e11: "Chou " -0x4e12: "Chou " -0x4e13: "Zhuan " -0x4e14: "Qie " -0x4e15: "Pi " -0x4e16: "Shi " -0x4e17: "Shi " -0x4e18: "Qiu " -0x4e19: "Bing " -0x4e1a: "Ye " -0x4e1b: "Cong " -0x4e1c: "Dong " -0x4e1d: "Si " -0x4e1e: "Cheng " -0x4e1f: "Diu " -0x4e20: "Qiu " -0x4e21: "Liang " -0x4e22: "Diu " -0x4e23: "You " -0x4e24: "Liang " -0x4e25: "Yan " -0x4e26: "Bing " -0x4e27: "Sang " -0x4e28: "Gun " -0x4e29: "Jiu " -0x4e2a: "Ge " -0x4e2b: "Ya " -0x4e2c: "Qiang " -0x4e2d: "Zhong " -0x4e2e: "Ji " -0x4e2f: "Jie " -0x4e30: "Feng " -0x4e31: "Guan " -0x4e32: "Chuan " -0x4e33: "Chan " -0x4e34: "Lin " -0x4e35: "Zhuo " -0x4e36: "Zhu " -0x4e37: "Ha " -0x4e38: "Wan " -0x4e39: "Dan " -0x4e3a: "Wei " -0x4e3b: "Zhu " -0x4e3c: "Jing " -0x4e3d: "Li " -0x4e3e: "Ju " -0x4e3f: "Pie " -0x4e40: "Fu " -0x4e41: "Yi " -0x4e42: "Yi " -0x4e43: "Nai " -0x4e44: "Shime " -0x4e45: "Jiu " -0x4e46: "Jiu " -0x4e47: "Zhe " -0x4e48: "Yao " -0x4e49: "Yi " -0x4e4a: "[?] " -0x4e4b: "Zhi " -0x4e4c: "Wu " -0x4e4d: "Zha " -0x4e4e: "Hu " -0x4e4f: "Fa " -0x4e50: "Le " -0x4e51: "Zhong " -0x4e52: "Ping " -0x4e53: "Pang " -0x4e54: "Qiao " -0x4e55: "Hu " -0x4e56: "Guai " -0x4e57: "Cheng " -0x4e58: "Cheng " -0x4e59: "Yi " -0x4e5a: "Yin " -0x4e5b: "[?] " -0x4e5c: "Mie " -0x4e5d: "Jiu " -0x4e5e: "Qi " -0x4e5f: "Ye " -0x4e60: "Xi " -0x4e61: "Xiang " -0x4e62: "Gai " -0x4e63: "Diu " -0x4e64: "Hal " -0x4e65: "[?] " -0x4e66: "Shu " -0x4e67: "Twul " -0x4e68: "Shi " -0x4e69: "Ji " -0x4e6a: "Nang " -0x4e6b: "Jia " -0x4e6c: "Kel " -0x4e6d: "Shi " -0x4e6e: "[?] " -0x4e6f: "Ol " -0x4e70: "Mai " -0x4e71: "Luan " -0x4e72: "Cal " -0x4e73: "Ru " -0x4e74: "Xue " -0x4e75: "Yan " -0x4e76: "Fu " -0x4e77: "Sha " -0x4e78: "Na " -0x4e79: "Gan " -0x4e7a: "Sol " -0x4e7b: "El " -0x4e7c: "Cwul " -0x4e7d: "[?] " -0x4e7e: "Gan " -0x4e7f: "Chi " -0x4e80: "Gui " -0x4e81: "Gan " -0x4e82: "Luan " -0x4e83: "Lin " -0x4e84: "Yi " -0x4e85: "Jue " -0x4e86: "Liao " -0x4e87: "Ma " -0x4e88: "Yu " -0x4e89: "Zheng " -0x4e8a: "Shi " -0x4e8b: "Shi " -0x4e8c: "Er " -0x4e8d: "Chu " -0x4e8e: "Yu " -0x4e8f: "Yu " -0x4e90: "Yu " -0x4e91: "Yun " -0x4e92: "Hu " -0x4e93: "Qi " -0x4e94: "Wu " -0x4e95: "Jing " -0x4e96: "Si " -0x4e97: "Sui " -0x4e98: "Gen " -0x4e99: "Gen " -0x4e9a: "Ya " -0x4e9b: "Xie " -0x4e9c: "Ya " -0x4e9d: "Qi " -0x4e9e: "Ya " -0x4e9f: "Ji " -0x4ea0: "Tou " -0x4ea1: "Wang " -0x4ea2: "Kang " -0x4ea3: "Ta " -0x4ea4: "Jiao " -0x4ea5: "Hai " -0x4ea6: "Yi " -0x4ea7: "Chan " -0x4ea8: "Heng " -0x4ea9: "Mu " -0x4eaa: "[?] " -0x4eab: "Xiang " -0x4eac: "Jing " -0x4ead: "Ting " -0x4eae: "Liang " -0x4eaf: "Xiang " -0x4eb0: "Jing " -0x4eb1: "Ye " -0x4eb2: "Qin " -0x4eb3: "Bo " -0x4eb4: "You " -0x4eb5: "Xie " -0x4eb6: "Dan " -0x4eb7: "Lian " -0x4eb8: "Duo " -0x4eb9: "Wei " -0x4eba: "Ren " -0x4ebb: "Ren " -0x4ebc: "Ji " -0x4ebd: "La " -0x4ebe: "Wang " -0x4ebf: "Yi " -0x4ec0: "Shi " -0x4ec1: "Ren " -0x4ec2: "Le " -0x4ec3: "Ding " -0x4ec4: "Ze " -0x4ec5: "Jin " -0x4ec6: "Pu " -0x4ec7: "Chou " -0x4ec8: "Ba " -0x4ec9: "Zhang " -0x4eca: "Jin " -0x4ecb: "Jie " -0x4ecc: "Bing " -0x4ecd: "Reng " -0x4ece: "Cong " -0x4ecf: "Fo " -0x4ed0: "San " -0x4ed1: "Lun " -0x4ed2: "Sya " -0x4ed3: "Cang " -0x4ed4: "Zi " -0x4ed5: "Shi " -0x4ed6: "Ta " -0x4ed7: "Zhang " -0x4ed8: "Fu " -0x4ed9: "Xian " -0x4eda: "Xian " -0x4edb: "Tuo " -0x4edc: "Hong " -0x4edd: "Tong " -0x4ede: "Ren " -0x4edf: "Qian " -0x4ee0: "Gan " -0x4ee1: "Yi " -0x4ee2: "Di " -0x4ee3: "Dai " -0x4ee4: "Ling " -0x4ee5: "Yi " -0x4ee6: "Chao " -0x4ee7: "Chang " -0x4ee8: "Sa " -0x4ee9: "[?] " -0x4eea: "Yi " -0x4eeb: "Mu " -0x4eec: "Men " -0x4eed: "Ren " -0x4eee: "Jia " -0x4eef: "Chao " -0x4ef0: "Yang " -0x4ef1: "Qian " -0x4ef2: "Zhong " -0x4ef3: "Pi " -0x4ef4: "Wan " -0x4ef5: "Wu " -0x4ef6: "Jian " -0x4ef7: "Jie " -0x4ef8: "Yao " -0x4ef9: "Feng " -0x4efa: "Cang " -0x4efb: "Ren " -0x4efc: "Wang " -0x4efd: "Fen " -0x4efe: "Di " -0x4eff: "Fang " -/* x04f */ -0x4f00: "Zhong " -0x4f01: "Qi " -0x4f02: "Pei " -0x4f03: "Yu " -0x4f04: "Diao " -0x4f05: "Dun " -0x4f06: "Wen " -0x4f07: "Yi " -0x4f08: "Xin " -0x4f09: "Kang " -0x4f0a: "Yi " -0x4f0b: "Ji " -0x4f0c: "Ai " -0x4f0d: "Wu " -0x4f0e: "Ji " -0x4f0f: "Fu " -0x4f10: "Fa " -0x4f11: "Xiu " -0x4f12: "Jin " -0x4f13: "Bei " -0x4f14: "Dan " -0x4f15: "Fu " -0x4f16: "Tang " -0x4f17: "Zhong " -0x4f18: "You " -0x4f19: "Huo " -0x4f1a: "Hui " -0x4f1b: "Yu " -0x4f1c: "Cui " -0x4f1d: "Chuan " -0x4f1e: "San " -0x4f1f: "Wei " -0x4f20: "Chuan " -0x4f21: "Che " -0x4f22: "Ya " -0x4f23: "Xian " -0x4f24: "Shang " -0x4f25: "Chang " -0x4f26: "Lun " -0x4f27: "Cang " -0x4f28: "Xun " -0x4f29: "Xin " -0x4f2a: "Wei " -0x4f2b: "Zhu " -0x4f2c: "[?] " -0x4f2d: "Xuan " -0x4f2e: "Nu " -0x4f2f: "Bo " -0x4f30: "Gu " -0x4f31: "Ni " -0x4f32: "Ni " -0x4f33: "Xie " -0x4f34: "Ban " -0x4f35: "Xu " -0x4f36: "Ling " -0x4f37: "Zhou " -0x4f38: "Shen " -0x4f39: "Qu " -0x4f3a: "Si " -0x4f3b: "Beng " -0x4f3c: "Si " -0x4f3d: "Jia " -0x4f3e: "Pi " -0x4f3f: "Yi " -0x4f40: "Si " -0x4f41: "Ai " -0x4f42: "Zheng " -0x4f43: "Dian " -0x4f44: "Han " -0x4f45: "Mai " -0x4f46: "Dan " -0x4f47: "Zhu " -0x4f48: "Bu " -0x4f49: "Qu " -0x4f4a: "Bi " -0x4f4b: "Shao " -0x4f4c: "Ci " -0x4f4d: "Wei " -0x4f4e: "Di " -0x4f4f: "Zhu " -0x4f50: "Zuo " -0x4f51: "You " -0x4f52: "Yang " -0x4f53: "Ti " -0x4f54: "Zhan " -0x4f55: "He " -0x4f56: "Bi " -0x4f57: "Tuo " -0x4f58: "She " -0x4f59: "Yu " -0x4f5a: "Yi " -0x4f5b: "Fo " -0x4f5c: "Zuo " -0x4f5d: "Kou " -0x4f5e: "Ning " -0x4f5f: "Tong " -0x4f60: "Ni " -0x4f61: "Xuan " -0x4f62: "Qu " -0x4f63: "Yong " -0x4f64: "Wa " -0x4f65: "Qian " -0x4f66: "[?] " -0x4f67: "Ka " -0x4f68: "[?] " -0x4f69: "Pei " -0x4f6a: "Huai " -0x4f6b: "He " -0x4f6c: "Lao " -0x4f6d: "Xiang " -0x4f6e: "Ge " -0x4f6f: "Yang " -0x4f70: "Bai " -0x4f71: "Fa " -0x4f72: "Ming " -0x4f73: "Jia " -0x4f74: "Er " -0x4f75: "Bing " -0x4f76: "Ji " -0x4f77: "Hen " -0x4f78: "Huo " -0x4f79: "Gui " -0x4f7a: "Quan " -0x4f7b: "Tiao " -0x4f7c: "Jiao " -0x4f7d: "Ci " -0x4f7e: "Yi " -0x4f7f: "Shi " -0x4f80: "Xing " -0x4f81: "Shen " -0x4f82: "Tuo " -0x4f83: "Kan " -0x4f84: "Zhi " -0x4f85: "Gai " -0x4f86: "Lai " -0x4f87: "Yi " -0x4f88: "Chi " -0x4f89: "Kua " -0x4f8a: "Guang " -0x4f8b: "Li " -0x4f8c: "Yin " -0x4f8d: "Shi " -0x4f8e: "Mi " -0x4f8f: "Zhu " -0x4f90: "Xu " -0x4f91: "You " -0x4f92: "An " -0x4f93: "Lu " -0x4f94: "Mou " -0x4f95: "Er " -0x4f96: "Lun " -0x4f97: "Tong " -0x4f98: "Cha " -0x4f99: "Chi " -0x4f9a: "Xun " -0x4f9b: "Gong " -0x4f9c: "Zhou " -0x4f9d: "Yi " -0x4f9e: "Ru " -0x4f9f: "Jian " -0x4fa0: "Xia " -0x4fa1: "Jia " -0x4fa2: "Zai " -0x4fa3: "Lu " -0x4fa4: "Ko " -0x4fa5: "Jiao " -0x4fa6: "Zhen " -0x4fa7: "Ce " -0x4fa8: "Qiao " -0x4fa9: "Kuai " -0x4faa: "Chai " -0x4fab: "Ning " -0x4fac: "Nong " -0x4fad: "Jin " -0x4fae: "Wu " -0x4faf: "Hou " -0x4fb0: "Jiong " -0x4fb1: "Cheng " -0x4fb2: "Zhen " -0x4fb3: "Zuo " -0x4fb4: "Chou " -0x4fb5: "Qin " -0x4fb6: "Lu " -0x4fb7: "Ju " -0x4fb8: "Shu " -0x4fb9: "Ting " -0x4fba: "Shen " -0x4fbb: "Tuo " -0x4fbc: "Bo " -0x4fbd: "Nan " -0x4fbe: "Hao " -0x4fbf: "Bian " -0x4fc0: "Tui " -0x4fc1: "Yu " -0x4fc2: "Xi " -0x4fc3: "Cu " -0x4fc4: "E " -0x4fc5: "Qiu " -0x4fc6: "Xu " -0x4fc7: "Kuang " -0x4fc8: "Ku " -0x4fc9: "Wu " -0x4fca: "Jun " -0x4fcb: "Yi " -0x4fcc: "Fu " -0x4fcd: "Lang " -0x4fce: "Zu " -0x4fcf: "Qiao " -0x4fd0: "Li " -0x4fd1: "Yong " -0x4fd2: "Hun " -0x4fd3: "Jing " -0x4fd4: "Xian " -0x4fd5: "San " -0x4fd6: "Pai " -0x4fd7: "Su " -0x4fd8: "Fu " -0x4fd9: "Xi " -0x4fda: "Li " -0x4fdb: "Fu " -0x4fdc: "Ping " -0x4fdd: "Bao " -0x4fde: "Yu " -0x4fdf: "Si " -0x4fe0: "Xia " -0x4fe1: "Xin " -0x4fe2: "Xiu " -0x4fe3: "Yu " -0x4fe4: "Ti " -0x4fe5: "Che " -0x4fe6: "Chou " -0x4fe7: "[?] " -0x4fe8: "Yan " -0x4fe9: "Lia " -0x4fea: "Li " -0x4feb: "Lai " -0x4fec: "[?] " -0x4fed: "Jian " -0x4fee: "Xiu " -0x4fef: "Fu " -0x4ff0: "He " -0x4ff1: "Ju " -0x4ff2: "Xiao " -0x4ff3: "Pai " -0x4ff4: "Jian " -0x4ff5: "Biao " -0x4ff6: "Chu " -0x4ff7: "Fei " -0x4ff8: "Feng " -0x4ff9: "Ya " -0x4ffa: "An " -0x4ffb: "Bei " -0x4ffc: "Yu " -0x4ffd: "Xin " -0x4ffe: "Bi " -0x4fff: "Jian " -/* x050 */ -0x5000: "Chang " -0x5001: "Chi " -0x5002: "Bing " -0x5003: "Zan " -0x5004: "Yao " -0x5005: "Cui " -0x5006: "Lia " -0x5007: "Wan " -0x5008: "Lai " -0x5009: "Cang " -0x500a: "Zong " -0x500b: "Ge " -0x500c: "Guan " -0x500d: "Bei " -0x500e: "Tian " -0x500f: "Shu " -0x5010: "Shu " -0x5011: "Men " -0x5012: "Dao " -0x5013: "Tan " -0x5014: "Jue " -0x5015: "Chui " -0x5016: "Xing " -0x5017: "Peng " -0x5018: "Tang " -0x5019: "Hou " -0x501a: "Yi " -0x501b: "Qi " -0x501c: "Ti " -0x501d: "Gan " -0x501e: "Jing " -0x501f: "Jie " -0x5020: "Sui " -0x5021: "Chang " -0x5022: "Jie " -0x5023: "Fang " -0x5024: "Zhi " -0x5025: "Kong " -0x5026: "Juan " -0x5027: "Zong " -0x5028: "Ju " -0x5029: "Qian " -0x502a: "Ni " -0x502b: "Lun " -0x502c: "Zhuo " -0x502d: "Wei " -0x502e: "Luo " -0x502f: "Song " -0x5030: "Leng " -0x5031: "Hun " -0x5032: "Dong " -0x5033: "Zi " -0x5034: "Ben " -0x5035: "Wu " -0x5036: "Ju " -0x5037: "Nai " -0x5038: "Cai " -0x5039: "Jian " -0x503a: "Zhai " -0x503b: "Ye " -0x503c: "Zhi " -0x503d: "Sha " -0x503e: "Qing " -0x503f: "[?] " -0x5040: "Ying " -0x5041: "Cheng " -0x5042: "Jian " -0x5043: "Yan " -0x5044: "Nuan " -0x5045: "Zhong " -0x5046: "Chun " -0x5047: "Jia " -0x5048: "Jie " -0x5049: "Wei " -0x504a: "Yu " -0x504b: "Bing " -0x504c: "Ruo " -0x504d: "Ti " -0x504e: "Wei " -0x504f: "Pian " -0x5050: "Yan " -0x5051: "Feng " -0x5052: "Tang " -0x5053: "Wo " -0x5054: "E " -0x5055: "Xie " -0x5056: "Che " -0x5057: "Sheng " -0x5058: "Kan " -0x5059: "Di " -0x505a: "Zuo " -0x505b: "Cha " -0x505c: "Ting " -0x505d: "Bei " -0x505e: "Ye " -0x505f: "Huang " -0x5060: "Yao " -0x5061: "Zhan " -0x5062: "Chou " -0x5063: "Yan " -0x5064: "You " -0x5065: "Jian " -0x5066: "Xu " -0x5067: "Zha " -0x5068: "Ci " -0x5069: "Fu " -0x506a: "Bi " -0x506b: "Zhi " -0x506c: "Zong " -0x506d: "Mian " -0x506e: "Ji " -0x506f: "Yi " -0x5070: "Xie " -0x5071: "Xun " -0x5072: "Si " -0x5073: "Duan " -0x5074: "Ce " -0x5075: "Zhen " -0x5076: "Ou " -0x5077: "Tou " -0x5078: "Tou " -0x5079: "Bei " -0x507a: "Za " -0x507b: "Lu " -0x507c: "Jie " -0x507d: "Wei " -0x507e: "Fen " -0x507f: "Chang " -0x5080: "Gui " -0x5081: "Sou " -0x5082: "Zhi " -0x5083: "Su " -0x5084: "Xia " -0x5085: "Fu " -0x5086: "Yuan " -0x5087: "Rong " -0x5088: "Li " -0x5089: "Ru " -0x508a: "Yun " -0x508b: "Gou " -0x508c: "Ma " -0x508d: "Bang " -0x508e: "Dian " -0x508f: "Tang " -0x5090: "Hao " -0x5091: "Jie " -0x5092: "Xi " -0x5093: "Shan " -0x5094: "Qian " -0x5095: "Jue " -0x5096: "Cang " -0x5097: "Chu " -0x5098: "San " -0x5099: "Bei " -0x509a: "Xiao " -0x509b: "Yong " -0x509c: "Yao " -0x509d: "Tan " -0x509e: "Suo " -0x509f: "Yang " -0x50a0: "Fa " -0x50a1: "Bing " -0x50a2: "Jia " -0x50a3: "Dai " -0x50a4: "Zai " -0x50a5: "Tang " -0x50a6: "[?] " -0x50a7: "Bin " -0x50a8: "Chu " -0x50a9: "Nuo " -0x50aa: "Can " -0x50ab: "Lei " -0x50ac: "Cui " -0x50ad: "Yong " -0x50ae: "Zao " -0x50af: "Zong " -0x50b0: "Peng " -0x50b1: "Song " -0x50b2: "Ao " -0x50b3: "Chuan " -0x50b4: "Yu " -0x50b5: "Zhai " -0x50b6: "Cou " -0x50b7: "Shang " -0x50b8: "Qiang " -0x50b9: "Jing " -0x50ba: "Chi " -0x50bb: "Sha " -0x50bc: "Han " -0x50bd: "Zhang " -0x50be: "Qing " -0x50bf: "Yan " -0x50c0: "Di " -0x50c1: "Xi " -0x50c2: "Lu " -0x50c3: "Bei " -0x50c4: "Piao " -0x50c5: "Jin " -0x50c6: "Lian " -0x50c7: "Lu " -0x50c8: "Man " -0x50c9: "Qian " -0x50ca: "Xian " -0x50cb: "Tan " -0x50cc: "Ying " -0x50cd: "Dong " -0x50ce: "Zhuan " -0x50cf: "Xiang " -0x50d0: "Shan " -0x50d1: "Qiao " -0x50d2: "Jiong " -0x50d3: "Tui " -0x50d4: "Zun " -0x50d5: "Pu " -0x50d6: "Xi " -0x50d7: "Lao " -0x50d8: "Chang " -0x50d9: "Guang " -0x50da: "Liao " -0x50db: "Qi " -0x50dc: "Deng " -0x50dd: "Chan " -0x50de: "Wei " -0x50df: "Ji " -0x50e0: "Fan " -0x50e1: "Hui " -0x50e2: "Chuan " -0x50e3: "Jian " -0x50e4: "Dan " -0x50e5: "Jiao " -0x50e6: "Jiu " -0x50e7: "Seng " -0x50e8: "Fen " -0x50e9: "Xian " -0x50ea: "Jue " -0x50eb: "E " -0x50ec: "Jiao " -0x50ed: "Jian " -0x50ee: "Tong " -0x50ef: "Lin " -0x50f0: "Bo " -0x50f1: "Gu " -0x50f2: "[?] " -0x50f3: "Su " -0x50f4: "Xian " -0x50f5: "Jiang " -0x50f6: "Min " -0x50f7: "Ye " -0x50f8: "Jin " -0x50f9: "Jia " -0x50fa: "Qiao " -0x50fb: "Pi " -0x50fc: "Feng " -0x50fd: "Zhou " -0x50fe: "Ai " -0x50ff: "Sai " -/* x051 */ -0x5100: "Yi " -0x5101: "Jun " -0x5102: "Nong " -0x5103: "Chan " -0x5104: "Yi " -0x5105: "Dang " -0x5106: "Jing " -0x5107: "Xuan " -0x5108: "Kuai " -0x5109: "Jian " -0x510a: "Chu " -0x510b: "Dan " -0x510c: "Jiao " -0x510d: "Sha " -0x510e: "Zai " -0x510f: "[?] " -0x5110: "Bin " -0x5111: "An " -0x5112: "Ru " -0x5113: "Tai " -0x5114: "Chou " -0x5115: "Chai " -0x5116: "Lan " -0x5117: "Ni " -0x5118: "Jin " -0x5119: "Qian " -0x511a: "Meng " -0x511b: "Wu " -0x511c: "Ning " -0x511d: "Qiong " -0x511e: "Ni " -0x511f: "Chang " -0x5120: "Lie " -0x5121: "Lei " -0x5122: "Lu " -0x5123: "Kuang " -0x5124: "Bao " -0x5125: "Du " -0x5126: "Biao " -0x5127: "Zan " -0x5128: "Zhi " -0x5129: "Si " -0x512a: "You " -0x512b: "Hao " -0x512c: "Chen " -0x512d: "Chen " -0x512e: "Li " -0x512f: "Teng " -0x5130: "Wei " -0x5131: "Long " -0x5132: "Chu " -0x5133: "Chan " -0x5134: "Rang " -0x5135: "Shu " -0x5136: "Hui " -0x5137: "Li " -0x5138: "Luo " -0x5139: "Zan " -0x513a: "Nuo " -0x513b: "Tang " -0x513c: "Yan " -0x513d: "Lei " -0x513e: "Nang " -0x513f: "Er " -0x5140: "Wu " -0x5141: "Yun " -0x5142: "Zan " -0x5143: "Yuan " -0x5144: "Xiong " -0x5145: "Chong " -0x5146: "Zhao " -0x5147: "Xiong " -0x5148: "Xian " -0x5149: "Guang " -0x514a: "Dui " -0x514b: "Ke " -0x514c: "Dui " -0x514d: "Mian " -0x514e: "Tu " -0x514f: "Chang " -0x5150: "Er " -0x5151: "Dui " -0x5152: "Er " -0x5153: "Xin " -0x5154: "Tu " -0x5155: "Si " -0x5156: "Yan " -0x5157: "Yan " -0x5158: "Shi " -0x5159: "Shi " -0x515a: "Dang " -0x515b: "Qian " -0x515c: "Dou " -0x515d: "Fen " -0x515e: "Mao " -0x515f: "Shen " -0x5160: "Dou " -0x5161: "Bai " -0x5162: "Jing " -0x5163: "Li " -0x5164: "Huang " -0x5165: "Ru " -0x5166: "Wang " -0x5167: "Nei " -0x5168: "Quan " -0x5169: "Liang " -0x516a: "Yu " -0x516b: "Ba " -0x516c: "Gong " -0x516d: "Liu " -0x516e: "Xi " -0x516f: "[?] " -0x5170: "Lan " -0x5171: "Gong " -0x5172: "Tian " -0x5173: "Guan " -0x5174: "Xing " -0x5175: "Bing " -0x5176: "Qi " -0x5177: "Ju " -0x5178: "Dian " -0x5179: "Zi " -0x517a: "Ppwun " -0x517b: "Yang " -0x517c: "Jian " -0x517d: "Shou " -0x517e: "Ji " -0x517f: "Yi " -0x5180: "Ji " -0x5181: "Chan " -0x5182: "Jiong " -0x5183: "Mao " -0x5184: "Ran " -0x5185: "Nei " -0x5186: "Yuan " -0x5187: "Mao " -0x5188: "Gang " -0x5189: "Ran " -0x518a: "Ce " -0x518b: "Jiong " -0x518c: "Ce " -0x518d: "Zai " -0x518e: "Gua " -0x518f: "Jiong " -0x5190: "Mao " -0x5191: "Zhou " -0x5192: "Mou " -0x5193: "Gou " -0x5194: "Xu " -0x5195: "Mian " -0x5196: "Mi " -0x5197: "Rong " -0x5198: "Yin " -0x5199: "Xie " -0x519a: "Kan " -0x519b: "Jun " -0x519c: "Nong " -0x519d: "Yi " -0x519e: "Mi " -0x519f: "Shi " -0x51a0: "Guan " -0x51a1: "Meng " -0x51a2: "Zhong " -0x51a3: "Ju " -0x51a4: "Yuan " -0x51a5: "Ming " -0x51a6: "Kou " -0x51a7: "Lam " -0x51a8: "Fu " -0x51a9: "Xie " -0x51aa: "Mi " -0x51ab: "Bing " -0x51ac: "Dong " -0x51ad: "Tai " -0x51ae: "Gang " -0x51af: "Feng " -0x51b0: "Bing " -0x51b1: "Hu " -0x51b2: "Chong " -0x51b3: "Jue " -0x51b4: "Hu " -0x51b5: "Kuang " -0x51b6: "Ye " -0x51b7: "Leng " -0x51b8: "Pan " -0x51b9: "Fu " -0x51ba: "Min " -0x51bb: "Dong " -0x51bc: "Xian " -0x51bd: "Lie " -0x51be: "Xia " -0x51bf: "Jian " -0x51c0: "Jing " -0x51c1: "Shu " -0x51c2: "Mei " -0x51c3: "Tu " -0x51c4: "Qi " -0x51c5: "Gu " -0x51c6: "Zhun " -0x51c7: "Song " -0x51c8: "Jing " -0x51c9: "Liang " -0x51ca: "Qing " -0x51cb: "Diao " -0x51cc: "Ling " -0x51cd: "Dong " -0x51ce: "Gan " -0x51cf: "Jian " -0x51d0: "Yin " -0x51d1: "Cou " -0x51d2: "Yi " -0x51d3: "Li " -0x51d4: "Cang " -0x51d5: "Ming " -0x51d6: "Zhuen " -0x51d7: "Cui " -0x51d8: "Si " -0x51d9: "Duo " -0x51da: "Jin " -0x51db: "Lin " -0x51dc: "Lin " -0x51dd: "Ning " -0x51de: "Xi " -0x51df: "Du " -0x51e0: "Ji " -0x51e1: "Fan " -0x51e2: "Fan " -0x51e3: "Fan " -0x51e4: "Feng " -0x51e5: "Ju " -0x51e6: "Chu " -0x51e7: "Tako " -0x51e8: "Feng " -0x51e9: "Mok " -0x51ea: "Ci " -0x51eb: "Fu " -0x51ec: "Feng " -0x51ed: "Ping " -0x51ee: "Feng " -0x51ef: "Kai " -0x51f0: "Huang " -0x51f1: "Kai " -0x51f2: "Gan " -0x51f3: "Deng " -0x51f4: "Ping " -0x51f5: "Qu " -0x51f6: "Xiong " -0x51f7: "Kuai " -0x51f8: "Tu " -0x51f9: "Ao " -0x51fa: "Chu " -0x51fb: "Ji " -0x51fc: "Dang " -0x51fd: "Han " -0x51fe: "Han " -0x51ff: "Zao " -/* x052 */ -0x5200: "Dao " -0x5201: "Diao " -0x5202: "Dao " -0x5203: "Ren " -0x5204: "Ren " -0x5205: "Chuang " -0x5206: "Fen " -0x5207: "Qie " -0x5208: "Yi " -0x5209: "Ji " -0x520a: "Kan " -0x520b: "Qian " -0x520c: "Cun " -0x520d: "Chu " -0x520e: "Wen " -0x520f: "Ji " -0x5210: "Dan " -0x5211: "Xing " -0x5212: "Hua " -0x5213: "Wan " -0x5214: "Jue " -0x5215: "Li " -0x5216: "Yue " -0x5217: "Lie " -0x5218: "Liu " -0x5219: "Ze " -0x521a: "Gang " -0x521b: "Chuang " -0x521c: "Fu " -0x521d: "Chu " -0x521e: "Qu " -0x521f: "Ju " -0x5220: "Shan " -0x5221: "Min " -0x5222: "Ling " -0x5223: "Zhong " -0x5224: "Pan " -0x5225: "Bie " -0x5226: "Jie " -0x5227: "Jie " -0x5228: "Bao " -0x5229: "Li " -0x522a: "Shan " -0x522b: "Bie " -0x522c: "Chan " -0x522d: "Jing " -0x522e: "Gua " -0x522f: "Gen " -0x5230: "Dao " -0x5231: "Chuang " -0x5232: "Kui " -0x5233: "Ku " -0x5234: "Duo " -0x5235: "Er " -0x5236: "Zhi " -0x5237: "Shua " -0x5238: "Quan " -0x5239: "Cha " -0x523a: "Ci " -0x523b: "Ke " -0x523c: "Jie " -0x523d: "Gui " -0x523e: "Ci " -0x523f: "Gui " -0x5240: "Kai " -0x5241: "Duo " -0x5242: "Ji " -0x5243: "Ti " -0x5244: "Jing " -0x5245: "Lou " -0x5246: "Gen " -0x5247: "Ze " -0x5248: "Yuan " -0x5249: "Cuo " -0x524a: "Xue " -0x524b: "Ke " -0x524c: "La " -0x524d: "Qian " -0x524e: "Cha " -0x524f: "Chuang " -0x5250: "Gua " -0x5251: "Jian " -0x5252: "Cuo " -0x5253: "Li " -0x5254: "Ti " -0x5255: "Fei " -0x5256: "Pou " -0x5257: "Chan " -0x5258: "Qi " -0x5259: "Chuang " -0x525a: "Zi " -0x525b: "Gang " -0x525c: "Wan " -0x525d: "Bo " -0x525e: "Ji " -0x525f: "Duo " -0x5260: "Qing " -0x5261: "Yan " -0x5262: "Zhuo " -0x5263: "Jian " -0x5264: "Ji " -0x5265: "Bo " -0x5266: "Yan " -0x5267: "Ju " -0x5268: "Huo " -0x5269: "Sheng " -0x526a: "Jian " -0x526b: "Duo " -0x526c: "Duan " -0x526d: "Wu " -0x526e: "Gua " -0x526f: "Fu " -0x5270: "Sheng " -0x5271: "Jian " -0x5272: "Ge " -0x5273: "Zha " -0x5274: "Kai " -0x5275: "Chuang " -0x5276: "Juan " -0x5277: "Chan " -0x5278: "Tuan " -0x5279: "Lu " -0x527a: "Li " -0x527b: "Fou " -0x527c: "Shan " -0x527d: "Piao " -0x527e: "Kou " -0x527f: "Jiao " -0x5280: "Gua " -0x5281: "Qiao " -0x5282: "Jue " -0x5283: "Hua " -0x5284: "Zha " -0x5285: "Zhuo " -0x5286: "Lian " -0x5287: "Ju " -0x5288: "Pi " -0x5289: "Liu " -0x528a: "Gui " -0x528b: "Jiao " -0x528c: "Gui " -0x528d: "Jian " -0x528e: "Jian " -0x528f: "Tang " -0x5290: "Huo " -0x5291: "Ji " -0x5292: "Jian " -0x5293: "Yi " -0x5294: "Jian " -0x5295: "Zhi " -0x5296: "Chan " -0x5297: "Cuan " -0x5298: "Mo " -0x5299: "Li " -0x529a: "Zhu " -0x529b: "Li " -0x529c: "Ya " -0x529d: "Quan " -0x529e: "Ban " -0x529f: "Gong " -0x52a0: "Jia " -0x52a1: "Wu " -0x52a2: "Mai " -0x52a3: "Lie " -0x52a4: "Jin " -0x52a5: "Keng " -0x52a6: "Xie " -0x52a7: "Zhi " -0x52a8: "Dong " -0x52a9: "Zhu " -0x52aa: "Nu " -0x52ab: "Jie " -0x52ac: "Qu " -0x52ad: "Shao " -0x52ae: "Yi " -0x52af: "Zhu " -0x52b0: "Miao " -0x52b1: "Li " -0x52b2: "Jing " -0x52b3: "Lao " -0x52b4: "Lao " -0x52b5: "Juan " -0x52b6: "Kou " -0x52b7: "Yang " -0x52b8: "Wa " -0x52b9: "Xiao " -0x52ba: "Mou " -0x52bb: "Kuang " -0x52bc: "Jie " -0x52bd: "Lie " -0x52be: "He " -0x52bf: "Shi " -0x52c0: "Ke " -0x52c1: "Jing " -0x52c2: "Hao " -0x52c3: "Bo " -0x52c4: "Min " -0x52c5: "Chi " -0x52c6: "Lang " -0x52c7: "Yong " -0x52c8: "Yong " -0x52c9: "Mian " -0x52ca: "Ke " -0x52cb: "Xun " -0x52cc: "Juan " -0x52cd: "Qing " -0x52ce: "Lu " -0x52cf: "Pou " -0x52d0: "Meng " -0x52d1: "Lai " -0x52d2: "Le " -0x52d3: "Kai " -0x52d4: "Mian " -0x52d5: "Dong " -0x52d6: "Xu " -0x52d7: "Xu " -0x52d8: "Kan " -0x52d9: "Wu " -0x52da: "Yi " -0x52db: "Xun " -0x52dc: "Weng " -0x52dd: "Sheng " -0x52de: "Lao " -0x52df: "Mu " -0x52e0: "Lu " -0x52e1: "Piao " -0x52e2: "Shi " -0x52e3: "Ji " -0x52e4: "Qin " -0x52e5: "Qiang " -0x52e6: "Jiao " -0x52e7: "Quan " -0x52e8: "Yang " -0x52e9: "Yi " -0x52ea: "Jue " -0x52eb: "Fan " -0x52ec: "Juan " -0x52ed: "Tong " -0x52ee: "Ju " -0x52ef: "Dan " -0x52f0: "Xie " -0x52f1: "Mai " -0x52f2: "Xun " -0x52f3: "Xun " -0x52f4: "Lu " -0x52f5: "Li " -0x52f6: "Che " -0x52f7: "Rang " -0x52f8: "Quan " -0x52f9: "Bao " -0x52fa: "Shao " -0x52fb: "Yun " -0x52fc: "Jiu " -0x52fd: "Bao " -0x52fe: "Gou " -0x52ff: "Wu " -/* x053 */ -0x5300: "Yun " -0x5301: "Mwun " -0x5302: "Nay " -0x5303: "Gai " -0x5304: "Gai " -0x5305: "Bao " -0x5306: "Cong " -0x5307: "[?] " -0x5308: "Xiong " -0x5309: "Peng " -0x530a: "Ju " -0x530b: "Tao " -0x530c: "Ge " -0x530d: "Pu " -0x530e: "An " -0x530f: "Pao " -0x5310: "Fu " -0x5311: "Gong " -0x5312: "Da " -0x5313: "Jiu " -0x5314: "Qiong " -0x5315: "Bi " -0x5316: "Hua " -0x5317: "Bei " -0x5318: "Nao " -0x5319: "Chi " -0x531a: "Fang " -0x531b: "Jiu " -0x531c: "Yi " -0x531d: "Za " -0x531e: "Jiang " -0x531f: "Kang " -0x5320: "Jiang " -0x5321: "Kuang " -0x5322: "Hu " -0x5323: "Xia " -0x5324: "Qu " -0x5325: "Bian " -0x5326: "Gui " -0x5327: "Qie " -0x5328: "Zang " -0x5329: "Kuang " -0x532a: "Fei " -0x532b: "Hu " -0x532c: "Tou " -0x532d: "Gui " -0x532e: "Gui " -0x532f: "Hui " -0x5330: "Dan " -0x5331: "Gui " -0x5332: "Lian " -0x5333: "Lian " -0x5334: "Suan " -0x5335: "Du " -0x5336: "Jiu " -0x5337: "Qu " -0x5338: "Xi " -0x5339: "Pi " -0x533a: "Qu " -0x533b: "Yi " -0x533c: "Qia " -0x533d: "Yan " -0x533e: "Bian " -0x533f: "Ni " -0x5340: "Qu " -0x5341: "Shi " -0x5342: "Xin " -0x5343: "Qian " -0x5344: "Nian " -0x5345: "Sa " -0x5346: "Zu " -0x5347: "Sheng " -0x5348: "Wu " -0x5349: "Hui " -0x534a: "Ban " -0x534b: "Shi " -0x534c: "Xi " -0x534d: "Wan " -0x534e: "Hua " -0x534f: "Xie " -0x5350: "Wan " -0x5351: "Bei " -0x5352: "Zu " -0x5353: "Zhuo " -0x5354: "Xie " -0x5355: "Dan " -0x5356: "Mai " -0x5357: "Nan " -0x5358: "Dan " -0x5359: "Ji " -0x535a: "Bo " -0x535b: "Shuai " -0x535c: "Bu " -0x535d: "Kuang " -0x535e: "Bian " -0x535f: "Bu " -0x5360: "Zhan " -0x5361: "Qia " -0x5362: "Lu " -0x5363: "You " -0x5364: "Lu " -0x5365: "Xi " -0x5366: "Gua " -0x5367: "Wo " -0x5368: "Xie " -0x5369: "Jie " -0x536a: "Jie " -0x536b: "Wei " -0x536c: "Ang " -0x536d: "Qiong " -0x536e: "Zhi " -0x536f: "Mao " -0x5370: "Yin " -0x5371: "Wei " -0x5372: "Shao " -0x5373: "Ji " -0x5374: "Que " -0x5375: "Luan " -0x5376: "Shi " -0x5377: "Juan " -0x5378: "Xie " -0x5379: "Xu " -0x537a: "Jin " -0x537b: "Que " -0x537c: "Wu " -0x537d: "Ji " -0x537e: "E " -0x537f: "Qing " -0x5380: "Xi " -0x5381: "[?] " -0x5382: "Han " -0x5383: "Zhan " -0x5384: "E " -0x5385: "Ting " -0x5386: "Li " -0x5387: "Zhe " -0x5388: "Han " -0x5389: "Li " -0x538a: "Ya " -0x538b: "Ya " -0x538c: "Yan " -0x538d: "She " -0x538e: "Zhi " -0x538f: "Zha " -0x5390: "Pang " -0x5391: "[?] " -0x5392: "He " -0x5393: "Ya " -0x5394: "Zhi " -0x5395: "Ce " -0x5396: "Pang " -0x5397: "Ti " -0x5398: "Li " -0x5399: "She " -0x539a: "Hou " -0x539b: "Ting " -0x539c: "Zui " -0x539d: "Cuo " -0x539e: "Fei " -0x539f: "Yuan " -0x53a0: "Ce " -0x53a1: "Yuan " -0x53a2: "Xiang " -0x53a3: "Yan " -0x53a4: "Li " -0x53a5: "Jue " -0x53a6: "Sha " -0x53a7: "Dian " -0x53a8: "Chu " -0x53a9: "Jiu " -0x53aa: "Qin " -0x53ab: "Ao " -0x53ac: "Gui " -0x53ad: "Yan " -0x53ae: "Si " -0x53af: "Li " -0x53b0: "Chang " -0x53b1: "Lan " -0x53b2: "Li " -0x53b3: "Yan " -0x53b4: "Yan " -0x53b5: "Yuan " -0x53b6: "Si " -0x53b7: "Gong " -0x53b8: "Lin " -0x53b9: "Qiu " -0x53ba: "Qu " -0x53bb: "Qu " -0x53bc: "Uk " -0x53bd: "Lei " -0x53be: "Du " -0x53bf: "Xian " -0x53c0: "Zhuan " -0x53c1: "San " -0x53c2: "Can " -0x53c3: "Can " -0x53c4: "Can " -0x53c5: "Can " -0x53c6: "Ai " -0x53c7: "Dai " -0x53c8: "You " -0x53c9: "Cha " -0x53ca: "Ji " -0x53cb: "You " -0x53cc: "Shuang " -0x53cd: "Fan " -0x53ce: "Shou " -0x53cf: "Guai " -0x53d0: "Ba " -0x53d1: "Fa " -0x53d2: "Ruo " -0x53d3: "Shi " -0x53d4: "Shu " -0x53d5: "Zhuo " -0x53d6: "Qu " -0x53d7: "Shou " -0x53d8: "Bian " -0x53d9: "Xu " -0x53da: "Jia " -0x53db: "Pan " -0x53dc: "Sou " -0x53dd: "Gao " -0x53de: "Wei " -0x53df: "Sou " -0x53e0: "Die " -0x53e1: "Rui " -0x53e2: "Cong " -0x53e3: "Kou " -0x53e4: "Gu " -0x53e5: "Ju " -0x53e6: "Ling " -0x53e7: "Gua " -0x53e8: "Tao " -0x53e9: "Kou " -0x53ea: "Zhi " -0x53eb: "Jiao " -0x53ec: "Zhao " -0x53ed: "Ba " -0x53ee: "Ding " -0x53ef: "Ke " -0x53f0: "Tai " -0x53f1: "Chi " -0x53f2: "Shi " -0x53f3: "You " -0x53f4: "Qiu " -0x53f5: "Po " -0x53f6: "Xie " -0x53f7: "Hao " -0x53f8: "Si " -0x53f9: "Tan " -0x53fa: "Chi " -0x53fb: "Le " -0x53fc: "Diao " -0x53fd: "Ji " -0x53fe: "[?] " -0x53ff: "Hong " -/* x054 */ -0x5400: "Mie " -0x5401: "Xu " -0x5402: "Mang " -0x5403: "Chi " -0x5404: "Ge " -0x5405: "Xuan " -0x5406: "Yao " -0x5407: "Zi " -0x5408: "He " -0x5409: "Ji " -0x540a: "Diao " -0x540b: "Cun " -0x540c: "Tong " -0x540d: "Ming " -0x540e: "Hou " -0x540f: "Li " -0x5410: "Tu " -0x5411: "Xiang " -0x5412: "Zha " -0x5413: "Xia " -0x5414: "Ye " -0x5415: "Lu " -0x5416: "A " -0x5417: "Ma " -0x5418: "Ou " -0x5419: "Xue " -0x541a: "Yi " -0x541b: "Jun " -0x541c: "Chou " -0x541d: "Lin " -0x541e: "Tun " -0x541f: "Yin " -0x5420: "Fei " -0x5421: "Bi " -0x5422: "Qin " -0x5423: "Qin " -0x5424: "Jie " -0x5425: "Bu " -0x5426: "Fou " -0x5427: "Ba " -0x5428: "Dun " -0x5429: "Fen " -0x542a: "E " -0x542b: "Han " -0x542c: "Ting " -0x542d: "Hang " -0x542e: "Shun " -0x542f: "Qi " -0x5430: "Hong " -0x5431: "Zhi " -0x5432: "Shen " -0x5433: "Wu " -0x5434: "Wu " -0x5435: "Chao " -0x5436: "Ne " -0x5437: "Xue " -0x5438: "Xi " -0x5439: "Chui " -0x543a: "Dou " -0x543b: "Wen " -0x543c: "Hou " -0x543d: "Ou " -0x543e: "Wu " -0x543f: "Gao " -0x5440: "Ya " -0x5441: "Jun " -0x5442: "Lu " -0x5443: "E " -0x5444: "Ge " -0x5445: "Mei " -0x5446: "Ai " -0x5447: "Qi " -0x5448: "Cheng " -0x5449: "Wu " -0x544a: "Gao " -0x544b: "Fu " -0x544c: "Jiao " -0x544d: "Hong " -0x544e: "Chi " -0x544f: "Sheng " -0x5450: "Ne " -0x5451: "Tun " -0x5452: "Fu " -0x5453: "Yi " -0x5454: "Dai " -0x5455: "Ou " -0x5456: "Li " -0x5457: "Bai " -0x5458: "Yuan " -0x5459: "Kuai " -0x545a: "[?] " -0x545b: "Qiang " -0x545c: "Wu " -0x545d: "E " -0x545e: "Shi " -0x545f: "Quan " -0x5460: "Pen " -0x5461: "Wen " -0x5462: "Ni " -0x5463: "M " -0x5464: "Ling " -0x5465: "Ran " -0x5466: "You " -0x5467: "Di " -0x5468: "Zhou " -0x5469: "Shi " -0x546a: "Zhou " -0x546b: "Tie " -0x546c: "Xi " -0x546d: "Yi " -0x546e: "Qi " -0x546f: "Ping " -0x5470: "Zi " -0x5471: "Gu " -0x5472: "Zi " -0x5473: "Wei " -0x5474: "Xu " -0x5475: "He " -0x5476: "Nao " -0x5477: "Xia " -0x5478: "Pei " -0x5479: "Yi " -0x547a: "Xiao " -0x547b: "Shen " -0x547c: "Hu " -0x547d: "Ming " -0x547e: "Da " -0x547f: "Qu " -0x5480: "Ju " -0x5481: "Gem " -0x5482: "Za " -0x5483: "Tuo " -0x5484: "Duo " -0x5485: "Pou " -0x5486: "Pao " -0x5487: "Bi " -0x5488: "Fu " -0x5489: "Yang " -0x548a: "He " -0x548b: "Zha " -0x548c: "He " -0x548d: "Hai " -0x548e: "Jiu " -0x548f: "Yong " -0x5490: "Fu " -0x5491: "Que " -0x5492: "Zhou " -0x5493: "Wa " -0x5494: "Ka " -0x5495: "Gu " -0x5496: "Ka " -0x5497: "Zuo " -0x5498: "Bu " -0x5499: "Long " -0x549a: "Dong " -0x549b: "Ning " -0x549c: "Tha " -0x549d: "Si " -0x549e: "Xian " -0x549f: "Huo " -0x54a0: "Qi " -0x54a1: "Er " -0x54a2: "E " -0x54a3: "Guang " -0x54a4: "Zha " -0x54a5: "Xi " -0x54a6: "Yi " -0x54a7: "Lie " -0x54a8: "Zi " -0x54a9: "Mie " -0x54aa: "Mi " -0x54ab: "Zhi " -0x54ac: "Yao " -0x54ad: "Ji " -0x54ae: "Zhou " -0x54af: "Ge " -0x54b0: "Shuai " -0x54b1: "Zan " -0x54b2: "Xiao " -0x54b3: "Ke " -0x54b4: "Hui " -0x54b5: "Kua " -0x54b6: "Huai " -0x54b7: "Tao " -0x54b8: "Xian " -0x54b9: "E " -0x54ba: "Xuan " -0x54bb: "Xiu " -0x54bc: "Wai " -0x54bd: "Yan " -0x54be: "Lao " -0x54bf: "Yi " -0x54c0: "Ai " -0x54c1: "Pin " -0x54c2: "Shen " -0x54c3: "Tong " -0x54c4: "Hong " -0x54c5: "Xiong " -0x54c6: "Chi " -0x54c7: "Wa " -0x54c8: "Ha " -0x54c9: "Zai " -0x54ca: "Yu " -0x54cb: "Di " -0x54cc: "Pai " -0x54cd: "Xiang " -0x54ce: "Ai " -0x54cf: "Hen " -0x54d0: "Kuang " -0x54d1: "Ya " -0x54d2: "Da " -0x54d3: "Xiao " -0x54d4: "Bi " -0x54d5: "Yue " -0x54d6: "[?] " -0x54d7: "Hua " -0x54d8: "Sasou " -0x54d9: "Kuai " -0x54da: "Duo " -0x54db: "[?] " -0x54dc: "Ji " -0x54dd: "Nong " -0x54de: "Mou " -0x54df: "Yo " -0x54e0: "Hao " -0x54e1: "Yuan " -0x54e2: "Long " -0x54e3: "Pou " -0x54e4: "Mang " -0x54e5: "Ge " -0x54e6: "E " -0x54e7: "Chi " -0x54e8: "Shao " -0x54e9: "Li " -0x54ea: "Na " -0x54eb: "Zu " -0x54ec: "He " -0x54ed: "Ku " -0x54ee: "Xiao " -0x54ef: "Xian " -0x54f0: "Lao " -0x54f1: "Bo " -0x54f2: "Zhe " -0x54f3: "Zha " -0x54f4: "Liang " -0x54f5: "Ba " -0x54f6: "Mie " -0x54f7: "Le " -0x54f8: "Sui " -0x54f9: "Fou " -0x54fa: "Bu " -0x54fb: "Han " -0x54fc: "Heng " -0x54fd: "Geng " -0x54fe: "Shuo " -0x54ff: "Ge " -/* x055 */ -0x5500: "You " -0x5501: "Yan " -0x5502: "Gu " -0x5503: "Gu " -0x5504: "Bai " -0x5505: "Han " -0x5506: "Suo " -0x5507: "Chun " -0x5508: "Yi " -0x5509: "Ai " -0x550a: "Jia " -0x550b: "Tu " -0x550c: "Xian " -0x550d: "Huan " -0x550e: "Li " -0x550f: "Xi " -0x5510: "Tang " -0x5511: "Zuo " -0x5512: "Qiu " -0x5513: "Che " -0x5514: "Wu " -0x5515: "Zao " -0x5516: "Ya " -0x5517: "Dou " -0x5518: "Qi " -0x5519: "Di " -0x551a: "Qin " -0x551b: "Ma " -0x551c: "Mal " -0x551d: "Hong " -0x551e: "Dou " -0x551f: "Kes " -0x5520: "Lao " -0x5521: "Liang " -0x5522: "Suo " -0x5523: "Zao " -0x5524: "Huan " -0x5525: "Lang " -0x5526: "Sha " -0x5527: "Ji " -0x5528: "Zuo " -0x5529: "Wo " -0x552a: "Feng " -0x552b: "Yin " -0x552c: "Hu " -0x552d: "Qi " -0x552e: "Shou " -0x552f: "Wei " -0x5530: "Shua " -0x5531: "Chang " -0x5532: "Er " -0x5533: "Li " -0x5534: "Qiang " -0x5535: "An " -0x5536: "Jie " -0x5537: "Yo " -0x5538: "Nian " -0x5539: "Yu " -0x553a: "Tian " -0x553b: "Lai " -0x553c: "Sha " -0x553d: "Xi " -0x553e: "Tuo " -0x553f: "Hu " -0x5540: "Ai " -0x5541: "Zhou " -0x5542: "Nou " -0x5543: "Ken " -0x5544: "Zhuo " -0x5545: "Zhuo " -0x5546: "Shang " -0x5547: "Di " -0x5548: "Heng " -0x5549: "Lan " -0x554a: "A " -0x554b: "Xiao " -0x554c: "Xiang " -0x554d: "Tun " -0x554e: "Wu " -0x554f: "Wen " -0x5550: "Cui " -0x5551: "Sha " -0x5552: "Hu " -0x5553: "Qi " -0x5554: "Qi " -0x5555: "Tao " -0x5556: "Dan " -0x5557: "Dan " -0x5558: "Ye " -0x5559: "Zi " -0x555a: "Bi " -0x555b: "Cui " -0x555c: "Chuo " -0x555d: "He " -0x555e: "Ya " -0x555f: "Qi " -0x5560: "Zhe " -0x5561: "Pei " -0x5562: "Liang " -0x5563: "Xian " -0x5564: "Pi " -0x5565: "Sha " -0x5566: "La " -0x5567: "Ze " -0x5568: "Qing " -0x5569: "Gua " -0x556a: "Pa " -0x556b: "Zhe " -0x556c: "Se " -0x556d: "Zhuan " -0x556e: "Nie " -0x556f: "Guo " -0x5570: "Luo " -0x5571: "Yan " -0x5572: "Di " -0x5573: "Quan " -0x5574: "Tan " -0x5575: "Bo " -0x5576: "Ding " -0x5577: "Lang " -0x5578: "Xiao " -0x5579: "[?] " -0x557a: "Tang " -0x557b: "Chi " -0x557c: "Ti " -0x557d: "An " -0x557e: "Jiu " -0x557f: "Dan " -0x5580: "Ke " -0x5581: "Yong " -0x5582: "Wei " -0x5583: "Nan " -0x5584: "Shan " -0x5585: "Yu " -0x5586: "Zhe " -0x5587: "La " -0x5588: "Jie " -0x5589: "Hou " -0x558a: "Han " -0x558b: "Die " -0x558c: "Zhou " -0x558d: "Chai " -0x558e: "Wai " -0x558f: "Re " -0x5590: "Yu " -0x5591: "Yin " -0x5592: "Zan " -0x5593: "Yao " -0x5594: "Wo " -0x5595: "Mian " -0x5596: "Hu " -0x5597: "Yun " -0x5598: "Chuan " -0x5599: "Hui " -0x559a: "Huan " -0x559b: "Huan " -0x559c: "Xi " -0x559d: "He " -0x559e: "Ji " -0x559f: "Kui " -0x55a0: "Zhong " -0x55a1: "Wei " -0x55a2: "Sha " -0x55a3: "Xu " -0x55a4: "Huang " -0x55a5: "Du " -0x55a6: "Nie " -0x55a7: "Xuan " -0x55a8: "Liang " -0x55a9: "Yu " -0x55aa: "Sang " -0x55ab: "Chi " -0x55ac: "Qiao " -0x55ad: "Yan " -0x55ae: "Dan " -0x55af: "Pen " -0x55b0: "Can " -0x55b1: "Li " -0x55b2: "Yo " -0x55b3: "Zha " -0x55b4: "Wei " -0x55b5: "Miao " -0x55b6: "Ying " -0x55b7: "Pen " -0x55b8: "Phos " -0x55b9: "Kui " -0x55ba: "Xi " -0x55bb: "Yu " -0x55bc: "Jie " -0x55bd: "Lou " -0x55be: "Ku " -0x55bf: "Sao " -0x55c0: "Huo " -0x55c1: "Ti " -0x55c2: "Yao " -0x55c3: "He " -0x55c4: "A " -0x55c5: "Xiu " -0x55c6: "Qiang " -0x55c7: "Se " -0x55c8: "Yong " -0x55c9: "Su " -0x55ca: "Hong " -0x55cb: "Xie " -0x55cc: "Yi " -0x55cd: "Suo " -0x55ce: "Ma " -0x55cf: "Cha " -0x55d0: "Hai " -0x55d1: "Ke " -0x55d2: "Ta " -0x55d3: "Sang " -0x55d4: "Tian " -0x55d5: "Ru " -0x55d6: "Sou " -0x55d7: "Wa " -0x55d8: "Ji " -0x55d9: "Pang " -0x55da: "Wu " -0x55db: "Xian " -0x55dc: "Shi " -0x55dd: "Ge " -0x55de: "Zi " -0x55df: "Jie " -0x55e0: "Luo " -0x55e1: "Weng " -0x55e2: "Wa " -0x55e3: "Si " -0x55e4: "Chi " -0x55e5: "Hao " -0x55e6: "Suo " -0x55e7: "Jia " -0x55e8: "Hai " -0x55e9: "Suo " -0x55ea: "Qin " -0x55eb: "Nie " -0x55ec: "He " -0x55ed: "Cis " -0x55ee: "Sai " -0x55ef: "Ng " -0x55f0: "Ge " -0x55f1: "Na " -0x55f2: "Dia " -0x55f3: "Ai " -0x55f4: "[?] " -0x55f5: "Tong " -0x55f6: "Bi " -0x55f7: "Ao " -0x55f8: "Ao " -0x55f9: "Lian " -0x55fa: "Cui " -0x55fb: "Zhe " -0x55fc: "Mo " -0x55fd: "Sou " -0x55fe: "Sou " -0x55ff: "Tan " -/* x056 */ -0x5600: "Di " -0x5601: "Qi " -0x5602: "Jiao " -0x5603: "Chong " -0x5604: "Jiao " -0x5605: "Kai " -0x5606: "Tan " -0x5607: "San " -0x5608: "Cao " -0x5609: "Jia " -0x560a: "Ai " -0x560b: "Xiao " -0x560c: "Piao " -0x560d: "Lou " -0x560e: "Ga " -0x560f: "Gu " -0x5610: "Xiao " -0x5611: "Hu " -0x5612: "Hui " -0x5613: "Guo " -0x5614: "Ou " -0x5615: "Xian " -0x5616: "Ze " -0x5617: "Chang " -0x5618: "Xu " -0x5619: "Po " -0x561a: "De " -0x561b: "Ma " -0x561c: "Ma " -0x561d: "Hu " -0x561e: "Lei " -0x561f: "Du " -0x5620: "Ga " -0x5621: "Tang " -0x5622: "Ye " -0x5623: "Beng " -0x5624: "Ying " -0x5625: "Saai " -0x5626: "Jiao " -0x5627: "Mi " -0x5628: "Xiao " -0x5629: "Hua " -0x562a: "Mai " -0x562b: "Ran " -0x562c: "Zuo " -0x562d: "Peng " -0x562e: "Lao " -0x562f: "Xiao " -0x5630: "Ji " -0x5631: "Zhu " -0x5632: "Chao " -0x5633: "Kui " -0x5634: "Zui " -0x5635: "Xiao " -0x5636: "Si " -0x5637: "Hao " -0x5638: "Fu " -0x5639: "Liao " -0x563a: "Qiao " -0x563b: "Xi " -0x563c: "Xiu " -0x563d: "Tan " -0x563e: "Tan " -0x563f: "Mo " -0x5640: "Xun " -0x5641: "E " -0x5642: "Zun " -0x5643: "Fan " -0x5644: "Chi " -0x5645: "Hui " -0x5646: "Zan " -0x5647: "Chuang " -0x5648: "Cu " -0x5649: "Dan " -0x564a: "Yu " -0x564b: "Tun " -0x564c: "Cheng " -0x564d: "Jiao " -0x564e: "Ye " -0x564f: "Xi " -0x5650: "Qi " -0x5651: "Hao " -0x5652: "Lian " -0x5653: "Xu " -0x5654: "Deng " -0x5655: "Hui " -0x5656: "Yin " -0x5657: "Pu " -0x5658: "Jue " -0x5659: "Qin " -0x565a: "Xun " -0x565b: "Nie " -0x565c: "Lu " -0x565d: "Si " -0x565e: "Yan " -0x565f: "Ying " -0x5660: "Da " -0x5661: "Dan " -0x5662: "Yu " -0x5663: "Zhou " -0x5664: "Jin " -0x5665: "Nong " -0x5666: "Yue " -0x5667: "Hui " -0x5668: "Qi " -0x5669: "E " -0x566a: "Zao " -0x566b: "Yi " -0x566c: "Shi " -0x566d: "Jiao " -0x566e: "Yuan " -0x566f: "Ai " -0x5670: "Yong " -0x5671: "Jue " -0x5672: "Kuai " -0x5673: "Yu " -0x5674: "Pen " -0x5675: "Dao " -0x5676: "Ge " -0x5677: "Xin " -0x5678: "Dun " -0x5679: "Dang " -0x567a: "Sin " -0x567b: "Sai " -0x567c: "Pi " -0x567d: "Pi " -0x567e: "Yin " -0x567f: "Zui " -0x5680: "Ning " -0x5681: "Di " -0x5682: "Lan " -0x5683: "Ta " -0x5684: "Huo " -0x5685: "Ru " -0x5686: "Hao " -0x5687: "Xia " -0x5688: "Ya " -0x5689: "Duo " -0x568a: "Xi " -0x568b: "Chou " -0x568c: "Ji " -0x568d: "Jin " -0x568e: "Hao " -0x568f: "Ti " -0x5690: "Chang " -0x5691: "[?] " -0x5692: "[?] " -0x5693: "Ca " -0x5694: "Ti " -0x5695: "Lu " -0x5696: "Hui " -0x5697: "Bo " -0x5698: "You " -0x5699: "Nie " -0x569a: "Yin " -0x569b: "Hu " -0x569c: "Mo " -0x569d: "Huang " -0x569e: "Zhe " -0x569f: "Li " -0x56a0: "Liu " -0x56a1: "Haai " -0x56a2: "Nang " -0x56a3: "Xiao " -0x56a4: "Mo " -0x56a5: "Yan " -0x56a6: "Li " -0x56a7: "Lu " -0x56a8: "Long " -0x56a9: "Fu " -0x56aa: "Dan " -0x56ab: "Chen " -0x56ac: "Pin " -0x56ad: "Pi " -0x56ae: "Xiang " -0x56af: "Huo " -0x56b0: "Mo " -0x56b1: "Xi " -0x56b2: "Duo " -0x56b3: "Ku " -0x56b4: "Yan " -0x56b5: "Chan " -0x56b6: "Ying " -0x56b7: "Rang " -0x56b8: "Dian " -0x56b9: "La " -0x56ba: "Ta " -0x56bb: "Xiao " -0x56bc: "Jiao " -0x56bd: "Chuo " -0x56be: "Huan " -0x56bf: "Huo " -0x56c0: "Zhuan " -0x56c1: "Nie " -0x56c2: "Xiao " -0x56c3: "Ca " -0x56c4: "Li " -0x56c5: "Chan " -0x56c6: "Chai " -0x56c7: "Li " -0x56c8: "Yi " -0x56c9: "Luo " -0x56ca: "Nang " -0x56cb: "Zan " -0x56cc: "Su " -0x56cd: "Xi " -0x56ce: "So " -0x56cf: "Jian " -0x56d0: "Za " -0x56d1: "Zhu " -0x56d2: "Lan " -0x56d3: "Nie " -0x56d4: "Nang " -0x56d5: "[?] " -0x56d6: "[?] " -0x56d7: "Wei " -0x56d8: "Hui " -0x56d9: "Yin " -0x56da: "Qiu " -0x56db: "Si " -0x56dc: "Nin " -0x56dd: "Jian " -0x56de: "Hui " -0x56df: "Xin " -0x56e0: "Yin " -0x56e1: "Nan " -0x56e2: "Tuan " -0x56e3: "Tuan " -0x56e4: "Dun " -0x56e5: "Kang " -0x56e6: "Yuan " -0x56e7: "Jiong " -0x56e8: "Pian " -0x56e9: "Yun " -0x56ea: "Cong " -0x56eb: "Hu " -0x56ec: "Hui " -0x56ed: "Yuan " -0x56ee: "You " -0x56ef: "Guo " -0x56f0: "Kun " -0x56f1: "Cong " -0x56f2: "Wei " -0x56f3: "Tu " -0x56f4: "Wei " -0x56f5: "Lun " -0x56f6: "Guo " -0x56f7: "Qun " -0x56f8: "Ri " -0x56f9: "Ling " -0x56fa: "Gu " -0x56fb: "Guo " -0x56fc: "Tai " -0x56fd: "Guo " -0x56fe: "Tu " -0x56ff: "You " -/* x057 */ -0x5700: "Guo " -0x5701: "Yin " -0x5702: "Hun " -0x5703: "Pu " -0x5704: "Yu " -0x5705: "Han " -0x5706: "Yuan " -0x5707: "Lun " -0x5708: "Quan " -0x5709: "Yu " -0x570a: "Qing " -0x570b: "Guo " -0x570c: "Chuan " -0x570d: "Wei " -0x570e: "Yuan " -0x570f: "Quan " -0x5710: "Ku " -0x5711: "Fu " -0x5712: "Yuan " -0x5713: "Yuan " -0x5714: "E " -0x5715: "Tu " -0x5716: "Tu " -0x5717: "Tu " -0x5718: "Tuan " -0x5719: "Lue " -0x571a: "Hui " -0x571b: "Yi " -0x571c: "Yuan " -0x571d: "Luan " -0x571e: "Luan " -0x571f: "Tu " -0x5720: "Ya " -0x5721: "Tu " -0x5722: "Ting " -0x5723: "Sheng " -0x5724: "Pu " -0x5725: "Lu " -0x5726: "Iri " -0x5727: "Ya " -0x5728: "Zai " -0x5729: "Wei " -0x572a: "Ge " -0x572b: "Yu " -0x572c: "Wu " -0x572d: "Gui " -0x572e: "Pi " -0x572f: "Yi " -0x5730: "Di " -0x5731: "Qian " -0x5732: "Qian " -0x5733: "Zhen " -0x5734: "Zhuo " -0x5735: "Dang " -0x5736: "Qia " -0x5737: "Akutsu " -0x5738: "Yama " -0x5739: "Kuang " -0x573a: "Chang " -0x573b: "Qi " -0x573c: "Nie " -0x573d: "Mo " -0x573e: "Ji " -0x573f: "Jia " -0x5740: "Zhi " -0x5741: "Zhi " -0x5742: "Ban " -0x5743: "Xun " -0x5744: "Tou " -0x5745: "Qin " -0x5746: "Fen " -0x5747: "Jun " -0x5748: "Keng " -0x5749: "Tun " -0x574a: "Fang " -0x574b: "Fen " -0x574c: "Ben " -0x574d: "Tan " -0x574e: "Kan " -0x574f: "Pi " -0x5750: "Zuo " -0x5751: "Keng " -0x5752: "Bi " -0x5753: "Xing " -0x5754: "Di " -0x5755: "Jing " -0x5756: "Ji " -0x5757: "Kuai " -0x5758: "Di " -0x5759: "Jing " -0x575a: "Jian " -0x575b: "Tan " -0x575c: "Li " -0x575d: "Ba " -0x575e: "Wu " -0x575f: "Fen " -0x5760: "Zhui " -0x5761: "Po " -0x5762: "Pan " -0x5763: "Tang " -0x5764: "Kun " -0x5765: "Qu " -0x5766: "Tan " -0x5767: "Zhi " -0x5768: "Tuo " -0x5769: "Gan " -0x576a: "Ping " -0x576b: "Dian " -0x576c: "Gua " -0x576d: "Ni " -0x576e: "Tai " -0x576f: "Pi " -0x5770: "Jiong " -0x5771: "Yang " -0x5772: "Fo " -0x5773: "Ao " -0x5774: "Liu " -0x5775: "Qiu " -0x5776: "Mu " -0x5777: "Ke " -0x5778: "Gou " -0x5779: "Xue " -0x577a: "Ba " -0x577b: "Chi " -0x577c: "Che " -0x577d: "Ling " -0x577e: "Zhu " -0x577f: "Fu " -0x5780: "Hu " -0x5781: "Zhi " -0x5782: "Chui " -0x5783: "La " -0x5784: "Long " -0x5785: "Long " -0x5786: "Lu " -0x5787: "Ao " -0x5788: "Tay " -0x5789: "Pao " -0x578a: "[?] " -0x578b: "Xing " -0x578c: "Dong " -0x578d: "Ji " -0x578e: "Ke " -0x578f: "Lu " -0x5790: "Ci " -0x5791: "Chi " -0x5792: "Lei " -0x5793: "Gai " -0x5794: "Yin " -0x5795: "Hou " -0x5796: "Dui " -0x5797: "Zhao " -0x5798: "Fu " -0x5799: "Guang " -0x579a: "Yao " -0x579b: "Duo " -0x579c: "Duo " -0x579d: "Gui " -0x579e: "Cha " -0x579f: "Yang " -0x57a0: "Yin " -0x57a1: "Fa " -0x57a2: "Gou " -0x57a3: "Yuan " -0x57a4: "Die " -0x57a5: "Xie " -0x57a6: "Ken " -0x57a7: "Jiong " -0x57a8: "Shou " -0x57a9: "E " -0x57aa: "Ha " -0x57ab: "Dian " -0x57ac: "Hong " -0x57ad: "Wu " -0x57ae: "Kua " -0x57af: "[?] " -0x57b0: "Tao " -0x57b1: "Dang " -0x57b2: "Kai " -0x57b3: "Gake " -0x57b4: "Nao " -0x57b5: "An " -0x57b6: "Xing " -0x57b7: "Xian " -0x57b8: "Huan " -0x57b9: "Bang " -0x57ba: "Pei " -0x57bb: "Ba " -0x57bc: "Yi " -0x57bd: "Yin " -0x57be: "Han " -0x57bf: "Xu " -0x57c0: "Chui " -0x57c1: "Cen " -0x57c2: "Geng " -0x57c3: "Ai " -0x57c4: "Peng " -0x57c5: "Fang " -0x57c6: "Que " -0x57c7: "Yong " -0x57c8: "Xun " -0x57c9: "Jia " -0x57ca: "Di " -0x57cb: "Mai " -0x57cc: "Lang " -0x57cd: "Xuan " -0x57ce: "Cheng " -0x57cf: "Yan " -0x57d0: "Jin " -0x57d1: "Zhe " -0x57d2: "Lei " -0x57d3: "Lie " -0x57d4: "Bu " -0x57d5: "Cheng " -0x57d6: "Gomi " -0x57d7: "Bu " -0x57d8: "Shi " -0x57d9: "Xun " -0x57da: "Guo " -0x57db: "Jiong " -0x57dc: "Ye " -0x57dd: "Nian " -0x57de: "Di " -0x57df: "Yu " -0x57e0: "Bu " -0x57e1: "Ya " -0x57e2: "Juan " -0x57e3: "Sui " -0x57e4: "Pi " -0x57e5: "Cheng " -0x57e6: "Wan " -0x57e7: "Ju " -0x57e8: "Lun " -0x57e9: "Zheng " -0x57ea: "Kong " -0x57eb: "Chong " -0x57ec: "Dong " -0x57ed: "Dai " -0x57ee: "Tan " -0x57ef: "An " -0x57f0: "Cai " -0x57f1: "Shu " -0x57f2: "Beng " -0x57f3: "Kan " -0x57f4: "Zhi " -0x57f5: "Duo " -0x57f6: "Yi " -0x57f7: "Zhi " -0x57f8: "Yi " -0x57f9: "Pei " -0x57fa: "Ji " -0x57fb: "Zhun " -0x57fc: "Qi " -0x57fd: "Sao " -0x57fe: "Ju " -0x57ff: "Ni " -/* x058 */ -0x5800: "Ku " -0x5801: "Ke " -0x5802: "Tang " -0x5803: "Kun " -0x5804: "Ni " -0x5805: "Jian " -0x5806: "Dui " -0x5807: "Jin " -0x5808: "Gang " -0x5809: "Yu " -0x580a: "E " -0x580b: "Peng " -0x580c: "Gu " -0x580d: "Tu " -0x580e: "Leng " -0x580f: "[?] " -0x5810: "Ya " -0x5811: "Qian " -0x5812: "[?] " -0x5813: "An " -0x5814: "[?] " -0x5815: "Duo " -0x5816: "Nao " -0x5817: "Tu " -0x5818: "Cheng " -0x5819: "Yin " -0x581a: "Hun " -0x581b: "Bi " -0x581c: "Lian " -0x581d: "Guo " -0x581e: "Die " -0x581f: "Zhuan " -0x5820: "Hou " -0x5821: "Bao " -0x5822: "Bao " -0x5823: "Yu " -0x5824: "Di " -0x5825: "Mao " -0x5826: "Jie " -0x5827: "Ruan " -0x5828: "E " -0x5829: "Geng " -0x582a: "Kan " -0x582b: "Zong " -0x582c: "Yu " -0x582d: "Huang " -0x582e: "E " -0x582f: "Yao " -0x5830: "Yan " -0x5831: "Bao " -0x5832: "Ji " -0x5833: "Mei " -0x5834: "Chang " -0x5835: "Du " -0x5836: "Tuo " -0x5837: "Yin " -0x5838: "Feng " -0x5839: "Zhong " -0x583a: "Jie " -0x583b: "Zhen " -0x583c: "Feng " -0x583d: "Gang " -0x583e: "Chuan " -0x583f: "Jian " -0x5840: "Pyeng " -0x5841: "Toride " -0x5842: "Xiang " -0x5843: "Huang " -0x5844: "Leng " -0x5845: "Duan " -0x5846: "[?] " -0x5847: "Xuan " -0x5848: "Ji " -0x5849: "Ji " -0x584a: "Kuai " -0x584b: "Ying " -0x584c: "Ta " -0x584d: "Cheng " -0x584e: "Yong " -0x584f: "Kai " -0x5850: "Su " -0x5851: "Su " -0x5852: "Shi " -0x5853: "Mi " -0x5854: "Ta " -0x5855: "Weng " -0x5856: "Cheng " -0x5857: "Tu " -0x5858: "Tang " -0x5859: "Que " -0x585a: "Zhong " -0x585b: "Li " -0x585c: "Peng " -0x585d: "Bang " -0x585e: "Sai " -0x585f: "Zang " -0x5860: "Dui " -0x5861: "Tian " -0x5862: "Wu " -0x5863: "Cheng " -0x5864: "Xun " -0x5865: "Ge " -0x5866: "Zhen " -0x5867: "Ai " -0x5868: "Gong " -0x5869: "Yan " -0x586a: "Kan " -0x586b: "Tian " -0x586c: "Yuan " -0x586d: "Wen " -0x586e: "Xie " -0x586f: "Liu " -0x5870: "Ama " -0x5871: "Lang " -0x5872: "Chang " -0x5873: "Peng " -0x5874: "Beng " -0x5875: "Chen " -0x5876: "Cu " -0x5877: "Lu " -0x5878: "Ou " -0x5879: "Qian " -0x587a: "Mei " -0x587b: "Mo " -0x587c: "Zhuan " -0x587d: "Shuang " -0x587e: "Shu " -0x587f: "Lou " -0x5880: "Chi " -0x5881: "Man " -0x5882: "Biao " -0x5883: "Jing " -0x5884: "Qi " -0x5885: "Shu " -0x5886: "Di " -0x5887: "Zhang " -0x5888: "Kan " -0x5889: "Yong " -0x588a: "Dian " -0x588b: "Chen " -0x588c: "Zhi " -0x588d: "Xi " -0x588e: "Guo " -0x588f: "Qiang " -0x5890: "Jin " -0x5891: "Di " -0x5892: "Shang " -0x5893: "Mu " -0x5894: "Cui " -0x5895: "Yan " -0x5896: "Ta " -0x5897: "Zeng " -0x5898: "Qi " -0x5899: "Qiang " -0x589a: "Liang " -0x589b: "[?] " -0x589c: "Zhui " -0x589d: "Qiao " -0x589e: "Zeng " -0x589f: "Xu " -0x58a0: "Shan " -0x58a1: "Shan " -0x58a2: "Ba " -0x58a3: "Pu " -0x58a4: "Kuai " -0x58a5: "Dong " -0x58a6: "Fan " -0x58a7: "Que " -0x58a8: "Mo " -0x58a9: "Dun " -0x58aa: "Dun " -0x58ab: "Dun " -0x58ac: "Di " -0x58ad: "Sheng " -0x58ae: "Duo " -0x58af: "Duo " -0x58b0: "Tan " -0x58b1: "Deng " -0x58b2: "Wu " -0x58b3: "Fen " -0x58b4: "Huang " -0x58b5: "Tan " -0x58b6: "Da " -0x58b7: "Ye " -0x58b8: "Sho " -0x58b9: "Mama " -0x58ba: "Yu " -0x58bb: "Qiang " -0x58bc: "Ji " -0x58bd: "Qiao " -0x58be: "Ken " -0x58bf: "Yi " -0x58c0: "Pi " -0x58c1: "Bi " -0x58c2: "Dian " -0x58c3: "Jiang " -0x58c4: "Ye " -0x58c5: "Yong " -0x58c6: "Bo " -0x58c7: "Tan " -0x58c8: "Lan " -0x58c9: "Ju " -0x58ca: "Huai " -0x58cb: "Dang " -0x58cc: "Rang " -0x58cd: "Qian " -0x58ce: "Xun " -0x58cf: "Lan " -0x58d0: "Xi " -0x58d1: "He " -0x58d2: "Ai " -0x58d3: "Ya " -0x58d4: "Dao " -0x58d5: "Hao " -0x58d6: "Ruan " -0x58d7: "Mama " -0x58d8: "Lei " -0x58d9: "Kuang " -0x58da: "Lu " -0x58db: "Yan " -0x58dc: "Tan " -0x58dd: "Wei " -0x58de: "Huai " -0x58df: "Long " -0x58e0: "Long " -0x58e1: "Rui " -0x58e2: "Li " -0x58e3: "Lin " -0x58e4: "Rang " -0x58e5: "Ten " -0x58e6: "Xun " -0x58e7: "Yan " -0x58e8: "Lei " -0x58e9: "Ba " -0x58ea: "[?] " -0x58eb: "Shi " -0x58ec: "Ren " -0x58ed: "[?] " -0x58ee: "Zhuang " -0x58ef: "Zhuang " -0x58f0: "Sheng " -0x58f1: "Yi " -0x58f2: "Mai " -0x58f3: "Ke " -0x58f4: "Zhu " -0x58f5: "Zhuang " -0x58f6: "Hu " -0x58f7: "Hu " -0x58f8: "Kun " -0x58f9: "Yi " -0x58fa: "Hu " -0x58fb: "Xu " -0x58fc: "Kun " -0x58fd: "Shou " -0x58fe: "Mang " -0x58ff: "Zun " -/* x059 */ -0x5900: "Shou " -0x5901: "Yi " -0x5902: "Zhi " -0x5903: "Gu " -0x5904: "Chu " -0x5905: "Jiang " -0x5906: "Feng " -0x5907: "Bei " -0x5908: "Cay " -0x5909: "Bian " -0x590a: "Sui " -0x590b: "Qun " -0x590c: "Ling " -0x590d: "Fu " -0x590e: "Zuo " -0x590f: "Xia " -0x5910: "Xiong " -0x5911: "[?] " -0x5912: "Nao " -0x5913: "Xia " -0x5914: "Kui " -0x5915: "Xi " -0x5916: "Wai " -0x5917: "Yuan " -0x5918: "Mao " -0x5919: "Su " -0x591a: "Duo " -0x591b: "Duo " -0x591c: "Ye " -0x591d: "Qing " -0x591e: "Uys " -0x591f: "Gou " -0x5920: "Gou " -0x5921: "Qi " -0x5922: "Meng " -0x5923: "Meng " -0x5924: "Yin " -0x5925: "Huo " -0x5926: "Chen " -0x5927: "Da " -0x5928: "Ze " -0x5929: "Tian " -0x592a: "Tai " -0x592b: "Fu " -0x592c: "Guai " -0x592d: "Yao " -0x592e: "Yang " -0x592f: "Hang " -0x5930: "Gao " -0x5931: "Shi " -0x5932: "Ben " -0x5933: "Tai " -0x5934: "Tou " -0x5935: "Yan " -0x5936: "Bi " -0x5937: "Yi " -0x5938: "Kua " -0x5939: "Jia " -0x593a: "Duo " -0x593b: "Kwu " -0x593c: "Kuang " -0x593d: "Yun " -0x593e: "Jia " -0x593f: "Pa " -0x5940: "En " -0x5941: "Lian " -0x5942: "Huan " -0x5943: "Di " -0x5944: "Yan " -0x5945: "Pao " -0x5946: "Quan " -0x5947: "Qi " -0x5948: "Nai " -0x5949: "Feng " -0x594a: "Xie " -0x594b: "Fen " -0x594c: "Dian " -0x594d: "[?] " -0x594e: "Kui " -0x594f: "Zou " -0x5950: "Huan " -0x5951: "Qi " -0x5952: "Kai " -0x5953: "Zha " -0x5954: "Ben " -0x5955: "Yi " -0x5956: "Jiang " -0x5957: "Tao " -0x5958: "Zang " -0x5959: "Ben " -0x595a: "Xi " -0x595b: "Xiang " -0x595c: "Fei " -0x595d: "Diao " -0x595e: "Xun " -0x595f: "Keng " -0x5960: "Dian " -0x5961: "Ao " -0x5962: "She " -0x5963: "Weng " -0x5964: "Pan " -0x5965: "Ao " -0x5966: "Wu " -0x5967: "Ao " -0x5968: "Jiang " -0x5969: "Lian " -0x596a: "Duo " -0x596b: "Yun " -0x596c: "Jiang " -0x596d: "Shi " -0x596e: "Fen " -0x596f: "Huo " -0x5970: "Bi " -0x5971: "Lian " -0x5972: "Duo " -0x5973: "Nu " -0x5974: "Nu " -0x5975: "Ding " -0x5976: "Nai " -0x5977: "Qian " -0x5978: "Jian " -0x5979: "Ta " -0x597a: "Jiu " -0x597b: "Nan " -0x597c: "Cha " -0x597d: "Hao " -0x597e: "Xian " -0x597f: "Fan " -0x5980: "Ji " -0x5981: "Shuo " -0x5982: "Ru " -0x5983: "Fei " -0x5984: "Wang " -0x5985: "Hong " -0x5986: "Zhuang " -0x5987: "Fu " -0x5988: "Ma " -0x5989: "Dan " -0x598a: "Ren " -0x598b: "Fu " -0x598c: "Jing " -0x598d: "Yan " -0x598e: "Xie " -0x598f: "Wen " -0x5990: "Zhong " -0x5991: "Pa " -0x5992: "Du " -0x5993: "Ji " -0x5994: "Keng " -0x5995: "Zhong " -0x5996: "Yao " -0x5997: "Jin " -0x5998: "Yun " -0x5999: "Miao " -0x599a: "Pei " -0x599b: "Shi " -0x599c: "Yue " -0x599d: "Zhuang " -0x599e: "Niu " -0x599f: "Yan " -0x59a0: "Na " -0x59a1: "Xin " -0x59a2: "Fen " -0x59a3: "Bi " -0x59a4: "Yu " -0x59a5: "Tuo " -0x59a6: "Feng " -0x59a7: "Yuan " -0x59a8: "Fang " -0x59a9: "Wu " -0x59aa: "Yu " -0x59ab: "Gui " -0x59ac: "Du " -0x59ad: "Ba " -0x59ae: "Ni " -0x59af: "Zhou " -0x59b0: "Zhuo " -0x59b1: "Zhao " -0x59b2: "Da " -0x59b3: "Nai " -0x59b4: "Yuan " -0x59b5: "Tou " -0x59b6: "Xuan " -0x59b7: "Zhi " -0x59b8: "E " -0x59b9: "Mei " -0x59ba: "Mo " -0x59bb: "Qi " -0x59bc: "Bi " -0x59bd: "Shen " -0x59be: "Qie " -0x59bf: "E " -0x59c0: "He " -0x59c1: "Xu " -0x59c2: "Fa " -0x59c3: "Zheng " -0x59c4: "Min " -0x59c5: "Ban " -0x59c6: "Mu " -0x59c7: "Fu " -0x59c8: "Ling " -0x59c9: "Zi " -0x59ca: "Zi " -0x59cb: "Shi " -0x59cc: "Ran " -0x59cd: "Shan " -0x59ce: "Yang " -0x59cf: "Man " -0x59d0: "Jie " -0x59d1: "Gu " -0x59d2: "Si " -0x59d3: "Xing " -0x59d4: "Wei " -0x59d5: "Zi " -0x59d6: "Ju " -0x59d7: "Shan " -0x59d8: "Pin " -0x59d9: "Ren " -0x59da: "Yao " -0x59db: "Tong " -0x59dc: "Jiang " -0x59dd: "Shu " -0x59de: "Ji " -0x59df: "Gai " -0x59e0: "Shang " -0x59e1: "Kuo " -0x59e2: "Juan " -0x59e3: "Jiao " -0x59e4: "Gou " -0x59e5: "Mu " -0x59e6: "Jian " -0x59e7: "Jian " -0x59e8: "Yi " -0x59e9: "Nian " -0x59ea: "Zhi " -0x59eb: "Ji " -0x59ec: "Ji " -0x59ed: "Xian " -0x59ee: "Heng " -0x59ef: "Guang " -0x59f0: "Jun " -0x59f1: "Kua " -0x59f2: "Yan " -0x59f3: "Ming " -0x59f4: "Lie " -0x59f5: "Pei " -0x59f6: "Yan " -0x59f7: "You " -0x59f8: "Yan " -0x59f9: "Cha " -0x59fa: "Shen " -0x59fb: "Yin " -0x59fc: "Chi " -0x59fd: "Gui " -0x59fe: "Quan " -0x59ff: "Zi " -/* x05a */ -0x5a00: "Song " -0x5a01: "Wei " -0x5a02: "Hong " -0x5a03: "Wa " -0x5a04: "Lou " -0x5a05: "Ya " -0x5a06: "Rao " -0x5a07: "Jiao " -0x5a08: "Luan " -0x5a09: "Ping " -0x5a0a: "Xian " -0x5a0b: "Shao " -0x5a0c: "Li " -0x5a0d: "Cheng " -0x5a0e: "Xiao " -0x5a0f: "Mang " -0x5a10: "Fu " -0x5a11: "Suo " -0x5a12: "Wu " -0x5a13: "Wei " -0x5a14: "Ke " -0x5a15: "Lai " -0x5a16: "Chuo " -0x5a17: "Ding " -0x5a18: "Niang " -0x5a19: "Xing " -0x5a1a: "Nan " -0x5a1b: "Yu " -0x5a1c: "Nuo " -0x5a1d: "Pei " -0x5a1e: "Nei " -0x5a1f: "Juan " -0x5a20: "Shen " -0x5a21: "Zhi " -0x5a22: "Han " -0x5a23: "Di " -0x5a24: "Zhuang " -0x5a25: "E " -0x5a26: "Pin " -0x5a27: "Tui " -0x5a28: "Han " -0x5a29: "Mian " -0x5a2a: "Wu " -0x5a2b: "Yan " -0x5a2c: "Wu " -0x5a2d: "Xi " -0x5a2e: "Yan " -0x5a2f: "Yu " -0x5a30: "Si " -0x5a31: "Yu " -0x5a32: "Wa " -0x5a33: "[?] " -0x5a34: "Xian " -0x5a35: "Ju " -0x5a36: "Qu " -0x5a37: "Shui " -0x5a38: "Qi " -0x5a39: "Xian " -0x5a3a: "Zhui " -0x5a3b: "Dong " -0x5a3c: "Chang " -0x5a3d: "Lu " -0x5a3e: "Ai " -0x5a3f: "E " -0x5a40: "E " -0x5a41: "Lou " -0x5a42: "Mian " -0x5a43: "Cong " -0x5a44: "Pou " -0x5a45: "Ju " -0x5a46: "Po " -0x5a47: "Cai " -0x5a48: "Ding " -0x5a49: "Wan " -0x5a4a: "Biao " -0x5a4b: "Xiao " -0x5a4c: "Shu " -0x5a4d: "Qi " -0x5a4e: "Hui " -0x5a4f: "Fu " -0x5a50: "E " -0x5a51: "Wo " -0x5a52: "Tan " -0x5a53: "Fei " -0x5a54: "Wei " -0x5a55: "Jie " -0x5a56: "Tian " -0x5a57: "Ni " -0x5a58: "Quan " -0x5a59: "Jing " -0x5a5a: "Hun " -0x5a5b: "Jing " -0x5a5c: "Qian " -0x5a5d: "Dian " -0x5a5e: "Xing " -0x5a5f: "Hu " -0x5a60: "Wa " -0x5a61: "Lai " -0x5a62: "Bi " -0x5a63: "Yin " -0x5a64: "Chou " -0x5a65: "Chuo " -0x5a66: "Fu " -0x5a67: "Jing " -0x5a68: "Lun " -0x5a69: "Yan " -0x5a6a: "Lan " -0x5a6b: "Kun " -0x5a6c: "Yin " -0x5a6d: "Ya " -0x5a6e: "Ju " -0x5a6f: "Li " -0x5a70: "Dian " -0x5a71: "Xian " -0x5a72: "Hwa " -0x5a73: "Hua " -0x5a74: "Ying " -0x5a75: "Chan " -0x5a76: "Shen " -0x5a77: "Ting " -0x5a78: "Dang " -0x5a79: "Yao " -0x5a7a: "Wu " -0x5a7b: "Nan " -0x5a7c: "Ruo " -0x5a7d: "Jia " -0x5a7e: "Tou " -0x5a7f: "Xu " -0x5a80: "Yu " -0x5a81: "Wei " -0x5a82: "Ti " -0x5a83: "Rou " -0x5a84: "Mei " -0x5a85: "Dan " -0x5a86: "Ruan " -0x5a87: "Qin " -0x5a88: "Hui " -0x5a89: "Wu " -0x5a8a: "Qian " -0x5a8b: "Chun " -0x5a8c: "Mao " -0x5a8d: "Fu " -0x5a8e: "Jie " -0x5a8f: "Duan " -0x5a90: "Xi " -0x5a91: "Zhong " -0x5a92: "Mei " -0x5a93: "Huang " -0x5a94: "Mian " -0x5a95: "An " -0x5a96: "Ying " -0x5a97: "Xuan " -0x5a98: "Jie " -0x5a99: "Wei " -0x5a9a: "Mei " -0x5a9b: "Yuan " -0x5a9c: "Zhen " -0x5a9d: "Qiu " -0x5a9e: "Ti " -0x5a9f: "Xie " -0x5aa0: "Tuo " -0x5aa1: "Lian " -0x5aa2: "Mao " -0x5aa3: "Ran " -0x5aa4: "Si " -0x5aa5: "Pian " -0x5aa6: "Wei " -0x5aa7: "Wa " -0x5aa8: "Jiu " -0x5aa9: "Hu " -0x5aaa: "Ao " -0x5aab: "[?] " -0x5aac: "Bou " -0x5aad: "Xu " -0x5aae: "Tou " -0x5aaf: "Gui " -0x5ab0: "Zou " -0x5ab1: "Yao " -0x5ab2: "Pi " -0x5ab3: "Xi " -0x5ab4: "Yuan " -0x5ab5: "Ying " -0x5ab6: "Rong " -0x5ab7: "Ru " -0x5ab8: "Chi " -0x5ab9: "Liu " -0x5aba: "Mei " -0x5abb: "Pan " -0x5abc: "Ao " -0x5abd: "Ma " -0x5abe: "Gou " -0x5abf: "Kui " -0x5ac0: "Qin " -0x5ac1: "Jia " -0x5ac2: "Sao " -0x5ac3: "Zhen " -0x5ac4: "Yuan " -0x5ac5: "Cha " -0x5ac6: "Yong " -0x5ac7: "Ming " -0x5ac8: "Ying " -0x5ac9: "Ji " -0x5aca: "Su " -0x5acb: "Niao " -0x5acc: "Xian " -0x5acd: "Tao " -0x5ace: "Pang " -0x5acf: "Lang " -0x5ad0: "Nao " -0x5ad1: "Bao " -0x5ad2: "Ai " -0x5ad3: "Pi " -0x5ad4: "Pin " -0x5ad5: "Yi " -0x5ad6: "Piao " -0x5ad7: "Yu " -0x5ad8: "Lei " -0x5ad9: "Xuan " -0x5ada: "Man " -0x5adb: "Yi " -0x5adc: "Zhang " -0x5add: "Kang " -0x5ade: "Yong " -0x5adf: "Ni " -0x5ae0: "Li " -0x5ae1: "Di " -0x5ae2: "Gui " -0x5ae3: "Yan " -0x5ae4: "Jin " -0x5ae5: "Zhuan " -0x5ae6: "Chang " -0x5ae7: "Ce " -0x5ae8: "Han " -0x5ae9: "Nen " -0x5aea: "Lao " -0x5aeb: "Mo " -0x5aec: "Zhe " -0x5aed: "Hu " -0x5aee: "Hu " -0x5aef: "Ao " -0x5af0: "Nen " -0x5af1: "Qiang " -0x5af2: "Ma " -0x5af3: "Pie " -0x5af4: "Gu " -0x5af5: "Wu " -0x5af6: "Jiao " -0x5af7: "Tuo " -0x5af8: "Zhan " -0x5af9: "Mao " -0x5afa: "Xian " -0x5afb: "Xian " -0x5afc: "Mo " -0x5afd: "Liao " -0x5afe: "Lian " -0x5aff: "Hua " -/* x05b */ -0x5b00: "Gui " -0x5b01: "Deng " -0x5b02: "Zhi " -0x5b03: "Xu " -0x5b04: "Yi " -0x5b05: "Hua " -0x5b06: "Xi " -0x5b07: "Hui " -0x5b08: "Rao " -0x5b09: "Xi " -0x5b0a: "Yan " -0x5b0b: "Chan " -0x5b0c: "Jiao " -0x5b0d: "Mei " -0x5b0e: "Fan " -0x5b0f: "Fan " -0x5b10: "Xian " -0x5b11: "Yi " -0x5b12: "Wei " -0x5b13: "Jiao " -0x5b14: "Fu " -0x5b15: "Shi " -0x5b16: "Bi " -0x5b17: "Shan " -0x5b18: "Sui " -0x5b19: "Qiang " -0x5b1a: "Lian " -0x5b1b: "Huan " -0x5b1c: "Xin " -0x5b1d: "Niao " -0x5b1e: "Dong " -0x5b1f: "Yi " -0x5b20: "Can " -0x5b21: "Ai " -0x5b22: "Niang " -0x5b23: "Neng " -0x5b24: "Ma " -0x5b25: "Tiao " -0x5b26: "Chou " -0x5b27: "Jin " -0x5b28: "Ci " -0x5b29: "Yu " -0x5b2a: "Pin " -0x5b2b: "Yong " -0x5b2c: "Xu " -0x5b2d: "Nai " -0x5b2e: "Yan " -0x5b2f: "Tai " -0x5b30: "Ying " -0x5b31: "Can " -0x5b32: "Niao " -0x5b33: "Wo " -0x5b34: "Ying " -0x5b35: "Mian " -0x5b36: "Kaka " -0x5b37: "Ma " -0x5b38: "Shen " -0x5b39: "Xing " -0x5b3a: "Ni " -0x5b3b: "Du " -0x5b3c: "Liu " -0x5b3d: "Yuan " -0x5b3e: "Lan " -0x5b3f: "Yan " -0x5b40: "Shuang " -0x5b41: "Ling " -0x5b42: "Jiao " -0x5b43: "Niang " -0x5b44: "Lan " -0x5b45: "Xian " -0x5b46: "Ying " -0x5b47: "Shuang " -0x5b48: "Shuai " -0x5b49: "Quan " -0x5b4a: "Mi " -0x5b4b: "Li " -0x5b4c: "Luan " -0x5b4d: "Yan " -0x5b4e: "Zhu " -0x5b4f: "Lan " -0x5b50: "Zi " -0x5b51: "Jie " -0x5b52: "Jue " -0x5b53: "Jue " -0x5b54: "Kong " -0x5b55: "Yun " -0x5b56: "Zi " -0x5b57: "Zi " -0x5b58: "Cun " -0x5b59: "Sun " -0x5b5a: "Fu " -0x5b5b: "Bei " -0x5b5c: "Zi " -0x5b5d: "Xiao " -0x5b5e: "Xin " -0x5b5f: "Meng " -0x5b60: "Si " -0x5b61: "Tai " -0x5b62: "Bao " -0x5b63: "Ji " -0x5b64: "Gu " -0x5b65: "Nu " -0x5b66: "Xue " -0x5b67: "[?] " -0x5b68: "Zhuan " -0x5b69: "Hai " -0x5b6a: "Luan " -0x5b6b: "Sun " -0x5b6c: "Huai " -0x5b6d: "Mie " -0x5b6e: "Cong " -0x5b6f: "Qian " -0x5b70: "Shu " -0x5b71: "Chan " -0x5b72: "Ya " -0x5b73: "Zi " -0x5b74: "Ni " -0x5b75: "Fu " -0x5b76: "Zi " -0x5b77: "Li " -0x5b78: "Xue " -0x5b79: "Bo " -0x5b7a: "Ru " -0x5b7b: "Lai " -0x5b7c: "Nie " -0x5b7d: "Nie " -0x5b7e: "Ying " -0x5b7f: "Luan " -0x5b80: "Mian " -0x5b81: "Zhu " -0x5b82: "Rong " -0x5b83: "Ta " -0x5b84: "Gui " -0x5b85: "Zhai " -0x5b86: "Qiong " -0x5b87: "Yu " -0x5b88: "Shou " -0x5b89: "An " -0x5b8a: "Tu " -0x5b8b: "Song " -0x5b8c: "Wan " -0x5b8d: "Rou " -0x5b8e: "Yao " -0x5b8f: "Hong " -0x5b90: "Yi " -0x5b91: "Jing " -0x5b92: "Zhun " -0x5b93: "Mi " -0x5b94: "Zhu " -0x5b95: "Dang " -0x5b96: "Hong " -0x5b97: "Zong " -0x5b98: "Guan " -0x5b99: "Zhou " -0x5b9a: "Ding " -0x5b9b: "Wan " -0x5b9c: "Yi " -0x5b9d: "Bao " -0x5b9e: "Shi " -0x5b9f: "Shi " -0x5ba0: "Chong " -0x5ba1: "Shen " -0x5ba2: "Ke " -0x5ba3: "Xuan " -0x5ba4: "Shi " -0x5ba5: "You " -0x5ba6: "Huan " -0x5ba7: "Yi " -0x5ba8: "Tiao " -0x5ba9: "Shi " -0x5baa: "Xian " -0x5bab: "Gong " -0x5bac: "Cheng " -0x5bad: "Qun " -0x5bae: "Gong " -0x5baf: "Xiao " -0x5bb0: "Zai " -0x5bb1: "Zha " -0x5bb2: "Bao " -0x5bb3: "Hai " -0x5bb4: "Yan " -0x5bb5: "Xiao " -0x5bb6: "Jia " -0x5bb7: "Shen " -0x5bb8: "Chen " -0x5bb9: "Rong " -0x5bba: "Huang " -0x5bbb: "Mi " -0x5bbc: "Kou " -0x5bbd: "Kuan " -0x5bbe: "Bin " -0x5bbf: "Su " -0x5bc0: "Cai " -0x5bc1: "Zan " -0x5bc2: "Ji " -0x5bc3: "Yuan " -0x5bc4: "Ji " -0x5bc5: "Yin " -0x5bc6: "Mi " -0x5bc7: "Kou " -0x5bc8: "Qing " -0x5bc9: "Que " -0x5bca: "Zhen " -0x5bcb: "Jian " -0x5bcc: "Fu " -0x5bcd: "Ning " -0x5bce: "Bing " -0x5bcf: "Huan " -0x5bd0: "Mei " -0x5bd1: "Qin " -0x5bd2: "Han " -0x5bd3: "Yu " -0x5bd4: "Shi " -0x5bd5: "Ning " -0x5bd6: "Qin " -0x5bd7: "Ning " -0x5bd8: "Zhi " -0x5bd9: "Yu " -0x5bda: "Bao " -0x5bdb: "Kuan " -0x5bdc: "Ning " -0x5bdd: "Qin " -0x5bde: "Mo " -0x5bdf: "Cha " -0x5be0: "Ju " -0x5be1: "Gua " -0x5be2: "Qin " -0x5be3: "Hu " -0x5be4: "Wu " -0x5be5: "Liao " -0x5be6: "Shi " -0x5be7: "Zhu " -0x5be8: "Zhai " -0x5be9: "Shen " -0x5bea: "Wei " -0x5beb: "Xie " -0x5bec: "Kuan " -0x5bed: "Hui " -0x5bee: "Liao " -0x5bef: "Jun " -0x5bf0: "Huan " -0x5bf1: "Yi " -0x5bf2: "Yi " -0x5bf3: "Bao " -0x5bf4: "Qin " -0x5bf5: "Chong " -0x5bf6: "Bao " -0x5bf7: "Feng " -0x5bf8: "Cun " -0x5bf9: "Dui " -0x5bfa: "Si " -0x5bfb: "Xun " -0x5bfc: "Dao " -0x5bfd: "Lu " -0x5bfe: "Dui " -0x5bff: "Shou " -/* x05c */ -0x5c00: "Po " -0x5c01: "Feng " -0x5c02: "Zhuan " -0x5c03: "Fu " -0x5c04: "She " -0x5c05: "Ke " -0x5c06: "Jiang " -0x5c07: "Jiang " -0x5c08: "Zhuan " -0x5c09: "Wei " -0x5c0a: "Zun " -0x5c0b: "Xun " -0x5c0c: "Shu " -0x5c0d: "Dui " -0x5c0e: "Dao " -0x5c0f: "Xiao " -0x5c10: "Ji " -0x5c11: "Shao " -0x5c12: "Er " -0x5c13: "Er " -0x5c14: "Er " -0x5c15: "Ga " -0x5c16: "Jian " -0x5c17: "Shu " -0x5c18: "Chen " -0x5c19: "Shang " -0x5c1a: "Shang " -0x5c1b: "Mo " -0x5c1c: "Ga " -0x5c1d: "Chang " -0x5c1e: "Liao " -0x5c1f: "Xian " -0x5c20: "Xian " -0x5c21: "[?] " -0x5c22: "Wang " -0x5c23: "Wang " -0x5c24: "You " -0x5c25: "Liao " -0x5c26: "Liao " -0x5c27: "Yao " -0x5c28: "Mang " -0x5c29: "Wang " -0x5c2a: "Wang " -0x5c2b: "Wang " -0x5c2c: "Ga " -0x5c2d: "Yao " -0x5c2e: "Duo " -0x5c2f: "Kui " -0x5c30: "Zhong " -0x5c31: "Jiu " -0x5c32: "Gan " -0x5c33: "Gu " -0x5c34: "Gan " -0x5c35: "Tui " -0x5c36: "Gan " -0x5c37: "Gan " -0x5c38: "Shi " -0x5c39: "Yin " -0x5c3a: "Chi " -0x5c3b: "Kao " -0x5c3c: "Ni " -0x5c3d: "Jin " -0x5c3e: "Wei " -0x5c3f: "Niao " -0x5c40: "Ju " -0x5c41: "Pi " -0x5c42: "Ceng " -0x5c43: "Xi " -0x5c44: "Bi " -0x5c45: "Ju " -0x5c46: "Jie " -0x5c47: "Tian " -0x5c48: "Qu " -0x5c49: "Ti " -0x5c4a: "Jie " -0x5c4b: "Wu " -0x5c4c: "Diao " -0x5c4d: "Shi " -0x5c4e: "Shi " -0x5c4f: "Ping " -0x5c50: "Ji " -0x5c51: "Xie " -0x5c52: "Chen " -0x5c53: "Xi " -0x5c54: "Ni " -0x5c55: "Zhan " -0x5c56: "Xi " -0x5c57: "[?] " -0x5c58: "Man " -0x5c59: "E " -0x5c5a: "Lou " -0x5c5b: "Ping " -0x5c5c: "Ti " -0x5c5d: "Fei " -0x5c5e: "Shu " -0x5c5f: "Xie " -0x5c60: "Tu " -0x5c61: "Lu " -0x5c62: "Lu " -0x5c63: "Xi " -0x5c64: "Ceng " -0x5c65: "Lu " -0x5c66: "Ju " -0x5c67: "Xie " -0x5c68: "Ju " -0x5c69: "Jue " -0x5c6a: "Liao " -0x5c6b: "Jue " -0x5c6c: "Shu " -0x5c6d: "Xi " -0x5c6e: "Che " -0x5c6f: "Tun " -0x5c70: "Ni " -0x5c71: "Shan " -0x5c72: "[?] " -0x5c73: "Xian " -0x5c74: "Li " -0x5c75: "Xue " -0x5c76: "Nata " -0x5c77: "[?] " -0x5c78: "Long " -0x5c79: "Yi " -0x5c7a: "Qi " -0x5c7b: "Ren " -0x5c7c: "Wu " -0x5c7d: "Han " -0x5c7e: "Shen " -0x5c7f: "Yu " -0x5c80: "Chu " -0x5c81: "Sui " -0x5c82: "Qi " -0x5c83: "[?] " -0x5c84: "Yue " -0x5c85: "Ban " -0x5c86: "Yao " -0x5c87: "Ang " -0x5c88: "Ya " -0x5c89: "Wu " -0x5c8a: "Jie " -0x5c8b: "E " -0x5c8c: "Ji " -0x5c8d: "Qian " -0x5c8e: "Fen " -0x5c8f: "Yuan " -0x5c90: "Qi " -0x5c91: "Cen " -0x5c92: "Qian " -0x5c93: "Qi " -0x5c94: "Cha " -0x5c95: "Jie " -0x5c96: "Qu " -0x5c97: "Gang " -0x5c98: "Xian " -0x5c99: "Ao " -0x5c9a: "Lan " -0x5c9b: "Dao " -0x5c9c: "Ba " -0x5c9d: "Zuo " -0x5c9e: "Zuo " -0x5c9f: "Yang " -0x5ca0: "Ju " -0x5ca1: "Gang " -0x5ca2: "Ke " -0x5ca3: "Gou " -0x5ca4: "Xue " -0x5ca5: "Bei " -0x5ca6: "Li " -0x5ca7: "Tiao " -0x5ca8: "Ju " -0x5ca9: "Yan " -0x5caa: "Fu " -0x5cab: "Xiu " -0x5cac: "Jia " -0x5cad: "Ling " -0x5cae: "Tuo " -0x5caf: "Pei " -0x5cb0: "You " -0x5cb1: "Dai " -0x5cb2: "Kuang " -0x5cb3: "Yue " -0x5cb4: "Qu " -0x5cb5: "Hu " -0x5cb6: "Po " -0x5cb7: "Min " -0x5cb8: "An " -0x5cb9: "Tiao " -0x5cba: "Ling " -0x5cbb: "Chi " -0x5cbc: "Yuri " -0x5cbd: "Dong " -0x5cbe: "Cem " -0x5cbf: "Kui " -0x5cc0: "Xiu " -0x5cc1: "Mao " -0x5cc2: "Tong " -0x5cc3: "Xue " -0x5cc4: "Yi " -0x5cc5: "Kura " -0x5cc6: "He " -0x5cc7: "Ke " -0x5cc8: "Luo " -0x5cc9: "E " -0x5cca: "Fu " -0x5ccb: "Xun " -0x5ccc: "Die " -0x5ccd: "Lu " -0x5cce: "An " -0x5ccf: "Er " -0x5cd0: "Gai " -0x5cd1: "Quan " -0x5cd2: "Tong " -0x5cd3: "Yi " -0x5cd4: "Mu " -0x5cd5: "Shi " -0x5cd6: "An " -0x5cd7: "Wei " -0x5cd8: "Hu " -0x5cd9: "Zhi " -0x5cda: "Mi " -0x5cdb: "Li " -0x5cdc: "Ji " -0x5cdd: "Tong " -0x5cde: "Wei " -0x5cdf: "You " -0x5ce0: "Sang " -0x5ce1: "Xia " -0x5ce2: "Li " -0x5ce3: "Yao " -0x5ce4: "Jiao " -0x5ce5: "Zheng " -0x5ce6: "Luan " -0x5ce7: "Jiao " -0x5ce8: "E " -0x5ce9: "E " -0x5cea: "Yu " -0x5ceb: "Ye " -0x5cec: "Bu " -0x5ced: "Qiao " -0x5cee: "Qun " -0x5cef: "Feng " -0x5cf0: "Feng " -0x5cf1: "Nao " -0x5cf2: "Li " -0x5cf3: "You " -0x5cf4: "Xian " -0x5cf5: "Hong " -0x5cf6: "Dao " -0x5cf7: "Shen " -0x5cf8: "Cheng " -0x5cf9: "Tu " -0x5cfa: "Geng " -0x5cfb: "Jun " -0x5cfc: "Hao " -0x5cfd: "Xia " -0x5cfe: "Yin " -0x5cff: "Yu " -/* x05d */ -0x5d00: "Lang " -0x5d01: "Kan " -0x5d02: "Lao " -0x5d03: "Lai " -0x5d04: "Xian " -0x5d05: "Que " -0x5d06: "Kong " -0x5d07: "Chong " -0x5d08: "Chong " -0x5d09: "Ta " -0x5d0a: "Lin " -0x5d0b: "Hua " -0x5d0c: "Ju " -0x5d0d: "Lai " -0x5d0e: "Qi " -0x5d0f: "Min " -0x5d10: "Kun " -0x5d11: "Kun " -0x5d12: "Zu " -0x5d13: "Gu " -0x5d14: "Cui " -0x5d15: "Ya " -0x5d16: "Ya " -0x5d17: "Gang " -0x5d18: "Lun " -0x5d19: "Lun " -0x5d1a: "Leng " -0x5d1b: "Jue " -0x5d1c: "Duo " -0x5d1d: "Zheng " -0x5d1e: "Guo " -0x5d1f: "Yin " -0x5d20: "Dong " -0x5d21: "Han " -0x5d22: "Zheng " -0x5d23: "Wei " -0x5d24: "Yao " -0x5d25: "Pi " -0x5d26: "Yan " -0x5d27: "Song " -0x5d28: "Jie " -0x5d29: "Beng " -0x5d2a: "Zu " -0x5d2b: "Jue " -0x5d2c: "Dong " -0x5d2d: "Zhan " -0x5d2e: "Gu " -0x5d2f: "Yin " -0x5d30: "[?] " -0x5d31: "Ze " -0x5d32: "Huang " -0x5d33: "Yu " -0x5d34: "Wei " -0x5d35: "Yang " -0x5d36: "Feng " -0x5d37: "Qiu " -0x5d38: "Dun " -0x5d39: "Ti " -0x5d3a: "Yi " -0x5d3b: "Zhi " -0x5d3c: "Shi " -0x5d3d: "Zai " -0x5d3e: "Yao " -0x5d3f: "E " -0x5d40: "Zhu " -0x5d41: "Kan " -0x5d42: "Lu " -0x5d43: "Yan " -0x5d44: "Mei " -0x5d45: "Gan " -0x5d46: "Ji " -0x5d47: "Ji " -0x5d48: "Huan " -0x5d49: "Ting " -0x5d4a: "Sheng " -0x5d4b: "Mei " -0x5d4c: "Qian " -0x5d4d: "Wu " -0x5d4e: "Yu " -0x5d4f: "Zong " -0x5d50: "Lan " -0x5d51: "Jue " -0x5d52: "Yan " -0x5d53: "Yan " -0x5d54: "Wei " -0x5d55: "Zong " -0x5d56: "Cha " -0x5d57: "Sui " -0x5d58: "Rong " -0x5d59: "Yamashina " -0x5d5a: "Qin " -0x5d5b: "Yu " -0x5d5c: "Kewashii " -0x5d5d: "Lou " -0x5d5e: "Tu " -0x5d5f: "Dui " -0x5d60: "Xi " -0x5d61: "Weng " -0x5d62: "Cang " -0x5d63: "Dang " -0x5d64: "Hong " -0x5d65: "Jie " -0x5d66: "Ai " -0x5d67: "Liu " -0x5d68: "Wu " -0x5d69: "Song " -0x5d6a: "Qiao " -0x5d6b: "Zi " -0x5d6c: "Wei " -0x5d6d: "Beng " -0x5d6e: "Dian " -0x5d6f: "Cuo " -0x5d70: "Qian " -0x5d71: "Yong " -0x5d72: "Nie " -0x5d73: "Cuo " -0x5d74: "Ji " -0x5d75: "[?] " -0x5d76: "Tao " -0x5d77: "Song " -0x5d78: "Zong " -0x5d79: "Jiang " -0x5d7a: "Liao " -0x5d7b: "Kang " -0x5d7c: "Chan " -0x5d7d: "Die " -0x5d7e: "Cen " -0x5d7f: "Ding " -0x5d80: "Tu " -0x5d81: "Lou " -0x5d82: "Zhang " -0x5d83: "Zhan " -0x5d84: "Zhan " -0x5d85: "Ao " -0x5d86: "Cao " -0x5d87: "Qu " -0x5d88: "Qiang " -0x5d89: "Zui " -0x5d8a: "Zui " -0x5d8b: "Dao " -0x5d8c: "Dao " -0x5d8d: "Xi " -0x5d8e: "Yu " -0x5d8f: "Bo " -0x5d90: "Long " -0x5d91: "Xiang " -0x5d92: "Ceng " -0x5d93: "Bo " -0x5d94: "Qin " -0x5d95: "Jiao " -0x5d96: "Yan " -0x5d97: "Lao " -0x5d98: "Zhan " -0x5d99: "Lin " -0x5d9a: "Liao " -0x5d9b: "Liao " -0x5d9c: "Jin " -0x5d9d: "Deng " -0x5d9e: "Duo " -0x5d9f: "Zun " -0x5da0: "Jiao " -0x5da1: "Gui " -0x5da2: "Yao " -0x5da3: "Qiao " -0x5da4: "Yao " -0x5da5: "Jue " -0x5da6: "Zhan " -0x5da7: "Yi " -0x5da8: "Xue " -0x5da9: "Nao " -0x5daa: "Ye " -0x5dab: "Ye " -0x5dac: "Yi " -0x5dad: "E " -0x5dae: "Xian " -0x5daf: "Ji " -0x5db0: "Xie " -0x5db1: "Ke " -0x5db2: "Xi " -0x5db3: "Di " -0x5db4: "Ao " -0x5db5: "Zui " -0x5db6: "[?] " -0x5db7: "Ni " -0x5db8: "Rong " -0x5db9: "Dao " -0x5dba: "Ling " -0x5dbb: "Za " -0x5dbc: "Yu " -0x5dbd: "Yue " -0x5dbe: "Yin " -0x5dbf: "[?] " -0x5dc0: "Jie " -0x5dc1: "Li " -0x5dc2: "Sui " -0x5dc3: "Long " -0x5dc4: "Long " -0x5dc5: "Dian " -0x5dc6: "Ying " -0x5dc7: "Xi " -0x5dc8: "Ju " -0x5dc9: "Chan " -0x5dca: "Ying " -0x5dcb: "Kui " -0x5dcc: "Yan " -0x5dcd: "Wei " -0x5dce: "Nao " -0x5dcf: "Quan " -0x5dd0: "Chao " -0x5dd1: "Cuan " -0x5dd2: "Luan " -0x5dd3: "Dian " -0x5dd4: "Dian " -0x5dd5: "[?] " -0x5dd6: "Yan " -0x5dd7: "Yan " -0x5dd8: "Yan " -0x5dd9: "Nao " -0x5dda: "Yan " -0x5ddb: "Chuan " -0x5ddc: "Gui " -0x5ddd: "Chuan " -0x5dde: "Zhou " -0x5ddf: "Huang " -0x5de0: "Jing " -0x5de1: "Xun " -0x5de2: "Chao " -0x5de3: "Chao " -0x5de4: "Lie " -0x5de5: "Gong " -0x5de6: "Zuo " -0x5de7: "Qiao " -0x5de8: "Ju " -0x5de9: "Gong " -0x5dea: "Kek " -0x5deb: "Wu " -0x5dec: "Pwu " -0x5ded: "Pwu " -0x5dee: "Chai " -0x5def: "Qiu " -0x5df0: "Qiu " -0x5df1: "Ji " -0x5df2: "Yi " -0x5df3: "Si " -0x5df4: "Ba " -0x5df5: "Zhi " -0x5df6: "Zhao " -0x5df7: "Xiang " -0x5df8: "Yi " -0x5df9: "Jin " -0x5dfa: "Xun " -0x5dfb: "Juan " -0x5dfc: "Phas " -0x5dfd: "Xun " -0x5dfe: "Jin " -0x5dff: "Fu " -/* x05e */ -0x5e00: "Za " -0x5e01: "Bi " -0x5e02: "Shi " -0x5e03: "Bu " -0x5e04: "Ding " -0x5e05: "Shuai " -0x5e06: "Fan " -0x5e07: "Nie " -0x5e08: "Shi " -0x5e09: "Fen " -0x5e0a: "Pa " -0x5e0b: "Zhi " -0x5e0c: "Xi " -0x5e0d: "Hu " -0x5e0e: "Dan " -0x5e0f: "Wei " -0x5e10: "Zhang " -0x5e11: "Tang " -0x5e12: "Dai " -0x5e13: "Ma " -0x5e14: "Pei " -0x5e15: "Pa " -0x5e16: "Tie " -0x5e17: "Fu " -0x5e18: "Lian " -0x5e19: "Zhi " -0x5e1a: "Zhou " -0x5e1b: "Bo " -0x5e1c: "Zhi " -0x5e1d: "Di " -0x5e1e: "Mo " -0x5e1f: "Yi " -0x5e20: "Yi " -0x5e21: "Ping " -0x5e22: "Qia " -0x5e23: "Juan " -0x5e24: "Ru " -0x5e25: "Shuai " -0x5e26: "Dai " -0x5e27: "Zheng " -0x5e28: "Shui " -0x5e29: "Qiao " -0x5e2a: "Zhen " -0x5e2b: "Shi " -0x5e2c: "Qun " -0x5e2d: "Xi " -0x5e2e: "Bang " -0x5e2f: "Dai " -0x5e30: "Gui " -0x5e31: "Chou " -0x5e32: "Ping " -0x5e33: "Zhang " -0x5e34: "Sha " -0x5e35: "Wan " -0x5e36: "Dai " -0x5e37: "Wei " -0x5e38: "Chang " -0x5e39: "Sha " -0x5e3a: "Qi " -0x5e3b: "Ze " -0x5e3c: "Guo " -0x5e3d: "Mao " -0x5e3e: "Du " -0x5e3f: "Hou " -0x5e40: "Zheng " -0x5e41: "Xu " -0x5e42: "Mi " -0x5e43: "Wei " -0x5e44: "Wo " -0x5e45: "Fu " -0x5e46: "Yi " -0x5e47: "Bang " -0x5e48: "Ping " -0x5e49: "Tazuna " -0x5e4a: "Gong " -0x5e4b: "Pan " -0x5e4c: "Huang " -0x5e4d: "Dao " -0x5e4e: "Mi " -0x5e4f: "Jia " -0x5e50: "Teng " -0x5e51: "Hui " -0x5e52: "Zhong " -0x5e53: "Shan " -0x5e54: "Man " -0x5e55: "Mu " -0x5e56: "Biao " -0x5e57: "Guo " -0x5e58: "Ze " -0x5e59: "Mu " -0x5e5a: "Bang " -0x5e5b: "Zhang " -0x5e5c: "Jiong " -0x5e5d: "Chan " -0x5e5e: "Fu " -0x5e5f: "Zhi " -0x5e60: "Hu " -0x5e61: "Fan " -0x5e62: "Chuang " -0x5e63: "Bi " -0x5e64: "Hei " -0x5e65: "[?] " -0x5e66: "Mi " -0x5e67: "Qiao " -0x5e68: "Chan " -0x5e69: "Fen " -0x5e6a: "Meng " -0x5e6b: "Bang " -0x5e6c: "Chou " -0x5e6d: "Mie " -0x5e6e: "Chu " -0x5e6f: "Jie " -0x5e70: "Xian " -0x5e71: "Lan " -0x5e72: "Gan " -0x5e73: "Ping " -0x5e74: "Nian " -0x5e75: "Qian " -0x5e76: "Bing " -0x5e77: "Bing " -0x5e78: "Xing " -0x5e79: "Gan " -0x5e7a: "Yao " -0x5e7b: "Huan " -0x5e7c: "You " -0x5e7d: "You " -0x5e7e: "Ji " -0x5e7f: "Yan " -0x5e80: "Pi " -0x5e81: "Ting " -0x5e82: "Ze " -0x5e83: "Guang " -0x5e84: "Zhuang " -0x5e85: "Mo " -0x5e86: "Qing " -0x5e87: "Bi " -0x5e88: "Qin " -0x5e89: "Dun " -0x5e8a: "Chuang " -0x5e8b: "Gui " -0x5e8c: "Ya " -0x5e8d: "Bai " -0x5e8e: "Jie " -0x5e8f: "Xu " -0x5e90: "Lu " -0x5e91: "Wu " -0x5e92: "[?] " -0x5e93: "Ku " -0x5e94: "Ying " -0x5e95: "Di " -0x5e96: "Pao " -0x5e97: "Dian " -0x5e98: "Ya " -0x5e99: "Miao " -0x5e9a: "Geng " -0x5e9b: "Ci " -0x5e9c: "Fu " -0x5e9d: "Tong " -0x5e9e: "Pang " -0x5e9f: "Fei " -0x5ea0: "Xiang " -0x5ea1: "Yi " -0x5ea2: "Zhi " -0x5ea3: "Tiao " -0x5ea4: "Zhi " -0x5ea5: "Xiu " -0x5ea6: "Du " -0x5ea7: "Zuo " -0x5ea8: "Xiao " -0x5ea9: "Tu " -0x5eaa: "Gui " -0x5eab: "Ku " -0x5eac: "Pang " -0x5ead: "Ting " -0x5eae: "You " -0x5eaf: "Bu " -0x5eb0: "Ding " -0x5eb1: "Cheng " -0x5eb2: "Lai " -0x5eb3: "Bei " -0x5eb4: "Ji " -0x5eb5: "An " -0x5eb6: "Shu " -0x5eb7: "Kang " -0x5eb8: "Yong " -0x5eb9: "Tuo " -0x5eba: "Song " -0x5ebb: "Shu " -0x5ebc: "Qing " -0x5ebd: "Yu " -0x5ebe: "Yu " -0x5ebf: "Miao " -0x5ec0: "Sou " -0x5ec1: "Ce " -0x5ec2: "Xiang " -0x5ec3: "Fei " -0x5ec4: "Jiu " -0x5ec5: "He " -0x5ec6: "Hui " -0x5ec7: "Liu " -0x5ec8: "Sha " -0x5ec9: "Lian " -0x5eca: "Lang " -0x5ecb: "Sou " -0x5ecc: "Jian " -0x5ecd: "Pou " -0x5ece: "Qing " -0x5ecf: "Jiu " -0x5ed0: "Jiu " -0x5ed1: "Qin " -0x5ed2: "Ao " -0x5ed3: "Kuo " -0x5ed4: "Lou " -0x5ed5: "Yin " -0x5ed6: "Liao " -0x5ed7: "Dai " -0x5ed8: "Lu " -0x5ed9: "Yi " -0x5eda: "Chu " -0x5edb: "Chan " -0x5edc: "Tu " -0x5edd: "Si " -0x5ede: "Xin " -0x5edf: "Miao " -0x5ee0: "Chang " -0x5ee1: "Wu " -0x5ee2: "Fei " -0x5ee3: "Guang " -0x5ee4: "Koc " -0x5ee5: "Kuai " -0x5ee6: "Bi " -0x5ee7: "Qiang " -0x5ee8: "Xie " -0x5ee9: "Lin " -0x5eea: "Lin " -0x5eeb: "Liao " -0x5eec: "Lu " -0x5eed: "[?] " -0x5eee: "Ying " -0x5eef: "Xian " -0x5ef0: "Ting " -0x5ef1: "Yong " -0x5ef2: "Li " -0x5ef3: "Ting " -0x5ef4: "Yin " -0x5ef5: "Xun " -0x5ef6: "Yan " -0x5ef7: "Ting " -0x5ef8: "Di " -0x5ef9: "Po " -0x5efa: "Jian " -0x5efb: "Hui " -0x5efc: "Nai " -0x5efd: "Hui " -0x5efe: "Gong " -0x5eff: "Nian " -/* x05f */ -0x5f00: "Kai " -0x5f01: "Bian " -0x5f02: "Yi " -0x5f03: "Qi " -0x5f04: "Nong " -0x5f05: "Fen " -0x5f06: "Ju " -0x5f07: "Yan " -0x5f08: "Yi " -0x5f09: "Zang " -0x5f0a: "Bi " -0x5f0b: "Yi " -0x5f0c: "Yi " -0x5f0d: "Er " -0x5f0e: "San " -0x5f0f: "Shi " -0x5f10: "Er " -0x5f11: "Shi " -0x5f12: "Shi " -0x5f13: "Gong " -0x5f14: "Diao " -0x5f15: "Yin " -0x5f16: "Hu " -0x5f17: "Fu " -0x5f18: "Hong " -0x5f19: "Wu " -0x5f1a: "Tui " -0x5f1b: "Chi " -0x5f1c: "Jiang " -0x5f1d: "Ba " -0x5f1e: "Shen " -0x5f1f: "Di " -0x5f20: "Zhang " -0x5f21: "Jue " -0x5f22: "Tao " -0x5f23: "Fu " -0x5f24: "Di " -0x5f25: "Mi " -0x5f26: "Xian " -0x5f27: "Hu " -0x5f28: "Chao " -0x5f29: "Nu " -0x5f2a: "Jing " -0x5f2b: "Zhen " -0x5f2c: "Yi " -0x5f2d: "Mi " -0x5f2e: "Quan " -0x5f2f: "Wan " -0x5f30: "Shao " -0x5f31: "Ruo " -0x5f32: "Xuan " -0x5f33: "Jing " -0x5f34: "Dun " -0x5f35: "Zhang " -0x5f36: "Jiang " -0x5f37: "Qiang " -0x5f38: "Peng " -0x5f39: "Dan " -0x5f3a: "Qiang " -0x5f3b: "Bi " -0x5f3c: "Bi " -0x5f3d: "She " -0x5f3e: "Dan " -0x5f3f: "Jian " -0x5f40: "Gou " -0x5f41: "Sei " -0x5f42: "Fa " -0x5f43: "Bi " -0x5f44: "Kou " -0x5f45: "Nagi " -0x5f46: "Bie " -0x5f47: "Xiao " -0x5f48: "Dan " -0x5f49: "Kuo " -0x5f4a: "Qiang " -0x5f4b: "Hong " -0x5f4c: "Mi " -0x5f4d: "Kuo " -0x5f4e: "Wan " -0x5f4f: "Jue " -0x5f50: "Ji " -0x5f51: "Ji " -0x5f52: "Gui " -0x5f53: "Dang " -0x5f54: "Lu " -0x5f55: "Lu " -0x5f56: "Tuan " -0x5f57: "Hui " -0x5f58: "Zhi " -0x5f59: "Hui " -0x5f5a: "Hui " -0x5f5b: "Yi " -0x5f5c: "Yi " -0x5f5d: "Yi " -0x5f5e: "Yi " -0x5f5f: "Huo " -0x5f60: "Huo " -0x5f61: "Shan " -0x5f62: "Xing " -0x5f63: "Wen " -0x5f64: "Tong " -0x5f65: "Yan " -0x5f66: "Yan " -0x5f67: "Yu " -0x5f68: "Chi " -0x5f69: "Cai " -0x5f6a: "Biao " -0x5f6b: "Diao " -0x5f6c: "Bin " -0x5f6d: "Peng " -0x5f6e: "Yong " -0x5f6f: "Piao " -0x5f70: "Zhang " -0x5f71: "Ying " -0x5f72: "Chi " -0x5f73: "Chi " -0x5f74: "Zhuo " -0x5f75: "Tuo " -0x5f76: "Ji " -0x5f77: "Pang " -0x5f78: "Zhong " -0x5f79: "Yi " -0x5f7a: "Wang " -0x5f7b: "Che " -0x5f7c: "Bi " -0x5f7d: "Chi " -0x5f7e: "Ling " -0x5f7f: "Fu " -0x5f80: "Wang " -0x5f81: "Zheng " -0x5f82: "Cu " -0x5f83: "Wang " -0x5f84: "Jing " -0x5f85: "Dai " -0x5f86: "Xi " -0x5f87: "Xun " -0x5f88: "Hen " -0x5f89: "Yang " -0x5f8a: "Huai " -0x5f8b: "Lu " -0x5f8c: "Hou " -0x5f8d: "Wa " -0x5f8e: "Cheng " -0x5f8f: "Zhi " -0x5f90: "Xu " -0x5f91: "Jing " -0x5f92: "Tu " -0x5f93: "Cong " -0x5f94: "[?] " -0x5f95: "Lai " -0x5f96: "Cong " -0x5f97: "De " -0x5f98: "Pai " -0x5f99: "Xi " -0x5f9a: "[?] " -0x5f9b: "Qi " -0x5f9c: "Chang " -0x5f9d: "Zhi " -0x5f9e: "Cong " -0x5f9f: "Zhou " -0x5fa0: "Lai " -0x5fa1: "Yu " -0x5fa2: "Xie " -0x5fa3: "Jie " -0x5fa4: "Jian " -0x5fa5: "Chi " -0x5fa6: "Jia " -0x5fa7: "Bian " -0x5fa8: "Huang " -0x5fa9: "Fu " -0x5faa: "Xun " -0x5fab: "Wei " -0x5fac: "Pang " -0x5fad: "Yao " -0x5fae: "Wei " -0x5faf: "Xi " -0x5fb0: "Zheng " -0x5fb1: "Piao " -0x5fb2: "Chi " -0x5fb3: "De " -0x5fb4: "Zheng " -0x5fb5: "Zheng " -0x5fb6: "Bie " -0x5fb7: "De " -0x5fb8: "Chong " -0x5fb9: "Che " -0x5fba: "Jiao " -0x5fbb: "Wei " -0x5fbc: "Jiao " -0x5fbd: "Hui " -0x5fbe: "Mei " -0x5fbf: "Long " -0x5fc0: "Xiang " -0x5fc1: "Bao " -0x5fc2: "Qu " -0x5fc3: "Xin " -0x5fc4: "Shu " -0x5fc5: "Bi " -0x5fc6: "Yi " -0x5fc7: "Le " -0x5fc8: "Ren " -0x5fc9: "Dao " -0x5fca: "Ding " -0x5fcb: "Gai " -0x5fcc: "Ji " -0x5fcd: "Ren " -0x5fce: "Ren " -0x5fcf: "Chan " -0x5fd0: "Tan " -0x5fd1: "Te " -0x5fd2: "Te " -0x5fd3: "Gan " -0x5fd4: "Qi " -0x5fd5: "Shi " -0x5fd6: "Cun " -0x5fd7: "Zhi " -0x5fd8: "Wang " -0x5fd9: "Mang " -0x5fda: "Xi " -0x5fdb: "Fan " -0x5fdc: "Ying " -0x5fdd: "Tian " -0x5fde: "Min " -0x5fdf: "Min " -0x5fe0: "Zhong " -0x5fe1: "Chong " -0x5fe2: "Wu " -0x5fe3: "Ji " -0x5fe4: "Wu " -0x5fe5: "Xi " -0x5fe6: "Ye " -0x5fe7: "You " -0x5fe8: "Wan " -0x5fe9: "Cong " -0x5fea: "Zhong " -0x5feb: "Kuai " -0x5fec: "Yu " -0x5fed: "Bian " -0x5fee: "Zhi " -0x5fef: "Qi " -0x5ff0: "Cui " -0x5ff1: "Chen " -0x5ff2: "Tai " -0x5ff3: "Tun " -0x5ff4: "Qian " -0x5ff5: "Nian " -0x5ff6: "Hun " -0x5ff7: "Xiong " -0x5ff8: "Niu " -0x5ff9: "Wang " -0x5ffa: "Xian " -0x5ffb: "Xin " -0x5ffc: "Kang " -0x5ffd: "Hu " -0x5ffe: "Kai " -0x5fff: "Fen " -/* x060 */ -0x6000: "Huai " -0x6001: "Tai " -0x6002: "Song " -0x6003: "Wu " -0x6004: "Ou " -0x6005: "Chang " -0x6006: "Chuang " -0x6007: "Ju " -0x6008: "Yi " -0x6009: "Bao " -0x600a: "Chao " -0x600b: "Min " -0x600c: "Pei " -0x600d: "Zuo " -0x600e: "Zen " -0x600f: "Yang " -0x6010: "Kou " -0x6011: "Ban " -0x6012: "Nu " -0x6013: "Nao " -0x6014: "Zheng " -0x6015: "Pa " -0x6016: "Bu " -0x6017: "Tie " -0x6018: "Gu " -0x6019: "Hu " -0x601a: "Ju " -0x601b: "Da " -0x601c: "Lian " -0x601d: "Si " -0x601e: "Chou " -0x601f: "Di " -0x6020: "Dai " -0x6021: "Yi " -0x6022: "Tu " -0x6023: "You " -0x6024: "Fu " -0x6025: "Ji " -0x6026: "Peng " -0x6027: "Xing " -0x6028: "Yuan " -0x6029: "Ni " -0x602a: "Guai " -0x602b: "Fu " -0x602c: "Xi " -0x602d: "Bi " -0x602e: "You " -0x602f: "Qie " -0x6030: "Xuan " -0x6031: "Cong " -0x6032: "Bing " -0x6033: "Huang " -0x6034: "Xu " -0x6035: "Chu " -0x6036: "Pi " -0x6037: "Xi " -0x6038: "Xi " -0x6039: "Tan " -0x603a: "Koraeru " -0x603b: "Zong " -0x603c: "Dui " -0x603d: "[?] " -0x603e: "Ki " -0x603f: "Yi " -0x6040: "Chi " -0x6041: "Ren " -0x6042: "Xun " -0x6043: "Shi " -0x6044: "Xi " -0x6045: "Lao " -0x6046: "Heng " -0x6047: "Kuang " -0x6048: "Mu " -0x6049: "Zhi " -0x604a: "Xie " -0x604b: "Lian " -0x604c: "Tiao " -0x604d: "Huang " -0x604e: "Die " -0x604f: "Hao " -0x6050: "Kong " -0x6051: "Gui " -0x6052: "Heng " -0x6053: "Xi " -0x6054: "Xiao " -0x6055: "Shu " -0x6056: "S " -0x6057: "Kua " -0x6058: "Qiu " -0x6059: "Yang " -0x605a: "Hui " -0x605b: "Hui " -0x605c: "Chi " -0x605d: "Jia " -0x605e: "Yi " -0x605f: "Xiong " -0x6060: "Guai " -0x6061: "Lin " -0x6062: "Hui " -0x6063: "Zi " -0x6064: "Xu " -0x6065: "Chi " -0x6066: "Xiang " -0x6067: "Nu " -0x6068: "Hen " -0x6069: "En " -0x606a: "Ke " -0x606b: "Tong " -0x606c: "Tian " -0x606d: "Gong " -0x606e: "Quan " -0x606f: "Xi " -0x6070: "Qia " -0x6071: "Yue " -0x6072: "Peng " -0x6073: "Ken " -0x6074: "De " -0x6075: "Hui " -0x6076: "E " -0x6077: "Kyuu " -0x6078: "Tong " -0x6079: "Yan " -0x607a: "Kai " -0x607b: "Ce " -0x607c: "Nao " -0x607d: "Yun " -0x607e: "Mang " -0x607f: "Yong " -0x6080: "Yong " -0x6081: "Yuan " -0x6082: "Pi " -0x6083: "Kun " -0x6084: "Qiao " -0x6085: "Yue " -0x6086: "Yu " -0x6087: "Yu " -0x6088: "Jie " -0x6089: "Xi " -0x608a: "Zhe " -0x608b: "Lin " -0x608c: "Ti " -0x608d: "Han " -0x608e: "Hao " -0x608f: "Qie " -0x6090: "Ti " -0x6091: "Bu " -0x6092: "Yi " -0x6093: "Qian " -0x6094: "Hui " -0x6095: "Xi " -0x6096: "Bei " -0x6097: "Man " -0x6098: "Yi " -0x6099: "Heng " -0x609a: "Song " -0x609b: "Quan " -0x609c: "Cheng " -0x609d: "Hui " -0x609e: "Wu " -0x609f: "Wu " -0x60a0: "You " -0x60a1: "Li " -0x60a2: "Liang " -0x60a3: "Huan " -0x60a4: "Cong " -0x60a5: "Yi " -0x60a6: "Yue " -0x60a7: "Li " -0x60a8: "Nin " -0x60a9: "Nao " -0x60aa: "E " -0x60ab: "Que " -0x60ac: "Xuan " -0x60ad: "Qian " -0x60ae: "Wu " -0x60af: "Min " -0x60b0: "Cong " -0x60b1: "Fei " -0x60b2: "Bei " -0x60b3: "Duo " -0x60b4: "Cui " -0x60b5: "Chang " -0x60b6: "Men " -0x60b7: "Li " -0x60b8: "Ji " -0x60b9: "Guan " -0x60ba: "Guan " -0x60bb: "Xing " -0x60bc: "Dao " -0x60bd: "Qi " -0x60be: "Kong " -0x60bf: "Tian " -0x60c0: "Lun " -0x60c1: "Xi " -0x60c2: "Kan " -0x60c3: "Kun " -0x60c4: "Ni " -0x60c5: "Qing " -0x60c6: "Chou " -0x60c7: "Dun " -0x60c8: "Guo " -0x60c9: "Chan " -0x60ca: "Liang " -0x60cb: "Wan " -0x60cc: "Yuan " -0x60cd: "Jin " -0x60ce: "Ji " -0x60cf: "Lin " -0x60d0: "Yu " -0x60d1: "Huo " -0x60d2: "He " -0x60d3: "Quan " -0x60d4: "Tan " -0x60d5: "Ti " -0x60d6: "Ti " -0x60d7: "Nie " -0x60d8: "Wang " -0x60d9: "Chuo " -0x60da: "Bu " -0x60db: "Hun " -0x60dc: "Xi " -0x60dd: "Tang " -0x60de: "Xin " -0x60df: "Wei " -0x60e0: "Hui " -0x60e1: "E " -0x60e2: "Rui " -0x60e3: "Zong " -0x60e4: "Jian " -0x60e5: "Yong " -0x60e6: "Dian " -0x60e7: "Ju " -0x60e8: "Can " -0x60e9: "Cheng " -0x60ea: "De " -0x60eb: "Bei " -0x60ec: "Qie " -0x60ed: "Can " -0x60ee: "Dan " -0x60ef: "Guan " -0x60f0: "Duo " -0x60f1: "Nao " -0x60f2: "Yun " -0x60f3: "Xiang " -0x60f4: "Zhui " -0x60f5: "Die " -0x60f6: "Huang " -0x60f7: "Chun " -0x60f8: "Qiong " -0x60f9: "Re " -0x60fa: "Xing " -0x60fb: "Ce " -0x60fc: "Bian " -0x60fd: "Hun " -0x60fe: "Zong " -0x60ff: "Ti " -/* x061 */ -0x6100: "Qiao " -0x6101: "Chou " -0x6102: "Bei " -0x6103: "Xuan " -0x6104: "Wei " -0x6105: "Ge " -0x6106: "Qian " -0x6107: "Wei " -0x6108: "Yu " -0x6109: "Yu " -0x610a: "Bi " -0x610b: "Xuan " -0x610c: "Huan " -0x610d: "Min " -0x610e: "Bi " -0x610f: "Yi " -0x6110: "Mian " -0x6111: "Yong " -0x6112: "Kai " -0x6113: "Dang " -0x6114: "Yin " -0x6115: "E " -0x6116: "Chen " -0x6117: "Mou " -0x6118: "Ke " -0x6119: "Ke " -0x611a: "Yu " -0x611b: "Ai " -0x611c: "Qie " -0x611d: "Yan " -0x611e: "Nuo " -0x611f: "Gan " -0x6120: "Yun " -0x6121: "Zong " -0x6122: "Sai " -0x6123: "Leng " -0x6124: "Fen " -0x6125: "[?] " -0x6126: "Kui " -0x6127: "Kui " -0x6128: "Que " -0x6129: "Gong " -0x612a: "Yun " -0x612b: "Su " -0x612c: "Su " -0x612d: "Qi " -0x612e: "Yao " -0x612f: "Song " -0x6130: "Huang " -0x6131: "Ji " -0x6132: "Gu " -0x6133: "Ju " -0x6134: "Chuang " -0x6135: "Ni " -0x6136: "Xie " -0x6137: "Kai " -0x6138: "Zheng " -0x6139: "Yong " -0x613a: "Cao " -0x613b: "Sun " -0x613c: "Shen " -0x613d: "Bo " -0x613e: "Kai " -0x613f: "Yuan " -0x6140: "Xie " -0x6141: "Hun " -0x6142: "Yong " -0x6143: "Yang " -0x6144: "Li " -0x6145: "Sao " -0x6146: "Tao " -0x6147: "Yin " -0x6148: "Ci " -0x6149: "Xu " -0x614a: "Qian " -0x614b: "Tai " -0x614c: "Huang " -0x614d: "Yun " -0x614e: "Shen " -0x614f: "Ming " -0x6150: "[?] " -0x6151: "She " -0x6152: "Cong " -0x6153: "Piao " -0x6154: "Mo " -0x6155: "Mu " -0x6156: "Guo " -0x6157: "Chi " -0x6158: "Can " -0x6159: "Can " -0x615a: "Can " -0x615b: "Cui " -0x615c: "Min " -0x615d: "Te " -0x615e: "Zhang " -0x615f: "Tong " -0x6160: "Ao " -0x6161: "Shuang " -0x6162: "Man " -0x6163: "Guan " -0x6164: "Que " -0x6165: "Zao " -0x6166: "Jiu " -0x6167: "Hui " -0x6168: "Kai " -0x6169: "Lian " -0x616a: "Ou " -0x616b: "Song " -0x616c: "Jin " -0x616d: "Yin " -0x616e: "Lu " -0x616f: "Shang " -0x6170: "Wei " -0x6171: "Tuan " -0x6172: "Man " -0x6173: "Qian " -0x6174: "She " -0x6175: "Yong " -0x6176: "Qing " -0x6177: "Kang " -0x6178: "Di " -0x6179: "Zhi " -0x617a: "Lou " -0x617b: "Juan " -0x617c: "Qi " -0x617d: "Qi " -0x617e: "Yu " -0x617f: "Ping " -0x6180: "Liao " -0x6181: "Cong " -0x6182: "You " -0x6183: "Chong " -0x6184: "Zhi " -0x6185: "Tong " -0x6186: "Cheng " -0x6187: "Qi " -0x6188: "Qu " -0x6189: "Peng " -0x618a: "Bei " -0x618b: "Bie " -0x618c: "Chun " -0x618d: "Jiao " -0x618e: "Zeng " -0x618f: "Chi " -0x6190: "Lian " -0x6191: "Ping " -0x6192: "Kui " -0x6193: "Hui " -0x6194: "Qiao " -0x6195: "Cheng " -0x6196: "Yin " -0x6197: "Yin " -0x6198: "Xi " -0x6199: "Xi " -0x619a: "Dan " -0x619b: "Tan " -0x619c: "Duo " -0x619d: "Dui " -0x619e: "Dui " -0x619f: "Su " -0x61a0: "Jue " -0x61a1: "Ce " -0x61a2: "Xiao " -0x61a3: "Fan " -0x61a4: "Fen " -0x61a5: "Lao " -0x61a6: "Lao " -0x61a7: "Chong " -0x61a8: "Han " -0x61a9: "Qi " -0x61aa: "Xian " -0x61ab: "Min " -0x61ac: "Jing " -0x61ad: "Liao " -0x61ae: "Wu " -0x61af: "Can " -0x61b0: "Jue " -0x61b1: "Cu " -0x61b2: "Xian " -0x61b3: "Tan " -0x61b4: "Sheng " -0x61b5: "Pi " -0x61b6: "Yi " -0x61b7: "Chu " -0x61b8: "Xian " -0x61b9: "Nao " -0x61ba: "Dan " -0x61bb: "Tan " -0x61bc: "Jing " -0x61bd: "Song " -0x61be: "Han " -0x61bf: "Jiao " -0x61c0: "Wai " -0x61c1: "Huan " -0x61c2: "Dong " -0x61c3: "Qin " -0x61c4: "Qin " -0x61c5: "Qu " -0x61c6: "Cao " -0x61c7: "Ken " -0x61c8: "Xie " -0x61c9: "Ying " -0x61ca: "Ao " -0x61cb: "Mao " -0x61cc: "Yi " -0x61cd: "Lin " -0x61ce: "Se " -0x61cf: "Jun " -0x61d0: "Huai " -0x61d1: "Men " -0x61d2: "Lan " -0x61d3: "Ai " -0x61d4: "Lin " -0x61d5: "Yan " -0x61d6: "Gua " -0x61d7: "Xia " -0x61d8: "Chi " -0x61d9: "Yu " -0x61da: "Yin " -0x61db: "Dai " -0x61dc: "Meng " -0x61dd: "Ai " -0x61de: "Meng " -0x61df: "Dui " -0x61e0: "Qi " -0x61e1: "Mo " -0x61e2: "Lan " -0x61e3: "Men " -0x61e4: "Chou " -0x61e5: "Zhi " -0x61e6: "Nuo " -0x61e7: "Nuo " -0x61e8: "Yan " -0x61e9: "Yang " -0x61ea: "Bo " -0x61eb: "Zhi " -0x61ec: "Kuang " -0x61ed: "Kuang " -0x61ee: "You " -0x61ef: "Fu " -0x61f0: "Liu " -0x61f1: "Mie " -0x61f2: "Cheng " -0x61f3: "[?] " -0x61f4: "Chan " -0x61f5: "Meng " -0x61f6: "Lan " -0x61f7: "Huai " -0x61f8: "Xuan " -0x61f9: "Rang " -0x61fa: "Chan " -0x61fb: "Ji " -0x61fc: "Ju " -0x61fd: "Huan " -0x61fe: "She " -0x61ff: "Yi " -/* x062 */ -0x6200: "Lian " -0x6201: "Nan " -0x6202: "Mi " -0x6203: "Tang " -0x6204: "Jue " -0x6205: "Gang " -0x6206: "Gang " -0x6207: "Gang " -0x6208: "Ge " -0x6209: "Yue " -0x620a: "Wu " -0x620b: "Jian " -0x620c: "Xu " -0x620d: "Shu " -0x620e: "Rong " -0x620f: "Xi " -0x6210: "Cheng " -0x6211: "Wo " -0x6212: "Jie " -0x6213: "Ge " -0x6214: "Jian " -0x6215: "Qiang " -0x6216: "Huo " -0x6217: "Qiang " -0x6218: "Zhan " -0x6219: "Dong " -0x621a: "Qi " -0x621b: "Jia " -0x621c: "Die " -0x621d: "Zei " -0x621e: "Jia " -0x621f: "Ji " -0x6220: "Shi " -0x6221: "Kan " -0x6222: "Ji " -0x6223: "Kui " -0x6224: "Gai " -0x6225: "Deng " -0x6226: "Zhan " -0x6227: "Chuang " -0x6228: "Ge " -0x6229: "Jian " -0x622a: "Jie " -0x622b: "Yu " -0x622c: "Jian " -0x622d: "Yan " -0x622e: "Lu " -0x622f: "Xi " -0x6230: "Zhan " -0x6231: "Xi " -0x6232: "Xi " -0x6233: "Chuo " -0x6234: "Dai " -0x6235: "Qu " -0x6236: "Hu " -0x6237: "Hu " -0x6238: "Hu " -0x6239: "E " -0x623a: "Shi " -0x623b: "Li " -0x623c: "Mao " -0x623d: "Hu " -0x623e: "Li " -0x623f: "Fang " -0x6240: "Suo " -0x6241: "Bian " -0x6242: "Dian " -0x6243: "Jiong " -0x6244: "Shang " -0x6245: "Yi " -0x6246: "Yi " -0x6247: "Shan " -0x6248: "Hu " -0x6249: "Fei " -0x624a: "Yan " -0x624b: "Shou " -0x624c: "T " -0x624d: "Cai " -0x624e: "Zha " -0x624f: "Qiu " -0x6250: "Le " -0x6251: "Bu " -0x6252: "Ba " -0x6253: "Da " -0x6254: "Reng " -0x6255: "Fu " -0x6256: "Hameru " -0x6257: "Zai " -0x6258: "Tuo " -0x6259: "Zhang " -0x625a: "Diao " -0x625b: "Kang " -0x625c: "Yu " -0x625d: "Ku " -0x625e: "Han " -0x625f: "Shen " -0x6260: "Cha " -0x6261: "Yi " -0x6262: "Gu " -0x6263: "Kou " -0x6264: "Wu " -0x6265: "Tuo " -0x6266: "Qian " -0x6267: "Zhi " -0x6268: "Ren " -0x6269: "Kuo " -0x626a: "Men " -0x626b: "Sao " -0x626c: "Yang " -0x626d: "Niu " -0x626e: "Ban " -0x626f: "Che " -0x6270: "Rao " -0x6271: "Xi " -0x6272: "Qian " -0x6273: "Ban " -0x6274: "Jia " -0x6275: "Yu " -0x6276: "Fu " -0x6277: "Ao " -0x6278: "Xi " -0x6279: "Pi " -0x627a: "Zhi " -0x627b: "Zi " -0x627c: "E " -0x627d: "Dun " -0x627e: "Zhao " -0x627f: "Cheng " -0x6280: "Ji " -0x6281: "Yan " -0x6282: "Kuang " -0x6283: "Bian " -0x6284: "Chao " -0x6285: "Ju " -0x6286: "Wen " -0x6287: "Hu " -0x6288: "Yue " -0x6289: "Jue " -0x628a: "Ba " -0x628b: "Qin " -0x628c: "Zhen " -0x628d: "Zheng " -0x628e: "Yun " -0x628f: "Wan " -0x6290: "Nu " -0x6291: "Yi " -0x6292: "Shu " -0x6293: "Zhua " -0x6294: "Pou " -0x6295: "Tou " -0x6296: "Dou " -0x6297: "Kang " -0x6298: "Zhe " -0x6299: "Pou " -0x629a: "Fu " -0x629b: "Pao " -0x629c: "Ba " -0x629d: "Ao " -0x629e: "Ze " -0x629f: "Tuan " -0x62a0: "Kou " -0x62a1: "Lun " -0x62a2: "Qiang " -0x62a3: "[?] " -0x62a4: "Hu " -0x62a5: "Bao " -0x62a6: "Bing " -0x62a7: "Zhi " -0x62a8: "Peng " -0x62a9: "Tan " -0x62aa: "Pu " -0x62ab: "Pi " -0x62ac: "Tai " -0x62ad: "Yao " -0x62ae: "Zhen " -0x62af: "Zha " -0x62b0: "Yang " -0x62b1: "Bao " -0x62b2: "He " -0x62b3: "Ni " -0x62b4: "Yi " -0x62b5: "Di " -0x62b6: "Chi " -0x62b7: "Pi " -0x62b8: "Za " -0x62b9: "Mo " -0x62ba: "Mo " -0x62bb: "Shen " -0x62bc: "Ya " -0x62bd: "Chou " -0x62be: "Qu " -0x62bf: "Min " -0x62c0: "Chu " -0x62c1: "Jia " -0x62c2: "Fu " -0x62c3: "Zhan " -0x62c4: "Zhu " -0x62c5: "Dan " -0x62c6: "Chai " -0x62c7: "Mu " -0x62c8: "Nian " -0x62c9: "La " -0x62ca: "Fu " -0x62cb: "Pao " -0x62cc: "Ban " -0x62cd: "Pai " -0x62ce: "Ling " -0x62cf: "Na " -0x62d0: "Guai " -0x62d1: "Qian " -0x62d2: "Ju " -0x62d3: "Tuo " -0x62d4: "Ba " -0x62d5: "Tuo " -0x62d6: "Tuo " -0x62d7: "Ao " -0x62d8: "Ju " -0x62d9: "Zhuo " -0x62da: "Pan " -0x62db: "Zhao " -0x62dc: "Bai " -0x62dd: "Bai " -0x62de: "Di " -0x62df: "Ni " -0x62e0: "Ju " -0x62e1: "Kuo " -0x62e2: "Long " -0x62e3: "Jian " -0x62e4: "[?] " -0x62e5: "Yong " -0x62e6: "Lan " -0x62e7: "Ning " -0x62e8: "Bo " -0x62e9: "Ze " -0x62ea: "Qian " -0x62eb: "Hen " -0x62ec: "Gua " -0x62ed: "Shi " -0x62ee: "Jie " -0x62ef: "Zheng " -0x62f0: "Nin " -0x62f1: "Gong " -0x62f2: "Gong " -0x62f3: "Quan " -0x62f4: "Shuan " -0x62f5: "Cun " -0x62f6: "Zan " -0x62f7: "Kao " -0x62f8: "Chi " -0x62f9: "Xie " -0x62fa: "Ce " -0x62fb: "Hui " -0x62fc: "Pin " -0x62fd: "Zhuai " -0x62fe: "Shi " -0x62ff: "Na " -/* x063 */ -0x6300: "Bo " -0x6301: "Chi " -0x6302: "Gua " -0x6303: "Zhi " -0x6304: "Kuo " -0x6305: "Duo " -0x6306: "Duo " -0x6307: "Zhi " -0x6308: "Qie " -0x6309: "An " -0x630a: "Nong " -0x630b: "Zhen " -0x630c: "Ge " -0x630d: "Jiao " -0x630e: "Ku " -0x630f: "Dong " -0x6310: "Ru " -0x6311: "Tiao " -0x6312: "Lie " -0x6313: "Zha " -0x6314: "Lu " -0x6315: "Die " -0x6316: "Wa " -0x6317: "Jue " -0x6318: "Mushiru " -0x6319: "Ju " -0x631a: "Zhi " -0x631b: "Luan " -0x631c: "Ya " -0x631d: "Zhua " -0x631e: "Ta " -0x631f: "Xie " -0x6320: "Nao " -0x6321: "Dang " -0x6322: "Jiao " -0x6323: "Zheng " -0x6324: "Ji " -0x6325: "Hui " -0x6326: "Xun " -0x6327: "Ku " -0x6328: "Ai " -0x6329: "Tuo " -0x632a: "Nuo " -0x632b: "Cuo " -0x632c: "Bo " -0x632d: "Geng " -0x632e: "Ti " -0x632f: "Zhen " -0x6330: "Cheng " -0x6331: "Suo " -0x6332: "Suo " -0x6333: "Keng " -0x6334: "Mei " -0x6335: "Long " -0x6336: "Ju " -0x6337: "Peng " -0x6338: "Jian " -0x6339: "Yi " -0x633a: "Ting " -0x633b: "Shan " -0x633c: "Nuo " -0x633d: "Wan " -0x633e: "Xie " -0x633f: "Cha " -0x6340: "Feng " -0x6341: "Jiao " -0x6342: "Wu " -0x6343: "Jun " -0x6344: "Jiu " -0x6345: "Tong " -0x6346: "Kun " -0x6347: "Huo " -0x6348: "Tu " -0x6349: "Zhuo " -0x634a: "Pou " -0x634b: "Le " -0x634c: "Ba " -0x634d: "Han " -0x634e: "Shao " -0x634f: "Nie " -0x6350: "Juan " -0x6351: "Ze " -0x6352: "Song " -0x6353: "Ye " -0x6354: "Jue " -0x6355: "Bu " -0x6356: "Huan " -0x6357: "Bu " -0x6358: "Zun " -0x6359: "Yi " -0x635a: "Zhai " -0x635b: "Lu " -0x635c: "Sou " -0x635d: "Tuo " -0x635e: "Lao " -0x635f: "Sun " -0x6360: "Bang " -0x6361: "Jian " -0x6362: "Huan " -0x6363: "Dao " -0x6364: "[?] " -0x6365: "Wan " -0x6366: "Qin " -0x6367: "Peng " -0x6368: "She " -0x6369: "Lie " -0x636a: "Min " -0x636b: "Men " -0x636c: "Fu " -0x636d: "Bai " -0x636e: "Ju " -0x636f: "Dao " -0x6370: "Wo " -0x6371: "Ai " -0x6372: "Juan " -0x6373: "Yue " -0x6374: "Zong " -0x6375: "Chen " -0x6376: "Chui " -0x6377: "Jie " -0x6378: "Tu " -0x6379: "Ben " -0x637a: "Na " -0x637b: "Nian " -0x637c: "Nuo " -0x637d: "Zu " -0x637e: "Wo " -0x637f: "Xi " -0x6380: "Xian " -0x6381: "Cheng " -0x6382: "Dian " -0x6383: "Sao " -0x6384: "Lun " -0x6385: "Qing " -0x6386: "Gang " -0x6387: "Duo " -0x6388: "Shou " -0x6389: "Diao " -0x638a: "Pou " -0x638b: "Di " -0x638c: "Zhang " -0x638d: "Gun " -0x638e: "Ji " -0x638f: "Tao " -0x6390: "Qia " -0x6391: "Qi " -0x6392: "Pai " -0x6393: "Shu " -0x6394: "Qian " -0x6395: "Ling " -0x6396: "Yi " -0x6397: "Ya " -0x6398: "Jue " -0x6399: "Zheng " -0x639a: "Liang " -0x639b: "Gua " -0x639c: "Yi " -0x639d: "Huo " -0x639e: "Shan " -0x639f: "Zheng " -0x63a0: "Lue " -0x63a1: "Cai " -0x63a2: "Tan " -0x63a3: "Che " -0x63a4: "Bing " -0x63a5: "Jie " -0x63a6: "Ti " -0x63a7: "Kong " -0x63a8: "Tui " -0x63a9: "Yan " -0x63aa: "Cuo " -0x63ab: "Zou " -0x63ac: "Ju " -0x63ad: "Tian " -0x63ae: "Qian " -0x63af: "Ken " -0x63b0: "Bai " -0x63b1: "Shou " -0x63b2: "Jie " -0x63b3: "Lu " -0x63b4: "Guo " -0x63b5: "Haba " -0x63b6: "[?] " -0x63b7: "Zhi " -0x63b8: "Dan " -0x63b9: "Mang " -0x63ba: "Xian " -0x63bb: "Sao " -0x63bc: "Guan " -0x63bd: "Peng " -0x63be: "Yuan " -0x63bf: "Nuo " -0x63c0: "Jian " -0x63c1: "Zhen " -0x63c2: "Jiu " -0x63c3: "Jian " -0x63c4: "Yu " -0x63c5: "Yan " -0x63c6: "Kui " -0x63c7: "Nan " -0x63c8: "Hong " -0x63c9: "Rou " -0x63ca: "Pi " -0x63cb: "Wei " -0x63cc: "Sai " -0x63cd: "Zou " -0x63ce: "Xuan " -0x63cf: "Miao " -0x63d0: "Ti " -0x63d1: "Nie " -0x63d2: "Cha " -0x63d3: "Shi " -0x63d4: "Zong " -0x63d5: "Zhen " -0x63d6: "Yi " -0x63d7: "Shun " -0x63d8: "Heng " -0x63d9: "Bian " -0x63da: "Yang " -0x63db: "Huan " -0x63dc: "Yan " -0x63dd: "Zuan " -0x63de: "An " -0x63df: "Xu " -0x63e0: "Ya " -0x63e1: "Wo " -0x63e2: "Ke " -0x63e3: "Chuai " -0x63e4: "Ji " -0x63e5: "Ti " -0x63e6: "La " -0x63e7: "La " -0x63e8: "Cheng " -0x63e9: "Kai " -0x63ea: "Jiu " -0x63eb: "Jiu " -0x63ec: "Tu " -0x63ed: "Jie " -0x63ee: "Hui " -0x63ef: "Geng " -0x63f0: "Chong " -0x63f1: "Shuo " -0x63f2: "She " -0x63f3: "Xie " -0x63f4: "Yuan " -0x63f5: "Qian " -0x63f6: "Ye " -0x63f7: "Cha " -0x63f8: "Zha " -0x63f9: "Bei " -0x63fa: "Yao " -0x63fb: "[?] " -0x63fc: "[?] " -0x63fd: "Lan " -0x63fe: "Wen " -0x63ff: "Qin " -/* x064 */ -0x6400: "Chan " -0x6401: "Ge " -0x6402: "Lou " -0x6403: "Zong " -0x6404: "Geng " -0x6405: "Jiao " -0x6406: "Gou " -0x6407: "Qin " -0x6408: "Yong " -0x6409: "Que " -0x640a: "Chou " -0x640b: "Chi " -0x640c: "Zhan " -0x640d: "Sun " -0x640e: "Sun " -0x640f: "Bo " -0x6410: "Chu " -0x6411: "Rong " -0x6412: "Beng " -0x6413: "Cuo " -0x6414: "Sao " -0x6415: "Ke " -0x6416: "Yao " -0x6417: "Dao " -0x6418: "Zhi " -0x6419: "Nu " -0x641a: "Xie " -0x641b: "Jian " -0x641c: "Sou " -0x641d: "Qiu " -0x641e: "Gao " -0x641f: "Xian " -0x6420: "Shuo " -0x6421: "Sang " -0x6422: "Jin " -0x6423: "Mie " -0x6424: "E " -0x6425: "Chui " -0x6426: "Nuo " -0x6427: "Shan " -0x6428: "Ta " -0x6429: "Jie " -0x642a: "Tang " -0x642b: "Pan " -0x642c: "Ban " -0x642d: "Da " -0x642e: "Li " -0x642f: "Tao " -0x6430: "Hu " -0x6431: "Zhi " -0x6432: "Wa " -0x6433: "Xia " -0x6434: "Qian " -0x6435: "Wen " -0x6436: "Qiang " -0x6437: "Tian " -0x6438: "Zhen " -0x6439: "E " -0x643a: "Xi " -0x643b: "Nuo " -0x643c: "Quan " -0x643d: "Cha " -0x643e: "Zha " -0x643f: "Ge " -0x6440: "Wu " -0x6441: "En " -0x6442: "She " -0x6443: "Kang " -0x6444: "She " -0x6445: "Shu " -0x6446: "Bai " -0x6447: "Yao " -0x6448: "Bin " -0x6449: "Sou " -0x644a: "Tan " -0x644b: "Sa " -0x644c: "Chan " -0x644d: "Suo " -0x644e: "Liao " -0x644f: "Chong " -0x6450: "Chuang " -0x6451: "Guo " -0x6452: "Bing " -0x6453: "Feng " -0x6454: "Shuai " -0x6455: "Di " -0x6456: "Qi " -0x6457: "Sou " -0x6458: "Zhai " -0x6459: "Lian " -0x645a: "Tang " -0x645b: "Chi " -0x645c: "Guan " -0x645d: "Lu " -0x645e: "Luo " -0x645f: "Lou " -0x6460: "Zong " -0x6461: "Gai " -0x6462: "Hu " -0x6463: "Zha " -0x6464: "Chuang " -0x6465: "Tang " -0x6466: "Hua " -0x6467: "Cui " -0x6468: "Nai " -0x6469: "Mo " -0x646a: "Jiang " -0x646b: "Gui " -0x646c: "Ying " -0x646d: "Zhi " -0x646e: "Ao " -0x646f: "Zhi " -0x6470: "Nie " -0x6471: "Man " -0x6472: "Shan " -0x6473: "Kou " -0x6474: "Shu " -0x6475: "Suo " -0x6476: "Tuan " -0x6477: "Jiao " -0x6478: "Mo " -0x6479: "Mo " -0x647a: "Zhe " -0x647b: "Xian " -0x647c: "Keng " -0x647d: "Piao " -0x647e: "Jiang " -0x647f: "Yin " -0x6480: "Gou " -0x6481: "Qian " -0x6482: "Lue " -0x6483: "Ji " -0x6484: "Ying " -0x6485: "Jue " -0x6486: "Pie " -0x6487: "Pie " -0x6488: "Lao " -0x6489: "Dun " -0x648a: "Xian " -0x648b: "Ruan " -0x648c: "Kui " -0x648d: "Zan " -0x648e: "Yi " -0x648f: "Xun " -0x6490: "Cheng " -0x6491: "Cheng " -0x6492: "Sa " -0x6493: "Nao " -0x6494: "Heng " -0x6495: "Si " -0x6496: "Qian " -0x6497: "Huang " -0x6498: "Da " -0x6499: "Zun " -0x649a: "Nian " -0x649b: "Lin " -0x649c: "Zheng " -0x649d: "Hui " -0x649e: "Zhuang " -0x649f: "Jiao " -0x64a0: "Ji " -0x64a1: "Cao " -0x64a2: "Dan " -0x64a3: "Dan " -0x64a4: "Che " -0x64a5: "Bo " -0x64a6: "Che " -0x64a7: "Jue " -0x64a8: "Xiao " -0x64a9: "Liao " -0x64aa: "Ben " -0x64ab: "Fu " -0x64ac: "Qiao " -0x64ad: "Bo " -0x64ae: "Cuo " -0x64af: "Zhuo " -0x64b0: "Zhuan " -0x64b1: "Tuo " -0x64b2: "Pu " -0x64b3: "Qin " -0x64b4: "Dun " -0x64b5: "Nian " -0x64b6: "[?] " -0x64b7: "Xie " -0x64b8: "Lu " -0x64b9: "Jiao " -0x64ba: "Cuan " -0x64bb: "Ta " -0x64bc: "Han " -0x64bd: "Qiao " -0x64be: "Zhua " -0x64bf: "Jian " -0x64c0: "Gan " -0x64c1: "Yong " -0x64c2: "Lei " -0x64c3: "Kuo " -0x64c4: "Lu " -0x64c5: "Shan " -0x64c6: "Zhuo " -0x64c7: "Ze " -0x64c8: "Pu " -0x64c9: "Chuo " -0x64ca: "Ji " -0x64cb: "Dang " -0x64cc: "Suo " -0x64cd: "Cao " -0x64ce: "Qing " -0x64cf: "Jing " -0x64d0: "Huan " -0x64d1: "Jie " -0x64d2: "Qin " -0x64d3: "Kuai " -0x64d4: "Dan " -0x64d5: "Xi " -0x64d6: "Ge " -0x64d7: "Pi " -0x64d8: "Bo " -0x64d9: "Ao " -0x64da: "Ju " -0x64db: "Ye " -0x64dc: "[?] " -0x64dd: "Mang " -0x64de: "Sou " -0x64df: "Mi " -0x64e0: "Ji " -0x64e1: "Tai " -0x64e2: "Zhuo " -0x64e3: "Dao " -0x64e4: "Xing " -0x64e5: "Lan " -0x64e6: "Ca " -0x64e7: "Ju " -0x64e8: "Ye " -0x64e9: "Ru " -0x64ea: "Ye " -0x64eb: "Ye " -0x64ec: "Ni " -0x64ed: "Hu " -0x64ee: "Ji " -0x64ef: "Bin " -0x64f0: "Ning " -0x64f1: "Ge " -0x64f2: "Zhi " -0x64f3: "Jie " -0x64f4: "Kuo " -0x64f5: "Mo " -0x64f6: "Jian " -0x64f7: "Xie " -0x64f8: "Lie " -0x64f9: "Tan " -0x64fa: "Bai " -0x64fb: "Sou " -0x64fc: "Lu " -0x64fd: "Lue " -0x64fe: "Rao " -0x64ff: "Zhi " -/* x065 */ -0x6500: "Pan " -0x6501: "Yang " -0x6502: "Lei " -0x6503: "Sa " -0x6504: "Shu " -0x6505: "Zan " -0x6506: "Nian " -0x6507: "Xian " -0x6508: "Jun " -0x6509: "Huo " -0x650a: "Li " -0x650b: "La " -0x650c: "Han " -0x650d: "Ying " -0x650e: "Lu " -0x650f: "Long " -0x6510: "Qian " -0x6511: "Qian " -0x6512: "Zan " -0x6513: "Qian " -0x6514: "Lan " -0x6515: "San " -0x6516: "Ying " -0x6517: "Mei " -0x6518: "Rang " -0x6519: "Chan " -0x651a: "[?] " -0x651b: "Cuan " -0x651c: "Xi " -0x651d: "She " -0x651e: "Luo " -0x651f: "Jun " -0x6520: "Mi " -0x6521: "Li " -0x6522: "Zan " -0x6523: "Luan " -0x6524: "Tan " -0x6525: "Zuan " -0x6526: "Li " -0x6527: "Dian " -0x6528: "Wa " -0x6529: "Dang " -0x652a: "Jiao " -0x652b: "Jue " -0x652c: "Lan " -0x652d: "Li " -0x652e: "Nang " -0x652f: "Zhi " -0x6530: "Gui " -0x6531: "Gui " -0x6532: "Qi " -0x6533: "Xin " -0x6534: "Pu " -0x6535: "Sui " -0x6536: "Shou " -0x6537: "Kao " -0x6538: "You " -0x6539: "Gai " -0x653a: "Yi " -0x653b: "Gong " -0x653c: "Gan " -0x653d: "Ban " -0x653e: "Fang " -0x653f: "Zheng " -0x6540: "Bo " -0x6541: "Dian " -0x6542: "Kou " -0x6543: "Min " -0x6544: "Wu " -0x6545: "Gu " -0x6546: "He " -0x6547: "Ce " -0x6548: "Xiao " -0x6549: "Mi " -0x654a: "Chu " -0x654b: "Ge " -0x654c: "Di " -0x654d: "Xu " -0x654e: "Jiao " -0x654f: "Min " -0x6550: "Chen " -0x6551: "Jiu " -0x6552: "Zhen " -0x6553: "Duo " -0x6554: "Yu " -0x6555: "Chi " -0x6556: "Ao " -0x6557: "Bai " -0x6558: "Xu " -0x6559: "Jiao " -0x655a: "Duo " -0x655b: "Lian " -0x655c: "Nie " -0x655d: "Bi " -0x655e: "Chang " -0x655f: "Dian " -0x6560: "Duo " -0x6561: "Yi " -0x6562: "Gan " -0x6563: "San " -0x6564: "Ke " -0x6565: "Yan " -0x6566: "Dun " -0x6567: "Qi " -0x6568: "Dou " -0x6569: "Xiao " -0x656a: "Duo " -0x656b: "Jiao " -0x656c: "Jing " -0x656d: "Yang " -0x656e: "Xia " -0x656f: "Min " -0x6570: "Shu " -0x6571: "Ai " -0x6572: "Qiao " -0x6573: "Ai " -0x6574: "Zheng " -0x6575: "Di " -0x6576: "Zhen " -0x6577: "Fu " -0x6578: "Shu " -0x6579: "Liao " -0x657a: "Qu " -0x657b: "Xiong " -0x657c: "Xi " -0x657d: "Jiao " -0x657e: "Sen " -0x657f: "Jiao " -0x6580: "Zhuo " -0x6581: "Yi " -0x6582: "Lian " -0x6583: "Bi " -0x6584: "Li " -0x6585: "Xiao " -0x6586: "Xiao " -0x6587: "Wen " -0x6588: "Xue " -0x6589: "Qi " -0x658a: "Qi " -0x658b: "Zhai " -0x658c: "Bin " -0x658d: "Jue " -0x658e: "Zhai " -0x658f: "[?] " -0x6590: "Fei " -0x6591: "Ban " -0x6592: "Ban " -0x6593: "Lan " -0x6594: "Yu " -0x6595: "Lan " -0x6596: "Wei " -0x6597: "Dou " -0x6598: "Sheng " -0x6599: "Liao " -0x659a: "Jia " -0x659b: "Hu " -0x659c: "Xie " -0x659d: "Jia " -0x659e: "Yu " -0x659f: "Zhen " -0x65a0: "Jiao " -0x65a1: "Wo " -0x65a2: "Tou " -0x65a3: "Chu " -0x65a4: "Jin " -0x65a5: "Chi " -0x65a6: "Yin " -0x65a7: "Fu " -0x65a8: "Qiang " -0x65a9: "Zhan " -0x65aa: "Qu " -0x65ab: "Zhuo " -0x65ac: "Zhan " -0x65ad: "Duan " -0x65ae: "Zhuo " -0x65af: "Si " -0x65b0: "Xin " -0x65b1: "Zhuo " -0x65b2: "Zhuo " -0x65b3: "Qin " -0x65b4: "Lin " -0x65b5: "Zhuo " -0x65b6: "Chu " -0x65b7: "Duan " -0x65b8: "Zhu " -0x65b9: "Fang " -0x65ba: "Xie " -0x65bb: "Hang " -0x65bc: "Yu " -0x65bd: "Shi " -0x65be: "Pei " -0x65bf: "You " -0x65c0: "Mye " -0x65c1: "Pang " -0x65c2: "Qi " -0x65c3: "Zhan " -0x65c4: "Mao " -0x65c5: "Lu " -0x65c6: "Pei " -0x65c7: "Pi " -0x65c8: "Liu " -0x65c9: "Fu " -0x65ca: "Fang " -0x65cb: "Xuan " -0x65cc: "Jing " -0x65cd: "Jing " -0x65ce: "Ni " -0x65cf: "Zu " -0x65d0: "Zhao " -0x65d1: "Yi " -0x65d2: "Liu " -0x65d3: "Shao " -0x65d4: "Jian " -0x65d5: "Es " -0x65d6: "Yi " -0x65d7: "Qi " -0x65d8: "Zhi " -0x65d9: "Fan " -0x65da: "Piao " -0x65db: "Fan " -0x65dc: "Zhan " -0x65dd: "Guai " -0x65de: "Sui " -0x65df: "Yu " -0x65e0: "Wu " -0x65e1: "Ji " -0x65e2: "Ji " -0x65e3: "Ji " -0x65e4: "Huo " -0x65e5: "Ri " -0x65e6: "Dan " -0x65e7: "Jiu " -0x65e8: "Zhi " -0x65e9: "Zao " -0x65ea: "Xie " -0x65eb: "Tiao " -0x65ec: "Xun " -0x65ed: "Xu " -0x65ee: "Xu " -0x65ef: "Xu " -0x65f0: "Gan " -0x65f1: "Han " -0x65f2: "Tai " -0x65f3: "Di " -0x65f4: "Xu " -0x65f5: "Chan " -0x65f6: "Shi " -0x65f7: "Kuang " -0x65f8: "Yang " -0x65f9: "Shi " -0x65fa: "Wang " -0x65fb: "Min " -0x65fc: "Min " -0x65fd: "Tun " -0x65fe: "Chun " -0x65ff: "Wu " -/* x066 */ -0x6600: "Yun " -0x6601: "Bei " -0x6602: "Ang " -0x6603: "Ze " -0x6604: "Ban " -0x6605: "Jie " -0x6606: "Kun " -0x6607: "Sheng " -0x6608: "Hu " -0x6609: "Fang " -0x660a: "Hao " -0x660b: "Gui " -0x660c: "Chang " -0x660d: "Xuan " -0x660e: "Ming " -0x660f: "Hun " -0x6610: "Fen " -0x6611: "Qin " -0x6612: "Hu " -0x6613: "Yi " -0x6614: "Xi " -0x6615: "Xin " -0x6616: "Yan " -0x6617: "Ze " -0x6618: "Fang " -0x6619: "Tan " -0x661a: "Shen " -0x661b: "Ju " -0x661c: "Yang " -0x661d: "Zan " -0x661e: "Bing " -0x661f: "Xing " -0x6620: "Ying " -0x6621: "Xuan " -0x6622: "Pei " -0x6623: "Zhen " -0x6624: "Ling " -0x6625: "Chun " -0x6626: "Hao " -0x6627: "Mei " -0x6628: "Zuo " -0x6629: "Mo " -0x662a: "Bian " -0x662b: "Xu " -0x662c: "Hun " -0x662d: "Zhao " -0x662e: "Zong " -0x662f: "Shi " -0x6630: "Shi " -0x6631: "Yu " -0x6632: "Fei " -0x6633: "Die " -0x6634: "Mao " -0x6635: "Ni " -0x6636: "Chang " -0x6637: "Wen " -0x6638: "Dong " -0x6639: "Ai " -0x663a: "Bing " -0x663b: "Ang " -0x663c: "Zhou " -0x663d: "Long " -0x663e: "Xian " -0x663f: "Kuang " -0x6640: "Tiao " -0x6641: "Chao " -0x6642: "Shi " -0x6643: "Huang " -0x6644: "Huang " -0x6645: "Xuan " -0x6646: "Kui " -0x6647: "Xu " -0x6648: "Jiao " -0x6649: "Jin " -0x664a: "Zhi " -0x664b: "Jin " -0x664c: "Shang " -0x664d: "Tong " -0x664e: "Hong " -0x664f: "Yan " -0x6650: "Gai " -0x6651: "Xiang " -0x6652: "Shai " -0x6653: "Xiao " -0x6654: "Ye " -0x6655: "Yun " -0x6656: "Hui " -0x6657: "Han " -0x6658: "Han " -0x6659: "Jun " -0x665a: "Wan " -0x665b: "Xian " -0x665c: "Kun " -0x665d: "Zhou " -0x665e: "Xi " -0x665f: "Cheng " -0x6660: "Sheng " -0x6661: "Bu " -0x6662: "Zhe " -0x6663: "Zhe " -0x6664: "Wu " -0x6665: "Han " -0x6666: "Hui " -0x6667: "Hao " -0x6668: "Chen " -0x6669: "Wan " -0x666a: "Tian " -0x666b: "Zhuo " -0x666c: "Zui " -0x666d: "Zhou " -0x666e: "Pu " -0x666f: "Jing " -0x6670: "Xi " -0x6671: "Shan " -0x6672: "Yi " -0x6673: "Xi " -0x6674: "Qing " -0x6675: "Qi " -0x6676: "Jing " -0x6677: "Gui " -0x6678: "Zhen " -0x6679: "Yi " -0x667a: "Zhi " -0x667b: "An " -0x667c: "Wan " -0x667d: "Lin " -0x667e: "Liang " -0x667f: "Chang " -0x6680: "Wang " -0x6681: "Xiao " -0x6682: "Zan " -0x6683: "Hi " -0x6684: "Xuan " -0x6685: "Xuan " -0x6686: "Yi " -0x6687: "Xia " -0x6688: "Yun " -0x6689: "Hui " -0x668a: "Fu " -0x668b: "Min " -0x668c: "Kui " -0x668d: "He " -0x668e: "Ying " -0x668f: "Du " -0x6690: "Wei " -0x6691: "Shu " -0x6692: "Qing " -0x6693: "Mao " -0x6694: "Nan " -0x6695: "Jian " -0x6696: "Nuan " -0x6697: "An " -0x6698: "Yang " -0x6699: "Chun " -0x669a: "Yao " -0x669b: "Suo " -0x669c: "Jin " -0x669d: "Ming " -0x669e: "Jiao " -0x669f: "Kai " -0x66a0: "Gao " -0x66a1: "Weng " -0x66a2: "Chang " -0x66a3: "Qi " -0x66a4: "Hao " -0x66a5: "Yan " -0x66a6: "Li " -0x66a7: "Ai " -0x66a8: "Ji " -0x66a9: "Gui " -0x66aa: "Men " -0x66ab: "Zan " -0x66ac: "Xie " -0x66ad: "Hao " -0x66ae: "Mu " -0x66af: "Mo " -0x66b0: "Cong " -0x66b1: "Ni " -0x66b2: "Zhang " -0x66b3: "Hui " -0x66b4: "Bao " -0x66b5: "Han " -0x66b6: "Xuan " -0x66b7: "Chuan " -0x66b8: "Liao " -0x66b9: "Xian " -0x66ba: "Dan " -0x66bb: "Jing " -0x66bc: "Pie " -0x66bd: "Lin " -0x66be: "Tun " -0x66bf: "Xi " -0x66c0: "Yi " -0x66c1: "Ji " -0x66c2: "Huang " -0x66c3: "Tai " -0x66c4: "Ye " -0x66c5: "Ye " -0x66c6: "Li " -0x66c7: "Tan " -0x66c8: "Tong " -0x66c9: "Xiao " -0x66ca: "Fei " -0x66cb: "Qin " -0x66cc: "Zhao " -0x66cd: "Hao " -0x66ce: "Yi " -0x66cf: "Xiang " -0x66d0: "Xing " -0x66d1: "Sen " -0x66d2: "Jiao " -0x66d3: "Bao " -0x66d4: "Jing " -0x66d5: "Yian " -0x66d6: "Ai " -0x66d7: "Ye " -0x66d8: "Ru " -0x66d9: "Shu " -0x66da: "Meng " -0x66db: "Xun " -0x66dc: "Yao " -0x66dd: "Pu " -0x66de: "Li " -0x66df: "Chen " -0x66e0: "Kuang " -0x66e1: "Die " -0x66e2: "[?] " -0x66e3: "Yan " -0x66e4: "Huo " -0x66e5: "Lu " -0x66e6: "Xi " -0x66e7: "Rong " -0x66e8: "Long " -0x66e9: "Nang " -0x66ea: "Luo " -0x66eb: "Luan " -0x66ec: "Shai " -0x66ed: "Tang " -0x66ee: "Yan " -0x66ef: "Chu " -0x66f0: "Yue " -0x66f1: "Yue " -0x66f2: "Qu " -0x66f3: "Yi " -0x66f4: "Geng " -0x66f5: "Ye " -0x66f6: "Hu " -0x66f7: "He " -0x66f8: "Shu " -0x66f9: "Cao " -0x66fa: "Cao " -0x66fb: "Noboru " -0x66fc: "Man " -0x66fd: "Ceng " -0x66fe: "Ceng " -0x66ff: "Ti " -/* x067 */ -0x6700: "Zui " -0x6701: "Can " -0x6702: "Xu " -0x6703: "Hui " -0x6704: "Yin " -0x6705: "Qie " -0x6706: "Fen " -0x6707: "Pi " -0x6708: "Yue " -0x6709: "You " -0x670a: "Ruan " -0x670b: "Peng " -0x670c: "Ban " -0x670d: "Fu " -0x670e: "Ling " -0x670f: "Fei " -0x6710: "Qu " -0x6711: "[?] " -0x6712: "Nu " -0x6713: "Tiao " -0x6714: "Shuo " -0x6715: "Zhen " -0x6716: "Lang " -0x6717: "Lang " -0x6718: "Juan " -0x6719: "Ming " -0x671a: "Huang " -0x671b: "Wang " -0x671c: "Tun " -0x671d: "Zhao " -0x671e: "Ji " -0x671f: "Qi " -0x6720: "Ying " -0x6721: "Zong " -0x6722: "Wang " -0x6723: "Tong " -0x6724: "Lang " -0x6725: "[?] " -0x6726: "Meng " -0x6727: "Long " -0x6728: "Mu " -0x6729: "Deng " -0x672a: "Wei " -0x672b: "Mo " -0x672c: "Ben " -0x672d: "Zha " -0x672e: "Zhu " -0x672f: "Zhu " -0x6730: "[?] " -0x6731: "Zhu " -0x6732: "Ren " -0x6733: "Ba " -0x6734: "Po " -0x6735: "Duo " -0x6736: "Duo " -0x6737: "Dao " -0x6738: "Li " -0x6739: "Qiu " -0x673a: "Ji " -0x673b: "Jiu " -0x673c: "Bi " -0x673d: "Xiu " -0x673e: "Ting " -0x673f: "Ci " -0x6740: "Sha " -0x6741: "Eburi " -0x6742: "Za " -0x6743: "Quan " -0x6744: "Qian " -0x6745: "Yu " -0x6746: "Gan " -0x6747: "Wu " -0x6748: "Cha " -0x6749: "Shan " -0x674a: "Xun " -0x674b: "Fan " -0x674c: "Wu " -0x674d: "Zi " -0x674e: "Li " -0x674f: "Xing " -0x6750: "Cai " -0x6751: "Cun " -0x6752: "Ren " -0x6753: "Shao " -0x6754: "Tuo " -0x6755: "Di " -0x6756: "Zhang " -0x6757: "Mang " -0x6758: "Chi " -0x6759: "Yi " -0x675a: "Gu " -0x675b: "Gong " -0x675c: "Du " -0x675d: "Yi " -0x675e: "Qi " -0x675f: "Shu " -0x6760: "Gang " -0x6761: "Tiao " -0x6762: "Moku " -0x6763: "Soma " -0x6764: "Tochi " -0x6765: "Lai " -0x6766: "Sugi " -0x6767: "Mang " -0x6768: "Yang " -0x6769: "Ma " -0x676a: "Miao " -0x676b: "Si " -0x676c: "Yuan " -0x676d: "Hang " -0x676e: "Fei " -0x676f: "Bei " -0x6770: "Jie " -0x6771: "Dong " -0x6772: "Gao " -0x6773: "Yao " -0x6774: "Xian " -0x6775: "Chu " -0x6776: "Qun " -0x6777: "Pa " -0x6778: "Shu " -0x6779: "Hua " -0x677a: "Xin " -0x677b: "Chou " -0x677c: "Zhu " -0x677d: "Chou " -0x677e: "Song " -0x677f: "Ban " -0x6780: "Song " -0x6781: "Ji " -0x6782: "Yue " -0x6783: "Jin " -0x6784: "Gou " -0x6785: "Ji " -0x6786: "Mao " -0x6787: "Pi " -0x6788: "Bi " -0x6789: "Wang " -0x678a: "Ang " -0x678b: "Fang " -0x678c: "Fen " -0x678d: "Yi " -0x678e: "Fu " -0x678f: "Nan " -0x6790: "Xi " -0x6791: "Hu " -0x6792: "Ya " -0x6793: "Dou " -0x6794: "Xun " -0x6795: "Zhen " -0x6796: "Yao " -0x6797: "Lin " -0x6798: "Rui " -0x6799: "E " -0x679a: "Mei " -0x679b: "Zhao " -0x679c: "Guo " -0x679d: "Zhi " -0x679e: "Cong " -0x679f: "Yun " -0x67a0: "Waku " -0x67a1: "Dou " -0x67a2: "Shu " -0x67a3: "Zao " -0x67a4: "[?] " -0x67a5: "Li " -0x67a6: "Haze " -0x67a7: "Jian " -0x67a8: "Cheng " -0x67a9: "Matsu " -0x67aa: "Qiang " -0x67ab: "Feng " -0x67ac: "Nan " -0x67ad: "Xiao " -0x67ae: "Xian " -0x67af: "Ku " -0x67b0: "Ping " -0x67b1: "Yi " -0x67b2: "Xi " -0x67b3: "Zhi " -0x67b4: "Guai " -0x67b5: "Xiao " -0x67b6: "Jia " -0x67b7: "Jia " -0x67b8: "Gou " -0x67b9: "Fu " -0x67ba: "Mo " -0x67bb: "Yi " -0x67bc: "Ye " -0x67bd: "Ye " -0x67be: "Shi " -0x67bf: "Nie " -0x67c0: "Bi " -0x67c1: "Duo " -0x67c2: "Yi " -0x67c3: "Ling " -0x67c4: "Bing " -0x67c5: "Ni " -0x67c6: "La " -0x67c7: "He " -0x67c8: "Pan " -0x67c9: "Fan " -0x67ca: "Zhong " -0x67cb: "Dai " -0x67cc: "Ci " -0x67cd: "Yang " -0x67ce: "Fu " -0x67cf: "Bo " -0x67d0: "Mou " -0x67d1: "Gan " -0x67d2: "Qi " -0x67d3: "Ran " -0x67d4: "Rou " -0x67d5: "Mao " -0x67d6: "Zhao " -0x67d7: "Song " -0x67d8: "Zhe " -0x67d9: "Xia " -0x67da: "You " -0x67db: "Shen " -0x67dc: "Ju " -0x67dd: "Tuo " -0x67de: "Zuo " -0x67df: "Nan " -0x67e0: "Ning " -0x67e1: "Yong " -0x67e2: "Di " -0x67e3: "Zhi " -0x67e4: "Zha " -0x67e5: "Cha " -0x67e6: "Dan " -0x67e7: "Gu " -0x67e8: "Pu " -0x67e9: "Jiu " -0x67ea: "Ao " -0x67eb: "Fu " -0x67ec: "Jian " -0x67ed: "Bo " -0x67ee: "Duo " -0x67ef: "Ke " -0x67f0: "Nai " -0x67f1: "Zhu " -0x67f2: "Bi " -0x67f3: "Liu " -0x67f4: "Chai " -0x67f5: "Zha " -0x67f6: "Si " -0x67f7: "Zhu " -0x67f8: "Pei " -0x67f9: "Shi " -0x67fa: "Guai " -0x67fb: "Cha " -0x67fc: "Yao " -0x67fd: "Jue " -0x67fe: "Jiu " -0x67ff: "Shi " -/* x068 */ -0x6800: "Zhi " -0x6801: "Liu " -0x6802: "Mei " -0x6803: "Hoy " -0x6804: "Rong " -0x6805: "Zha " -0x6806: "[?] " -0x6807: "Biao " -0x6808: "Zhan " -0x6809: "Jie " -0x680a: "Long " -0x680b: "Dong " -0x680c: "Lu " -0x680d: "Sayng " -0x680e: "Li " -0x680f: "Lan " -0x6810: "Yong " -0x6811: "Shu " -0x6812: "Xun " -0x6813: "Shuan " -0x6814: "Qi " -0x6815: "Zhen " -0x6816: "Qi " -0x6817: "Li " -0x6818: "Yi " -0x6819: "Xiang " -0x681a: "Zhen " -0x681b: "Li " -0x681c: "Su " -0x681d: "Gua " -0x681e: "Kan " -0x681f: "Bing " -0x6820: "Ren " -0x6821: "Xiao " -0x6822: "Bo " -0x6823: "Ren " -0x6824: "Bing " -0x6825: "Zi " -0x6826: "Chou " -0x6827: "Yi " -0x6828: "Jie " -0x6829: "Xu " -0x682a: "Zhu " -0x682b: "Jian " -0x682c: "Zui " -0x682d: "Er " -0x682e: "Er " -0x682f: "You " -0x6830: "Fa " -0x6831: "Gong " -0x6832: "Kao " -0x6833: "Lao " -0x6834: "Zhan " -0x6835: "Li " -0x6836: "Yin " -0x6837: "Yang " -0x6838: "He " -0x6839: "Gen " -0x683a: "Zhi " -0x683b: "Chi " -0x683c: "Ge " -0x683d: "Zai " -0x683e: "Luan " -0x683f: "Fu " -0x6840: "Jie " -0x6841: "Hang " -0x6842: "Gui " -0x6843: "Tao " -0x6844: "Guang " -0x6845: "Wei " -0x6846: "Kuang " -0x6847: "Ru " -0x6848: "An " -0x6849: "An " -0x684a: "Juan " -0x684b: "Yi " -0x684c: "Zhuo " -0x684d: "Ku " -0x684e: "Zhi " -0x684f: "Qiong " -0x6850: "Tong " -0x6851: "Sang " -0x6852: "Sang " -0x6853: "Huan " -0x6854: "Jie " -0x6855: "Jiu " -0x6856: "Xue " -0x6857: "Duo " -0x6858: "Zhui " -0x6859: "Yu " -0x685a: "Zan " -0x685b: "Kasei " -0x685c: "Ying " -0x685d: "Masu " -0x685e: "[?] " -0x685f: "Zhan " -0x6860: "Ya " -0x6861: "Nao " -0x6862: "Zhen " -0x6863: "Dang " -0x6864: "Qi " -0x6865: "Qiao " -0x6866: "Hua " -0x6867: "Kuai " -0x6868: "Jiang " -0x6869: "Zhuang " -0x686a: "Xun " -0x686b: "Suo " -0x686c: "Sha " -0x686d: "Zhen " -0x686e: "Bei " -0x686f: "Ting " -0x6870: "Gua " -0x6871: "Jing " -0x6872: "Bo " -0x6873: "Ben " -0x6874: "Fu " -0x6875: "Rui " -0x6876: "Tong " -0x6877: "Jue " -0x6878: "Xi " -0x6879: "Lang " -0x687a: "Liu " -0x687b: "Feng " -0x687c: "Qi " -0x687d: "Wen " -0x687e: "Jun " -0x687f: "Gan " -0x6880: "Cu " -0x6881: "Liang " -0x6882: "Qiu " -0x6883: "Ting " -0x6884: "You " -0x6885: "Mei " -0x6886: "Bang " -0x6887: "Long " -0x6888: "Peng " -0x6889: "Zhuang " -0x688a: "Di " -0x688b: "Xuan " -0x688c: "Tu " -0x688d: "Zao " -0x688e: "Ao " -0x688f: "Gu " -0x6890: "Bi " -0x6891: "Di " -0x6892: "Han " -0x6893: "Zi " -0x6894: "Zhi " -0x6895: "Ren " -0x6896: "Bei " -0x6897: "Geng " -0x6898: "Jian " -0x6899: "Huan " -0x689a: "Wan " -0x689b: "Nuo " -0x689c: "Jia " -0x689d: "Tiao " -0x689e: "Ji " -0x689f: "Xiao " -0x68a0: "Lu " -0x68a1: "Huan " -0x68a2: "Shao " -0x68a3: "Cen " -0x68a4: "Fen " -0x68a5: "Song " -0x68a6: "Meng " -0x68a7: "Wu " -0x68a8: "Li " -0x68a9: "Li " -0x68aa: "Dou " -0x68ab: "Cen " -0x68ac: "Ying " -0x68ad: "Suo " -0x68ae: "Ju " -0x68af: "Ti " -0x68b0: "Jie " -0x68b1: "Kun " -0x68b2: "Zhuo " -0x68b3: "Shu " -0x68b4: "Chan " -0x68b5: "Fan " -0x68b6: "Wei " -0x68b7: "Jing " -0x68b8: "Li " -0x68b9: "Bing " -0x68ba: "Fumoto " -0x68bb: "Shikimi " -0x68bc: "Tao " -0x68bd: "Zhi " -0x68be: "Lai " -0x68bf: "Lian " -0x68c0: "Jian " -0x68c1: "Zhuo " -0x68c2: "Ling " -0x68c3: "Li " -0x68c4: "Qi " -0x68c5: "Bing " -0x68c6: "Zhun " -0x68c7: "Cong " -0x68c8: "Qian " -0x68c9: "Mian " -0x68ca: "Qi " -0x68cb: "Qi " -0x68cc: "Cai " -0x68cd: "Gun " -0x68ce: "Chan " -0x68cf: "Te " -0x68d0: "Fei " -0x68d1: "Pai " -0x68d2: "Bang " -0x68d3: "Pou " -0x68d4: "Hun " -0x68d5: "Zong " -0x68d6: "Cheng " -0x68d7: "Zao " -0x68d8: "Ji " -0x68d9: "Li " -0x68da: "Peng " -0x68db: "Yu " -0x68dc: "Yu " -0x68dd: "Gu " -0x68de: "Hun " -0x68df: "Dong " -0x68e0: "Tang " -0x68e1: "Gang " -0x68e2: "Wang " -0x68e3: "Di " -0x68e4: "Xi " -0x68e5: "Fan " -0x68e6: "Cheng " -0x68e7: "Zhan " -0x68e8: "Qi " -0x68e9: "Yuan " -0x68ea: "Yan " -0x68eb: "Yu " -0x68ec: "Quan " -0x68ed: "Yi " -0x68ee: "Sen " -0x68ef: "Ren " -0x68f0: "Chui " -0x68f1: "Leng " -0x68f2: "Qi " -0x68f3: "Zhuo " -0x68f4: "Fu " -0x68f5: "Ke " -0x68f6: "Lai " -0x68f7: "Zou " -0x68f8: "Zou " -0x68f9: "Zhuo " -0x68fa: "Guan " -0x68fb: "Fen " -0x68fc: "Fen " -0x68fd: "Chen " -0x68fe: "Qiong " -0x68ff: "Nie " -/* x069 */ -0x6900: "Wan " -0x6901: "Guo " -0x6902: "Lu " -0x6903: "Hao " -0x6904: "Jie " -0x6905: "Yi " -0x6906: "Chou " -0x6907: "Ju " -0x6908: "Ju " -0x6909: "Cheng " -0x690a: "Zuo " -0x690b: "Liang " -0x690c: "Qiang " -0x690d: "Zhi " -0x690e: "Zhui " -0x690f: "Ya " -0x6910: "Ju " -0x6911: "Bei " -0x6912: "Jiao " -0x6913: "Zhuo " -0x6914: "Zi " -0x6915: "Bin " -0x6916: "Peng " -0x6917: "Ding " -0x6918: "Chu " -0x6919: "Chang " -0x691a: "Kunugi " -0x691b: "Momiji " -0x691c: "Jian " -0x691d: "Gui " -0x691e: "Xi " -0x691f: "Du " -0x6920: "Qian " -0x6921: "Kunugi " -0x6922: "Soko " -0x6923: "Shide " -0x6924: "Luo " -0x6925: "Zhi " -0x6926: "Ken " -0x6927: "Myeng " -0x6928: "Tafu " -0x6929: "[?] " -0x692a: "Peng " -0x692b: "Zhan " -0x692c: "[?] " -0x692d: "Tuo " -0x692e: "Sen " -0x692f: "Duo " -0x6930: "Ye " -0x6931: "Fou " -0x6932: "Wei " -0x6933: "Wei " -0x6934: "Duan " -0x6935: "Jia " -0x6936: "Zong " -0x6937: "Jian " -0x6938: "Yi " -0x6939: "Shen " -0x693a: "Xi " -0x693b: "Yan " -0x693c: "Yan " -0x693d: "Chuan " -0x693e: "Zhan " -0x693f: "Chun " -0x6940: "Yu " -0x6941: "He " -0x6942: "Zha " -0x6943: "Wo " -0x6944: "Pian " -0x6945: "Bi " -0x6946: "Yao " -0x6947: "Huo " -0x6948: "Xu " -0x6949: "Ruo " -0x694a: "Yang " -0x694b: "La " -0x694c: "Yan " -0x694d: "Ben " -0x694e: "Hun " -0x694f: "Kui " -0x6950: "Jie " -0x6951: "Kui " -0x6952: "Si " -0x6953: "Feng " -0x6954: "Xie " -0x6955: "Tuo " -0x6956: "Zhi " -0x6957: "Jian " -0x6958: "Mu " -0x6959: "Mao " -0x695a: "Chu " -0x695b: "Hu " -0x695c: "Hu " -0x695d: "Lian " -0x695e: "Leng " -0x695f: "Ting " -0x6960: "Nan " -0x6961: "Yu " -0x6962: "You " -0x6963: "Mei " -0x6964: "Song " -0x6965: "Xuan " -0x6966: "Xuan " -0x6967: "Ying " -0x6968: "Zhen " -0x6969: "Pian " -0x696a: "Ye " -0x696b: "Ji " -0x696c: "Jie " -0x696d: "Ye " -0x696e: "Chu " -0x696f: "Shun " -0x6970: "Yu " -0x6971: "Cou " -0x6972: "Wei " -0x6973: "Mei " -0x6974: "Di " -0x6975: "Ji " -0x6976: "Jie " -0x6977: "Kai " -0x6978: "Qiu " -0x6979: "Ying " -0x697a: "Rou " -0x697b: "Heng " -0x697c: "Lou " -0x697d: "Le " -0x697e: "Hazou " -0x697f: "Katsura " -0x6980: "Pin " -0x6981: "Muro " -0x6982: "Gai " -0x6983: "Tan " -0x6984: "Lan " -0x6985: "Yun " -0x6986: "Yu " -0x6987: "Chen " -0x6988: "Lu " -0x6989: "Ju " -0x698a: "Sakaki " -0x698b: "[?] " -0x698c: "Pi " -0x698d: "Xie " -0x698e: "Jia " -0x698f: "Yi " -0x6990: "Zhan " -0x6991: "Fu " -0x6992: "Nai " -0x6993: "Mi " -0x6994: "Lang " -0x6995: "Rong " -0x6996: "Gu " -0x6997: "Jian " -0x6998: "Ju " -0x6999: "Ta " -0x699a: "Yao " -0x699b: "Zhen " -0x699c: "Bang " -0x699d: "Sha " -0x699e: "Yuan " -0x699f: "Zi " -0x69a0: "Ming " -0x69a1: "Su " -0x69a2: "Jia " -0x69a3: "Yao " -0x69a4: "Jie " -0x69a5: "Huang " -0x69a6: "Gan " -0x69a7: "Fei " -0x69a8: "Zha " -0x69a9: "Qian " -0x69aa: "Ma " -0x69ab: "Sun " -0x69ac: "Yuan " -0x69ad: "Xie " -0x69ae: "Rong " -0x69af: "Shi " -0x69b0: "Zhi " -0x69b1: "Cui " -0x69b2: "Yun " -0x69b3: "Ting " -0x69b4: "Liu " -0x69b5: "Rong " -0x69b6: "Tang " -0x69b7: "Que " -0x69b8: "Zhai " -0x69b9: "Si " -0x69ba: "Sheng " -0x69bb: "Ta " -0x69bc: "Ke " -0x69bd: "Xi " -0x69be: "Gu " -0x69bf: "Qi " -0x69c0: "Kao " -0x69c1: "Gao " -0x69c2: "Sun " -0x69c3: "Pan " -0x69c4: "Tao " -0x69c5: "Ge " -0x69c6: "Xun " -0x69c7: "Dian " -0x69c8: "Nou " -0x69c9: "Ji " -0x69ca: "Shuo " -0x69cb: "Gou " -0x69cc: "Chui " -0x69cd: "Qiang " -0x69ce: "Cha " -0x69cf: "Qian " -0x69d0: "Huai " -0x69d1: "Mei " -0x69d2: "Xu " -0x69d3: "Gang " -0x69d4: "Gao " -0x69d5: "Zhuo " -0x69d6: "Tuo " -0x69d7: "Hashi " -0x69d8: "Yang " -0x69d9: "Dian " -0x69da: "Jia " -0x69db: "Jian " -0x69dc: "Zui " -0x69dd: "Kashi " -0x69de: "Ori " -0x69df: "Bin " -0x69e0: "Zhu " -0x69e1: "[?] " -0x69e2: "Xi " -0x69e3: "Qi " -0x69e4: "Lian " -0x69e5: "Hui " -0x69e6: "Yong " -0x69e7: "Qian " -0x69e8: "Guo " -0x69e9: "Gai " -0x69ea: "Gai " -0x69eb: "Tuan " -0x69ec: "Hua " -0x69ed: "Cu " -0x69ee: "Sen " -0x69ef: "Cui " -0x69f0: "Beng " -0x69f1: "You " -0x69f2: "Hu " -0x69f3: "Jiang " -0x69f4: "Hu " -0x69f5: "Huan " -0x69f6: "Kui " -0x69f7: "Yi " -0x69f8: "Nie " -0x69f9: "Gao " -0x69fa: "Kang " -0x69fb: "Gui " -0x69fc: "Gui " -0x69fd: "Cao " -0x69fe: "Man " -0x69ff: "Jin " -/* x06a */ -0x6a00: "Di " -0x6a01: "Zhuang " -0x6a02: "Le " -0x6a03: "Lang " -0x6a04: "Chen " -0x6a05: "Cong " -0x6a06: "Li " -0x6a07: "Xiu " -0x6a08: "Qing " -0x6a09: "Shuang " -0x6a0a: "Fan " -0x6a0b: "Tong " -0x6a0c: "Guan " -0x6a0d: "Ji " -0x6a0e: "Suo " -0x6a0f: "Lei " -0x6a10: "Lu " -0x6a11: "Liang " -0x6a12: "Mi " -0x6a13: "Lou " -0x6a14: "Chao " -0x6a15: "Su " -0x6a16: "Ke " -0x6a17: "Shu " -0x6a18: "Tang " -0x6a19: "Biao " -0x6a1a: "Lu " -0x6a1b: "Jiu " -0x6a1c: "Shu " -0x6a1d: "Zha " -0x6a1e: "Shu " -0x6a1f: "Zhang " -0x6a20: "Men " -0x6a21: "Mo " -0x6a22: "Niao " -0x6a23: "Yang " -0x6a24: "Tiao " -0x6a25: "Peng " -0x6a26: "Zhu " -0x6a27: "Sha " -0x6a28: "Xi " -0x6a29: "Quan " -0x6a2a: "Heng " -0x6a2b: "Jian " -0x6a2c: "Cong " -0x6a2d: "[?] " -0x6a2e: "Hokuso " -0x6a2f: "Qiang " -0x6a30: "Tara " -0x6a31: "Ying " -0x6a32: "Er " -0x6a33: "Xin " -0x6a34: "Zhi " -0x6a35: "Qiao " -0x6a36: "Zui " -0x6a37: "Cong " -0x6a38: "Pu " -0x6a39: "Shu " -0x6a3a: "Hua " -0x6a3b: "Kui " -0x6a3c: "Zhen " -0x6a3d: "Zun " -0x6a3e: "Yue " -0x6a3f: "Zhan " -0x6a40: "Xi " -0x6a41: "Xun " -0x6a42: "Dian " -0x6a43: "Fa " -0x6a44: "Gan " -0x6a45: "Mo " -0x6a46: "Wu " -0x6a47: "Qiao " -0x6a48: "Nao " -0x6a49: "Lin " -0x6a4a: "Liu " -0x6a4b: "Qiao " -0x6a4c: "Xian " -0x6a4d: "Run " -0x6a4e: "Fan " -0x6a4f: "Zhan " -0x6a50: "Tuo " -0x6a51: "Lao " -0x6a52: "Yun " -0x6a53: "Shun " -0x6a54: "Tui " -0x6a55: "Cheng " -0x6a56: "Tang " -0x6a57: "Meng " -0x6a58: "Ju " -0x6a59: "Cheng " -0x6a5a: "Su " -0x6a5b: "Jue " -0x6a5c: "Jue " -0x6a5d: "Tan " -0x6a5e: "Hui " -0x6a5f: "Ji " -0x6a60: "Nuo " -0x6a61: "Xiang " -0x6a62: "Tuo " -0x6a63: "Ning " -0x6a64: "Rui " -0x6a65: "Zhu " -0x6a66: "Chuang " -0x6a67: "Zeng " -0x6a68: "Fen " -0x6a69: "Qiong " -0x6a6a: "Ran " -0x6a6b: "Heng " -0x6a6c: "Cen " -0x6a6d: "Gu " -0x6a6e: "Liu " -0x6a6f: "Lao " -0x6a70: "Gao " -0x6a71: "Chu " -0x6a72: "Zusa " -0x6a73: "Nude " -0x6a74: "Ca " -0x6a75: "San " -0x6a76: "Ji " -0x6a77: "Dou " -0x6a78: "Shou " -0x6a79: "Lu " -0x6a7a: "[?] " -0x6a7b: "[?] " -0x6a7c: "Yuan " -0x6a7d: "Ta " -0x6a7e: "Shu " -0x6a7f: "Jiang " -0x6a80: "Tan " -0x6a81: "Lin " -0x6a82: "Nong " -0x6a83: "Yin " -0x6a84: "Xi " -0x6a85: "Sui " -0x6a86: "Shan " -0x6a87: "Zui " -0x6a88: "Xuan " -0x6a89: "Cheng " -0x6a8a: "Gan " -0x6a8b: "Ju " -0x6a8c: "Zui " -0x6a8d: "Yi " -0x6a8e: "Qin " -0x6a8f: "Pu " -0x6a90: "Yan " -0x6a91: "Lei " -0x6a92: "Feng " -0x6a93: "Hui " -0x6a94: "Dang " -0x6a95: "Ji " -0x6a96: "Sui " -0x6a97: "Bo " -0x6a98: "Bi " -0x6a99: "Ding " -0x6a9a: "Chu " -0x6a9b: "Zhua " -0x6a9c: "Kuai " -0x6a9d: "Ji " -0x6a9e: "Jie " -0x6a9f: "Jia " -0x6aa0: "Qing " -0x6aa1: "Zhe " -0x6aa2: "Jian " -0x6aa3: "Qiang " -0x6aa4: "Dao " -0x6aa5: "Yi " -0x6aa6: "Biao " -0x6aa7: "Song " -0x6aa8: "She " -0x6aa9: "Lin " -0x6aaa: "Kunugi " -0x6aab: "Cha " -0x6aac: "Meng " -0x6aad: "Yin " -0x6aae: "Tao " -0x6aaf: "Tai " -0x6ab0: "Mian " -0x6ab1: "Qi " -0x6ab2: "Toan " -0x6ab3: "Bin " -0x6ab4: "Huo " -0x6ab5: "Ji " -0x6ab6: "Qian " -0x6ab7: "Mi " -0x6ab8: "Ning " -0x6ab9: "Yi " -0x6aba: "Gao " -0x6abb: "Jian " -0x6abc: "Yin " -0x6abd: "Er " -0x6abe: "Qing " -0x6abf: "Yan " -0x6ac0: "Qi " -0x6ac1: "Mi " -0x6ac2: "Zhao " -0x6ac3: "Gui " -0x6ac4: "Chun " -0x6ac5: "Ji " -0x6ac6: "Kui " -0x6ac7: "Po " -0x6ac8: "Deng " -0x6ac9: "Chu " -0x6aca: "[?] " -0x6acb: "Mian " -0x6acc: "You " -0x6acd: "Zhi " -0x6ace: "Guang " -0x6acf: "Qian " -0x6ad0: "Lei " -0x6ad1: "Lei " -0x6ad2: "Sa " -0x6ad3: "Lu " -0x6ad4: "Li " -0x6ad5: "Cuan " -0x6ad6: "Lu " -0x6ad7: "Mie " -0x6ad8: "Hui " -0x6ad9: "Ou " -0x6ada: "Lu " -0x6adb: "Jie " -0x6adc: "Gao " -0x6add: "Du " -0x6ade: "Yuan " -0x6adf: "Li " -0x6ae0: "Fei " -0x6ae1: "Zhuo " -0x6ae2: "Sou " -0x6ae3: "Lian " -0x6ae4: "Tamo " -0x6ae5: "Chu " -0x6ae6: "[?] " -0x6ae7: "Zhu " -0x6ae8: "Lu " -0x6ae9: "Yan " -0x6aea: "Li " -0x6aeb: "Zhu " -0x6aec: "Chen " -0x6aed: "Jie " -0x6aee: "E " -0x6aef: "Su " -0x6af0: "Huai " -0x6af1: "Nie " -0x6af2: "Yu " -0x6af3: "Long " -0x6af4: "Lai " -0x6af5: "[?] " -0x6af6: "Xian " -0x6af7: "Kwi " -0x6af8: "Ju " -0x6af9: "Xiao " -0x6afa: "Ling " -0x6afb: "Ying " -0x6afc: "Jian " -0x6afd: "Yin " -0x6afe: "You " -0x6aff: "Ying " -/* x06b */ -0x6b00: "Xiang " -0x6b01: "Nong " -0x6b02: "Bo " -0x6b03: "Chan " -0x6b04: "Lan " -0x6b05: "Ju " -0x6b06: "Shuang " -0x6b07: "She " -0x6b08: "Wei " -0x6b09: "Cong " -0x6b0a: "Quan " -0x6b0b: "Qu " -0x6b0c: "Cang " -0x6b0d: "[?] " -0x6b0e: "Yu " -0x6b0f: "Luo " -0x6b10: "Li " -0x6b11: "Zan " -0x6b12: "Luan " -0x6b13: "Dang " -0x6b14: "Jue " -0x6b15: "Em " -0x6b16: "Lan " -0x6b17: "Lan " -0x6b18: "Zhu " -0x6b19: "Lei " -0x6b1a: "Li " -0x6b1b: "Ba " -0x6b1c: "Nang " -0x6b1d: "Yu " -0x6b1e: "Ling " -0x6b1f: "Tsuki " -0x6b20: "Qian " -0x6b21: "Ci " -0x6b22: "Huan " -0x6b23: "Xin " -0x6b24: "Yu " -0x6b25: "Yu " -0x6b26: "Qian " -0x6b27: "Ou " -0x6b28: "Xu " -0x6b29: "Chao " -0x6b2a: "Chu " -0x6b2b: "Chi " -0x6b2c: "Kai " -0x6b2d: "Yi " -0x6b2e: "Jue " -0x6b2f: "Xi " -0x6b30: "Xu " -0x6b31: "Xia " -0x6b32: "Yu " -0x6b33: "Kuai " -0x6b34: "Lang " -0x6b35: "Kuan " -0x6b36: "Shuo " -0x6b37: "Xi " -0x6b38: "Ai " -0x6b39: "Yi " -0x6b3a: "Qi " -0x6b3b: "Hu " -0x6b3c: "Chi " -0x6b3d: "Qin " -0x6b3e: "Kuan " -0x6b3f: "Kan " -0x6b40: "Kuan " -0x6b41: "Kan " -0x6b42: "Chuan " -0x6b43: "Sha " -0x6b44: "Gua " -0x6b45: "Yin " -0x6b46: "Xin " -0x6b47: "Xie " -0x6b48: "Yu " -0x6b49: "Qian " -0x6b4a: "Xiao " -0x6b4b: "Yi " -0x6b4c: "Ge " -0x6b4d: "Wu " -0x6b4e: "Tan " -0x6b4f: "Jin " -0x6b50: "Ou " -0x6b51: "Hu " -0x6b52: "Ti " -0x6b53: "Huan " -0x6b54: "Xu " -0x6b55: "Pen " -0x6b56: "Xi " -0x6b57: "Xiao " -0x6b58: "Xu " -0x6b59: "Xi " -0x6b5a: "Sen " -0x6b5b: "Lian " -0x6b5c: "Chu " -0x6b5d: "Yi " -0x6b5e: "Kan " -0x6b5f: "Yu " -0x6b60: "Chuo " -0x6b61: "Huan " -0x6b62: "Zhi " -0x6b63: "Zheng " -0x6b64: "Ci " -0x6b65: "Bu " -0x6b66: "Wu " -0x6b67: "Qi " -0x6b68: "Bu " -0x6b69: "Bu " -0x6b6a: "Wai " -0x6b6b: "Ju " -0x6b6c: "Qian " -0x6b6d: "Chi " -0x6b6e: "Se " -0x6b6f: "Chi " -0x6b70: "Se " -0x6b71: "Zhong " -0x6b72: "Sui " -0x6b73: "Sui " -0x6b74: "Li " -0x6b75: "Cuo " -0x6b76: "Yu " -0x6b77: "Li " -0x6b78: "Gui " -0x6b79: "Dai " -0x6b7a: "Dai " -0x6b7b: "Si " -0x6b7c: "Jian " -0x6b7d: "Zhe " -0x6b7e: "Mo " -0x6b7f: "Mo " -0x6b80: "Yao " -0x6b81: "Mo " -0x6b82: "Cu " -0x6b83: "Yang " -0x6b84: "Tian " -0x6b85: "Sheng " -0x6b86: "Dai " -0x6b87: "Shang " -0x6b88: "Xu " -0x6b89: "Xun " -0x6b8a: "Shu " -0x6b8b: "Can " -0x6b8c: "Jue " -0x6b8d: "Piao " -0x6b8e: "Qia " -0x6b8f: "Qiu " -0x6b90: "Su " -0x6b91: "Qing " -0x6b92: "Yun " -0x6b93: "Lian " -0x6b94: "Yi " -0x6b95: "Fou " -0x6b96: "Zhi " -0x6b97: "Ye " -0x6b98: "Can " -0x6b99: "Hun " -0x6b9a: "Dan " -0x6b9b: "Ji " -0x6b9c: "Ye " -0x6b9d: "Zhen " -0x6b9e: "Yun " -0x6b9f: "Wen " -0x6ba0: "Chou " -0x6ba1: "Bin " -0x6ba2: "Ti " -0x6ba3: "Jin " -0x6ba4: "Shang " -0x6ba5: "Yin " -0x6ba6: "Diao " -0x6ba7: "Cu " -0x6ba8: "Hui " -0x6ba9: "Cuan " -0x6baa: "Yi " -0x6bab: "Dan " -0x6bac: "Du " -0x6bad: "Jiang " -0x6bae: "Lian " -0x6baf: "Bin " -0x6bb0: "Du " -0x6bb1: "Tsukusu " -0x6bb2: "Jian " -0x6bb3: "Shu " -0x6bb4: "Ou " -0x6bb5: "Duan " -0x6bb6: "Zhu " -0x6bb7: "Yin " -0x6bb8: "Qing " -0x6bb9: "Yi " -0x6bba: "Sha " -0x6bbb: "Que " -0x6bbc: "Ke " -0x6bbd: "Yao " -0x6bbe: "Jun " -0x6bbf: "Dian " -0x6bc0: "Hui " -0x6bc1: "Hui " -0x6bc2: "Gu " -0x6bc3: "Que " -0x6bc4: "Ji " -0x6bc5: "Yi " -0x6bc6: "Ou " -0x6bc7: "Hui " -0x6bc8: "Duan " -0x6bc9: "Yi " -0x6bca: "Xiao " -0x6bcb: "Wu " -0x6bcc: "Guan " -0x6bcd: "Mu " -0x6bce: "Mei " -0x6bcf: "Mei " -0x6bd0: "Ai " -0x6bd1: "Zuo " -0x6bd2: "Du " -0x6bd3: "Yu " -0x6bd4: "Bi " -0x6bd5: "Bi " -0x6bd6: "Bi " -0x6bd7: "Pi " -0x6bd8: "Pi " -0x6bd9: "Bi " -0x6bda: "Chan " -0x6bdb: "Mao " -0x6bdc: "[?] " -0x6bdd: "[?] " -0x6bde: "Pu " -0x6bdf: "Mushiru " -0x6be0: "Jia " -0x6be1: "Zhan " -0x6be2: "Sai " -0x6be3: "Mu " -0x6be4: "Tuo " -0x6be5: "Xun " -0x6be6: "Er " -0x6be7: "Rong " -0x6be8: "Xian " -0x6be9: "Ju " -0x6bea: "Mu " -0x6beb: "Hao " -0x6bec: "Qiu " -0x6bed: "Dou " -0x6bee: "Mushiru " -0x6bef: "Tan " -0x6bf0: "Pei " -0x6bf1: "Ju " -0x6bf2: "Duo " -0x6bf3: "Cui " -0x6bf4: "Bi " -0x6bf5: "San " -0x6bf6: "[?] " -0x6bf7: "Mao " -0x6bf8: "Sui " -0x6bf9: "Yu " -0x6bfa: "Yu " -0x6bfb: "Tuo " -0x6bfc: "He " -0x6bfd: "Jian " -0x6bfe: "Ta " -0x6bff: "San " -/* x06c */ -0x6c00: "Lu " -0x6c01: "Mu " -0x6c02: "Li " -0x6c03: "Tong " -0x6c04: "Rong " -0x6c05: "Chang " -0x6c06: "Pu " -0x6c07: "Luo " -0x6c08: "Zhan " -0x6c09: "Sao " -0x6c0a: "Zhan " -0x6c0b: "Meng " -0x6c0c: "Luo " -0x6c0d: "Qu " -0x6c0e: "Die " -0x6c0f: "Shi " -0x6c10: "Di " -0x6c11: "Min " -0x6c12: "Jue " -0x6c13: "Mang " -0x6c14: "Qi " -0x6c15: "Pie " -0x6c16: "Nai " -0x6c17: "Qi " -0x6c18: "Dao " -0x6c19: "Xian " -0x6c1a: "Chuan " -0x6c1b: "Fen " -0x6c1c: "Ri " -0x6c1d: "Nei " -0x6c1e: "[?] " -0x6c1f: "Fu " -0x6c20: "Shen " -0x6c21: "Dong " -0x6c22: "Qing " -0x6c23: "Qi " -0x6c24: "Yin " -0x6c25: "Xi " -0x6c26: "Hai " -0x6c27: "Yang " -0x6c28: "An " -0x6c29: "Ya " -0x6c2a: "Ke " -0x6c2b: "Qing " -0x6c2c: "Ya " -0x6c2d: "Dong " -0x6c2e: "Dan " -0x6c2f: "Lu " -0x6c30: "Qing " -0x6c31: "Yang " -0x6c32: "Yun " -0x6c33: "Yun " -0x6c34: "Shui " -0x6c35: "San " -0x6c36: "Zheng " -0x6c37: "Bing " -0x6c38: "Yong " -0x6c39: "Dang " -0x6c3a: "Shitamizu " -0x6c3b: "Le " -0x6c3c: "Ni " -0x6c3d: "Tun " -0x6c3e: "Fan " -0x6c3f: "Gui " -0x6c40: "Ting " -0x6c41: "Zhi " -0x6c42: "Qiu " -0x6c43: "Bin " -0x6c44: "Ze " -0x6c45: "Mian " -0x6c46: "Cuan " -0x6c47: "Hui " -0x6c48: "Diao " -0x6c49: "Yi " -0x6c4a: "Cha " -0x6c4b: "Zhuo " -0x6c4c: "Chuan " -0x6c4d: "Wan " -0x6c4e: "Fan " -0x6c4f: "Dai " -0x6c50: "Xi " -0x6c51: "Tuo " -0x6c52: "Mang " -0x6c53: "Qiu " -0x6c54: "Qi " -0x6c55: "Shan " -0x6c56: "Pai " -0x6c57: "Han " -0x6c58: "Qian " -0x6c59: "Wu " -0x6c5a: "Wu " -0x6c5b: "Xun " -0x6c5c: "Si " -0x6c5d: "Ru " -0x6c5e: "Gong " -0x6c5f: "Jiang " -0x6c60: "Chi " -0x6c61: "Wu " -0x6c62: "Tsuchi " -0x6c63: "[?] " -0x6c64: "Tang " -0x6c65: "Zhi " -0x6c66: "Chi " -0x6c67: "Qian " -0x6c68: "Mi " -0x6c69: "Yu " -0x6c6a: "Wang " -0x6c6b: "Qing " -0x6c6c: "Jing " -0x6c6d: "Rui " -0x6c6e: "Jun " -0x6c6f: "Hong " -0x6c70: "Tai " -0x6c71: "Quan " -0x6c72: "Ji " -0x6c73: "Bian " -0x6c74: "Bian " -0x6c75: "Gan " -0x6c76: "Wen " -0x6c77: "Zhong " -0x6c78: "Fang " -0x6c79: "Xiong " -0x6c7a: "Jue " -0x6c7b: "Hang " -0x6c7c: "Niou " -0x6c7d: "Qi " -0x6c7e: "Fen " -0x6c7f: "Xu " -0x6c80: "Xu " -0x6c81: "Qin " -0x6c82: "Yi " -0x6c83: "Wo " -0x6c84: "Yun " -0x6c85: "Yuan " -0x6c86: "Hang " -0x6c87: "Yan " -0x6c88: "Chen " -0x6c89: "Chen " -0x6c8a: "Dan " -0x6c8b: "You " -0x6c8c: "Dun " -0x6c8d: "Hu " -0x6c8e: "Huo " -0x6c8f: "Qie " -0x6c90: "Mu " -0x6c91: "Rou " -0x6c92: "Mei " -0x6c93: "Ta " -0x6c94: "Mian " -0x6c95: "Wu " -0x6c96: "Chong " -0x6c97: "Tian " -0x6c98: "Bi " -0x6c99: "Sha " -0x6c9a: "Zhi " -0x6c9b: "Pei " -0x6c9c: "Pan " -0x6c9d: "Zhui " -0x6c9e: "Za " -0x6c9f: "Gou " -0x6ca0: "Liu " -0x6ca1: "Mei " -0x6ca2: "Ze " -0x6ca3: "Feng " -0x6ca4: "Ou " -0x6ca5: "Li " -0x6ca6: "Lun " -0x6ca7: "Cang " -0x6ca8: "Feng " -0x6ca9: "Wei " -0x6caa: "Hu " -0x6cab: "Mo " -0x6cac: "Mei " -0x6cad: "Shu " -0x6cae: "Ju " -0x6caf: "Zan " -0x6cb0: "Tuo " -0x6cb1: "Tuo " -0x6cb2: "Tuo " -0x6cb3: "He " -0x6cb4: "Li " -0x6cb5: "Mi " -0x6cb6: "Yi " -0x6cb7: "Fa " -0x6cb8: "Fei " -0x6cb9: "You " -0x6cba: "Tian " -0x6cbb: "Zhi " -0x6cbc: "Zhao " -0x6cbd: "Gu " -0x6cbe: "Zhan " -0x6cbf: "Yan " -0x6cc0: "Si " -0x6cc1: "Kuang " -0x6cc2: "Jiong " -0x6cc3: "Ju " -0x6cc4: "Xie " -0x6cc5: "Qiu " -0x6cc6: "Yi " -0x6cc7: "Jia " -0x6cc8: "Zhong " -0x6cc9: "Quan " -0x6cca: "Bo " -0x6ccb: "Hui " -0x6ccc: "Mi " -0x6ccd: "Ben " -0x6cce: "Zhuo " -0x6ccf: "Chu " -0x6cd0: "Le " -0x6cd1: "You " -0x6cd2: "Gu " -0x6cd3: "Hong " -0x6cd4: "Gan " -0x6cd5: "Fa " -0x6cd6: "Mao " -0x6cd7: "Si " -0x6cd8: "Hu " -0x6cd9: "Ping " -0x6cda: "Ci " -0x6cdb: "Fan " -0x6cdc: "Chi " -0x6cdd: "Su " -0x6cde: "Ning " -0x6cdf: "Cheng " -0x6ce0: "Ling " -0x6ce1: "Pao " -0x6ce2: "Bo " -0x6ce3: "Qi " -0x6ce4: "Si " -0x6ce5: "Ni " -0x6ce6: "Ju " -0x6ce7: "Yue " -0x6ce8: "Zhu " -0x6ce9: "Sheng " -0x6cea: "Lei " -0x6ceb: "Xuan " -0x6cec: "Xue " -0x6ced: "Fu " -0x6cee: "Pan " -0x6cef: "Min " -0x6cf0: "Tai " -0x6cf1: "Yang " -0x6cf2: "Ji " -0x6cf3: "Yong " -0x6cf4: "Guan " -0x6cf5: "Beng " -0x6cf6: "Xue " -0x6cf7: "Long " -0x6cf8: "Lu " -0x6cf9: "[?] " -0x6cfa: "Bo " -0x6cfb: "Xie " -0x6cfc: "Po " -0x6cfd: "Ze " -0x6cfe: "Jing " -0x6cff: "Yin " -/* x06d */ -0x6d00: "Zhou " -0x6d01: "Ji " -0x6d02: "Yi " -0x6d03: "Hui " -0x6d04: "Hui " -0x6d05: "Zui " -0x6d06: "Cheng " -0x6d07: "Yin " -0x6d08: "Wei " -0x6d09: "Hou " -0x6d0a: "Jian " -0x6d0b: "Yang " -0x6d0c: "Lie " -0x6d0d: "Si " -0x6d0e: "Ji " -0x6d0f: "Er " -0x6d10: "Xing " -0x6d11: "Fu " -0x6d12: "Sa " -0x6d13: "Suo " -0x6d14: "Zhi " -0x6d15: "Yin " -0x6d16: "Wu " -0x6d17: "Xi " -0x6d18: "Kao " -0x6d19: "Zhu " -0x6d1a: "Jiang " -0x6d1b: "Luo " -0x6d1c: "[?] " -0x6d1d: "An " -0x6d1e: "Dong " -0x6d1f: "Yi " -0x6d20: "Mou " -0x6d21: "Lei " -0x6d22: "Yi " -0x6d23: "Mi " -0x6d24: "Quan " -0x6d25: "Jin " -0x6d26: "Mo " -0x6d27: "Wei " -0x6d28: "Xiao " -0x6d29: "Xie " -0x6d2a: "Hong " -0x6d2b: "Xu " -0x6d2c: "Shuo " -0x6d2d: "Kuang " -0x6d2e: "Tao " -0x6d2f: "Qie " -0x6d30: "Ju " -0x6d31: "Er " -0x6d32: "Zhou " -0x6d33: "Ru " -0x6d34: "Ping " -0x6d35: "Xun " -0x6d36: "Xiong " -0x6d37: "Zhi " -0x6d38: "Guang " -0x6d39: "Huan " -0x6d3a: "Ming " -0x6d3b: "Huo " -0x6d3c: "Wa " -0x6d3d: "Qia " -0x6d3e: "Pai " -0x6d3f: "Wu " -0x6d40: "Qu " -0x6d41: "Liu " -0x6d42: "Yi " -0x6d43: "Jia " -0x6d44: "Jing " -0x6d45: "Qian " -0x6d46: "Jiang " -0x6d47: "Jiao " -0x6d48: "Cheng " -0x6d49: "Shi " -0x6d4a: "Zhuo " -0x6d4b: "Ce " -0x6d4c: "Pal " -0x6d4d: "Kuai " -0x6d4e: "Ji " -0x6d4f: "Liu " -0x6d50: "Chan " -0x6d51: "Hun " -0x6d52: "Hu " -0x6d53: "Nong " -0x6d54: "Xun " -0x6d55: "Jin " -0x6d56: "Lie " -0x6d57: "Qiu " -0x6d58: "Wei " -0x6d59: "Zhe " -0x6d5a: "Jun " -0x6d5b: "Han " -0x6d5c: "Bang " -0x6d5d: "Mang " -0x6d5e: "Zhuo " -0x6d5f: "You " -0x6d60: "Xi " -0x6d61: "Bo " -0x6d62: "Dou " -0x6d63: "Wan " -0x6d64: "Hong " -0x6d65: "Yi " -0x6d66: "Pu " -0x6d67: "Ying " -0x6d68: "Lan " -0x6d69: "Hao " -0x6d6a: "Lang " -0x6d6b: "Han " -0x6d6c: "Li " -0x6d6d: "Geng " -0x6d6e: "Fu " -0x6d6f: "Wu " -0x6d70: "Lian " -0x6d71: "Chun " -0x6d72: "Feng " -0x6d73: "Yi " -0x6d74: "Yu " -0x6d75: "Tong " -0x6d76: "Lao " -0x6d77: "Hai " -0x6d78: "Jin " -0x6d79: "Jia " -0x6d7a: "Chong " -0x6d7b: "Weng " -0x6d7c: "Mei " -0x6d7d: "Sui " -0x6d7e: "Cheng " -0x6d7f: "Pei " -0x6d80: "Xian " -0x6d81: "Shen " -0x6d82: "Tu " -0x6d83: "Kun " -0x6d84: "Pin " -0x6d85: "Nie " -0x6d86: "Han " -0x6d87: "Jing " -0x6d88: "Xiao " -0x6d89: "She " -0x6d8a: "Nian " -0x6d8b: "Tu " -0x6d8c: "Yong " -0x6d8d: "Xiao " -0x6d8e: "Xian " -0x6d8f: "Ting " -0x6d90: "E " -0x6d91: "Su " -0x6d92: "Tun " -0x6d93: "Juan " -0x6d94: "Cen " -0x6d95: "Ti " -0x6d96: "Li " -0x6d97: "Shui " -0x6d98: "Si " -0x6d99: "Lei " -0x6d9a: "Shui " -0x6d9b: "Tao " -0x6d9c: "Du " -0x6d9d: "Lao " -0x6d9e: "Lai " -0x6d9f: "Lian " -0x6da0: "Wei " -0x6da1: "Wo " -0x6da2: "Yun " -0x6da3: "Huan " -0x6da4: "Di " -0x6da5: "[?] " -0x6da6: "Run " -0x6da7: "Jian " -0x6da8: "Zhang " -0x6da9: "Se " -0x6daa: "Fu " -0x6dab: "Guan " -0x6dac: "Xing " -0x6dad: "Shou " -0x6dae: "Shuan " -0x6daf: "Ya " -0x6db0: "Chuo " -0x6db1: "Zhang " -0x6db2: "Ye " -0x6db3: "Kong " -0x6db4: "Wo " -0x6db5: "Han " -0x6db6: "Tuo " -0x6db7: "Dong " -0x6db8: "He " -0x6db9: "Wo " -0x6dba: "Ju " -0x6dbb: "Gan " -0x6dbc: "Liang " -0x6dbd: "Hun " -0x6dbe: "Ta " -0x6dbf: "Zhuo " -0x6dc0: "Dian " -0x6dc1: "Qie " -0x6dc2: "De " -0x6dc3: "Juan " -0x6dc4: "Zi " -0x6dc5: "Xi " -0x6dc6: "Yao " -0x6dc7: "Qi " -0x6dc8: "Gu " -0x6dc9: "Guo " -0x6dca: "Han " -0x6dcb: "Lin " -0x6dcc: "Tang " -0x6dcd: "Zhou " -0x6dce: "Peng " -0x6dcf: "Hao " -0x6dd0: "Chang " -0x6dd1: "Shu " -0x6dd2: "Qi " -0x6dd3: "Fang " -0x6dd4: "Chi " -0x6dd5: "Lu " -0x6dd6: "Nao " -0x6dd7: "Ju " -0x6dd8: "Tao " -0x6dd9: "Cong " -0x6dda: "Lei " -0x6ddb: "Zhi " -0x6ddc: "Peng " -0x6ddd: "Fei " -0x6dde: "Song " -0x6ddf: "Tian " -0x6de0: "Pi " -0x6de1: "Dan " -0x6de2: "Yu " -0x6de3: "Ni " -0x6de4: "Yu " -0x6de5: "Lu " -0x6de6: "Gan " -0x6de7: "Mi " -0x6de8: "Jing " -0x6de9: "Ling " -0x6dea: "Lun " -0x6deb: "Yin " -0x6dec: "Cui " -0x6ded: "Qu " -0x6dee: "Huai " -0x6def: "Yu " -0x6df0: "Nian " -0x6df1: "Shen " -0x6df2: "Piao " -0x6df3: "Chun " -0x6df4: "Wa " -0x6df5: "Yuan " -0x6df6: "Lai " -0x6df7: "Hun " -0x6df8: "Qing " -0x6df9: "Yan " -0x6dfa: "Qian " -0x6dfb: "Tian " -0x6dfc: "Miao " -0x6dfd: "Zhi " -0x6dfe: "Yin " -0x6dff: "Mi " -/* x06e */ -0x6e00: "Ben " -0x6e01: "Yuan " -0x6e02: "Wen " -0x6e03: "Re " -0x6e04: "Fei " -0x6e05: "Qing " -0x6e06: "Yuan " -0x6e07: "Ke " -0x6e08: "Ji " -0x6e09: "She " -0x6e0a: "Yuan " -0x6e0b: "Shibui " -0x6e0c: "Lu " -0x6e0d: "Zi " -0x6e0e: "Du " -0x6e0f: "[?] " -0x6e10: "Jian " -0x6e11: "Min " -0x6e12: "Pi " -0x6e13: "Tani " -0x6e14: "Yu " -0x6e15: "Yuan " -0x6e16: "Shen " -0x6e17: "Shen " -0x6e18: "Rou " -0x6e19: "Huan " -0x6e1a: "Zhu " -0x6e1b: "Jian " -0x6e1c: "Nuan " -0x6e1d: "Yu " -0x6e1e: "Qiu " -0x6e1f: "Ting " -0x6e20: "Qu " -0x6e21: "Du " -0x6e22: "Feng " -0x6e23: "Zha " -0x6e24: "Bo " -0x6e25: "Wo " -0x6e26: "Wo " -0x6e27: "Di " -0x6e28: "Wei " -0x6e29: "Wen " -0x6e2a: "Ru " -0x6e2b: "Xie " -0x6e2c: "Ce " -0x6e2d: "Wei " -0x6e2e: "Ge " -0x6e2f: "Gang " -0x6e30: "Yan " -0x6e31: "Hong " -0x6e32: "Xuan " -0x6e33: "Mi " -0x6e34: "Ke " -0x6e35: "Mao " -0x6e36: "Ying " -0x6e37: "Yan " -0x6e38: "You " -0x6e39: "Hong " -0x6e3a: "Miao " -0x6e3b: "Xing " -0x6e3c: "Mei " -0x6e3d: "Zai " -0x6e3e: "Hun " -0x6e3f: "Nai " -0x6e40: "Kui " -0x6e41: "Shi " -0x6e42: "E " -0x6e43: "Pai " -0x6e44: "Mei " -0x6e45: "Lian " -0x6e46: "Qi " -0x6e47: "Qi " -0x6e48: "Mei " -0x6e49: "Tian " -0x6e4a: "Cou " -0x6e4b: "Wei " -0x6e4c: "Can " -0x6e4d: "Tuan " -0x6e4e: "Mian " -0x6e4f: "Hui " -0x6e50: "Mo " -0x6e51: "Xu " -0x6e52: "Ji " -0x6e53: "Pen " -0x6e54: "Jian " -0x6e55: "Jian " -0x6e56: "Hu " -0x6e57: "Feng " -0x6e58: "Xiang " -0x6e59: "Yi " -0x6e5a: "Yin " -0x6e5b: "Zhan " -0x6e5c: "Shi " -0x6e5d: "Jie " -0x6e5e: "Cheng " -0x6e5f: "Huang " -0x6e60: "Tan " -0x6e61: "Yu " -0x6e62: "Bi " -0x6e63: "Min " -0x6e64: "Shi " -0x6e65: "Tu " -0x6e66: "Sheng " -0x6e67: "Yong " -0x6e68: "Qu " -0x6e69: "Zhong " -0x6e6a: "Suei " -0x6e6b: "Jiu " -0x6e6c: "Jiao " -0x6e6d: "Qiou " -0x6e6e: "Yin " -0x6e6f: "Tang " -0x6e70: "Long " -0x6e71: "Huo " -0x6e72: "Yuan " -0x6e73: "Nan " -0x6e74: "Ban " -0x6e75: "You " -0x6e76: "Quan " -0x6e77: "Chui " -0x6e78: "Liang " -0x6e79: "Chan " -0x6e7a: "Yan " -0x6e7b: "Chun " -0x6e7c: "Nie " -0x6e7d: "Zi " -0x6e7e: "Wan " -0x6e7f: "Shi " -0x6e80: "Man " -0x6e81: "Ying " -0x6e82: "Ratsu " -0x6e83: "Kui " -0x6e84: "[?] " -0x6e85: "Jian " -0x6e86: "Xu " -0x6e87: "Lu " -0x6e88: "Gui " -0x6e89: "Gai " -0x6e8a: "[?] " -0x6e8b: "[?] " -0x6e8c: "Po " -0x6e8d: "Jin " -0x6e8e: "Gui " -0x6e8f: "Tang " -0x6e90: "Yuan " -0x6e91: "Suo " -0x6e92: "Yuan " -0x6e93: "Lian " -0x6e94: "Yao " -0x6e95: "Meng " -0x6e96: "Zhun " -0x6e97: "Sheng " -0x6e98: "Ke " -0x6e99: "Tai " -0x6e9a: "Da " -0x6e9b: "Wa " -0x6e9c: "Liu " -0x6e9d: "Gou " -0x6e9e: "Sao " -0x6e9f: "Ming " -0x6ea0: "Zha " -0x6ea1: "Shi " -0x6ea2: "Yi " -0x6ea3: "Lun " -0x6ea4: "Ma " -0x6ea5: "Pu " -0x6ea6: "Wei " -0x6ea7: "Li " -0x6ea8: "Cai " -0x6ea9: "Wu " -0x6eaa: "Xi " -0x6eab: "Wen " -0x6eac: "Qiang " -0x6ead: "Ze " -0x6eae: "Shi " -0x6eaf: "Su " -0x6eb0: "Yi " -0x6eb1: "Zhen " -0x6eb2: "Sou " -0x6eb3: "Yun " -0x6eb4: "Xiu " -0x6eb5: "Yin " -0x6eb6: "Rong " -0x6eb7: "Hun " -0x6eb8: "Su " -0x6eb9: "Su " -0x6eba: "Ni " -0x6ebb: "Ta " -0x6ebc: "Shi " -0x6ebd: "Ru " -0x6ebe: "Wei " -0x6ebf: "Pan " -0x6ec0: "Chu " -0x6ec1: "Chu " -0x6ec2: "Pang " -0x6ec3: "Weng " -0x6ec4: "Cang " -0x6ec5: "Mie " -0x6ec6: "He " -0x6ec7: "Dian " -0x6ec8: "Hao " -0x6ec9: "Huang " -0x6eca: "Xi " -0x6ecb: "Zi " -0x6ecc: "Di " -0x6ecd: "Zhi " -0x6ece: "Ying " -0x6ecf: "Fu " -0x6ed0: "Jie " -0x6ed1: "Hua " -0x6ed2: "Ge " -0x6ed3: "Zi " -0x6ed4: "Tao " -0x6ed5: "Teng " -0x6ed6: "Sui " -0x6ed7: "Bi " -0x6ed8: "Jiao " -0x6ed9: "Hui " -0x6eda: "Gun " -0x6edb: "Yin " -0x6edc: "Gao " -0x6edd: "Long " -0x6ede: "Zhi " -0x6edf: "Yan " -0x6ee0: "She " -0x6ee1: "Man " -0x6ee2: "Ying " -0x6ee3: "Chun " -0x6ee4: "Lu " -0x6ee5: "Lan " -0x6ee6: "Luan " -0x6ee7: "[?] " -0x6ee8: "Bin " -0x6ee9: "Tan " -0x6eea: "Yu " -0x6eeb: "Sou " -0x6eec: "Hu " -0x6eed: "Bi " -0x6eee: "Biao " -0x6eef: "Zhi " -0x6ef0: "Jiang " -0x6ef1: "Kou " -0x6ef2: "Shen " -0x6ef3: "Shang " -0x6ef4: "Di " -0x6ef5: "Mi " -0x6ef6: "Ao " -0x6ef7: "Lu " -0x6ef8: "Hu " -0x6ef9: "Hu " -0x6efa: "You " -0x6efb: "Chan " -0x6efc: "Fan " -0x6efd: "Yong " -0x6efe: "Gun " -0x6eff: "Man " -/* x06f */ -0x6f00: "Qing " -0x6f01: "Yu " -0x6f02: "Piao " -0x6f03: "Ji " -0x6f04: "Ya " -0x6f05: "Jiao " -0x6f06: "Qi " -0x6f07: "Xi " -0x6f08: "Ji " -0x6f09: "Lu " -0x6f0a: "Lu " -0x6f0b: "Long " -0x6f0c: "Jin " -0x6f0d: "Guo " -0x6f0e: "Cong " -0x6f0f: "Lou " -0x6f10: "Zhi " -0x6f11: "Gai " -0x6f12: "Qiang " -0x6f13: "Li " -0x6f14: "Yan " -0x6f15: "Cao " -0x6f16: "Jiao " -0x6f17: "Cong " -0x6f18: "Qun " -0x6f19: "Tuan " -0x6f1a: "Ou " -0x6f1b: "Teng " -0x6f1c: "Ye " -0x6f1d: "Xi " -0x6f1e: "Mi " -0x6f1f: "Tang " -0x6f20: "Mo " -0x6f21: "Shang " -0x6f22: "Han " -0x6f23: "Lian " -0x6f24: "Lan " -0x6f25: "Wa " -0x6f26: "Li " -0x6f27: "Qian " -0x6f28: "Feng " -0x6f29: "Xuan " -0x6f2a: "Yi " -0x6f2b: "Man " -0x6f2c: "Zi " -0x6f2d: "Mang " -0x6f2e: "Kang " -0x6f2f: "Lei " -0x6f30: "Peng " -0x6f31: "Shu " -0x6f32: "Zhang " -0x6f33: "Zhang " -0x6f34: "Chong " -0x6f35: "Xu " -0x6f36: "Huan " -0x6f37: "Kuo " -0x6f38: "Jian " -0x6f39: "Yan " -0x6f3a: "Chuang " -0x6f3b: "Liao " -0x6f3c: "Cui " -0x6f3d: "Ti " -0x6f3e: "Yang " -0x6f3f: "Jiang " -0x6f40: "Cong " -0x6f41: "Ying " -0x6f42: "Hong " -0x6f43: "Xun " -0x6f44: "Shu " -0x6f45: "Guan " -0x6f46: "Ying " -0x6f47: "Xiao " -0x6f48: "[?] " -0x6f49: "[?] " -0x6f4a: "Xu " -0x6f4b: "Lian " -0x6f4c: "Zhi " -0x6f4d: "Wei " -0x6f4e: "Pi " -0x6f4f: "Jue " -0x6f50: "Jiao " -0x6f51: "Po " -0x6f52: "Dang " -0x6f53: "Hui " -0x6f54: "Jie " -0x6f55: "Wu " -0x6f56: "Pa " -0x6f57: "Ji " -0x6f58: "Pan " -0x6f59: "Gui " -0x6f5a: "Xiao " -0x6f5b: "Qian " -0x6f5c: "Qian " -0x6f5d: "Xi " -0x6f5e: "Lu " -0x6f5f: "Xi " -0x6f60: "Xuan " -0x6f61: "Dun " -0x6f62: "Huang " -0x6f63: "Min " -0x6f64: "Run " -0x6f65: "Su " -0x6f66: "Liao " -0x6f67: "Zhen " -0x6f68: "Zhong " -0x6f69: "Yi " -0x6f6a: "Di " -0x6f6b: "Wan " -0x6f6c: "Dan " -0x6f6d: "Tan " -0x6f6e: "Chao " -0x6f6f: "Xun " -0x6f70: "Kui " -0x6f71: "Yie " -0x6f72: "Shao " -0x6f73: "Tu " -0x6f74: "Zhu " -0x6f75: "San " -0x6f76: "Hei " -0x6f77: "Bi " -0x6f78: "Shan " -0x6f79: "Chan " -0x6f7a: "Chan " -0x6f7b: "Shu " -0x6f7c: "Tong " -0x6f7d: "Pu " -0x6f7e: "Lin " -0x6f7f: "Wei " -0x6f80: "Se " -0x6f81: "Se " -0x6f82: "Cheng " -0x6f83: "Jiong " -0x6f84: "Cheng " -0x6f85: "Hua " -0x6f86: "Jiao " -0x6f87: "Lao " -0x6f88: "Che " -0x6f89: "Gan " -0x6f8a: "Cun " -0x6f8b: "Heng " -0x6f8c: "Si " -0x6f8d: "Shu " -0x6f8e: "Peng " -0x6f8f: "Han " -0x6f90: "Yun " -0x6f91: "Liu " -0x6f92: "Hong " -0x6f93: "Fu " -0x6f94: "Hao " -0x6f95: "He " -0x6f96: "Xian " -0x6f97: "Jian " -0x6f98: "Shan " -0x6f99: "Xi " -0x6f9a: "Oki " -0x6f9b: "[?] " -0x6f9c: "Lan " -0x6f9d: "[?] " -0x6f9e: "Yu " -0x6f9f: "Lin " -0x6fa0: "Min " -0x6fa1: "Zao " -0x6fa2: "Dang " -0x6fa3: "Wan " -0x6fa4: "Ze " -0x6fa5: "Xie " -0x6fa6: "Yu " -0x6fa7: "Li " -0x6fa8: "Shi " -0x6fa9: "Xue " -0x6faa: "Ling " -0x6fab: "Man " -0x6fac: "Zi " -0x6fad: "Yong " -0x6fae: "Kuai " -0x6faf: "Can " -0x6fb0: "Lian " -0x6fb1: "Dian " -0x6fb2: "Ye " -0x6fb3: "Ao " -0x6fb4: "Huan " -0x6fb5: "Zhen " -0x6fb6: "Chan " -0x6fb7: "Man " -0x6fb8: "Dan " -0x6fb9: "Dan " -0x6fba: "Yi " -0x6fbb: "Sui " -0x6fbc: "Pi " -0x6fbd: "Ju " -0x6fbe: "Ta " -0x6fbf: "Qin " -0x6fc0: "Ji " -0x6fc1: "Zhuo " -0x6fc2: "Lian " -0x6fc3: "Nong " -0x6fc4: "Guo " -0x6fc5: "Jin " -0x6fc6: "Fen " -0x6fc7: "Se " -0x6fc8: "Ji " -0x6fc9: "Sui " -0x6fca: "Hui " -0x6fcb: "Chu " -0x6fcc: "Ta " -0x6fcd: "Song " -0x6fce: "Ding " -0x6fcf: "[?] " -0x6fd0: "Zhu " -0x6fd1: "Lai " -0x6fd2: "Bin " -0x6fd3: "Lian " -0x6fd4: "Mi " -0x6fd5: "Shi " -0x6fd6: "Shu " -0x6fd7: "Mi " -0x6fd8: "Ning " -0x6fd9: "Ying " -0x6fda: "Ying " -0x6fdb: "Meng " -0x6fdc: "Jin " -0x6fdd: "Qi " -0x6fde: "Pi " -0x6fdf: "Ji " -0x6fe0: "Hao " -0x6fe1: "Ru " -0x6fe2: "Zui " -0x6fe3: "Wo " -0x6fe4: "Tao " -0x6fe5: "Yin " -0x6fe6: "Yin " -0x6fe7: "Dui " -0x6fe8: "Ci " -0x6fe9: "Huo " -0x6fea: "Jing " -0x6feb: "Lan " -0x6fec: "Jun " -0x6fed: "Ai " -0x6fee: "Pu " -0x6fef: "Zhuo " -0x6ff0: "Wei " -0x6ff1: "Bin " -0x6ff2: "Gu " -0x6ff3: "Qian " -0x6ff4: "Xing " -0x6ff5: "Hama " -0x6ff6: "Kuo " -0x6ff7: "Fei " -0x6ff8: "[?] " -0x6ff9: "Boku " -0x6ffa: "Jian " -0x6ffb: "Wei " -0x6ffc: "Luo " -0x6ffd: "Zan " -0x6ffe: "Lu " -0x6fff: "Li " -/* x070 */ -0x7000: "You " -0x7001: "Yang " -0x7002: "Lu " -0x7003: "Si " -0x7004: "Jie " -0x7005: "Ying " -0x7006: "Du " -0x7007: "Wang " -0x7008: "Hui " -0x7009: "Xie " -0x700a: "Pan " -0x700b: "Shen " -0x700c: "Biao " -0x700d: "Chan " -0x700e: "Mo " -0x700f: "Liu " -0x7010: "Jian " -0x7011: "Pu " -0x7012: "Se " -0x7013: "Cheng " -0x7014: "Gu " -0x7015: "Bin " -0x7016: "Huo " -0x7017: "Xian " -0x7018: "Lu " -0x7019: "Qin " -0x701a: "Han " -0x701b: "Ying " -0x701c: "Yong " -0x701d: "Li " -0x701e: "Jing " -0x701f: "Xiao " -0x7020: "Ying " -0x7021: "Sui " -0x7022: "Wei " -0x7023: "Xie " -0x7024: "Huai " -0x7025: "Hao " -0x7026: "Zhu " -0x7027: "Long " -0x7028: "Lai " -0x7029: "Dui " -0x702a: "Fan " -0x702b: "Hu " -0x702c: "Lai " -0x702d: "[?] " -0x702e: "[?] " -0x702f: "Ying " -0x7030: "Mi " -0x7031: "Ji " -0x7032: "Lian " -0x7033: "Jian " -0x7034: "Ying " -0x7035: "Fen " -0x7036: "Lin " -0x7037: "Yi " -0x7038: "Jian " -0x7039: "Yue " -0x703a: "Chan " -0x703b: "Dai " -0x703c: "Rang " -0x703d: "Jian " -0x703e: "Lan " -0x703f: "Fan " -0x7040: "Shuang " -0x7041: "Yuan " -0x7042: "Zhuo " -0x7043: "Feng " -0x7044: "She " -0x7045: "Lei " -0x7046: "Lan " -0x7047: "Cong " -0x7048: "Qu " -0x7049: "Yong " -0x704a: "Qian " -0x704b: "Fa " -0x704c: "Guan " -0x704d: "Que " -0x704e: "Yan " -0x704f: "Hao " -0x7050: "Hyeng " -0x7051: "Sa " -0x7052: "Zan " -0x7053: "Luan " -0x7054: "Yan " -0x7055: "Li " -0x7056: "Mi " -0x7057: "Shan " -0x7058: "Tan " -0x7059: "Dang " -0x705a: "Jiao " -0x705b: "Chan " -0x705c: "[?] " -0x705d: "Hao " -0x705e: "Ba " -0x705f: "Zhu " -0x7060: "Lan " -0x7061: "Lan " -0x7062: "Nang " -0x7063: "Wan " -0x7064: "Luan " -0x7065: "Xun " -0x7066: "Xian " -0x7067: "Yan " -0x7068: "Gan " -0x7069: "Yan " -0x706a: "Yu " -0x706b: "Huo " -0x706c: "Si " -0x706d: "Mie " -0x706e: "Guang " -0x706f: "Deng " -0x7070: "Hui " -0x7071: "Xiao " -0x7072: "Xiao " -0x7073: "Hu " -0x7074: "Hong " -0x7075: "Ling " -0x7076: "Zao " -0x7077: "Zhuan " -0x7078: "Jiu " -0x7079: "Zha " -0x707a: "Xie " -0x707b: "Chi " -0x707c: "Zhuo " -0x707d: "Zai " -0x707e: "Zai " -0x707f: "Can " -0x7080: "Yang " -0x7081: "Qi " -0x7082: "Zhong " -0x7083: "Fen " -0x7084: "Niu " -0x7085: "Jiong " -0x7086: "Wen " -0x7087: "Po " -0x7088: "Yi " -0x7089: "Lu " -0x708a: "Chui " -0x708b: "Pi " -0x708c: "Kai " -0x708d: "Pan " -0x708e: "Yan " -0x708f: "Kai " -0x7090: "Pang " -0x7091: "Mu " -0x7092: "Chao " -0x7093: "Liao " -0x7094: "Gui " -0x7095: "Kang " -0x7096: "Tun " -0x7097: "Guang " -0x7098: "Xin " -0x7099: "Zhi " -0x709a: "Guang " -0x709b: "Guang " -0x709c: "Wei " -0x709d: "Qiang " -0x709e: "[?] " -0x709f: "Da " -0x70a0: "Xia " -0x70a1: "Zheng " -0x70a2: "Zhu " -0x70a3: "Ke " -0x70a4: "Zhao " -0x70a5: "Fu " -0x70a6: "Ba " -0x70a7: "Duo " -0x70a8: "Duo " -0x70a9: "Ling " -0x70aa: "Zhuo " -0x70ab: "Xuan " -0x70ac: "Ju " -0x70ad: "Tan " -0x70ae: "Pao " -0x70af: "Jiong " -0x70b0: "Pao " -0x70b1: "Tai " -0x70b2: "Tai " -0x70b3: "Bing " -0x70b4: "Yang " -0x70b5: "Tong " -0x70b6: "Han " -0x70b7: "Zhu " -0x70b8: "Zha " -0x70b9: "Dian " -0x70ba: "Wei " -0x70bb: "Shi " -0x70bc: "Lian " -0x70bd: "Chi " -0x70be: "Huang " -0x70bf: "[?] " -0x70c0: "Hu " -0x70c1: "Shuo " -0x70c2: "Lan " -0x70c3: "Jing " -0x70c4: "Jiao " -0x70c5: "Xu " -0x70c6: "Xing " -0x70c7: "Quan " -0x70c8: "Lie " -0x70c9: "Huan " -0x70ca: "Yang " -0x70cb: "Xiao " -0x70cc: "Xiu " -0x70cd: "Xian " -0x70ce: "Yin " -0x70cf: "Wu " -0x70d0: "Zhou " -0x70d1: "Yao " -0x70d2: "Shi " -0x70d3: "Wei " -0x70d4: "Tong " -0x70d5: "Xue " -0x70d6: "Zai " -0x70d7: "Kai " -0x70d8: "Hong " -0x70d9: "Luo " -0x70da: "Xia " -0x70db: "Zhu " -0x70dc: "Xuan " -0x70dd: "Zheng " -0x70de: "Po " -0x70df: "Yan " -0x70e0: "Hui " -0x70e1: "Guang " -0x70e2: "Zhe " -0x70e3: "Hui " -0x70e4: "Kao " -0x70e5: "[?] " -0x70e6: "Fan " -0x70e7: "Shao " -0x70e8: "Ye " -0x70e9: "Hui " -0x70ea: "[?] " -0x70eb: "Tang " -0x70ec: "Jin " -0x70ed: "Re " -0x70ee: "[?] " -0x70ef: "Xi " -0x70f0: "Fu " -0x70f1: "Jiong " -0x70f2: "Che " -0x70f3: "Pu " -0x70f4: "Jing " -0x70f5: "Zhuo " -0x70f6: "Ting " -0x70f7: "Wan " -0x70f8: "Hai " -0x70f9: "Peng " -0x70fa: "Lang " -0x70fb: "Shan " -0x70fc: "Hu " -0x70fd: "Feng " -0x70fe: "Chi " -0x70ff: "Rong " -/* x071 */ -0x7100: "Hu " -0x7101: "Xi " -0x7102: "Shu " -0x7103: "He " -0x7104: "Xun " -0x7105: "Ku " -0x7106: "Jue " -0x7107: "Xiao " -0x7108: "Xi " -0x7109: "Yan " -0x710a: "Han " -0x710b: "Zhuang " -0x710c: "Jun " -0x710d: "Di " -0x710e: "Xie " -0x710f: "Ji " -0x7110: "Wu " -0x7111: "[?] " -0x7112: "[?] " -0x7113: "Han " -0x7114: "Yan " -0x7115: "Huan " -0x7116: "Men " -0x7117: "Ju " -0x7118: "Chou " -0x7119: "Bei " -0x711a: "Fen " -0x711b: "Lin " -0x711c: "Kun " -0x711d: "Hun " -0x711e: "Tun " -0x711f: "Xi " -0x7120: "Cui " -0x7121: "Wu " -0x7122: "Hong " -0x7123: "Ju " -0x7124: "Fu " -0x7125: "Wo " -0x7126: "Jiao " -0x7127: "Cong " -0x7128: "Feng " -0x7129: "Ping " -0x712a: "Qiong " -0x712b: "Ruo " -0x712c: "Xi " -0x712d: "Qiong " -0x712e: "Xin " -0x712f: "Zhuo " -0x7130: "Yan " -0x7131: "Yan " -0x7132: "Yi " -0x7133: "Jue " -0x7134: "Yu " -0x7135: "Gang " -0x7136: "Ran " -0x7137: "Pi " -0x7138: "Gu " -0x7139: "[?] " -0x713a: "Sheng " -0x713b: "Chang " -0x713c: "Shao " -0x713d: "[?] " -0x713e: "[?] " -0x713f: "[?] " -0x7140: "[?] " -0x7141: "Chen " -0x7142: "He " -0x7143: "Kui " -0x7144: "Zhong " -0x7145: "Duan " -0x7146: "Xia " -0x7147: "Hui " -0x7148: "Feng " -0x7149: "Lian " -0x714a: "Xuan " -0x714b: "Xing " -0x714c: "Huang " -0x714d: "Jiao " -0x714e: "Jian " -0x714f: "Bi " -0x7150: "Ying " -0x7151: "Zhu " -0x7152: "Wei " -0x7153: "Tuan " -0x7154: "Tian " -0x7155: "Xi " -0x7156: "Nuan " -0x7157: "Nuan " -0x7158: "Chan " -0x7159: "Yan " -0x715a: "Jiong " -0x715b: "Jiong " -0x715c: "Yu " -0x715d: "Mei " -0x715e: "Sha " -0x715f: "Wei " -0x7160: "Ye " -0x7161: "Xin " -0x7162: "Qiong " -0x7163: "Rou " -0x7164: "Mei " -0x7165: "Huan " -0x7166: "Xu " -0x7167: "Zhao " -0x7168: "Wei " -0x7169: "Fan " -0x716a: "Qiu " -0x716b: "Sui " -0x716c: "Yang " -0x716d: "Lie " -0x716e: "Zhu " -0x716f: "Jie " -0x7170: "Gao " -0x7171: "Gua " -0x7172: "Bao " -0x7173: "Hu " -0x7174: "Yun " -0x7175: "Xia " -0x7176: "[?] " -0x7177: "[?] " -0x7178: "Bian " -0x7179: "Gou " -0x717a: "Tui " -0x717b: "Tang " -0x717c: "Chao " -0x717d: "Shan " -0x717e: "N " -0x717f: "Bo " -0x7180: "Huang " -0x7181: "Xie " -0x7182: "Xi " -0x7183: "Wu " -0x7184: "Xi " -0x7185: "Yun " -0x7186: "He " -0x7187: "He " -0x7188: "Xi " -0x7189: "Yun " -0x718a: "Xiong " -0x718b: "Nai " -0x718c: "Shan " -0x718d: "Qiong " -0x718e: "Yao " -0x718f: "Xun " -0x7190: "Mi " -0x7191: "Lian " -0x7192: "Ying " -0x7193: "Wen " -0x7194: "Rong " -0x7195: "Oozutsu " -0x7196: "[?] " -0x7197: "Qiang " -0x7198: "Liu " -0x7199: "Xi " -0x719a: "Bi " -0x719b: "Biao " -0x719c: "Zong " -0x719d: "Lu " -0x719e: "Jian " -0x719f: "Shou " -0x71a0: "Yi " -0x71a1: "Lou " -0x71a2: "Feng " -0x71a3: "Sui " -0x71a4: "Yi " -0x71a5: "Tong " -0x71a6: "Jue " -0x71a7: "Zong " -0x71a8: "Yun " -0x71a9: "Hu " -0x71aa: "Yi " -0x71ab: "Zhi " -0x71ac: "Ao " -0x71ad: "Wei " -0x71ae: "Liao " -0x71af: "Han " -0x71b0: "Ou " -0x71b1: "Re " -0x71b2: "Jiong " -0x71b3: "Man " -0x71b4: "[?] " -0x71b5: "Shang " -0x71b6: "Cuan " -0x71b7: "Zeng " -0x71b8: "Jian " -0x71b9: "Xi " -0x71ba: "Xi " -0x71bb: "Xi " -0x71bc: "Yi " -0x71bd: "Xiao " -0x71be: "Chi " -0x71bf: "Huang " -0x71c0: "Chan " -0x71c1: "Ye " -0x71c2: "Qian " -0x71c3: "Ran " -0x71c4: "Yan " -0x71c5: "Xian " -0x71c6: "Qiao " -0x71c7: "Zun " -0x71c8: "Deng " -0x71c9: "Dun " -0x71ca: "Shen " -0x71cb: "Jiao " -0x71cc: "Fen " -0x71cd: "Si " -0x71ce: "Liao " -0x71cf: "Yu " -0x71d0: "Lin " -0x71d1: "Tong " -0x71d2: "Shao " -0x71d3: "Fen " -0x71d4: "Fan " -0x71d5: "Yan " -0x71d6: "Xun " -0x71d7: "Lan " -0x71d8: "Mei " -0x71d9: "Tang " -0x71da: "Yi " -0x71db: "Jing " -0x71dc: "Men " -0x71dd: "[?] " -0x71de: "[?] " -0x71df: "Ying " -0x71e0: "Yu " -0x71e1: "Yi " -0x71e2: "Xue " -0x71e3: "Lan " -0x71e4: "Tai " -0x71e5: "Zao " -0x71e6: "Can " -0x71e7: "Sui " -0x71e8: "Xi " -0x71e9: "Que " -0x71ea: "Cong " -0x71eb: "Lian " -0x71ec: "Hui " -0x71ed: "Zhu " -0x71ee: "Xie " -0x71ef: "Ling " -0x71f0: "Wei " -0x71f1: "Yi " -0x71f2: "Xie " -0x71f3: "Zhao " -0x71f4: "Hui " -0x71f5: "Tatsu " -0x71f6: "Nung " -0x71f7: "Lan " -0x71f8: "Ru " -0x71f9: "Xian " -0x71fa: "Kao " -0x71fb: "Xun " -0x71fc: "Jin " -0x71fd: "Chou " -0x71fe: "Chou " -0x71ff: "Yao " -/* x072 */ -0x7200: "He " -0x7201: "Lan " -0x7202: "Biao " -0x7203: "Rong " -0x7204: "Li " -0x7205: "Mo " -0x7206: "Bao " -0x7207: "Ruo " -0x7208: "Lu " -0x7209: "La " -0x720a: "Ao " -0x720b: "Xun " -0x720c: "Kuang " -0x720d: "Shuo " -0x720e: "[?] " -0x720f: "Li " -0x7210: "Lu " -0x7211: "Jue " -0x7212: "Liao " -0x7213: "Yan " -0x7214: "Xi " -0x7215: "Xie " -0x7216: "Long " -0x7217: "Ye " -0x7218: "[?] " -0x7219: "Rang " -0x721a: "Yue " -0x721b: "Lan " -0x721c: "Cong " -0x721d: "Jue " -0x721e: "Tong " -0x721f: "Guan " -0x7220: "[?] " -0x7221: "Che " -0x7222: "Mi " -0x7223: "Tang " -0x7224: "Lan " -0x7225: "Zhu " -0x7226: "[?] " -0x7227: "Ling " -0x7228: "Cuan " -0x7229: "Yu " -0x722a: "Zhua " -0x722b: "Tsumekanmuri " -0x722c: "Pa " -0x722d: "Zheng " -0x722e: "Pao " -0x722f: "Cheng " -0x7230: "Yuan " -0x7231: "Ai " -0x7232: "Wei " -0x7233: "[?] " -0x7234: "Jue " -0x7235: "Jue " -0x7236: "Fu " -0x7237: "Ye " -0x7238: "Ba " -0x7239: "Die " -0x723a: "Ye " -0x723b: "Yao " -0x723c: "Zu " -0x723d: "Shuang " -0x723e: "Er " -0x723f: "Qiang " -0x7240: "Chuang " -0x7241: "Ge " -0x7242: "Zang " -0x7243: "Die " -0x7244: "Qiang " -0x7245: "Yong " -0x7246: "Qiang " -0x7247: "Pian " -0x7248: "Ban " -0x7249: "Pan " -0x724a: "Shao " -0x724b: "Jian " -0x724c: "Pai " -0x724d: "Du " -0x724e: "Chuang " -0x724f: "Tou " -0x7250: "Zha " -0x7251: "Bian " -0x7252: "Die " -0x7253: "Bang " -0x7254: "Bo " -0x7255: "Chuang " -0x7256: "You " -0x7257: "[?] " -0x7258: "Du " -0x7259: "Ya " -0x725a: "Cheng " -0x725b: "Niu " -0x725c: "Ushihen " -0x725d: "Pin " -0x725e: "Jiu " -0x725f: "Mou " -0x7260: "Tuo " -0x7261: "Mu " -0x7262: "Lao " -0x7263: "Ren " -0x7264: "Mang " -0x7265: "Fang " -0x7266: "Mao " -0x7267: "Mu " -0x7268: "Gang " -0x7269: "Wu " -0x726a: "Yan " -0x726b: "Ge " -0x726c: "Bei " -0x726d: "Si " -0x726e: "Jian " -0x726f: "Gu " -0x7270: "You " -0x7271: "Ge " -0x7272: "Sheng " -0x7273: "Mu " -0x7274: "Di " -0x7275: "Qian " -0x7276: "Quan " -0x7277: "Quan " -0x7278: "Zi " -0x7279: "Te " -0x727a: "Xi " -0x727b: "Mang " -0x727c: "Keng " -0x727d: "Qian " -0x727e: "Wu " -0x727f: "Gu " -0x7280: "Xi " -0x7281: "Li " -0x7282: "Li " -0x7283: "Pou " -0x7284: "Ji " -0x7285: "Gang " -0x7286: "Zhi " -0x7287: "Ben " -0x7288: "Quan " -0x7289: "Run " -0x728a: "Du " -0x728b: "Ju " -0x728c: "Jia " -0x728d: "Jian " -0x728e: "Feng " -0x728f: "Pian " -0x7290: "Ke " -0x7291: "Ju " -0x7292: "Kao " -0x7293: "Chu " -0x7294: "Xi " -0x7295: "Bei " -0x7296: "Luo " -0x7297: "Jie " -0x7298: "Ma " -0x7299: "San " -0x729a: "Wei " -0x729b: "Li " -0x729c: "Dun " -0x729d: "Tong " -0x729e: "[?] " -0x729f: "Jiang " -0x72a0: "Ikenie " -0x72a1: "Li " -0x72a2: "Du " -0x72a3: "Lie " -0x72a4: "Pi " -0x72a5: "Piao " -0x72a6: "Bao " -0x72a7: "Xi " -0x72a8: "Chou " -0x72a9: "Wei " -0x72aa: "Kui " -0x72ab: "Chou " -0x72ac: "Quan " -0x72ad: "Fan " -0x72ae: "Ba " -0x72af: "Fan " -0x72b0: "Qiu " -0x72b1: "Ji " -0x72b2: "Cai " -0x72b3: "Chuo " -0x72b4: "An " -0x72b5: "Jie " -0x72b6: "Zhuang " -0x72b7: "Guang " -0x72b8: "Ma " -0x72b9: "You " -0x72ba: "Kang " -0x72bb: "Bo " -0x72bc: "Hou " -0x72bd: "Ya " -0x72be: "Yin " -0x72bf: "Huan " -0x72c0: "Zhuang " -0x72c1: "Yun " -0x72c2: "Kuang " -0x72c3: "Niu " -0x72c4: "Di " -0x72c5: "Qing " -0x72c6: "Zhong " -0x72c7: "Mu " -0x72c8: "Bei " -0x72c9: "Pi " -0x72ca: "Ju " -0x72cb: "Ni " -0x72cc: "Sheng " -0x72cd: "Pao " -0x72ce: "Xia " -0x72cf: "Tuo " -0x72d0: "Hu " -0x72d1: "Ling " -0x72d2: "Fei " -0x72d3: "Pi " -0x72d4: "Ni " -0x72d5: "Ao " -0x72d6: "You " -0x72d7: "Gou " -0x72d8: "Yue " -0x72d9: "Ju " -0x72da: "Dan " -0x72db: "Po " -0x72dc: "Gu " -0x72dd: "Xian " -0x72de: "Ning " -0x72df: "Huan " -0x72e0: "Hen " -0x72e1: "Jiao " -0x72e2: "He " -0x72e3: "Zhao " -0x72e4: "Ji " -0x72e5: "Xun " -0x72e6: "Shan " -0x72e7: "Ta " -0x72e8: "Rong " -0x72e9: "Shou " -0x72ea: "Tong " -0x72eb: "Lao " -0x72ec: "Du " -0x72ed: "Xia " -0x72ee: "Shi " -0x72ef: "Hua " -0x72f0: "Zheng " -0x72f1: "Yu " -0x72f2: "Sun " -0x72f3: "Yu " -0x72f4: "Bi " -0x72f5: "Mang " -0x72f6: "Xi " -0x72f7: "Juan " -0x72f8: "Li " -0x72f9: "Xia " -0x72fa: "Yin " -0x72fb: "Suan " -0x72fc: "Lang " -0x72fd: "Bei " -0x72fe: "Zhi " -0x72ff: "Yan " -/* x073 */ -0x7300: "Sha " -0x7301: "Li " -0x7302: "Han " -0x7303: "Xian " -0x7304: "Jing " -0x7305: "Pai " -0x7306: "Fei " -0x7307: "Yao " -0x7308: "Ba " -0x7309: "Qi " -0x730a: "Ni " -0x730b: "Biao " -0x730c: "Yin " -0x730d: "Lai " -0x730e: "Xi " -0x730f: "Jian " -0x7310: "Qiang " -0x7311: "Kun " -0x7312: "Yan " -0x7313: "Guo " -0x7314: "Zong " -0x7315: "Mi " -0x7316: "Chang " -0x7317: "Yi " -0x7318: "Zhi " -0x7319: "Zheng " -0x731a: "Ya " -0x731b: "Meng " -0x731c: "Cai " -0x731d: "Cu " -0x731e: "She " -0x731f: "Kari " -0x7320: "Cen " -0x7321: "Luo " -0x7322: "Hu " -0x7323: "Zong " -0x7324: "Ji " -0x7325: "Wei " -0x7326: "Feng " -0x7327: "Wo " -0x7328: "Yuan " -0x7329: "Xing " -0x732a: "Zhu " -0x732b: "Mao " -0x732c: "Wei " -0x732d: "Yuan " -0x732e: "Xian " -0x732f: "Tuan " -0x7330: "Ya " -0x7331: "Nao " -0x7332: "Xie " -0x7333: "Jia " -0x7334: "Hou " -0x7335: "Bian " -0x7336: "You " -0x7337: "You " -0x7338: "Mei " -0x7339: "Zha " -0x733a: "Yao " -0x733b: "Sun " -0x733c: "Bo " -0x733d: "Ming " -0x733e: "Hua " -0x733f: "Yuan " -0x7340: "Sou " -0x7341: "Ma " -0x7342: "Yuan " -0x7343: "Dai " -0x7344: "Yu " -0x7345: "Shi " -0x7346: "Hao " -0x7347: "[?] " -0x7348: "Yi " -0x7349: "Zhen " -0x734a: "Chuang " -0x734b: "Hao " -0x734c: "Man " -0x734d: "Jing " -0x734e: "Jiang " -0x734f: "Mu " -0x7350: "Zhang " -0x7351: "Chan " -0x7352: "Ao " -0x7353: "Ao " -0x7354: "Hao " -0x7355: "Cui " -0x7356: "Fen " -0x7357: "Jue " -0x7358: "Bi " -0x7359: "Bi " -0x735a: "Huang " -0x735b: "Pu " -0x735c: "Lin " -0x735d: "Yu " -0x735e: "Tong " -0x735f: "Yao " -0x7360: "Liao " -0x7361: "Shuo " -0x7362: "Xiao " -0x7363: "Swu " -0x7364: "Ton " -0x7365: "Xi " -0x7366: "Ge " -0x7367: "Juan " -0x7368: "Du " -0x7369: "Hui " -0x736a: "Kuai " -0x736b: "Xian " -0x736c: "Xie " -0x736d: "Ta " -0x736e: "Xian " -0x736f: "Xun " -0x7370: "Ning " -0x7371: "Pin " -0x7372: "Huo " -0x7373: "Nou " -0x7374: "Meng " -0x7375: "Lie " -0x7376: "Nao " -0x7377: "Guang " -0x7378: "Shou " -0x7379: "Lu " -0x737a: "Ta " -0x737b: "Xian " -0x737c: "Mi " -0x737d: "Rang " -0x737e: "Huan " -0x737f: "Nao " -0x7380: "Luo " -0x7381: "Xian " -0x7382: "Qi " -0x7383: "Jue " -0x7384: "Xuan " -0x7385: "Miao " -0x7386: "Zi " -0x7387: "Lu " -0x7388: "Lu " -0x7389: "Yu " -0x738a: "Su " -0x738b: "Wang " -0x738c: "Qiu " -0x738d: "Ga " -0x738e: "Ding " -0x738f: "Le " -0x7390: "Ba " -0x7391: "Ji " -0x7392: "Hong " -0x7393: "Di " -0x7394: "Quan " -0x7395: "Gan " -0x7396: "Jiu " -0x7397: "Yu " -0x7398: "Ji " -0x7399: "Yu " -0x739a: "Yang " -0x739b: "Ma " -0x739c: "Gong " -0x739d: "Wu " -0x739e: "Fu " -0x739f: "Wen " -0x73a0: "Jie " -0x73a1: "Ya " -0x73a2: "Fen " -0x73a3: "Bian " -0x73a4: "Beng " -0x73a5: "Yue " -0x73a6: "Jue " -0x73a7: "Yun " -0x73a8: "Jue " -0x73a9: "Wan " -0x73aa: "Jian " -0x73ab: "Mei " -0x73ac: "Dan " -0x73ad: "Pi " -0x73ae: "Wei " -0x73af: "Huan " -0x73b0: "Xian " -0x73b1: "Qiang " -0x73b2: "Ling " -0x73b3: "Dai " -0x73b4: "Yi " -0x73b5: "An " -0x73b6: "Ping " -0x73b7: "Dian " -0x73b8: "Fu " -0x73b9: "Xuan " -0x73ba: "Xi " -0x73bb: "Bo " -0x73bc: "Ci " -0x73bd: "Gou " -0x73be: "Jia " -0x73bf: "Shao " -0x73c0: "Po " -0x73c1: "Ci " -0x73c2: "Ke " -0x73c3: "Ran " -0x73c4: "Sheng " -0x73c5: "Shen " -0x73c6: "Yi " -0x73c7: "Zu " -0x73c8: "Jia " -0x73c9: "Min " -0x73ca: "Shan " -0x73cb: "Liu " -0x73cc: "Bi " -0x73cd: "Zhen " -0x73ce: "Zhen " -0x73cf: "Jue " -0x73d0: "Fa " -0x73d1: "Long " -0x73d2: "Jin " -0x73d3: "Jiao " -0x73d4: "Jian " -0x73d5: "Li " -0x73d6: "Guang " -0x73d7: "Xian " -0x73d8: "Zhou " -0x73d9: "Gong " -0x73da: "Yan " -0x73db: "Xiu " -0x73dc: "Yang " -0x73dd: "Xu " -0x73de: "Luo " -0x73df: "Su " -0x73e0: "Zhu " -0x73e1: "Qin " -0x73e2: "Ken " -0x73e3: "Xun " -0x73e4: "Bao " -0x73e5: "Er " -0x73e6: "Xiang " -0x73e7: "Yao " -0x73e8: "Xia " -0x73e9: "Heng " -0x73ea: "Gui " -0x73eb: "Chong " -0x73ec: "Xu " -0x73ed: "Ban " -0x73ee: "Pei " -0x73ef: "[?] " -0x73f0: "Dang " -0x73f1: "Ei " -0x73f2: "Hun " -0x73f3: "Wen " -0x73f4: "E " -0x73f5: "Cheng " -0x73f6: "Ti " -0x73f7: "Wu " -0x73f8: "Wu " -0x73f9: "Cheng " -0x73fa: "Jun " -0x73fb: "Mei " -0x73fc: "Bei " -0x73fd: "Ting " -0x73fe: "Xian " -0x73ff: "Chuo " -/* x074 */ -0x7400: "Han " -0x7401: "Xuan " -0x7402: "Yan " -0x7403: "Qiu " -0x7404: "Quan " -0x7405: "Lang " -0x7406: "Li " -0x7407: "Xiu " -0x7408: "Fu " -0x7409: "Liu " -0x740a: "Ye " -0x740b: "Xi " -0x740c: "Ling " -0x740d: "Li " -0x740e: "Jin " -0x740f: "Lian " -0x7410: "Suo " -0x7411: "Chiisai " -0x7412: "[?] " -0x7413: "Wan " -0x7414: "Dian " -0x7415: "Pin " -0x7416: "Zhan " -0x7417: "Cui " -0x7418: "Min " -0x7419: "Yu " -0x741a: "Ju " -0x741b: "Chen " -0x741c: "Lai " -0x741d: "Wen " -0x741e: "Sheng " -0x741f: "Wei " -0x7420: "Dian " -0x7421: "Chu " -0x7422: "Zhuo " -0x7423: "Pei " -0x7424: "Cheng " -0x7425: "Hu " -0x7426: "Qi " -0x7427: "E " -0x7428: "Kun " -0x7429: "Chang " -0x742a: "Qi " -0x742b: "Beng " -0x742c: "Wan " -0x742d: "Lu " -0x742e: "Cong " -0x742f: "Guan " -0x7430: "Yan " -0x7431: "Diao " -0x7432: "Bei " -0x7433: "Lin " -0x7434: "Qin " -0x7435: "Pi " -0x7436: "Pa " -0x7437: "Que " -0x7438: "Zhuo " -0x7439: "Qin " -0x743a: "Fa " -0x743b: "[?] " -0x743c: "Qiong " -0x743d: "Du " -0x743e: "Jie " -0x743f: "Hun " -0x7440: "Yu " -0x7441: "Mao " -0x7442: "Mei " -0x7443: "Chun " -0x7444: "Xuan " -0x7445: "Ti " -0x7446: "Xing " -0x7447: "Dai " -0x7448: "Rou " -0x7449: "Min " -0x744a: "Zhen " -0x744b: "Wei " -0x744c: "Ruan " -0x744d: "Huan " -0x744e: "Jie " -0x744f: "Chuan " -0x7450: "Jian " -0x7451: "Zhuan " -0x7452: "Yang " -0x7453: "Lian " -0x7454: "Quan " -0x7455: "Xia " -0x7456: "Duan " -0x7457: "Yuan " -0x7458: "Ye " -0x7459: "Nao " -0x745a: "Hu " -0x745b: "Ying " -0x745c: "Yu " -0x745d: "Huang " -0x745e: "Rui " -0x745f: "Se " -0x7460: "Liu " -0x7461: "Shi " -0x7462: "Rong " -0x7463: "Suo " -0x7464: "Yao " -0x7465: "Wen " -0x7466: "Wu " -0x7467: "Jin " -0x7468: "Jin " -0x7469: "Ying " -0x746a: "Ma " -0x746b: "Tao " -0x746c: "Liu " -0x746d: "Tang " -0x746e: "Li " -0x746f: "Lang " -0x7470: "Gui " -0x7471: "Zhen " -0x7472: "Qiang " -0x7473: "Cuo " -0x7474: "Jue " -0x7475: "Zhao " -0x7476: "Yao " -0x7477: "Ai " -0x7478: "Bin " -0x7479: "Tu " -0x747a: "Chang " -0x747b: "Kun " -0x747c: "Zhuan " -0x747d: "Cong " -0x747e: "Jin " -0x747f: "Yi " -0x7480: "Cui " -0x7481: "Cong " -0x7482: "Qi " -0x7483: "Li " -0x7484: "Ying " -0x7485: "Suo " -0x7486: "Qiu " -0x7487: "Xuan " -0x7488: "Ao " -0x7489: "Lian " -0x748a: "Man " -0x748b: "Zhang " -0x748c: "Yin " -0x748d: "[?] " -0x748e: "Ying " -0x748f: "Zhi " -0x7490: "Lu " -0x7491: "Wu " -0x7492: "Deng " -0x7493: "Xiou " -0x7494: "Zeng " -0x7495: "Xun " -0x7496: "Qu " -0x7497: "Dang " -0x7498: "Lin " -0x7499: "Liao " -0x749a: "Qiong " -0x749b: "Su " -0x749c: "Huang " -0x749d: "Gui " -0x749e: "Pu " -0x749f: "Jing " -0x74a0: "Fan " -0x74a1: "Jin " -0x74a2: "Liu " -0x74a3: "Ji " -0x74a4: "[?] " -0x74a5: "Jing " -0x74a6: "Ai " -0x74a7: "Bi " -0x74a8: "Can " -0x74a9: "Qu " -0x74aa: "Zao " -0x74ab: "Dang " -0x74ac: "Jiao " -0x74ad: "Gun " -0x74ae: "Tan " -0x74af: "Hui " -0x74b0: "Huan " -0x74b1: "Se " -0x74b2: "Sui " -0x74b3: "Tian " -0x74b4: "[?] " -0x74b5: "Yu " -0x74b6: "Jin " -0x74b7: "Lu " -0x74b8: "Bin " -0x74b9: "Shou " -0x74ba: "Wen " -0x74bb: "Zui " -0x74bc: "Lan " -0x74bd: "Xi " -0x74be: "Ji " -0x74bf: "Xuan " -0x74c0: "Ruan " -0x74c1: "Huo " -0x74c2: "Gai " -0x74c3: "Lei " -0x74c4: "Du " -0x74c5: "Li " -0x74c6: "Zhi " -0x74c7: "Rou " -0x74c8: "Li " -0x74c9: "Zan " -0x74ca: "Qiong " -0x74cb: "Zhe " -0x74cc: "Gui " -0x74cd: "Sui " -0x74ce: "La " -0x74cf: "Long " -0x74d0: "Lu " -0x74d1: "Li " -0x74d2: "Zan " -0x74d3: "Lan " -0x74d4: "Ying " -0x74d5: "Mi " -0x74d6: "Xiang " -0x74d7: "Xi " -0x74d8: "Guan " -0x74d9: "Dao " -0x74da: "Zan " -0x74db: "Huan " -0x74dc: "Gua " -0x74dd: "Bo " -0x74de: "Die " -0x74df: "Bao " -0x74e0: "Hu " -0x74e1: "Zhi " -0x74e2: "Piao " -0x74e3: "Ban " -0x74e4: "Rang " -0x74e5: "Li " -0x74e6: "Wa " -0x74e7: "Dekaguramu " -0x74e8: "Jiang " -0x74e9: "Qian " -0x74ea: "Fan " -0x74eb: "Pen " -0x74ec: "Fang " -0x74ed: "Dan " -0x74ee: "Weng " -0x74ef: "Ou " -0x74f0: "Deshiguramu " -0x74f1: "Miriguramu " -0x74f2: "Thon " -0x74f3: "Hu " -0x74f4: "Ling " -0x74f5: "Yi " -0x74f6: "Ping " -0x74f7: "Ci " -0x74f8: "Hekutogura " -0x74f9: "Juan " -0x74fa: "Chang " -0x74fb: "Chi " -0x74fc: "Sarake " -0x74fd: "Dang " -0x74fe: "Meng " -0x74ff: "Pou " -/* x075 */ -0x7500: "Zhui " -0x7501: "Ping " -0x7502: "Bian " -0x7503: "Zhou " -0x7504: "Zhen " -0x7505: "Senchigura " -0x7506: "Ci " -0x7507: "Ying " -0x7508: "Qi " -0x7509: "Xian " -0x750a: "Lou " -0x750b: "Di " -0x750c: "Ou " -0x750d: "Meng " -0x750e: "Zhuan " -0x750f: "Peng " -0x7510: "Lin " -0x7511: "Zeng " -0x7512: "Wu " -0x7513: "Pi " -0x7514: "Dan " -0x7515: "Weng " -0x7516: "Ying " -0x7517: "Yan " -0x7518: "Gan " -0x7519: "Dai " -0x751a: "Shen " -0x751b: "Tian " -0x751c: "Tian " -0x751d: "Han " -0x751e: "Chang " -0x751f: "Sheng " -0x7520: "Qing " -0x7521: "Sheng " -0x7522: "Chan " -0x7523: "Chan " -0x7524: "Rui " -0x7525: "Sheng " -0x7526: "Su " -0x7527: "Sen " -0x7528: "Yong " -0x7529: "Shuai " -0x752a: "Lu " -0x752b: "Fu " -0x752c: "Yong " -0x752d: "Beng " -0x752e: "Feng " -0x752f: "Ning " -0x7530: "Tian " -0x7531: "You " -0x7532: "Jia " -0x7533: "Shen " -0x7534: "Zha " -0x7535: "Dian " -0x7536: "Fu " -0x7537: "Nan " -0x7538: "Dian " -0x7539: "Ping " -0x753a: "Ting " -0x753b: "Hua " -0x753c: "Ting " -0x753d: "Quan " -0x753e: "Zi " -0x753f: "Meng " -0x7540: "Bi " -0x7541: "Qi " -0x7542: "Liu " -0x7543: "Xun " -0x7544: "Liu " -0x7545: "Chang " -0x7546: "Mu " -0x7547: "Yun " -0x7548: "Fan " -0x7549: "Fu " -0x754a: "Geng " -0x754b: "Tian " -0x754c: "Jie " -0x754d: "Jie " -0x754e: "Quan " -0x754f: "Wei " -0x7550: "Fu " -0x7551: "Tian " -0x7552: "Mu " -0x7553: "Tap " -0x7554: "Pan " -0x7555: "Jiang " -0x7556: "Wa " -0x7557: "Da " -0x7558: "Nan " -0x7559: "Liu " -0x755a: "Ben " -0x755b: "Zhen " -0x755c: "Chu " -0x755d: "Mu " -0x755e: "Mu " -0x755f: "Ce " -0x7560: "Cen " -0x7561: "Gai " -0x7562: "Bi " -0x7563: "Da " -0x7564: "Zhi " -0x7565: "Lue " -0x7566: "Qi " -0x7567: "Lue " -0x7568: "Pan " -0x7569: "Kesa " -0x756a: "Fan " -0x756b: "Hua " -0x756c: "Yu " -0x756d: "Yu " -0x756e: "Mu " -0x756f: "Jun " -0x7570: "Yi " -0x7571: "Liu " -0x7572: "Yu " -0x7573: "Die " -0x7574: "Chou " -0x7575: "Hua " -0x7576: "Dang " -0x7577: "Chuo " -0x7578: "Ji " -0x7579: "Wan " -0x757a: "Jiang " -0x757b: "Sheng " -0x757c: "Chang " -0x757d: "Tuan " -0x757e: "Lei " -0x757f: "Ji " -0x7580: "Cha " -0x7581: "Liu " -0x7582: "Tatamu " -0x7583: "Tuan " -0x7584: "Lin " -0x7585: "Jiang " -0x7586: "Jiang " -0x7587: "Chou " -0x7588: "Bo " -0x7589: "Die " -0x758a: "Die " -0x758b: "Pi " -0x758c: "Nie " -0x758d: "Dan " -0x758e: "Shu " -0x758f: "Shu " -0x7590: "Zhi " -0x7591: "Yi " -0x7592: "Chuang " -0x7593: "Nai " -0x7594: "Ding " -0x7595: "Bi " -0x7596: "Jie " -0x7597: "Liao " -0x7598: "Gong " -0x7599: "Ge " -0x759a: "Jiu " -0x759b: "Zhou " -0x759c: "Xia " -0x759d: "Shan " -0x759e: "Xu " -0x759f: "Nue " -0x75a0: "Li " -0x75a1: "Yang " -0x75a2: "Chen " -0x75a3: "You " -0x75a4: "Ba " -0x75a5: "Jie " -0x75a6: "Jue " -0x75a7: "Zhi " -0x75a8: "Xia " -0x75a9: "Cui " -0x75aa: "Bi " -0x75ab: "Yi " -0x75ac: "Li " -0x75ad: "Zong " -0x75ae: "Chuang " -0x75af: "Feng " -0x75b0: "Zhu " -0x75b1: "Pao " -0x75b2: "Pi " -0x75b3: "Gan " -0x75b4: "Ke " -0x75b5: "Ci " -0x75b6: "Xie " -0x75b7: "Qi " -0x75b8: "Dan " -0x75b9: "Zhen " -0x75ba: "Fa " -0x75bb: "Zhi " -0x75bc: "Teng " -0x75bd: "Ju " -0x75be: "Ji " -0x75bf: "Fei " -0x75c0: "Qu " -0x75c1: "Dian " -0x75c2: "Jia " -0x75c3: "Xian " -0x75c4: "Cha " -0x75c5: "Bing " -0x75c6: "Ni " -0x75c7: "Zheng " -0x75c8: "Yong " -0x75c9: "Jing " -0x75ca: "Quan " -0x75cb: "Chong " -0x75cc: "Tong " -0x75cd: "Yi " -0x75ce: "Kai " -0x75cf: "Wei " -0x75d0: "Hui " -0x75d1: "Duo " -0x75d2: "Yang " -0x75d3: "Chi " -0x75d4: "Zhi " -0x75d5: "Hen " -0x75d6: "Ya " -0x75d7: "Mei " -0x75d8: "Dou " -0x75d9: "Jing " -0x75da: "Xiao " -0x75db: "Tong " -0x75dc: "Tu " -0x75dd: "Mang " -0x75de: "Pi " -0x75df: "Xiao " -0x75e0: "Suan " -0x75e1: "Pu " -0x75e2: "Li " -0x75e3: "Zhi " -0x75e4: "Cuo " -0x75e5: "Duo " -0x75e6: "Wu " -0x75e7: "Sha " -0x75e8: "Lao " -0x75e9: "Shou " -0x75ea: "Huan " -0x75eb: "Xian " -0x75ec: "Yi " -0x75ed: "Peng " -0x75ee: "Zhang " -0x75ef: "Guan " -0x75f0: "Tan " -0x75f1: "Fei " -0x75f2: "Ma " -0x75f3: "Lin " -0x75f4: "Chi " -0x75f5: "Ji " -0x75f6: "Dian " -0x75f7: "An " -0x75f8: "Chi " -0x75f9: "Bi " -0x75fa: "Bei " -0x75fb: "Min " -0x75fc: "Gu " -0x75fd: "Dui " -0x75fe: "E " -0x75ff: "Wei " -/* x076 */ -0x7600: "Yu " -0x7601: "Cui " -0x7602: "Ya " -0x7603: "Zhu " -0x7604: "Cu " -0x7605: "Dan " -0x7606: "Shen " -0x7607: "Zhung " -0x7608: "Ji " -0x7609: "Yu " -0x760a: "Hou " -0x760b: "Feng " -0x760c: "La " -0x760d: "Yang " -0x760e: "Shen " -0x760f: "Tu " -0x7610: "Yu " -0x7611: "Gua " -0x7612: "Wen " -0x7613: "Huan " -0x7614: "Ku " -0x7615: "Jia " -0x7616: "Yin " -0x7617: "Yi " -0x7618: "Lu " -0x7619: "Sao " -0x761a: "Jue " -0x761b: "Chi " -0x761c: "Xi " -0x761d: "Guan " -0x761e: "Yi " -0x761f: "Wen " -0x7620: "Ji " -0x7621: "Chuang " -0x7622: "Ban " -0x7623: "Lei " -0x7624: "Liu " -0x7625: "Chai " -0x7626: "Shou " -0x7627: "Nue " -0x7628: "Dian " -0x7629: "Da " -0x762a: "Pie " -0x762b: "Tan " -0x762c: "Zhang " -0x762d: "Biao " -0x762e: "Shen " -0x762f: "Cu " -0x7630: "Luo " -0x7631: "Yi " -0x7632: "Zong " -0x7633: "Chou " -0x7634: "Zhang " -0x7635: "Zhai " -0x7636: "Sou " -0x7637: "Suo " -0x7638: "Que " -0x7639: "Diao " -0x763a: "Lou " -0x763b: "Lu " -0x763c: "Mo " -0x763d: "Jin " -0x763e: "Yin " -0x763f: "Ying " -0x7640: "Huang " -0x7641: "Fu " -0x7642: "Liao " -0x7643: "Long " -0x7644: "Qiao " -0x7645: "Liu " -0x7646: "Lao " -0x7647: "Xian " -0x7648: "Fei " -0x7649: "Dan " -0x764a: "Yin " -0x764b: "He " -0x764c: "Yan " -0x764d: "Ban " -0x764e: "Xian " -0x764f: "Guan " -0x7650: "Guai " -0x7651: "Nong " -0x7652: "Yu " -0x7653: "Wei " -0x7654: "Yi " -0x7655: "Yong " -0x7656: "Pi " -0x7657: "Lei " -0x7658: "Li " -0x7659: "Shu " -0x765a: "Dan " -0x765b: "Lin " -0x765c: "Dian " -0x765d: "Lin " -0x765e: "Lai " -0x765f: "Pie " -0x7660: "Ji " -0x7661: "Chi " -0x7662: "Yang " -0x7663: "Xian " -0x7664: "Jie " -0x7665: "Zheng " -0x7666: "[?] " -0x7667: "Li " -0x7668: "Huo " -0x7669: "Lai " -0x766a: "Shaku " -0x766b: "Dian " -0x766c: "Xian " -0x766d: "Ying " -0x766e: "Yin " -0x766f: "Qu " -0x7670: "Yong " -0x7671: "Tan " -0x7672: "Dian " -0x7673: "Luo " -0x7674: "Luan " -0x7675: "Luan " -0x7676: "Bo " -0x7677: "[?] " -0x7678: "Gui " -0x7679: "Po " -0x767a: "Fa " -0x767b: "Deng " -0x767c: "Fa " -0x767d: "Bai " -0x767e: "Bai " -0x767f: "Qie " -0x7680: "Bi " -0x7681: "Zao " -0x7682: "Zao " -0x7683: "Mao " -0x7684: "De " -0x7685: "Pa " -0x7686: "Jie " -0x7687: "Huang " -0x7688: "Gui " -0x7689: "Ci " -0x768a: "Ling " -0x768b: "Gao " -0x768c: "Mo " -0x768d: "Ji " -0x768e: "Jiao " -0x768f: "Peng " -0x7690: "Gao " -0x7691: "Ai " -0x7692: "E " -0x7693: "Hao " -0x7694: "Han " -0x7695: "Bi " -0x7696: "Wan " -0x7697: "Chou " -0x7698: "Qian " -0x7699: "Xi " -0x769a: "Ai " -0x769b: "Jiong " -0x769c: "Hao " -0x769d: "Huang " -0x769e: "Hao " -0x769f: "Ze " -0x76a0: "Cui " -0x76a1: "Hao " -0x76a2: "Xiao " -0x76a3: "Ye " -0x76a4: "Po " -0x76a5: "Hao " -0x76a6: "Jiao " -0x76a7: "Ai " -0x76a8: "Xing " -0x76a9: "Huang " -0x76aa: "Li " -0x76ab: "Piao " -0x76ac: "He " -0x76ad: "Jiao " -0x76ae: "Pi " -0x76af: "Gan " -0x76b0: "Pao " -0x76b1: "Zhou " -0x76b2: "Jun " -0x76b3: "Qiu " -0x76b4: "Cun " -0x76b5: "Que " -0x76b6: "Zha " -0x76b7: "Gu " -0x76b8: "Jun " -0x76b9: "Jun " -0x76ba: "Zhou " -0x76bb: "Zha " -0x76bc: "Gu " -0x76bd: "Zhan " -0x76be: "Du " -0x76bf: "Min " -0x76c0: "Qi " -0x76c1: "Ying " -0x76c2: "Yu " -0x76c3: "Bei " -0x76c4: "Zhao " -0x76c5: "Zhong " -0x76c6: "Pen " -0x76c7: "He " -0x76c8: "Ying " -0x76c9: "He " -0x76ca: "Yi " -0x76cb: "Bo " -0x76cc: "Wan " -0x76cd: "He " -0x76ce: "Ang " -0x76cf: "Zhan " -0x76d0: "Yan " -0x76d1: "Jian " -0x76d2: "He " -0x76d3: "Yu " -0x76d4: "Kui " -0x76d5: "Fan " -0x76d6: "Gai " -0x76d7: "Dao " -0x76d8: "Pan " -0x76d9: "Fu " -0x76da: "Qiu " -0x76db: "Sheng " -0x76dc: "Dao " -0x76dd: "Lu " -0x76de: "Zhan " -0x76df: "Meng " -0x76e0: "Li " -0x76e1: "Jin " -0x76e2: "Xu " -0x76e3: "Jian " -0x76e4: "Pan " -0x76e5: "Guan " -0x76e6: "An " -0x76e7: "Lu " -0x76e8: "Shu " -0x76e9: "Zhou " -0x76ea: "Dang " -0x76eb: "An " -0x76ec: "Gu " -0x76ed: "Li " -0x76ee: "Mu " -0x76ef: "Cheng " -0x76f0: "Gan " -0x76f1: "Xu " -0x76f2: "Mang " -0x76f3: "Mang " -0x76f4: "Zhi " -0x76f5: "Qi " -0x76f6: "Ruan " -0x76f7: "Tian " -0x76f8: "Xiang " -0x76f9: "Dun " -0x76fa: "Xin " -0x76fb: "Xi " -0x76fc: "Pan " -0x76fd: "Feng " -0x76fe: "Dun " -0x76ff: "Min " -/* x077 */ -0x7700: "Ming " -0x7701: "Sheng " -0x7702: "Shi " -0x7703: "Yun " -0x7704: "Mian " -0x7705: "Pan " -0x7706: "Fang " -0x7707: "Miao " -0x7708: "Dan " -0x7709: "Mei " -0x770a: "Mao " -0x770b: "Kan " -0x770c: "Xian " -0x770d: "Ou " -0x770e: "Shi " -0x770f: "Yang " -0x7710: "Zheng " -0x7711: "Yao " -0x7712: "Shen " -0x7713: "Huo " -0x7714: "Da " -0x7715: "Zhen " -0x7716: "Kuang " -0x7717: "Ju " -0x7718: "Shen " -0x7719: "Chi " -0x771a: "Sheng " -0x771b: "Mei " -0x771c: "Mo " -0x771d: "Zhu " -0x771e: "Zhen " -0x771f: "Zhen " -0x7720: "Mian " -0x7721: "Di " -0x7722: "Yuan " -0x7723: "Die " -0x7724: "Yi " -0x7725: "Zi " -0x7726: "Zi " -0x7727: "Chao " -0x7728: "Zha " -0x7729: "Xuan " -0x772a: "Bing " -0x772b: "Mi " -0x772c: "Long " -0x772d: "Sui " -0x772e: "Dong " -0x772f: "Mi " -0x7730: "Die " -0x7731: "Yi " -0x7732: "Er " -0x7733: "Ming " -0x7734: "Xuan " -0x7735: "Chi " -0x7736: "Kuang " -0x7737: "Juan " -0x7738: "Mou " -0x7739: "Zhen " -0x773a: "Tiao " -0x773b: "Yang " -0x773c: "Yan " -0x773d: "Mo " -0x773e: "Zhong " -0x773f: "Mai " -0x7740: "Zhao " -0x7741: "Zheng " -0x7742: "Mei " -0x7743: "Jun " -0x7744: "Shao " -0x7745: "Han " -0x7746: "Huan " -0x7747: "Di " -0x7748: "Cheng " -0x7749: "Cuo " -0x774a: "Juan " -0x774b: "E " -0x774c: "Wan " -0x774d: "Xian " -0x774e: "Xi " -0x774f: "Kun " -0x7750: "Lai " -0x7751: "Jian " -0x7752: "Shan " -0x7753: "Tian " -0x7754: "Hun " -0x7755: "Wan " -0x7756: "Ling " -0x7757: "Shi " -0x7758: "Qiong " -0x7759: "Lie " -0x775a: "Yai " -0x775b: "Jing " -0x775c: "Zheng " -0x775d: "Li " -0x775e: "Lai " -0x775f: "Sui " -0x7760: "Juan " -0x7761: "Shui " -0x7762: "Sui " -0x7763: "Du " -0x7764: "Bi " -0x7765: "Bi " -0x7766: "Mu " -0x7767: "Hun " -0x7768: "Ni " -0x7769: "Lu " -0x776a: "Yi " -0x776b: "Jie " -0x776c: "Cai " -0x776d: "Zhou " -0x776e: "Yu " -0x776f: "Hun " -0x7770: "Ma " -0x7771: "Xia " -0x7772: "Xing " -0x7773: "Xi " -0x7774: "Gun " -0x7775: "Cai " -0x7776: "Chun " -0x7777: "Jian " -0x7778: "Mei " -0x7779: "Du " -0x777a: "Hou " -0x777b: "Xuan " -0x777c: "Ti " -0x777d: "Kui " -0x777e: "Gao " -0x777f: "Rui " -0x7780: "Mou " -0x7781: "Xu " -0x7782: "Fa " -0x7783: "Wen " -0x7784: "Miao " -0x7785: "Chou " -0x7786: "Kui " -0x7787: "Mi " -0x7788: "Weng " -0x7789: "Kou " -0x778a: "Dang " -0x778b: "Chen " -0x778c: "Ke " -0x778d: "Sou " -0x778e: "Xia " -0x778f: "Qiong " -0x7790: "Mao " -0x7791: "Ming " -0x7792: "Man " -0x7793: "Shui " -0x7794: "Ze " -0x7795: "Zhang " -0x7796: "Yi " -0x7797: "Diao " -0x7798: "Ou " -0x7799: "Mo " -0x779a: "Shun " -0x779b: "Cong " -0x779c: "Lou " -0x779d: "Chi " -0x779e: "Man " -0x779f: "Piao " -0x77a0: "Cheng " -0x77a1: "Ji " -0x77a2: "Meng " -0x77a3: "[?] " -0x77a4: "Run " -0x77a5: "Pie " -0x77a6: "Xi " -0x77a7: "Qiao " -0x77a8: "Pu " -0x77a9: "Zhu " -0x77aa: "Deng " -0x77ab: "Shen " -0x77ac: "Shun " -0x77ad: "Liao " -0x77ae: "Che " -0x77af: "Xian " -0x77b0: "Kan " -0x77b1: "Ye " -0x77b2: "Xu " -0x77b3: "Tong " -0x77b4: "Mou " -0x77b5: "Lin " -0x77b6: "Kui " -0x77b7: "Xian " -0x77b8: "Ye " -0x77b9: "Ai " -0x77ba: "Hui " -0x77bb: "Zhan " -0x77bc: "Jian " -0x77bd: "Gu " -0x77be: "Zhao " -0x77bf: "Qu " -0x77c0: "Wei " -0x77c1: "Chou " -0x77c2: "Sao " -0x77c3: "Ning " -0x77c4: "Xun " -0x77c5: "Yao " -0x77c6: "Huo " -0x77c7: "Meng " -0x77c8: "Mian " -0x77c9: "Bin " -0x77ca: "Mian " -0x77cb: "Li " -0x77cc: "Kuang " -0x77cd: "Jue " -0x77ce: "Xuan " -0x77cf: "Mian " -0x77d0: "Huo " -0x77d1: "Lu " -0x77d2: "Meng " -0x77d3: "Long " -0x77d4: "Guan " -0x77d5: "Man " -0x77d6: "Xi " -0x77d7: "Chu " -0x77d8: "Tang " -0x77d9: "Kan " -0x77da: "Zhu " -0x77db: "Mao " -0x77dc: "Jin " -0x77dd: "Lin " -0x77de: "Yu " -0x77df: "Shuo " -0x77e0: "Ce " -0x77e1: "Jue " -0x77e2: "Shi " -0x77e3: "Yi " -0x77e4: "Shen " -0x77e5: "Zhi " -0x77e6: "Hou " -0x77e7: "Shen " -0x77e8: "Ying " -0x77e9: "Ju " -0x77ea: "Zhou " -0x77eb: "Jiao " -0x77ec: "Cuo " -0x77ed: "Duan " -0x77ee: "Ai " -0x77ef: "Jiao " -0x77f0: "Zeng " -0x77f1: "Huo " -0x77f2: "Bai " -0x77f3: "Shi " -0x77f4: "Ding " -0x77f5: "Qi " -0x77f6: "Ji " -0x77f7: "Zi " -0x77f8: "Gan " -0x77f9: "Wu " -0x77fa: "Tuo " -0x77fb: "Ku " -0x77fc: "Qiang " -0x77fd: "Xi " -0x77fe: "Fan " -0x77ff: "Kuang " -/* x078 */ -0x7800: "Dang " -0x7801: "Ma " -0x7802: "Sha " -0x7803: "Dan " -0x7804: "Jue " -0x7805: "Li " -0x7806: "Fu " -0x7807: "Min " -0x7808: "Nuo " -0x7809: "Huo " -0x780a: "Kang " -0x780b: "Zhi " -0x780c: "Qi " -0x780d: "Kan " -0x780e: "Jie " -0x780f: "Fen " -0x7810: "E " -0x7811: "Ya " -0x7812: "Pi " -0x7813: "Zhe " -0x7814: "Yan " -0x7815: "Sui " -0x7816: "Zhuan " -0x7817: "Che " -0x7818: "Dun " -0x7819: "Pan " -0x781a: "Yan " -0x781b: "[?] " -0x781c: "Feng " -0x781d: "Fa " -0x781e: "Mo " -0x781f: "Zha " -0x7820: "Qu " -0x7821: "Yu " -0x7822: "Luo " -0x7823: "Tuo " -0x7824: "Tuo " -0x7825: "Di " -0x7826: "Zhai " -0x7827: "Zhen " -0x7828: "Ai " -0x7829: "Fei " -0x782a: "Mu " -0x782b: "Zhu " -0x782c: "Li " -0x782d: "Bian " -0x782e: "Nu " -0x782f: "Ping " -0x7830: "Peng " -0x7831: "Ling " -0x7832: "Pao " -0x7833: "Le " -0x7834: "Po " -0x7835: "Bo " -0x7836: "Po " -0x7837: "Shen " -0x7838: "Za " -0x7839: "Nuo " -0x783a: "Li " -0x783b: "Long " -0x783c: "Tong " -0x783d: "[?] " -0x783e: "Li " -0x783f: "Aragane " -0x7840: "Chu " -0x7841: "Keng " -0x7842: "Quan " -0x7843: "Zhu " -0x7844: "Kuang " -0x7845: "Huo " -0x7846: "E " -0x7847: "Nao " -0x7848: "Jia " -0x7849: "Lu " -0x784a: "Wei " -0x784b: "Ai " -0x784c: "Luo " -0x784d: "Ken " -0x784e: "Xing " -0x784f: "Yan " -0x7850: "Tong " -0x7851: "Peng " -0x7852: "Xi " -0x7853: "[?] " -0x7854: "Hong " -0x7855: "Shuo " -0x7856: "Xia " -0x7857: "Qiao " -0x7858: "[?] " -0x7859: "Wei " -0x785a: "Qiao " -0x785b: "[?] " -0x785c: "Keng " -0x785d: "Xiao " -0x785e: "Que " -0x785f: "Chan " -0x7860: "Lang " -0x7861: "Hong " -0x7862: "Yu " -0x7863: "Xiao " -0x7864: "Xia " -0x7865: "Mang " -0x7866: "Long " -0x7867: "Iong " -0x7868: "Che " -0x7869: "Che " -0x786a: "E " -0x786b: "Liu " -0x786c: "Ying " -0x786d: "Mang " -0x786e: "Que " -0x786f: "Yan " -0x7870: "Sha " -0x7871: "Kun " -0x7872: "Yu " -0x7873: "[?] " -0x7874: "Kaki " -0x7875: "Lu " -0x7876: "Chen " -0x7877: "Jian " -0x7878: "Nue " -0x7879: "Song " -0x787a: "Zhuo " -0x787b: "Keng " -0x787c: "Peng " -0x787d: "Yan " -0x787e: "Zhui " -0x787f: "Kong " -0x7880: "Ceng " -0x7881: "Qi " -0x7882: "Zong " -0x7883: "Qing " -0x7884: "Lin " -0x7885: "Jun " -0x7886: "Bo " -0x7887: "Ding " -0x7888: "Min " -0x7889: "Diao " -0x788a: "Jian " -0x788b: "He " -0x788c: "Lu " -0x788d: "Ai " -0x788e: "Sui " -0x788f: "Que " -0x7890: "Ling " -0x7891: "Bei " -0x7892: "Yin " -0x7893: "Dui " -0x7894: "Wu " -0x7895: "Qi " -0x7896: "Lun " -0x7897: "Wan " -0x7898: "Dian " -0x7899: "Gang " -0x789a: "Pei " -0x789b: "Qi " -0x789c: "Chen " -0x789d: "Ruan " -0x789e: "Yan " -0x789f: "Die " -0x78a0: "Ding " -0x78a1: "Du " -0x78a2: "Tuo " -0x78a3: "Jie " -0x78a4: "Ying " -0x78a5: "Bian " -0x78a6: "Ke " -0x78a7: "Bi " -0x78a8: "Wei " -0x78a9: "Shuo " -0x78aa: "Zhen " -0x78ab: "Duan " -0x78ac: "Xia " -0x78ad: "Dang " -0x78ae: "Ti " -0x78af: "Nao " -0x78b0: "Peng " -0x78b1: "Jian " -0x78b2: "Di " -0x78b3: "Tan " -0x78b4: "Cha " -0x78b5: "Seki " -0x78b6: "Qi " -0x78b7: "[?] " -0x78b8: "Feng " -0x78b9: "Xuan " -0x78ba: "Que " -0x78bb: "Que " -0x78bc: "Ma " -0x78bd: "Gong " -0x78be: "Nian " -0x78bf: "Su " -0x78c0: "E " -0x78c1: "Ci " -0x78c2: "Liu " -0x78c3: "Si " -0x78c4: "Tang " -0x78c5: "Bang " -0x78c6: "Hua " -0x78c7: "Pi " -0x78c8: "Wei " -0x78c9: "Sang " -0x78ca: "Lei " -0x78cb: "Cuo " -0x78cc: "Zhen " -0x78cd: "Xia " -0x78ce: "Qi " -0x78cf: "Lian " -0x78d0: "Pan " -0x78d1: "Wei " -0x78d2: "Yun " -0x78d3: "Dui " -0x78d4: "Zhe " -0x78d5: "Ke " -0x78d6: "La " -0x78d7: "[?] " -0x78d8: "Qing " -0x78d9: "Gun " -0x78da: "Zhuan " -0x78db: "Chan " -0x78dc: "Qi " -0x78dd: "Ao " -0x78de: "Peng " -0x78df: "Lu " -0x78e0: "Lu " -0x78e1: "Kan " -0x78e2: "Qiang " -0x78e3: "Chen " -0x78e4: "Yin " -0x78e5: "Lei " -0x78e6: "Biao " -0x78e7: "Qi " -0x78e8: "Mo " -0x78e9: "Qi " -0x78ea: "Cui " -0x78eb: "Zong " -0x78ec: "Qing " -0x78ed: "Chuo " -0x78ee: "[?] " -0x78ef: "Ji " -0x78f0: "Shan " -0x78f1: "Lao " -0x78f2: "Qu " -0x78f3: "Zeng " -0x78f4: "Deng " -0x78f5: "Jian " -0x78f6: "Xi " -0x78f7: "Lin " -0x78f8: "Ding " -0x78f9: "Dian " -0x78fa: "Huang " -0x78fb: "Pan " -0x78fc: "Za " -0x78fd: "Qiao " -0x78fe: "Di " -0x78ff: "Li " -/* x079 */ -0x7900: "Tani " -0x7901: "Jiao " -0x7902: "[?] " -0x7903: "Zhang " -0x7904: "Qiao " -0x7905: "Dun " -0x7906: "Xian " -0x7907: "Yu " -0x7908: "Zhui " -0x7909: "He " -0x790a: "Huo " -0x790b: "Zhai " -0x790c: "Lei " -0x790d: "Ke " -0x790e: "Chu " -0x790f: "Ji " -0x7910: "Que " -0x7911: "Dang " -0x7912: "Yi " -0x7913: "Jiang " -0x7914: "Pi " -0x7915: "Pi " -0x7916: "Yu " -0x7917: "Pin " -0x7918: "Qi " -0x7919: "Ai " -0x791a: "Kai " -0x791b: "Jian " -0x791c: "Yu " -0x791d: "Ruan " -0x791e: "Meng " -0x791f: "Pao " -0x7920: "Ci " -0x7921: "[?] " -0x7922: "[?] " -0x7923: "Mie " -0x7924: "Ca " -0x7925: "Xian " -0x7926: "Kuang " -0x7927: "Lei " -0x7928: "Lei " -0x7929: "Zhi " -0x792a: "Li " -0x792b: "Li " -0x792c: "Fan " -0x792d: "Que " -0x792e: "Pao " -0x792f: "Ying " -0x7930: "Li " -0x7931: "Long " -0x7932: "Long " -0x7933: "Mo " -0x7934: "Bo " -0x7935: "Shuang " -0x7936: "Guan " -0x7937: "Lan " -0x7938: "Zan " -0x7939: "Yan " -0x793a: "Shi " -0x793b: "Shi " -0x793c: "Li " -0x793d: "Reng " -0x793e: "She " -0x793f: "Yue " -0x7940: "Si " -0x7941: "Qi " -0x7942: "Ta " -0x7943: "Ma " -0x7944: "Xie " -0x7945: "Xian " -0x7946: "Xian " -0x7947: "Zhi " -0x7948: "Qi " -0x7949: "Zhi " -0x794a: "Beng " -0x794b: "Dui " -0x794c: "Zhong " -0x794d: "[?] " -0x794e: "Yi " -0x794f: "Shi " -0x7950: "You " -0x7951: "Zhi " -0x7952: "Tiao " -0x7953: "Fu " -0x7954: "Fu " -0x7955: "Mi " -0x7956: "Zu " -0x7957: "Zhi " -0x7958: "Suan " -0x7959: "Mei " -0x795a: "Zuo " -0x795b: "Qu " -0x795c: "Hu " -0x795d: "Zhu " -0x795e: "Shen " -0x795f: "Sui " -0x7960: "Ci " -0x7961: "Chai " -0x7962: "Mi " -0x7963: "Lu " -0x7964: "Yu " -0x7965: "Xiang " -0x7966: "Wu " -0x7967: "Tiao " -0x7968: "Piao " -0x7969: "Zhu " -0x796a: "Gui " -0x796b: "Xia " -0x796c: "Zhi " -0x796d: "Ji " -0x796e: "Gao " -0x796f: "Zhen " -0x7970: "Gao " -0x7971: "Shui " -0x7972: "Jin " -0x7973: "Chen " -0x7974: "Gai " -0x7975: "Kun " -0x7976: "Di " -0x7977: "Dao " -0x7978: "Huo " -0x7979: "Tao " -0x797a: "Qi " -0x797b: "Gu " -0x797c: "Guan " -0x797d: "Zui " -0x797e: "Ling " -0x797f: "Lu " -0x7980: "Bing " -0x7981: "Jin " -0x7982: "Dao " -0x7983: "Zhi " -0x7984: "Lu " -0x7985: "Shan " -0x7986: "Bei " -0x7987: "Zhe " -0x7988: "Hui " -0x7989: "You " -0x798a: "Xi " -0x798b: "Yin " -0x798c: "Zi " -0x798d: "Huo " -0x798e: "Zhen " -0x798f: "Fu " -0x7990: "Yuan " -0x7991: "Wu " -0x7992: "Xian " -0x7993: "Yang " -0x7994: "Ti " -0x7995: "Yi " -0x7996: "Mei " -0x7997: "Si " -0x7998: "Di " -0x7999: "[?] " -0x799a: "Zhuo " -0x799b: "Zhen " -0x799c: "Yong " -0x799d: "Ji " -0x799e: "Gao " -0x799f: "Tang " -0x79a0: "Si " -0x79a1: "Ma " -0x79a2: "Ta " -0x79a3: "[?] " -0x79a4: "Xuan " -0x79a5: "Qi " -0x79a6: "Yu " -0x79a7: "Xi " -0x79a8: "Ji " -0x79a9: "Si " -0x79aa: "Chan " -0x79ab: "Tan " -0x79ac: "Kuai " -0x79ad: "Sui " -0x79ae: "Li " -0x79af: "Nong " -0x79b0: "Ni " -0x79b1: "Dao " -0x79b2: "Li " -0x79b3: "Rang " -0x79b4: "Yue " -0x79b5: "Ti " -0x79b6: "Zan " -0x79b7: "Lei " -0x79b8: "Rou " -0x79b9: "Yu " -0x79ba: "Yu " -0x79bb: "Chi " -0x79bc: "Xie " -0x79bd: "Qin " -0x79be: "He " -0x79bf: "Tu " -0x79c0: "Xiu " -0x79c1: "Si " -0x79c2: "Ren " -0x79c3: "Tu " -0x79c4: "Zi " -0x79c5: "Cha " -0x79c6: "Gan " -0x79c7: "Yi " -0x79c8: "Xian " -0x79c9: "Bing " -0x79ca: "Nian " -0x79cb: "Qiu " -0x79cc: "Qiu " -0x79cd: "Chong " -0x79ce: "Fen " -0x79cf: "Hao " -0x79d0: "Yun " -0x79d1: "Ke " -0x79d2: "Miao " -0x79d3: "Zhi " -0x79d4: "Geng " -0x79d5: "Bi " -0x79d6: "Zhi " -0x79d7: "Yu " -0x79d8: "Mi " -0x79d9: "Ku " -0x79da: "Ban " -0x79db: "Pi " -0x79dc: "Ni " -0x79dd: "Li " -0x79de: "You " -0x79df: "Zu " -0x79e0: "Pi " -0x79e1: "Ba " -0x79e2: "Ling " -0x79e3: "Mo " -0x79e4: "Cheng " -0x79e5: "Nian " -0x79e6: "Qin " -0x79e7: "Yang " -0x79e8: "Zuo " -0x79e9: "Zhi " -0x79ea: "Zhi " -0x79eb: "Shu " -0x79ec: "Ju " -0x79ed: "Zi " -0x79ee: "Huo " -0x79ef: "Ji " -0x79f0: "Cheng " -0x79f1: "Tong " -0x79f2: "Zhi " -0x79f3: "Huo " -0x79f4: "He " -0x79f5: "Yin " -0x79f6: "Zi " -0x79f7: "Zhi " -0x79f8: "Jie " -0x79f9: "Ren " -0x79fa: "Du " -0x79fb: "Yi " -0x79fc: "Zhu " -0x79fd: "Hui " -0x79fe: "Nong " -0x79ff: "Fu " -/* x07a */ -0x7a00: "Xi " -0x7a01: "Kao " -0x7a02: "Lang " -0x7a03: "Fu " -0x7a04: "Ze " -0x7a05: "Shui " -0x7a06: "Lu " -0x7a07: "Kun " -0x7a08: "Gan " -0x7a09: "Geng " -0x7a0a: "Ti " -0x7a0b: "Cheng " -0x7a0c: "Tu " -0x7a0d: "Shao " -0x7a0e: "Shui " -0x7a0f: "Ya " -0x7a10: "Lun " -0x7a11: "Lu " -0x7a12: "Gu " -0x7a13: "Zuo " -0x7a14: "Ren " -0x7a15: "Zhun " -0x7a16: "Bang " -0x7a17: "Bai " -0x7a18: "Ji " -0x7a19: "Zhi " -0x7a1a: "Zhi " -0x7a1b: "Kun " -0x7a1c: "Leng " -0x7a1d: "Peng " -0x7a1e: "Ke " -0x7a1f: "Bing " -0x7a20: "Chou " -0x7a21: "Zu " -0x7a22: "Yu " -0x7a23: "Su " -0x7a24: "Lue " -0x7a25: "[?] " -0x7a26: "Yi " -0x7a27: "Xi " -0x7a28: "Bian " -0x7a29: "Ji " -0x7a2a: "Fu " -0x7a2b: "Bi " -0x7a2c: "Nuo " -0x7a2d: "Jie " -0x7a2e: "Zhong " -0x7a2f: "Zong " -0x7a30: "Xu " -0x7a31: "Cheng " -0x7a32: "Dao " -0x7a33: "Wen " -0x7a34: "Lian " -0x7a35: "Zi " -0x7a36: "Yu " -0x7a37: "Ji " -0x7a38: "Xu " -0x7a39: "Zhen " -0x7a3a: "Zhi " -0x7a3b: "Dao " -0x7a3c: "Jia " -0x7a3d: "Ji " -0x7a3e: "Gao " -0x7a3f: "Gao " -0x7a40: "Gu " -0x7a41: "Rong " -0x7a42: "Sui " -0x7a43: "You " -0x7a44: "Ji " -0x7a45: "Kang " -0x7a46: "Mu " -0x7a47: "Shan " -0x7a48: "Men " -0x7a49: "Zhi " -0x7a4a: "Ji " -0x7a4b: "Lu " -0x7a4c: "Su " -0x7a4d: "Ji " -0x7a4e: "Ying " -0x7a4f: "Wen " -0x7a50: "Qiu " -0x7a51: "Se " -0x7a52: "[?] " -0x7a53: "Yi " -0x7a54: "Huang " -0x7a55: "Qie " -0x7a56: "Ji " -0x7a57: "Sui " -0x7a58: "Xiao " -0x7a59: "Pu " -0x7a5a: "Jiao " -0x7a5b: "Zhuo " -0x7a5c: "Tong " -0x7a5d: "Sai " -0x7a5e: "Lu " -0x7a5f: "Sui " -0x7a60: "Nong " -0x7a61: "Se " -0x7a62: "Hui " -0x7a63: "Rang " -0x7a64: "Nuo " -0x7a65: "Yu " -0x7a66: "Bin " -0x7a67: "Ji " -0x7a68: "Tui " -0x7a69: "Wen " -0x7a6a: "Cheng " -0x7a6b: "Huo " -0x7a6c: "Gong " -0x7a6d: "Lu " -0x7a6e: "Biao " -0x7a6f: "[?] " -0x7a70: "Rang " -0x7a71: "Zhuo " -0x7a72: "Li " -0x7a73: "Zan " -0x7a74: "Xue " -0x7a75: "Wa " -0x7a76: "Jiu " -0x7a77: "Qiong " -0x7a78: "Xi " -0x7a79: "Qiong " -0x7a7a: "Kong " -0x7a7b: "Yu " -0x7a7c: "Sen " -0x7a7d: "Jing " -0x7a7e: "Yao " -0x7a7f: "Chuan " -0x7a80: "Zhun " -0x7a81: "Tu " -0x7a82: "Lao " -0x7a83: "Qie " -0x7a84: "Zhai " -0x7a85: "Yao " -0x7a86: "Bian " -0x7a87: "Bao " -0x7a88: "Yao " -0x7a89: "Bing " -0x7a8a: "Wa " -0x7a8b: "Zhu " -0x7a8c: "Jiao " -0x7a8d: "Qiao " -0x7a8e: "Diao " -0x7a8f: "Wu " -0x7a90: "Gui " -0x7a91: "Yao " -0x7a92: "Zhi " -0x7a93: "Chuang " -0x7a94: "Yao " -0x7a95: "Tiao " -0x7a96: "Jiao " -0x7a97: "Chuang " -0x7a98: "Jiong " -0x7a99: "Xiao " -0x7a9a: "Cheng " -0x7a9b: "Kou " -0x7a9c: "Cuan " -0x7a9d: "Wo " -0x7a9e: "Dan " -0x7a9f: "Ku " -0x7aa0: "Ke " -0x7aa1: "Zhui " -0x7aa2: "Xu " -0x7aa3: "Su " -0x7aa4: "Guan " -0x7aa5: "Kui " -0x7aa6: "Dou " -0x7aa7: "[?] " -0x7aa8: "Yin " -0x7aa9: "Wo " -0x7aaa: "Wa " -0x7aab: "Ya " -0x7aac: "Yu " -0x7aad: "Ju " -0x7aae: "Qiong " -0x7aaf: "Yao " -0x7ab0: "Yao " -0x7ab1: "Tiao " -0x7ab2: "Chao " -0x7ab3: "Yu " -0x7ab4: "Tian " -0x7ab5: "Diao " -0x7ab6: "Ju " -0x7ab7: "Liao " -0x7ab8: "Xi " -0x7ab9: "Wu " -0x7aba: "Kui " -0x7abb: "Chuang " -0x7abc: "Zhao " -0x7abd: "[?] " -0x7abe: "Kuan " -0x7abf: "Long " -0x7ac0: "Cheng " -0x7ac1: "Cui " -0x7ac2: "Piao " -0x7ac3: "Zao " -0x7ac4: "Cuan " -0x7ac5: "Qiao " -0x7ac6: "Qiong " -0x7ac7: "Dou " -0x7ac8: "Zao " -0x7ac9: "Long " -0x7aca: "Qie " -0x7acb: "Li " -0x7acc: "Chu " -0x7acd: "Shi " -0x7ace: "Fou " -0x7acf: "Qian " -0x7ad0: "Chu " -0x7ad1: "Hong " -0x7ad2: "Qi " -0x7ad3: "Qian " -0x7ad4: "Gong " -0x7ad5: "Shi " -0x7ad6: "Shu " -0x7ad7: "Miao " -0x7ad8: "Ju " -0x7ad9: "Zhan " -0x7ada: "Zhu " -0x7adb: "Ling " -0x7adc: "Long " -0x7add: "Bing " -0x7ade: "Jing " -0x7adf: "Jing " -0x7ae0: "Zhang " -0x7ae1: "Yi " -0x7ae2: "Si " -0x7ae3: "Jun " -0x7ae4: "Hong " -0x7ae5: "Tong " -0x7ae6: "Song " -0x7ae7: "Jing " -0x7ae8: "Diao " -0x7ae9: "Yi " -0x7aea: "Shu " -0x7aeb: "Jing " -0x7aec: "Qu " -0x7aed: "Jie " -0x7aee: "Ping " -0x7aef: "Duan " -0x7af0: "Shao " -0x7af1: "Zhuan " -0x7af2: "Ceng " -0x7af3: "Deng " -0x7af4: "Cui " -0x7af5: "Huai " -0x7af6: "Jing " -0x7af7: "Kan " -0x7af8: "Jing " -0x7af9: "Zhu " -0x7afa: "Zhu " -0x7afb: "Le " -0x7afc: "Peng " -0x7afd: "Yu " -0x7afe: "Chi " -0x7aff: "Gan " -/* x07b */ -0x7b00: "Mang " -0x7b01: "Zhu " -0x7b02: "Utsubo " -0x7b03: "Du " -0x7b04: "Ji " -0x7b05: "Xiao " -0x7b06: "Ba " -0x7b07: "Suan " -0x7b08: "Ji " -0x7b09: "Zhen " -0x7b0a: "Zhao " -0x7b0b: "Sun " -0x7b0c: "Ya " -0x7b0d: "Zhui " -0x7b0e: "Yuan " -0x7b0f: "Hu " -0x7b10: "Gang " -0x7b11: "Xiao " -0x7b12: "Cen " -0x7b13: "Pi " -0x7b14: "Bi " -0x7b15: "Jian " -0x7b16: "Yi " -0x7b17: "Dong " -0x7b18: "Shan " -0x7b19: "Sheng " -0x7b1a: "Xia " -0x7b1b: "Di " -0x7b1c: "Zhu " -0x7b1d: "Na " -0x7b1e: "Chi " -0x7b1f: "Gu " -0x7b20: "Li " -0x7b21: "Qie " -0x7b22: "Min " -0x7b23: "Bao " -0x7b24: "Tiao " -0x7b25: "Si " -0x7b26: "Fu " -0x7b27: "Ce " -0x7b28: "Ben " -0x7b29: "Pei " -0x7b2a: "Da " -0x7b2b: "Zi " -0x7b2c: "Di " -0x7b2d: "Ling " -0x7b2e: "Ze " -0x7b2f: "Nu " -0x7b30: "Fu " -0x7b31: "Gou " -0x7b32: "Fan " -0x7b33: "Jia " -0x7b34: "Ge " -0x7b35: "Fan " -0x7b36: "Shi " -0x7b37: "Mao " -0x7b38: "Po " -0x7b39: "Sey " -0x7b3a: "Jian " -0x7b3b: "Qiong " -0x7b3c: "Long " -0x7b3d: "Souke " -0x7b3e: "Bian " -0x7b3f: "Luo " -0x7b40: "Gui " -0x7b41: "Qu " -0x7b42: "Chi " -0x7b43: "Yin " -0x7b44: "Yao " -0x7b45: "Xian " -0x7b46: "Bi " -0x7b47: "Qiong " -0x7b48: "Gua " -0x7b49: "Deng " -0x7b4a: "Jiao " -0x7b4b: "Jin " -0x7b4c: "Quan " -0x7b4d: "Sun " -0x7b4e: "Ru " -0x7b4f: "Fa " -0x7b50: "Kuang " -0x7b51: "Zhu " -0x7b52: "Tong " -0x7b53: "Ji " -0x7b54: "Da " -0x7b55: "Xing " -0x7b56: "Ce " -0x7b57: "Zhong " -0x7b58: "Kou " -0x7b59: "Lai " -0x7b5a: "Bi " -0x7b5b: "Shai " -0x7b5c: "Dang " -0x7b5d: "Zheng " -0x7b5e: "Ce " -0x7b5f: "Fu " -0x7b60: "Yun " -0x7b61: "Tu " -0x7b62: "Pa " -0x7b63: "Li " -0x7b64: "Lang " -0x7b65: "Ju " -0x7b66: "Guan " -0x7b67: "Jian " -0x7b68: "Han " -0x7b69: "Tong " -0x7b6a: "Xia " -0x7b6b: "Zhi " -0x7b6c: "Cheng " -0x7b6d: "Suan " -0x7b6e: "Shi " -0x7b6f: "Zhu " -0x7b70: "Zuo " -0x7b71: "Xiao " -0x7b72: "Shao " -0x7b73: "Ting " -0x7b74: "Ce " -0x7b75: "Yan " -0x7b76: "Gao " -0x7b77: "Kuai " -0x7b78: "Gan " -0x7b79: "Chou " -0x7b7a: "Kago " -0x7b7b: "Gang " -0x7b7c: "Yun " -0x7b7d: "O " -0x7b7e: "Qian " -0x7b7f: "Xiao " -0x7b80: "Jian " -0x7b81: "Pu " -0x7b82: "Lai " -0x7b83: "Zou " -0x7b84: "Bi " -0x7b85: "Bi " -0x7b86: "Bi " -0x7b87: "Ge " -0x7b88: "Chi " -0x7b89: "Guai " -0x7b8a: "Yu " -0x7b8b: "Jian " -0x7b8c: "Zhao " -0x7b8d: "Gu " -0x7b8e: "Chi " -0x7b8f: "Zheng " -0x7b90: "Jing " -0x7b91: "Sha " -0x7b92: "Zhou " -0x7b93: "Lu " -0x7b94: "Bo " -0x7b95: "Ji " -0x7b96: "Lin " -0x7b97: "Suan " -0x7b98: "Jun " -0x7b99: "Fu " -0x7b9a: "Zha " -0x7b9b: "Gu " -0x7b9c: "Kong " -0x7b9d: "Qian " -0x7b9e: "Quan " -0x7b9f: "Jun " -0x7ba0: "Chui " -0x7ba1: "Guan " -0x7ba2: "Yuan " -0x7ba3: "Ce " -0x7ba4: "Ju " -0x7ba5: "Bo " -0x7ba6: "Ze " -0x7ba7: "Qie " -0x7ba8: "Tuo " -0x7ba9: "Luo " -0x7baa: "Dan " -0x7bab: "Xiao " -0x7bac: "Ruo " -0x7bad: "Jian " -0x7bae: "Xuan " -0x7baf: "Bian " -0x7bb0: "Sun " -0x7bb1: "Xiang " -0x7bb2: "Xian " -0x7bb3: "Ping " -0x7bb4: "Zhen " -0x7bb5: "Sheng " -0x7bb6: "Hu " -0x7bb7: "Shi " -0x7bb8: "Zhu " -0x7bb9: "Yue " -0x7bba: "Chun " -0x7bbb: "Lu " -0x7bbc: "Wu " -0x7bbd: "Dong " -0x7bbe: "Xiao " -0x7bbf: "Ji " -0x7bc0: "Jie " -0x7bc1: "Huang " -0x7bc2: "Xing " -0x7bc3: "Mei " -0x7bc4: "Fan " -0x7bc5: "Chui " -0x7bc6: "Zhuan " -0x7bc7: "Pian " -0x7bc8: "Feng " -0x7bc9: "Zhu " -0x7bca: "Hong " -0x7bcb: "Qie " -0x7bcc: "Hou " -0x7bcd: "Qiu " -0x7bce: "Miao " -0x7bcf: "Qian " -0x7bd0: "[?] " -0x7bd1: "Kui " -0x7bd2: "Sik " -0x7bd3: "Lou " -0x7bd4: "Yun " -0x7bd5: "He " -0x7bd6: "Tang " -0x7bd7: "Yue " -0x7bd8: "Chou " -0x7bd9: "Gao " -0x7bda: "Fei " -0x7bdb: "Ruo " -0x7bdc: "Zheng " -0x7bdd: "Gou " -0x7bde: "Nie " -0x7bdf: "Qian " -0x7be0: "Xiao " -0x7be1: "Cuan " -0x7be2: "Gong " -0x7be3: "Pang " -0x7be4: "Du " -0x7be5: "Li " -0x7be6: "Bi " -0x7be7: "Zhuo " -0x7be8: "Chu " -0x7be9: "Shai " -0x7bea: "Chi " -0x7beb: "Zhu " -0x7bec: "Qiang " -0x7bed: "Long " -0x7bee: "Lan " -0x7bef: "Jian " -0x7bf0: "Bu " -0x7bf1: "Li " -0x7bf2: "Hui " -0x7bf3: "Bi " -0x7bf4: "Di " -0x7bf5: "Cong " -0x7bf6: "Yan " -0x7bf7: "Peng " -0x7bf8: "Sen " -0x7bf9: "Zhuan " -0x7bfa: "Pai " -0x7bfb: "Piao " -0x7bfc: "Dou " -0x7bfd: "Yu " -0x7bfe: "Mie " -0x7bff: "Zhuan " -/* x07c */ -0x7c00: "Ze " -0x7c01: "Xi " -0x7c02: "Guo " -0x7c03: "Yi " -0x7c04: "Hu " -0x7c05: "Chan " -0x7c06: "Kou " -0x7c07: "Cu " -0x7c08: "Ping " -0x7c09: "Chou " -0x7c0a: "Ji " -0x7c0b: "Gui " -0x7c0c: "Su " -0x7c0d: "Lou " -0x7c0e: "Zha " -0x7c0f: "Lu " -0x7c10: "Nian " -0x7c11: "Suo " -0x7c12: "Cuan " -0x7c13: "Sasara " -0x7c14: "Suo " -0x7c15: "Le " -0x7c16: "Duan " -0x7c17: "Yana " -0x7c18: "Xiao " -0x7c19: "Bo " -0x7c1a: "Mi " -0x7c1b: "Si " -0x7c1c: "Dang " -0x7c1d: "Liao " -0x7c1e: "Dan " -0x7c1f: "Dian " -0x7c20: "Fu " -0x7c21: "Jian " -0x7c22: "Min " -0x7c23: "Kui " -0x7c24: "Dai " -0x7c25: "Qiao " -0x7c26: "Deng " -0x7c27: "Huang " -0x7c28: "Sun " -0x7c29: "Lao " -0x7c2a: "Zan " -0x7c2b: "Xiao " -0x7c2c: "Du " -0x7c2d: "Shi " -0x7c2e: "Zan " -0x7c2f: "[?] " -0x7c30: "Pai " -0x7c31: "Hata " -0x7c32: "Pai " -0x7c33: "Gan " -0x7c34: "Ju " -0x7c35: "Du " -0x7c36: "Lu " -0x7c37: "Yan " -0x7c38: "Bo " -0x7c39: "Dang " -0x7c3a: "Sai " -0x7c3b: "Ke " -0x7c3c: "Long " -0x7c3d: "Qian " -0x7c3e: "Lian " -0x7c3f: "Bo " -0x7c40: "Zhou " -0x7c41: "Lai " -0x7c42: "[?] " -0x7c43: "Lan " -0x7c44: "Kui " -0x7c45: "Yu " -0x7c46: "Yue " -0x7c47: "Hao " -0x7c48: "Zhen " -0x7c49: "Tai " -0x7c4a: "Ti " -0x7c4b: "Mi " -0x7c4c: "Chou " -0x7c4d: "Ji " -0x7c4e: "[?] " -0x7c4f: "Hata " -0x7c50: "Teng " -0x7c51: "Zhuan " -0x7c52: "Zhou " -0x7c53: "Fan " -0x7c54: "Sou " -0x7c55: "Zhou " -0x7c56: "Kuji " -0x7c57: "Zhuo " -0x7c58: "Teng " -0x7c59: "Lu " -0x7c5a: "Lu " -0x7c5b: "Jian " -0x7c5c: "Tuo " -0x7c5d: "Ying " -0x7c5e: "Yu " -0x7c5f: "Lai " -0x7c60: "Long " -0x7c61: "Shinshi " -0x7c62: "Lian " -0x7c63: "Lan " -0x7c64: "Qian " -0x7c65: "Yue " -0x7c66: "Zhong " -0x7c67: "Qu " -0x7c68: "Lian " -0x7c69: "Bian " -0x7c6a: "Duan " -0x7c6b: "Zuan " -0x7c6c: "Li " -0x7c6d: "Si " -0x7c6e: "Luo " -0x7c6f: "Ying " -0x7c70: "Yue " -0x7c71: "Zhuo " -0x7c72: "Xu " -0x7c73: "Mi " -0x7c74: "Di " -0x7c75: "Fan " -0x7c76: "Shen " -0x7c77: "Zhe " -0x7c78: "Shen " -0x7c79: "Nu " -0x7c7a: "Xie " -0x7c7b: "Lei " -0x7c7c: "Xian " -0x7c7d: "Zi " -0x7c7e: "Ni " -0x7c7f: "Cun " -0x7c80: "[?] " -0x7c81: "Qian " -0x7c82: "Kume " -0x7c83: "Bi " -0x7c84: "Ban " -0x7c85: "Wu " -0x7c86: "Sha " -0x7c87: "Kang " -0x7c88: "Rou " -0x7c89: "Fen " -0x7c8a: "Bi " -0x7c8b: "Cui " -0x7c8c: "[?] " -0x7c8d: "Li " -0x7c8e: "Chi " -0x7c8f: "Nukamiso " -0x7c90: "Ro " -0x7c91: "Ba " -0x7c92: "Li " -0x7c93: "Gan " -0x7c94: "Ju " -0x7c95: "Po " -0x7c96: "Mo " -0x7c97: "Cu " -0x7c98: "Nian " -0x7c99: "Zhou " -0x7c9a: "Li " -0x7c9b: "Su " -0x7c9c: "Tiao " -0x7c9d: "Li " -0x7c9e: "Qi " -0x7c9f: "Su " -0x7ca0: "Hong " -0x7ca1: "Tong " -0x7ca2: "Zi " -0x7ca3: "Ce " -0x7ca4: "Yue " -0x7ca5: "Zhou " -0x7ca6: "Lin " -0x7ca7: "Zhuang " -0x7ca8: "Bai " -0x7ca9: "[?] " -0x7caa: "Fen " -0x7cab: "Ji " -0x7cac: "[?] " -0x7cad: "Sukumo " -0x7cae: "Liang " -0x7caf: "Xian " -0x7cb0: "Fu " -0x7cb1: "Liang " -0x7cb2: "Can " -0x7cb3: "Geng " -0x7cb4: "Li " -0x7cb5: "Yue " -0x7cb6: "Lu " -0x7cb7: "Ju " -0x7cb8: "Qi " -0x7cb9: "Cui " -0x7cba: "Bai " -0x7cbb: "Zhang " -0x7cbc: "Lin " -0x7cbd: "Zong " -0x7cbe: "Jing " -0x7cbf: "Guo " -0x7cc0: "Kouji " -0x7cc1: "San " -0x7cc2: "San " -0x7cc3: "Tang " -0x7cc4: "Bian " -0x7cc5: "Rou " -0x7cc6: "Mian " -0x7cc7: "Hou " -0x7cc8: "Xu " -0x7cc9: "Zong " -0x7cca: "Hu " -0x7ccb: "Jian " -0x7ccc: "Zan " -0x7ccd: "Ci " -0x7cce: "Li " -0x7ccf: "Xie " -0x7cd0: "Fu " -0x7cd1: "Ni " -0x7cd2: "Bei " -0x7cd3: "Gu " -0x7cd4: "Xiu " -0x7cd5: "Gao " -0x7cd6: "Tang " -0x7cd7: "Qiu " -0x7cd8: "Sukumo " -0x7cd9: "Cao " -0x7cda: "Zhuang " -0x7cdb: "Tang " -0x7cdc: "Mi " -0x7cdd: "San " -0x7cde: "Fen " -0x7cdf: "Zao " -0x7ce0: "Kang " -0x7ce1: "Jiang " -0x7ce2: "Mo " -0x7ce3: "San " -0x7ce4: "San " -0x7ce5: "Nuo " -0x7ce6: "Xi " -0x7ce7: "Liang " -0x7ce8: "Jiang " -0x7ce9: "Kuai " -0x7cea: "Bo " -0x7ceb: "Huan " -0x7cec: "[?] " -0x7ced: "Zong " -0x7cee: "Xian " -0x7cef: "Nuo " -0x7cf0: "Tuan " -0x7cf1: "Nie " -0x7cf2: "Li " -0x7cf3: "Zuo " -0x7cf4: "Di " -0x7cf5: "Nie " -0x7cf6: "Tiao " -0x7cf7: "Lan " -0x7cf8: "Mi " -0x7cf9: "Jiao " -0x7cfa: "Jiu " -0x7cfb: "Xi " -0x7cfc: "Gong " -0x7cfd: "Zheng " -0x7cfe: "Jiu " -0x7cff: "You " -/* x07d */ -0x7d00: "Ji " -0x7d01: "Cha " -0x7d02: "Zhou " -0x7d03: "Xun " -0x7d04: "Yue " -0x7d05: "Hong " -0x7d06: "Yu " -0x7d07: "He " -0x7d08: "Wan " -0x7d09: "Ren " -0x7d0a: "Wen " -0x7d0b: "Wen " -0x7d0c: "Qiu " -0x7d0d: "Na " -0x7d0e: "Zi " -0x7d0f: "Tou " -0x7d10: "Niu " -0x7d11: "Fou " -0x7d12: "Jie " -0x7d13: "Shu " -0x7d14: "Chun " -0x7d15: "Pi " -0x7d16: "Yin " -0x7d17: "Sha " -0x7d18: "Hong " -0x7d19: "Zhi " -0x7d1a: "Ji " -0x7d1b: "Fen " -0x7d1c: "Yun " -0x7d1d: "Ren " -0x7d1e: "Dan " -0x7d1f: "Jin " -0x7d20: "Su " -0x7d21: "Fang " -0x7d22: "Suo " -0x7d23: "Cui " -0x7d24: "Jiu " -0x7d25: "Zha " -0x7d26: "Kinu " -0x7d27: "Jin " -0x7d28: "Fu " -0x7d29: "Zhi " -0x7d2a: "Ci " -0x7d2b: "Zi " -0x7d2c: "Chou " -0x7d2d: "Hong " -0x7d2e: "Zha " -0x7d2f: "Lei " -0x7d30: "Xi " -0x7d31: "Fu " -0x7d32: "Xie " -0x7d33: "Shen " -0x7d34: "Bei " -0x7d35: "Zhu " -0x7d36: "Qu " -0x7d37: "Ling " -0x7d38: "Zhu " -0x7d39: "Shao " -0x7d3a: "Gan " -0x7d3b: "Yang " -0x7d3c: "Fu " -0x7d3d: "Tuo " -0x7d3e: "Zhen " -0x7d3f: "Dai " -0x7d40: "Zhuo " -0x7d41: "Shi " -0x7d42: "Zhong " -0x7d43: "Xian " -0x7d44: "Zu " -0x7d45: "Jiong " -0x7d46: "Ban " -0x7d47: "Ju " -0x7d48: "Mo " -0x7d49: "Shu " -0x7d4a: "Zui " -0x7d4b: "Wata " -0x7d4c: "Jing " -0x7d4d: "Ren " -0x7d4e: "Heng " -0x7d4f: "Xie " -0x7d50: "Jie " -0x7d51: "Zhu " -0x7d52: "Chou " -0x7d53: "Gua " -0x7d54: "Bai " -0x7d55: "Jue " -0x7d56: "Kuang " -0x7d57: "Hu " -0x7d58: "Ci " -0x7d59: "Geng " -0x7d5a: "Geng " -0x7d5b: "Tao " -0x7d5c: "Xie " -0x7d5d: "Ku " -0x7d5e: "Jiao " -0x7d5f: "Quan " -0x7d60: "Gai " -0x7d61: "Luo " -0x7d62: "Xuan " -0x7d63: "Bing " -0x7d64: "Xian " -0x7d65: "Fu " -0x7d66: "Gei " -0x7d67: "Tong " -0x7d68: "Rong " -0x7d69: "Tiao " -0x7d6a: "Yin " -0x7d6b: "Lei " -0x7d6c: "Xie " -0x7d6d: "Quan " -0x7d6e: "Xu " -0x7d6f: "Lun " -0x7d70: "Die " -0x7d71: "Tong " -0x7d72: "Si " -0x7d73: "Jiang " -0x7d74: "Xiang " -0x7d75: "Hui " -0x7d76: "Jue " -0x7d77: "Zhi " -0x7d78: "Jian " -0x7d79: "Juan " -0x7d7a: "Chi " -0x7d7b: "Mian " -0x7d7c: "Zhen " -0x7d7d: "Lu " -0x7d7e: "Cheng " -0x7d7f: "Qiu " -0x7d80: "Shu " -0x7d81: "Bang " -0x7d82: "Tong " -0x7d83: "Xiao " -0x7d84: "Wan " -0x7d85: "Qin " -0x7d86: "Geng " -0x7d87: "Xiu " -0x7d88: "Ti " -0x7d89: "Xiu " -0x7d8a: "Xie " -0x7d8b: "Hong " -0x7d8c: "Xi " -0x7d8d: "Fu " -0x7d8e: "Ting " -0x7d8f: "Sui " -0x7d90: "Dui " -0x7d91: "Kun " -0x7d92: "Fu " -0x7d93: "Jing " -0x7d94: "Hu " -0x7d95: "Zhi " -0x7d96: "Yan " -0x7d97: "Jiong " -0x7d98: "Feng " -0x7d99: "Ji " -0x7d9a: "Sok " -0x7d9b: "Kase " -0x7d9c: "Zong " -0x7d9d: "Lin " -0x7d9e: "Duo " -0x7d9f: "Li " -0x7da0: "Lu " -0x7da1: "Liang " -0x7da2: "Chou " -0x7da3: "Quan " -0x7da4: "Shao " -0x7da5: "Qi " -0x7da6: "Qi " -0x7da7: "Zhun " -0x7da8: "Qi " -0x7da9: "Wan " -0x7daa: "Qian " -0x7dab: "Xian " -0x7dac: "Shou " -0x7dad: "Wei " -0x7dae: "Qi " -0x7daf: "Tao " -0x7db0: "Wan " -0x7db1: "Gang " -0x7db2: "Wang " -0x7db3: "Beng " -0x7db4: "Zhui " -0x7db5: "Cai " -0x7db6: "Guo " -0x7db7: "Cui " -0x7db8: "Lun " -0x7db9: "Liu " -0x7dba: "Qi " -0x7dbb: "Zhan " -0x7dbc: "Bei " -0x7dbd: "Chuo " -0x7dbe: "Ling " -0x7dbf: "Mian " -0x7dc0: "Qi " -0x7dc1: "Qie " -0x7dc2: "Tan " -0x7dc3: "Zong " -0x7dc4: "Gun " -0x7dc5: "Zou " -0x7dc6: "Yi " -0x7dc7: "Zi " -0x7dc8: "Xing " -0x7dc9: "Liang " -0x7dca: "Jin " -0x7dcb: "Fei " -0x7dcc: "Rui " -0x7dcd: "Min " -0x7dce: "Yu " -0x7dcf: "Zong " -0x7dd0: "Fan " -0x7dd1: "Lu " -0x7dd2: "Xu " -0x7dd3: "Yingl " -0x7dd4: "Zhang " -0x7dd5: "Kasuri " -0x7dd6: "Xu " -0x7dd7: "Xiang " -0x7dd8: "Jian " -0x7dd9: "Ke " -0x7dda: "Xian " -0x7ddb: "Ruan " -0x7ddc: "Mian " -0x7ddd: "Qi " -0x7dde: "Duan " -0x7ddf: "Zhong " -0x7de0: "Di " -0x7de1: "Min " -0x7de2: "Miao " -0x7de3: "Yuan " -0x7de4: "Xie " -0x7de5: "Bao " -0x7de6: "Si " -0x7de7: "Qiu " -0x7de8: "Bian " -0x7de9: "Huan " -0x7dea: "Geng " -0x7deb: "Cong " -0x7dec: "Mian " -0x7ded: "Wei " -0x7dee: "Fu " -0x7def: "Wei " -0x7df0: "Yu " -0x7df1: "Gou " -0x7df2: "Miao " -0x7df3: "Xie " -0x7df4: "Lian " -0x7df5: "Zong " -0x7df6: "Bian " -0x7df7: "Yun " -0x7df8: "Yin " -0x7df9: "Ti " -0x7dfa: "Gua " -0x7dfb: "Zhi " -0x7dfc: "Yun " -0x7dfd: "Cheng " -0x7dfe: "Chan " -0x7dff: "Dai " -/* x07e */ -0x7e00: "Xia " -0x7e01: "Yuan " -0x7e02: "Zong " -0x7e03: "Xu " -0x7e04: "Nawa " -0x7e05: "Odoshi " -0x7e06: "Geng " -0x7e07: "Sen " -0x7e08: "Ying " -0x7e09: "Jin " -0x7e0a: "Yi " -0x7e0b: "Zhui " -0x7e0c: "Ni " -0x7e0d: "Bang " -0x7e0e: "Gu " -0x7e0f: "Pan " -0x7e10: "Zhou " -0x7e11: "Jian " -0x7e12: "Cuo " -0x7e13: "Quan " -0x7e14: "Shuang " -0x7e15: "Yun " -0x7e16: "Xia " -0x7e17: "Shuai " -0x7e18: "Xi " -0x7e19: "Rong " -0x7e1a: "Tao " -0x7e1b: "Fu " -0x7e1c: "Yun " -0x7e1d: "Zhen " -0x7e1e: "Gao " -0x7e1f: "Ru " -0x7e20: "Hu " -0x7e21: "Zai " -0x7e22: "Teng " -0x7e23: "Xian " -0x7e24: "Su " -0x7e25: "Zhen " -0x7e26: "Zong " -0x7e27: "Tao " -0x7e28: "Horo " -0x7e29: "Cai " -0x7e2a: "Bi " -0x7e2b: "Feng " -0x7e2c: "Cu " -0x7e2d: "Li " -0x7e2e: "Suo " -0x7e2f: "Yin " -0x7e30: "Xi " -0x7e31: "Zong " -0x7e32: "Lei " -0x7e33: "Zhuan " -0x7e34: "Qian " -0x7e35: "Man " -0x7e36: "Zhi " -0x7e37: "Lu " -0x7e38: "Mo " -0x7e39: "Piao " -0x7e3a: "Lian " -0x7e3b: "Mi " -0x7e3c: "Xuan " -0x7e3d: "Zong " -0x7e3e: "Ji " -0x7e3f: "Shan " -0x7e40: "Sui " -0x7e41: "Fan " -0x7e42: "Shuai " -0x7e43: "Beng " -0x7e44: "Yi " -0x7e45: "Sao " -0x7e46: "Mou " -0x7e47: "Zhou " -0x7e48: "Qiang " -0x7e49: "Hun " -0x7e4a: "Sem " -0x7e4b: "Xi " -0x7e4c: "Jung " -0x7e4d: "Xiu " -0x7e4e: "Ran " -0x7e4f: "Xuan " -0x7e50: "Hui " -0x7e51: "Qiao " -0x7e52: "Zeng " -0x7e53: "Zuo " -0x7e54: "Zhi " -0x7e55: "Shan " -0x7e56: "San " -0x7e57: "Lin " -0x7e58: "Yu " -0x7e59: "Fan " -0x7e5a: "Liao " -0x7e5b: "Chuo " -0x7e5c: "Zun " -0x7e5d: "Jian " -0x7e5e: "Rao " -0x7e5f: "Chan " -0x7e60: "Rui " -0x7e61: "Xiu " -0x7e62: "Hui " -0x7e63: "Hua " -0x7e64: "Zuan " -0x7e65: "Xi " -0x7e66: "Qiang " -0x7e67: "Un " -0x7e68: "Da " -0x7e69: "Sheng " -0x7e6a: "Hui " -0x7e6b: "Xi " -0x7e6c: "Se " -0x7e6d: "Jian " -0x7e6e: "Jiang " -0x7e6f: "Huan " -0x7e70: "Zao " -0x7e71: "Cong " -0x7e72: "Jie " -0x7e73: "Jiao " -0x7e74: "Bo " -0x7e75: "Chan " -0x7e76: "Yi " -0x7e77: "Nao " -0x7e78: "Sui " -0x7e79: "Yi " -0x7e7a: "Shai " -0x7e7b: "Xu " -0x7e7c: "Ji " -0x7e7d: "Bin " -0x7e7e: "Qian " -0x7e7f: "Lan " -0x7e80: "Pu " -0x7e81: "Xun " -0x7e82: "Zuan " -0x7e83: "Qi " -0x7e84: "Peng " -0x7e85: "Li " -0x7e86: "Mo " -0x7e87: "Lei " -0x7e88: "Xie " -0x7e89: "Zuan " -0x7e8a: "Kuang " -0x7e8b: "You " -0x7e8c: "Xu " -0x7e8d: "Lei " -0x7e8e: "Xian " -0x7e8f: "Chan " -0x7e90: "Kou " -0x7e91: "Lu " -0x7e92: "Chan " -0x7e93: "Ying " -0x7e94: "Cai " -0x7e95: "Xiang " -0x7e96: "Xian " -0x7e97: "Zui " -0x7e98: "Zuan " -0x7e99: "Luo " -0x7e9a: "Xi " -0x7e9b: "Dao " -0x7e9c: "Lan " -0x7e9d: "Lei " -0x7e9e: "Lian " -0x7e9f: "Si " -0x7ea0: "Jiu " -0x7ea1: "Yu " -0x7ea2: "Hong " -0x7ea3: "Zhou " -0x7ea4: "Xian " -0x7ea5: "He " -0x7ea6: "Yue " -0x7ea7: "Ji " -0x7ea8: "Wan " -0x7ea9: "Kuang " -0x7eaa: "Ji " -0x7eab: "Ren " -0x7eac: "Wei " -0x7ead: "Yun " -0x7eae: "Hong " -0x7eaf: "Chun " -0x7eb0: "Pi " -0x7eb1: "Sha " -0x7eb2: "Gang " -0x7eb3: "Na " -0x7eb4: "Ren " -0x7eb5: "Zong " -0x7eb6: "Lun " -0x7eb7: "Fen " -0x7eb8: "Zhi " -0x7eb9: "Wen " -0x7eba: "Fang " -0x7ebb: "Zhu " -0x7ebc: "Yin " -0x7ebd: "Niu " -0x7ebe: "Shu " -0x7ebf: "Xian " -0x7ec0: "Gan " -0x7ec1: "Xie " -0x7ec2: "Fu " -0x7ec3: "Lian " -0x7ec4: "Zu " -0x7ec5: "Shen " -0x7ec6: "Xi " -0x7ec7: "Zhi " -0x7ec8: "Zhong " -0x7ec9: "Zhou " -0x7eca: "Ban " -0x7ecb: "Fu " -0x7ecc: "Zhuo " -0x7ecd: "Shao " -0x7ece: "Yi " -0x7ecf: "Jing " -0x7ed0: "Dai " -0x7ed1: "Bang " -0x7ed2: "Rong " -0x7ed3: "Jie " -0x7ed4: "Ku " -0x7ed5: "Rao " -0x7ed6: "Die " -0x7ed7: "Heng " -0x7ed8: "Hui " -0x7ed9: "Gei " -0x7eda: "Xuan " -0x7edb: "Jiang " -0x7edc: "Luo " -0x7edd: "Jue " -0x7ede: "Jiao " -0x7edf: "Tong " -0x7ee0: "Geng " -0x7ee1: "Xiao " -0x7ee2: "Juan " -0x7ee3: "Xiu " -0x7ee4: "Xi " -0x7ee5: "Sui " -0x7ee6: "Tao " -0x7ee7: "Ji " -0x7ee8: "Ti " -0x7ee9: "Ji " -0x7eea: "Xu " -0x7eeb: "Ling " -0x7eec: "[?] " -0x7eed: "Xu " -0x7eee: "Qi " -0x7eef: "Fei " -0x7ef0: "Chuo " -0x7ef1: "Zhang " -0x7ef2: "Gun " -0x7ef3: "Sheng " -0x7ef4: "Wei " -0x7ef5: "Mian " -0x7ef6: "Shou " -0x7ef7: "Beng " -0x7ef8: "Chou " -0x7ef9: "Tao " -0x7efa: "Liu " -0x7efb: "Quan " -0x7efc: "Zong " -0x7efd: "Zhan " -0x7efe: "Wan " -0x7eff: "Lu " -/* x07f */ -0x7f00: "Zhui " -0x7f01: "Zi " -0x7f02: "Ke " -0x7f03: "Xiang " -0x7f04: "Jian " -0x7f05: "Mian " -0x7f06: "Lan " -0x7f07: "Ti " -0x7f08: "Miao " -0x7f09: "Qi " -0x7f0a: "Yun " -0x7f0b: "Hui " -0x7f0c: "Si " -0x7f0d: "Duo " -0x7f0e: "Duan " -0x7f0f: "Bian " -0x7f10: "Xian " -0x7f11: "Gou " -0x7f12: "Zhui " -0x7f13: "Huan " -0x7f14: "Di " -0x7f15: "Lu " -0x7f16: "Bian " -0x7f17: "Min " -0x7f18: "Yuan " -0x7f19: "Jin " -0x7f1a: "Fu " -0x7f1b: "Ru " -0x7f1c: "Zhen " -0x7f1d: "Feng " -0x7f1e: "Shuai " -0x7f1f: "Gao " -0x7f20: "Chan " -0x7f21: "Li " -0x7f22: "Yi " -0x7f23: "Jian " -0x7f24: "Bin " -0x7f25: "Piao " -0x7f26: "Man " -0x7f27: "Lei " -0x7f28: "Ying " -0x7f29: "Suo " -0x7f2a: "Mou " -0x7f2b: "Sao " -0x7f2c: "Xie " -0x7f2d: "Liao " -0x7f2e: "Shan " -0x7f2f: "Zeng " -0x7f30: "Jiang " -0x7f31: "Qian " -0x7f32: "Zao " -0x7f33: "Huan " -0x7f34: "Jiao " -0x7f35: "Zuan " -0x7f36: "Fou " -0x7f37: "Xie " -0x7f38: "Gang " -0x7f39: "Fou " -0x7f3a: "Que " -0x7f3b: "Fou " -0x7f3c: "Kaakeru " -0x7f3d: "Bo " -0x7f3e: "Ping " -0x7f3f: "Hou " -0x7f40: "[?] " -0x7f41: "Gang " -0x7f42: "Ying " -0x7f43: "Ying " -0x7f44: "Qing " -0x7f45: "Xia " -0x7f46: "Guan " -0x7f47: "Zun " -0x7f48: "Tan " -0x7f49: "Chang " -0x7f4a: "Qi " -0x7f4b: "Weng " -0x7f4c: "Ying " -0x7f4d: "Lei " -0x7f4e: "Tan " -0x7f4f: "Lu " -0x7f50: "Guan " -0x7f51: "Wang " -0x7f52: "Wang " -0x7f53: "Gang " -0x7f54: "Wang " -0x7f55: "Han " -0x7f56: "[?] " -0x7f57: "Luo " -0x7f58: "Fu " -0x7f59: "Mi " -0x7f5a: "Fa " -0x7f5b: "Gu " -0x7f5c: "Zhu " -0x7f5d: "Ju " -0x7f5e: "Mao " -0x7f5f: "Gu " -0x7f60: "Min " -0x7f61: "Gang " -0x7f62: "Ba " -0x7f63: "Gua " -0x7f64: "Ti " -0x7f65: "Juan " -0x7f66: "Fu " -0x7f67: "Lin " -0x7f68: "Yan " -0x7f69: "Zhao " -0x7f6a: "Zui " -0x7f6b: "Gua " -0x7f6c: "Zhuo " -0x7f6d: "Yu " -0x7f6e: "Zhi " -0x7f6f: "An " -0x7f70: "Fa " -0x7f71: "Nan " -0x7f72: "Shu " -0x7f73: "Si " -0x7f74: "Pi " -0x7f75: "Ma " -0x7f76: "Liu " -0x7f77: "Ba " -0x7f78: "Fa " -0x7f79: "Li " -0x7f7a: "Chao " -0x7f7b: "Wei " -0x7f7c: "Bi " -0x7f7d: "Ji " -0x7f7e: "Zeng " -0x7f7f: "Tong " -0x7f80: "Liu " -0x7f81: "Ji " -0x7f82: "Juan " -0x7f83: "Mi " -0x7f84: "Zhao " -0x7f85: "Luo " -0x7f86: "Pi " -0x7f87: "Ji " -0x7f88: "Ji " -0x7f89: "Luan " -0x7f8a: "Yang " -0x7f8b: "Mie " -0x7f8c: "Qiang " -0x7f8d: "Ta " -0x7f8e: "Mei " -0x7f8f: "Yang " -0x7f90: "You " -0x7f91: "You " -0x7f92: "Fen " -0x7f93: "Ba " -0x7f94: "Gao " -0x7f95: "Yang " -0x7f96: "Gu " -0x7f97: "Qiang " -0x7f98: "Zang " -0x7f99: "Gao " -0x7f9a: "Ling " -0x7f9b: "Yi " -0x7f9c: "Zhu " -0x7f9d: "Di " -0x7f9e: "Xiu " -0x7f9f: "Qian " -0x7fa0: "Yi " -0x7fa1: "Xian " -0x7fa2: "Rong " -0x7fa3: "Qun " -0x7fa4: "Qun " -0x7fa5: "Qian " -0x7fa6: "Huan " -0x7fa7: "Zui " -0x7fa8: "Xian " -0x7fa9: "Yi " -0x7faa: "Yashinau " -0x7fab: "Qiang " -0x7fac: "Xian " -0x7fad: "Yu " -0x7fae: "Geng " -0x7faf: "Jie " -0x7fb0: "Tang " -0x7fb1: "Yuan " -0x7fb2: "Xi " -0x7fb3: "Fan " -0x7fb4: "Shan " -0x7fb5: "Fen " -0x7fb6: "Shan " -0x7fb7: "Lian " -0x7fb8: "Lei " -0x7fb9: "Geng " -0x7fba: "Nou " -0x7fbb: "Qiang " -0x7fbc: "Chan " -0x7fbd: "Yu " -0x7fbe: "Gong " -0x7fbf: "Yi " -0x7fc0: "Chong " -0x7fc1: "Weng " -0x7fc2: "Fen " -0x7fc3: "Hong " -0x7fc4: "Chi " -0x7fc5: "Chi " -0x7fc6: "Cui " -0x7fc7: "Fu " -0x7fc8: "Xia " -0x7fc9: "Pen " -0x7fca: "Yi " -0x7fcb: "La " -0x7fcc: "Yi " -0x7fcd: "Pi " -0x7fce: "Ling " -0x7fcf: "Liu " -0x7fd0: "Zhi " -0x7fd1: "Qu " -0x7fd2: "Xi " -0x7fd3: "Xie " -0x7fd4: "Xiang " -0x7fd5: "Xi " -0x7fd6: "Xi " -0x7fd7: "Qi " -0x7fd8: "Qiao " -0x7fd9: "Hui " -0x7fda: "Hui " -0x7fdb: "Xiao " -0x7fdc: "Se " -0x7fdd: "Hong " -0x7fde: "Jiang " -0x7fdf: "Di " -0x7fe0: "Cui " -0x7fe1: "Fei " -0x7fe2: "Tao " -0x7fe3: "Sha " -0x7fe4: "Chi " -0x7fe5: "Zhu " -0x7fe6: "Jian " -0x7fe7: "Xuan " -0x7fe8: "Shi " -0x7fe9: "Pian " -0x7fea: "Zong " -0x7feb: "Wan " -0x7fec: "Hui " -0x7fed: "Hou " -0x7fee: "He " -0x7fef: "He " -0x7ff0: "Han " -0x7ff1: "Ao " -0x7ff2: "Piao " -0x7ff3: "Yi " -0x7ff4: "Lian " -0x7ff5: "Qu " -0x7ff6: "[?] " -0x7ff7: "Lin " -0x7ff8: "Pen " -0x7ff9: "Qiao " -0x7ffa: "Ao " -0x7ffb: "Fan " -0x7ffc: "Yi " -0x7ffd: "Hui " -0x7ffe: "Xuan " -0x7fff: "Dao " -/* x080 */ -0x8000: "Yao " -0x8001: "Lao " -0x8002: "[?] " -0x8003: "Kao " -0x8004: "Mao " -0x8005: "Zhe " -0x8006: "Qi " -0x8007: "Gou " -0x8008: "Gou " -0x8009: "Gou " -0x800a: "Die " -0x800b: "Die " -0x800c: "Er " -0x800d: "Shua " -0x800e: "Ruan " -0x800f: "Er " -0x8010: "Nai " -0x8011: "Zhuan " -0x8012: "Lei " -0x8013: "Ting " -0x8014: "Zi " -0x8015: "Geng " -0x8016: "Chao " -0x8017: "Hao " -0x8018: "Yun " -0x8019: "Pa " -0x801a: "Pi " -0x801b: "Chi " -0x801c: "Si " -0x801d: "Chu " -0x801e: "Jia " -0x801f: "Ju " -0x8020: "He " -0x8021: "Chu " -0x8022: "Lao " -0x8023: "Lun " -0x8024: "Ji " -0x8025: "Tang " -0x8026: "Ou " -0x8027: "Lou " -0x8028: "Nou " -0x8029: "Gou " -0x802a: "Pang " -0x802b: "Ze " -0x802c: "Lou " -0x802d: "Ji " -0x802e: "Lao " -0x802f: "Huo " -0x8030: "You " -0x8031: "Mo " -0x8032: "Huai " -0x8033: "Er " -0x8034: "Zhe " -0x8035: "Ting " -0x8036: "Ye " -0x8037: "Da " -0x8038: "Song " -0x8039: "Qin " -0x803a: "Yun " -0x803b: "Chi " -0x803c: "Dan " -0x803d: "Dan " -0x803e: "Hong " -0x803f: "Geng " -0x8040: "Zhi " -0x8041: "[?] " -0x8042: "Nie " -0x8043: "Dan " -0x8044: "Zhen " -0x8045: "Che " -0x8046: "Ling " -0x8047: "Zheng " -0x8048: "You " -0x8049: "Wa " -0x804a: "Liao " -0x804b: "Long " -0x804c: "Zhi " -0x804d: "Ning " -0x804e: "Tiao " -0x804f: "Er " -0x8050: "Ya " -0x8051: "Die " -0x8052: "Gua " -0x8053: "[?] " -0x8054: "Lian " -0x8055: "Hao " -0x8056: "Sheng " -0x8057: "Lie " -0x8058: "Pin " -0x8059: "Jing " -0x805a: "Ju " -0x805b: "Bi " -0x805c: "Di " -0x805d: "Guo " -0x805e: "Wen " -0x805f: "Xu " -0x8060: "Ping " -0x8061: "Cong " -0x8062: "Shikato " -0x8063: "[?] " -0x8064: "Ting " -0x8065: "Yu " -0x8066: "Cong " -0x8067: "Kui " -0x8068: "Tsuraneru " -0x8069: "Kui " -0x806a: "Cong " -0x806b: "Lian " -0x806c: "Weng " -0x806d: "Kui " -0x806e: "Lian " -0x806f: "Lian " -0x8070: "Cong " -0x8071: "Ao " -0x8072: "Sheng " -0x8073: "Song " -0x8074: "Ting " -0x8075: "Kui " -0x8076: "Nie " -0x8077: "Zhi " -0x8078: "Dan " -0x8079: "Ning " -0x807a: "Qie " -0x807b: "Ji " -0x807c: "Ting " -0x807d: "Ting " -0x807e: "Long " -0x807f: "Yu " -0x8080: "Yu " -0x8081: "Zhao " -0x8082: "Si " -0x8083: "Su " -0x8084: "Yi " -0x8085: "Su " -0x8086: "Si " -0x8087: "Zhao " -0x8088: "Zhao " -0x8089: "Rou " -0x808a: "Yi " -0x808b: "Le " -0x808c: "Ji " -0x808d: "Qiu " -0x808e: "Ken " -0x808f: "Cao " -0x8090: "Ge " -0x8091: "Di " -0x8092: "Huan " -0x8093: "Huang " -0x8094: "Yi " -0x8095: "Ren " -0x8096: "Xiao " -0x8097: "Ru " -0x8098: "Zhou " -0x8099: "Yuan " -0x809a: "Du " -0x809b: "Gang " -0x809c: "Rong " -0x809d: "Gan " -0x809e: "Cha " -0x809f: "Wo " -0x80a0: "Chang " -0x80a1: "Gu " -0x80a2: "Zhi " -0x80a3: "Han " -0x80a4: "Fu " -0x80a5: "Fei " -0x80a6: "Fen " -0x80a7: "Pei " -0x80a8: "Pang " -0x80a9: "Jian " -0x80aa: "Fang " -0x80ab: "Zhun " -0x80ac: "You " -0x80ad: "Na " -0x80ae: "Hang " -0x80af: "Ken " -0x80b0: "Ran " -0x80b1: "Gong " -0x80b2: "Yu " -0x80b3: "Wen " -0x80b4: "Yao " -0x80b5: "Jin " -0x80b6: "Pi " -0x80b7: "Qian " -0x80b8: "Xi " -0x80b9: "Xi " -0x80ba: "Fei " -0x80bb: "Ken " -0x80bc: "Jing " -0x80bd: "Tai " -0x80be: "Shen " -0x80bf: "Zhong " -0x80c0: "Zhang " -0x80c1: "Xie " -0x80c2: "Shen " -0x80c3: "Wei " -0x80c4: "Zhou " -0x80c5: "Die " -0x80c6: "Dan " -0x80c7: "Fei " -0x80c8: "Ba " -0x80c9: "Bo " -0x80ca: "Qu " -0x80cb: "Tian " -0x80cc: "Bei " -0x80cd: "Gua " -0x80ce: "Tai " -0x80cf: "Zi " -0x80d0: "Ku " -0x80d1: "Zhi " -0x80d2: "Ni " -0x80d3: "Ping " -0x80d4: "Zi " -0x80d5: "Fu " -0x80d6: "Pang " -0x80d7: "Zhen " -0x80d8: "Xian " -0x80d9: "Zuo " -0x80da: "Pei " -0x80db: "Jia " -0x80dc: "Sheng " -0x80dd: "Zhi " -0x80de: "Bao " -0x80df: "Mu " -0x80e0: "Qu " -0x80e1: "Hu " -0x80e2: "Ke " -0x80e3: "Yi " -0x80e4: "Yin " -0x80e5: "Xu " -0x80e6: "Yang " -0x80e7: "Long " -0x80e8: "Dong " -0x80e9: "Ka " -0x80ea: "Lu " -0x80eb: "Jing " -0x80ec: "Nu " -0x80ed: "Yan " -0x80ee: "Pang " -0x80ef: "Kua " -0x80f0: "Yi " -0x80f1: "Guang " -0x80f2: "Gai " -0x80f3: "Ge " -0x80f4: "Dong " -0x80f5: "Zhi " -0x80f6: "Xiao " -0x80f7: "Xiong " -0x80f8: "Xiong " -0x80f9: "Er " -0x80fa: "E " -0x80fb: "Xing " -0x80fc: "Pian " -0x80fd: "Neng " -0x80fe: "Zi " -0x80ff: "Gui " -/* x081 */ -0x8100: "Cheng " -0x8101: "Tiao " -0x8102: "Zhi " -0x8103: "Cui " -0x8104: "Mei " -0x8105: "Xie " -0x8106: "Cui " -0x8107: "Xie " -0x8108: "Mo " -0x8109: "Mai " -0x810a: "Ji " -0x810b: "Obiyaakasu " -0x810c: "[?] " -0x810d: "Kuai " -0x810e: "Sa " -0x810f: "Zang " -0x8110: "Qi " -0x8111: "Nao " -0x8112: "Mi " -0x8113: "Nong " -0x8114: "Luan " -0x8115: "Wan " -0x8116: "Bo " -0x8117: "Wen " -0x8118: "Guan " -0x8119: "Qiu " -0x811a: "Jiao " -0x811b: "Jing " -0x811c: "Rou " -0x811d: "Heng " -0x811e: "Cuo " -0x811f: "Lie " -0x8120: "Shan " -0x8121: "Ting " -0x8122: "Mei " -0x8123: "Chun " -0x8124: "Shen " -0x8125: "Xie " -0x8126: "De " -0x8127: "Zui " -0x8128: "Cu " -0x8129: "Xiu " -0x812a: "Xin " -0x812b: "Tuo " -0x812c: "Pao " -0x812d: "Cheng " -0x812e: "Nei " -0x812f: "Fu " -0x8130: "Dou " -0x8131: "Tuo " -0x8132: "Niao " -0x8133: "Noy " -0x8134: "Pi " -0x8135: "Gu " -0x8136: "Gua " -0x8137: "Li " -0x8138: "Lian " -0x8139: "Zhang " -0x813a: "Cui " -0x813b: "Jie " -0x813c: "Liang " -0x813d: "Zhou " -0x813e: "Pi " -0x813f: "Biao " -0x8140: "Lun " -0x8141: "Pian " -0x8142: "Guo " -0x8143: "Kui " -0x8144: "Chui " -0x8145: "Dan " -0x8146: "Tian " -0x8147: "Nei " -0x8148: "Jing " -0x8149: "Jie " -0x814a: "La " -0x814b: "Yi " -0x814c: "An " -0x814d: "Ren " -0x814e: "Shen " -0x814f: "Chuo " -0x8150: "Fu " -0x8151: "Fu " -0x8152: "Ju " -0x8153: "Fei " -0x8154: "Qiang " -0x8155: "Wan " -0x8156: "Dong " -0x8157: "Pi " -0x8158: "Guo " -0x8159: "Zong " -0x815a: "Ding " -0x815b: "Wu " -0x815c: "Mei " -0x815d: "Ruan " -0x815e: "Zhuan " -0x815f: "Zhi " -0x8160: "Cou " -0x8161: "Gua " -0x8162: "Ou " -0x8163: "Di " -0x8164: "An " -0x8165: "Xing " -0x8166: "Nao " -0x8167: "Yu " -0x8168: "Chuan " -0x8169: "Nan " -0x816a: "Yun " -0x816b: "Zhong " -0x816c: "Rou " -0x816d: "E " -0x816e: "Sai " -0x816f: "Tu " -0x8170: "Yao " -0x8171: "Jian " -0x8172: "Wei " -0x8173: "Jiao " -0x8174: "Yu " -0x8175: "Jia " -0x8176: "Duan " -0x8177: "Bi " -0x8178: "Chang " -0x8179: "Fu " -0x817a: "Xian " -0x817b: "Ni " -0x817c: "Mian " -0x817d: "Wa " -0x817e: "Teng " -0x817f: "Tui " -0x8180: "Bang " -0x8181: "Qian " -0x8182: "Lu " -0x8183: "Wa " -0x8184: "Sou " -0x8185: "Tang " -0x8186: "Su " -0x8187: "Zhui " -0x8188: "Ge " -0x8189: "Yi " -0x818a: "Bo " -0x818b: "Liao " -0x818c: "Ji " -0x818d: "Pi " -0x818e: "Xie " -0x818f: "Gao " -0x8190: "Lu " -0x8191: "Bin " -0x8192: "Ou " -0x8193: "Chang " -0x8194: "Lu " -0x8195: "Guo " -0x8196: "Pang " -0x8197: "Chuai " -0x8198: "Piao " -0x8199: "Jiang " -0x819a: "Fu " -0x819b: "Tang " -0x819c: "Mo " -0x819d: "Xi " -0x819e: "Zhuan " -0x819f: "Lu " -0x81a0: "Jiao " -0x81a1: "Ying " -0x81a2: "Lu " -0x81a3: "Zhi " -0x81a4: "Tara " -0x81a5: "Chun " -0x81a6: "Lian " -0x81a7: "Tong " -0x81a8: "Peng " -0x81a9: "Ni " -0x81aa: "Zha " -0x81ab: "Liao " -0x81ac: "Cui " -0x81ad: "Gui " -0x81ae: "Xiao " -0x81af: "Teng " -0x81b0: "Fan " -0x81b1: "Zhi " -0x81b2: "Jiao " -0x81b3: "Shan " -0x81b4: "Wu " -0x81b5: "Cui " -0x81b6: "Run " -0x81b7: "Xiang " -0x81b8: "Sui " -0x81b9: "Fen " -0x81ba: "Ying " -0x81bb: "Tan " -0x81bc: "Zhua " -0x81bd: "Dan " -0x81be: "Kuai " -0x81bf: "Nong " -0x81c0: "Tun " -0x81c1: "Lian " -0x81c2: "Bi " -0x81c3: "Yong " -0x81c4: "Jue " -0x81c5: "Chu " -0x81c6: "Yi " -0x81c7: "Juan " -0x81c8: "La " -0x81c9: "Lian " -0x81ca: "Sao " -0x81cb: "Tun " -0x81cc: "Gu " -0x81cd: "Qi " -0x81ce: "Cui " -0x81cf: "Bin " -0x81d0: "Xun " -0x81d1: "Ru " -0x81d2: "Huo " -0x81d3: "Zang " -0x81d4: "Xian " -0x81d5: "Biao " -0x81d6: "Xing " -0x81d7: "Kuan " -0x81d8: "La " -0x81d9: "Yan " -0x81da: "Lu " -0x81db: "Huo " -0x81dc: "Zang " -0x81dd: "Luo " -0x81de: "Qu " -0x81df: "Zang " -0x81e0: "Luan " -0x81e1: "Ni " -0x81e2: "Zang " -0x81e3: "Chen " -0x81e4: "Qian " -0x81e5: "Wo " -0x81e6: "Guang " -0x81e7: "Zang " -0x81e8: "Lin " -0x81e9: "Guang " -0x81ea: "Zi " -0x81eb: "Jiao " -0x81ec: "Nie " -0x81ed: "Chou " -0x81ee: "Ji " -0x81ef: "Gao " -0x81f0: "Chou " -0x81f1: "Mian " -0x81f2: "Nie " -0x81f3: "Zhi " -0x81f4: "Zhi " -0x81f5: "Ge " -0x81f6: "Jian " -0x81f7: "Die " -0x81f8: "Zhi " -0x81f9: "Xiu " -0x81fa: "Tai " -0x81fb: "Zhen " -0x81fc: "Jiu " -0x81fd: "Xian " -0x81fe: "Yu " -0x81ff: "Cha " -/* x082 */ -0x8200: "Yao " -0x8201: "Yu " -0x8202: "Chong " -0x8203: "Xi " -0x8204: "Xi " -0x8205: "Jiu " -0x8206: "Yu " -0x8207: "Yu " -0x8208: "Xing " -0x8209: "Ju " -0x820a: "Jiu " -0x820b: "Xin " -0x820c: "She " -0x820d: "She " -0x820e: "Yadoru " -0x820f: "Jiu " -0x8210: "Shi " -0x8211: "Tan " -0x8212: "Shu " -0x8213: "Shi " -0x8214: "Tian " -0x8215: "Dan " -0x8216: "Pu " -0x8217: "Pu " -0x8218: "Guan " -0x8219: "Hua " -0x821a: "Tan " -0x821b: "Chuan " -0x821c: "Shun " -0x821d: "Xia " -0x821e: "Wu " -0x821f: "Zhou " -0x8220: "Dao " -0x8221: "Gang " -0x8222: "Shan " -0x8223: "Yi " -0x8224: "[?] " -0x8225: "Pa " -0x8226: "Tai " -0x8227: "Fan " -0x8228: "Ban " -0x8229: "Chuan " -0x822a: "Hang " -0x822b: "Fang " -0x822c: "Ban " -0x822d: "Que " -0x822e: "Hesaki " -0x822f: "Zhong " -0x8230: "Jian " -0x8231: "Cang " -0x8232: "Ling " -0x8233: "Zhu " -0x8234: "Ze " -0x8235: "Duo " -0x8236: "Bo " -0x8237: "Xian " -0x8238: "Ge " -0x8239: "Chuan " -0x823a: "Jia " -0x823b: "Lu " -0x823c: "Hong " -0x823d: "Pang " -0x823e: "Xi " -0x823f: "[?] " -0x8240: "Fu " -0x8241: "Zao " -0x8242: "Feng " -0x8243: "Li " -0x8244: "Shao " -0x8245: "Yu " -0x8246: "Lang " -0x8247: "Ting " -0x8248: "[?] " -0x8249: "Wei " -0x824a: "Bo " -0x824b: "Meng " -0x824c: "Nian " -0x824d: "Ju " -0x824e: "Huang " -0x824f: "Shou " -0x8250: "Zong " -0x8251: "Bian " -0x8252: "Mao " -0x8253: "Die " -0x8254: "[?] " -0x8255: "Bang " -0x8256: "Cha " -0x8257: "Yi " -0x8258: "Sao " -0x8259: "Cang " -0x825a: "Cao " -0x825b: "Lou " -0x825c: "Dai " -0x825d: "Sori " -0x825e: "Yao " -0x825f: "Tong " -0x8260: "Yofune " -0x8261: "Dang " -0x8262: "Tan " -0x8263: "Lu " -0x8264: "Yi " -0x8265: "Jie " -0x8266: "Jian " -0x8267: "Huo " -0x8268: "Meng " -0x8269: "Qi " -0x826a: "Lu " -0x826b: "Lu " -0x826c: "Chan " -0x826d: "Shuang " -0x826e: "Gen " -0x826f: "Liang " -0x8270: "Jian " -0x8271: "Jian " -0x8272: "Se " -0x8273: "Yan " -0x8274: "Fu " -0x8275: "Ping " -0x8276: "Yan " -0x8277: "Yan " -0x8278: "Cao " -0x8279: "Cao " -0x827a: "Yi " -0x827b: "Le " -0x827c: "Ting " -0x827d: "Qiu " -0x827e: "Ai " -0x827f: "Nai " -0x8280: "Tiao " -0x8281: "Jiao " -0x8282: "Jie " -0x8283: "Peng " -0x8284: "Wan " -0x8285: "Yi " -0x8286: "Chai " -0x8287: "Mian " -0x8288: "Mie " -0x8289: "Gan " -0x828a: "Qian " -0x828b: "Yu " -0x828c: "Yu " -0x828d: "Shuo " -0x828e: "Qiong " -0x828f: "Tu " -0x8290: "Xia " -0x8291: "Qi " -0x8292: "Mang " -0x8293: "Zi " -0x8294: "Hui " -0x8295: "Sui " -0x8296: "Zhi " -0x8297: "Xiang " -0x8298: "Bi " -0x8299: "Fu " -0x829a: "Tun " -0x829b: "Wei " -0x829c: "Wu " -0x829d: "Zhi " -0x829e: "Qi " -0x829f: "Shan " -0x82a0: "Wen " -0x82a1: "Qian " -0x82a2: "Ren " -0x82a3: "Fou " -0x82a4: "Kou " -0x82a5: "Jie " -0x82a6: "Lu " -0x82a7: "Xu " -0x82a8: "Ji " -0x82a9: "Qin " -0x82aa: "Qi " -0x82ab: "Yuan " -0x82ac: "Fen " -0x82ad: "Ba " -0x82ae: "Rui " -0x82af: "Xin " -0x82b0: "Ji " -0x82b1: "Hua " -0x82b2: "Hua " -0x82b3: "Fang " -0x82b4: "Wu " -0x82b5: "Jue " -0x82b6: "Gou " -0x82b7: "Zhi " -0x82b8: "Yun " -0x82b9: "Qin " -0x82ba: "Ao " -0x82bb: "Chu " -0x82bc: "Mao " -0x82bd: "Ya " -0x82be: "Fei " -0x82bf: "Reng " -0x82c0: "Hang " -0x82c1: "Cong " -0x82c2: "Yin " -0x82c3: "You " -0x82c4: "Bian " -0x82c5: "Yi " -0x82c6: "Susa " -0x82c7: "Wei " -0x82c8: "Li " -0x82c9: "Pi " -0x82ca: "E " -0x82cb: "Xian " -0x82cc: "Chang " -0x82cd: "Cang " -0x82ce: "Meng " -0x82cf: "Su " -0x82d0: "Yi " -0x82d1: "Yuan " -0x82d2: "Ran " -0x82d3: "Ling " -0x82d4: "Tai " -0x82d5: "Tiao " -0x82d6: "Di " -0x82d7: "Miao " -0x82d8: "Qiong " -0x82d9: "Li " -0x82da: "Yong " -0x82db: "Ke " -0x82dc: "Mu " -0x82dd: "Pei " -0x82de: "Bao " -0x82df: "Gou " -0x82e0: "Min " -0x82e1: "Yi " -0x82e2: "Yi " -0x82e3: "Ju " -0x82e4: "Pi " -0x82e5: "Ruo " -0x82e6: "Ku " -0x82e7: "Zhu " -0x82e8: "Ni " -0x82e9: "Bo " -0x82ea: "Bing " -0x82eb: "Shan " -0x82ec: "Qiu " -0x82ed: "Yao " -0x82ee: "Xian " -0x82ef: "Ben " -0x82f0: "Hong " -0x82f1: "Ying " -0x82f2: "Zha " -0x82f3: "Dong " -0x82f4: "Ju " -0x82f5: "Die " -0x82f6: "Nie " -0x82f7: "Gan " -0x82f8: "Hu " -0x82f9: "Ping " -0x82fa: "Mei " -0x82fb: "Fu " -0x82fc: "Sheng " -0x82fd: "Gu " -0x82fe: "Bi " -0x82ff: "Wei " -/* x083 */ -0x8300: "Fu " -0x8301: "Zhuo " -0x8302: "Mao " -0x8303: "Fan " -0x8304: "Qie " -0x8305: "Mao " -0x8306: "Mao " -0x8307: "Ba " -0x8308: "Zi " -0x8309: "Mo " -0x830a: "Zi " -0x830b: "Di " -0x830c: "Chi " -0x830d: "Ji " -0x830e: "Jing " -0x830f: "Long " -0x8310: "[?] " -0x8311: "Niao " -0x8312: "[?] " -0x8313: "Xue " -0x8314: "Ying " -0x8315: "Qiong " -0x8316: "Ge " -0x8317: "Ming " -0x8318: "Li " -0x8319: "Rong " -0x831a: "Yin " -0x831b: "Gen " -0x831c: "Qian " -0x831d: "Chai " -0x831e: "Chen " -0x831f: "Yu " -0x8320: "Xiu " -0x8321: "Zi " -0x8322: "Lie " -0x8323: "Wu " -0x8324: "Ji " -0x8325: "Kui " -0x8326: "Ce " -0x8327: "Chong " -0x8328: "Ci " -0x8329: "Gou " -0x832a: "Guang " -0x832b: "Mang " -0x832c: "Chi " -0x832d: "Jiao " -0x832e: "Jiao " -0x832f: "Fu " -0x8330: "Yu " -0x8331: "Zhu " -0x8332: "Zi " -0x8333: "Jiang " -0x8334: "Hui " -0x8335: "Yin " -0x8336: "Cha " -0x8337: "Fa " -0x8338: "Rong " -0x8339: "Ru " -0x833a: "Chong " -0x833b: "Mang " -0x833c: "Tong " -0x833d: "Zhong " -0x833e: "[?] " -0x833f: "Zhu " -0x8340: "Xun " -0x8341: "Huan " -0x8342: "Kua " -0x8343: "Quan " -0x8344: "Gai " -0x8345: "Da " -0x8346: "Jing " -0x8347: "Xing " -0x8348: "Quan " -0x8349: "Cao " -0x834a: "Jing " -0x834b: "Er " -0x834c: "An " -0x834d: "Shou " -0x834e: "Chi " -0x834f: "Ren " -0x8350: "Jian " -0x8351: "Ti " -0x8352: "Huang " -0x8353: "Ping " -0x8354: "Li " -0x8355: "Jin " -0x8356: "Lao " -0x8357: "Shu " -0x8358: "Zhuang " -0x8359: "Da " -0x835a: "Jia " -0x835b: "Rao " -0x835c: "Bi " -0x835d: "Ze " -0x835e: "Qiao " -0x835f: "Hui " -0x8360: "Qi " -0x8361: "Dang " -0x8362: "[?] " -0x8363: "Rong " -0x8364: "Hun " -0x8365: "Ying " -0x8366: "Luo " -0x8367: "Ying " -0x8368: "Xun " -0x8369: "Jin " -0x836a: "Sun " -0x836b: "Yin " -0x836c: "Mai " -0x836d: "Hong " -0x836e: "Zhou " -0x836f: "Yao " -0x8370: "Du " -0x8371: "Wei " -0x8372: "Chu " -0x8373: "Dou " -0x8374: "Fu " -0x8375: "Ren " -0x8376: "Yin " -0x8377: "He " -0x8378: "Bi " -0x8379: "Bu " -0x837a: "Yun " -0x837b: "Di " -0x837c: "Tu " -0x837d: "Sui " -0x837e: "Sui " -0x837f: "Cheng " -0x8380: "Chen " -0x8381: "Wu " -0x8382: "Bie " -0x8383: "Xi " -0x8384: "Geng " -0x8385: "Li " -0x8386: "Fu " -0x8387: "Zhu " -0x8388: "Mo " -0x8389: "Li " -0x838a: "Zhuang " -0x838b: "Ji " -0x838c: "Duo " -0x838d: "Qiu " -0x838e: "Sha " -0x838f: "Suo " -0x8390: "Chen " -0x8391: "Feng " -0x8392: "Ju " -0x8393: "Mei " -0x8394: "Meng " -0x8395: "Xing " -0x8396: "Jing " -0x8397: "Che " -0x8398: "Xin " -0x8399: "Jun " -0x839a: "Yan " -0x839b: "Ting " -0x839c: "Diao " -0x839d: "Cuo " -0x839e: "Wan " -0x839f: "Han " -0x83a0: "You " -0x83a1: "Cuo " -0x83a2: "Jia " -0x83a3: "Wang " -0x83a4: "You " -0x83a5: "Niu " -0x83a6: "Shao " -0x83a7: "Xian " -0x83a8: "Lang " -0x83a9: "Fu " -0x83aa: "E " -0x83ab: "Mo " -0x83ac: "Wen " -0x83ad: "Jie " -0x83ae: "Nan " -0x83af: "Mu " -0x83b0: "Kan " -0x83b1: "Lai " -0x83b2: "Lian " -0x83b3: "Shi " -0x83b4: "Wo " -0x83b5: "Usagi " -0x83b6: "Lian " -0x83b7: "Huo " -0x83b8: "You " -0x83b9: "Ying " -0x83ba: "Ying " -0x83bb: "Nuc " -0x83bc: "Chun " -0x83bd: "Mang " -0x83be: "Mang " -0x83bf: "Ci " -0x83c0: "Wan " -0x83c1: "Jing " -0x83c2: "Di " -0x83c3: "Qu " -0x83c4: "Dong " -0x83c5: "Jian " -0x83c6: "Zou " -0x83c7: "Gu " -0x83c8: "La " -0x83c9: "Lu " -0x83ca: "Ju " -0x83cb: "Wei " -0x83cc: "Jun " -0x83cd: "Nie " -0x83ce: "Kun " -0x83cf: "He " -0x83d0: "Pu " -0x83d1: "Zi " -0x83d2: "Gao " -0x83d3: "Guo " -0x83d4: "Fu " -0x83d5: "Lun " -0x83d6: "Chang " -0x83d7: "Chou " -0x83d8: "Song " -0x83d9: "Chui " -0x83da: "Zhan " -0x83db: "Men " -0x83dc: "Cai " -0x83dd: "Ba " -0x83de: "Li " -0x83df: "Tu " -0x83e0: "Bo " -0x83e1: "Han " -0x83e2: "Bao " -0x83e3: "Qin " -0x83e4: "Juan " -0x83e5: "Xi " -0x83e6: "Qin " -0x83e7: "Di " -0x83e8: "Jie " -0x83e9: "Pu " -0x83ea: "Dang " -0x83eb: "Jin " -0x83ec: "Zhao " -0x83ed: "Tai " -0x83ee: "Geng " -0x83ef: "Hua " -0x83f0: "Gu " -0x83f1: "Ling " -0x83f2: "Fei " -0x83f3: "Jin " -0x83f4: "An " -0x83f5: "Wang " -0x83f6: "Beng " -0x83f7: "Zhou " -0x83f8: "Yan " -0x83f9: "Ju " -0x83fa: "Jian " -0x83fb: "Lin " -0x83fc: "Tan " -0x83fd: "Shu " -0x83fe: "Tian " -0x83ff: "Dao " -/* x084 */ -0x8400: "Hu " -0x8401: "Qi " -0x8402: "He " -0x8403: "Cui " -0x8404: "Tao " -0x8405: "Chun " -0x8406: "Bei " -0x8407: "Chang " -0x8408: "Huan " -0x8409: "Fei " -0x840a: "Lai " -0x840b: "Qi " -0x840c: "Meng " -0x840d: "Ping " -0x840e: "Wei " -0x840f: "Dan " -0x8410: "Sha " -0x8411: "Huan " -0x8412: "Yan " -0x8413: "Yi " -0x8414: "Tiao " -0x8415: "Qi " -0x8416: "Wan " -0x8417: "Ce " -0x8418: "Nai " -0x8419: "Kutabireru " -0x841a: "Tuo " -0x841b: "Jiu " -0x841c: "Tie " -0x841d: "Luo " -0x841e: "[?] " -0x841f: "[?] " -0x8420: "Meng " -0x8421: "[?] " -0x8422: "Yaji " -0x8423: "[?] " -0x8424: "Ying " -0x8425: "Ying " -0x8426: "Ying " -0x8427: "Xiao " -0x8428: "Sa " -0x8429: "Qiu " -0x842a: "Ke " -0x842b: "Xiang " -0x842c: "Wan " -0x842d: "Yu " -0x842e: "Yu " -0x842f: "Fu " -0x8430: "Lian " -0x8431: "Xuan " -0x8432: "Yuan " -0x8433: "Nan " -0x8434: "Ze " -0x8435: "Wo " -0x8436: "Chun " -0x8437: "Xiao " -0x8438: "Yu " -0x8439: "Pian " -0x843a: "Mao " -0x843b: "An " -0x843c: "E " -0x843d: "Luo " -0x843e: "Ying " -0x843f: "Huo " -0x8440: "Gua " -0x8441: "Jiang " -0x8442: "Mian " -0x8443: "Zuo " -0x8444: "Zuo " -0x8445: "Ju " -0x8446: "Bao " -0x8447: "Rou " -0x8448: "Xi " -0x8449: "Xie " -0x844a: "An " -0x844b: "Qu " -0x844c: "Jian " -0x844d: "Fu " -0x844e: "Lu " -0x844f: "Jing " -0x8450: "Pen " -0x8451: "Feng " -0x8452: "Hong " -0x8453: "Hong " -0x8454: "Hou " -0x8455: "Yan " -0x8456: "Tu " -0x8457: "Zhu " -0x8458: "Zi " -0x8459: "Xiang " -0x845a: "Shen " -0x845b: "Ge " -0x845c: "Jie " -0x845d: "Jing " -0x845e: "Mi " -0x845f: "Huang " -0x8460: "Shen " -0x8461: "Pu " -0x8462: "Gai " -0x8463: "Dong " -0x8464: "Zhou " -0x8465: "Qian " -0x8466: "Wei " -0x8467: "Bo " -0x8468: "Wei " -0x8469: "Pa " -0x846a: "Ji " -0x846b: "Hu " -0x846c: "Zang " -0x846d: "Jia " -0x846e: "Duan " -0x846f: "Yao " -0x8470: "Jun " -0x8471: "Cong " -0x8472: "Quan " -0x8473: "Wei " -0x8474: "Xian " -0x8475: "Kui " -0x8476: "Ting " -0x8477: "Hun " -0x8478: "Xi " -0x8479: "Shi " -0x847a: "Qi " -0x847b: "Lan " -0x847c: "Zong " -0x847d: "Yao " -0x847e: "Yuan " -0x847f: "Mei " -0x8480: "Yun " -0x8481: "Shu " -0x8482: "Di " -0x8483: "Zhuan " -0x8484: "Guan " -0x8485: "Sukumo " -0x8486: "Xue " -0x8487: "Chan " -0x8488: "Kai " -0x8489: "Kui " -0x848a: "[?] " -0x848b: "Jiang " -0x848c: "Lou " -0x848d: "Wei " -0x848e: "Pai " -0x848f: "[?] " -0x8490: "Sou " -0x8491: "Yin " -0x8492: "Shi " -0x8493: "Chun " -0x8494: "Shi " -0x8495: "Yun " -0x8496: "Zhen " -0x8497: "Lang " -0x8498: "Nu " -0x8499: "Meng " -0x849a: "He " -0x849b: "Que " -0x849c: "Suan " -0x849d: "Yuan " -0x849e: "Li " -0x849f: "Ju " -0x84a0: "Xi " -0x84a1: "Pang " -0x84a2: "Chu " -0x84a3: "Xu " -0x84a4: "Tu " -0x84a5: "Liu " -0x84a6: "Wo " -0x84a7: "Zhen " -0x84a8: "Qian " -0x84a9: "Zu " -0x84aa: "Po " -0x84ab: "Cuo " -0x84ac: "Yuan " -0x84ad: "Chu " -0x84ae: "Yu " -0x84af: "Kuai " -0x84b0: "Pan " -0x84b1: "Pu " -0x84b2: "Pu " -0x84b3: "Na " -0x84b4: "Shuo " -0x84b5: "Xi " -0x84b6: "Fen " -0x84b7: "Yun " -0x84b8: "Zheng " -0x84b9: "Jian " -0x84ba: "Ji " -0x84bb: "Ruo " -0x84bc: "Cang " -0x84bd: "En " -0x84be: "Mi " -0x84bf: "Hao " -0x84c0: "Sun " -0x84c1: "Zhen " -0x84c2: "Ming " -0x84c3: "Sou " -0x84c4: "Xu " -0x84c5: "Liu " -0x84c6: "Xi " -0x84c7: "Gu " -0x84c8: "Lang " -0x84c9: "Rong " -0x84ca: "Weng " -0x84cb: "Gai " -0x84cc: "Cuo " -0x84cd: "Shi " -0x84ce: "Tang " -0x84cf: "Luo " -0x84d0: "Ru " -0x84d1: "Suo " -0x84d2: "Xian " -0x84d3: "Bei " -0x84d4: "Yao " -0x84d5: "Gui " -0x84d6: "Bi " -0x84d7: "Zong " -0x84d8: "Gun " -0x84d9: "Za " -0x84da: "Xiu " -0x84db: "Ce " -0x84dc: "Hai " -0x84dd: "Lan " -0x84de: "[?] " -0x84df: "Ji " -0x84e0: "Li " -0x84e1: "Can " -0x84e2: "Lang " -0x84e3: "Yu " -0x84e4: "[?] " -0x84e5: "Ying " -0x84e6: "Mo " -0x84e7: "Diao " -0x84e8: "Tiao " -0x84e9: "Mao " -0x84ea: "Tong " -0x84eb: "Zhu " -0x84ec: "Peng " -0x84ed: "An " -0x84ee: "Lian " -0x84ef: "Cong " -0x84f0: "Xi " -0x84f1: "Ping " -0x84f2: "Qiu " -0x84f3: "Jin " -0x84f4: "Chun " -0x84f5: "Jie " -0x84f6: "Wei " -0x84f7: "Tui " -0x84f8: "Cao " -0x84f9: "Yu " -0x84fa: "Yi " -0x84fb: "Ji " -0x84fc: "Liao " -0x84fd: "Bi " -0x84fe: "Lu " -0x84ff: "Su " -/* x085 */ -0x8500: "Bu " -0x8501: "Zhang " -0x8502: "Luo " -0x8503: "Jiang " -0x8504: "Man " -0x8505: "Yan " -0x8506: "Ling " -0x8507: "Ji " -0x8508: "Piao " -0x8509: "Gun " -0x850a: "Han " -0x850b: "Di " -0x850c: "Su " -0x850d: "Lu " -0x850e: "She " -0x850f: "Shang " -0x8510: "Di " -0x8511: "Mie " -0x8512: "Xun " -0x8513: "Man " -0x8514: "Bo " -0x8515: "Di " -0x8516: "Cuo " -0x8517: "Zhe " -0x8518: "Sen " -0x8519: "Xuan " -0x851a: "Wei " -0x851b: "Hu " -0x851c: "Ao " -0x851d: "Mi " -0x851e: "Lou " -0x851f: "Cu " -0x8520: "Zhong " -0x8521: "Cai " -0x8522: "Po " -0x8523: "Jiang " -0x8524: "Mi " -0x8525: "Cong " -0x8526: "Niao " -0x8527: "Hui " -0x8528: "Jun " -0x8529: "Yin " -0x852a: "Jian " -0x852b: "Yan " -0x852c: "Shu " -0x852d: "Yin " -0x852e: "Kui " -0x852f: "Chen " -0x8530: "Hu " -0x8531: "Sha " -0x8532: "Kou " -0x8533: "Qian " -0x8534: "Ma " -0x8535: "Zang " -0x8536: "Sonoko " -0x8537: "Qiang " -0x8538: "Dou " -0x8539: "Lian " -0x853a: "Lin " -0x853b: "Kou " -0x853c: "Ai " -0x853d: "Bi " -0x853e: "Li " -0x853f: "Wei " -0x8540: "Ji " -0x8541: "Xun " -0x8542: "Sheng " -0x8543: "Fan " -0x8544: "Meng " -0x8545: "Ou " -0x8546: "Chan " -0x8547: "Dian " -0x8548: "Xun " -0x8549: "Jiao " -0x854a: "Rui " -0x854b: "Rui " -0x854c: "Lei " -0x854d: "Yu " -0x854e: "Qiao " -0x854f: "Chu " -0x8550: "Hua " -0x8551: "Jian " -0x8552: "Mai " -0x8553: "Yun " -0x8554: "Bao " -0x8555: "You " -0x8556: "Qu " -0x8557: "Lu " -0x8558: "Rao " -0x8559: "Hui " -0x855a: "E " -0x855b: "Teng " -0x855c: "Fei " -0x855d: "Jue " -0x855e: "Zui " -0x855f: "Fa " -0x8560: "Ru " -0x8561: "Fen " -0x8562: "Kui " -0x8563: "Shun " -0x8564: "Rui " -0x8565: "Ya " -0x8566: "Xu " -0x8567: "Fu " -0x8568: "Jue " -0x8569: "Dang " -0x856a: "Wu " -0x856b: "Tong " -0x856c: "Si " -0x856d: "Xiao " -0x856e: "Xi " -0x856f: "Long " -0x8570: "Yun " -0x8571: "[?] " -0x8572: "Qi " -0x8573: "Jian " -0x8574: "Yun " -0x8575: "Sun " -0x8576: "Ling " -0x8577: "Yu " -0x8578: "Xia " -0x8579: "Yong " -0x857a: "Ji " -0x857b: "Hong " -0x857c: "Si " -0x857d: "Nong " -0x857e: "Lei " -0x857f: "Xuan " -0x8580: "Yun " -0x8581: "Yu " -0x8582: "Xi " -0x8583: "Hao " -0x8584: "Bo " -0x8585: "Hao " -0x8586: "Ai " -0x8587: "Wei " -0x8588: "Hui " -0x8589: "Wei " -0x858a: "Ji " -0x858b: "Ci " -0x858c: "Xiang " -0x858d: "Luan " -0x858e: "Mie " -0x858f: "Yi " -0x8590: "Leng " -0x8591: "Jiang " -0x8592: "Can " -0x8593: "Shen " -0x8594: "Qiang " -0x8595: "Lian " -0x8596: "Ke " -0x8597: "Yuan " -0x8598: "Da " -0x8599: "Ti " -0x859a: "Tang " -0x859b: "Xie " -0x859c: "Bi " -0x859d: "Zhan " -0x859e: "Sun " -0x859f: "Lian " -0x85a0: "Fan " -0x85a1: "Ding " -0x85a2: "Jie " -0x85a3: "Gu " -0x85a4: "Xie " -0x85a5: "Shu " -0x85a6: "Jian " -0x85a7: "Kao " -0x85a8: "Hong " -0x85a9: "Sa " -0x85aa: "Xin " -0x85ab: "Xun " -0x85ac: "Yao " -0x85ad: "Hie " -0x85ae: "Sou " -0x85af: "Shu " -0x85b0: "Xun " -0x85b1: "Dui " -0x85b2: "Pin " -0x85b3: "Wei " -0x85b4: "Neng " -0x85b5: "Chou " -0x85b6: "Mai " -0x85b7: "Ru " -0x85b8: "Piao " -0x85b9: "Tai " -0x85ba: "Qi " -0x85bb: "Zao " -0x85bc: "Chen " -0x85bd: "Zhen " -0x85be: "Er " -0x85bf: "Ni " -0x85c0: "Ying " -0x85c1: "Gao " -0x85c2: "Cong " -0x85c3: "Xiao " -0x85c4: "Qi " -0x85c5: "Fa " -0x85c6: "Jian " -0x85c7: "Xu " -0x85c8: "Kui " -0x85c9: "Jie " -0x85ca: "Bian " -0x85cb: "Diao " -0x85cc: "Mi " -0x85cd: "Lan " -0x85ce: "Jin " -0x85cf: "Cang " -0x85d0: "Miao " -0x85d1: "Qiong " -0x85d2: "Qie " -0x85d3: "Xian " -0x85d4: "[?] " -0x85d5: "Ou " -0x85d6: "Xian " -0x85d7: "Su " -0x85d8: "Lu " -0x85d9: "Yi " -0x85da: "Xu " -0x85db: "Xie " -0x85dc: "Li " -0x85dd: "Yi " -0x85de: "La " -0x85df: "Lei " -0x85e0: "Xiao " -0x85e1: "Di " -0x85e2: "Zhi " -0x85e3: "Bei " -0x85e4: "Teng " -0x85e5: "Yao " -0x85e6: "Mo " -0x85e7: "Huan " -0x85e8: "Piao " -0x85e9: "Fan " -0x85ea: "Sou " -0x85eb: "Tan " -0x85ec: "Tui " -0x85ed: "Qiong " -0x85ee: "Qiao " -0x85ef: "Wei " -0x85f0: "Liu " -0x85f1: "Hui " -0x85f2: "[?] " -0x85f3: "Gao " -0x85f4: "Yun " -0x85f5: "[?] " -0x85f6: "Li " -0x85f7: "Shu " -0x85f8: "Chu " -0x85f9: "Ai " -0x85fa: "Lin " -0x85fb: "Zao " -0x85fc: "Xuan " -0x85fd: "Chen " -0x85fe: "Lai " -0x85ff: "Huo " -/* x086 */ -0x8600: "Tuo " -0x8601: "Wu " -0x8602: "Rui " -0x8603: "Rui " -0x8604: "Qi " -0x8605: "Heng " -0x8606: "Lu " -0x8607: "Su " -0x8608: "Tui " -0x8609: "Mang " -0x860a: "Yun " -0x860b: "Pin " -0x860c: "Yu " -0x860d: "Xun " -0x860e: "Ji " -0x860f: "Jiong " -0x8610: "Xian " -0x8611: "Mo " -0x8612: "Hagi " -0x8613: "Su " -0x8614: "Jiong " -0x8615: "[?] " -0x8616: "Nie " -0x8617: "Bo " -0x8618: "Rang " -0x8619: "Yi " -0x861a: "Xian " -0x861b: "Yu " -0x861c: "Ju " -0x861d: "Lian " -0x861e: "Lian " -0x861f: "Yin " -0x8620: "Qiang " -0x8621: "Ying " -0x8622: "Long " -0x8623: "Tong " -0x8624: "Wei " -0x8625: "Yue " -0x8626: "Ling " -0x8627: "Qu " -0x8628: "Yao " -0x8629: "Fan " -0x862a: "Mi " -0x862b: "Lan " -0x862c: "Kui " -0x862d: "Lan " -0x862e: "Ji " -0x862f: "Dang " -0x8630: "Katsura " -0x8631: "Lei " -0x8632: "Lei " -0x8633: "Hua " -0x8634: "Feng " -0x8635: "Zhi " -0x8636: "Wei " -0x8637: "Kui " -0x8638: "Zhan " -0x8639: "Huai " -0x863a: "Li " -0x863b: "Ji " -0x863c: "Mi " -0x863d: "Lei " -0x863e: "Huai " -0x863f: "Luo " -0x8640: "Ji " -0x8641: "Kui " -0x8642: "Lu " -0x8643: "Jian " -0x8644: "San " -0x8645: "[?] " -0x8646: "Lei " -0x8647: "Quan " -0x8648: "Xiao " -0x8649: "Yi " -0x864a: "Luan " -0x864b: "Men " -0x864c: "Bie " -0x864d: "Hu " -0x864e: "Hu " -0x864f: "Lu " -0x8650: "Nue " -0x8651: "Lu " -0x8652: "Si " -0x8653: "Xiao " -0x8654: "Qian " -0x8655: "Chu " -0x8656: "Hu " -0x8657: "Xu " -0x8658: "Cuo " -0x8659: "Fu " -0x865a: "Xu " -0x865b: "Xu " -0x865c: "Lu " -0x865d: "Hu " -0x865e: "Yu " -0x865f: "Hao " -0x8660: "Jiao " -0x8661: "Ju " -0x8662: "Guo " -0x8663: "Bao " -0x8664: "Yan " -0x8665: "Zhan " -0x8666: "Zhan " -0x8667: "Kui " -0x8668: "Ban " -0x8669: "Xi " -0x866a: "Shu " -0x866b: "Chong " -0x866c: "Qiu " -0x866d: "Diao " -0x866e: "Ji " -0x866f: "Qiu " -0x8670: "Cheng " -0x8671: "Shi " -0x8672: "[?] " -0x8673: "Di " -0x8674: "Zhe " -0x8675: "She " -0x8676: "Yu " -0x8677: "Gan " -0x8678: "Zi " -0x8679: "Hong " -0x867a: "Hui " -0x867b: "Meng " -0x867c: "Ge " -0x867d: "Sui " -0x867e: "Xia " -0x867f: "Chai " -0x8680: "Shi " -0x8681: "Yi " -0x8682: "Ma " -0x8683: "Xiang " -0x8684: "Fang " -0x8685: "E " -0x8686: "Pa " -0x8687: "Chi " -0x8688: "Qian " -0x8689: "Wen " -0x868a: "Wen " -0x868b: "Rui " -0x868c: "Bang " -0x868d: "Bi " -0x868e: "Yue " -0x868f: "Yue " -0x8690: "Jun " -0x8691: "Qi " -0x8692: "Ran " -0x8693: "Yin " -0x8694: "Qi " -0x8695: "Tian " -0x8696: "Yuan " -0x8697: "Jue " -0x8698: "Hui " -0x8699: "Qin " -0x869a: "Qi " -0x869b: "Zhong " -0x869c: "Ya " -0x869d: "Ci " -0x869e: "Mu " -0x869f: "Wang " -0x86a0: "Fen " -0x86a1: "Fen " -0x86a2: "Hang " -0x86a3: "Gong " -0x86a4: "Zao " -0x86a5: "Fu " -0x86a6: "Ran " -0x86a7: "Jie " -0x86a8: "Fu " -0x86a9: "Chi " -0x86aa: "Dou " -0x86ab: "Piao " -0x86ac: "Xian " -0x86ad: "Ni " -0x86ae: "Te " -0x86af: "Qiu " -0x86b0: "You " -0x86b1: "Zha " -0x86b2: "Ping " -0x86b3: "Chi " -0x86b4: "You " -0x86b5: "He " -0x86b6: "Han " -0x86b7: "Ju " -0x86b8: "Li " -0x86b9: "Fu " -0x86ba: "Ran " -0x86bb: "Zha " -0x86bc: "Gou " -0x86bd: "Pi " -0x86be: "Bo " -0x86bf: "Xian " -0x86c0: "Zhu " -0x86c1: "Diao " -0x86c2: "Bie " -0x86c3: "Bing " -0x86c4: "Gu " -0x86c5: "Ran " -0x86c6: "Qu " -0x86c7: "She " -0x86c8: "Tie " -0x86c9: "Ling " -0x86ca: "Gu " -0x86cb: "Dan " -0x86cc: "Gu " -0x86cd: "Ying " -0x86ce: "Li " -0x86cf: "Cheng " -0x86d0: "Qu " -0x86d1: "Mou " -0x86d2: "Ge " -0x86d3: "Ci " -0x86d4: "Hui " -0x86d5: "Hui " -0x86d6: "Mang " -0x86d7: "Fu " -0x86d8: "Yang " -0x86d9: "Wa " -0x86da: "Lie " -0x86db: "Zhu " -0x86dc: "Yi " -0x86dd: "Xian " -0x86de: "Kuo " -0x86df: "Jiao " -0x86e0: "Li " -0x86e1: "Yi " -0x86e2: "Ping " -0x86e3: "Ji " -0x86e4: "Ha " -0x86e5: "She " -0x86e6: "Yi " -0x86e7: "Wang " -0x86e8: "Mo " -0x86e9: "Qiong " -0x86ea: "Qie " -0x86eb: "Gui " -0x86ec: "Gong " -0x86ed: "Zhi " -0x86ee: "Man " -0x86ef: "Ebi " -0x86f0: "Zhi " -0x86f1: "Jia " -0x86f2: "Rao " -0x86f3: "Si " -0x86f4: "Qi " -0x86f5: "Xing " -0x86f6: "Lie " -0x86f7: "Qiu " -0x86f8: "Shao " -0x86f9: "Yong " -0x86fa: "Jia " -0x86fb: "Shui " -0x86fc: "Che " -0x86fd: "Bai " -0x86fe: "E " -0x86ff: "Han " -/* x087 */ -0x8700: "Shu " -0x8701: "Xuan " -0x8702: "Feng " -0x8703: "Shen " -0x8704: "Zhen " -0x8705: "Fu " -0x8706: "Xian " -0x8707: "Zhe " -0x8708: "Wu " -0x8709: "Fu " -0x870a: "Li " -0x870b: "Lang " -0x870c: "Bi " -0x870d: "Chu " -0x870e: "Yuan " -0x870f: "You " -0x8710: "Jie " -0x8711: "Dan " -0x8712: "Yan " -0x8713: "Ting " -0x8714: "Dian " -0x8715: "Shui " -0x8716: "Hui " -0x8717: "Gua " -0x8718: "Zhi " -0x8719: "Song " -0x871a: "Fei " -0x871b: "Ju " -0x871c: "Mi " -0x871d: "Qi " -0x871e: "Qi " -0x871f: "Yu " -0x8720: "Jun " -0x8721: "Zha " -0x8722: "Meng " -0x8723: "Qiang " -0x8724: "Si " -0x8725: "Xi " -0x8726: "Lun " -0x8727: "Li " -0x8728: "Die " -0x8729: "Tiao " -0x872a: "Tao " -0x872b: "Kun " -0x872c: "Gan " -0x872d: "Han " -0x872e: "Yu " -0x872f: "Bang " -0x8730: "Fei " -0x8731: "Pi " -0x8732: "Wei " -0x8733: "Dun " -0x8734: "Yi " -0x8735: "Yuan " -0x8736: "Su " -0x8737: "Quan " -0x8738: "Qian " -0x8739: "Rui " -0x873a: "Ni " -0x873b: "Qing " -0x873c: "Wei " -0x873d: "Liang " -0x873e: "Guo " -0x873f: "Wan " -0x8740: "Dong " -0x8741: "E " -0x8742: "Ban " -0x8743: "Di " -0x8744: "Wang " -0x8745: "Can " -0x8746: "Yang " -0x8747: "Ying " -0x8748: "Guo " -0x8749: "Chan " -0x874a: "[?] " -0x874b: "La " -0x874c: "Ke " -0x874d: "Ji " -0x874e: "He " -0x874f: "Ting " -0x8750: "Mai " -0x8751: "Xu " -0x8752: "Mian " -0x8753: "Yu " -0x8754: "Jie " -0x8755: "Shi " -0x8756: "Xuan " -0x8757: "Huang " -0x8758: "Yan " -0x8759: "Bian " -0x875a: "Rou " -0x875b: "Wei " -0x875c: "Fu " -0x875d: "Yuan " -0x875e: "Mei " -0x875f: "Wei " -0x8760: "Fu " -0x8761: "Ruan " -0x8762: "Xie " -0x8763: "You " -0x8764: "Qiu " -0x8765: "Mao " -0x8766: "Xia " -0x8767: "Ying " -0x8768: "Shi " -0x8769: "Chong " -0x876a: "Tang " -0x876b: "Zhu " -0x876c: "Zong " -0x876d: "Ti " -0x876e: "Fu " -0x876f: "Yuan " -0x8770: "Hui " -0x8771: "Meng " -0x8772: "La " -0x8773: "Du " -0x8774: "Hu " -0x8775: "Qiu " -0x8776: "Die " -0x8777: "Li " -0x8778: "Gua " -0x8779: "Yun " -0x877a: "Ju " -0x877b: "Nan " -0x877c: "Lou " -0x877d: "Qun " -0x877e: "Rong " -0x877f: "Ying " -0x8780: "Jiang " -0x8781: "[?] " -0x8782: "Lang " -0x8783: "Pang " -0x8784: "Si " -0x8785: "Xi " -0x8786: "Ci " -0x8787: "Xi " -0x8788: "Yuan " -0x8789: "Weng " -0x878a: "Lian " -0x878b: "Sou " -0x878c: "Ban " -0x878d: "Rong " -0x878e: "Rong " -0x878f: "Ji " -0x8790: "Wu " -0x8791: "Qiu " -0x8792: "Han " -0x8793: "Qin " -0x8794: "Yi " -0x8795: "Bi " -0x8796: "Hua " -0x8797: "Tang " -0x8798: "Yi " -0x8799: "Du " -0x879a: "Nai " -0x879b: "He " -0x879c: "Hu " -0x879d: "Hui " -0x879e: "Ma " -0x879f: "Ming " -0x87a0: "Yi " -0x87a1: "Wen " -0x87a2: "Ying " -0x87a3: "Teng " -0x87a4: "Yu " -0x87a5: "Cang " -0x87a6: "So " -0x87a7: "Ebi " -0x87a8: "Man " -0x87a9: "[?] " -0x87aa: "Shang " -0x87ab: "Zhe " -0x87ac: "Cao " -0x87ad: "Chi " -0x87ae: "Di " -0x87af: "Ao " -0x87b0: "Lu " -0x87b1: "Wei " -0x87b2: "Zhi " -0x87b3: "Tang " -0x87b4: "Chen " -0x87b5: "Piao " -0x87b6: "Qu " -0x87b7: "Pi " -0x87b8: "Yu " -0x87b9: "Jian " -0x87ba: "Luo " -0x87bb: "Lou " -0x87bc: "Qin " -0x87bd: "Zhong " -0x87be: "Yin " -0x87bf: "Jiang " -0x87c0: "Shuai " -0x87c1: "Wen " -0x87c2: "Jiao " -0x87c3: "Wan " -0x87c4: "Zhi " -0x87c5: "Zhe " -0x87c6: "Ma " -0x87c7: "Ma " -0x87c8: "Guo " -0x87c9: "Liu " -0x87ca: "Mao " -0x87cb: "Xi " -0x87cc: "Cong " -0x87cd: "Li " -0x87ce: "Man " -0x87cf: "Xiao " -0x87d0: "Kamakiri " -0x87d1: "Zhang " -0x87d2: "Mang " -0x87d3: "Xiang " -0x87d4: "Mo " -0x87d5: "Zui " -0x87d6: "Si " -0x87d7: "Qiu " -0x87d8: "Te " -0x87d9: "Zhi " -0x87da: "Peng " -0x87db: "Peng " -0x87dc: "Jiao " -0x87dd: "Qu " -0x87de: "Bie " -0x87df: "Liao " -0x87e0: "Pan " -0x87e1: "Gui " -0x87e2: "Xi " -0x87e3: "Ji " -0x87e4: "Zhuan " -0x87e5: "Huang " -0x87e6: "Fei " -0x87e7: "Lao " -0x87e8: "Jue " -0x87e9: "Jue " -0x87ea: "Hui " -0x87eb: "Yin " -0x87ec: "Chan " -0x87ed: "Jiao " -0x87ee: "Shan " -0x87ef: "Rao " -0x87f0: "Xiao " -0x87f1: "Mou " -0x87f2: "Chong " -0x87f3: "Xun " -0x87f4: "Si " -0x87f5: "[?] " -0x87f6: "Cheng " -0x87f7: "Dang " -0x87f8: "Li " -0x87f9: "Xie " -0x87fa: "Shan " -0x87fb: "Yi " -0x87fc: "Jing " -0x87fd: "Da " -0x87fe: "Chan " -0x87ff: "Qi " -/* x088 */ -0x8800: "Ci " -0x8801: "Xiang " -0x8802: "She " -0x8803: "Luo " -0x8804: "Qin " -0x8805: "Ying " -0x8806: "Chai " -0x8807: "Li " -0x8808: "Ze " -0x8809: "Xuan " -0x880a: "Lian " -0x880b: "Zhu " -0x880c: "Ze " -0x880d: "Xie " -0x880e: "Mang " -0x880f: "Xie " -0x8810: "Qi " -0x8811: "Rong " -0x8812: "Jian " -0x8813: "Meng " -0x8814: "Hao " -0x8815: "Ruan " -0x8816: "Huo " -0x8817: "Zhuo " -0x8818: "Jie " -0x8819: "Bin " -0x881a: "He " -0x881b: "Mie " -0x881c: "Fan " -0x881d: "Lei " -0x881e: "Jie " -0x881f: "La " -0x8820: "Mi " -0x8821: "Li " -0x8822: "Chun " -0x8823: "Li " -0x8824: "Qiu " -0x8825: "Nie " -0x8826: "Lu " -0x8827: "Du " -0x8828: "Xiao " -0x8829: "Zhu " -0x882a: "Long " -0x882b: "Li " -0x882c: "Long " -0x882d: "Feng " -0x882e: "Ye " -0x882f: "Beng " -0x8830: "Shang " -0x8831: "Gu " -0x8832: "Juan " -0x8833: "Ying " -0x8834: "[?] " -0x8835: "Xi " -0x8836: "Can " -0x8837: "Qu " -0x8838: "Quan " -0x8839: "Du " -0x883a: "Can " -0x883b: "Man " -0x883c: "Jue " -0x883d: "Jie " -0x883e: "Zhu " -0x883f: "Zha " -0x8840: "Xie " -0x8841: "Huang " -0x8842: "Niu " -0x8843: "Pei " -0x8844: "Nu " -0x8845: "Xin " -0x8846: "Zhong " -0x8847: "Mo " -0x8848: "Er " -0x8849: "Ke " -0x884a: "Mie " -0x884b: "Xi " -0x884c: "Xing " -0x884d: "Yan " -0x884e: "Kan " -0x884f: "Yuan " -0x8850: "[?] " -0x8851: "Ling " -0x8852: "Xuan " -0x8853: "Shu " -0x8854: "Xian " -0x8855: "Tong " -0x8856: "Long " -0x8857: "Jie " -0x8858: "Xian " -0x8859: "Ya " -0x885a: "Hu " -0x885b: "Wei " -0x885c: "Dao " -0x885d: "Chong " -0x885e: "Wei " -0x885f: "Dao " -0x8860: "Zhun " -0x8861: "Heng " -0x8862: "Qu " -0x8863: "Yi " -0x8864: "Yi " -0x8865: "Bu " -0x8866: "Gan " -0x8867: "Yu " -0x8868: "Biao " -0x8869: "Cha " -0x886a: "Yi " -0x886b: "Shan " -0x886c: "Chen " -0x886d: "Fu " -0x886e: "Gun " -0x886f: "Fen " -0x8870: "Shuai " -0x8871: "Jie " -0x8872: "Na " -0x8873: "Zhong " -0x8874: "Dan " -0x8875: "Ri " -0x8876: "Zhong " -0x8877: "Zhong " -0x8878: "Xie " -0x8879: "Qi " -0x887a: "Xie " -0x887b: "Ran " -0x887c: "Zhi " -0x887d: "Ren " -0x887e: "Qin " -0x887f: "Jin " -0x8880: "Jun " -0x8881: "Yuan " -0x8882: "Mei " -0x8883: "Chai " -0x8884: "Ao " -0x8885: "Niao " -0x8886: "Hui " -0x8887: "Ran " -0x8888: "Jia " -0x8889: "Tuo " -0x888a: "Ling " -0x888b: "Dai " -0x888c: "Bao " -0x888d: "Pao " -0x888e: "Yao " -0x888f: "Zuo " -0x8890: "Bi " -0x8891: "Shao " -0x8892: "Tan " -0x8893: "Ju " -0x8894: "He " -0x8895: "Shu " -0x8896: "Xiu " -0x8897: "Zhen " -0x8898: "Yi " -0x8899: "Pa " -0x889a: "Bo " -0x889b: "Di " -0x889c: "Wa " -0x889d: "Fu " -0x889e: "Gun " -0x889f: "Zhi " -0x88a0: "Zhi " -0x88a1: "Ran " -0x88a2: "Pan " -0x88a3: "Yi " -0x88a4: "Mao " -0x88a5: "Tuo " -0x88a6: "Na " -0x88a7: "Kou " -0x88a8: "Xian " -0x88a9: "Chan " -0x88aa: "Qu " -0x88ab: "Bei " -0x88ac: "Gun " -0x88ad: "Xi " -0x88ae: "Ne " -0x88af: "Bo " -0x88b0: "Horo " -0x88b1: "Fu " -0x88b2: "Yi " -0x88b3: "Chi " -0x88b4: "Ku " -0x88b5: "Ren " -0x88b6: "Jiang " -0x88b7: "Jia " -0x88b8: "Cun " -0x88b9: "Mo " -0x88ba: "Jie " -0x88bb: "Er " -0x88bc: "Luo " -0x88bd: "Ru " -0x88be: "Zhu " -0x88bf: "Gui " -0x88c0: "Yin " -0x88c1: "Cai " -0x88c2: "Lie " -0x88c3: "Kamishimo " -0x88c4: "Yuki " -0x88c5: "Zhuang " -0x88c6: "Dang " -0x88c7: "[?] " -0x88c8: "Kun " -0x88c9: "Ken " -0x88ca: "Niao " -0x88cb: "Shu " -0x88cc: "Jia " -0x88cd: "Kun " -0x88ce: "Cheng " -0x88cf: "Li " -0x88d0: "Juan " -0x88d1: "Shen " -0x88d2: "Pou " -0x88d3: "Ge " -0x88d4: "Yi " -0x88d5: "Yu " -0x88d6: "Zhen " -0x88d7: "Liu " -0x88d8: "Qiu " -0x88d9: "Qun " -0x88da: "Ji " -0x88db: "Yi " -0x88dc: "Bu " -0x88dd: "Zhuang " -0x88de: "Shui " -0x88df: "Sha " -0x88e0: "Qun " -0x88e1: "Li " -0x88e2: "Lian " -0x88e3: "Lian " -0x88e4: "Ku " -0x88e5: "Jian " -0x88e6: "Fou " -0x88e7: "Chan " -0x88e8: "Bi " -0x88e9: "Gun " -0x88ea: "Tao " -0x88eb: "Yuan " -0x88ec: "Ling " -0x88ed: "Chi " -0x88ee: "Chang " -0x88ef: "Chou " -0x88f0: "Duo " -0x88f1: "Biao " -0x88f2: "Liang " -0x88f3: "Chang " -0x88f4: "Pei " -0x88f5: "Pei " -0x88f6: "Fei " -0x88f7: "Yuan " -0x88f8: "Luo " -0x88f9: "Guo " -0x88fa: "Yan " -0x88fb: "Du " -0x88fc: "Xi " -0x88fd: "Zhi " -0x88fe: "Ju " -0x88ff: "Qi " -/* x089 */ -0x8900: "Ji " -0x8901: "Zhi " -0x8902: "Gua " -0x8903: "Ken " -0x8904: "Che " -0x8905: "Ti " -0x8906: "Ti " -0x8907: "Fu " -0x8908: "Chong " -0x8909: "Xie " -0x890a: "Bian " -0x890b: "Die " -0x890c: "Kun " -0x890d: "Duan " -0x890e: "Xiu " -0x890f: "Xiu " -0x8910: "He " -0x8911: "Yuan " -0x8912: "Bao " -0x8913: "Bao " -0x8914: "Fu " -0x8915: "Yu " -0x8916: "Tuan " -0x8917: "Yan " -0x8918: "Hui " -0x8919: "Bei " -0x891a: "Chu " -0x891b: "Lu " -0x891c: "Ena " -0x891d: "Hitoe " -0x891e: "Yun " -0x891f: "Da " -0x8920: "Gou " -0x8921: "Da " -0x8922: "Huai " -0x8923: "Rong " -0x8924: "Yuan " -0x8925: "Ru " -0x8926: "Nai " -0x8927: "Jiong " -0x8928: "Suo " -0x8929: "Ban " -0x892a: "Tun " -0x892b: "Chi " -0x892c: "Sang " -0x892d: "Niao " -0x892e: "Ying " -0x892f: "Jie " -0x8930: "Qian " -0x8931: "Huai " -0x8932: "Ku " -0x8933: "Lian " -0x8934: "Bao " -0x8935: "Li " -0x8936: "Zhe " -0x8937: "Shi " -0x8938: "Lu " -0x8939: "Yi " -0x893a: "Die " -0x893b: "Xie " -0x893c: "Xian " -0x893d: "Wei " -0x893e: "Biao " -0x893f: "Cao " -0x8940: "Ji " -0x8941: "Jiang " -0x8942: "Sen " -0x8943: "Bao " -0x8944: "Xiang " -0x8945: "Chihaya " -0x8946: "Pu " -0x8947: "Jian " -0x8948: "Zhuan " -0x8949: "Jian " -0x894a: "Zui " -0x894b: "Ji " -0x894c: "Dan " -0x894d: "Za " -0x894e: "Fan " -0x894f: "Bo " -0x8950: "Xiang " -0x8951: "Xin " -0x8952: "Bie " -0x8953: "Rao " -0x8954: "Man " -0x8955: "Lan " -0x8956: "Ao " -0x8957: "Duo " -0x8958: "Gui " -0x8959: "Cao " -0x895a: "Sui " -0x895b: "Nong " -0x895c: "Chan " -0x895d: "Lian " -0x895e: "Bi " -0x895f: "Jin " -0x8960: "Dang " -0x8961: "Shu " -0x8962: "Tan " -0x8963: "Bi " -0x8964: "Lan " -0x8965: "Pu " -0x8966: "Ru " -0x8967: "Zhi " -0x8968: "[?] " -0x8969: "Shu " -0x896a: "Wa " -0x896b: "Shi " -0x896c: "Bai " -0x896d: "Xie " -0x896e: "Bo " -0x896f: "Chen " -0x8970: "Lai " -0x8971: "Long " -0x8972: "Xi " -0x8973: "Xian " -0x8974: "Lan " -0x8975: "Zhe " -0x8976: "Dai " -0x8977: "Tasuki " -0x8978: "Zan " -0x8979: "Shi " -0x897a: "Jian " -0x897b: "Pan " -0x897c: "Yi " -0x897d: "Ran " -0x897e: "Ya " -0x897f: "Xi " -0x8980: "Xi " -0x8981: "Yao " -0x8982: "Feng " -0x8983: "Tan " -0x8984: "[?] " -0x8985: "Biao " -0x8986: "Fu " -0x8987: "Ba " -0x8988: "He " -0x8989: "Ji " -0x898a: "Ji " -0x898b: "Jian " -0x898c: "Guan " -0x898d: "Bian " -0x898e: "Yan " -0x898f: "Gui " -0x8990: "Jue " -0x8991: "Pian " -0x8992: "Mao " -0x8993: "Mi " -0x8994: "Mi " -0x8995: "Mie " -0x8996: "Shi " -0x8997: "Si " -0x8998: "Zhan " -0x8999: "Luo " -0x899a: "Jue " -0x899b: "Mi " -0x899c: "Tiao " -0x899d: "Lian " -0x899e: "Yao " -0x899f: "Zhi " -0x89a0: "Jun " -0x89a1: "Xi " -0x89a2: "Shan " -0x89a3: "Wei " -0x89a4: "Xi " -0x89a5: "Tian " -0x89a6: "Yu " -0x89a7: "Lan " -0x89a8: "E " -0x89a9: "Du " -0x89aa: "Qin " -0x89ab: "Pang " -0x89ac: "Ji " -0x89ad: "Ming " -0x89ae: "Ying " -0x89af: "Gou " -0x89b0: "Qu " -0x89b1: "Zhan " -0x89b2: "Jin " -0x89b3: "Guan " -0x89b4: "Deng " -0x89b5: "Jian " -0x89b6: "Luo " -0x89b7: "Qu " -0x89b8: "Jian " -0x89b9: "Wei " -0x89ba: "Jue " -0x89bb: "Qu " -0x89bc: "Luo " -0x89bd: "Lan " -0x89be: "Shen " -0x89bf: "Di " -0x89c0: "Guan " -0x89c1: "Jian " -0x89c2: "Guan " -0x89c3: "Yan " -0x89c4: "Gui " -0x89c5: "Mi " -0x89c6: "Shi " -0x89c7: "Zhan " -0x89c8: "Lan " -0x89c9: "Jue " -0x89ca: "Ji " -0x89cb: "Xi " -0x89cc: "Di " -0x89cd: "Tian " -0x89ce: "Yu " -0x89cf: "Gou " -0x89d0: "Jin " -0x89d1: "Qu " -0x89d2: "Jiao " -0x89d3: "Jiu " -0x89d4: "Jin " -0x89d5: "Cu " -0x89d6: "Jue " -0x89d7: "Zhi " -0x89d8: "Chao " -0x89d9: "Ji " -0x89da: "Gu " -0x89db: "Dan " -0x89dc: "Zui " -0x89dd: "Di " -0x89de: "Shang " -0x89df: "Hua " -0x89e0: "Quan " -0x89e1: "Ge " -0x89e2: "Chi " -0x89e3: "Jie " -0x89e4: "Gui " -0x89e5: "Gong " -0x89e6: "Hong " -0x89e7: "Jie " -0x89e8: "Hun " -0x89e9: "Qiu " -0x89ea: "Xing " -0x89eb: "Su " -0x89ec: "Ni " -0x89ed: "Ji " -0x89ee: "Lu " -0x89ef: "Zhi " -0x89f0: "Zha " -0x89f1: "Bi " -0x89f2: "Xing " -0x89f3: "Hu " -0x89f4: "Shang " -0x89f5: "Gong " -0x89f6: "Zhi " -0x89f7: "Xue " -0x89f8: "Chu " -0x89f9: "Xi " -0x89fa: "Yi " -0x89fb: "Lu " -0x89fc: "Jue " -0x89fd: "Xi " -0x89fe: "Yan " -0x89ff: "Xi " -/* x08a */ -0x8a00: "Yan " -0x8a01: "Yan " -0x8a02: "Ding " -0x8a03: "Fu " -0x8a04: "Qiu " -0x8a05: "Qiu " -0x8a06: "Jiao " -0x8a07: "Hong " -0x8a08: "Ji " -0x8a09: "Fan " -0x8a0a: "Xun " -0x8a0b: "Diao " -0x8a0c: "Hong " -0x8a0d: "Cha " -0x8a0e: "Tao " -0x8a0f: "Xu " -0x8a10: "Jie " -0x8a11: "Yi " -0x8a12: "Ren " -0x8a13: "Xun " -0x8a14: "Yin " -0x8a15: "Shan " -0x8a16: "Qi " -0x8a17: "Tuo " -0x8a18: "Ji " -0x8a19: "Xun " -0x8a1a: "Yin " -0x8a1b: "E " -0x8a1c: "Fen " -0x8a1d: "Ya " -0x8a1e: "Yao " -0x8a1f: "Song " -0x8a20: "Shen " -0x8a21: "Yin " -0x8a22: "Xin " -0x8a23: "Jue " -0x8a24: "Xiao " -0x8a25: "Ne " -0x8a26: "Chen " -0x8a27: "You " -0x8a28: "Zhi " -0x8a29: "Xiong " -0x8a2a: "Fang " -0x8a2b: "Xin " -0x8a2c: "Chao " -0x8a2d: "She " -0x8a2e: "Xian " -0x8a2f: "Sha " -0x8a30: "Tun " -0x8a31: "Xu " -0x8a32: "Yi " -0x8a33: "Yi " -0x8a34: "Su " -0x8a35: "Chi " -0x8a36: "He " -0x8a37: "Shen " -0x8a38: "He " -0x8a39: "Xu " -0x8a3a: "Zhen " -0x8a3b: "Zhu " -0x8a3c: "Zheng " -0x8a3d: "Gou " -0x8a3e: "Zi " -0x8a3f: "Zi " -0x8a40: "Zhan " -0x8a41: "Gu " -0x8a42: "Fu " -0x8a43: "Quan " -0x8a44: "Die " -0x8a45: "Ling " -0x8a46: "Di " -0x8a47: "Yang " -0x8a48: "Li " -0x8a49: "Nao " -0x8a4a: "Pan " -0x8a4b: "Zhou " -0x8a4c: "Gan " -0x8a4d: "Yi " -0x8a4e: "Ju " -0x8a4f: "Ao " -0x8a50: "Zha " -0x8a51: "Tuo " -0x8a52: "Yi " -0x8a53: "Qu " -0x8a54: "Zhao " -0x8a55: "Ping " -0x8a56: "Bi " -0x8a57: "Xiong " -0x8a58: "Qu " -0x8a59: "Ba " -0x8a5a: "Da " -0x8a5b: "Zu " -0x8a5c: "Tao " -0x8a5d: "Zhu " -0x8a5e: "Ci " -0x8a5f: "Zhe " -0x8a60: "Yong " -0x8a61: "Xu " -0x8a62: "Xun " -0x8a63: "Yi " -0x8a64: "Huang " -0x8a65: "He " -0x8a66: "Shi " -0x8a67: "Cha " -0x8a68: "Jiao " -0x8a69: "Shi " -0x8a6a: "Hen " -0x8a6b: "Cha " -0x8a6c: "Gou " -0x8a6d: "Gui " -0x8a6e: "Quan " -0x8a6f: "Hui " -0x8a70: "Jie " -0x8a71: "Hua " -0x8a72: "Gai " -0x8a73: "Xiang " -0x8a74: "Wei " -0x8a75: "Shen " -0x8a76: "Chou " -0x8a77: "Tong " -0x8a78: "Mi " -0x8a79: "Zhan " -0x8a7a: "Ming " -0x8a7b: "E " -0x8a7c: "Hui " -0x8a7d: "Yan " -0x8a7e: "Xiong " -0x8a7f: "Gua " -0x8a80: "Er " -0x8a81: "Beng " -0x8a82: "Tiao " -0x8a83: "Chi " -0x8a84: "Lei " -0x8a85: "Zhu " -0x8a86: "Kuang " -0x8a87: "Kua " -0x8a88: "Wu " -0x8a89: "Yu " -0x8a8a: "Teng " -0x8a8b: "Ji " -0x8a8c: "Zhi " -0x8a8d: "Ren " -0x8a8e: "Su " -0x8a8f: "Lang " -0x8a90: "E " -0x8a91: "Kuang " -0x8a92: "E " -0x8a93: "Shi " -0x8a94: "Ting " -0x8a95: "Dan " -0x8a96: "Bo " -0x8a97: "Chan " -0x8a98: "You " -0x8a99: "Heng " -0x8a9a: "Qiao " -0x8a9b: "Qin " -0x8a9c: "Shua " -0x8a9d: "An " -0x8a9e: "Yu " -0x8a9f: "Xiao " -0x8aa0: "Cheng " -0x8aa1: "Jie " -0x8aa2: "Xian " -0x8aa3: "Wu " -0x8aa4: "Wu " -0x8aa5: "Gao " -0x8aa6: "Song " -0x8aa7: "Pu " -0x8aa8: "Hui " -0x8aa9: "Jing " -0x8aaa: "Shuo " -0x8aab: "Zhen " -0x8aac: "Shuo " -0x8aad: "Du " -0x8aae: "Yasashi " -0x8aaf: "Chang " -0x8ab0: "Shui " -0x8ab1: "Jie " -0x8ab2: "Ke " -0x8ab3: "Qu " -0x8ab4: "Cong " -0x8ab5: "Xiao " -0x8ab6: "Sui " -0x8ab7: "Wang " -0x8ab8: "Xuan " -0x8ab9: "Fei " -0x8aba: "Chi " -0x8abb: "Ta " -0x8abc: "Yi " -0x8abd: "Na " -0x8abe: "Yin " -0x8abf: "Diao " -0x8ac0: "Pi " -0x8ac1: "Chuo " -0x8ac2: "Chan " -0x8ac3: "Chen " -0x8ac4: "Zhun " -0x8ac5: "Ji " -0x8ac6: "Qi " -0x8ac7: "Tan " -0x8ac8: "Zhui " -0x8ac9: "Wei " -0x8aca: "Ju " -0x8acb: "Qing " -0x8acc: "Jian " -0x8acd: "Zheng " -0x8ace: "Ze " -0x8acf: "Zou " -0x8ad0: "Qian " -0x8ad1: "Zhuo " -0x8ad2: "Liang " -0x8ad3: "Jian " -0x8ad4: "Zhu " -0x8ad5: "Hao " -0x8ad6: "Lun " -0x8ad7: "Shen " -0x8ad8: "Biao " -0x8ad9: "Huai " -0x8ada: "Pian " -0x8adb: "Yu " -0x8adc: "Die " -0x8add: "Xu " -0x8ade: "Pian " -0x8adf: "Shi " -0x8ae0: "Xuan " -0x8ae1: "Shi " -0x8ae2: "Hun " -0x8ae3: "Hua " -0x8ae4: "E " -0x8ae5: "Zhong " -0x8ae6: "Di " -0x8ae7: "Xie " -0x8ae8: "Fu " -0x8ae9: "Pu " -0x8aea: "Ting " -0x8aeb: "Jian " -0x8aec: "Qi " -0x8aed: "Yu " -0x8aee: "Zi " -0x8aef: "Chuan " -0x8af0: "Xi " -0x8af1: "Hui " -0x8af2: "Yin " -0x8af3: "An " -0x8af4: "Xian " -0x8af5: "Nan " -0x8af6: "Chen " -0x8af7: "Feng " -0x8af8: "Zhu " -0x8af9: "Yang " -0x8afa: "Yan " -0x8afb: "Heng " -0x8afc: "Xuan " -0x8afd: "Ge " -0x8afe: "Nuo " -0x8aff: "Qi " -/* x08b */ -0x8b00: "Mou " -0x8b01: "Ye " -0x8b02: "Wei " -0x8b03: "[?] " -0x8b04: "Teng " -0x8b05: "Zou " -0x8b06: "Shan " -0x8b07: "Jian " -0x8b08: "Bo " -0x8b09: "Ku " -0x8b0a: "Huang " -0x8b0b: "Huo " -0x8b0c: "Ge " -0x8b0d: "Ying " -0x8b0e: "Mi " -0x8b0f: "Xiao " -0x8b10: "Mi " -0x8b11: "Xi " -0x8b12: "Qiang " -0x8b13: "Chen " -0x8b14: "Nue " -0x8b15: "Ti " -0x8b16: "Su " -0x8b17: "Bang " -0x8b18: "Chi " -0x8b19: "Qian " -0x8b1a: "Shi " -0x8b1b: "Jiang " -0x8b1c: "Yuan " -0x8b1d: "Xie " -0x8b1e: "Xue " -0x8b1f: "Tao " -0x8b20: "Yao " -0x8b21: "Yao " -0x8b22: "[?] " -0x8b23: "Yu " -0x8b24: "Biao " -0x8b25: "Cong " -0x8b26: "Qing " -0x8b27: "Li " -0x8b28: "Mo " -0x8b29: "Mo " -0x8b2a: "Shang " -0x8b2b: "Zhe " -0x8b2c: "Miu " -0x8b2d: "Jian " -0x8b2e: "Ze " -0x8b2f: "Jie " -0x8b30: "Lian " -0x8b31: "Lou " -0x8b32: "Can " -0x8b33: "Ou " -0x8b34: "Guan " -0x8b35: "Xi " -0x8b36: "Zhuo " -0x8b37: "Ao " -0x8b38: "Ao " -0x8b39: "Jin " -0x8b3a: "Zhe " -0x8b3b: "Yi " -0x8b3c: "Hu " -0x8b3d: "Jiang " -0x8b3e: "Man " -0x8b3f: "Chao " -0x8b40: "Han " -0x8b41: "Hua " -0x8b42: "Chan " -0x8b43: "Xu " -0x8b44: "Zeng " -0x8b45: "Se " -0x8b46: "Xi " -0x8b47: "She " -0x8b48: "Dui " -0x8b49: "Zheng " -0x8b4a: "Nao " -0x8b4b: "Lan " -0x8b4c: "E " -0x8b4d: "Ying " -0x8b4e: "Jue " -0x8b4f: "Ji " -0x8b50: "Zun " -0x8b51: "Jiao " -0x8b52: "Bo " -0x8b53: "Hui " -0x8b54: "Zhuan " -0x8b55: "Mu " -0x8b56: "Zen " -0x8b57: "Zha " -0x8b58: "Shi " -0x8b59: "Qiao " -0x8b5a: "Tan " -0x8b5b: "Zen " -0x8b5c: "Pu " -0x8b5d: "Sheng " -0x8b5e: "Xuan " -0x8b5f: "Zao " -0x8b60: "Tan " -0x8b61: "Dang " -0x8b62: "Sui " -0x8b63: "Qian " -0x8b64: "Ji " -0x8b65: "Jiao " -0x8b66: "Jing " -0x8b67: "Lian " -0x8b68: "Nou " -0x8b69: "Yi " -0x8b6a: "Ai " -0x8b6b: "Zhan " -0x8b6c: "Pi " -0x8b6d: "Hui " -0x8b6e: "Hua " -0x8b6f: "Yi " -0x8b70: "Yi " -0x8b71: "Shan " -0x8b72: "Rang " -0x8b73: "Nou " -0x8b74: "Qian " -0x8b75: "Zhui " -0x8b76: "Ta " -0x8b77: "Hu " -0x8b78: "Zhou " -0x8b79: "Hao " -0x8b7a: "Ye " -0x8b7b: "Ying " -0x8b7c: "Jian " -0x8b7d: "Yu " -0x8b7e: "Jian " -0x8b7f: "Hui " -0x8b80: "Du " -0x8b81: "Zhe " -0x8b82: "Xuan " -0x8b83: "Zan " -0x8b84: "Lei " -0x8b85: "Shen " -0x8b86: "Wei " -0x8b87: "Chan " -0x8b88: "Li " -0x8b89: "Yi " -0x8b8a: "Bian " -0x8b8b: "Zhe " -0x8b8c: "Yan " -0x8b8d: "E " -0x8b8e: "Chou " -0x8b8f: "Wei " -0x8b90: "Chou " -0x8b91: "Yao " -0x8b92: "Chan " -0x8b93: "Rang " -0x8b94: "Yin " -0x8b95: "Lan " -0x8b96: "Chen " -0x8b97: "Huo " -0x8b98: "Zhe " -0x8b99: "Huan " -0x8b9a: "Zan " -0x8b9b: "Yi " -0x8b9c: "Dang " -0x8b9d: "Zhan " -0x8b9e: "Yan " -0x8b9f: "Du " -0x8ba0: "Yan " -0x8ba1: "Ji " -0x8ba2: "Ding " -0x8ba3: "Fu " -0x8ba4: "Ren " -0x8ba5: "Ji " -0x8ba6: "Jie " -0x8ba7: "Hong " -0x8ba8: "Tao " -0x8ba9: "Rang " -0x8baa: "Shan " -0x8bab: "Qi " -0x8bac: "Tuo " -0x8bad: "Xun " -0x8bae: "Yi " -0x8baf: "Xun " -0x8bb0: "Ji " -0x8bb1: "Ren " -0x8bb2: "Jiang " -0x8bb3: "Hui " -0x8bb4: "Ou " -0x8bb5: "Ju " -0x8bb6: "Ya " -0x8bb7: "Ne " -0x8bb8: "Xu " -0x8bb9: "E " -0x8bba: "Lun " -0x8bbb: "Xiong " -0x8bbc: "Song " -0x8bbd: "Feng " -0x8bbe: "She " -0x8bbf: "Fang " -0x8bc0: "Jue " -0x8bc1: "Zheng " -0x8bc2: "Gu " -0x8bc3: "He " -0x8bc4: "Ping " -0x8bc5: "Zu " -0x8bc6: "Shi " -0x8bc7: "Xiong " -0x8bc8: "Zha " -0x8bc9: "Su " -0x8bca: "Zhen " -0x8bcb: "Di " -0x8bcc: "Zou " -0x8bcd: "Ci " -0x8bce: "Qu " -0x8bcf: "Zhao " -0x8bd0: "Bi " -0x8bd1: "Yi " -0x8bd2: "Yi " -0x8bd3: "Kuang " -0x8bd4: "Lei " -0x8bd5: "Shi " -0x8bd6: "Gua " -0x8bd7: "Shi " -0x8bd8: "Jie " -0x8bd9: "Hui " -0x8bda: "Cheng " -0x8bdb: "Zhu " -0x8bdc: "Shen " -0x8bdd: "Hua " -0x8bde: "Dan " -0x8bdf: "Gou " -0x8be0: "Quan " -0x8be1: "Gui " -0x8be2: "Xun " -0x8be3: "Yi " -0x8be4: "Zheng " -0x8be5: "Gai " -0x8be6: "Xiang " -0x8be7: "Cha " -0x8be8: "Hun " -0x8be9: "Xu " -0x8bea: "Zhou " -0x8beb: "Jie " -0x8bec: "Wu " -0x8bed: "Yu " -0x8bee: "Qiao " -0x8bef: "Wu " -0x8bf0: "Gao " -0x8bf1: "You " -0x8bf2: "Hui " -0x8bf3: "Kuang " -0x8bf4: "Shuo " -0x8bf5: "Song " -0x8bf6: "Ai " -0x8bf7: "Qing " -0x8bf8: "Zhu " -0x8bf9: "Zou " -0x8bfa: "Nuo " -0x8bfb: "Du " -0x8bfc: "Zhuo " -0x8bfd: "Fei " -0x8bfe: "Ke " -0x8bff: "Wei " -/* x08c */ -0x8c00: "Yu " -0x8c01: "Shui " -0x8c02: "Shen " -0x8c03: "Diao " -0x8c04: "Chan " -0x8c05: "Liang " -0x8c06: "Zhun " -0x8c07: "Sui " -0x8c08: "Tan " -0x8c09: "Shen " -0x8c0a: "Yi " -0x8c0b: "Mou " -0x8c0c: "Chen " -0x8c0d: "Die " -0x8c0e: "Huang " -0x8c0f: "Jian " -0x8c10: "Xie " -0x8c11: "Nue " -0x8c12: "Ye " -0x8c13: "Wei " -0x8c14: "E " -0x8c15: "Yu " -0x8c16: "Xuan " -0x8c17: "Chan " -0x8c18: "Zi " -0x8c19: "An " -0x8c1a: "Yan " -0x8c1b: "Di " -0x8c1c: "Mi " -0x8c1d: "Pian " -0x8c1e: "Xu " -0x8c1f: "Mo " -0x8c20: "Dang " -0x8c21: "Su " -0x8c22: "Xie " -0x8c23: "Yao " -0x8c24: "Bang " -0x8c25: "Shi " -0x8c26: "Qian " -0x8c27: "Mi " -0x8c28: "Jin " -0x8c29: "Man " -0x8c2a: "Zhe " -0x8c2b: "Jian " -0x8c2c: "Miu " -0x8c2d: "Tan " -0x8c2e: "Zen " -0x8c2f: "Qiao " -0x8c30: "Lan " -0x8c31: "Pu " -0x8c32: "Jue " -0x8c33: "Yan " -0x8c34: "Qian " -0x8c35: "Zhan " -0x8c36: "Chen " -0x8c37: "Gu " -0x8c38: "Qian " -0x8c39: "Hong " -0x8c3a: "Xia " -0x8c3b: "Jue " -0x8c3c: "Hong " -0x8c3d: "Han " -0x8c3e: "Hong " -0x8c3f: "Xi " -0x8c40: "Xi " -0x8c41: "Huo " -0x8c42: "Liao " -0x8c43: "Han " -0x8c44: "Du " -0x8c45: "Long " -0x8c46: "Dou " -0x8c47: "Jiang " -0x8c48: "Qi " -0x8c49: "Shi " -0x8c4a: "Li " -0x8c4b: "Deng " -0x8c4c: "Wan " -0x8c4d: "Bi " -0x8c4e: "Shu " -0x8c4f: "Xian " -0x8c50: "Feng " -0x8c51: "Zhi " -0x8c52: "Zhi " -0x8c53: "Yan " -0x8c54: "Yan " -0x8c55: "Shi " -0x8c56: "Chu " -0x8c57: "Hui " -0x8c58: "Tun " -0x8c59: "Yi " -0x8c5a: "Tun " -0x8c5b: "Yi " -0x8c5c: "Jian " -0x8c5d: "Ba " -0x8c5e: "Hou " -0x8c5f: "E " -0x8c60: "Cu " -0x8c61: "Xiang " -0x8c62: "Huan " -0x8c63: "Jian " -0x8c64: "Ken " -0x8c65: "Gai " -0x8c66: "Qu " -0x8c67: "Fu " -0x8c68: "Xi " -0x8c69: "Bin " -0x8c6a: "Hao " -0x8c6b: "Yu " -0x8c6c: "Zhu " -0x8c6d: "Jia " -0x8c6e: "[?] " -0x8c6f: "Xi " -0x8c70: "Bo " -0x8c71: "Wen " -0x8c72: "Huan " -0x8c73: "Bin " -0x8c74: "Di " -0x8c75: "Zong " -0x8c76: "Fen " -0x8c77: "Yi " -0x8c78: "Zhi " -0x8c79: "Bao " -0x8c7a: "Chai " -0x8c7b: "Han " -0x8c7c: "Pi " -0x8c7d: "Na " -0x8c7e: "Pi " -0x8c7f: "Gou " -0x8c80: "Na " -0x8c81: "You " -0x8c82: "Diao " -0x8c83: "Mo " -0x8c84: "Si " -0x8c85: "Xiu " -0x8c86: "Huan " -0x8c87: "Kun " -0x8c88: "He " -0x8c89: "He " -0x8c8a: "Mo " -0x8c8b: "Han " -0x8c8c: "Mao " -0x8c8d: "Li " -0x8c8e: "Ni " -0x8c8f: "Bi " -0x8c90: "Yu " -0x8c91: "Jia " -0x8c92: "Tuan " -0x8c93: "Mao " -0x8c94: "Pi " -0x8c95: "Xi " -0x8c96: "E " -0x8c97: "Ju " -0x8c98: "Mo " -0x8c99: "Chu " -0x8c9a: "Tan " -0x8c9b: "Huan " -0x8c9c: "Jue " -0x8c9d: "Bei " -0x8c9e: "Zhen " -0x8c9f: "Yuan " -0x8ca0: "Fu " -0x8ca1: "Cai " -0x8ca2: "Gong " -0x8ca3: "Te " -0x8ca4: "Yi " -0x8ca5: "Hang " -0x8ca6: "Wan " -0x8ca7: "Pin " -0x8ca8: "Huo " -0x8ca9: "Fan " -0x8caa: "Tan " -0x8cab: "Guan " -0x8cac: "Ze " -0x8cad: "Zhi " -0x8cae: "Er " -0x8caf: "Zhu " -0x8cb0: "Shi " -0x8cb1: "Bi " -0x8cb2: "Zi " -0x8cb3: "Er " -0x8cb4: "Gui " -0x8cb5: "Pian " -0x8cb6: "Bian " -0x8cb7: "Mai " -0x8cb8: "Dai " -0x8cb9: "Sheng " -0x8cba: "Kuang " -0x8cbb: "Fei " -0x8cbc: "Tie " -0x8cbd: "Yi " -0x8cbe: "Chi " -0x8cbf: "Mao " -0x8cc0: "He " -0x8cc1: "Bi " -0x8cc2: "Lu " -0x8cc3: "Ren " -0x8cc4: "Hui " -0x8cc5: "Gai " -0x8cc6: "Pian " -0x8cc7: "Zi " -0x8cc8: "Jia " -0x8cc9: "Xu " -0x8cca: "Zei " -0x8ccb: "Jiao " -0x8ccc: "Gai " -0x8ccd: "Zang " -0x8cce: "Jian " -0x8ccf: "Ying " -0x8cd0: "Xun " -0x8cd1: "Zhen " -0x8cd2: "She " -0x8cd3: "Bin " -0x8cd4: "Bin " -0x8cd5: "Qiu " -0x8cd6: "She " -0x8cd7: "Chuan " -0x8cd8: "Zang " -0x8cd9: "Zhou " -0x8cda: "Lai " -0x8cdb: "Zan " -0x8cdc: "Si " -0x8cdd: "Chen " -0x8cde: "Shang " -0x8cdf: "Tian " -0x8ce0: "Pei " -0x8ce1: "Geng " -0x8ce2: "Xian " -0x8ce3: "Mai " -0x8ce4: "Jian " -0x8ce5: "Sui " -0x8ce6: "Fu " -0x8ce7: "Tan " -0x8ce8: "Cong " -0x8ce9: "Cong " -0x8cea: "Zhi " -0x8ceb: "Ji " -0x8cec: "Zhang " -0x8ced: "Du " -0x8cee: "Jin " -0x8cef: "Xiong " -0x8cf0: "Shun " -0x8cf1: "Yun " -0x8cf2: "Bao " -0x8cf3: "Zai " -0x8cf4: "Lai " -0x8cf5: "Feng " -0x8cf6: "Cang " -0x8cf7: "Ji " -0x8cf8: "Sheng " -0x8cf9: "Ai " -0x8cfa: "Zhuan " -0x8cfb: "Fu " -0x8cfc: "Gou " -0x8cfd: "Sai " -0x8cfe: "Ze " -0x8cff: "Liao " -/* x08d */ -0x8d00: "Wei " -0x8d01: "Bai " -0x8d02: "Chen " -0x8d03: "Zhuan " -0x8d04: "Zhi " -0x8d05: "Zhui " -0x8d06: "Biao " -0x8d07: "Yun " -0x8d08: "Zeng " -0x8d09: "Tan " -0x8d0a: "Zan " -0x8d0b: "Yan " -0x8d0c: "[?] " -0x8d0d: "Shan " -0x8d0e: "Wan " -0x8d0f: "Ying " -0x8d10: "Jin " -0x8d11: "Gan " -0x8d12: "Xian " -0x8d13: "Zang " -0x8d14: "Bi " -0x8d15: "Du " -0x8d16: "Shu " -0x8d17: "Yan " -0x8d18: "[?] " -0x8d19: "Xuan " -0x8d1a: "Long " -0x8d1b: "Gan " -0x8d1c: "Zang " -0x8d1d: "Bei " -0x8d1e: "Zhen " -0x8d1f: "Fu " -0x8d20: "Yuan " -0x8d21: "Gong " -0x8d22: "Cai " -0x8d23: "Ze " -0x8d24: "Xian " -0x8d25: "Bai " -0x8d26: "Zhang " -0x8d27: "Huo " -0x8d28: "Zhi " -0x8d29: "Fan " -0x8d2a: "Tan " -0x8d2b: "Pin " -0x8d2c: "Bian " -0x8d2d: "Gou " -0x8d2e: "Zhu " -0x8d2f: "Guan " -0x8d30: "Er " -0x8d31: "Jian " -0x8d32: "Bi " -0x8d33: "Shi " -0x8d34: "Tie " -0x8d35: "Gui " -0x8d36: "Kuang " -0x8d37: "Dai " -0x8d38: "Mao " -0x8d39: "Fei " -0x8d3a: "He " -0x8d3b: "Yi " -0x8d3c: "Zei " -0x8d3d: "Zhi " -0x8d3e: "Jia " -0x8d3f: "Hui " -0x8d40: "Zi " -0x8d41: "Ren " -0x8d42: "Lu " -0x8d43: "Zang " -0x8d44: "Zi " -0x8d45: "Gai " -0x8d46: "Jin " -0x8d47: "Qiu " -0x8d48: "Zhen " -0x8d49: "Lai " -0x8d4a: "She " -0x8d4b: "Fu " -0x8d4c: "Du " -0x8d4d: "Ji " -0x8d4e: "Shu " -0x8d4f: "Shang " -0x8d50: "Si " -0x8d51: "Bi " -0x8d52: "Zhou " -0x8d53: "Geng " -0x8d54: "Pei " -0x8d55: "Tan " -0x8d56: "Lai " -0x8d57: "Feng " -0x8d58: "Zhui " -0x8d59: "Fu " -0x8d5a: "Zhuan " -0x8d5b: "Sai " -0x8d5c: "Ze " -0x8d5d: "Yan " -0x8d5e: "Zan " -0x8d5f: "Yun " -0x8d60: "Zeng " -0x8d61: "Shan " -0x8d62: "Ying " -0x8d63: "Gan " -0x8d64: "Chi " -0x8d65: "Xi " -0x8d66: "She " -0x8d67: "Nan " -0x8d68: "Xiong " -0x8d69: "Xi " -0x8d6a: "Cheng " -0x8d6b: "He " -0x8d6c: "Cheng " -0x8d6d: "Zhe " -0x8d6e: "Xia " -0x8d6f: "Tang " -0x8d70: "Zou " -0x8d71: "Zou " -0x8d72: "Li " -0x8d73: "Jiu " -0x8d74: "Fu " -0x8d75: "Zhao " -0x8d76: "Gan " -0x8d77: "Qi " -0x8d78: "Shan " -0x8d79: "Qiong " -0x8d7a: "Qin " -0x8d7b: "Xian " -0x8d7c: "Ci " -0x8d7d: "Jue " -0x8d7e: "Qin " -0x8d7f: "Chi " -0x8d80: "Ci " -0x8d81: "Chen " -0x8d82: "Chen " -0x8d83: "Die " -0x8d84: "Ju " -0x8d85: "Chao " -0x8d86: "Di " -0x8d87: "Se " -0x8d88: "Zhan " -0x8d89: "Zhu " -0x8d8a: "Yue " -0x8d8b: "Qu " -0x8d8c: "Jie " -0x8d8d: "Chi " -0x8d8e: "Chu " -0x8d8f: "Gua " -0x8d90: "Xue " -0x8d91: "Ci " -0x8d92: "Tiao " -0x8d93: "Duo " -0x8d94: "Lie " -0x8d95: "Gan " -0x8d96: "Suo " -0x8d97: "Cu " -0x8d98: "Xi " -0x8d99: "Zhao " -0x8d9a: "Su " -0x8d9b: "Yin " -0x8d9c: "Ju " -0x8d9d: "Jian " -0x8d9e: "Que " -0x8d9f: "Tang " -0x8da0: "Chuo " -0x8da1: "Cui " -0x8da2: "Lu " -0x8da3: "Qu " -0x8da4: "Dang " -0x8da5: "Qiu " -0x8da6: "Zi " -0x8da7: "Ti " -0x8da8: "Qu " -0x8da9: "Chi " -0x8daa: "Huang " -0x8dab: "Qiao " -0x8dac: "Qiao " -0x8dad: "Yao " -0x8dae: "Zao " -0x8daf: "Ti " -0x8db0: "[?] " -0x8db1: "Zan " -0x8db2: "Zan " -0x8db3: "Zu " -0x8db4: "Pa " -0x8db5: "Bao " -0x8db6: "Ku " -0x8db7: "Ke " -0x8db8: "Dun " -0x8db9: "Jue " -0x8dba: "Fu " -0x8dbb: "Chen " -0x8dbc: "Jian " -0x8dbd: "Fang " -0x8dbe: "Zhi " -0x8dbf: "Sa " -0x8dc0: "Yue " -0x8dc1: "Pa " -0x8dc2: "Qi " -0x8dc3: "Yue " -0x8dc4: "Qiang " -0x8dc5: "Tuo " -0x8dc6: "Tai " -0x8dc7: "Yi " -0x8dc8: "Nian " -0x8dc9: "Ling " -0x8dca: "Mei " -0x8dcb: "Ba " -0x8dcc: "Die " -0x8dcd: "Ku " -0x8dce: "Tuo " -0x8dcf: "Jia " -0x8dd0: "Ci " -0x8dd1: "Pao " -0x8dd2: "Qia " -0x8dd3: "Zhu " -0x8dd4: "Ju " -0x8dd5: "Die " -0x8dd6: "Zhi " -0x8dd7: "Fu " -0x8dd8: "Pan " -0x8dd9: "Ju " -0x8dda: "Shan " -0x8ddb: "Bo " -0x8ddc: "Ni " -0x8ddd: "Ju " -0x8dde: "Li " -0x8ddf: "Gen " -0x8de0: "Yi " -0x8de1: "Ji " -0x8de2: "Dai " -0x8de3: "Xian " -0x8de4: "Jiao " -0x8de5: "Duo " -0x8de6: "Zhu " -0x8de7: "Zhuan " -0x8de8: "Kua " -0x8de9: "Zhuai " -0x8dea: "Gui " -0x8deb: "Qiong " -0x8dec: "Kui " -0x8ded: "Xiang " -0x8dee: "Chi " -0x8def: "Lu " -0x8df0: "Beng " -0x8df1: "Zhi " -0x8df2: "Jia " -0x8df3: "Tiao " -0x8df4: "Cai " -0x8df5: "Jian " -0x8df6: "Ta " -0x8df7: "Qiao " -0x8df8: "Bi " -0x8df9: "Xian " -0x8dfa: "Duo " -0x8dfb: "Ji " -0x8dfc: "Ju " -0x8dfd: "Ji " -0x8dfe: "Shu " -0x8dff: "Tu " -/* x08e */ -0x8e00: "Chu " -0x8e01: "Jing " -0x8e02: "Nie " -0x8e03: "Xiao " -0x8e04: "Bo " -0x8e05: "Chi " -0x8e06: "Qun " -0x8e07: "Mou " -0x8e08: "Shu " -0x8e09: "Lang " -0x8e0a: "Yong " -0x8e0b: "Jiao " -0x8e0c: "Chou " -0x8e0d: "Qiao " -0x8e0e: "[?] " -0x8e0f: "Ta " -0x8e10: "Jian " -0x8e11: "Qi " -0x8e12: "Wo " -0x8e13: "Wei " -0x8e14: "Zhuo " -0x8e15: "Jie " -0x8e16: "Ji " -0x8e17: "Nie " -0x8e18: "Ju " -0x8e19: "Ju " -0x8e1a: "Lun " -0x8e1b: "Lu " -0x8e1c: "Leng " -0x8e1d: "Huai " -0x8e1e: "Ju " -0x8e1f: "Chi " -0x8e20: "Wan " -0x8e21: "Quan " -0x8e22: "Ti " -0x8e23: "Bo " -0x8e24: "Zu " -0x8e25: "Qie " -0x8e26: "Ji " -0x8e27: "Cu " -0x8e28: "Zong " -0x8e29: "Cai " -0x8e2a: "Zong " -0x8e2b: "Peng " -0x8e2c: "Zhi " -0x8e2d: "Zheng " -0x8e2e: "Dian " -0x8e2f: "Zhi " -0x8e30: "Yu " -0x8e31: "Duo " -0x8e32: "Dun " -0x8e33: "Chun " -0x8e34: "Yong " -0x8e35: "Zhong " -0x8e36: "Di " -0x8e37: "Zhe " -0x8e38: "Chen " -0x8e39: "Chuai " -0x8e3a: "Jian " -0x8e3b: "Gua " -0x8e3c: "Tang " -0x8e3d: "Ju " -0x8e3e: "Fu " -0x8e3f: "Zu " -0x8e40: "Die " -0x8e41: "Pian " -0x8e42: "Rou " -0x8e43: "Nuo " -0x8e44: "Ti " -0x8e45: "Cha " -0x8e46: "Tui " -0x8e47: "Jian " -0x8e48: "Dao " -0x8e49: "Cuo " -0x8e4a: "Xi " -0x8e4b: "Ta " -0x8e4c: "Qiang " -0x8e4d: "Zhan " -0x8e4e: "Dian " -0x8e4f: "Ti " -0x8e50: "Ji " -0x8e51: "Nie " -0x8e52: "Man " -0x8e53: "Liu " -0x8e54: "Zhan " -0x8e55: "Bi " -0x8e56: "Chong " -0x8e57: "Lu " -0x8e58: "Liao " -0x8e59: "Cu " -0x8e5a: "Tang " -0x8e5b: "Dai " -0x8e5c: "Suo " -0x8e5d: "Xi " -0x8e5e: "Kui " -0x8e5f: "Ji " -0x8e60: "Zhi " -0x8e61: "Qiang " -0x8e62: "Di " -0x8e63: "Man " -0x8e64: "Zong " -0x8e65: "Lian " -0x8e66: "Beng " -0x8e67: "Zao " -0x8e68: "Nian " -0x8e69: "Bie " -0x8e6a: "Tui " -0x8e6b: "Ju " -0x8e6c: "Deng " -0x8e6d: "Ceng " -0x8e6e: "Xian " -0x8e6f: "Fan " -0x8e70: "Chu " -0x8e71: "Zhong " -0x8e72: "Dun " -0x8e73: "Bo " -0x8e74: "Cu " -0x8e75: "Zu " -0x8e76: "Jue " -0x8e77: "Jue " -0x8e78: "Lin " -0x8e79: "Ta " -0x8e7a: "Qiao " -0x8e7b: "Qiao " -0x8e7c: "Pu " -0x8e7d: "Liao " -0x8e7e: "Dun " -0x8e7f: "Cuan " -0x8e80: "Kuang " -0x8e81: "Zao " -0x8e82: "Ta " -0x8e83: "Bi " -0x8e84: "Bi " -0x8e85: "Zhu " -0x8e86: "Ju " -0x8e87: "Chu " -0x8e88: "Qiao " -0x8e89: "Dun " -0x8e8a: "Chou " -0x8e8b: "Ji " -0x8e8c: "Wu " -0x8e8d: "Yue " -0x8e8e: "Nian " -0x8e8f: "Lin " -0x8e90: "Lie " -0x8e91: "Zhi " -0x8e92: "Li " -0x8e93: "Zhi " -0x8e94: "Chan " -0x8e95: "Chu " -0x8e96: "Duan " -0x8e97: "Wei " -0x8e98: "Long " -0x8e99: "Lin " -0x8e9a: "Xian " -0x8e9b: "Wei " -0x8e9c: "Zuan " -0x8e9d: "Lan " -0x8e9e: "Xie " -0x8e9f: "Rang " -0x8ea0: "Xie " -0x8ea1: "Nie " -0x8ea2: "Ta " -0x8ea3: "Qu " -0x8ea4: "Jie " -0x8ea5: "Cuan " -0x8ea6: "Zuan " -0x8ea7: "Xi " -0x8ea8: "Kui " -0x8ea9: "Jue " -0x8eaa: "Lin " -0x8eab: "Shen " -0x8eac: "Gong " -0x8ead: "Dan " -0x8eae: "Segare " -0x8eaf: "Qu " -0x8eb0: "Ti " -0x8eb1: "Duo " -0x8eb2: "Duo " -0x8eb3: "Gong " -0x8eb4: "Lang " -0x8eb5: "Nerau " -0x8eb6: "Luo " -0x8eb7: "Ai " -0x8eb8: "Ji " -0x8eb9: "Ju " -0x8eba: "Tang " -0x8ebb: "Utsuke " -0x8ebc: "[?] " -0x8ebd: "Yan " -0x8ebe: "Shitsuke " -0x8ebf: "Kang " -0x8ec0: "Qu " -0x8ec1: "Lou " -0x8ec2: "Lao " -0x8ec3: "Tuo " -0x8ec4: "Zhi " -0x8ec5: "Yagate " -0x8ec6: "Ti " -0x8ec7: "Dao " -0x8ec8: "Yagate " -0x8ec9: "Yu " -0x8eca: "Che " -0x8ecb: "Ya " -0x8ecc: "Gui " -0x8ecd: "Jun " -0x8ece: "Wei " -0x8ecf: "Yue " -0x8ed0: "Xin " -0x8ed1: "Di " -0x8ed2: "Xuan " -0x8ed3: "Fan " -0x8ed4: "Ren " -0x8ed5: "Shan " -0x8ed6: "Qiang " -0x8ed7: "Shu " -0x8ed8: "Tun " -0x8ed9: "Chen " -0x8eda: "Dai " -0x8edb: "E " -0x8edc: "Na " -0x8edd: "Qi " -0x8ede: "Mao " -0x8edf: "Ruan " -0x8ee0: "Ren " -0x8ee1: "Fan " -0x8ee2: "Zhuan " -0x8ee3: "Hong " -0x8ee4: "Hu " -0x8ee5: "Qu " -0x8ee6: "Huang " -0x8ee7: "Di " -0x8ee8: "Ling " -0x8ee9: "Dai " -0x8eea: "Ao " -0x8eeb: "Zhen " -0x8eec: "Fan " -0x8eed: "Kuang " -0x8eee: "Ang " -0x8eef: "Peng " -0x8ef0: "Bei " -0x8ef1: "Gu " -0x8ef2: "Ku " -0x8ef3: "Pao " -0x8ef4: "Zhu " -0x8ef5: "Rong " -0x8ef6: "E " -0x8ef7: "Ba " -0x8ef8: "Zhou " -0x8ef9: "Zhi " -0x8efa: "Yao " -0x8efb: "Ke " -0x8efc: "Yi " -0x8efd: "Qing " -0x8efe: "Shi " -0x8eff: "Ping " -/* x08f */ -0x8f00: "Er " -0x8f01: "Qiong " -0x8f02: "Ju " -0x8f03: "Jiao " -0x8f04: "Guang " -0x8f05: "Lu " -0x8f06: "Kai " -0x8f07: "Quan " -0x8f08: "Zhou " -0x8f09: "Zai " -0x8f0a: "Zhi " -0x8f0b: "She " -0x8f0c: "Liang " -0x8f0d: "Yu " -0x8f0e: "Shao " -0x8f0f: "You " -0x8f10: "Huan " -0x8f11: "Yun " -0x8f12: "Zhe " -0x8f13: "Wan " -0x8f14: "Fu " -0x8f15: "Qing " -0x8f16: "Zhou " -0x8f17: "Ni " -0x8f18: "Ling " -0x8f19: "Zhe " -0x8f1a: "Zhan " -0x8f1b: "Liang " -0x8f1c: "Zi " -0x8f1d: "Hui " -0x8f1e: "Wang " -0x8f1f: "Chuo " -0x8f20: "Guo " -0x8f21: "Kan " -0x8f22: "Yi " -0x8f23: "Peng " -0x8f24: "Qian " -0x8f25: "Gun " -0x8f26: "Nian " -0x8f27: "Pian " -0x8f28: "Guan " -0x8f29: "Bei " -0x8f2a: "Lun " -0x8f2b: "Pai " -0x8f2c: "Liang " -0x8f2d: "Ruan " -0x8f2e: "Rou " -0x8f2f: "Ji " -0x8f30: "Yang " -0x8f31: "Xian " -0x8f32: "Chuan " -0x8f33: "Cou " -0x8f34: "Qun " -0x8f35: "Ge " -0x8f36: "You " -0x8f37: "Hong " -0x8f38: "Shu " -0x8f39: "Fu " -0x8f3a: "Zi " -0x8f3b: "Fu " -0x8f3c: "Wen " -0x8f3d: "Ben " -0x8f3e: "Zhan " -0x8f3f: "Yu " -0x8f40: "Wen " -0x8f41: "Tao " -0x8f42: "Gu " -0x8f43: "Zhen " -0x8f44: "Xia " -0x8f45: "Yuan " -0x8f46: "Lu " -0x8f47: "Jiu " -0x8f48: "Chao " -0x8f49: "Zhuan " -0x8f4a: "Wei " -0x8f4b: "Hun " -0x8f4c: "Sori " -0x8f4d: "Che " -0x8f4e: "Jiao " -0x8f4f: "Zhan " -0x8f50: "Pu " -0x8f51: "Lao " -0x8f52: "Fen " -0x8f53: "Fan " -0x8f54: "Lin " -0x8f55: "Ge " -0x8f56: "Se " -0x8f57: "Kan " -0x8f58: "Huan " -0x8f59: "Yi " -0x8f5a: "Ji " -0x8f5b: "Dui " -0x8f5c: "Er " -0x8f5d: "Yu " -0x8f5e: "Xian " -0x8f5f: "Hong " -0x8f60: "Lei " -0x8f61: "Pei " -0x8f62: "Li " -0x8f63: "Li " -0x8f64: "Lu " -0x8f65: "Lin " -0x8f66: "Che " -0x8f67: "Ya " -0x8f68: "Gui " -0x8f69: "Xuan " -0x8f6a: "Di " -0x8f6b: "Ren " -0x8f6c: "Zhuan " -0x8f6d: "E " -0x8f6e: "Lun " -0x8f6f: "Ruan " -0x8f70: "Hong " -0x8f71: "Ku " -0x8f72: "Ke " -0x8f73: "Lu " -0x8f74: "Zhou " -0x8f75: "Zhi " -0x8f76: "Yi " -0x8f77: "Hu " -0x8f78: "Zhen " -0x8f79: "Li " -0x8f7a: "Yao " -0x8f7b: "Qing " -0x8f7c: "Shi " -0x8f7d: "Zai " -0x8f7e: "Zhi " -0x8f7f: "Jiao " -0x8f80: "Zhou " -0x8f81: "Quan " -0x8f82: "Lu " -0x8f83: "Jiao " -0x8f84: "Zhe " -0x8f85: "Fu " -0x8f86: "Liang " -0x8f87: "Nian " -0x8f88: "Bei " -0x8f89: "Hui " -0x8f8a: "Gun " -0x8f8b: "Wang " -0x8f8c: "Liang " -0x8f8d: "Chuo " -0x8f8e: "Zi " -0x8f8f: "Cou " -0x8f90: "Fu " -0x8f91: "Ji " -0x8f92: "Wen " -0x8f93: "Shu " -0x8f94: "Pei " -0x8f95: "Yuan " -0x8f96: "Xia " -0x8f97: "Zhan " -0x8f98: "Lu " -0x8f99: "Che " -0x8f9a: "Lin " -0x8f9b: "Xin " -0x8f9c: "Gu " -0x8f9d: "Ci " -0x8f9e: "Ci " -0x8f9f: "Pi " -0x8fa0: "Zui " -0x8fa1: "Bian " -0x8fa2: "La " -0x8fa3: "La " -0x8fa4: "Ci " -0x8fa5: "Xue " -0x8fa6: "Ban " -0x8fa7: "Bian " -0x8fa8: "Bian " -0x8fa9: "Bian " -0x8faa: "[?] " -0x8fab: "Bian " -0x8fac: "Ban " -0x8fad: "Ci " -0x8fae: "Bian " -0x8faf: "Bian " -0x8fb0: "Chen " -0x8fb1: "Ru " -0x8fb2: "Nong " -0x8fb3: "Nong " -0x8fb4: "Zhen " -0x8fb5: "Chuo " -0x8fb6: "Chuo " -0x8fb7: "Suberu " -0x8fb8: "Reng " -0x8fb9: "Bian " -0x8fba: "Bian " -0x8fbb: "Sip " -0x8fbc: "Ip " -0x8fbd: "Liao " -0x8fbe: "Da " -0x8fbf: "Chan " -0x8fc0: "Gan " -0x8fc1: "Qian " -0x8fc2: "Yu " -0x8fc3: "Yu " -0x8fc4: "Qi " -0x8fc5: "Xun " -0x8fc6: "Yi " -0x8fc7: "Guo " -0x8fc8: "Mai " -0x8fc9: "Qi " -0x8fca: "Za " -0x8fcb: "Wang " -0x8fcc: "Jia " -0x8fcd: "Zhun " -0x8fce: "Ying " -0x8fcf: "Ti " -0x8fd0: "Yun " -0x8fd1: "Jin " -0x8fd2: "Hang " -0x8fd3: "Ya " -0x8fd4: "Fan " -0x8fd5: "Wu " -0x8fd6: "Da " -0x8fd7: "E " -0x8fd8: "Huan " -0x8fd9: "Zhe " -0x8fda: "Totemo " -0x8fdb: "Jin " -0x8fdc: "Yuan " -0x8fdd: "Wei " -0x8fde: "Lian " -0x8fdf: "Chi " -0x8fe0: "Che " -0x8fe1: "Ni " -0x8fe2: "Tiao " -0x8fe3: "Zhi " -0x8fe4: "Yi " -0x8fe5: "Jiong " -0x8fe6: "Jia " -0x8fe7: "Chen " -0x8fe8: "Dai " -0x8fe9: "Er " -0x8fea: "Di " -0x8feb: "Po " -0x8fec: "Wang " -0x8fed: "Die " -0x8fee: "Ze " -0x8fef: "Tao " -0x8ff0: "Shu " -0x8ff1: "Tuo " -0x8ff2: "Kep " -0x8ff3: "Jing " -0x8ff4: "Hui " -0x8ff5: "Tong " -0x8ff6: "You " -0x8ff7: "Mi " -0x8ff8: "Beng " -0x8ff9: "Ji " -0x8ffa: "Nai " -0x8ffb: "Yi " -0x8ffc: "Jie " -0x8ffd: "Zhui " -0x8ffe: "Lie " -0x8fff: "Xun " -/* x090 */ -0x9000: "Tui " -0x9001: "Song " -0x9002: "Gua " -0x9003: "Tao " -0x9004: "Pang " -0x9005: "Hou " -0x9006: "Ni " -0x9007: "Dun " -0x9008: "Jiong " -0x9009: "Xuan " -0x900a: "Xun " -0x900b: "Bu " -0x900c: "You " -0x900d: "Xiao " -0x900e: "Qiu " -0x900f: "Tou " -0x9010: "Zhu " -0x9011: "Qiu " -0x9012: "Di " -0x9013: "Di " -0x9014: "Tu " -0x9015: "Jing " -0x9016: "Ti " -0x9017: "Dou " -0x9018: "Yi " -0x9019: "Zhe " -0x901a: "Tong " -0x901b: "Guang " -0x901c: "Wu " -0x901d: "Shi " -0x901e: "Cheng " -0x901f: "Su " -0x9020: "Zao " -0x9021: "Qun " -0x9022: "Feng " -0x9023: "Lian " -0x9024: "Suo " -0x9025: "Hui " -0x9026: "Li " -0x9027: "Sako " -0x9028: "Lai " -0x9029: "Ben " -0x902a: "Cuo " -0x902b: "Jue " -0x902c: "Beng " -0x902d: "Huan " -0x902e: "Dai " -0x902f: "Lu " -0x9030: "You " -0x9031: "Zhou " -0x9032: "Jin " -0x9033: "Yu " -0x9034: "Chuo " -0x9035: "Kui " -0x9036: "Wei " -0x9037: "Ti " -0x9038: "Yi " -0x9039: "Da " -0x903a: "Yuan " -0x903b: "Luo " -0x903c: "Bi " -0x903d: "Nuo " -0x903e: "Yu " -0x903f: "Dang " -0x9040: "Sui " -0x9041: "Dun " -0x9042: "Sui " -0x9043: "Yan " -0x9044: "Chuan " -0x9045: "Chi " -0x9046: "Ti " -0x9047: "Yu " -0x9048: "Shi " -0x9049: "Zhen " -0x904a: "You " -0x904b: "Yun " -0x904c: "E " -0x904d: "Bian " -0x904e: "Guo " -0x904f: "E " -0x9050: "Xia " -0x9051: "Huang " -0x9052: "Qiu " -0x9053: "Dao " -0x9054: "Da " -0x9055: "Wei " -0x9056: "Appare " -0x9057: "Yi " -0x9058: "Gou " -0x9059: "Yao " -0x905a: "Chu " -0x905b: "Liu " -0x905c: "Xun " -0x905d: "Ta " -0x905e: "Di " -0x905f: "Chi " -0x9060: "Yuan " -0x9061: "Su " -0x9062: "Ta " -0x9063: "Qian " -0x9064: "[?] " -0x9065: "Yao " -0x9066: "Guan " -0x9067: "Zhang " -0x9068: "Ao " -0x9069: "Shi " -0x906a: "Ce " -0x906b: "Chi " -0x906c: "Su " -0x906d: "Zao " -0x906e: "Zhe " -0x906f: "Dun " -0x9070: "Di " -0x9071: "Lou " -0x9072: "Chi " -0x9073: "Cuo " -0x9074: "Lin " -0x9075: "Zun " -0x9076: "Rao " -0x9077: "Qian " -0x9078: "Xuan " -0x9079: "Yu " -0x907a: "Yi " -0x907b: "Wu " -0x907c: "Liao " -0x907d: "Ju " -0x907e: "Shi " -0x907f: "Bi " -0x9080: "Yao " -0x9081: "Mai " -0x9082: "Xie " -0x9083: "Sui " -0x9084: "Huan " -0x9085: "Zhan " -0x9086: "Teng " -0x9087: "Er " -0x9088: "Miao " -0x9089: "Bian " -0x908a: "Bian " -0x908b: "La " -0x908c: "Li " -0x908d: "Yuan " -0x908e: "Yao " -0x908f: "Luo " -0x9090: "Li " -0x9091: "Yi " -0x9092: "Ting " -0x9093: "Deng " -0x9094: "Qi " -0x9095: "Yong " -0x9096: "Shan " -0x9097: "Han " -0x9098: "Yu " -0x9099: "Mang " -0x909a: "Ru " -0x909b: "Qiong " -0x909c: "[?] " -0x909d: "Kuang " -0x909e: "Fu " -0x909f: "Kang " -0x90a0: "Bin " -0x90a1: "Fang " -0x90a2: "Xing " -0x90a3: "Na " -0x90a4: "Xin " -0x90a5: "Shen " -0x90a6: "Bang " -0x90a7: "Yuan " -0x90a8: "Cun " -0x90a9: "Huo " -0x90aa: "Xie " -0x90ab: "Bang " -0x90ac: "Wu " -0x90ad: "Ju " -0x90ae: "You " -0x90af: "Han " -0x90b0: "Tai " -0x90b1: "Qiu " -0x90b2: "Bi " -0x90b3: "Pei " -0x90b4: "Bing " -0x90b5: "Shao " -0x90b6: "Bei " -0x90b7: "Wa " -0x90b8: "Di " -0x90b9: "Zou " -0x90ba: "Ye " -0x90bb: "Lin " -0x90bc: "Kuang " -0x90bd: "Gui " -0x90be: "Zhu " -0x90bf: "Shi " -0x90c0: "Ku " -0x90c1: "Yu " -0x90c2: "Gai " -0x90c3: "Ge " -0x90c4: "Xi " -0x90c5: "Zhi " -0x90c6: "Ji " -0x90c7: "Xun " -0x90c8: "Hou " -0x90c9: "Xing " -0x90ca: "Jiao " -0x90cb: "Xi " -0x90cc: "Gui " -0x90cd: "Nuo " -0x90ce: "Lang " -0x90cf: "Jia " -0x90d0: "Kuai " -0x90d1: "Zheng " -0x90d2: "Otoko " -0x90d3: "Yun " -0x90d4: "Yan " -0x90d5: "Cheng " -0x90d6: "Dou " -0x90d7: "Chi " -0x90d8: "Lu " -0x90d9: "Fu " -0x90da: "Wu " -0x90db: "Fu " -0x90dc: "Gao " -0x90dd: "Hao " -0x90de: "Lang " -0x90df: "Jia " -0x90e0: "Geng " -0x90e1: "Jun " -0x90e2: "Ying " -0x90e3: "Bo " -0x90e4: "Xi " -0x90e5: "Bei " -0x90e6: "Li " -0x90e7: "Yun " -0x90e8: "Bu " -0x90e9: "Xiao " -0x90ea: "Qi " -0x90eb: "Pi " -0x90ec: "Qing " -0x90ed: "Guo " -0x90ee: "Zhou " -0x90ef: "Tan " -0x90f0: "Zou " -0x90f1: "Ping " -0x90f2: "Lai " -0x90f3: "Ni " -0x90f4: "Chen " -0x90f5: "You " -0x90f6: "Bu " -0x90f7: "Xiang " -0x90f8: "Dan " -0x90f9: "Ju " -0x90fa: "Yong " -0x90fb: "Qiao " -0x90fc: "Yi " -0x90fd: "Du " -0x90fe: "Yan " -0x90ff: "Mei " -/* x091 */ -0x9100: "Ruo " -0x9101: "Bei " -0x9102: "E " -0x9103: "Yu " -0x9104: "Juan " -0x9105: "Yu " -0x9106: "Yun " -0x9107: "Hou " -0x9108: "Kui " -0x9109: "Xiang " -0x910a: "Xiang " -0x910b: "Sou " -0x910c: "Tang " -0x910d: "Ming " -0x910e: "Xi " -0x910f: "Ru " -0x9110: "Chu " -0x9111: "Zi " -0x9112: "Zou " -0x9113: "Ju " -0x9114: "Wu " -0x9115: "Xiang " -0x9116: "Yun " -0x9117: "Hao " -0x9118: "Yong " -0x9119: "Bi " -0x911a: "Mo " -0x911b: "Chao " -0x911c: "Fu " -0x911d: "Liao " -0x911e: "Yin " -0x911f: "Zhuan " -0x9120: "Hu " -0x9121: "Qiao " -0x9122: "Yan " -0x9123: "Zhang " -0x9124: "Fan " -0x9125: "Qiao " -0x9126: "Xu " -0x9127: "Deng " -0x9128: "Bi " -0x9129: "Xin " -0x912a: "Bi " -0x912b: "Ceng " -0x912c: "Wei " -0x912d: "Zheng " -0x912e: "Mao " -0x912f: "Shan " -0x9130: "Lin " -0x9131: "Po " -0x9132: "Dan " -0x9133: "Meng " -0x9134: "Ye " -0x9135: "Cao " -0x9136: "Kuai " -0x9137: "Feng " -0x9138: "Meng " -0x9139: "Zou " -0x913a: "Kuang " -0x913b: "Lian " -0x913c: "Zan " -0x913d: "Chan " -0x913e: "You " -0x913f: "Qi " -0x9140: "Yan " -0x9141: "Chan " -0x9142: "Zan " -0x9143: "Ling " -0x9144: "Huan " -0x9145: "Xi " -0x9146: "Feng " -0x9147: "Zan " -0x9148: "Li " -0x9149: "You " -0x914a: "Ding " -0x914b: "Qiu " -0x914c: "Zhuo " -0x914d: "Pei " -0x914e: "Zhou " -0x914f: "Yi " -0x9150: "Hang " -0x9151: "Yu " -0x9152: "Jiu " -0x9153: "Yan " -0x9154: "Zui " -0x9155: "Mao " -0x9156: "Dan " -0x9157: "Xu " -0x9158: "Tou " -0x9159: "Zhen " -0x915a: "Fen " -0x915b: "Sakenomoto " -0x915c: "[?] " -0x915d: "Yun " -0x915e: "Tai " -0x915f: "Tian " -0x9160: "Qia " -0x9161: "Tuo " -0x9162: "Zuo " -0x9163: "Han " -0x9164: "Gu " -0x9165: "Su " -0x9166: "Po " -0x9167: "Chou " -0x9168: "Zai " -0x9169: "Ming " -0x916a: "Luo " -0x916b: "Chuo " -0x916c: "Chou " -0x916d: "You " -0x916e: "Tong " -0x916f: "Zhi " -0x9170: "Xian " -0x9171: "Jiang " -0x9172: "Cheng " -0x9173: "Yin " -0x9174: "Tu " -0x9175: "Xiao " -0x9176: "Mei " -0x9177: "Ku " -0x9178: "Suan " -0x9179: "Lei " -0x917a: "Pu " -0x917b: "Zui " -0x917c: "Hai " -0x917d: "Yan " -0x917e: "Xi " -0x917f: "Niang " -0x9180: "Wei " -0x9181: "Lu " -0x9182: "Lan " -0x9183: "Yan " -0x9184: "Tao " -0x9185: "Pei " -0x9186: "Zhan " -0x9187: "Chun " -0x9188: "Tan " -0x9189: "Zui " -0x918a: "Chuo " -0x918b: "Cu " -0x918c: "Kun " -0x918d: "Ti " -0x918e: "Mian " -0x918f: "Du " -0x9190: "Hu " -0x9191: "Xu " -0x9192: "Xing " -0x9193: "Tan " -0x9194: "Jiu " -0x9195: "Chun " -0x9196: "Yun " -0x9197: "Po " -0x9198: "Ke " -0x9199: "Sou " -0x919a: "Mi " -0x919b: "Quan " -0x919c: "Chou " -0x919d: "Cuo " -0x919e: "Yun " -0x919f: "Yong " -0x91a0: "Ang " -0x91a1: "Zha " -0x91a2: "Hai " -0x91a3: "Tang " -0x91a4: "Jiang " -0x91a5: "Piao " -0x91a6: "Shan " -0x91a7: "Yu " -0x91a8: "Li " -0x91a9: "Zao " -0x91aa: "Lao " -0x91ab: "Yi " -0x91ac: "Jiang " -0x91ad: "Pu " -0x91ae: "Jiao " -0x91af: "Xi " -0x91b0: "Tan " -0x91b1: "Po " -0x91b2: "Nong " -0x91b3: "Yi " -0x91b4: "Li " -0x91b5: "Ju " -0x91b6: "Jiao " -0x91b7: "Yi " -0x91b8: "Niang " -0x91b9: "Ru " -0x91ba: "Xun " -0x91bb: "Chou " -0x91bc: "Yan " -0x91bd: "Ling " -0x91be: "Mi " -0x91bf: "Mi " -0x91c0: "Niang " -0x91c1: "Xin " -0x91c2: "Jiao " -0x91c3: "Xi " -0x91c4: "Mi " -0x91c5: "Yan " -0x91c6: "Bian " -0x91c7: "Cai " -0x91c8: "Shi " -0x91c9: "You " -0x91ca: "Shi " -0x91cb: "Shi " -0x91cc: "Li " -0x91cd: "Zhong " -0x91ce: "Ye " -0x91cf: "Liang " -0x91d0: "Li " -0x91d1: "Jin " -0x91d2: "Jin " -0x91d3: "Qiu " -0x91d4: "Yi " -0x91d5: "Diao " -0x91d6: "Dao " -0x91d7: "Zhao " -0x91d8: "Ding " -0x91d9: "Po " -0x91da: "Qiu " -0x91db: "He " -0x91dc: "Fu " -0x91dd: "Zhen " -0x91de: "Zhi " -0x91df: "Ba " -0x91e0: "Luan " -0x91e1: "Fu " -0x91e2: "Nai " -0x91e3: "Diao " -0x91e4: "Shan " -0x91e5: "Qiao " -0x91e6: "Kou " -0x91e7: "Chuan " -0x91e8: "Zi " -0x91e9: "Fan " -0x91ea: "Yu " -0x91eb: "Hua " -0x91ec: "Han " -0x91ed: "Gong " -0x91ee: "Qi " -0x91ef: "Mang " -0x91f0: "Ri " -0x91f1: "Di " -0x91f2: "Si " -0x91f3: "Xi " -0x91f4: "Yi " -0x91f5: "Chai " -0x91f6: "Shi " -0x91f7: "Tu " -0x91f8: "Xi " -0x91f9: "Nu " -0x91fa: "Qian " -0x91fb: "Ishiyumi " -0x91fc: "Jian " -0x91fd: "Pi " -0x91fe: "Ye " -0x91ff: "Yin " -/* x092 */ -0x9200: "Ba " -0x9201: "Fang " -0x9202: "Chen " -0x9203: "Xing " -0x9204: "Tou " -0x9205: "Yue " -0x9206: "Yan " -0x9207: "Fu " -0x9208: "Pi " -0x9209: "Na " -0x920a: "Xin " -0x920b: "E " -0x920c: "Jue " -0x920d: "Dun " -0x920e: "Gou " -0x920f: "Yin " -0x9210: "Qian " -0x9211: "Ban " -0x9212: "Ji " -0x9213: "Ren " -0x9214: "Chao " -0x9215: "Niu " -0x9216: "Fen " -0x9217: "Yun " -0x9218: "Ji " -0x9219: "Qin " -0x921a: "Pi " -0x921b: "Guo " -0x921c: "Hong " -0x921d: "Yin " -0x921e: "Jun " -0x921f: "Shi " -0x9220: "Yi " -0x9221: "Zhong " -0x9222: "Nie " -0x9223: "Gai " -0x9224: "Ri " -0x9225: "Huo " -0x9226: "Tai " -0x9227: "Kang " -0x9228: "Habaki " -0x9229: "Irori " -0x922a: "Ngaak " -0x922b: "[?] " -0x922c: "Duo " -0x922d: "Zi " -0x922e: "Ni " -0x922f: "Tu " -0x9230: "Shi " -0x9231: "Min " -0x9232: "Gu " -0x9233: "E " -0x9234: "Ling " -0x9235: "Bing " -0x9236: "Yi " -0x9237: "Gu " -0x9238: "Ba " -0x9239: "Pi " -0x923a: "Yu " -0x923b: "Si " -0x923c: "Zuo " -0x923d: "Bu " -0x923e: "You " -0x923f: "Dian " -0x9240: "Jia " -0x9241: "Zhen " -0x9242: "Shi " -0x9243: "Shi " -0x9244: "Tie " -0x9245: "Ju " -0x9246: "Zhan " -0x9247: "Shi " -0x9248: "She " -0x9249: "Xuan " -0x924a: "Zhao " -0x924b: "Bao " -0x924c: "He " -0x924d: "Bi " -0x924e: "Sheng " -0x924f: "Chu " -0x9250: "Shi " -0x9251: "Bo " -0x9252: "Zhu " -0x9253: "Chi " -0x9254: "Za " -0x9255: "Po " -0x9256: "Tong " -0x9257: "Qian " -0x9258: "Fu " -0x9259: "Zhai " -0x925a: "Liu " -0x925b: "Qian " -0x925c: "Fu " -0x925d: "Li " -0x925e: "Yue " -0x925f: "Pi " -0x9260: "Yang " -0x9261: "Ban " -0x9262: "Bo " -0x9263: "Jie " -0x9264: "Gou " -0x9265: "Shu " -0x9266: "Zheng " -0x9267: "Mu " -0x9268: "Ni " -0x9269: "Nie " -0x926a: "Di " -0x926b: "Jia " -0x926c: "Mu " -0x926d: "Dan " -0x926e: "Shen " -0x926f: "Yi " -0x9270: "Si " -0x9271: "Kuang " -0x9272: "Ka " -0x9273: "Bei " -0x9274: "Jian " -0x9275: "Tong " -0x9276: "Xing " -0x9277: "Hong " -0x9278: "Jiao " -0x9279: "Chi " -0x927a: "Er " -0x927b: "Ge " -0x927c: "Bing " -0x927d: "Shi " -0x927e: "Mou " -0x927f: "Jia " -0x9280: "Yin " -0x9281: "Jun " -0x9282: "Zhou " -0x9283: "Chong " -0x9284: "Shang " -0x9285: "Tong " -0x9286: "Mo " -0x9287: "Lei " -0x9288: "Ji " -0x9289: "Yu " -0x928a: "Xu " -0x928b: "Ren " -0x928c: "Zun " -0x928d: "Zhi " -0x928e: "Qiong " -0x928f: "Shan " -0x9290: "Chi " -0x9291: "Xian " -0x9292: "Xing " -0x9293: "Quan " -0x9294: "Pi " -0x9295: "Tie " -0x9296: "Zhu " -0x9297: "Hou " -0x9298: "Ming " -0x9299: "Kua " -0x929a: "Yao " -0x929b: "Xian " -0x929c: "Xian " -0x929d: "Xiu " -0x929e: "Jun " -0x929f: "Cha " -0x92a0: "Lao " -0x92a1: "Ji " -0x92a2: "Pi " -0x92a3: "Ru " -0x92a4: "Mi " -0x92a5: "Yi " -0x92a6: "Yin " -0x92a7: "Guang " -0x92a8: "An " -0x92a9: "Diou " -0x92aa: "You " -0x92ab: "Se " -0x92ac: "Kao " -0x92ad: "Qian " -0x92ae: "Luan " -0x92af: "Kasugai " -0x92b0: "Ai " -0x92b1: "Diao " -0x92b2: "Han " -0x92b3: "Rui " -0x92b4: "Shi " -0x92b5: "Keng " -0x92b6: "Qiu " -0x92b7: "Xiao " -0x92b8: "Zhe " -0x92b9: "Xiu " -0x92ba: "Zang " -0x92bb: "Ti " -0x92bc: "Cuo " -0x92bd: "Gua " -0x92be: "Gong " -0x92bf: "Zhong " -0x92c0: "Dou " -0x92c1: "Lu " -0x92c2: "Mei " -0x92c3: "Lang " -0x92c4: "Wan " -0x92c5: "Xin " -0x92c6: "Yun " -0x92c7: "Bei " -0x92c8: "Wu " -0x92c9: "Su " -0x92ca: "Yu " -0x92cb: "Chan " -0x92cc: "Ting " -0x92cd: "Bo " -0x92ce: "Han " -0x92cf: "Jia " -0x92d0: "Hong " -0x92d1: "Cuan " -0x92d2: "Feng " -0x92d3: "Chan " -0x92d4: "Wan " -0x92d5: "Zhi " -0x92d6: "Si " -0x92d7: "Xuan " -0x92d8: "Wu " -0x92d9: "Wu " -0x92da: "Tiao " -0x92db: "Gong " -0x92dc: "Zhuo " -0x92dd: "Lue " -0x92de: "Xing " -0x92df: "Qian " -0x92e0: "Shen " -0x92e1: "Han " -0x92e2: "Lue " -0x92e3: "Xie " -0x92e4: "Chu " -0x92e5: "Zheng " -0x92e6: "Ju " -0x92e7: "Xian " -0x92e8: "Tie " -0x92e9: "Mang " -0x92ea: "Pu " -0x92eb: "Li " -0x92ec: "Pan " -0x92ed: "Rui " -0x92ee: "Cheng " -0x92ef: "Gao " -0x92f0: "Li " -0x92f1: "Te " -0x92f2: "Pyeng " -0x92f3: "Zhu " -0x92f4: "[?] " -0x92f5: "Tu " -0x92f6: "Liu " -0x92f7: "Zui " -0x92f8: "Ju " -0x92f9: "Chang " -0x92fa: "Yuan " -0x92fb: "Jian " -0x92fc: "Gang " -0x92fd: "Diao " -0x92fe: "Tao " -0x92ff: "Chang " -/* x093 */ -0x9300: "Lun " -0x9301: "Kua " -0x9302: "Ling " -0x9303: "Bei " -0x9304: "Lu " -0x9305: "Li " -0x9306: "Qiang " -0x9307: "Pou " -0x9308: "Juan " -0x9309: "Min " -0x930a: "Zui " -0x930b: "Peng " -0x930c: "An " -0x930d: "Pi " -0x930e: "Xian " -0x930f: "Ya " -0x9310: "Zhui " -0x9311: "Lei " -0x9312: "A " -0x9313: "Kong " -0x9314: "Ta " -0x9315: "Kun " -0x9316: "Du " -0x9317: "Wei " -0x9318: "Chui " -0x9319: "Zi " -0x931a: "Zheng " -0x931b: "Ben " -0x931c: "Nie " -0x931d: "Cong " -0x931e: "Qun " -0x931f: "Tan " -0x9320: "Ding " -0x9321: "Qi " -0x9322: "Qian " -0x9323: "Zhuo " -0x9324: "Qi " -0x9325: "Yu " -0x9326: "Jin " -0x9327: "Guan " -0x9328: "Mao " -0x9329: "Chang " -0x932a: "Tian " -0x932b: "Xi " -0x932c: "Lian " -0x932d: "Tao " -0x932e: "Gu " -0x932f: "Cuo " -0x9330: "Shu " -0x9331: "Zhen " -0x9332: "Lu " -0x9333: "Meng " -0x9334: "Lu " -0x9335: "Hua " -0x9336: "Biao " -0x9337: "Ga " -0x9338: "Lai " -0x9339: "Ken " -0x933a: "Kazari " -0x933b: "Bu " -0x933c: "Nai " -0x933d: "Wan " -0x933e: "Zan " -0x933f: "[?] " -0x9340: "De " -0x9341: "Xian " -0x9342: "[?] " -0x9343: "Huo " -0x9344: "Liang " -0x9345: "[?] " -0x9346: "Men " -0x9347: "Kai " -0x9348: "Ying " -0x9349: "Di " -0x934a: "Lian " -0x934b: "Guo " -0x934c: "Xian " -0x934d: "Du " -0x934e: "Tu " -0x934f: "Wei " -0x9350: "Cong " -0x9351: "Fu " -0x9352: "Rou " -0x9353: "Ji " -0x9354: "E " -0x9355: "Rou " -0x9356: "Chen " -0x9357: "Ti " -0x9358: "Zha " -0x9359: "Hong " -0x935a: "Yang " -0x935b: "Duan " -0x935c: "Xia " -0x935d: "Yu " -0x935e: "Keng " -0x935f: "Xing " -0x9360: "Huang " -0x9361: "Wei " -0x9362: "Fu " -0x9363: "Zhao " -0x9364: "Cha " -0x9365: "Qie " -0x9366: "She " -0x9367: "Hong " -0x9368: "Kui " -0x9369: "Tian " -0x936a: "Mou " -0x936b: "Qiao " -0x936c: "Qiao " -0x936d: "Hou " -0x936e: "Tou " -0x936f: "Cong " -0x9370: "Huan " -0x9371: "Ye " -0x9372: "Min " -0x9373: "Jian " -0x9374: "Duan " -0x9375: "Jian " -0x9376: "Song " -0x9377: "Kui " -0x9378: "Hu " -0x9379: "Xuan " -0x937a: "Duo " -0x937b: "Jie " -0x937c: "Zhen " -0x937d: "Bian " -0x937e: "Zhong " -0x937f: "Zi " -0x9380: "Xiu " -0x9381: "Ye " -0x9382: "Mei " -0x9383: "Pai " -0x9384: "Ai " -0x9385: "Jie " -0x9386: "[?] " -0x9387: "Mei " -0x9388: "Chuo " -0x9389: "Ta " -0x938a: "Bang " -0x938b: "Xia " -0x938c: "Lian " -0x938d: "Suo " -0x938e: "Xi " -0x938f: "Liu " -0x9390: "Zu " -0x9391: "Ye " -0x9392: "Nou " -0x9393: "Weng " -0x9394: "Rong " -0x9395: "Tang " -0x9396: "Suo " -0x9397: "Qiang " -0x9398: "Ge " -0x9399: "Shuo " -0x939a: "Chui " -0x939b: "Bo " -0x939c: "Pan " -0x939d: "Sa " -0x939e: "Bi " -0x939f: "Sang " -0x93a0: "Gang " -0x93a1: "Zi " -0x93a2: "Wu " -0x93a3: "Ying " -0x93a4: "Huang " -0x93a5: "Tiao " -0x93a6: "Liu " -0x93a7: "Kai " -0x93a8: "Sun " -0x93a9: "Sha " -0x93aa: "Sou " -0x93ab: "Wan " -0x93ac: "Hao " -0x93ad: "Zhen " -0x93ae: "Zhen " -0x93af: "Luo " -0x93b0: "Yi " -0x93b1: "Yuan " -0x93b2: "Tang " -0x93b3: "Nie " -0x93b4: "Xi " -0x93b5: "Jia " -0x93b6: "Ge " -0x93b7: "Ma " -0x93b8: "Juan " -0x93b9: "Kasugai " -0x93ba: "Habaki " -0x93bb: "Suo " -0x93bc: "[?] " -0x93bd: "[?] " -0x93be: "[?] " -0x93bf: "Na " -0x93c0: "Lu " -0x93c1: "Suo " -0x93c2: "Ou " -0x93c3: "Zu " -0x93c4: "Tuan " -0x93c5: "Xiu " -0x93c6: "Guan " -0x93c7: "Xuan " -0x93c8: "Lian " -0x93c9: "Shou " -0x93ca: "Ao " -0x93cb: "Man " -0x93cc: "Mo " -0x93cd: "Luo " -0x93ce: "Bi " -0x93cf: "Wei " -0x93d0: "Liu " -0x93d1: "Di " -0x93d2: "Qiao " -0x93d3: "Cong " -0x93d4: "Yi " -0x93d5: "Lu " -0x93d6: "Ao " -0x93d7: "Keng " -0x93d8: "Qiang " -0x93d9: "Cui " -0x93da: "Qi " -0x93db: "Chang " -0x93dc: "Tang " -0x93dd: "Man " -0x93de: "Yong " -0x93df: "Chan " -0x93e0: "Feng " -0x93e1: "Jing " -0x93e2: "Biao " -0x93e3: "Shu " -0x93e4: "Lou " -0x93e5: "Xiu " -0x93e6: "Cong " -0x93e7: "Long " -0x93e8: "Zan " -0x93e9: "Jian " -0x93ea: "Cao " -0x93eb: "Li " -0x93ec: "Xia " -0x93ed: "Xi " -0x93ee: "Kang " -0x93ef: "[?] " -0x93f0: "Beng " -0x93f1: "[?] " -0x93f2: "[?] " -0x93f3: "Zheng " -0x93f4: "Lu " -0x93f5: "Hua " -0x93f6: "Ji " -0x93f7: "Pu " -0x93f8: "Hui " -0x93f9: "Qiang " -0x93fa: "Po " -0x93fb: "Lin " -0x93fc: "Suo " -0x93fd: "Xiu " -0x93fe: "San " -0x93ff: "Cheng " -/* x094 */ -0x9400: "Kui " -0x9401: "Si " -0x9402: "Liu " -0x9403: "Nao " -0x9404: "Heng " -0x9405: "Pie " -0x9406: "Sui " -0x9407: "Fan " -0x9408: "Qiao " -0x9409: "Quan " -0x940a: "Yang " -0x940b: "Tang " -0x940c: "Xiang " -0x940d: "Jue " -0x940e: "Jiao " -0x940f: "Zun " -0x9410: "Liao " -0x9411: "Jie " -0x9412: "Lao " -0x9413: "Dui " -0x9414: "Tan " -0x9415: "Zan " -0x9416: "Ji " -0x9417: "Jian " -0x9418: "Zhong " -0x9419: "Deng " -0x941a: "Ya " -0x941b: "Ying " -0x941c: "Dui " -0x941d: "Jue " -0x941e: "Nou " -0x941f: "Ti " -0x9420: "Pu " -0x9421: "Tie " -0x9422: "[?] " -0x9423: "[?] " -0x9424: "Ding " -0x9425: "Shan " -0x9426: "Kai " -0x9427: "Jian " -0x9428: "Fei " -0x9429: "Sui " -0x942a: "Lu " -0x942b: "Juan " -0x942c: "Hui " -0x942d: "Yu " -0x942e: "Lian " -0x942f: "Zhuo " -0x9430: "Qiao " -0x9431: "Qian " -0x9432: "Zhuo " -0x9433: "Lei " -0x9434: "Bi " -0x9435: "Tie " -0x9436: "Huan " -0x9437: "Ye " -0x9438: "Duo " -0x9439: "Guo " -0x943a: "Dang " -0x943b: "Ju " -0x943c: "Fen " -0x943d: "Da " -0x943e: "Bei " -0x943f: "Yi " -0x9440: "Ai " -0x9441: "Zong " -0x9442: "Xun " -0x9443: "Diao " -0x9444: "Zhu " -0x9445: "Heng " -0x9446: "Zhui " -0x9447: "Ji " -0x9448: "Nie " -0x9449: "Ta " -0x944a: "Huo " -0x944b: "Qing " -0x944c: "Bin " -0x944d: "Ying " -0x944e: "Kui " -0x944f: "Ning " -0x9450: "Xu " -0x9451: "Jian " -0x9452: "Jian " -0x9453: "Yari " -0x9454: "Cha " -0x9455: "Zhi " -0x9456: "Mie " -0x9457: "Li " -0x9458: "Lei " -0x9459: "Ji " -0x945a: "Zuan " -0x945b: "Kuang " -0x945c: "Shang " -0x945d: "Peng " -0x945e: "La " -0x945f: "Du " -0x9460: "Shuo " -0x9461: "Chuo " -0x9462: "Lu " -0x9463: "Biao " -0x9464: "Bao " -0x9465: "Lu " -0x9466: "[?] " -0x9467: "[?] " -0x9468: "Long " -0x9469: "E " -0x946a: "Lu " -0x946b: "Xin " -0x946c: "Jian " -0x946d: "Lan " -0x946e: "Bo " -0x946f: "Jian " -0x9470: "Yao " -0x9471: "Chan " -0x9472: "Xiang " -0x9473: "Jian " -0x9474: "Xi " -0x9475: "Guan " -0x9476: "Cang " -0x9477: "Nie " -0x9478: "Lei " -0x9479: "Cuan " -0x947a: "Qu " -0x947b: "Pan " -0x947c: "Luo " -0x947d: "Zuan " -0x947e: "Luan " -0x947f: "Zao " -0x9480: "Nie " -0x9481: "Jue " -0x9482: "Tang " -0x9483: "Shu " -0x9484: "Lan " -0x9485: "Jin " -0x9486: "Qiu " -0x9487: "Yi " -0x9488: "Zhen " -0x9489: "Ding " -0x948a: "Zhao " -0x948b: "Po " -0x948c: "Diao " -0x948d: "Tu " -0x948e: "Qian " -0x948f: "Chuan " -0x9490: "Shan " -0x9491: "Ji " -0x9492: "Fan " -0x9493: "Diao " -0x9494: "Men " -0x9495: "Nu " -0x9496: "Xi " -0x9497: "Chai " -0x9498: "Xing " -0x9499: "Gai " -0x949a: "Bu " -0x949b: "Tai " -0x949c: "Ju " -0x949d: "Dun " -0x949e: "Chao " -0x949f: "Zhong " -0x94a0: "Na " -0x94a1: "Bei " -0x94a2: "Gang " -0x94a3: "Ban " -0x94a4: "Qian " -0x94a5: "Yao " -0x94a6: "Qin " -0x94a7: "Jun " -0x94a8: "Wu " -0x94a9: "Gou " -0x94aa: "Kang " -0x94ab: "Fang " -0x94ac: "Huo " -0x94ad: "Tou " -0x94ae: "Niu " -0x94af: "Ba " -0x94b0: "Yu " -0x94b1: "Qian " -0x94b2: "Zheng " -0x94b3: "Qian " -0x94b4: "Gu " -0x94b5: "Bo " -0x94b6: "E " -0x94b7: "Po " -0x94b8: "Bu " -0x94b9: "Ba " -0x94ba: "Yue " -0x94bb: "Zuan " -0x94bc: "Mu " -0x94bd: "Dan " -0x94be: "Jia " -0x94bf: "Dian " -0x94c0: "You " -0x94c1: "Tie " -0x94c2: "Bo " -0x94c3: "Ling " -0x94c4: "Shuo " -0x94c5: "Qian " -0x94c6: "Liu " -0x94c7: "Bao " -0x94c8: "Shi " -0x94c9: "Xuan " -0x94ca: "She " -0x94cb: "Bi " -0x94cc: "Ni " -0x94cd: "Pi " -0x94ce: "Duo " -0x94cf: "Xing " -0x94d0: "Kao " -0x94d1: "Lao " -0x94d2: "Er " -0x94d3: "Mang " -0x94d4: "Ya " -0x94d5: "You " -0x94d6: "Cheng " -0x94d7: "Jia " -0x94d8: "Ye " -0x94d9: "Nao " -0x94da: "Zhi " -0x94db: "Dang " -0x94dc: "Tong " -0x94dd: "Lu " -0x94de: "Diao " -0x94df: "Yin " -0x94e0: "Kai " -0x94e1: "Zha " -0x94e2: "Zhu " -0x94e3: "Xian " -0x94e4: "Ting " -0x94e5: "Diu " -0x94e6: "Xian " -0x94e7: "Hua " -0x94e8: "Quan " -0x94e9: "Sha " -0x94ea: "Jia " -0x94eb: "Yao " -0x94ec: "Ge " -0x94ed: "Ming " -0x94ee: "Zheng " -0x94ef: "Se " -0x94f0: "Jiao " -0x94f1: "Yi " -0x94f2: "Chan " -0x94f3: "Chong " -0x94f4: "Tang " -0x94f5: "An " -0x94f6: "Yin " -0x94f7: "Ru " -0x94f8: "Zhu " -0x94f9: "Lao " -0x94fa: "Pu " -0x94fb: "Wu " -0x94fc: "Lai " -0x94fd: "Te " -0x94fe: "Lian " -0x94ff: "Keng " -/* x095 */ -0x9500: "Xiao " -0x9501: "Suo " -0x9502: "Li " -0x9503: "Zheng " -0x9504: "Chu " -0x9505: "Guo " -0x9506: "Gao " -0x9507: "Tie " -0x9508: "Xiu " -0x9509: "Cuo " -0x950a: "Lue " -0x950b: "Feng " -0x950c: "Xin " -0x950d: "Liu " -0x950e: "Kai " -0x950f: "Jian " -0x9510: "Rui " -0x9511: "Ti " -0x9512: "Lang " -0x9513: "Qian " -0x9514: "Ju " -0x9515: "A " -0x9516: "Qiang " -0x9517: "Duo " -0x9518: "Tian " -0x9519: "Cuo " -0x951a: "Mao " -0x951b: "Ben " -0x951c: "Qi " -0x951d: "De " -0x951e: "Kua " -0x951f: "Kun " -0x9520: "Chang " -0x9521: "Xi " -0x9522: "Gu " -0x9523: "Luo " -0x9524: "Chui " -0x9525: "Zhui " -0x9526: "Jin " -0x9527: "Zhi " -0x9528: "Xian " -0x9529: "Juan " -0x952a: "Huo " -0x952b: "Pou " -0x952c: "Tan " -0x952d: "Ding " -0x952e: "Jian " -0x952f: "Ju " -0x9530: "Meng " -0x9531: "Zi " -0x9532: "Qie " -0x9533: "Ying " -0x9534: "Kai " -0x9535: "Qiang " -0x9536: "Song " -0x9537: "E " -0x9538: "Cha " -0x9539: "Qiao " -0x953a: "Zhong " -0x953b: "Duan " -0x953c: "Sou " -0x953d: "Huang " -0x953e: "Huan " -0x953f: "Ai " -0x9540: "Du " -0x9541: "Mei " -0x9542: "Lou " -0x9543: "Zi " -0x9544: "Fei " -0x9545: "Mei " -0x9546: "Mo " -0x9547: "Zhen " -0x9548: "Bo " -0x9549: "Ge " -0x954a: "Nie " -0x954b: "Tang " -0x954c: "Juan " -0x954d: "Nie " -0x954e: "Na " -0x954f: "Liu " -0x9550: "Hao " -0x9551: "Bang " -0x9552: "Yi " -0x9553: "Jia " -0x9554: "Bin " -0x9555: "Rong " -0x9556: "Biao " -0x9557: "Tang " -0x9558: "Man " -0x9559: "Luo " -0x955a: "Beng " -0x955b: "Yong " -0x955c: "Jing " -0x955d: "Di " -0x955e: "Zu " -0x955f: "Xuan " -0x9560: "Liu " -0x9561: "Tan " -0x9562: "Jue " -0x9563: "Liao " -0x9564: "Pu " -0x9565: "Lu " -0x9566: "Dui " -0x9567: "Lan " -0x9568: "Pu " -0x9569: "Cuan " -0x956a: "Qiang " -0x956b: "Deng " -0x956c: "Huo " -0x956d: "Lei " -0x956e: "Huan " -0x956f: "Zhuo " -0x9570: "Lian " -0x9571: "Yi " -0x9572: "Cha " -0x9573: "Biao " -0x9574: "La " -0x9575: "Chan " -0x9576: "Xiang " -0x9577: "Chang " -0x9578: "Chang " -0x9579: "Jiu " -0x957a: "Ao " -0x957b: "Die " -0x957c: "Qu " -0x957d: "Liao " -0x957e: "Mi " -0x957f: "Chang " -0x9580: "Men " -0x9581: "Ma " -0x9582: "Shuan " -0x9583: "Shan " -0x9584: "Huo " -0x9585: "Men " -0x9586: "Yan " -0x9587: "Bi " -0x9588: "Han " -0x9589: "Bi " -0x958a: "San " -0x958b: "Kai " -0x958c: "Kang " -0x958d: "Beng " -0x958e: "Hong " -0x958f: "Run " -0x9590: "San " -0x9591: "Xian " -0x9592: "Xian " -0x9593: "Jian " -0x9594: "Min " -0x9595: "Xia " -0x9596: "Yuru " -0x9597: "Dou " -0x9598: "Zha " -0x9599: "Nao " -0x959a: "Jian " -0x959b: "Peng " -0x959c: "Xia " -0x959d: "Ling " -0x959e: "Bian " -0x959f: "Bi " -0x95a0: "Run " -0x95a1: "He " -0x95a2: "Guan " -0x95a3: "Ge " -0x95a4: "Ge " -0x95a5: "Fa " -0x95a6: "Chu " -0x95a7: "Hong " -0x95a8: "Gui " -0x95a9: "Min " -0x95aa: "Se " -0x95ab: "Kun " -0x95ac: "Lang " -0x95ad: "Lu " -0x95ae: "Ting " -0x95af: "Sha " -0x95b0: "Ju " -0x95b1: "Yue " -0x95b2: "Yue " -0x95b3: "Chan " -0x95b4: "Qu " -0x95b5: "Lin " -0x95b6: "Chang " -0x95b7: "Shai " -0x95b8: "Kun " -0x95b9: "Yan " -0x95ba: "Min " -0x95bb: "Yan " -0x95bc: "E " -0x95bd: "Hun " -0x95be: "Yu " -0x95bf: "Wen " -0x95c0: "Xiang " -0x95c1: "Bao " -0x95c2: "Xiang " -0x95c3: "Qu " -0x95c4: "Yao " -0x95c5: "Wen " -0x95c6: "Ban " -0x95c7: "An " -0x95c8: "Wei " -0x95c9: "Yin " -0x95ca: "Kuo " -0x95cb: "Que " -0x95cc: "Lan " -0x95cd: "Du " -0x95ce: "[?] " -0x95cf: "Phwung " -0x95d0: "Tian " -0x95d1: "Nie " -0x95d2: "Ta " -0x95d3: "Kai " -0x95d4: "He " -0x95d5: "Que " -0x95d6: "Chuang " -0x95d7: "Guan " -0x95d8: "Dou " -0x95d9: "Qi " -0x95da: "Kui " -0x95db: "Tang " -0x95dc: "Guan " -0x95dd: "Piao " -0x95de: "Kan " -0x95df: "Xi " -0x95e0: "Hui " -0x95e1: "Chan " -0x95e2: "Pi " -0x95e3: "Dang " -0x95e4: "Huan " -0x95e5: "Ta " -0x95e6: "Wen " -0x95e7: "[?] " -0x95e8: "Men " -0x95e9: "Shuan " -0x95ea: "Shan " -0x95eb: "Yan " -0x95ec: "Han " -0x95ed: "Bi " -0x95ee: "Wen " -0x95ef: "Chuang " -0x95f0: "Run " -0x95f1: "Wei " -0x95f2: "Xian " -0x95f3: "Hong " -0x95f4: "Jian " -0x95f5: "Min " -0x95f6: "Kang " -0x95f7: "Men " -0x95f8: "Zha " -0x95f9: "Nao " -0x95fa: "Gui " -0x95fb: "Wen " -0x95fc: "Ta " -0x95fd: "Min " -0x95fe: "Lu " -0x95ff: "Kai " -/* x096 */ -0x9600: "Fa " -0x9601: "Ge " -0x9602: "He " -0x9603: "Kun " -0x9604: "Jiu " -0x9605: "Yue " -0x9606: "Lang " -0x9607: "Du " -0x9608: "Yu " -0x9609: "Yan " -0x960a: "Chang " -0x960b: "Xi " -0x960c: "Wen " -0x960d: "Hun " -0x960e: "Yan " -0x960f: "E " -0x9610: "Chan " -0x9611: "Lan " -0x9612: "Qu " -0x9613: "Hui " -0x9614: "Kuo " -0x9615: "Que " -0x9616: "Ge " -0x9617: "Tian " -0x9618: "Ta " -0x9619: "Que " -0x961a: "Kan " -0x961b: "Huan " -0x961c: "Fu " -0x961d: "Fu " -0x961e: "Le " -0x961f: "Dui " -0x9620: "Xin " -0x9621: "Qian " -0x9622: "Wu " -0x9623: "Yi " -0x9624: "Tuo " -0x9625: "Yin " -0x9626: "Yang " -0x9627: "Dou " -0x9628: "E " -0x9629: "Sheng " -0x962a: "Ban " -0x962b: "Pei " -0x962c: "Keng " -0x962d: "Yun " -0x962e: "Ruan " -0x962f: "Zhi " -0x9630: "Pi " -0x9631: "Jing " -0x9632: "Fang " -0x9633: "Yang " -0x9634: "Yin " -0x9635: "Zhen " -0x9636: "Jie " -0x9637: "Cheng " -0x9638: "E " -0x9639: "Qu " -0x963a: "Di " -0x963b: "Zu " -0x963c: "Zuo " -0x963d: "Dian " -0x963e: "Ling " -0x963f: "A " -0x9640: "Tuo " -0x9641: "Tuo " -0x9642: "Po " -0x9643: "Bing " -0x9644: "Fu " -0x9645: "Ji " -0x9646: "Lu " -0x9647: "Long " -0x9648: "Chen " -0x9649: "Xing " -0x964a: "Duo " -0x964b: "Lou " -0x964c: "Mo " -0x964d: "Jiang " -0x964e: "Shu " -0x964f: "Duo " -0x9650: "Xian " -0x9651: "Er " -0x9652: "Gui " -0x9653: "Yu " -0x9654: "Gai " -0x9655: "Shan " -0x9656: "Xun " -0x9657: "Qiao " -0x9658: "Xing " -0x9659: "Chun " -0x965a: "Fu " -0x965b: "Bi " -0x965c: "Xia " -0x965d: "Shan " -0x965e: "Sheng " -0x965f: "Zhi " -0x9660: "Pu " -0x9661: "Dou " -0x9662: "Yuan " -0x9663: "Zhen " -0x9664: "Chu " -0x9665: "Xian " -0x9666: "Tou " -0x9667: "Nie " -0x9668: "Yun " -0x9669: "Xian " -0x966a: "Pei " -0x966b: "Pei " -0x966c: "Zou " -0x966d: "Yi " -0x966e: "Dui " -0x966f: "Lun " -0x9670: "Yin " -0x9671: "Ju " -0x9672: "Chui " -0x9673: "Chen " -0x9674: "Pi " -0x9675: "Ling " -0x9676: "Tao " -0x9677: "Xian " -0x9678: "Lu " -0x9679: "Sheng " -0x967a: "Xian " -0x967b: "Yin " -0x967c: "Zhu " -0x967d: "Yang " -0x967e: "Reng " -0x967f: "Shan " -0x9680: "Chong " -0x9681: "Yan " -0x9682: "Yin " -0x9683: "Yu " -0x9684: "Ti " -0x9685: "Yu " -0x9686: "Long " -0x9687: "Wei " -0x9688: "Wei " -0x9689: "Nie " -0x968a: "Dui " -0x968b: "Sui " -0x968c: "An " -0x968d: "Huang " -0x968e: "Jie " -0x968f: "Sui " -0x9690: "Yin " -0x9691: "Gai " -0x9692: "Yan " -0x9693: "Hui " -0x9694: "Ge " -0x9695: "Yun " -0x9696: "Wu " -0x9697: "Wei " -0x9698: "Ai " -0x9699: "Xi " -0x969a: "Tang " -0x969b: "Ji " -0x969c: "Zhang " -0x969d: "Dao " -0x969e: "Ao " -0x969f: "Xi " -0x96a0: "Yin " -0x96a1: "[?] " -0x96a2: "Rao " -0x96a3: "Lin " -0x96a4: "Tui " -0x96a5: "Deng " -0x96a6: "Pi " -0x96a7: "Sui " -0x96a8: "Sui " -0x96a9: "Yu " -0x96aa: "Xian " -0x96ab: "Fen " -0x96ac: "Ni " -0x96ad: "Er " -0x96ae: "Ji " -0x96af: "Dao " -0x96b0: "Xi " -0x96b1: "Yin " -0x96b2: "E " -0x96b3: "Hui " -0x96b4: "Long " -0x96b5: "Xi " -0x96b6: "Li " -0x96b7: "Li " -0x96b8: "Li " -0x96b9: "Zhui " -0x96ba: "He " -0x96bb: "Zhi " -0x96bc: "Zhun " -0x96bd: "Jun " -0x96be: "Nan " -0x96bf: "Yi " -0x96c0: "Que " -0x96c1: "Yan " -0x96c2: "Qian " -0x96c3: "Ya " -0x96c4: "Xiong " -0x96c5: "Ya " -0x96c6: "Ji " -0x96c7: "Gu " -0x96c8: "Huan " -0x96c9: "Zhi " -0x96ca: "Gou " -0x96cb: "Jun " -0x96cc: "Ci " -0x96cd: "Yong " -0x96ce: "Ju " -0x96cf: "Chu " -0x96d0: "Hu " -0x96d1: "Za " -0x96d2: "Luo " -0x96d3: "Yu " -0x96d4: "Chou " -0x96d5: "Diao " -0x96d6: "Sui " -0x96d7: "Han " -0x96d8: "Huo " -0x96d9: "Shuang " -0x96da: "Guan " -0x96db: "Chu " -0x96dc: "Za " -0x96dd: "Yong " -0x96de: "Ji " -0x96df: "Xi " -0x96e0: "Chou " -0x96e1: "Liu " -0x96e2: "Li " -0x96e3: "Nan " -0x96e4: "Xue " -0x96e5: "Za " -0x96e6: "Ji " -0x96e7: "Ji " -0x96e8: "Yu " -0x96e9: "Yu " -0x96ea: "Xue " -0x96eb: "Na " -0x96ec: "Fou " -0x96ed: "Se " -0x96ee: "Mu " -0x96ef: "Wen " -0x96f0: "Fen " -0x96f1: "Pang " -0x96f2: "Yun " -0x96f3: "Li " -0x96f4: "Li " -0x96f5: "Ang " -0x96f6: "Ling " -0x96f7: "Lei " -0x96f8: "An " -0x96f9: "Bao " -0x96fa: "Meng " -0x96fb: "Dian " -0x96fc: "Dang " -0x96fd: "Xing " -0x96fe: "Wu " -0x96ff: "Zhao " -/* x097 */ -0x9700: "Xu " -0x9701: "Ji " -0x9702: "Mu " -0x9703: "Chen " -0x9704: "Xiao " -0x9705: "Zha " -0x9706: "Ting " -0x9707: "Zhen " -0x9708: "Pei " -0x9709: "Mei " -0x970a: "Ling " -0x970b: "Qi " -0x970c: "Chou " -0x970d: "Huo " -0x970e: "Sha " -0x970f: "Fei " -0x9710: "Weng " -0x9711: "Zhan " -0x9712: "Yin " -0x9713: "Ni " -0x9714: "Chou " -0x9715: "Tun " -0x9716: "Lin " -0x9717: "[?] " -0x9718: "Dong " -0x9719: "Ying " -0x971a: "Wu " -0x971b: "Ling " -0x971c: "Shuang " -0x971d: "Ling " -0x971e: "Xia " -0x971f: "Hong " -0x9720: "Yin " -0x9721: "Mo " -0x9722: "Mai " -0x9723: "Yun " -0x9724: "Liu " -0x9725: "Meng " -0x9726: "Bin " -0x9727: "Wu " -0x9728: "Wei " -0x9729: "Huo " -0x972a: "Yin " -0x972b: "Xi " -0x972c: "Yi " -0x972d: "Ai " -0x972e: "Dan " -0x972f: "Deng " -0x9730: "Xian " -0x9731: "Yu " -0x9732: "Lu " -0x9733: "Long " -0x9734: "Dai " -0x9735: "Ji " -0x9736: "Pang " -0x9737: "Yang " -0x9738: "Ba " -0x9739: "Pi " -0x973a: "Wei " -0x973b: "[?] " -0x973c: "Xi " -0x973d: "Ji " -0x973e: "Mai " -0x973f: "Meng " -0x9740: "Meng " -0x9741: "Lei " -0x9742: "Li " -0x9743: "Huo " -0x9744: "Ai " -0x9745: "Fei " -0x9746: "Dai " -0x9747: "Long " -0x9748: "Ling " -0x9749: "Ai " -0x974a: "Feng " -0x974b: "Li " -0x974c: "Bao " -0x974d: "[?] " -0x974e: "He " -0x974f: "He " -0x9750: "Bing " -0x9751: "Qing " -0x9752: "Qing " -0x9753: "Jing " -0x9754: "Tian " -0x9755: "Zhen " -0x9756: "Jing " -0x9757: "Cheng " -0x9758: "Qing " -0x9759: "Jing " -0x975a: "Jing " -0x975b: "Dian " -0x975c: "Jing " -0x975d: "Tian " -0x975e: "Fei " -0x975f: "Fei " -0x9760: "Kao " -0x9761: "Mi " -0x9762: "Mian " -0x9763: "Mian " -0x9764: "Pao " -0x9765: "Ye " -0x9766: "Tian " -0x9767: "Hui " -0x9768: "Ye " -0x9769: "Ge " -0x976a: "Ding " -0x976b: "Cha " -0x976c: "Jian " -0x976d: "Ren " -0x976e: "Di " -0x976f: "Du " -0x9770: "Wu " -0x9771: "Ren " -0x9772: "Qin " -0x9773: "Jin " -0x9774: "Xue " -0x9775: "Niu " -0x9776: "Ba " -0x9777: "Yin " -0x9778: "Sa " -0x9779: "Na " -0x977a: "Mo " -0x977b: "Zu " -0x977c: "Da " -0x977d: "Ban " -0x977e: "Yi " -0x977f: "Yao " -0x9780: "Tao " -0x9781: "Tuo " -0x9782: "Jia " -0x9783: "Hong " -0x9784: "Pao " -0x9785: "Yang " -0x9786: "Tomo " -0x9787: "Yin " -0x9788: "Jia " -0x9789: "Tao " -0x978a: "Ji " -0x978b: "Xie " -0x978c: "An " -0x978d: "An " -0x978e: "Hen " -0x978f: "Gong " -0x9790: "Kohaze " -0x9791: "Da " -0x9792: "Qiao " -0x9793: "Ting " -0x9794: "Wan " -0x9795: "Ying " -0x9796: "Sui " -0x9797: "Tiao " -0x9798: "Qiao " -0x9799: "Xuan " -0x979a: "Kong " -0x979b: "Beng " -0x979c: "Ta " -0x979d: "Zhang " -0x979e: "Bing " -0x979f: "Kuo " -0x97a0: "Ju " -0x97a1: "La " -0x97a2: "Xie " -0x97a3: "Rou " -0x97a4: "Bang " -0x97a5: "Yi " -0x97a6: "Qiu " -0x97a7: "Qiu " -0x97a8: "He " -0x97a9: "Xiao " -0x97aa: "Mu " -0x97ab: "Ju " -0x97ac: "Jian " -0x97ad: "Bian " -0x97ae: "Di " -0x97af: "Jian " -0x97b0: "On " -0x97b1: "Tao " -0x97b2: "Gou " -0x97b3: "Ta " -0x97b4: "Bei " -0x97b5: "Xie " -0x97b6: "Pan " -0x97b7: "Ge " -0x97b8: "Bi " -0x97b9: "Kuo " -0x97ba: "Tang " -0x97bb: "Lou " -0x97bc: "Gui " -0x97bd: "Qiao " -0x97be: "Xue " -0x97bf: "Ji " -0x97c0: "Jian " -0x97c1: "Jiang " -0x97c2: "Chan " -0x97c3: "Da " -0x97c4: "Huo " -0x97c5: "Xian " -0x97c6: "Qian " -0x97c7: "Du " -0x97c8: "Wa " -0x97c9: "Jian " -0x97ca: "Lan " -0x97cb: "Wei " -0x97cc: "Ren " -0x97cd: "Fu " -0x97ce: "Mei " -0x97cf: "Juan " -0x97d0: "Ge " -0x97d1: "Wei " -0x97d2: "Qiao " -0x97d3: "Han " -0x97d4: "Chang " -0x97d5: "[?] " -0x97d6: "Rou " -0x97d7: "Xun " -0x97d8: "She " -0x97d9: "Wei " -0x97da: "Ge " -0x97db: "Bei " -0x97dc: "Tao " -0x97dd: "Gou " -0x97de: "Yun " -0x97df: "[?] " -0x97e0: "Bi " -0x97e1: "Wei " -0x97e2: "Hui " -0x97e3: "Du " -0x97e4: "Wa " -0x97e5: "Du " -0x97e6: "Wei " -0x97e7: "Ren " -0x97e8: "Fu " -0x97e9: "Han " -0x97ea: "Wei " -0x97eb: "Yun " -0x97ec: "Tao " -0x97ed: "Jiu " -0x97ee: "Jiu " -0x97ef: "Xian " -0x97f0: "Xie " -0x97f1: "Xian " -0x97f2: "Ji " -0x97f3: "Yin " -0x97f4: "Za " -0x97f5: "Yun " -0x97f6: "Shao " -0x97f7: "Le " -0x97f8: "Peng " -0x97f9: "Heng " -0x97fa: "Ying " -0x97fb: "Yun " -0x97fc: "Peng " -0x97fd: "Yin " -0x97fe: "Yin " -0x97ff: "Xiang " -/* x098 */ -0x9800: "Hu " -0x9801: "Ye " -0x9802: "Ding " -0x9803: "Qing " -0x9804: "Pan " -0x9805: "Xiang " -0x9806: "Shun " -0x9807: "Han " -0x9808: "Xu " -0x9809: "Yi " -0x980a: "Xu " -0x980b: "Gu " -0x980c: "Song " -0x980d: "Kui " -0x980e: "Qi " -0x980f: "Hang " -0x9810: "Yu " -0x9811: "Wan " -0x9812: "Ban " -0x9813: "Dun " -0x9814: "Di " -0x9815: "Dan " -0x9816: "Pan " -0x9817: "Po " -0x9818: "Ling " -0x9819: "Ce " -0x981a: "Jing " -0x981b: "Lei " -0x981c: "He " -0x981d: "Qiao " -0x981e: "E " -0x981f: "E " -0x9820: "Wei " -0x9821: "Jie " -0x9822: "Gua " -0x9823: "Shen " -0x9824: "Yi " -0x9825: "Shen " -0x9826: "Hai " -0x9827: "Dui " -0x9828: "Pian " -0x9829: "Ping " -0x982a: "Lei " -0x982b: "Fu " -0x982c: "Jia " -0x982d: "Tou " -0x982e: "Hui " -0x982f: "Kui " -0x9830: "Jia " -0x9831: "Le " -0x9832: "Tian " -0x9833: "Cheng " -0x9834: "Ying " -0x9835: "Jun " -0x9836: "Hu " -0x9837: "Han " -0x9838: "Jing " -0x9839: "Tui " -0x983a: "Tui " -0x983b: "Pin " -0x983c: "Lai " -0x983d: "Tui " -0x983e: "Zi " -0x983f: "Zi " -0x9840: "Chui " -0x9841: "Ding " -0x9842: "Lai " -0x9843: "Yan " -0x9844: "Han " -0x9845: "Jian " -0x9846: "Ke " -0x9847: "Cui " -0x9848: "Jiong " -0x9849: "Qin " -0x984a: "Yi " -0x984b: "Sai " -0x984c: "Ti " -0x984d: "E " -0x984e: "E " -0x984f: "Yan " -0x9850: "Hun " -0x9851: "Kan " -0x9852: "Yong " -0x9853: "Zhuan " -0x9854: "Yan " -0x9855: "Xian " -0x9856: "Xin " -0x9857: "Yi " -0x9858: "Yuan " -0x9859: "Sang " -0x985a: "Dian " -0x985b: "Dian " -0x985c: "Jiang " -0x985d: "Ku " -0x985e: "Lei " -0x985f: "Liao " -0x9860: "Piao " -0x9861: "Yi " -0x9862: "Man " -0x9863: "Qi " -0x9864: "Rao " -0x9865: "Hao " -0x9866: "Qiao " -0x9867: "Gu " -0x9868: "Xun " -0x9869: "Qian " -0x986a: "Hui " -0x986b: "Zhan " -0x986c: "Ru " -0x986d: "Hong " -0x986e: "Bin " -0x986f: "Xian " -0x9870: "Pin " -0x9871: "Lu " -0x9872: "Lan " -0x9873: "Nie " -0x9874: "Quan " -0x9875: "Ye " -0x9876: "Ding " -0x9877: "Qing " -0x9878: "Han " -0x9879: "Xiang " -0x987a: "Shun " -0x987b: "Xu " -0x987c: "Xu " -0x987d: "Wan " -0x987e: "Gu " -0x987f: "Dun " -0x9880: "Qi " -0x9881: "Ban " -0x9882: "Song " -0x9883: "Hang " -0x9884: "Yu " -0x9885: "Lu " -0x9886: "Ling " -0x9887: "Po " -0x9888: "Jing " -0x9889: "Jie " -0x988a: "Jia " -0x988b: "Tian " -0x988c: "Han " -0x988d: "Ying " -0x988e: "Jiong " -0x988f: "Hai " -0x9890: "Yi " -0x9891: "Pin " -0x9892: "Hui " -0x9893: "Tui " -0x9894: "Han " -0x9895: "Ying " -0x9896: "Ying " -0x9897: "Ke " -0x9898: "Ti " -0x9899: "Yong " -0x989a: "E " -0x989b: "Zhuan " -0x989c: "Yan " -0x989d: "E " -0x989e: "Nie " -0x989f: "Man " -0x98a0: "Dian " -0x98a1: "Sang " -0x98a2: "Hao " -0x98a3: "Lei " -0x98a4: "Zhan " -0x98a5: "Ru " -0x98a6: "Pin " -0x98a7: "Quan " -0x98a8: "Feng " -0x98a9: "Biao " -0x98aa: "Oroshi " -0x98ab: "Fu " -0x98ac: "Xia " -0x98ad: "Zhan " -0x98ae: "Biao " -0x98af: "Sa " -0x98b0: "Ba " -0x98b1: "Tai " -0x98b2: "Lie " -0x98b3: "Gua " -0x98b4: "Xuan " -0x98b5: "Shao " -0x98b6: "Ju " -0x98b7: "Bi " -0x98b8: "Si " -0x98b9: "Wei " -0x98ba: "Yang " -0x98bb: "Yao " -0x98bc: "Sou " -0x98bd: "Kai " -0x98be: "Sao " -0x98bf: "Fan " -0x98c0: "Liu " -0x98c1: "Xi " -0x98c2: "Liao " -0x98c3: "Piao " -0x98c4: "Piao " -0x98c5: "Liu " -0x98c6: "Biao " -0x98c7: "Biao " -0x98c8: "Biao " -0x98c9: "Liao " -0x98ca: "[?] " -0x98cb: "Se " -0x98cc: "Feng " -0x98cd: "Biao " -0x98ce: "Feng " -0x98cf: "Yang " -0x98d0: "Zhan " -0x98d1: "Biao " -0x98d2: "Sa " -0x98d3: "Ju " -0x98d4: "Si " -0x98d5: "Sou " -0x98d6: "Yao " -0x98d7: "Liu " -0x98d8: "Piao " -0x98d9: "Biao " -0x98da: "Biao " -0x98db: "Fei " -0x98dc: "Fan " -0x98dd: "Fei " -0x98de: "Fei " -0x98df: "Shi " -0x98e0: "Shi " -0x98e1: "Can " -0x98e2: "Ji " -0x98e3: "Ding " -0x98e4: "Si " -0x98e5: "Tuo " -0x98e6: "Zhan " -0x98e7: "Sun " -0x98e8: "Xiang " -0x98e9: "Tun " -0x98ea: "Ren " -0x98eb: "Yu " -0x98ec: "Juan " -0x98ed: "Chi " -0x98ee: "Yin " -0x98ef: "Fan " -0x98f0: "Fan " -0x98f1: "Sun " -0x98f2: "Yin " -0x98f3: "Zhu " -0x98f4: "Yi " -0x98f5: "Zhai " -0x98f6: "Bi " -0x98f7: "Jie " -0x98f8: "Tao " -0x98f9: "Liu " -0x98fa: "Ci " -0x98fb: "Tie " -0x98fc: "Si " -0x98fd: "Bao " -0x98fe: "Shi " -0x98ff: "Duo " -/* x099 */ -0x9900: "Hai " -0x9901: "Ren " -0x9902: "Tian " -0x9903: "Jiao " -0x9904: "Jia " -0x9905: "Bing " -0x9906: "Yao " -0x9907: "Tong " -0x9908: "Ci " -0x9909: "Xiang " -0x990a: "Yang " -0x990b: "Yang " -0x990c: "Er " -0x990d: "Yan " -0x990e: "Le " -0x990f: "Yi " -0x9910: "Can " -0x9911: "Bo " -0x9912: "Nei " -0x9913: "E " -0x9914: "Bu " -0x9915: "Jun " -0x9916: "Dou " -0x9917: "Su " -0x9918: "Yu " -0x9919: "Shi " -0x991a: "Yao " -0x991b: "Hun " -0x991c: "Guo " -0x991d: "Shi " -0x991e: "Jian " -0x991f: "Zhui " -0x9920: "Bing " -0x9921: "Xian " -0x9922: "Bu " -0x9923: "Ye " -0x9924: "Tan " -0x9925: "Fei " -0x9926: "Zhang " -0x9927: "Wei " -0x9928: "Guan " -0x9929: "E " -0x992a: "Nuan " -0x992b: "Hun " -0x992c: "Hu " -0x992d: "Huang " -0x992e: "Tie " -0x992f: "Hui " -0x9930: "Jian " -0x9931: "Hou " -0x9932: "He " -0x9933: "Xing " -0x9934: "Fen " -0x9935: "Wei " -0x9936: "Gu " -0x9937: "Cha " -0x9938: "Song " -0x9939: "Tang " -0x993a: "Bo " -0x993b: "Gao " -0x993c: "Xi " -0x993d: "Kui " -0x993e: "Liu " -0x993f: "Sou " -0x9940: "Tao " -0x9941: "Ye " -0x9942: "Yun " -0x9943: "Mo " -0x9944: "Tang " -0x9945: "Man " -0x9946: "Bi " -0x9947: "Yu " -0x9948: "Xiu " -0x9949: "Jin " -0x994a: "San " -0x994b: "Kui " -0x994c: "Zhuan " -0x994d: "Shan " -0x994e: "Chi " -0x994f: "Dan " -0x9950: "Yi " -0x9951: "Ji " -0x9952: "Rao " -0x9953: "Cheng " -0x9954: "Yong " -0x9955: "Tao " -0x9956: "Hui " -0x9957: "Xiang " -0x9958: "Zhan " -0x9959: "Fen " -0x995a: "Hai " -0x995b: "Meng " -0x995c: "Yan " -0x995d: "Mo " -0x995e: "Chan " -0x995f: "Xiang " -0x9960: "Luo " -0x9961: "Zuan " -0x9962: "Nang " -0x9963: "Shi " -0x9964: "Ding " -0x9965: "Ji " -0x9966: "Tuo " -0x9967: "Xing " -0x9968: "Tun " -0x9969: "Xi " -0x996a: "Ren " -0x996b: "Yu " -0x996c: "Chi " -0x996d: "Fan " -0x996e: "Yin " -0x996f: "Jian " -0x9970: "Shi " -0x9971: "Bao " -0x9972: "Si " -0x9973: "Duo " -0x9974: "Yi " -0x9975: "Er " -0x9976: "Rao " -0x9977: "Xiang " -0x9978: "Jia " -0x9979: "Le " -0x997a: "Jiao " -0x997b: "Yi " -0x997c: "Bing " -0x997d: "Bo " -0x997e: "Dou " -0x997f: "E " -0x9980: "Yu " -0x9981: "Nei " -0x9982: "Jun " -0x9983: "Guo " -0x9984: "Hun " -0x9985: "Xian " -0x9986: "Guan " -0x9987: "Cha " -0x9988: "Kui " -0x9989: "Gu " -0x998a: "Sou " -0x998b: "Chan " -0x998c: "Ye " -0x998d: "Mo " -0x998e: "Bo " -0x998f: "Liu " -0x9990: "Xiu " -0x9991: "Jin " -0x9992: "Man " -0x9993: "San " -0x9994: "Zhuan " -0x9995: "Nang " -0x9996: "Shou " -0x9997: "Kui " -0x9998: "Guo " -0x9999: "Xiang " -0x999a: "Fen " -0x999b: "Ba " -0x999c: "Ni " -0x999d: "Bi " -0x999e: "Bo " -0x999f: "Tu " -0x99a0: "Han " -0x99a1: "Fei " -0x99a2: "Jian " -0x99a3: "An " -0x99a4: "Ai " -0x99a5: "Fu " -0x99a6: "Xian " -0x99a7: "Wen " -0x99a8: "Xin " -0x99a9: "Fen " -0x99aa: "Bin " -0x99ab: "Xing " -0x99ac: "Ma " -0x99ad: "Yu " -0x99ae: "Feng " -0x99af: "Han " -0x99b0: "Di " -0x99b1: "Tuo " -0x99b2: "Tuo " -0x99b3: "Chi " -0x99b4: "Xun " -0x99b5: "Zhu " -0x99b6: "Zhi " -0x99b7: "Pei " -0x99b8: "Xin " -0x99b9: "Ri " -0x99ba: "Sa " -0x99bb: "Yin " -0x99bc: "Wen " -0x99bd: "Zhi " -0x99be: "Dan " -0x99bf: "Lu " -0x99c0: "You " -0x99c1: "Bo " -0x99c2: "Bao " -0x99c3: "Kuai " -0x99c4: "Tuo " -0x99c5: "Yi " -0x99c6: "Qu " -0x99c7: "[?] " -0x99c8: "Qu " -0x99c9: "Jiong " -0x99ca: "Bo " -0x99cb: "Zhao " -0x99cc: "Yuan " -0x99cd: "Peng " -0x99ce: "Zhou " -0x99cf: "Ju " -0x99d0: "Zhu " -0x99d1: "Nu " -0x99d2: "Ju " -0x99d3: "Pi " -0x99d4: "Zang " -0x99d5: "Jia " -0x99d6: "Ling " -0x99d7: "Zhen " -0x99d8: "Tai " -0x99d9: "Fu " -0x99da: "Yang " -0x99db: "Shi " -0x99dc: "Bi " -0x99dd: "Tuo " -0x99de: "Tuo " -0x99df: "Si " -0x99e0: "Liu " -0x99e1: "Ma " -0x99e2: "Pian " -0x99e3: "Tao " -0x99e4: "Zhi " -0x99e5: "Rong " -0x99e6: "Teng " -0x99e7: "Dong " -0x99e8: "Xun " -0x99e9: "Quan " -0x99ea: "Shen " -0x99eb: "Jiong " -0x99ec: "Er " -0x99ed: "Hai " -0x99ee: "Bo " -0x99ef: "Zhu " -0x99f0: "Yin " -0x99f1: "Luo " -0x99f2: "Shuu " -0x99f3: "Dan " -0x99f4: "Xie " -0x99f5: "Liu " -0x99f6: "Ju " -0x99f7: "Song " -0x99f8: "Qin " -0x99f9: "Mang " -0x99fa: "Liang " -0x99fb: "Han " -0x99fc: "Tu " -0x99fd: "Xuan " -0x99fe: "Tui " -0x99ff: "Jun " -/* x09a */ -0x9a00: "E " -0x9a01: "Cheng " -0x9a02: "Xin " -0x9a03: "Ai " -0x9a04: "Lu " -0x9a05: "Zhui " -0x9a06: "Zhou " -0x9a07: "She " -0x9a08: "Pian " -0x9a09: "Kun " -0x9a0a: "Tao " -0x9a0b: "Lai " -0x9a0c: "Zong " -0x9a0d: "Ke " -0x9a0e: "Qi " -0x9a0f: "Qi " -0x9a10: "Yan " -0x9a11: "Fei " -0x9a12: "Sao " -0x9a13: "Yan " -0x9a14: "Jie " -0x9a15: "Yao " -0x9a16: "Wu " -0x9a17: "Pian " -0x9a18: "Cong " -0x9a19: "Pian " -0x9a1a: "Qian " -0x9a1b: "Fei " -0x9a1c: "Huang " -0x9a1d: "Jian " -0x9a1e: "Huo " -0x9a1f: "Yu " -0x9a20: "Ti " -0x9a21: "Quan " -0x9a22: "Xia " -0x9a23: "Zong " -0x9a24: "Kui " -0x9a25: "Rou " -0x9a26: "Si " -0x9a27: "Gua " -0x9a28: "Tuo " -0x9a29: "Kui " -0x9a2a: "Sou " -0x9a2b: "Qian " -0x9a2c: "Cheng " -0x9a2d: "Zhi " -0x9a2e: "Liu " -0x9a2f: "Pang " -0x9a30: "Teng " -0x9a31: "Xi " -0x9a32: "Cao " -0x9a33: "Du " -0x9a34: "Yan " -0x9a35: "Yuan " -0x9a36: "Zou " -0x9a37: "Sao " -0x9a38: "Shan " -0x9a39: "Li " -0x9a3a: "Zhi " -0x9a3b: "Shuang " -0x9a3c: "Lu " -0x9a3d: "Xi " -0x9a3e: "Luo " -0x9a3f: "Zhang " -0x9a40: "Mo " -0x9a41: "Ao " -0x9a42: "Can " -0x9a43: "Piao " -0x9a44: "Cong " -0x9a45: "Qu " -0x9a46: "Bi " -0x9a47: "Zhi " -0x9a48: "Yu " -0x9a49: "Xu " -0x9a4a: "Hua " -0x9a4b: "Bo " -0x9a4c: "Su " -0x9a4d: "Xiao " -0x9a4e: "Lin " -0x9a4f: "Chan " -0x9a50: "Dun " -0x9a51: "Liu " -0x9a52: "Tuo " -0x9a53: "Zeng " -0x9a54: "Tan " -0x9a55: "Jiao " -0x9a56: "Tie " -0x9a57: "Yan " -0x9a58: "Luo " -0x9a59: "Zhan " -0x9a5a: "Jing " -0x9a5b: "Yi " -0x9a5c: "Ye " -0x9a5d: "Tuo " -0x9a5e: "Bin " -0x9a5f: "Zou " -0x9a60: "Yan " -0x9a61: "Peng " -0x9a62: "Lu " -0x9a63: "Teng " -0x9a64: "Xiang " -0x9a65: "Ji " -0x9a66: "Shuang " -0x9a67: "Ju " -0x9a68: "Xi " -0x9a69: "Huan " -0x9a6a: "Li " -0x9a6b: "Biao " -0x9a6c: "Ma " -0x9a6d: "Yu " -0x9a6e: "Tuo " -0x9a6f: "Xun " -0x9a70: "Chi " -0x9a71: "Qu " -0x9a72: "Ri " -0x9a73: "Bo " -0x9a74: "Lu " -0x9a75: "Zang " -0x9a76: "Shi " -0x9a77: "Si " -0x9a78: "Fu " -0x9a79: "Ju " -0x9a7a: "Zou " -0x9a7b: "Zhu " -0x9a7c: "Tuo " -0x9a7d: "Nu " -0x9a7e: "Jia " -0x9a7f: "Yi " -0x9a80: "Tai " -0x9a81: "Xiao " -0x9a82: "Ma " -0x9a83: "Yin " -0x9a84: "Jiao " -0x9a85: "Hua " -0x9a86: "Luo " -0x9a87: "Hai " -0x9a88: "Pian " -0x9a89: "Biao " -0x9a8a: "Li " -0x9a8b: "Cheng " -0x9a8c: "Yan " -0x9a8d: "Xin " -0x9a8e: "Qin " -0x9a8f: "Jun " -0x9a90: "Qi " -0x9a91: "Qi " -0x9a92: "Ke " -0x9a93: "Zhui " -0x9a94: "Zong " -0x9a95: "Su " -0x9a96: "Can " -0x9a97: "Pian " -0x9a98: "Zhi " -0x9a99: "Kui " -0x9a9a: "Sao " -0x9a9b: "Wu " -0x9a9c: "Ao " -0x9a9d: "Liu " -0x9a9e: "Qian " -0x9a9f: "Shan " -0x9aa0: "Piao " -0x9aa1: "Luo " -0x9aa2: "Cong " -0x9aa3: "Chan " -0x9aa4: "Zou " -0x9aa5: "Ji " -0x9aa6: "Shuang " -0x9aa7: "Xiang " -0x9aa8: "Gu " -0x9aa9: "Wei " -0x9aaa: "Wei " -0x9aab: "Wei " -0x9aac: "Yu " -0x9aad: "Gan " -0x9aae: "Yi " -0x9aaf: "Ang " -0x9ab0: "Tou " -0x9ab1: "Xie " -0x9ab2: "Bao " -0x9ab3: "Bi " -0x9ab4: "Chi " -0x9ab5: "Ti " -0x9ab6: "Di " -0x9ab7: "Ku " -0x9ab8: "Hai " -0x9ab9: "Qiao " -0x9aba: "Gou " -0x9abb: "Kua " -0x9abc: "Ge " -0x9abd: "Tui " -0x9abe: "Geng " -0x9abf: "Pian " -0x9ac0: "Bi " -0x9ac1: "Ke " -0x9ac2: "Ka " -0x9ac3: "Yu " -0x9ac4: "Sui " -0x9ac5: "Lou " -0x9ac6: "Bo " -0x9ac7: "Xiao " -0x9ac8: "Pang " -0x9ac9: "Bo " -0x9aca: "Ci " -0x9acb: "Kuan " -0x9acc: "Bin " -0x9acd: "Mo " -0x9ace: "Liao " -0x9acf: "Lou " -0x9ad0: "Nao " -0x9ad1: "Du " -0x9ad2: "Zang " -0x9ad3: "Sui " -0x9ad4: "Ti " -0x9ad5: "Bin " -0x9ad6: "Kuan " -0x9ad7: "Lu " -0x9ad8: "Gao " -0x9ad9: "Gao " -0x9ada: "Qiao " -0x9adb: "Kao " -0x9adc: "Qiao " -0x9add: "Lao " -0x9ade: "Zao " -0x9adf: "Biao " -0x9ae0: "Kun " -0x9ae1: "Kun " -0x9ae2: "Ti " -0x9ae3: "Fang " -0x9ae4: "Xiu " -0x9ae5: "Ran " -0x9ae6: "Mao " -0x9ae7: "Dan " -0x9ae8: "Kun " -0x9ae9: "Bin " -0x9aea: "Fa " -0x9aeb: "Tiao " -0x9aec: "Peng " -0x9aed: "Zi " -0x9aee: "Fa " -0x9aef: "Ran " -0x9af0: "Ti " -0x9af1: "Pao " -0x9af2: "Pi " -0x9af3: "Mao " -0x9af4: "Fu " -0x9af5: "Er " -0x9af6: "Rong " -0x9af7: "Qu " -0x9af8: "Gong " -0x9af9: "Xiu " -0x9afa: "Gua " -0x9afb: "Ji " -0x9afc: "Peng " -0x9afd: "Zhua " -0x9afe: "Shao " -0x9aff: "Sha " -/* x09b */ -0x9b00: "Ti " -0x9b01: "Li " -0x9b02: "Bin " -0x9b03: "Zong " -0x9b04: "Ti " -0x9b05: "Peng " -0x9b06: "Song " -0x9b07: "Zheng " -0x9b08: "Quan " -0x9b09: "Zong " -0x9b0a: "Shun " -0x9b0b: "Jian " -0x9b0c: "Duo " -0x9b0d: "Hu " -0x9b0e: "La " -0x9b0f: "Jiu " -0x9b10: "Qi " -0x9b11: "Lian " -0x9b12: "Zhen " -0x9b13: "Bin " -0x9b14: "Peng " -0x9b15: "Mo " -0x9b16: "San " -0x9b17: "Man " -0x9b18: "Man " -0x9b19: "Seng " -0x9b1a: "Xu " -0x9b1b: "Lie " -0x9b1c: "Qian " -0x9b1d: "Qian " -0x9b1e: "Nong " -0x9b1f: "Huan " -0x9b20: "Kuai " -0x9b21: "Ning " -0x9b22: "Bin " -0x9b23: "Lie " -0x9b24: "Rang " -0x9b25: "Dou " -0x9b26: "Dou " -0x9b27: "Nao " -0x9b28: "Hong " -0x9b29: "Xi " -0x9b2a: "Dou " -0x9b2b: "Han " -0x9b2c: "Dou " -0x9b2d: "Dou " -0x9b2e: "Jiu " -0x9b2f: "Chang " -0x9b30: "Yu " -0x9b31: "Yu " -0x9b32: "Li " -0x9b33: "Juan " -0x9b34: "Fu " -0x9b35: "Qian " -0x9b36: "Gui " -0x9b37: "Zong " -0x9b38: "Liu " -0x9b39: "Gui " -0x9b3a: "Shang " -0x9b3b: "Yu " -0x9b3c: "Gui " -0x9b3d: "Mei " -0x9b3e: "Ji " -0x9b3f: "Qi " -0x9b40: "Jie " -0x9b41: "Kui " -0x9b42: "Hun " -0x9b43: "Ba " -0x9b44: "Po " -0x9b45: "Mei " -0x9b46: "Xu " -0x9b47: "Yan " -0x9b48: "Xiao " -0x9b49: "Liang " -0x9b4a: "Yu " -0x9b4b: "Tui " -0x9b4c: "Qi " -0x9b4d: "Wang " -0x9b4e: "Liang " -0x9b4f: "Wei " -0x9b50: "Jian " -0x9b51: "Chi " -0x9b52: "Piao " -0x9b53: "Bi " -0x9b54: "Mo " -0x9b55: "Ji " -0x9b56: "Xu " -0x9b57: "Chou " -0x9b58: "Yan " -0x9b59: "Zhan " -0x9b5a: "Yu " -0x9b5b: "Dao " -0x9b5c: "Ren " -0x9b5d: "Ji " -0x9b5e: "Eri " -0x9b5f: "Gong " -0x9b60: "Tuo " -0x9b61: "Diao " -0x9b62: "Ji " -0x9b63: "Xu " -0x9b64: "E " -0x9b65: "E " -0x9b66: "Sha " -0x9b67: "Hang " -0x9b68: "Tun " -0x9b69: "Mo " -0x9b6a: "Jie " -0x9b6b: "Shen " -0x9b6c: "Fan " -0x9b6d: "Yuan " -0x9b6e: "Bi " -0x9b6f: "Lu " -0x9b70: "Wen " -0x9b71: "Hu " -0x9b72: "Lu " -0x9b73: "Za " -0x9b74: "Fang " -0x9b75: "Fen " -0x9b76: "Na " -0x9b77: "You " -0x9b78: "Namazu " -0x9b79: "Todo " -0x9b7a: "He " -0x9b7b: "Xia " -0x9b7c: "Qu " -0x9b7d: "Han " -0x9b7e: "Pi " -0x9b7f: "Ling " -0x9b80: "Tuo " -0x9b81: "Bo " -0x9b82: "Qiu " -0x9b83: "Ping " -0x9b84: "Fu " -0x9b85: "Bi " -0x9b86: "Ji " -0x9b87: "Wei " -0x9b88: "Ju " -0x9b89: "Diao " -0x9b8a: "Bo " -0x9b8b: "You " -0x9b8c: "Gun " -0x9b8d: "Pi " -0x9b8e: "Nian " -0x9b8f: "Xing " -0x9b90: "Tai " -0x9b91: "Bao " -0x9b92: "Fu " -0x9b93: "Zha " -0x9b94: "Ju " -0x9b95: "Gu " -0x9b96: "Kajika " -0x9b97: "Tong " -0x9b98: "[?] " -0x9b99: "Ta " -0x9b9a: "Jie " -0x9b9b: "Shu " -0x9b9c: "Hou " -0x9b9d: "Xiang " -0x9b9e: "Er " -0x9b9f: "An " -0x9ba0: "Wei " -0x9ba1: "Tiao " -0x9ba2: "Zhu " -0x9ba3: "Yin " -0x9ba4: "Lie " -0x9ba5: "Luo " -0x9ba6: "Tong " -0x9ba7: "Yi " -0x9ba8: "Qi " -0x9ba9: "Bing " -0x9baa: "Wei " -0x9bab: "Jiao " -0x9bac: "Bu " -0x9bad: "Gui " -0x9bae: "Xian " -0x9baf: "Ge " -0x9bb0: "Hui " -0x9bb1: "Bora " -0x9bb2: "Mate " -0x9bb3: "Kao " -0x9bb4: "Gori " -0x9bb5: "Duo " -0x9bb6: "Jun " -0x9bb7: "Ti " -0x9bb8: "Man " -0x9bb9: "Xiao " -0x9bba: "Za " -0x9bbb: "Sha " -0x9bbc: "Qin " -0x9bbd: "Yu " -0x9bbe: "Nei " -0x9bbf: "Zhe " -0x9bc0: "Gun " -0x9bc1: "Geng " -0x9bc2: "Su " -0x9bc3: "Wu " -0x9bc4: "Qiu " -0x9bc5: "Ting " -0x9bc6: "Fu " -0x9bc7: "Wan " -0x9bc8: "You " -0x9bc9: "Li " -0x9bca: "Sha " -0x9bcb: "Sha " -0x9bcc: "Gao " -0x9bcd: "Meng " -0x9bce: "Ugui " -0x9bcf: "Asari " -0x9bd0: "Subashiri " -0x9bd1: "Kazunoko " -0x9bd2: "Yong " -0x9bd3: "Ni " -0x9bd4: "Zi " -0x9bd5: "Qi " -0x9bd6: "Qing " -0x9bd7: "Xiang " -0x9bd8: "Nei " -0x9bd9: "Chun " -0x9bda: "Ji " -0x9bdb: "Diao " -0x9bdc: "Qie " -0x9bdd: "Gu " -0x9bde: "Zhou " -0x9bdf: "Dong " -0x9be0: "Lai " -0x9be1: "Fei " -0x9be2: "Ni " -0x9be3: "Yi " -0x9be4: "Kun " -0x9be5: "Lu " -0x9be6: "Jiu " -0x9be7: "Chang " -0x9be8: "Jing " -0x9be9: "Lun " -0x9bea: "Ling " -0x9beb: "Zou " -0x9bec: "Li " -0x9bed: "Meng " -0x9bee: "Zong " -0x9bef: "Zhi " -0x9bf0: "Nian " -0x9bf1: "Shachi " -0x9bf2: "Dojou " -0x9bf3: "Sukesou " -0x9bf4: "Shi " -0x9bf5: "Shen " -0x9bf6: "Hun " -0x9bf7: "Shi " -0x9bf8: "Hou " -0x9bf9: "Xing " -0x9bfa: "Zhu " -0x9bfb: "La " -0x9bfc: "Zong " -0x9bfd: "Ji " -0x9bfe: "Bian " -0x9bff: "Bian " -/* x09c */ -0x9c00: "Huan " -0x9c01: "Quan " -0x9c02: "Ze " -0x9c03: "Wei " -0x9c04: "Wei " -0x9c05: "Yu " -0x9c06: "Qun " -0x9c07: "Rou " -0x9c08: "Die " -0x9c09: "Huang " -0x9c0a: "Lian " -0x9c0b: "Yan " -0x9c0c: "Qiu " -0x9c0d: "Qiu " -0x9c0e: "Jian " -0x9c0f: "Bi " -0x9c10: "E " -0x9c11: "Yang " -0x9c12: "Fu " -0x9c13: "Sai " -0x9c14: "Jian " -0x9c15: "Xia " -0x9c16: "Tuo " -0x9c17: "Hu " -0x9c18: "Muroaji " -0x9c19: "Ruo " -0x9c1a: "Haraka " -0x9c1b: "Wen " -0x9c1c: "Jian " -0x9c1d: "Hao " -0x9c1e: "Wu " -0x9c1f: "Fang " -0x9c20: "Sao " -0x9c21: "Liu " -0x9c22: "Ma " -0x9c23: "Shi " -0x9c24: "Shi " -0x9c25: "Yin " -0x9c26: "Z " -0x9c27: "Teng " -0x9c28: "Ta " -0x9c29: "Yao " -0x9c2a: "Ge " -0x9c2b: "Rong " -0x9c2c: "Qian " -0x9c2d: "Qi " -0x9c2e: "Wen " -0x9c2f: "Ruo " -0x9c30: "Hatahata " -0x9c31: "Lian " -0x9c32: "Ao " -0x9c33: "Le " -0x9c34: "Hui " -0x9c35: "Min " -0x9c36: "Ji " -0x9c37: "Tiao " -0x9c38: "Qu " -0x9c39: "Jian " -0x9c3a: "Sao " -0x9c3b: "Man " -0x9c3c: "Xi " -0x9c3d: "Qiu " -0x9c3e: "Biao " -0x9c3f: "Ji " -0x9c40: "Ji " -0x9c41: "Zhu " -0x9c42: "Jiang " -0x9c43: "Qiu " -0x9c44: "Zhuan " -0x9c45: "Yong " -0x9c46: "Zhang " -0x9c47: "Kang " -0x9c48: "Xue " -0x9c49: "Bie " -0x9c4a: "Jue " -0x9c4b: "Qu " -0x9c4c: "Xiang " -0x9c4d: "Bo " -0x9c4e: "Jiao " -0x9c4f: "Xun " -0x9c50: "Su " -0x9c51: "Huang " -0x9c52: "Zun " -0x9c53: "Shan " -0x9c54: "Shan " -0x9c55: "Fan " -0x9c56: "Jue " -0x9c57: "Lin " -0x9c58: "Xun " -0x9c59: "Miao " -0x9c5a: "Xi " -0x9c5b: "Eso " -0x9c5c: "Kyou " -0x9c5d: "Fen " -0x9c5e: "Guan " -0x9c5f: "Hou " -0x9c60: "Kuai " -0x9c61: "Zei " -0x9c62: "Sao " -0x9c63: "Zhan " -0x9c64: "Gan " -0x9c65: "Gui " -0x9c66: "Sheng " -0x9c67: "Li " -0x9c68: "Chang " -0x9c69: "Hatahata " -0x9c6a: "Shiira " -0x9c6b: "Mutsu " -0x9c6c: "Ru " -0x9c6d: "Ji " -0x9c6e: "Xu " -0x9c6f: "Huo " -0x9c70: "Shiira " -0x9c71: "Li " -0x9c72: "Lie " -0x9c73: "Li " -0x9c74: "Mie " -0x9c75: "Zhen " -0x9c76: "Xiang " -0x9c77: "E " -0x9c78: "Lu " -0x9c79: "Guan " -0x9c7a: "Li " -0x9c7b: "Xian " -0x9c7c: "Yu " -0x9c7d: "Dao " -0x9c7e: "Ji " -0x9c7f: "You " -0x9c80: "Tun " -0x9c81: "Lu " -0x9c82: "Fang " -0x9c83: "Ba " -0x9c84: "He " -0x9c85: "Bo " -0x9c86: "Ping " -0x9c87: "Nian " -0x9c88: "Lu " -0x9c89: "You " -0x9c8a: "Zha " -0x9c8b: "Fu " -0x9c8c: "Bo " -0x9c8d: "Bao " -0x9c8e: "Hou " -0x9c8f: "Pi " -0x9c90: "Tai " -0x9c91: "Gui " -0x9c92: "Jie " -0x9c93: "Kao " -0x9c94: "Wei " -0x9c95: "Er " -0x9c96: "Tong " -0x9c97: "Ze " -0x9c98: "Hou " -0x9c99: "Kuai " -0x9c9a: "Ji " -0x9c9b: "Jiao " -0x9c9c: "Xian " -0x9c9d: "Za " -0x9c9e: "Xiang " -0x9c9f: "Xun " -0x9ca0: "Geng " -0x9ca1: "Li " -0x9ca2: "Lian " -0x9ca3: "Jian " -0x9ca4: "Li " -0x9ca5: "Shi " -0x9ca6: "Tiao " -0x9ca7: "Gun " -0x9ca8: "Sha " -0x9ca9: "Wan " -0x9caa: "Jun " -0x9cab: "Ji " -0x9cac: "Yong " -0x9cad: "Qing " -0x9cae: "Ling " -0x9caf: "Qi " -0x9cb0: "Zou " -0x9cb1: "Fei " -0x9cb2: "Kun " -0x9cb3: "Chang " -0x9cb4: "Gu " -0x9cb5: "Ni " -0x9cb6: "Nian " -0x9cb7: "Diao " -0x9cb8: "Jing " -0x9cb9: "Shen " -0x9cba: "Shi " -0x9cbb: "Zi " -0x9cbc: "Fen " -0x9cbd: "Die " -0x9cbe: "Bi " -0x9cbf: "Chang " -0x9cc0: "Shi " -0x9cc1: "Wen " -0x9cc2: "Wei " -0x9cc3: "Sai " -0x9cc4: "E " -0x9cc5: "Qiu " -0x9cc6: "Fu " -0x9cc7: "Huang " -0x9cc8: "Quan " -0x9cc9: "Jiang " -0x9cca: "Bian " -0x9ccb: "Sao " -0x9ccc: "Ao " -0x9ccd: "Qi " -0x9cce: "Ta " -0x9ccf: "Yin " -0x9cd0: "Yao " -0x9cd1: "Fang " -0x9cd2: "Jian " -0x9cd3: "Le " -0x9cd4: "Biao " -0x9cd5: "Xue " -0x9cd6: "Bie " -0x9cd7: "Man " -0x9cd8: "Min " -0x9cd9: "Yong " -0x9cda: "Wei " -0x9cdb: "Xi " -0x9cdc: "Jue " -0x9cdd: "Shan " -0x9cde: "Lin " -0x9cdf: "Zun " -0x9ce0: "Huo " -0x9ce1: "Gan " -0x9ce2: "Li " -0x9ce3: "Zhan " -0x9ce4: "Guan " -0x9ce5: "Niao " -0x9ce6: "Yi " -0x9ce7: "Fu " -0x9ce8: "Li " -0x9ce9: "Jiu " -0x9cea: "Bu " -0x9ceb: "Yan " -0x9cec: "Fu " -0x9ced: "Diao " -0x9cee: "Ji " -0x9cef: "Feng " -0x9cf0: "Nio " -0x9cf1: "Gan " -0x9cf2: "Shi " -0x9cf3: "Feng " -0x9cf4: "Ming " -0x9cf5: "Bao " -0x9cf6: "Yuan " -0x9cf7: "Zhi " -0x9cf8: "Hu " -0x9cf9: "Qin " -0x9cfa: "Fu " -0x9cfb: "Fen " -0x9cfc: "Wen " -0x9cfd: "Jian " -0x9cfe: "Shi " -0x9cff: "Yu " -/* x09d */ -0x9d00: "Fou " -0x9d01: "Yiao " -0x9d02: "Jue " -0x9d03: "Jue " -0x9d04: "Pi " -0x9d05: "Huan " -0x9d06: "Zhen " -0x9d07: "Bao " -0x9d08: "Yan " -0x9d09: "Ya " -0x9d0a: "Zheng " -0x9d0b: "Fang " -0x9d0c: "Feng " -0x9d0d: "Wen " -0x9d0e: "Ou " -0x9d0f: "Te " -0x9d10: "Jia " -0x9d11: "Nu " -0x9d12: "Ling " -0x9d13: "Mie " -0x9d14: "Fu " -0x9d15: "Tuo " -0x9d16: "Wen " -0x9d17: "Li " -0x9d18: "Bian " -0x9d19: "Zhi " -0x9d1a: "Ge " -0x9d1b: "Yuan " -0x9d1c: "Zi " -0x9d1d: "Qu " -0x9d1e: "Xiao " -0x9d1f: "Zhi " -0x9d20: "Dan " -0x9d21: "Ju " -0x9d22: "You " -0x9d23: "Gu " -0x9d24: "Zhong " -0x9d25: "Yu " -0x9d26: "Yang " -0x9d27: "Rong " -0x9d28: "Ya " -0x9d29: "Tie " -0x9d2a: "Yu " -0x9d2b: "Shigi " -0x9d2c: "Ying " -0x9d2d: "Zhui " -0x9d2e: "Wu " -0x9d2f: "Er " -0x9d30: "Gua " -0x9d31: "Ai " -0x9d32: "Zhi " -0x9d33: "Yan " -0x9d34: "Heng " -0x9d35: "Jiao " -0x9d36: "Ji " -0x9d37: "Lie " -0x9d38: "Zhu " -0x9d39: "Ren " -0x9d3a: "Yi " -0x9d3b: "Hong " -0x9d3c: "Luo " -0x9d3d: "Ru " -0x9d3e: "Mou " -0x9d3f: "Ge " -0x9d40: "Ren " -0x9d41: "Jiao " -0x9d42: "Xiu " -0x9d43: "Zhou " -0x9d44: "Zhi " -0x9d45: "Luo " -0x9d46: "Chidori " -0x9d47: "Toki " -0x9d48: "Ten " -0x9d49: "Luan " -0x9d4a: "Jia " -0x9d4b: "Ji " -0x9d4c: "Yu " -0x9d4d: "Huan " -0x9d4e: "Tuo " -0x9d4f: "Bu " -0x9d50: "Wu " -0x9d51: "Juan " -0x9d52: "Yu " -0x9d53: "Bo " -0x9d54: "Xun " -0x9d55: "Xun " -0x9d56: "Bi " -0x9d57: "Xi " -0x9d58: "Jun " -0x9d59: "Ju " -0x9d5a: "Tu " -0x9d5b: "Jing " -0x9d5c: "Ti " -0x9d5d: "E " -0x9d5e: "E " -0x9d5f: "Kuang " -0x9d60: "Hu " -0x9d61: "Wu " -0x9d62: "Shen " -0x9d63: "Lai " -0x9d64: "Ikaruga " -0x9d65: "Kakesu " -0x9d66: "Lu " -0x9d67: "Ping " -0x9d68: "Shu " -0x9d69: "Fu " -0x9d6a: "An " -0x9d6b: "Zhao " -0x9d6c: "Peng " -0x9d6d: "Qin " -0x9d6e: "Qian " -0x9d6f: "Bei " -0x9d70: "Diao " -0x9d71: "Lu " -0x9d72: "Que " -0x9d73: "Jian " -0x9d74: "Ju " -0x9d75: "Tu " -0x9d76: "Ya " -0x9d77: "Yuan " -0x9d78: "Qi " -0x9d79: "Li " -0x9d7a: "Ye " -0x9d7b: "Zhui " -0x9d7c: "Kong " -0x9d7d: "Zhui " -0x9d7e: "Kun " -0x9d7f: "Sheng " -0x9d80: "Qi " -0x9d81: "Jing " -0x9d82: "Yi " -0x9d83: "Yi " -0x9d84: "Jing " -0x9d85: "Zi " -0x9d86: "Lai " -0x9d87: "Dong " -0x9d88: "Qi " -0x9d89: "Chun " -0x9d8a: "Geng " -0x9d8b: "Ju " -0x9d8c: "Qu " -0x9d8d: "Isuka " -0x9d8e: "Kikuitadaki " -0x9d8f: "Ji " -0x9d90: "Shu " -0x9d91: "[?] " -0x9d92: "Chi " -0x9d93: "Miao " -0x9d94: "Rou " -0x9d95: "An " -0x9d96: "Qiu " -0x9d97: "Ti " -0x9d98: "Hu " -0x9d99: "Ti " -0x9d9a: "E " -0x9d9b: "Jie " -0x9d9c: "Mao " -0x9d9d: "Fu " -0x9d9e: "Chun " -0x9d9f: "Tu " -0x9da0: "Yan " -0x9da1: "He " -0x9da2: "Yuan " -0x9da3: "Pian " -0x9da4: "Yun " -0x9da5: "Mei " -0x9da6: "Hu " -0x9da7: "Ying " -0x9da8: "Dun " -0x9da9: "Mu " -0x9daa: "Ju " -0x9dab: "Tsugumi " -0x9dac: "Cang " -0x9dad: "Fang " -0x9dae: "Gu " -0x9daf: "Ying " -0x9db0: "Yuan " -0x9db1: "Xuan " -0x9db2: "Weng " -0x9db3: "Shi " -0x9db4: "He " -0x9db5: "Chu " -0x9db6: "Tang " -0x9db7: "Xia " -0x9db8: "Ruo " -0x9db9: "Liu " -0x9dba: "Ji " -0x9dbb: "Gu " -0x9dbc: "Jian " -0x9dbd: "Zhun " -0x9dbe: "Han " -0x9dbf: "Zi " -0x9dc0: "Zi " -0x9dc1: "Ni " -0x9dc2: "Yao " -0x9dc3: "Yan " -0x9dc4: "Ji " -0x9dc5: "Li " -0x9dc6: "Tian " -0x9dc7: "Kou " -0x9dc8: "Ti " -0x9dc9: "Ti " -0x9dca: "Ni " -0x9dcb: "Tu " -0x9dcc: "Ma " -0x9dcd: "Jiao " -0x9dce: "Gao " -0x9dcf: "Tian " -0x9dd0: "Chen " -0x9dd1: "Li " -0x9dd2: "Zhuan " -0x9dd3: "Zhe " -0x9dd4: "Ao " -0x9dd5: "Yao " -0x9dd6: "Yi " -0x9dd7: "Ou " -0x9dd8: "Chi " -0x9dd9: "Zhi " -0x9dda: "Liao " -0x9ddb: "Rong " -0x9ddc: "Lou " -0x9ddd: "Bi " -0x9dde: "Shuang " -0x9ddf: "Zhuo " -0x9de0: "Yu " -0x9de1: "Wu " -0x9de2: "Jue " -0x9de3: "Yin " -0x9de4: "Quan " -0x9de5: "Si " -0x9de6: "Jiao " -0x9de7: "Yi " -0x9de8: "Hua " -0x9de9: "Bi " -0x9dea: "Ying " -0x9deb: "Su " -0x9dec: "Huang " -0x9ded: "Fan " -0x9dee: "Jiao " -0x9def: "Liao " -0x9df0: "Yan " -0x9df1: "Kao " -0x9df2: "Jiu " -0x9df3: "Xian " -0x9df4: "Xian " -0x9df5: "Tu " -0x9df6: "Mai " -0x9df7: "Zun " -0x9df8: "Yu " -0x9df9: "Ying " -0x9dfa: "Lu " -0x9dfb: "Tuan " -0x9dfc: "Xian " -0x9dfd: "Xue " -0x9dfe: "Yi " -0x9dff: "Pi " -/* x09e */ -0x9e00: "Shu " -0x9e01: "Luo " -0x9e02: "Qi " -0x9e03: "Yi " -0x9e04: "Ji " -0x9e05: "Zhe " -0x9e06: "Yu " -0x9e07: "Zhan " -0x9e08: "Ye " -0x9e09: "Yang " -0x9e0a: "Pi " -0x9e0b: "Ning " -0x9e0c: "Huo " -0x9e0d: "Mi " -0x9e0e: "Ying " -0x9e0f: "Meng " -0x9e10: "Di " -0x9e11: "Yue " -0x9e12: "Yu " -0x9e13: "Lei " -0x9e14: "Bao " -0x9e15: "Lu " -0x9e16: "He " -0x9e17: "Long " -0x9e18: "Shuang " -0x9e19: "Yue " -0x9e1a: "Ying " -0x9e1b: "Guan " -0x9e1c: "Qu " -0x9e1d: "Li " -0x9e1e: "Luan " -0x9e1f: "Niao " -0x9e20: "Jiu " -0x9e21: "Ji " -0x9e22: "Yuan " -0x9e23: "Ming " -0x9e24: "Shi " -0x9e25: "Ou " -0x9e26: "Ya " -0x9e27: "Cang " -0x9e28: "Bao " -0x9e29: "Zhen " -0x9e2a: "Gu " -0x9e2b: "Dong " -0x9e2c: "Lu " -0x9e2d: "Ya " -0x9e2e: "Xiao " -0x9e2f: "Yang " -0x9e30: "Ling " -0x9e31: "Zhi " -0x9e32: "Qu " -0x9e33: "Yuan " -0x9e34: "Xue " -0x9e35: "Tuo " -0x9e36: "Si " -0x9e37: "Zhi " -0x9e38: "Er " -0x9e39: "Gua " -0x9e3a: "Xiu " -0x9e3b: "Heng " -0x9e3c: "Zhou " -0x9e3d: "Ge " -0x9e3e: "Luan " -0x9e3f: "Hong " -0x9e40: "Wu " -0x9e41: "Bo " -0x9e42: "Li " -0x9e43: "Juan " -0x9e44: "Hu " -0x9e45: "E " -0x9e46: "Yu " -0x9e47: "Xian " -0x9e48: "Ti " -0x9e49: "Wu " -0x9e4a: "Que " -0x9e4b: "Miao " -0x9e4c: "An " -0x9e4d: "Kun " -0x9e4e: "Bei " -0x9e4f: "Peng " -0x9e50: "Qian " -0x9e51: "Chun " -0x9e52: "Geng " -0x9e53: "Yuan " -0x9e54: "Su " -0x9e55: "Hu " -0x9e56: "He " -0x9e57: "E " -0x9e58: "Gu " -0x9e59: "Qiu " -0x9e5a: "Zi " -0x9e5b: "Mei " -0x9e5c: "Mu " -0x9e5d: "Ni " -0x9e5e: "Yao " -0x9e5f: "Weng " -0x9e60: "Liu " -0x9e61: "Ji " -0x9e62: "Ni " -0x9e63: "Jian " -0x9e64: "He " -0x9e65: "Yi " -0x9e66: "Ying " -0x9e67: "Zhe " -0x9e68: "Liao " -0x9e69: "Liao " -0x9e6a: "Jiao " -0x9e6b: "Jiu " -0x9e6c: "Yu " -0x9e6d: "Lu " -0x9e6e: "Xuan " -0x9e6f: "Zhan " -0x9e70: "Ying " -0x9e71: "Huo " -0x9e72: "Meng " -0x9e73: "Guan " -0x9e74: "Shuang " -0x9e75: "Lu " -0x9e76: "Jin " -0x9e77: "Ling " -0x9e78: "Jian " -0x9e79: "Xian " -0x9e7a: "Cuo " -0x9e7b: "Jian " -0x9e7c: "Jian " -0x9e7d: "Yan " -0x9e7e: "Cuo " -0x9e7f: "Lu " -0x9e80: "You " -0x9e81: "Cu " -0x9e82: "Ji " -0x9e83: "Biao " -0x9e84: "Cu " -0x9e85: "Biao " -0x9e86: "Zhu " -0x9e87: "Jun " -0x9e88: "Zhu " -0x9e89: "Jian " -0x9e8a: "Mi " -0x9e8b: "Mi " -0x9e8c: "Wu " -0x9e8d: "Liu " -0x9e8e: "Chen " -0x9e8f: "Jun " -0x9e90: "Lin " -0x9e91: "Ni " -0x9e92: "Qi " -0x9e93: "Lu " -0x9e94: "Jiu " -0x9e95: "Jun " -0x9e96: "Jing " -0x9e97: "Li " -0x9e98: "Xiang " -0x9e99: "Yan " -0x9e9a: "Jia " -0x9e9b: "Mi " -0x9e9c: "Li " -0x9e9d: "She " -0x9e9e: "Zhang " -0x9e9f: "Lin " -0x9ea0: "Jing " -0x9ea1: "Ji " -0x9ea2: "Ling " -0x9ea3: "Yan " -0x9ea4: "Cu " -0x9ea5: "Mai " -0x9ea6: "Mai " -0x9ea7: "Ge " -0x9ea8: "Chao " -0x9ea9: "Fu " -0x9eaa: "Mian " -0x9eab: "Mian " -0x9eac: "Fu " -0x9ead: "Pao " -0x9eae: "Qu " -0x9eaf: "Qu " -0x9eb0: "Mou " -0x9eb1: "Fu " -0x9eb2: "Xian " -0x9eb3: "Lai " -0x9eb4: "Qu " -0x9eb5: "Mian " -0x9eb6: "[?] " -0x9eb7: "Feng " -0x9eb8: "Fu " -0x9eb9: "Qu " -0x9eba: "Mian " -0x9ebb: "Ma " -0x9ebc: "Mo " -0x9ebd: "Mo " -0x9ebe: "Hui " -0x9ebf: "Ma " -0x9ec0: "Zou " -0x9ec1: "Nen " -0x9ec2: "Fen " -0x9ec3: "Huang " -0x9ec4: "Huang " -0x9ec5: "Jin " -0x9ec6: "Guang " -0x9ec7: "Tian " -0x9ec8: "Tou " -0x9ec9: "Heng " -0x9eca: "Xi " -0x9ecb: "Kuang " -0x9ecc: "Heng " -0x9ecd: "Shu " -0x9ece: "Li " -0x9ecf: "Nian " -0x9ed0: "Chi " -0x9ed1: "Hei " -0x9ed2: "Hei " -0x9ed3: "Yi " -0x9ed4: "Qian " -0x9ed5: "Dan " -0x9ed6: "Xi " -0x9ed7: "Tuan " -0x9ed8: "Mo " -0x9ed9: "Mo " -0x9eda: "Qian " -0x9edb: "Dai " -0x9edc: "Chu " -0x9edd: "You " -0x9ede: "Dian " -0x9edf: "Yi " -0x9ee0: "Xia " -0x9ee1: "Yan " -0x9ee2: "Qu " -0x9ee3: "Mei " -0x9ee4: "Yan " -0x9ee5: "Jing " -0x9ee6: "Yu " -0x9ee7: "Li " -0x9ee8: "Dang " -0x9ee9: "Du " -0x9eea: "Can " -0x9eeb: "Yin " -0x9eec: "An " -0x9eed: "Yan " -0x9eee: "Tan " -0x9eef: "An " -0x9ef0: "Zhen " -0x9ef1: "Dai " -0x9ef2: "Can " -0x9ef3: "Yi " -0x9ef4: "Mei " -0x9ef5: "Dan " -0x9ef6: "Yan " -0x9ef7: "Du " -0x9ef8: "Lu " -0x9ef9: "Zhi " -0x9efa: "Fen " -0x9efb: "Fu " -0x9efc: "Fu " -0x9efd: "Min " -0x9efe: "Min " -0x9eff: "Yuan " -/* x09f */ -0x9f00: "Cu " -0x9f01: "Qu " -0x9f02: "Chao " -0x9f03: "Wa " -0x9f04: "Zhu " -0x9f05: "Zhi " -0x9f06: "Mang " -0x9f07: "Ao " -0x9f08: "Bie " -0x9f09: "Tuo " -0x9f0a: "Bi " -0x9f0b: "Yuan " -0x9f0c: "Chao " -0x9f0d: "Tuo " -0x9f0e: "Ding " -0x9f0f: "Mi " -0x9f10: "Nai " -0x9f11: "Ding " -0x9f12: "Zi " -0x9f13: "Gu " -0x9f14: "Gu " -0x9f15: "Dong " -0x9f16: "Fen " -0x9f17: "Tao " -0x9f18: "Yuan " -0x9f19: "Pi " -0x9f1a: "Chang " -0x9f1b: "Gao " -0x9f1c: "Qi " -0x9f1d: "Yuan " -0x9f1e: "Tang " -0x9f1f: "Teng " -0x9f20: "Shu " -0x9f21: "Shu " -0x9f22: "Fen " -0x9f23: "Fei " -0x9f24: "Wen " -0x9f25: "Ba " -0x9f26: "Diao " -0x9f27: "Tuo " -0x9f28: "Tong " -0x9f29: "Qu " -0x9f2a: "Sheng " -0x9f2b: "Shi " -0x9f2c: "You " -0x9f2d: "Shi " -0x9f2e: "Ting " -0x9f2f: "Wu " -0x9f30: "Nian " -0x9f31: "Jing " -0x9f32: "Hun " -0x9f33: "Ju " -0x9f34: "Yan " -0x9f35: "Tu " -0x9f36: "Ti " -0x9f37: "Xi " -0x9f38: "Xian " -0x9f39: "Yan " -0x9f3a: "Lei " -0x9f3b: "Bi " -0x9f3c: "Yao " -0x9f3d: "Qiu " -0x9f3e: "Han " -0x9f3f: "Wu " -0x9f40: "Wu " -0x9f41: "Hou " -0x9f42: "Xi " -0x9f43: "Ge " -0x9f44: "Zha " -0x9f45: "Xiu " -0x9f46: "Weng " -0x9f47: "Zha " -0x9f48: "Nong " -0x9f49: "Nang " -0x9f4a: "Qi " -0x9f4b: "Zhai " -0x9f4c: "Ji " -0x9f4d: "Zi " -0x9f4e: "Ji " -0x9f4f: "Ji " -0x9f50: "Qi " -0x9f51: "Ji " -0x9f52: "Chi " -0x9f53: "Chen " -0x9f54: "Chen " -0x9f55: "He " -0x9f56: "Ya " -0x9f57: "Ken " -0x9f58: "Xie " -0x9f59: "Pao " -0x9f5a: "Cuo " -0x9f5b: "Shi " -0x9f5c: "Zi " -0x9f5d: "Chi " -0x9f5e: "Nian " -0x9f5f: "Ju " -0x9f60: "Tiao " -0x9f61: "Ling " -0x9f62: "Ling " -0x9f63: "Chu " -0x9f64: "Quan " -0x9f65: "Xie " -0x9f66: "Ken " -0x9f67: "Nie " -0x9f68: "Jiu " -0x9f69: "Yao " -0x9f6a: "Chuo " -0x9f6b: "Kun " -0x9f6c: "Yu " -0x9f6d: "Chu " -0x9f6e: "Yi " -0x9f6f: "Ni " -0x9f70: "Cuo " -0x9f71: "Zou " -0x9f72: "Qu " -0x9f73: "Nen " -0x9f74: "Xian " -0x9f75: "Ou " -0x9f76: "E " -0x9f77: "Wo " -0x9f78: "Yi " -0x9f79: "Chuo " -0x9f7a: "Zou " -0x9f7b: "Dian " -0x9f7c: "Chu " -0x9f7d: "Jin " -0x9f7e: "Ya " -0x9f7f: "Chi " -0x9f80: "Chen " -0x9f81: "He " -0x9f82: "Ken " -0x9f83: "Ju " -0x9f84: "Ling " -0x9f85: "Pao " -0x9f86: "Tiao " -0x9f87: "Zi " -0x9f88: "Ken " -0x9f89: "Yu " -0x9f8a: "Chuo " -0x9f8b: "Qu " -0x9f8c: "Wo " -0x9f8d: "Long " -0x9f8e: "Pang " -0x9f8f: "Gong " -0x9f90: "Pang " -0x9f91: "Yan " -0x9f92: "Long " -0x9f93: "Long " -0x9f94: "Gong " -0x9f95: "Kan " -0x9f96: "Ta " -0x9f97: "Ling " -0x9f98: "Ta " -0x9f99: "Long " -0x9f9a: "Gong " -0x9f9b: "Kan " -0x9f9c: "Gui " -0x9f9d: "Qiu " -0x9f9e: "Bie " -0x9f9f: "Gui " -0x9fa0: "Yue " -0x9fa1: "Chui " -0x9fa2: "He " -0x9fa3: "Jue " -0x9fa4: "Xie " -0x9fa5: "Yu " -0x9fa6: "[?]" -0x9fa7: "[?]" -0x9fa8: "[?]" -0x9fa9: "[?]" -0x9faa: "[?]" -0x9fab: "[?]" -0x9fac: "[?]" -0x9fad: "[?]" -0x9fae: "[?]" -0x9faf: "[?]" -0x9fb0: "[?]" -0x9fb1: "[?]" -0x9fb2: "[?]" -0x9fb3: "[?]" -0x9fb4: "[?]" -0x9fb5: "[?]" -0x9fb6: "[?]" -0x9fb7: "[?]" -0x9fb8: "[?]" -0x9fb9: "[?]" -0x9fba: "[?]" -0x9fbb: "[?]" -0x9fbc: "[?]" -0x9fbd: "[?]" -0x9fbe: "[?]" -0x9fbf: "[?]" -0x9fc0: "[?]" -0x9fc1: "[?]" -0x9fc2: "[?]" -0x9fc3: "[?]" -0x9fc4: "[?]" -0x9fc5: "[?]" -0x9fc6: "[?]" -0x9fc7: "[?]" -0x9fc8: "[?]" -0x9fc9: "[?]" -0x9fca: "[?]" -0x9fcb: "[?]" -0x9fcc: "[?]" -0x9fcd: "[?]" -0x9fce: "[?]" -0x9fcf: "[?]" -0x9fd0: "[?]" -0x9fd1: "[?]" -0x9fd2: "[?]" -0x9fd3: "[?]" -0x9fd4: "[?]" -0x9fd5: "[?]" -0x9fd6: "[?]" -0x9fd7: "[?]" -0x9fd8: "[?]" -0x9fd9: "[?]" -0x9fda: "[?]" -0x9fdb: "[?]" -0x9fdc: "[?]" -0x9fdd: "[?]" -0x9fde: "[?]" -0x9fdf: "[?]" -0x9fe0: "[?]" -0x9fe1: "[?]" -0x9fe2: "[?]" -0x9fe3: "[?]" -0x9fe4: "[?]" -0x9fe5: "[?]" -0x9fe6: "[?]" -0x9fe7: "[?]" -0x9fe8: "[?]" -0x9fe9: "[?]" -0x9fea: "[?]" -0x9feb: "[?]" -0x9fec: "[?]" -0x9fed: "[?]" -0x9fee: "[?]" -0x9fef: "[?]" -0x9ff0: "[?]" -0x9ff1: "[?]" -0x9ff2: "[?]" -0x9ff3: "[?]" -0x9ff4: "[?]" -0x9ff5: "[?]" -0x9ff6: "[?]" -0x9ff7: "[?]" -0x9ff8: "[?]" -0x9ff9: "[?]" -0x9ffa: "[?]" -0x9ffb: "[?]" -0x9ffc: "[?]" -0x9ffd: "[?]" -0x9ffe: "[?]" -/* x0a0 */ -0xa000: "it" -0xa001: "ix" -0xa002: "i" -0xa003: "ip" -0xa004: "iet" -0xa005: "iex" -0xa006: "ie" -0xa007: "iep" -0xa008: "at" -0xa009: "ax" -0xa00a: "a" -0xa00b: "ap" -0xa00c: "uox" -0xa00d: "uo" -0xa00e: "uop" -0xa00f: "ot" -0xa010: "ox" -0xa011: "o" -0xa012: "op" -0xa013: "ex" -0xa014: "e" -0xa015: "wu" -0xa016: "bit" -0xa017: "bix" -0xa018: "bi" -0xa019: "bip" -0xa01a: "biet" -0xa01b: "biex" -0xa01c: "bie" -0xa01d: "biep" -0xa01e: "bat" -0xa01f: "bax" -0xa020: "ba" -0xa021: "bap" -0xa022: "buox" -0xa023: "buo" -0xa024: "buop" -0xa025: "bot" -0xa026: "box" -0xa027: "bo" -0xa028: "bop" -0xa029: "bex" -0xa02a: "be" -0xa02b: "bep" -0xa02c: "but" -0xa02d: "bux" -0xa02e: "bu" -0xa02f: "bup" -0xa030: "burx" -0xa031: "bur" -0xa032: "byt" -0xa033: "byx" -0xa034: "by" -0xa035: "byp" -0xa036: "byrx" -0xa037: "byr" -0xa038: "pit" -0xa039: "pix" -0xa03a: "pi" -0xa03b: "pip" -0xa03c: "piex" -0xa03d: "pie" -0xa03e: "piep" -0xa03f: "pat" -0xa040: "pax" -0xa041: "pa" -0xa042: "pap" -0xa043: "puox" -0xa044: "puo" -0xa045: "puop" -0xa046: "pot" -0xa047: "pox" -0xa048: "po" -0xa049: "pop" -0xa04a: "put" -0xa04b: "pux" -0xa04c: "pu" -0xa04d: "pup" -0xa04e: "purx" -0xa04f: "pur" -0xa050: "pyt" -0xa051: "pyx" -0xa052: "py" -0xa053: "pyp" -0xa054: "pyrx" -0xa055: "pyr" -0xa056: "bbit" -0xa057: "bbix" -0xa058: "bbi" -0xa059: "bbip" -0xa05a: "bbiet" -0xa05b: "bbiex" -0xa05c: "bbie" -0xa05d: "bbiep" -0xa05e: "bbat" -0xa05f: "bbax" -0xa060: "bba" -0xa061: "bbap" -0xa062: "bbuox" -0xa063: "bbuo" -0xa064: "bbuop" -0xa065: "bbot" -0xa066: "bbox" -0xa067: "bbo" -0xa068: "bbop" -0xa069: "bbex" -0xa06a: "bbe" -0xa06b: "bbep" -0xa06c: "bbut" -0xa06d: "bbux" -0xa06e: "bbu" -0xa06f: "bbup" -0xa070: "bburx" -0xa071: "bbur" -0xa072: "bbyt" -0xa073: "bbyx" -0xa074: "bby" -0xa075: "bbyp" -0xa076: "nbit" -0xa077: "nbix" -0xa078: "nbi" -0xa079: "nbip" -0xa07a: "nbiex" -0xa07b: "nbie" -0xa07c: "nbiep" -0xa07d: "nbat" -0xa07e: "nbax" -0xa07f: "nba" -0xa080: "nbap" -0xa081: "nbot" -0xa082: "nbox" -0xa083: "nbo" -0xa084: "nbop" -0xa085: "nbut" -0xa086: "nbux" -0xa087: "nbu" -0xa088: "nbup" -0xa089: "nburx" -0xa08a: "nbur" -0xa08b: "nbyt" -0xa08c: "nbyx" -0xa08d: "nby" -0xa08e: "nbyp" -0xa08f: "nbyrx" -0xa090: "nbyr" -0xa091: "hmit" -0xa092: "hmix" -0xa093: "hmi" -0xa094: "hmip" -0xa095: "hmiex" -0xa096: "hmie" -0xa097: "hmiep" -0xa098: "hmat" -0xa099: "hmax" -0xa09a: "hma" -0xa09b: "hmap" -0xa09c: "hmuox" -0xa09d: "hmuo" -0xa09e: "hmuop" -0xa09f: "hmot" -0xa0a0: "hmox" -0xa0a1: "hmo" -0xa0a2: "hmop" -0xa0a3: "hmut" -0xa0a4: "hmux" -0xa0a5: "hmu" -0xa0a6: "hmup" -0xa0a7: "hmurx" -0xa0a8: "hmur" -0xa0a9: "hmyx" -0xa0aa: "hmy" -0xa0ab: "hmyp" -0xa0ac: "hmyrx" -0xa0ad: "hmyr" -0xa0ae: "mit" -0xa0af: "mix" -0xa0b0: "mi" -0xa0b1: "mip" -0xa0b2: "miex" -0xa0b3: "mie" -0xa0b4: "miep" -0xa0b5: "mat" -0xa0b6: "max" -0xa0b7: "ma" -0xa0b8: "map" -0xa0b9: "muot" -0xa0ba: "muox" -0xa0bb: "muo" -0xa0bc: "muop" -0xa0bd: "mot" -0xa0be: "mox" -0xa0bf: "mo" -0xa0c0: "mop" -0xa0c1: "mex" -0xa0c2: "me" -0xa0c3: "mut" -0xa0c4: "mux" -0xa0c5: "mu" -0xa0c6: "mup" -0xa0c7: "murx" -0xa0c8: "mur" -0xa0c9: "myt" -0xa0ca: "myx" -0xa0cb: "my" -0xa0cc: "myp" -0xa0cd: "fit" -0xa0ce: "fix" -0xa0cf: "fi" -0xa0d0: "fip" -0xa0d1: "fat" -0xa0d2: "fax" -0xa0d3: "fa" -0xa0d4: "fap" -0xa0d5: "fox" -0xa0d6: "fo" -0xa0d7: "fop" -0xa0d8: "fut" -0xa0d9: "fux" -0xa0da: "fu" -0xa0db: "fup" -0xa0dc: "furx" -0xa0dd: "fur" -0xa0de: "fyt" -0xa0df: "fyx" -0xa0e0: "fy" -0xa0e1: "fyp" -0xa0e2: "vit" -0xa0e3: "vix" -0xa0e4: "vi" -0xa0e5: "vip" -0xa0e6: "viet" -0xa0e7: "viex" -0xa0e8: "vie" -0xa0e9: "viep" -0xa0ea: "vat" -0xa0eb: "vax" -0xa0ec: "va" -0xa0ed: "vap" -0xa0ee: "vot" -0xa0ef: "vox" -0xa0f0: "vo" -0xa0f1: "vop" -0xa0f2: "vex" -0xa0f3: "vep" -0xa0f4: "vut" -0xa0f5: "vux" -0xa0f6: "vu" -0xa0f7: "vup" -0xa0f8: "vurx" -0xa0f9: "vur" -0xa0fa: "vyt" -0xa0fb: "vyx" -0xa0fc: "vy" -0xa0fd: "vyp" -0xa0fe: "vyrx" -0xa0ff: "vyr" -/* x0a1 */ -0xa100: "dit" -0xa101: "dix" -0xa102: "di" -0xa103: "dip" -0xa104: "diex" -0xa105: "die" -0xa106: "diep" -0xa107: "dat" -0xa108: "dax" -0xa109: "da" -0xa10a: "dap" -0xa10b: "duox" -0xa10c: "duo" -0xa10d: "dot" -0xa10e: "dox" -0xa10f: "do" -0xa110: "dop" -0xa111: "dex" -0xa112: "de" -0xa113: "dep" -0xa114: "dut" -0xa115: "dux" -0xa116: "du" -0xa117: "dup" -0xa118: "durx" -0xa119: "dur" -0xa11a: "tit" -0xa11b: "tix" -0xa11c: "ti" -0xa11d: "tip" -0xa11e: "tiex" -0xa11f: "tie" -0xa120: "tiep" -0xa121: "tat" -0xa122: "tax" -0xa123: "ta" -0xa124: "tap" -0xa125: "tuot" -0xa126: "tuox" -0xa127: "tuo" -0xa128: "tuop" -0xa129: "tot" -0xa12a: "tox" -0xa12b: "to" -0xa12c: "top" -0xa12d: "tex" -0xa12e: "te" -0xa12f: "tep" -0xa130: "tut" -0xa131: "tux" -0xa132: "tu" -0xa133: "tup" -0xa134: "turx" -0xa135: "tur" -0xa136: "ddit" -0xa137: "ddix" -0xa138: "ddi" -0xa139: "ddip" -0xa13a: "ddiex" -0xa13b: "ddie" -0xa13c: "ddiep" -0xa13d: "ddat" -0xa13e: "ddax" -0xa13f: "dda" -0xa140: "ddap" -0xa141: "dduox" -0xa142: "dduo" -0xa143: "dduop" -0xa144: "ddot" -0xa145: "ddox" -0xa146: "ddo" -0xa147: "ddop" -0xa148: "ddex" -0xa149: "dde" -0xa14a: "ddep" -0xa14b: "ddut" -0xa14c: "ddux" -0xa14d: "ddu" -0xa14e: "ddup" -0xa14f: "ddurx" -0xa150: "ddur" -0xa151: "ndit" -0xa152: "ndix" -0xa153: "ndi" -0xa154: "ndip" -0xa155: "ndiex" -0xa156: "ndie" -0xa157: "ndat" -0xa158: "ndax" -0xa159: "nda" -0xa15a: "ndap" -0xa15b: "ndot" -0xa15c: "ndox" -0xa15d: "ndo" -0xa15e: "ndop" -0xa15f: "ndex" -0xa160: "nde" -0xa161: "ndep" -0xa162: "ndut" -0xa163: "ndux" -0xa164: "ndu" -0xa165: "ndup" -0xa166: "ndurx" -0xa167: "ndur" -0xa168: "hnit" -0xa169: "hnix" -0xa16a: "hni" -0xa16b: "hnip" -0xa16c: "hniet" -0xa16d: "hniex" -0xa16e: "hnie" -0xa16f: "hniep" -0xa170: "hnat" -0xa171: "hnax" -0xa172: "hna" -0xa173: "hnap" -0xa174: "hnuox" -0xa175: "hnuo" -0xa176: "hnot" -0xa177: "hnox" -0xa178: "hnop" -0xa179: "hnex" -0xa17a: "hne" -0xa17b: "hnep" -0xa17c: "hnut" -0xa17d: "nit" -0xa17e: "nix" -0xa17f: "ni" -0xa180: "nip" -0xa181: "niex" -0xa182: "nie" -0xa183: "niep" -0xa184: "nax" -0xa185: "na" -0xa186: "nap" -0xa187: "nuox" -0xa188: "nuo" -0xa189: "nuop" -0xa18a: "not" -0xa18b: "nox" -0xa18c: "no" -0xa18d: "nop" -0xa18e: "nex" -0xa18f: "ne" -0xa190: "nep" -0xa191: "nut" -0xa192: "nux" -0xa193: "nu" -0xa194: "nup" -0xa195: "nurx" -0xa196: "nur" -0xa197: "hlit" -0xa198: "hlix" -0xa199: "hli" -0xa19a: "hlip" -0xa19b: "hliex" -0xa19c: "hlie" -0xa19d: "hliep" -0xa19e: "hlat" -0xa19f: "hlax" -0xa1a0: "hla" -0xa1a1: "hlap" -0xa1a2: "hluox" -0xa1a3: "hluo" -0xa1a4: "hluop" -0xa1a5: "hlox" -0xa1a6: "hlo" -0xa1a7: "hlop" -0xa1a8: "hlex" -0xa1a9: "hle" -0xa1aa: "hlep" -0xa1ab: "hlut" -0xa1ac: "hlux" -0xa1ad: "hlu" -0xa1ae: "hlup" -0xa1af: "hlurx" -0xa1b0: "hlur" -0xa1b1: "hlyt" -0xa1b2: "hlyx" -0xa1b3: "hly" -0xa1b4: "hlyp" -0xa1b5: "hlyrx" -0xa1b6: "hlyr" -0xa1b7: "lit" -0xa1b8: "lix" -0xa1b9: "li" -0xa1ba: "lip" -0xa1bb: "liet" -0xa1bc: "liex" -0xa1bd: "lie" -0xa1be: "liep" -0xa1bf: "lat" -0xa1c0: "lax" -0xa1c1: "la" -0xa1c2: "lap" -0xa1c3: "luot" -0xa1c4: "luox" -0xa1c5: "luo" -0xa1c6: "luop" -0xa1c7: "lot" -0xa1c8: "lox" -0xa1c9: "lo" -0xa1ca: "lop" -0xa1cb: "lex" -0xa1cc: "le" -0xa1cd: "lep" -0xa1ce: "lut" -0xa1cf: "lux" -0xa1d0: "lu" -0xa1d1: "lup" -0xa1d2: "lurx" -0xa1d3: "lur" -0xa1d4: "lyt" -0xa1d5: "lyx" -0xa1d6: "ly" -0xa1d7: "lyp" -0xa1d8: "lyrx" -0xa1d9: "lyr" -0xa1da: "git" -0xa1db: "gix" -0xa1dc: "gi" -0xa1dd: "gip" -0xa1de: "giet" -0xa1df: "giex" -0xa1e0: "gie" -0xa1e1: "giep" -0xa1e2: "gat" -0xa1e3: "gax" -0xa1e4: "ga" -0xa1e5: "gap" -0xa1e6: "guot" -0xa1e7: "guox" -0xa1e8: "guo" -0xa1e9: "guop" -0xa1ea: "got" -0xa1eb: "gox" -0xa1ec: "go" -0xa1ed: "gop" -0xa1ee: "get" -0xa1ef: "gex" -0xa1f0: "ge" -0xa1f1: "gep" -0xa1f2: "gut" -0xa1f3: "gux" -0xa1f4: "gu" -0xa1f5: "gup" -0xa1f6: "gurx" -0xa1f7: "gur" -0xa1f8: "kit" -0xa1f9: "kix" -0xa1fa: "ki" -0xa1fb: "kip" -0xa1fc: "kiex" -0xa1fd: "kie" -0xa1fe: "kiep" -0xa1ff: "kat" -/* x0a2 */ -0xa200: "kax" -0xa201: "ka" -0xa202: "kap" -0xa203: "kuox" -0xa204: "kuo" -0xa205: "kuop" -0xa206: "kot" -0xa207: "kox" -0xa208: "ko" -0xa209: "kop" -0xa20a: "ket" -0xa20b: "kex" -0xa20c: "ke" -0xa20d: "kep" -0xa20e: "kut" -0xa20f: "kux" -0xa210: "ku" -0xa211: "kup" -0xa212: "kurx" -0xa213: "kur" -0xa214: "ggit" -0xa215: "ggix" -0xa216: "ggi" -0xa217: "ggiex" -0xa218: "ggie" -0xa219: "ggiep" -0xa21a: "ggat" -0xa21b: "ggax" -0xa21c: "gga" -0xa21d: "ggap" -0xa21e: "gguot" -0xa21f: "gguox" -0xa220: "gguo" -0xa221: "gguop" -0xa222: "ggot" -0xa223: "ggox" -0xa224: "ggo" -0xa225: "ggop" -0xa226: "gget" -0xa227: "ggex" -0xa228: "gge" -0xa229: "ggep" -0xa22a: "ggut" -0xa22b: "ggux" -0xa22c: "ggu" -0xa22d: "ggup" -0xa22e: "ggurx" -0xa22f: "ggur" -0xa230: "mgiex" -0xa231: "mgie" -0xa232: "mgat" -0xa233: "mgax" -0xa234: "mga" -0xa235: "mgap" -0xa236: "mguox" -0xa237: "mguo" -0xa238: "mguop" -0xa239: "mgot" -0xa23a: "mgox" -0xa23b: "mgo" -0xa23c: "mgop" -0xa23d: "mgex" -0xa23e: "mge" -0xa23f: "mgep" -0xa240: "mgut" -0xa241: "mgux" -0xa242: "mgu" -0xa243: "mgup" -0xa244: "mgurx" -0xa245: "mgur" -0xa246: "hxit" -0xa247: "hxix" -0xa248: "hxi" -0xa249: "hxip" -0xa24a: "hxiet" -0xa24b: "hxiex" -0xa24c: "hxie" -0xa24d: "hxiep" -0xa24e: "hxat" -0xa24f: "hxax" -0xa250: "hxa" -0xa251: "hxap" -0xa252: "hxuot" -0xa253: "hxuox" -0xa254: "hxuo" -0xa255: "hxuop" -0xa256: "hxot" -0xa257: "hxox" -0xa258: "hxo" -0xa259: "hxop" -0xa25a: "hxex" -0xa25b: "hxe" -0xa25c: "hxep" -0xa25d: "ngiex" -0xa25e: "ngie" -0xa25f: "ngiep" -0xa260: "ngat" -0xa261: "ngax" -0xa262: "nga" -0xa263: "ngap" -0xa264: "nguot" -0xa265: "nguox" -0xa266: "nguo" -0xa267: "ngot" -0xa268: "ngox" -0xa269: "ngo" -0xa26a: "ngop" -0xa26b: "ngex" -0xa26c: "nge" -0xa26d: "ngep" -0xa26e: "hit" -0xa26f: "hiex" -0xa270: "hie" -0xa271: "hat" -0xa272: "hax" -0xa273: "ha" -0xa274: "hap" -0xa275: "huot" -0xa276: "huox" -0xa277: "huo" -0xa278: "huop" -0xa279: "hot" -0xa27a: "hox" -0xa27b: "ho" -0xa27c: "hop" -0xa27d: "hex" -0xa27e: "he" -0xa27f: "hep" -0xa280: "wat" -0xa281: "wax" -0xa282: "wa" -0xa283: "wap" -0xa284: "wuox" -0xa285: "wuo" -0xa286: "wuop" -0xa287: "wox" -0xa288: "wo" -0xa289: "wop" -0xa28a: "wex" -0xa28b: "we" -0xa28c: "wep" -0xa28d: "zit" -0xa28e: "zix" -0xa28f: "zi" -0xa290: "zip" -0xa291: "ziex" -0xa292: "zie" -0xa293: "ziep" -0xa294: "zat" -0xa295: "zax" -0xa296: "za" -0xa297: "zap" -0xa298: "zuox" -0xa299: "zuo" -0xa29a: "zuop" -0xa29b: "zot" -0xa29c: "zox" -0xa29d: "zo" -0xa29e: "zop" -0xa29f: "zex" -0xa2a0: "ze" -0xa2a1: "zep" -0xa2a2: "zut" -0xa2a3: "zux" -0xa2a4: "zu" -0xa2a5: "zup" -0xa2a6: "zurx" -0xa2a7: "zur" -0xa2a8: "zyt" -0xa2a9: "zyx" -0xa2aa: "zy" -0xa2ab: "zyp" -0xa2ac: "zyrx" -0xa2ad: "zyr" -0xa2ae: "cit" -0xa2af: "cix" -0xa2b0: "ci" -0xa2b1: "cip" -0xa2b2: "ciet" -0xa2b3: "ciex" -0xa2b4: "cie" -0xa2b5: "ciep" -0xa2b6: "cat" -0xa2b7: "cax" -0xa2b8: "ca" -0xa2b9: "cap" -0xa2ba: "cuox" -0xa2bb: "cuo" -0xa2bc: "cuop" -0xa2bd: "cot" -0xa2be: "cox" -0xa2bf: "co" -0xa2c0: "cop" -0xa2c1: "cex" -0xa2c2: "ce" -0xa2c3: "cep" -0xa2c4: "cut" -0xa2c5: "cux" -0xa2c6: "cu" -0xa2c7: "cup" -0xa2c8: "curx" -0xa2c9: "cur" -0xa2ca: "cyt" -0xa2cb: "cyx" -0xa2cc: "cy" -0xa2cd: "cyp" -0xa2ce: "cyrx" -0xa2cf: "cyr" -0xa2d0: "zzit" -0xa2d1: "zzix" -0xa2d2: "zzi" -0xa2d3: "zzip" -0xa2d4: "zziet" -0xa2d5: "zziex" -0xa2d6: "zzie" -0xa2d7: "zziep" -0xa2d8: "zzat" -0xa2d9: "zzax" -0xa2da: "zza" -0xa2db: "zzap" -0xa2dc: "zzox" -0xa2dd: "zzo" -0xa2de: "zzop" -0xa2df: "zzex" -0xa2e0: "zze" -0xa2e1: "zzep" -0xa2e2: "zzux" -0xa2e3: "zzu" -0xa2e4: "zzup" -0xa2e5: "zzurx" -0xa2e6: "zzur" -0xa2e7: "zzyt" -0xa2e8: "zzyx" -0xa2e9: "zzy" -0xa2ea: "zzyp" -0xa2eb: "zzyrx" -0xa2ec: "zzyr" -0xa2ed: "nzit" -0xa2ee: "nzix" -0xa2ef: "nzi" -0xa2f0: "nzip" -0xa2f1: "nziex" -0xa2f2: "nzie" -0xa2f3: "nziep" -0xa2f4: "nzat" -0xa2f5: "nzax" -0xa2f6: "nza" -0xa2f7: "nzap" -0xa2f8: "nzuox" -0xa2f9: "nzuo" -0xa2fa: "nzox" -0xa2fb: "nzop" -0xa2fc: "nzex" -0xa2fd: "nze" -0xa2fe: "nzux" -0xa2ff: "nzu" -/* x0a3 */ -0xa300: "nzup" -0xa301: "nzurx" -0xa302: "nzur" -0xa303: "nzyt" -0xa304: "nzyx" -0xa305: "nzy" -0xa306: "nzyp" -0xa307: "nzyrx" -0xa308: "nzyr" -0xa309: "sit" -0xa30a: "six" -0xa30b: "si" -0xa30c: "sip" -0xa30d: "siex" -0xa30e: "sie" -0xa30f: "siep" -0xa310: "sat" -0xa311: "sax" -0xa312: "sa" -0xa313: "sap" -0xa314: "suox" -0xa315: "suo" -0xa316: "suop" -0xa317: "sot" -0xa318: "sox" -0xa319: "so" -0xa31a: "sop" -0xa31b: "sex" -0xa31c: "se" -0xa31d: "sep" -0xa31e: "sut" -0xa31f: "sux" -0xa320: "su" -0xa321: "sup" -0xa322: "surx" -0xa323: "sur" -0xa324: "syt" -0xa325: "syx" -0xa326: "sy" -0xa327: "syp" -0xa328: "syrx" -0xa329: "syr" -0xa32a: "ssit" -0xa32b: "ssix" -0xa32c: "ssi" -0xa32d: "ssip" -0xa32e: "ssiex" -0xa32f: "ssie" -0xa330: "ssiep" -0xa331: "ssat" -0xa332: "ssax" -0xa333: "ssa" -0xa334: "ssap" -0xa335: "ssot" -0xa336: "ssox" -0xa337: "sso" -0xa338: "ssop" -0xa339: "ssex" -0xa33a: "sse" -0xa33b: "ssep" -0xa33c: "ssut" -0xa33d: "ssux" -0xa33e: "ssu" -0xa33f: "ssup" -0xa340: "ssyt" -0xa341: "ssyx" -0xa342: "ssy" -0xa343: "ssyp" -0xa344: "ssyrx" -0xa345: "ssyr" -0xa346: "zhat" -0xa347: "zhax" -0xa348: "zha" -0xa349: "zhap" -0xa34a: "zhuox" -0xa34b: "zhuo" -0xa34c: "zhuop" -0xa34d: "zhot" -0xa34e: "zhox" -0xa34f: "zho" -0xa350: "zhop" -0xa351: "zhet" -0xa352: "zhex" -0xa353: "zhe" -0xa354: "zhep" -0xa355: "zhut" -0xa356: "zhux" -0xa357: "zhu" -0xa358: "zhup" -0xa359: "zhurx" -0xa35a: "zhur" -0xa35b: "zhyt" -0xa35c: "zhyx" -0xa35d: "zhy" -0xa35e: "zhyp" -0xa35f: "zhyrx" -0xa360: "zhyr" -0xa361: "chat" -0xa362: "chax" -0xa363: "cha" -0xa364: "chap" -0xa365: "chuot" -0xa366: "chuox" -0xa367: "chuo" -0xa368: "chuop" -0xa369: "chot" -0xa36a: "chox" -0xa36b: "cho" -0xa36c: "chop" -0xa36d: "chet" -0xa36e: "chex" -0xa36f: "che" -0xa370: "chep" -0xa371: "chux" -0xa372: "chu" -0xa373: "chup" -0xa374: "churx" -0xa375: "chur" -0xa376: "chyt" -0xa377: "chyx" -0xa378: "chy" -0xa379: "chyp" -0xa37a: "chyrx" -0xa37b: "chyr" -0xa37c: "rrax" -0xa37d: "rra" -0xa37e: "rruox" -0xa37f: "rruo" -0xa380: "rrot" -0xa381: "rrox" -0xa382: "rro" -0xa383: "rrop" -0xa384: "rret" -0xa385: "rrex" -0xa386: "rre" -0xa387: "rrep" -0xa388: "rrut" -0xa389: "rrux" -0xa38a: "rru" -0xa38b: "rrup" -0xa38c: "rrurx" -0xa38d: "rrur" -0xa38e: "rryt" -0xa38f: "rryx" -0xa390: "rry" -0xa391: "rryp" -0xa392: "rryrx" -0xa393: "rryr" -0xa394: "nrat" -0xa395: "nrax" -0xa396: "nra" -0xa397: "nrap" -0xa398: "nrox" -0xa399: "nro" -0xa39a: "nrop" -0xa39b: "nret" -0xa39c: "nrex" -0xa39d: "nre" -0xa39e: "nrep" -0xa39f: "nrut" -0xa3a0: "nrux" -0xa3a1: "nru" -0xa3a2: "nrup" -0xa3a3: "nrurx" -0xa3a4: "nrur" -0xa3a5: "nryt" -0xa3a6: "nryx" -0xa3a7: "nry" -0xa3a8: "nryp" -0xa3a9: "nryrx" -0xa3aa: "nryr" -0xa3ab: "shat" -0xa3ac: "shax" -0xa3ad: "sha" -0xa3ae: "shap" -0xa3af: "shuox" -0xa3b0: "shuo" -0xa3b1: "shuop" -0xa3b2: "shot" -0xa3b3: "shox" -0xa3b4: "sho" -0xa3b5: "shop" -0xa3b6: "shet" -0xa3b7: "shex" -0xa3b8: "she" -0xa3b9: "shep" -0xa3ba: "shut" -0xa3bb: "shux" -0xa3bc: "shu" -0xa3bd: "shup" -0xa3be: "shurx" -0xa3bf: "shur" -0xa3c0: "shyt" -0xa3c1: "shyx" -0xa3c2: "shy" -0xa3c3: "shyp" -0xa3c4: "shyrx" -0xa3c5: "shyr" -0xa3c6: "rat" -0xa3c7: "rax" -0xa3c8: "ra" -0xa3c9: "rap" -0xa3ca: "ruox" -0xa3cb: "ruo" -0xa3cc: "ruop" -0xa3cd: "rot" -0xa3ce: "rox" -0xa3cf: "ro" -0xa3d0: "rop" -0xa3d1: "rex" -0xa3d2: "re" -0xa3d3: "rep" -0xa3d4: "rut" -0xa3d5: "rux" -0xa3d6: "ru" -0xa3d7: "rup" -0xa3d8: "rurx" -0xa3d9: "rur" -0xa3da: "ryt" -0xa3db: "ryx" -0xa3dc: "ry" -0xa3dd: "ryp" -0xa3de: "ryrx" -0xa3df: "ryr" -0xa3e0: "jit" -0xa3e1: "jix" -0xa3e2: "ji" -0xa3e3: "jip" -0xa3e4: "jiet" -0xa3e5: "jiex" -0xa3e6: "jie" -0xa3e7: "jiep" -0xa3e8: "juot" -0xa3e9: "juox" -0xa3ea: "juo" -0xa3eb: "juop" -0xa3ec: "jot" -0xa3ed: "jox" -0xa3ee: "jo" -0xa3ef: "jop" -0xa3f0: "jut" -0xa3f1: "jux" -0xa3f2: "ju" -0xa3f3: "jup" -0xa3f4: "jurx" -0xa3f5: "jur" -0xa3f6: "jyt" -0xa3f7: "jyx" -0xa3f8: "jy" -0xa3f9: "jyp" -0xa3fa: "jyrx" -0xa3fb: "jyr" -0xa3fc: "qit" -0xa3fd: "qix" -0xa3fe: "qi" -0xa3ff: "qip" -/* x0a4 */ -0xa400: "qiet" -0xa401: "qiex" -0xa402: "qie" -0xa403: "qiep" -0xa404: "quot" -0xa405: "quox" -0xa406: "quo" -0xa407: "quop" -0xa408: "qot" -0xa409: "qox" -0xa40a: "qo" -0xa40b: "qop" -0xa40c: "qut" -0xa40d: "qux" -0xa40e: "qu" -0xa40f: "qup" -0xa410: "qurx" -0xa411: "qur" -0xa412: "qyt" -0xa413: "qyx" -0xa414: "qy" -0xa415: "qyp" -0xa416: "qyrx" -0xa417: "qyr" -0xa418: "jjit" -0xa419: "jjix" -0xa41a: "jji" -0xa41b: "jjip" -0xa41c: "jjiet" -0xa41d: "jjiex" -0xa41e: "jjie" -0xa41f: "jjiep" -0xa420: "jjuox" -0xa421: "jjuo" -0xa422: "jjuop" -0xa423: "jjot" -0xa424: "jjox" -0xa425: "jjo" -0xa426: "jjop" -0xa427: "jjut" -0xa428: "jjux" -0xa429: "jju" -0xa42a: "jjup" -0xa42b: "jjurx" -0xa42c: "jjur" -0xa42d: "jjyt" -0xa42e: "jjyx" -0xa42f: "jjy" -0xa430: "jjyp" -0xa431: "njit" -0xa432: "njix" -0xa433: "nji" -0xa434: "njip" -0xa435: "njiet" -0xa436: "njiex" -0xa437: "njie" -0xa438: "njiep" -0xa439: "njuox" -0xa43a: "njuo" -0xa43b: "njot" -0xa43c: "njox" -0xa43d: "njo" -0xa43e: "njop" -0xa43f: "njux" -0xa440: "nju" -0xa441: "njup" -0xa442: "njurx" -0xa443: "njur" -0xa444: "njyt" -0xa445: "njyx" -0xa446: "njy" -0xa447: "njyp" -0xa448: "njyrx" -0xa449: "njyr" -0xa44a: "nyit" -0xa44b: "nyix" -0xa44c: "nyi" -0xa44d: "nyip" -0xa44e: "nyiet" -0xa44f: "nyiex" -0xa450: "nyie" -0xa451: "nyiep" -0xa452: "nyuox" -0xa453: "nyuo" -0xa454: "nyuop" -0xa455: "nyot" -0xa456: "nyox" -0xa457: "nyo" -0xa458: "nyop" -0xa459: "nyut" -0xa45a: "nyux" -0xa45b: "nyu" -0xa45c: "nyup" -0xa45d: "xit" -0xa45e: "xix" -0xa45f: "xi" -0xa460: "xip" -0xa461: "xiet" -0xa462: "xiex" -0xa463: "xie" -0xa464: "xiep" -0xa465: "xuox" -0xa466: "xuo" -0xa467: "xot" -0xa468: "xox" -0xa469: "xo" -0xa46a: "xop" -0xa46b: "xyt" -0xa46c: "xyx" -0xa46d: "xy" -0xa46e: "xyp" -0xa46f: "xyrx" -0xa470: "xyr" -0xa471: "yit" -0xa472: "yix" -0xa473: "yi" -0xa474: "yip" -0xa475: "yiet" -0xa476: "yiex" -0xa477: "yie" -0xa478: "yiep" -0xa479: "yuot" -0xa47a: "yuox" -0xa47b: "yuo" -0xa47c: "yuop" -0xa47d: "yot" -0xa47e: "yox" -0xa47f: "yo" -0xa480: "yop" -0xa481: "yut" -0xa482: "yux" -0xa483: "yu" -0xa484: "yup" -0xa485: "yurx" -0xa486: "yur" -0xa487: "yyt" -0xa488: "yyx" -0xa489: "yy" -0xa48a: "yyp" -0xa48b: "yyrx" -0xa48c: "yyr" -0xa48d: "[?]" -0xa48e: "[?]" -0xa48f: "[?]" -0xa490: "Qot" -0xa491: "Li" -0xa492: "Kit" -0xa493: "Nyip" -0xa494: "Cyp" -0xa495: "Ssi" -0xa496: "Ggop" -0xa497: "Gep" -0xa498: "Mi" -0xa499: "Hxit" -0xa49a: "Lyr" -0xa49b: "Bbut" -0xa49c: "Mop" -0xa49d: "Yo" -0xa49e: "Put" -0xa49f: "Hxuo" -0xa4a0: "Tat" -0xa4a1: "Ga" -0xa4a2: "[?]" -0xa4a3: "[?]" -0xa4a4: "Ddur" -0xa4a5: "Bur" -0xa4a6: "Gguo" -0xa4a7: "Nyop" -0xa4a8: "Tu" -0xa4a9: "Op" -0xa4aa: "Jjut" -0xa4ab: "Zot" -0xa4ac: "Pyt" -0xa4ad: "Hmo" -0xa4ae: "Yit" -0xa4af: "Vur" -0xa4b0: "Shy" -0xa4b1: "Vep" -0xa4b2: "Za" -0xa4b3: "Jo" -0xa4b4: "[?]" -0xa4b5: "Jjy" -0xa4b6: "Got" -0xa4b7: "Jjie" -0xa4b8: "Wo" -0xa4b9: "Du" -0xa4ba: "Shur" -0xa4bb: "Lie" -0xa4bc: "Cy" -0xa4bd: "Cuop" -0xa4be: "Cip" -0xa4bf: "Hxop" -0xa4c0: "Shat" -0xa4c1: "[?]" -0xa4c2: "Shop" -0xa4c3: "Che" -0xa4c4: "Zziet" -0xa4c5: "[?]" -0xa4c6: "Ke" -0xa4c7: "[?]" -0xa4c8: "[?]" -0xa4c9: "[?]" -0xa4ca: "[?]" -0xa4cb: "[?]" -0xa4cc: "[?]" -0xa4cd: "[?]" -0xa4ce: "[?]" -0xa4cf: "[?]" -0xa4d0: "[?]" -0xa4d1: "[?]" -0xa4d2: "[?]" -0xa4d3: "[?]" -0xa4d4: "[?]" -0xa4d5: "[?]" -0xa4d6: "[?]" -0xa4d7: "[?]" -0xa4d8: "[?]" -0xa4d9: "[?]" -0xa4da: "[?]" -0xa4db: "[?]" -0xa4dc: "[?]" -0xa4dd: "[?]" -0xa4de: "[?]" -0xa4df: "[?]" -0xa4e0: "[?]" -0xa4e1: "[?]" -0xa4e2: "[?]" -0xa4e3: "[?]" -0xa4e4: "[?]" -0xa4e5: "[?]" -0xa4e6: "[?]" -0xa4e7: "[?]" -0xa4e8: "[?]" -0xa4e9: "[?]" -0xa4ea: "[?]" -0xa4eb: "[?]" -0xa4ec: "[?]" -0xa4ed: "[?]" -0xa4ee: "[?]" -0xa4ef: "[?]" -0xa4f0: "[?]" -0xa4f1: "[?]" -0xa4f2: "[?]" -0xa4f3: "[?]" -0xa4f4: "[?]" -0xa4f5: "[?]" -0xa4f6: "[?]" -0xa4f7: "[?]" -0xa4f8: "[?]" -0xa4f9: "[?]" -0xa4fa: "[?]" -0xa4fb: "[?]" -0xa4fc: "[?]" -0xa4fd: "[?]" -0xa4fe: "[?]" -/* x0ac */ -0xac00: "ga" -0xac01: "gag" -0xac02: "gagg" -0xac03: "gags" -0xac04: "gan" -0xac05: "ganj" -0xac06: "ganh" -0xac07: "gad" -0xac08: "gal" -0xac09: "galg" -0xac0a: "galm" -0xac0b: "galb" -0xac0c: "gals" -0xac0d: "galt" -0xac0e: "galp" -0xac0f: "galh" -0xac10: "gam" -0xac11: "gab" -0xac12: "gabs" -0xac13: "gas" -0xac14: "gass" -0xac15: "gang" -0xac16: "gaj" -0xac17: "gac" -0xac18: "gak" -0xac19: "gat" -0xac1a: "gap" -0xac1b: "gah" -0xac1c: "gae" -0xac1d: "gaeg" -0xac1e: "gaegg" -0xac1f: "gaegs" -0xac20: "gaen" -0xac21: "gaenj" -0xac22: "gaenh" -0xac23: "gaed" -0xac24: "gael" -0xac25: "gaelg" -0xac26: "gaelm" -0xac27: "gaelb" -0xac28: "gaels" -0xac29: "gaelt" -0xac2a: "gaelp" -0xac2b: "gaelh" -0xac2c: "gaem" -0xac2d: "gaeb" -0xac2e: "gaebs" -0xac2f: "gaes" -0xac30: "gaess" -0xac31: "gaeng" -0xac32: "gaej" -0xac33: "gaec" -0xac34: "gaek" -0xac35: "gaet" -0xac36: "gaep" -0xac37: "gaeh" -0xac38: "gya" -0xac39: "gyag" -0xac3a: "gyagg" -0xac3b: "gyags" -0xac3c: "gyan" -0xac3d: "gyanj" -0xac3e: "gyanh" -0xac3f: "gyad" -0xac40: "gyal" -0xac41: "gyalg" -0xac42: "gyalm" -0xac43: "gyalb" -0xac44: "gyals" -0xac45: "gyalt" -0xac46: "gyalp" -0xac47: "gyalh" -0xac48: "gyam" -0xac49: "gyab" -0xac4a: "gyabs" -0xac4b: "gyas" -0xac4c: "gyass" -0xac4d: "gyang" -0xac4e: "gyaj" -0xac4f: "gyac" -0xac50: "gyak" -0xac51: "gyat" -0xac52: "gyap" -0xac53: "gyah" -0xac54: "gyae" -0xac55: "gyaeg" -0xac56: "gyaegg" -0xac57: "gyaegs" -0xac58: "gyaen" -0xac59: "gyaenj" -0xac5a: "gyaenh" -0xac5b: "gyaed" -0xac5c: "gyael" -0xac5d: "gyaelg" -0xac5e: "gyaelm" -0xac5f: "gyaelb" -0xac60: "gyaels" -0xac61: "gyaelt" -0xac62: "gyaelp" -0xac63: "gyaelh" -0xac64: "gyaem" -0xac65: "gyaeb" -0xac66: "gyaebs" -0xac67: "gyaes" -0xac68: "gyaess" -0xac69: "gyaeng" -0xac6a: "gyaej" -0xac6b: "gyaec" -0xac6c: "gyaek" -0xac6d: "gyaet" -0xac6e: "gyaep" -0xac6f: "gyaeh" -0xac70: "geo" -0xac71: "geog" -0xac72: "geogg" -0xac73: "geogs" -0xac74: "geon" -0xac75: "geonj" -0xac76: "geonh" -0xac77: "geod" -0xac78: "geol" -0xac79: "geolg" -0xac7a: "geolm" -0xac7b: "geolb" -0xac7c: "geols" -0xac7d: "geolt" -0xac7e: "geolp" -0xac7f: "geolh" -0xac80: "geom" -0xac81: "geob" -0xac82: "geobs" -0xac83: "geos" -0xac84: "geoss" -0xac85: "geong" -0xac86: "geoj" -0xac87: "geoc" -0xac88: "geok" -0xac89: "geot" -0xac8a: "geop" -0xac8b: "geoh" -0xac8c: "ge" -0xac8d: "geg" -0xac8e: "gegg" -0xac8f: "gegs" -0xac90: "gen" -0xac91: "genj" -0xac92: "genh" -0xac93: "ged" -0xac94: "gel" -0xac95: "gelg" -0xac96: "gelm" -0xac97: "gelb" -0xac98: "gels" -0xac99: "gelt" -0xac9a: "gelp" -0xac9b: "gelh" -0xac9c: "gem" -0xac9d: "geb" -0xac9e: "gebs" -0xac9f: "ges" -0xaca0: "gess" -0xaca1: "geng" -0xaca2: "gej" -0xaca3: "gec" -0xaca4: "gek" -0xaca5: "get" -0xaca6: "gep" -0xaca7: "geh" -0xaca8: "gyeo" -0xaca9: "gyeog" -0xacaa: "gyeogg" -0xacab: "gyeogs" -0xacac: "gyeon" -0xacad: "gyeonj" -0xacae: "gyeonh" -0xacaf: "gyeod" -0xacb0: "gyeol" -0xacb1: "gyeolg" -0xacb2: "gyeolm" -0xacb3: "gyeolb" -0xacb4: "gyeols" -0xacb5: "gyeolt" -0xacb6: "gyeolp" -0xacb7: "gyeolh" -0xacb8: "gyeom" -0xacb9: "gyeob" -0xacba: "gyeobs" -0xacbb: "gyeos" -0xacbc: "gyeoss" -0xacbd: "gyeong" -0xacbe: "gyeoj" -0xacbf: "gyeoc" -0xacc0: "gyeok" -0xacc1: "gyeot" -0xacc2: "gyeop" -0xacc3: "gyeoh" -0xacc4: "gye" -0xacc5: "gyeg" -0xacc6: "gyegg" -0xacc7: "gyegs" -0xacc8: "gyen" -0xacc9: "gyenj" -0xacca: "gyenh" -0xaccb: "gyed" -0xaccc: "gyel" -0xaccd: "gyelg" -0xacce: "gyelm" -0xaccf: "gyelb" -0xacd0: "gyels" -0xacd1: "gyelt" -0xacd2: "gyelp" -0xacd3: "gyelh" -0xacd4: "gyem" -0xacd5: "gyeb" -0xacd6: "gyebs" -0xacd7: "gyes" -0xacd8: "gyess" -0xacd9: "gyeng" -0xacda: "gyej" -0xacdb: "gyec" -0xacdc: "gyek" -0xacdd: "gyet" -0xacde: "gyep" -0xacdf: "gyeh" -0xace0: "go" -0xace1: "gog" -0xace2: "gogg" -0xace3: "gogs" -0xace4: "gon" -0xace5: "gonj" -0xace6: "gonh" -0xace7: "god" -0xace8: "gol" -0xace9: "golg" -0xacea: "golm" -0xaceb: "golb" -0xacec: "gols" -0xaced: "golt" -0xacee: "golp" -0xacef: "golh" -0xacf0: "gom" -0xacf1: "gob" -0xacf2: "gobs" -0xacf3: "gos" -0xacf4: "goss" -0xacf5: "gong" -0xacf6: "goj" -0xacf7: "goc" -0xacf8: "gok" -0xacf9: "got" -0xacfa: "gop" -0xacfb: "goh" -0xacfc: "gwa" -0xacfd: "gwag" -0xacfe: "gwagg" -0xacff: "gwags" -/* x0ad */ -0xad00: "gwan" -0xad01: "gwanj" -0xad02: "gwanh" -0xad03: "gwad" -0xad04: "gwal" -0xad05: "gwalg" -0xad06: "gwalm" -0xad07: "gwalb" -0xad08: "gwals" -0xad09: "gwalt" -0xad0a: "gwalp" -0xad0b: "gwalh" -0xad0c: "gwam" -0xad0d: "gwab" -0xad0e: "gwabs" -0xad0f: "gwas" -0xad10: "gwass" -0xad11: "gwang" -0xad12: "gwaj" -0xad13: "gwac" -0xad14: "gwak" -0xad15: "gwat" -0xad16: "gwap" -0xad17: "gwah" -0xad18: "gwae" -0xad19: "gwaeg" -0xad1a: "gwaegg" -0xad1b: "gwaegs" -0xad1c: "gwaen" -0xad1d: "gwaenj" -0xad1e: "gwaenh" -0xad1f: "gwaed" -0xad20: "gwael" -0xad21: "gwaelg" -0xad22: "gwaelm" -0xad23: "gwaelb" -0xad24: "gwaels" -0xad25: "gwaelt" -0xad26: "gwaelp" -0xad27: "gwaelh" -0xad28: "gwaem" -0xad29: "gwaeb" -0xad2a: "gwaebs" -0xad2b: "gwaes" -0xad2c: "gwaess" -0xad2d: "gwaeng" -0xad2e: "gwaej" -0xad2f: "gwaec" -0xad30: "gwaek" -0xad31: "gwaet" -0xad32: "gwaep" -0xad33: "gwaeh" -0xad34: "goe" -0xad35: "goeg" -0xad36: "goegg" -0xad37: "goegs" -0xad38: "goen" -0xad39: "goenj" -0xad3a: "goenh" -0xad3b: "goed" -0xad3c: "goel" -0xad3d: "goelg" -0xad3e: "goelm" -0xad3f: "goelb" -0xad40: "goels" -0xad41: "goelt" -0xad42: "goelp" -0xad43: "goelh" -0xad44: "goem" -0xad45: "goeb" -0xad46: "goebs" -0xad47: "goes" -0xad48: "goess" -0xad49: "goeng" -0xad4a: "goej" -0xad4b: "goec" -0xad4c: "goek" -0xad4d: "goet" -0xad4e: "goep" -0xad4f: "goeh" -0xad50: "gyo" -0xad51: "gyog" -0xad52: "gyogg" -0xad53: "gyogs" -0xad54: "gyon" -0xad55: "gyonj" -0xad56: "gyonh" -0xad57: "gyod" -0xad58: "gyol" -0xad59: "gyolg" -0xad5a: "gyolm" -0xad5b: "gyolb" -0xad5c: "gyols" -0xad5d: "gyolt" -0xad5e: "gyolp" -0xad5f: "gyolh" -0xad60: "gyom" -0xad61: "gyob" -0xad62: "gyobs" -0xad63: "gyos" -0xad64: "gyoss" -0xad65: "gyong" -0xad66: "gyoj" -0xad67: "gyoc" -0xad68: "gyok" -0xad69: "gyot" -0xad6a: "gyop" -0xad6b: "gyoh" -0xad6c: "gu" -0xad6d: "gug" -0xad6e: "gugg" -0xad6f: "gugs" -0xad70: "gun" -0xad71: "gunj" -0xad72: "gunh" -0xad73: "gud" -0xad74: "gul" -0xad75: "gulg" -0xad76: "gulm" -0xad77: "gulb" -0xad78: "guls" -0xad79: "gult" -0xad7a: "gulp" -0xad7b: "gulh" -0xad7c: "gum" -0xad7d: "gub" -0xad7e: "gubs" -0xad7f: "gus" -0xad80: "guss" -0xad81: "gung" -0xad82: "guj" -0xad83: "guc" -0xad84: "guk" -0xad85: "gut" -0xad86: "gup" -0xad87: "guh" -0xad88: "gweo" -0xad89: "gweog" -0xad8a: "gweogg" -0xad8b: "gweogs" -0xad8c: "gweon" -0xad8d: "gweonj" -0xad8e: "gweonh" -0xad8f: "gweod" -0xad90: "gweol" -0xad91: "gweolg" -0xad92: "gweolm" -0xad93: "gweolb" -0xad94: "gweols" -0xad95: "gweolt" -0xad96: "gweolp" -0xad97: "gweolh" -0xad98: "gweom" -0xad99: "gweob" -0xad9a: "gweobs" -0xad9b: "gweos" -0xad9c: "gweoss" -0xad9d: "gweong" -0xad9e: "gweoj" -0xad9f: "gweoc" -0xada0: "gweok" -0xada1: "gweot" -0xada2: "gweop" -0xada3: "gweoh" -0xada4: "gwe" -0xada5: "gweg" -0xada6: "gwegg" -0xada7: "gwegs" -0xada8: "gwen" -0xada9: "gwenj" -0xadaa: "gwenh" -0xadab: "gwed" -0xadac: "gwel" -0xadad: "gwelg" -0xadae: "gwelm" -0xadaf: "gwelb" -0xadb0: "gwels" -0xadb1: "gwelt" -0xadb2: "gwelp" -0xadb3: "gwelh" -0xadb4: "gwem" -0xadb5: "gweb" -0xadb6: "gwebs" -0xadb7: "gwes" -0xadb8: "gwess" -0xadb9: "gweng" -0xadba: "gwej" -0xadbb: "gwec" -0xadbc: "gwek" -0xadbd: "gwet" -0xadbe: "gwep" -0xadbf: "gweh" -0xadc0: "gwi" -0xadc1: "gwig" -0xadc2: "gwigg" -0xadc3: "gwigs" -0xadc4: "gwin" -0xadc5: "gwinj" -0xadc6: "gwinh" -0xadc7: "gwid" -0xadc8: "gwil" -0xadc9: "gwilg" -0xadca: "gwilm" -0xadcb: "gwilb" -0xadcc: "gwils" -0xadcd: "gwilt" -0xadce: "gwilp" -0xadcf: "gwilh" -0xadd0: "gwim" -0xadd1: "gwib" -0xadd2: "gwibs" -0xadd3: "gwis" -0xadd4: "gwiss" -0xadd5: "gwing" -0xadd6: "gwij" -0xadd7: "gwic" -0xadd8: "gwik" -0xadd9: "gwit" -0xadda: "gwip" -0xaddb: "gwih" -0xaddc: "gyu" -0xaddd: "gyug" -0xadde: "gyugg" -0xaddf: "gyugs" -0xade0: "gyun" -0xade1: "gyunj" -0xade2: "gyunh" -0xade3: "gyud" -0xade4: "gyul" -0xade5: "gyulg" -0xade6: "gyulm" -0xade7: "gyulb" -0xade8: "gyuls" -0xade9: "gyult" -0xadea: "gyulp" -0xadeb: "gyulh" -0xadec: "gyum" -0xaded: "gyub" -0xadee: "gyubs" -0xadef: "gyus" -0xadf0: "gyuss" -0xadf1: "gyung" -0xadf2: "gyuj" -0xadf3: "gyuc" -0xadf4: "gyuk" -0xadf5: "gyut" -0xadf6: "gyup" -0xadf7: "gyuh" -0xadf8: "geu" -0xadf9: "geug" -0xadfa: "geugg" -0xadfb: "geugs" -0xadfc: "geun" -0xadfd: "geunj" -0xadfe: "geunh" -0xadff: "geud" -/* x0ae */ -0xae00: "geul" -0xae01: "geulg" -0xae02: "geulm" -0xae03: "geulb" -0xae04: "geuls" -0xae05: "geult" -0xae06: "geulp" -0xae07: "geulh" -0xae08: "geum" -0xae09: "geub" -0xae0a: "geubs" -0xae0b: "geus" -0xae0c: "geuss" -0xae0d: "geung" -0xae0e: "geuj" -0xae0f: "geuc" -0xae10: "geuk" -0xae11: "geut" -0xae12: "geup" -0xae13: "geuh" -0xae14: "gyi" -0xae15: "gyig" -0xae16: "gyigg" -0xae17: "gyigs" -0xae18: "gyin" -0xae19: "gyinj" -0xae1a: "gyinh" -0xae1b: "gyid" -0xae1c: "gyil" -0xae1d: "gyilg" -0xae1e: "gyilm" -0xae1f: "gyilb" -0xae20: "gyils" -0xae21: "gyilt" -0xae22: "gyilp" -0xae23: "gyilh" -0xae24: "gyim" -0xae25: "gyib" -0xae26: "gyibs" -0xae27: "gyis" -0xae28: "gyiss" -0xae29: "gying" -0xae2a: "gyij" -0xae2b: "gyic" -0xae2c: "gyik" -0xae2d: "gyit" -0xae2e: "gyip" -0xae2f: "gyih" -0xae30: "gi" -0xae31: "gig" -0xae32: "gigg" -0xae33: "gigs" -0xae34: "gin" -0xae35: "ginj" -0xae36: "ginh" -0xae37: "gid" -0xae38: "gil" -0xae39: "gilg" -0xae3a: "gilm" -0xae3b: "gilb" -0xae3c: "gils" -0xae3d: "gilt" -0xae3e: "gilp" -0xae3f: "gilh" -0xae40: "gim" -0xae41: "gib" -0xae42: "gibs" -0xae43: "gis" -0xae44: "giss" -0xae45: "ging" -0xae46: "gij" -0xae47: "gic" -0xae48: "gik" -0xae49: "git" -0xae4a: "gip" -0xae4b: "gih" -0xae4c: "gga" -0xae4d: "ggag" -0xae4e: "ggagg" -0xae4f: "ggags" -0xae50: "ggan" -0xae51: "gganj" -0xae52: "gganh" -0xae53: "ggad" -0xae54: "ggal" -0xae55: "ggalg" -0xae56: "ggalm" -0xae57: "ggalb" -0xae58: "ggals" -0xae59: "ggalt" -0xae5a: "ggalp" -0xae5b: "ggalh" -0xae5c: "ggam" -0xae5d: "ggab" -0xae5e: "ggabs" -0xae5f: "ggas" -0xae60: "ggass" -0xae61: "ggang" -0xae62: "ggaj" -0xae63: "ggac" -0xae64: "ggak" -0xae65: "ggat" -0xae66: "ggap" -0xae67: "ggah" -0xae68: "ggae" -0xae69: "ggaeg" -0xae6a: "ggaegg" -0xae6b: "ggaegs" -0xae6c: "ggaen" -0xae6d: "ggaenj" -0xae6e: "ggaenh" -0xae6f: "ggaed" -0xae70: "ggael" -0xae71: "ggaelg" -0xae72: "ggaelm" -0xae73: "ggaelb" -0xae74: "ggaels" -0xae75: "ggaelt" -0xae76: "ggaelp" -0xae77: "ggaelh" -0xae78: "ggaem" -0xae79: "ggaeb" -0xae7a: "ggaebs" -0xae7b: "ggaes" -0xae7c: "ggaess" -0xae7d: "ggaeng" -0xae7e: "ggaej" -0xae7f: "ggaec" -0xae80: "ggaek" -0xae81: "ggaet" -0xae82: "ggaep" -0xae83: "ggaeh" -0xae84: "ggya" -0xae85: "ggyag" -0xae86: "ggyagg" -0xae87: "ggyags" -0xae88: "ggyan" -0xae89: "ggyanj" -0xae8a: "ggyanh" -0xae8b: "ggyad" -0xae8c: "ggyal" -0xae8d: "ggyalg" -0xae8e: "ggyalm" -0xae8f: "ggyalb" -0xae90: "ggyals" -0xae91: "ggyalt" -0xae92: "ggyalp" -0xae93: "ggyalh" -0xae94: "ggyam" -0xae95: "ggyab" -0xae96: "ggyabs" -0xae97: "ggyas" -0xae98: "ggyass" -0xae99: "ggyang" -0xae9a: "ggyaj" -0xae9b: "ggyac" -0xae9c: "ggyak" -0xae9d: "ggyat" -0xae9e: "ggyap" -0xae9f: "ggyah" -0xaea0: "ggyae" -0xaea1: "ggyaeg" -0xaea2: "ggyaegg" -0xaea3: "ggyaegs" -0xaea4: "ggyaen" -0xaea5: "ggyaenj" -0xaea6: "ggyaenh" -0xaea7: "ggyaed" -0xaea8: "ggyael" -0xaea9: "ggyaelg" -0xaeaa: "ggyaelm" -0xaeab: "ggyaelb" -0xaeac: "ggyaels" -0xaead: "ggyaelt" -0xaeae: "ggyaelp" -0xaeaf: "ggyaelh" -0xaeb0: "ggyaem" -0xaeb1: "ggyaeb" -0xaeb2: "ggyaebs" -0xaeb3: "ggyaes" -0xaeb4: "ggyaess" -0xaeb5: "ggyaeng" -0xaeb6: "ggyaej" -0xaeb7: "ggyaec" -0xaeb8: "ggyaek" -0xaeb9: "ggyaet" -0xaeba: "ggyaep" -0xaebb: "ggyaeh" -0xaebc: "ggeo" -0xaebd: "ggeog" -0xaebe: "ggeogg" -0xaebf: "ggeogs" -0xaec0: "ggeon" -0xaec1: "ggeonj" -0xaec2: "ggeonh" -0xaec3: "ggeod" -0xaec4: "ggeol" -0xaec5: "ggeolg" -0xaec6: "ggeolm" -0xaec7: "ggeolb" -0xaec8: "ggeols" -0xaec9: "ggeolt" -0xaeca: "ggeolp" -0xaecb: "ggeolh" -0xaecc: "ggeom" -0xaecd: "ggeob" -0xaece: "ggeobs" -0xaecf: "ggeos" -0xaed0: "ggeoss" -0xaed1: "ggeong" -0xaed2: "ggeoj" -0xaed3: "ggeoc" -0xaed4: "ggeok" -0xaed5: "ggeot" -0xaed6: "ggeop" -0xaed7: "ggeoh" -0xaed8: "gge" -0xaed9: "ggeg" -0xaeda: "ggegg" -0xaedb: "ggegs" -0xaedc: "ggen" -0xaedd: "ggenj" -0xaede: "ggenh" -0xaedf: "gged" -0xaee0: "ggel" -0xaee1: "ggelg" -0xaee2: "ggelm" -0xaee3: "ggelb" -0xaee4: "ggels" -0xaee5: "ggelt" -0xaee6: "ggelp" -0xaee7: "ggelh" -0xaee8: "ggem" -0xaee9: "ggeb" -0xaeea: "ggebs" -0xaeeb: "gges" -0xaeec: "ggess" -0xaeed: "ggeng" -0xaeee: "ggej" -0xaeef: "ggec" -0xaef0: "ggek" -0xaef1: "gget" -0xaef2: "ggep" -0xaef3: "ggeh" -0xaef4: "ggyeo" -0xaef5: "ggyeog" -0xaef6: "ggyeogg" -0xaef7: "ggyeogs" -0xaef8: "ggyeon" -0xaef9: "ggyeonj" -0xaefa: "ggyeonh" -0xaefb: "ggyeod" -0xaefc: "ggyeol" -0xaefd: "ggyeolg" -0xaefe: "ggyeolm" -0xaeff: "ggyeolb" -/* x0af */ -0xaf00: "ggyeols" -0xaf01: "ggyeolt" -0xaf02: "ggyeolp" -0xaf03: "ggyeolh" -0xaf04: "ggyeom" -0xaf05: "ggyeob" -0xaf06: "ggyeobs" -0xaf07: "ggyeos" -0xaf08: "ggyeoss" -0xaf09: "ggyeong" -0xaf0a: "ggyeoj" -0xaf0b: "ggyeoc" -0xaf0c: "ggyeok" -0xaf0d: "ggyeot" -0xaf0e: "ggyeop" -0xaf0f: "ggyeoh" -0xaf10: "ggye" -0xaf11: "ggyeg" -0xaf12: "ggyegg" -0xaf13: "ggyegs" -0xaf14: "ggyen" -0xaf15: "ggyenj" -0xaf16: "ggyenh" -0xaf17: "ggyed" -0xaf18: "ggyel" -0xaf19: "ggyelg" -0xaf1a: "ggyelm" -0xaf1b: "ggyelb" -0xaf1c: "ggyels" -0xaf1d: "ggyelt" -0xaf1e: "ggyelp" -0xaf1f: "ggyelh" -0xaf20: "ggyem" -0xaf21: "ggyeb" -0xaf22: "ggyebs" -0xaf23: "ggyes" -0xaf24: "ggyess" -0xaf25: "ggyeng" -0xaf26: "ggyej" -0xaf27: "ggyec" -0xaf28: "ggyek" -0xaf29: "ggyet" -0xaf2a: "ggyep" -0xaf2b: "ggyeh" -0xaf2c: "ggo" -0xaf2d: "ggog" -0xaf2e: "ggogg" -0xaf2f: "ggogs" -0xaf30: "ggon" -0xaf31: "ggonj" -0xaf32: "ggonh" -0xaf33: "ggod" -0xaf34: "ggol" -0xaf35: "ggolg" -0xaf36: "ggolm" -0xaf37: "ggolb" -0xaf38: "ggols" -0xaf39: "ggolt" -0xaf3a: "ggolp" -0xaf3b: "ggolh" -0xaf3c: "ggom" -0xaf3d: "ggob" -0xaf3e: "ggobs" -0xaf3f: "ggos" -0xaf40: "ggoss" -0xaf41: "ggong" -0xaf42: "ggoj" -0xaf43: "ggoc" -0xaf44: "ggok" -0xaf45: "ggot" -0xaf46: "ggop" -0xaf47: "ggoh" -0xaf48: "ggwa" -0xaf49: "ggwag" -0xaf4a: "ggwagg" -0xaf4b: "ggwags" -0xaf4c: "ggwan" -0xaf4d: "ggwanj" -0xaf4e: "ggwanh" -0xaf4f: "ggwad" -0xaf50: "ggwal" -0xaf51: "ggwalg" -0xaf52: "ggwalm" -0xaf53: "ggwalb" -0xaf54: "ggwals" -0xaf55: "ggwalt" -0xaf56: "ggwalp" -0xaf57: "ggwalh" -0xaf58: "ggwam" -0xaf59: "ggwab" -0xaf5a: "ggwabs" -0xaf5b: "ggwas" -0xaf5c: "ggwass" -0xaf5d: "ggwang" -0xaf5e: "ggwaj" -0xaf5f: "ggwac" -0xaf60: "ggwak" -0xaf61: "ggwat" -0xaf62: "ggwap" -0xaf63: "ggwah" -0xaf64: "ggwae" -0xaf65: "ggwaeg" -0xaf66: "ggwaegg" -0xaf67: "ggwaegs" -0xaf68: "ggwaen" -0xaf69: "ggwaenj" -0xaf6a: "ggwaenh" -0xaf6b: "ggwaed" -0xaf6c: "ggwael" -0xaf6d: "ggwaelg" -0xaf6e: "ggwaelm" -0xaf6f: "ggwaelb" -0xaf70: "ggwaels" -0xaf71: "ggwaelt" -0xaf72: "ggwaelp" -0xaf73: "ggwaelh" -0xaf74: "ggwaem" -0xaf75: "ggwaeb" -0xaf76: "ggwaebs" -0xaf77: "ggwaes" -0xaf78: "ggwaess" -0xaf79: "ggwaeng" -0xaf7a: "ggwaej" -0xaf7b: "ggwaec" -0xaf7c: "ggwaek" -0xaf7d: "ggwaet" -0xaf7e: "ggwaep" -0xaf7f: "ggwaeh" -0xaf80: "ggoe" -0xaf81: "ggoeg" -0xaf82: "ggoegg" -0xaf83: "ggoegs" -0xaf84: "ggoen" -0xaf85: "ggoenj" -0xaf86: "ggoenh" -0xaf87: "ggoed" -0xaf88: "ggoel" -0xaf89: "ggoelg" -0xaf8a: "ggoelm" -0xaf8b: "ggoelb" -0xaf8c: "ggoels" -0xaf8d: "ggoelt" -0xaf8e: "ggoelp" -0xaf8f: "ggoelh" -0xaf90: "ggoem" -0xaf91: "ggoeb" -0xaf92: "ggoebs" -0xaf93: "ggoes" -0xaf94: "ggoess" -0xaf95: "ggoeng" -0xaf96: "ggoej" -0xaf97: "ggoec" -0xaf98: "ggoek" -0xaf99: "ggoet" -0xaf9a: "ggoep" -0xaf9b: "ggoeh" -0xaf9c: "ggyo" -0xaf9d: "ggyog" -0xaf9e: "ggyogg" -0xaf9f: "ggyogs" -0xafa0: "ggyon" -0xafa1: "ggyonj" -0xafa2: "ggyonh" -0xafa3: "ggyod" -0xafa4: "ggyol" -0xafa5: "ggyolg" -0xafa6: "ggyolm" -0xafa7: "ggyolb" -0xafa8: "ggyols" -0xafa9: "ggyolt" -0xafaa: "ggyolp" -0xafab: "ggyolh" -0xafac: "ggyom" -0xafad: "ggyob" -0xafae: "ggyobs" -0xafaf: "ggyos" -0xafb0: "ggyoss" -0xafb1: "ggyong" -0xafb2: "ggyoj" -0xafb3: "ggyoc" -0xafb4: "ggyok" -0xafb5: "ggyot" -0xafb6: "ggyop" -0xafb7: "ggyoh" -0xafb8: "ggu" -0xafb9: "ggug" -0xafba: "ggugg" -0xafbb: "ggugs" -0xafbc: "ggun" -0xafbd: "ggunj" -0xafbe: "ggunh" -0xafbf: "ggud" -0xafc0: "ggul" -0xafc1: "ggulg" -0xafc2: "ggulm" -0xafc3: "ggulb" -0xafc4: "gguls" -0xafc5: "ggult" -0xafc6: "ggulp" -0xafc7: "ggulh" -0xafc8: "ggum" -0xafc9: "ggub" -0xafca: "ggubs" -0xafcb: "ggus" -0xafcc: "gguss" -0xafcd: "ggung" -0xafce: "gguj" -0xafcf: "gguc" -0xafd0: "gguk" -0xafd1: "ggut" -0xafd2: "ggup" -0xafd3: "gguh" -0xafd4: "ggweo" -0xafd5: "ggweog" -0xafd6: "ggweogg" -0xafd7: "ggweogs" -0xafd8: "ggweon" -0xafd9: "ggweonj" -0xafda: "ggweonh" -0xafdb: "ggweod" -0xafdc: "ggweol" -0xafdd: "ggweolg" -0xafde: "ggweolm" -0xafdf: "ggweolb" -0xafe0: "ggweols" -0xafe1: "ggweolt" -0xafe2: "ggweolp" -0xafe3: "ggweolh" -0xafe4: "ggweom" -0xafe5: "ggweob" -0xafe6: "ggweobs" -0xafe7: "ggweos" -0xafe8: "ggweoss" -0xafe9: "ggweong" -0xafea: "ggweoj" -0xafeb: "ggweoc" -0xafec: "ggweok" -0xafed: "ggweot" -0xafee: "ggweop" -0xafef: "ggweoh" -0xaff0: "ggwe" -0xaff1: "ggweg" -0xaff2: "ggwegg" -0xaff3: "ggwegs" -0xaff4: "ggwen" -0xaff5: "ggwenj" -0xaff6: "ggwenh" -0xaff7: "ggwed" -0xaff8: "ggwel" -0xaff9: "ggwelg" -0xaffa: "ggwelm" -0xaffb: "ggwelb" -0xaffc: "ggwels" -0xaffd: "ggwelt" -0xaffe: "ggwelp" -0xafff: "ggwelh" -/* x0b0 */ -0xb000: "ggwem" -0xb001: "ggweb" -0xb002: "ggwebs" -0xb003: "ggwes" -0xb004: "ggwess" -0xb005: "ggweng" -0xb006: "ggwej" -0xb007: "ggwec" -0xb008: "ggwek" -0xb009: "ggwet" -0xb00a: "ggwep" -0xb00b: "ggweh" -0xb00c: "ggwi" -0xb00d: "ggwig" -0xb00e: "ggwigg" -0xb00f: "ggwigs" -0xb010: "ggwin" -0xb011: "ggwinj" -0xb012: "ggwinh" -0xb013: "ggwid" -0xb014: "ggwil" -0xb015: "ggwilg" -0xb016: "ggwilm" -0xb017: "ggwilb" -0xb018: "ggwils" -0xb019: "ggwilt" -0xb01a: "ggwilp" -0xb01b: "ggwilh" -0xb01c: "ggwim" -0xb01d: "ggwib" -0xb01e: "ggwibs" -0xb01f: "ggwis" -0xb020: "ggwiss" -0xb021: "ggwing" -0xb022: "ggwij" -0xb023: "ggwic" -0xb024: "ggwik" -0xb025: "ggwit" -0xb026: "ggwip" -0xb027: "ggwih" -0xb028: "ggyu" -0xb029: "ggyug" -0xb02a: "ggyugg" -0xb02b: "ggyugs" -0xb02c: "ggyun" -0xb02d: "ggyunj" -0xb02e: "ggyunh" -0xb02f: "ggyud" -0xb030: "ggyul" -0xb031: "ggyulg" -0xb032: "ggyulm" -0xb033: "ggyulb" -0xb034: "ggyuls" -0xb035: "ggyult" -0xb036: "ggyulp" -0xb037: "ggyulh" -0xb038: "ggyum" -0xb039: "ggyub" -0xb03a: "ggyubs" -0xb03b: "ggyus" -0xb03c: "ggyuss" -0xb03d: "ggyung" -0xb03e: "ggyuj" -0xb03f: "ggyuc" -0xb040: "ggyuk" -0xb041: "ggyut" -0xb042: "ggyup" -0xb043: "ggyuh" -0xb044: "ggeu" -0xb045: "ggeug" -0xb046: "ggeugg" -0xb047: "ggeugs" -0xb048: "ggeun" -0xb049: "ggeunj" -0xb04a: "ggeunh" -0xb04b: "ggeud" -0xb04c: "ggeul" -0xb04d: "ggeulg" -0xb04e: "ggeulm" -0xb04f: "ggeulb" -0xb050: "ggeuls" -0xb051: "ggeult" -0xb052: "ggeulp" -0xb053: "ggeulh" -0xb054: "ggeum" -0xb055: "ggeub" -0xb056: "ggeubs" -0xb057: "ggeus" -0xb058: "ggeuss" -0xb059: "ggeung" -0xb05a: "ggeuj" -0xb05b: "ggeuc" -0xb05c: "ggeuk" -0xb05d: "ggeut" -0xb05e: "ggeup" -0xb05f: "ggeuh" -0xb060: "ggyi" -0xb061: "ggyig" -0xb062: "ggyigg" -0xb063: "ggyigs" -0xb064: "ggyin" -0xb065: "ggyinj" -0xb066: "ggyinh" -0xb067: "ggyid" -0xb068: "ggyil" -0xb069: "ggyilg" -0xb06a: "ggyilm" -0xb06b: "ggyilb" -0xb06c: "ggyils" -0xb06d: "ggyilt" -0xb06e: "ggyilp" -0xb06f: "ggyilh" -0xb070: "ggyim" -0xb071: "ggyib" -0xb072: "ggyibs" -0xb073: "ggyis" -0xb074: "ggyiss" -0xb075: "ggying" -0xb076: "ggyij" -0xb077: "ggyic" -0xb078: "ggyik" -0xb079: "ggyit" -0xb07a: "ggyip" -0xb07b: "ggyih" -0xb07c: "ggi" -0xb07d: "ggig" -0xb07e: "ggigg" -0xb07f: "ggigs" -0xb080: "ggin" -0xb081: "gginj" -0xb082: "gginh" -0xb083: "ggid" -0xb084: "ggil" -0xb085: "ggilg" -0xb086: "ggilm" -0xb087: "ggilb" -0xb088: "ggils" -0xb089: "ggilt" -0xb08a: "ggilp" -0xb08b: "ggilh" -0xb08c: "ggim" -0xb08d: "ggib" -0xb08e: "ggibs" -0xb08f: "ggis" -0xb090: "ggiss" -0xb091: "gging" -0xb092: "ggij" -0xb093: "ggic" -0xb094: "ggik" -0xb095: "ggit" -0xb096: "ggip" -0xb097: "ggih" -0xb098: "na" -0xb099: "nag" -0xb09a: "nagg" -0xb09b: "nags" -0xb09c: "nan" -0xb09d: "nanj" -0xb09e: "nanh" -0xb09f: "nad" -0xb0a0: "nal" -0xb0a1: "nalg" -0xb0a2: "nalm" -0xb0a3: "nalb" -0xb0a4: "nals" -0xb0a5: "nalt" -0xb0a6: "nalp" -0xb0a7: "nalh" -0xb0a8: "nam" -0xb0a9: "nab" -0xb0aa: "nabs" -0xb0ab: "nas" -0xb0ac: "nass" -0xb0ad: "nang" -0xb0ae: "naj" -0xb0af: "nac" -0xb0b0: "nak" -0xb0b1: "nat" -0xb0b2: "nap" -0xb0b3: "nah" -0xb0b4: "nae" -0xb0b5: "naeg" -0xb0b6: "naegg" -0xb0b7: "naegs" -0xb0b8: "naen" -0xb0b9: "naenj" -0xb0ba: "naenh" -0xb0bb: "naed" -0xb0bc: "nael" -0xb0bd: "naelg" -0xb0be: "naelm" -0xb0bf: "naelb" -0xb0c0: "naels" -0xb0c1: "naelt" -0xb0c2: "naelp" -0xb0c3: "naelh" -0xb0c4: "naem" -0xb0c5: "naeb" -0xb0c6: "naebs" -0xb0c7: "naes" -0xb0c8: "naess" -0xb0c9: "naeng" -0xb0ca: "naej" -0xb0cb: "naec" -0xb0cc: "naek" -0xb0cd: "naet" -0xb0ce: "naep" -0xb0cf: "naeh" -0xb0d0: "nya" -0xb0d1: "nyag" -0xb0d2: "nyagg" -0xb0d3: "nyags" -0xb0d4: "nyan" -0xb0d5: "nyanj" -0xb0d6: "nyanh" -0xb0d7: "nyad" -0xb0d8: "nyal" -0xb0d9: "nyalg" -0xb0da: "nyalm" -0xb0db: "nyalb" -0xb0dc: "nyals" -0xb0dd: "nyalt" -0xb0de: "nyalp" -0xb0df: "nyalh" -0xb0e0: "nyam" -0xb0e1: "nyab" -0xb0e2: "nyabs" -0xb0e3: "nyas" -0xb0e4: "nyass" -0xb0e5: "nyang" -0xb0e6: "nyaj" -0xb0e7: "nyac" -0xb0e8: "nyak" -0xb0e9: "nyat" -0xb0ea: "nyap" -0xb0eb: "nyah" -0xb0ec: "nyae" -0xb0ed: "nyaeg" -0xb0ee: "nyaegg" -0xb0ef: "nyaegs" -0xb0f0: "nyaen" -0xb0f1: "nyaenj" -0xb0f2: "nyaenh" -0xb0f3: "nyaed" -0xb0f4: "nyael" -0xb0f5: "nyaelg" -0xb0f6: "nyaelm" -0xb0f7: "nyaelb" -0xb0f8: "nyaels" -0xb0f9: "nyaelt" -0xb0fa: "nyaelp" -0xb0fb: "nyaelh" -0xb0fc: "nyaem" -0xb0fd: "nyaeb" -0xb0fe: "nyaebs" -0xb0ff: "nyaes" -/* x0b1 */ -0xb100: "nyaess" -0xb101: "nyaeng" -0xb102: "nyaej" -0xb103: "nyaec" -0xb104: "nyaek" -0xb105: "nyaet" -0xb106: "nyaep" -0xb107: "nyaeh" -0xb108: "neo" -0xb109: "neog" -0xb10a: "neogg" -0xb10b: "neogs" -0xb10c: "neon" -0xb10d: "neonj" -0xb10e: "neonh" -0xb10f: "neod" -0xb110: "neol" -0xb111: "neolg" -0xb112: "neolm" -0xb113: "neolb" -0xb114: "neols" -0xb115: "neolt" -0xb116: "neolp" -0xb117: "neolh" -0xb118: "neom" -0xb119: "neob" -0xb11a: "neobs" -0xb11b: "neos" -0xb11c: "neoss" -0xb11d: "neong" -0xb11e: "neoj" -0xb11f: "neoc" -0xb120: "neok" -0xb121: "neot" -0xb122: "neop" -0xb123: "neoh" -0xb124: "ne" -0xb125: "neg" -0xb126: "negg" -0xb127: "negs" -0xb128: "nen" -0xb129: "nenj" -0xb12a: "nenh" -0xb12b: "ned" -0xb12c: "nel" -0xb12d: "nelg" -0xb12e: "nelm" -0xb12f: "nelb" -0xb130: "nels" -0xb131: "nelt" -0xb132: "nelp" -0xb133: "nelh" -0xb134: "nem" -0xb135: "neb" -0xb136: "nebs" -0xb137: "nes" -0xb138: "ness" -0xb139: "neng" -0xb13a: "nej" -0xb13b: "nec" -0xb13c: "nek" -0xb13d: "net" -0xb13e: "nep" -0xb13f: "neh" -0xb140: "nyeo" -0xb141: "nyeog" -0xb142: "nyeogg" -0xb143: "nyeogs" -0xb144: "nyeon" -0xb145: "nyeonj" -0xb146: "nyeonh" -0xb147: "nyeod" -0xb148: "nyeol" -0xb149: "nyeolg" -0xb14a: "nyeolm" -0xb14b: "nyeolb" -0xb14c: "nyeols" -0xb14d: "nyeolt" -0xb14e: "nyeolp" -0xb14f: "nyeolh" -0xb150: "nyeom" -0xb151: "nyeob" -0xb152: "nyeobs" -0xb153: "nyeos" -0xb154: "nyeoss" -0xb155: "nyeong" -0xb156: "nyeoj" -0xb157: "nyeoc" -0xb158: "nyeok" -0xb159: "nyeot" -0xb15a: "nyeop" -0xb15b: "nyeoh" -0xb15c: "nye" -0xb15d: "nyeg" -0xb15e: "nyegg" -0xb15f: "nyegs" -0xb160: "nyen" -0xb161: "nyenj" -0xb162: "nyenh" -0xb163: "nyed" -0xb164: "nyel" -0xb165: "nyelg" -0xb166: "nyelm" -0xb167: "nyelb" -0xb168: "nyels" -0xb169: "nyelt" -0xb16a: "nyelp" -0xb16b: "nyelh" -0xb16c: "nyem" -0xb16d: "nyeb" -0xb16e: "nyebs" -0xb16f: "nyes" -0xb170: "nyess" -0xb171: "nyeng" -0xb172: "nyej" -0xb173: "nyec" -0xb174: "nyek" -0xb175: "nyet" -0xb176: "nyep" -0xb177: "nyeh" -0xb178: "no" -0xb179: "nog" -0xb17a: "nogg" -0xb17b: "nogs" -0xb17c: "non" -0xb17d: "nonj" -0xb17e: "nonh" -0xb17f: "nod" -0xb180: "nol" -0xb181: "nolg" -0xb182: "nolm" -0xb183: "nolb" -0xb184: "nols" -0xb185: "nolt" -0xb186: "nolp" -0xb187: "nolh" -0xb188: "nom" -0xb189: "nob" -0xb18a: "nobs" -0xb18b: "nos" -0xb18c: "noss" -0xb18d: "nong" -0xb18e: "noj" -0xb18f: "noc" -0xb190: "nok" -0xb191: "not" -0xb192: "nop" -0xb193: "noh" -0xb194: "nwa" -0xb195: "nwag" -0xb196: "nwagg" -0xb197: "nwags" -0xb198: "nwan" -0xb199: "nwanj" -0xb19a: "nwanh" -0xb19b: "nwad" -0xb19c: "nwal" -0xb19d: "nwalg" -0xb19e: "nwalm" -0xb19f: "nwalb" -0xb1a0: "nwals" -0xb1a1: "nwalt" -0xb1a2: "nwalp" -0xb1a3: "nwalh" -0xb1a4: "nwam" -0xb1a5: "nwab" -0xb1a6: "nwabs" -0xb1a7: "nwas" -0xb1a8: "nwass" -0xb1a9: "nwang" -0xb1aa: "nwaj" -0xb1ab: "nwac" -0xb1ac: "nwak" -0xb1ad: "nwat" -0xb1ae: "nwap" -0xb1af: "nwah" -0xb1b0: "nwae" -0xb1b1: "nwaeg" -0xb1b2: "nwaegg" -0xb1b3: "nwaegs" -0xb1b4: "nwaen" -0xb1b5: "nwaenj" -0xb1b6: "nwaenh" -0xb1b7: "nwaed" -0xb1b8: "nwael" -0xb1b9: "nwaelg" -0xb1ba: "nwaelm" -0xb1bb: "nwaelb" -0xb1bc: "nwaels" -0xb1bd: "nwaelt" -0xb1be: "nwaelp" -0xb1bf: "nwaelh" -0xb1c0: "nwaem" -0xb1c1: "nwaeb" -0xb1c2: "nwaebs" -0xb1c3: "nwaes" -0xb1c4: "nwaess" -0xb1c5: "nwaeng" -0xb1c6: "nwaej" -0xb1c7: "nwaec" -0xb1c8: "nwaek" -0xb1c9: "nwaet" -0xb1ca: "nwaep" -0xb1cb: "nwaeh" -0xb1cc: "noe" -0xb1cd: "noeg" -0xb1ce: "noegg" -0xb1cf: "noegs" -0xb1d0: "noen" -0xb1d1: "noenj" -0xb1d2: "noenh" -0xb1d3: "noed" -0xb1d4: "noel" -0xb1d5: "noelg" -0xb1d6: "noelm" -0xb1d7: "noelb" -0xb1d8: "noels" -0xb1d9: "noelt" -0xb1da: "noelp" -0xb1db: "noelh" -0xb1dc: "noem" -0xb1dd: "noeb" -0xb1de: "noebs" -0xb1df: "noes" -0xb1e0: "noess" -0xb1e1: "noeng" -0xb1e2: "noej" -0xb1e3: "noec" -0xb1e4: "noek" -0xb1e5: "noet" -0xb1e6: "noep" -0xb1e7: "noeh" -0xb1e8: "nyo" -0xb1e9: "nyog" -0xb1ea: "nyogg" -0xb1eb: "nyogs" -0xb1ec: "nyon" -0xb1ed: "nyonj" -0xb1ee: "nyonh" -0xb1ef: "nyod" -0xb1f0: "nyol" -0xb1f1: "nyolg" -0xb1f2: "nyolm" -0xb1f3: "nyolb" -0xb1f4: "nyols" -0xb1f5: "nyolt" -0xb1f6: "nyolp" -0xb1f7: "nyolh" -0xb1f8: "nyom" -0xb1f9: "nyob" -0xb1fa: "nyobs" -0xb1fb: "nyos" -0xb1fc: "nyoss" -0xb1fd: "nyong" -0xb1fe: "nyoj" -0xb1ff: "nyoc" -/* x0b2 */ -0xb200: "nyok" -0xb201: "nyot" -0xb202: "nyop" -0xb203: "nyoh" -0xb204: "nu" -0xb205: "nug" -0xb206: "nugg" -0xb207: "nugs" -0xb208: "nun" -0xb209: "nunj" -0xb20a: "nunh" -0xb20b: "nud" -0xb20c: "nul" -0xb20d: "nulg" -0xb20e: "nulm" -0xb20f: "nulb" -0xb210: "nuls" -0xb211: "nult" -0xb212: "nulp" -0xb213: "nulh" -0xb214: "num" -0xb215: "nub" -0xb216: "nubs" -0xb217: "nus" -0xb218: "nuss" -0xb219: "nung" -0xb21a: "nuj" -0xb21b: "nuc" -0xb21c: "nuk" -0xb21d: "nut" -0xb21e: "nup" -0xb21f: "nuh" -0xb220: "nweo" -0xb221: "nweog" -0xb222: "nweogg" -0xb223: "nweogs" -0xb224: "nweon" -0xb225: "nweonj" -0xb226: "nweonh" -0xb227: "nweod" -0xb228: "nweol" -0xb229: "nweolg" -0xb22a: "nweolm" -0xb22b: "nweolb" -0xb22c: "nweols" -0xb22d: "nweolt" -0xb22e: "nweolp" -0xb22f: "nweolh" -0xb230: "nweom" -0xb231: "nweob" -0xb232: "nweobs" -0xb233: "nweos" -0xb234: "nweoss" -0xb235: "nweong" -0xb236: "nweoj" -0xb237: "nweoc" -0xb238: "nweok" -0xb239: "nweot" -0xb23a: "nweop" -0xb23b: "nweoh" -0xb23c: "nwe" -0xb23d: "nweg" -0xb23e: "nwegg" -0xb23f: "nwegs" -0xb240: "nwen" -0xb241: "nwenj" -0xb242: "nwenh" -0xb243: "nwed" -0xb244: "nwel" -0xb245: "nwelg" -0xb246: "nwelm" -0xb247: "nwelb" -0xb248: "nwels" -0xb249: "nwelt" -0xb24a: "nwelp" -0xb24b: "nwelh" -0xb24c: "nwem" -0xb24d: "nweb" -0xb24e: "nwebs" -0xb24f: "nwes" -0xb250: "nwess" -0xb251: "nweng" -0xb252: "nwej" -0xb253: "nwec" -0xb254: "nwek" -0xb255: "nwet" -0xb256: "nwep" -0xb257: "nweh" -0xb258: "nwi" -0xb259: "nwig" -0xb25a: "nwigg" -0xb25b: "nwigs" -0xb25c: "nwin" -0xb25d: "nwinj" -0xb25e: "nwinh" -0xb25f: "nwid" -0xb260: "nwil" -0xb261: "nwilg" -0xb262: "nwilm" -0xb263: "nwilb" -0xb264: "nwils" -0xb265: "nwilt" -0xb266: "nwilp" -0xb267: "nwilh" -0xb268: "nwim" -0xb269: "nwib" -0xb26a: "nwibs" -0xb26b: "nwis" -0xb26c: "nwiss" -0xb26d: "nwing" -0xb26e: "nwij" -0xb26f: "nwic" -0xb270: "nwik" -0xb271: "nwit" -0xb272: "nwip" -0xb273: "nwih" -0xb274: "nyu" -0xb275: "nyug" -0xb276: "nyugg" -0xb277: "nyugs" -0xb278: "nyun" -0xb279: "nyunj" -0xb27a: "nyunh" -0xb27b: "nyud" -0xb27c: "nyul" -0xb27d: "nyulg" -0xb27e: "nyulm" -0xb27f: "nyulb" -0xb280: "nyuls" -0xb281: "nyult" -0xb282: "nyulp" -0xb283: "nyulh" -0xb284: "nyum" -0xb285: "nyub" -0xb286: "nyubs" -0xb287: "nyus" -0xb288: "nyuss" -0xb289: "nyung" -0xb28a: "nyuj" -0xb28b: "nyuc" -0xb28c: "nyuk" -0xb28d: "nyut" -0xb28e: "nyup" -0xb28f: "nyuh" -0xb290: "neu" -0xb291: "neug" -0xb292: "neugg" -0xb293: "neugs" -0xb294: "neun" -0xb295: "neunj" -0xb296: "neunh" -0xb297: "neud" -0xb298: "neul" -0xb299: "neulg" -0xb29a: "neulm" -0xb29b: "neulb" -0xb29c: "neuls" -0xb29d: "neult" -0xb29e: "neulp" -0xb29f: "neulh" -0xb2a0: "neum" -0xb2a1: "neub" -0xb2a2: "neubs" -0xb2a3: "neus" -0xb2a4: "neuss" -0xb2a5: "neung" -0xb2a6: "neuj" -0xb2a7: "neuc" -0xb2a8: "neuk" -0xb2a9: "neut" -0xb2aa: "neup" -0xb2ab: "neuh" -0xb2ac: "nyi" -0xb2ad: "nyig" -0xb2ae: "nyigg" -0xb2af: "nyigs" -0xb2b0: "nyin" -0xb2b1: "nyinj" -0xb2b2: "nyinh" -0xb2b3: "nyid" -0xb2b4: "nyil" -0xb2b5: "nyilg" -0xb2b6: "nyilm" -0xb2b7: "nyilb" -0xb2b8: "nyils" -0xb2b9: "nyilt" -0xb2ba: "nyilp" -0xb2bb: "nyilh" -0xb2bc: "nyim" -0xb2bd: "nyib" -0xb2be: "nyibs" -0xb2bf: "nyis" -0xb2c0: "nyiss" -0xb2c1: "nying" -0xb2c2: "nyij" -0xb2c3: "nyic" -0xb2c4: "nyik" -0xb2c5: "nyit" -0xb2c6: "nyip" -0xb2c7: "nyih" -0xb2c8: "ni" -0xb2c9: "nig" -0xb2ca: "nigg" -0xb2cb: "nigs" -0xb2cc: "nin" -0xb2cd: "ninj" -0xb2ce: "ninh" -0xb2cf: "nid" -0xb2d0: "nil" -0xb2d1: "nilg" -0xb2d2: "nilm" -0xb2d3: "nilb" -0xb2d4: "nils" -0xb2d5: "nilt" -0xb2d6: "nilp" -0xb2d7: "nilh" -0xb2d8: "nim" -0xb2d9: "nib" -0xb2da: "nibs" -0xb2db: "nis" -0xb2dc: "niss" -0xb2dd: "ning" -0xb2de: "nij" -0xb2df: "nic" -0xb2e0: "nik" -0xb2e1: "nit" -0xb2e2: "nip" -0xb2e3: "nih" -0xb2e4: "da" -0xb2e5: "dag" -0xb2e6: "dagg" -0xb2e7: "dags" -0xb2e8: "dan" -0xb2e9: "danj" -0xb2ea: "danh" -0xb2eb: "dad" -0xb2ec: "dal" -0xb2ed: "dalg" -0xb2ee: "dalm" -0xb2ef: "dalb" -0xb2f0: "dals" -0xb2f1: "dalt" -0xb2f2: "dalp" -0xb2f3: "dalh" -0xb2f4: "dam" -0xb2f5: "dab" -0xb2f6: "dabs" -0xb2f7: "das" -0xb2f8: "dass" -0xb2f9: "dang" -0xb2fa: "daj" -0xb2fb: "dac" -0xb2fc: "dak" -0xb2fd: "dat" -0xb2fe: "dap" -0xb2ff: "dah" -/* x0b3 */ -0xb300: "dae" -0xb301: "daeg" -0xb302: "daegg" -0xb303: "daegs" -0xb304: "daen" -0xb305: "daenj" -0xb306: "daenh" -0xb307: "daed" -0xb308: "dael" -0xb309: "daelg" -0xb30a: "daelm" -0xb30b: "daelb" -0xb30c: "daels" -0xb30d: "daelt" -0xb30e: "daelp" -0xb30f: "daelh" -0xb310: "daem" -0xb311: "daeb" -0xb312: "daebs" -0xb313: "daes" -0xb314: "daess" -0xb315: "daeng" -0xb316: "daej" -0xb317: "daec" -0xb318: "daek" -0xb319: "daet" -0xb31a: "daep" -0xb31b: "daeh" -0xb31c: "dya" -0xb31d: "dyag" -0xb31e: "dyagg" -0xb31f: "dyags" -0xb320: "dyan" -0xb321: "dyanj" -0xb322: "dyanh" -0xb323: "dyad" -0xb324: "dyal" -0xb325: "dyalg" -0xb326: "dyalm" -0xb327: "dyalb" -0xb328: "dyals" -0xb329: "dyalt" -0xb32a: "dyalp" -0xb32b: "dyalh" -0xb32c: "dyam" -0xb32d: "dyab" -0xb32e: "dyabs" -0xb32f: "dyas" -0xb330: "dyass" -0xb331: "dyang" -0xb332: "dyaj" -0xb333: "dyac" -0xb334: "dyak" -0xb335: "dyat" -0xb336: "dyap" -0xb337: "dyah" -0xb338: "dyae" -0xb339: "dyaeg" -0xb33a: "dyaegg" -0xb33b: "dyaegs" -0xb33c: "dyaen" -0xb33d: "dyaenj" -0xb33e: "dyaenh" -0xb33f: "dyaed" -0xb340: "dyael" -0xb341: "dyaelg" -0xb342: "dyaelm" -0xb343: "dyaelb" -0xb344: "dyaels" -0xb345: "dyaelt" -0xb346: "dyaelp" -0xb347: "dyaelh" -0xb348: "dyaem" -0xb349: "dyaeb" -0xb34a: "dyaebs" -0xb34b: "dyaes" -0xb34c: "dyaess" -0xb34d: "dyaeng" -0xb34e: "dyaej" -0xb34f: "dyaec" -0xb350: "dyaek" -0xb351: "dyaet" -0xb352: "dyaep" -0xb353: "dyaeh" -0xb354: "deo" -0xb355: "deog" -0xb356: "deogg" -0xb357: "deogs" -0xb358: "deon" -0xb359: "deonj" -0xb35a: "deonh" -0xb35b: "deod" -0xb35c: "deol" -0xb35d: "deolg" -0xb35e: "deolm" -0xb35f: "deolb" -0xb360: "deols" -0xb361: "deolt" -0xb362: "deolp" -0xb363: "deolh" -0xb364: "deom" -0xb365: "deob" -0xb366: "deobs" -0xb367: "deos" -0xb368: "deoss" -0xb369: "deong" -0xb36a: "deoj" -0xb36b: "deoc" -0xb36c: "deok" -0xb36d: "deot" -0xb36e: "deop" -0xb36f: "deoh" -0xb370: "de" -0xb371: "deg" -0xb372: "degg" -0xb373: "degs" -0xb374: "den" -0xb375: "denj" -0xb376: "denh" -0xb377: "ded" -0xb378: "del" -0xb379: "delg" -0xb37a: "delm" -0xb37b: "delb" -0xb37c: "dels" -0xb37d: "delt" -0xb37e: "delp" -0xb37f: "delh" -0xb380: "dem" -0xb381: "deb" -0xb382: "debs" -0xb383: "des" -0xb384: "dess" -0xb385: "deng" -0xb386: "dej" -0xb387: "dec" -0xb388: "dek" -0xb389: "det" -0xb38a: "dep" -0xb38b: "deh" -0xb38c: "dyeo" -0xb38d: "dyeog" -0xb38e: "dyeogg" -0xb38f: "dyeogs" -0xb390: "dyeon" -0xb391: "dyeonj" -0xb392: "dyeonh" -0xb393: "dyeod" -0xb394: "dyeol" -0xb395: "dyeolg" -0xb396: "dyeolm" -0xb397: "dyeolb" -0xb398: "dyeols" -0xb399: "dyeolt" -0xb39a: "dyeolp" -0xb39b: "dyeolh" -0xb39c: "dyeom" -0xb39d: "dyeob" -0xb39e: "dyeobs" -0xb39f: "dyeos" -0xb3a0: "dyeoss" -0xb3a1: "dyeong" -0xb3a2: "dyeoj" -0xb3a3: "dyeoc" -0xb3a4: "dyeok" -0xb3a5: "dyeot" -0xb3a6: "dyeop" -0xb3a7: "dyeoh" -0xb3a8: "dye" -0xb3a9: "dyeg" -0xb3aa: "dyegg" -0xb3ab: "dyegs" -0xb3ac: "dyen" -0xb3ad: "dyenj" -0xb3ae: "dyenh" -0xb3af: "dyed" -0xb3b0: "dyel" -0xb3b1: "dyelg" -0xb3b2: "dyelm" -0xb3b3: "dyelb" -0xb3b4: "dyels" -0xb3b5: "dyelt" -0xb3b6: "dyelp" -0xb3b7: "dyelh" -0xb3b8: "dyem" -0xb3b9: "dyeb" -0xb3ba: "dyebs" -0xb3bb: "dyes" -0xb3bc: "dyess" -0xb3bd: "dyeng" -0xb3be: "dyej" -0xb3bf: "dyec" -0xb3c0: "dyek" -0xb3c1: "dyet" -0xb3c2: "dyep" -0xb3c3: "dyeh" -0xb3c4: "do" -0xb3c5: "dog" -0xb3c6: "dogg" -0xb3c7: "dogs" -0xb3c8: "don" -0xb3c9: "donj" -0xb3ca: "donh" -0xb3cb: "dod" -0xb3cc: "dol" -0xb3cd: "dolg" -0xb3ce: "dolm" -0xb3cf: "dolb" -0xb3d0: "dols" -0xb3d1: "dolt" -0xb3d2: "dolp" -0xb3d3: "dolh" -0xb3d4: "dom" -0xb3d5: "dob" -0xb3d6: "dobs" -0xb3d7: "dos" -0xb3d8: "doss" -0xb3d9: "dong" -0xb3da: "doj" -0xb3db: "doc" -0xb3dc: "dok" -0xb3dd: "dot" -0xb3de: "dop" -0xb3df: "doh" -0xb3e0: "dwa" -0xb3e1: "dwag" -0xb3e2: "dwagg" -0xb3e3: "dwags" -0xb3e4: "dwan" -0xb3e5: "dwanj" -0xb3e6: "dwanh" -0xb3e7: "dwad" -0xb3e8: "dwal" -0xb3e9: "dwalg" -0xb3ea: "dwalm" -0xb3eb: "dwalb" -0xb3ec: "dwals" -0xb3ed: "dwalt" -0xb3ee: "dwalp" -0xb3ef: "dwalh" -0xb3f0: "dwam" -0xb3f1: "dwab" -0xb3f2: "dwabs" -0xb3f3: "dwas" -0xb3f4: "dwass" -0xb3f5: "dwang" -0xb3f6: "dwaj" -0xb3f7: "dwac" -0xb3f8: "dwak" -0xb3f9: "dwat" -0xb3fa: "dwap" -0xb3fb: "dwah" -0xb3fc: "dwae" -0xb3fd: "dwaeg" -0xb3fe: "dwaegg" -0xb3ff: "dwaegs" -/* x0b4 */ -0xb400: "dwaen" -0xb401: "dwaenj" -0xb402: "dwaenh" -0xb403: "dwaed" -0xb404: "dwael" -0xb405: "dwaelg" -0xb406: "dwaelm" -0xb407: "dwaelb" -0xb408: "dwaels" -0xb409: "dwaelt" -0xb40a: "dwaelp" -0xb40b: "dwaelh" -0xb40c: "dwaem" -0xb40d: "dwaeb" -0xb40e: "dwaebs" -0xb40f: "dwaes" -0xb410: "dwaess" -0xb411: "dwaeng" -0xb412: "dwaej" -0xb413: "dwaec" -0xb414: "dwaek" -0xb415: "dwaet" -0xb416: "dwaep" -0xb417: "dwaeh" -0xb418: "doe" -0xb419: "doeg" -0xb41a: "doegg" -0xb41b: "doegs" -0xb41c: "doen" -0xb41d: "doenj" -0xb41e: "doenh" -0xb41f: "doed" -0xb420: "doel" -0xb421: "doelg" -0xb422: "doelm" -0xb423: "doelb" -0xb424: "doels" -0xb425: "doelt" -0xb426: "doelp" -0xb427: "doelh" -0xb428: "doem" -0xb429: "doeb" -0xb42a: "doebs" -0xb42b: "does" -0xb42c: "doess" -0xb42d: "doeng" -0xb42e: "doej" -0xb42f: "doec" -0xb430: "doek" -0xb431: "doet" -0xb432: "doep" -0xb433: "doeh" -0xb434: "dyo" -0xb435: "dyog" -0xb436: "dyogg" -0xb437: "dyogs" -0xb438: "dyon" -0xb439: "dyonj" -0xb43a: "dyonh" -0xb43b: "dyod" -0xb43c: "dyol" -0xb43d: "dyolg" -0xb43e: "dyolm" -0xb43f: "dyolb" -0xb440: "dyols" -0xb441: "dyolt" -0xb442: "dyolp" -0xb443: "dyolh" -0xb444: "dyom" -0xb445: "dyob" -0xb446: "dyobs" -0xb447: "dyos" -0xb448: "dyoss" -0xb449: "dyong" -0xb44a: "dyoj" -0xb44b: "dyoc" -0xb44c: "dyok" -0xb44d: "dyot" -0xb44e: "dyop" -0xb44f: "dyoh" -0xb450: "du" -0xb451: "dug" -0xb452: "dugg" -0xb453: "dugs" -0xb454: "dun" -0xb455: "dunj" -0xb456: "dunh" -0xb457: "dud" -0xb458: "dul" -0xb459: "dulg" -0xb45a: "dulm" -0xb45b: "dulb" -0xb45c: "duls" -0xb45d: "dult" -0xb45e: "dulp" -0xb45f: "dulh" -0xb460: "dum" -0xb461: "dub" -0xb462: "dubs" -0xb463: "dus" -0xb464: "duss" -0xb465: "dung" -0xb466: "duj" -0xb467: "duc" -0xb468: "duk" -0xb469: "dut" -0xb46a: "dup" -0xb46b: "duh" -0xb46c: "dweo" -0xb46d: "dweog" -0xb46e: "dweogg" -0xb46f: "dweogs" -0xb470: "dweon" -0xb471: "dweonj" -0xb472: "dweonh" -0xb473: "dweod" -0xb474: "dweol" -0xb475: "dweolg" -0xb476: "dweolm" -0xb477: "dweolb" -0xb478: "dweols" -0xb479: "dweolt" -0xb47a: "dweolp" -0xb47b: "dweolh" -0xb47c: "dweom" -0xb47d: "dweob" -0xb47e: "dweobs" -0xb47f: "dweos" -0xb480: "dweoss" -0xb481: "dweong" -0xb482: "dweoj" -0xb483: "dweoc" -0xb484: "dweok" -0xb485: "dweot" -0xb486: "dweop" -0xb487: "dweoh" -0xb488: "dwe" -0xb489: "dweg" -0xb48a: "dwegg" -0xb48b: "dwegs" -0xb48c: "dwen" -0xb48d: "dwenj" -0xb48e: "dwenh" -0xb48f: "dwed" -0xb490: "dwel" -0xb491: "dwelg" -0xb492: "dwelm" -0xb493: "dwelb" -0xb494: "dwels" -0xb495: "dwelt" -0xb496: "dwelp" -0xb497: "dwelh" -0xb498: "dwem" -0xb499: "dweb" -0xb49a: "dwebs" -0xb49b: "dwes" -0xb49c: "dwess" -0xb49d: "dweng" -0xb49e: "dwej" -0xb49f: "dwec" -0xb4a0: "dwek" -0xb4a1: "dwet" -0xb4a2: "dwep" -0xb4a3: "dweh" -0xb4a4: "dwi" -0xb4a5: "dwig" -0xb4a6: "dwigg" -0xb4a7: "dwigs" -0xb4a8: "dwin" -0xb4a9: "dwinj" -0xb4aa: "dwinh" -0xb4ab: "dwid" -0xb4ac: "dwil" -0xb4ad: "dwilg" -0xb4ae: "dwilm" -0xb4af: "dwilb" -0xb4b0: "dwils" -0xb4b1: "dwilt" -0xb4b2: "dwilp" -0xb4b3: "dwilh" -0xb4b4: "dwim" -0xb4b5: "dwib" -0xb4b6: "dwibs" -0xb4b7: "dwis" -0xb4b8: "dwiss" -0xb4b9: "dwing" -0xb4ba: "dwij" -0xb4bb: "dwic" -0xb4bc: "dwik" -0xb4bd: "dwit" -0xb4be: "dwip" -0xb4bf: "dwih" -0xb4c0: "dyu" -0xb4c1: "dyug" -0xb4c2: "dyugg" -0xb4c3: "dyugs" -0xb4c4: "dyun" -0xb4c5: "dyunj" -0xb4c6: "dyunh" -0xb4c7: "dyud" -0xb4c8: "dyul" -0xb4c9: "dyulg" -0xb4ca: "dyulm" -0xb4cb: "dyulb" -0xb4cc: "dyuls" -0xb4cd: "dyult" -0xb4ce: "dyulp" -0xb4cf: "dyulh" -0xb4d0: "dyum" -0xb4d1: "dyub" -0xb4d2: "dyubs" -0xb4d3: "dyus" -0xb4d4: "dyuss" -0xb4d5: "dyung" -0xb4d6: "dyuj" -0xb4d7: "dyuc" -0xb4d8: "dyuk" -0xb4d9: "dyut" -0xb4da: "dyup" -0xb4db: "dyuh" -0xb4dc: "deu" -0xb4dd: "deug" -0xb4de: "deugg" -0xb4df: "deugs" -0xb4e0: "deun" -0xb4e1: "deunj" -0xb4e2: "deunh" -0xb4e3: "deud" -0xb4e4: "deul" -0xb4e5: "deulg" -0xb4e6: "deulm" -0xb4e7: "deulb" -0xb4e8: "deuls" -0xb4e9: "deult" -0xb4ea: "deulp" -0xb4eb: "deulh" -0xb4ec: "deum" -0xb4ed: "deub" -0xb4ee: "deubs" -0xb4ef: "deus" -0xb4f0: "deuss" -0xb4f1: "deung" -0xb4f2: "deuj" -0xb4f3: "deuc" -0xb4f4: "deuk" -0xb4f5: "deut" -0xb4f6: "deup" -0xb4f7: "deuh" -0xb4f8: "dyi" -0xb4f9: "dyig" -0xb4fa: "dyigg" -0xb4fb: "dyigs" -0xb4fc: "dyin" -0xb4fd: "dyinj" -0xb4fe: "dyinh" -0xb4ff: "dyid" -/* x0b5 */ -0xb500: "dyil" -0xb501: "dyilg" -0xb502: "dyilm" -0xb503: "dyilb" -0xb504: "dyils" -0xb505: "dyilt" -0xb506: "dyilp" -0xb507: "dyilh" -0xb508: "dyim" -0xb509: "dyib" -0xb50a: "dyibs" -0xb50b: "dyis" -0xb50c: "dyiss" -0xb50d: "dying" -0xb50e: "dyij" -0xb50f: "dyic" -0xb510: "dyik" -0xb511: "dyit" -0xb512: "dyip" -0xb513: "dyih" -0xb514: "di" -0xb515: "dig" -0xb516: "digg" -0xb517: "digs" -0xb518: "din" -0xb519: "dinj" -0xb51a: "dinh" -0xb51b: "did" -0xb51c: "dil" -0xb51d: "dilg" -0xb51e: "dilm" -0xb51f: "dilb" -0xb520: "dils" -0xb521: "dilt" -0xb522: "dilp" -0xb523: "dilh" -0xb524: "dim" -0xb525: "dib" -0xb526: "dibs" -0xb527: "dis" -0xb528: "diss" -0xb529: "ding" -0xb52a: "dij" -0xb52b: "dic" -0xb52c: "dik" -0xb52d: "dit" -0xb52e: "dip" -0xb52f: "dih" -0xb530: "dda" -0xb531: "ddag" -0xb532: "ddagg" -0xb533: "ddags" -0xb534: "ddan" -0xb535: "ddanj" -0xb536: "ddanh" -0xb537: "ddad" -0xb538: "ddal" -0xb539: "ddalg" -0xb53a: "ddalm" -0xb53b: "ddalb" -0xb53c: "ddals" -0xb53d: "ddalt" -0xb53e: "ddalp" -0xb53f: "ddalh" -0xb540: "ddam" -0xb541: "ddab" -0xb542: "ddabs" -0xb543: "ddas" -0xb544: "ddass" -0xb545: "ddang" -0xb546: "ddaj" -0xb547: "ddac" -0xb548: "ddak" -0xb549: "ddat" -0xb54a: "ddap" -0xb54b: "ddah" -0xb54c: "ddae" -0xb54d: "ddaeg" -0xb54e: "ddaegg" -0xb54f: "ddaegs" -0xb550: "ddaen" -0xb551: "ddaenj" -0xb552: "ddaenh" -0xb553: "ddaed" -0xb554: "ddael" -0xb555: "ddaelg" -0xb556: "ddaelm" -0xb557: "ddaelb" -0xb558: "ddaels" -0xb559: "ddaelt" -0xb55a: "ddaelp" -0xb55b: "ddaelh" -0xb55c: "ddaem" -0xb55d: "ddaeb" -0xb55e: "ddaebs" -0xb55f: "ddaes" -0xb560: "ddaess" -0xb561: "ddaeng" -0xb562: "ddaej" -0xb563: "ddaec" -0xb564: "ddaek" -0xb565: "ddaet" -0xb566: "ddaep" -0xb567: "ddaeh" -0xb568: "ddya" -0xb569: "ddyag" -0xb56a: "ddyagg" -0xb56b: "ddyags" -0xb56c: "ddyan" -0xb56d: "ddyanj" -0xb56e: "ddyanh" -0xb56f: "ddyad" -0xb570: "ddyal" -0xb571: "ddyalg" -0xb572: "ddyalm" -0xb573: "ddyalb" -0xb574: "ddyals" -0xb575: "ddyalt" -0xb576: "ddyalp" -0xb577: "ddyalh" -0xb578: "ddyam" -0xb579: "ddyab" -0xb57a: "ddyabs" -0xb57b: "ddyas" -0xb57c: "ddyass" -0xb57d: "ddyang" -0xb57e: "ddyaj" -0xb57f: "ddyac" -0xb580: "ddyak" -0xb581: "ddyat" -0xb582: "ddyap" -0xb583: "ddyah" -0xb584: "ddyae" -0xb585: "ddyaeg" -0xb586: "ddyaegg" -0xb587: "ddyaegs" -0xb588: "ddyaen" -0xb589: "ddyaenj" -0xb58a: "ddyaenh" -0xb58b: "ddyaed" -0xb58c: "ddyael" -0xb58d: "ddyaelg" -0xb58e: "ddyaelm" -0xb58f: "ddyaelb" -0xb590: "ddyaels" -0xb591: "ddyaelt" -0xb592: "ddyaelp" -0xb593: "ddyaelh" -0xb594: "ddyaem" -0xb595: "ddyaeb" -0xb596: "ddyaebs" -0xb597: "ddyaes" -0xb598: "ddyaess" -0xb599: "ddyaeng" -0xb59a: "ddyaej" -0xb59b: "ddyaec" -0xb59c: "ddyaek" -0xb59d: "ddyaet" -0xb59e: "ddyaep" -0xb59f: "ddyaeh" -0xb5a0: "ddeo" -0xb5a1: "ddeog" -0xb5a2: "ddeogg" -0xb5a3: "ddeogs" -0xb5a4: "ddeon" -0xb5a5: "ddeonj" -0xb5a6: "ddeonh" -0xb5a7: "ddeod" -0xb5a8: "ddeol" -0xb5a9: "ddeolg" -0xb5aa: "ddeolm" -0xb5ab: "ddeolb" -0xb5ac: "ddeols" -0xb5ad: "ddeolt" -0xb5ae: "ddeolp" -0xb5af: "ddeolh" -0xb5b0: "ddeom" -0xb5b1: "ddeob" -0xb5b2: "ddeobs" -0xb5b3: "ddeos" -0xb5b4: "ddeoss" -0xb5b5: "ddeong" -0xb5b6: "ddeoj" -0xb5b7: "ddeoc" -0xb5b8: "ddeok" -0xb5b9: "ddeot" -0xb5ba: "ddeop" -0xb5bb: "ddeoh" -0xb5bc: "dde" -0xb5bd: "ddeg" -0xb5be: "ddegg" -0xb5bf: "ddegs" -0xb5c0: "dden" -0xb5c1: "ddenj" -0xb5c2: "ddenh" -0xb5c3: "dded" -0xb5c4: "ddel" -0xb5c5: "ddelg" -0xb5c6: "ddelm" -0xb5c7: "ddelb" -0xb5c8: "ddels" -0xb5c9: "ddelt" -0xb5ca: "ddelp" -0xb5cb: "ddelh" -0xb5cc: "ddem" -0xb5cd: "ddeb" -0xb5ce: "ddebs" -0xb5cf: "ddes" -0xb5d0: "ddess" -0xb5d1: "ddeng" -0xb5d2: "ddej" -0xb5d3: "ddec" -0xb5d4: "ddek" -0xb5d5: "ddet" -0xb5d6: "ddep" -0xb5d7: "ddeh" -0xb5d8: "ddyeo" -0xb5d9: "ddyeog" -0xb5da: "ddyeogg" -0xb5db: "ddyeogs" -0xb5dc: "ddyeon" -0xb5dd: "ddyeonj" -0xb5de: "ddyeonh" -0xb5df: "ddyeod" -0xb5e0: "ddyeol" -0xb5e1: "ddyeolg" -0xb5e2: "ddyeolm" -0xb5e3: "ddyeolb" -0xb5e4: "ddyeols" -0xb5e5: "ddyeolt" -0xb5e6: "ddyeolp" -0xb5e7: "ddyeolh" -0xb5e8: "ddyeom" -0xb5e9: "ddyeob" -0xb5ea: "ddyeobs" -0xb5eb: "ddyeos" -0xb5ec: "ddyeoss" -0xb5ed: "ddyeong" -0xb5ee: "ddyeoj" -0xb5ef: "ddyeoc" -0xb5f0: "ddyeok" -0xb5f1: "ddyeot" -0xb5f2: "ddyeop" -0xb5f3: "ddyeoh" -0xb5f4: "ddye" -0xb5f5: "ddyeg" -0xb5f6: "ddyegg" -0xb5f7: "ddyegs" -0xb5f8: "ddyen" -0xb5f9: "ddyenj" -0xb5fa: "ddyenh" -0xb5fb: "ddyed" -0xb5fc: "ddyel" -0xb5fd: "ddyelg" -0xb5fe: "ddyelm" -0xb5ff: "ddyelb" -/* x0b6 */ -0xb600: "ddyels" -0xb601: "ddyelt" -0xb602: "ddyelp" -0xb603: "ddyelh" -0xb604: "ddyem" -0xb605: "ddyeb" -0xb606: "ddyebs" -0xb607: "ddyes" -0xb608: "ddyess" -0xb609: "ddyeng" -0xb60a: "ddyej" -0xb60b: "ddyec" -0xb60c: "ddyek" -0xb60d: "ddyet" -0xb60e: "ddyep" -0xb60f: "ddyeh" -0xb610: "ddo" -0xb611: "ddog" -0xb612: "ddogg" -0xb613: "ddogs" -0xb614: "ddon" -0xb615: "ddonj" -0xb616: "ddonh" -0xb617: "ddod" -0xb618: "ddol" -0xb619: "ddolg" -0xb61a: "ddolm" -0xb61b: "ddolb" -0xb61c: "ddols" -0xb61d: "ddolt" -0xb61e: "ddolp" -0xb61f: "ddolh" -0xb620: "ddom" -0xb621: "ddob" -0xb622: "ddobs" -0xb623: "ddos" -0xb624: "ddoss" -0xb625: "ddong" -0xb626: "ddoj" -0xb627: "ddoc" -0xb628: "ddok" -0xb629: "ddot" -0xb62a: "ddop" -0xb62b: "ddoh" -0xb62c: "ddwa" -0xb62d: "ddwag" -0xb62e: "ddwagg" -0xb62f: "ddwags" -0xb630: "ddwan" -0xb631: "ddwanj" -0xb632: "ddwanh" -0xb633: "ddwad" -0xb634: "ddwal" -0xb635: "ddwalg" -0xb636: "ddwalm" -0xb637: "ddwalb" -0xb638: "ddwals" -0xb639: "ddwalt" -0xb63a: "ddwalp" -0xb63b: "ddwalh" -0xb63c: "ddwam" -0xb63d: "ddwab" -0xb63e: "ddwabs" -0xb63f: "ddwas" -0xb640: "ddwass" -0xb641: "ddwang" -0xb642: "ddwaj" -0xb643: "ddwac" -0xb644: "ddwak" -0xb645: "ddwat" -0xb646: "ddwap" -0xb647: "ddwah" -0xb648: "ddwae" -0xb649: "ddwaeg" -0xb64a: "ddwaegg" -0xb64b: "ddwaegs" -0xb64c: "ddwaen" -0xb64d: "ddwaenj" -0xb64e: "ddwaenh" -0xb64f: "ddwaed" -0xb650: "ddwael" -0xb651: "ddwaelg" -0xb652: "ddwaelm" -0xb653: "ddwaelb" -0xb654: "ddwaels" -0xb655: "ddwaelt" -0xb656: "ddwaelp" -0xb657: "ddwaelh" -0xb658: "ddwaem" -0xb659: "ddwaeb" -0xb65a: "ddwaebs" -0xb65b: "ddwaes" -0xb65c: "ddwaess" -0xb65d: "ddwaeng" -0xb65e: "ddwaej" -0xb65f: "ddwaec" -0xb660: "ddwaek" -0xb661: "ddwaet" -0xb662: "ddwaep" -0xb663: "ddwaeh" -0xb664: "ddoe" -0xb665: "ddoeg" -0xb666: "ddoegg" -0xb667: "ddoegs" -0xb668: "ddoen" -0xb669: "ddoenj" -0xb66a: "ddoenh" -0xb66b: "ddoed" -0xb66c: "ddoel" -0xb66d: "ddoelg" -0xb66e: "ddoelm" -0xb66f: "ddoelb" -0xb670: "ddoels" -0xb671: "ddoelt" -0xb672: "ddoelp" -0xb673: "ddoelh" -0xb674: "ddoem" -0xb675: "ddoeb" -0xb676: "ddoebs" -0xb677: "ddoes" -0xb678: "ddoess" -0xb679: "ddoeng" -0xb67a: "ddoej" -0xb67b: "ddoec" -0xb67c: "ddoek" -0xb67d: "ddoet" -0xb67e: "ddoep" -0xb67f: "ddoeh" -0xb680: "ddyo" -0xb681: "ddyog" -0xb682: "ddyogg" -0xb683: "ddyogs" -0xb684: "ddyon" -0xb685: "ddyonj" -0xb686: "ddyonh" -0xb687: "ddyod" -0xb688: "ddyol" -0xb689: "ddyolg" -0xb68a: "ddyolm" -0xb68b: "ddyolb" -0xb68c: "ddyols" -0xb68d: "ddyolt" -0xb68e: "ddyolp" -0xb68f: "ddyolh" -0xb690: "ddyom" -0xb691: "ddyob" -0xb692: "ddyobs" -0xb693: "ddyos" -0xb694: "ddyoss" -0xb695: "ddyong" -0xb696: "ddyoj" -0xb697: "ddyoc" -0xb698: "ddyok" -0xb699: "ddyot" -0xb69a: "ddyop" -0xb69b: "ddyoh" -0xb69c: "ddu" -0xb69d: "ddug" -0xb69e: "ddugg" -0xb69f: "ddugs" -0xb6a0: "ddun" -0xb6a1: "ddunj" -0xb6a2: "ddunh" -0xb6a3: "ddud" -0xb6a4: "ddul" -0xb6a5: "ddulg" -0xb6a6: "ddulm" -0xb6a7: "ddulb" -0xb6a8: "dduls" -0xb6a9: "ddult" -0xb6aa: "ddulp" -0xb6ab: "ddulh" -0xb6ac: "ddum" -0xb6ad: "ddub" -0xb6ae: "ddubs" -0xb6af: "ddus" -0xb6b0: "dduss" -0xb6b1: "ddung" -0xb6b2: "dduj" -0xb6b3: "dduc" -0xb6b4: "dduk" -0xb6b5: "ddut" -0xb6b6: "ddup" -0xb6b7: "dduh" -0xb6b8: "ddweo" -0xb6b9: "ddweog" -0xb6ba: "ddweogg" -0xb6bb: "ddweogs" -0xb6bc: "ddweon" -0xb6bd: "ddweonj" -0xb6be: "ddweonh" -0xb6bf: "ddweod" -0xb6c0: "ddweol" -0xb6c1: "ddweolg" -0xb6c2: "ddweolm" -0xb6c3: "ddweolb" -0xb6c4: "ddweols" -0xb6c5: "ddweolt" -0xb6c6: "ddweolp" -0xb6c7: "ddweolh" -0xb6c8: "ddweom" -0xb6c9: "ddweob" -0xb6ca: "ddweobs" -0xb6cb: "ddweos" -0xb6cc: "ddweoss" -0xb6cd: "ddweong" -0xb6ce: "ddweoj" -0xb6cf: "ddweoc" -0xb6d0: "ddweok" -0xb6d1: "ddweot" -0xb6d2: "ddweop" -0xb6d3: "ddweoh" -0xb6d4: "ddwe" -0xb6d5: "ddweg" -0xb6d6: "ddwegg" -0xb6d7: "ddwegs" -0xb6d8: "ddwen" -0xb6d9: "ddwenj" -0xb6da: "ddwenh" -0xb6db: "ddwed" -0xb6dc: "ddwel" -0xb6dd: "ddwelg" -0xb6de: "ddwelm" -0xb6df: "ddwelb" -0xb6e0: "ddwels" -0xb6e1: "ddwelt" -0xb6e2: "ddwelp" -0xb6e3: "ddwelh" -0xb6e4: "ddwem" -0xb6e5: "ddweb" -0xb6e6: "ddwebs" -0xb6e7: "ddwes" -0xb6e8: "ddwess" -0xb6e9: "ddweng" -0xb6ea: "ddwej" -0xb6eb: "ddwec" -0xb6ec: "ddwek" -0xb6ed: "ddwet" -0xb6ee: "ddwep" -0xb6ef: "ddweh" -0xb6f0: "ddwi" -0xb6f1: "ddwig" -0xb6f2: "ddwigg" -0xb6f3: "ddwigs" -0xb6f4: "ddwin" -0xb6f5: "ddwinj" -0xb6f6: "ddwinh" -0xb6f7: "ddwid" -0xb6f8: "ddwil" -0xb6f9: "ddwilg" -0xb6fa: "ddwilm" -0xb6fb: "ddwilb" -0xb6fc: "ddwils" -0xb6fd: "ddwilt" -0xb6fe: "ddwilp" -0xb6ff: "ddwilh" -/* x0b7 */ -0xb700: "ddwim" -0xb701: "ddwib" -0xb702: "ddwibs" -0xb703: "ddwis" -0xb704: "ddwiss" -0xb705: "ddwing" -0xb706: "ddwij" -0xb707: "ddwic" -0xb708: "ddwik" -0xb709: "ddwit" -0xb70a: "ddwip" -0xb70b: "ddwih" -0xb70c: "ddyu" -0xb70d: "ddyug" -0xb70e: "ddyugg" -0xb70f: "ddyugs" -0xb710: "ddyun" -0xb711: "ddyunj" -0xb712: "ddyunh" -0xb713: "ddyud" -0xb714: "ddyul" -0xb715: "ddyulg" -0xb716: "ddyulm" -0xb717: "ddyulb" -0xb718: "ddyuls" -0xb719: "ddyult" -0xb71a: "ddyulp" -0xb71b: "ddyulh" -0xb71c: "ddyum" -0xb71d: "ddyub" -0xb71e: "ddyubs" -0xb71f: "ddyus" -0xb720: "ddyuss" -0xb721: "ddyung" -0xb722: "ddyuj" -0xb723: "ddyuc" -0xb724: "ddyuk" -0xb725: "ddyut" -0xb726: "ddyup" -0xb727: "ddyuh" -0xb728: "ddeu" -0xb729: "ddeug" -0xb72a: "ddeugg" -0xb72b: "ddeugs" -0xb72c: "ddeun" -0xb72d: "ddeunj" -0xb72e: "ddeunh" -0xb72f: "ddeud" -0xb730: "ddeul" -0xb731: "ddeulg" -0xb732: "ddeulm" -0xb733: "ddeulb" -0xb734: "ddeuls" -0xb735: "ddeult" -0xb736: "ddeulp" -0xb737: "ddeulh" -0xb738: "ddeum" -0xb739: "ddeub" -0xb73a: "ddeubs" -0xb73b: "ddeus" -0xb73c: "ddeuss" -0xb73d: "ddeung" -0xb73e: "ddeuj" -0xb73f: "ddeuc" -0xb740: "ddeuk" -0xb741: "ddeut" -0xb742: "ddeup" -0xb743: "ddeuh" -0xb744: "ddyi" -0xb745: "ddyig" -0xb746: "ddyigg" -0xb747: "ddyigs" -0xb748: "ddyin" -0xb749: "ddyinj" -0xb74a: "ddyinh" -0xb74b: "ddyid" -0xb74c: "ddyil" -0xb74d: "ddyilg" -0xb74e: "ddyilm" -0xb74f: "ddyilb" -0xb750: "ddyils" -0xb751: "ddyilt" -0xb752: "ddyilp" -0xb753: "ddyilh" -0xb754: "ddyim" -0xb755: "ddyib" -0xb756: "ddyibs" -0xb757: "ddyis" -0xb758: "ddyiss" -0xb759: "ddying" -0xb75a: "ddyij" -0xb75b: "ddyic" -0xb75c: "ddyik" -0xb75d: "ddyit" -0xb75e: "ddyip" -0xb75f: "ddyih" -0xb760: "ddi" -0xb761: "ddig" -0xb762: "ddigg" -0xb763: "ddigs" -0xb764: "ddin" -0xb765: "ddinj" -0xb766: "ddinh" -0xb767: "ddid" -0xb768: "ddil" -0xb769: "ddilg" -0xb76a: "ddilm" -0xb76b: "ddilb" -0xb76c: "ddils" -0xb76d: "ddilt" -0xb76e: "ddilp" -0xb76f: "ddilh" -0xb770: "ddim" -0xb771: "ddib" -0xb772: "ddibs" -0xb773: "ddis" -0xb774: "ddiss" -0xb775: "dding" -0xb776: "ddij" -0xb777: "ddic" -0xb778: "ddik" -0xb779: "ddit" -0xb77a: "ddip" -0xb77b: "ddih" -0xb77c: "ra" -0xb77d: "rag" -0xb77e: "ragg" -0xb77f: "rags" -0xb780: "ran" -0xb781: "ranj" -0xb782: "ranh" -0xb783: "rad" -0xb784: "ral" -0xb785: "ralg" -0xb786: "ralm" -0xb787: "ralb" -0xb788: "rals" -0xb789: "ralt" -0xb78a: "ralp" -0xb78b: "ralh" -0xb78c: "ram" -0xb78d: "rab" -0xb78e: "rabs" -0xb78f: "ras" -0xb790: "rass" -0xb791: "rang" -0xb792: "raj" -0xb793: "rac" -0xb794: "rak" -0xb795: "rat" -0xb796: "rap" -0xb797: "rah" -0xb798: "rae" -0xb799: "raeg" -0xb79a: "raegg" -0xb79b: "raegs" -0xb79c: "raen" -0xb79d: "raenj" -0xb79e: "raenh" -0xb79f: "raed" -0xb7a0: "rael" -0xb7a1: "raelg" -0xb7a2: "raelm" -0xb7a3: "raelb" -0xb7a4: "raels" -0xb7a5: "raelt" -0xb7a6: "raelp" -0xb7a7: "raelh" -0xb7a8: "raem" -0xb7a9: "raeb" -0xb7aa: "raebs" -0xb7ab: "raes" -0xb7ac: "raess" -0xb7ad: "raeng" -0xb7ae: "raej" -0xb7af: "raec" -0xb7b0: "raek" -0xb7b1: "raet" -0xb7b2: "raep" -0xb7b3: "raeh" -0xb7b4: "rya" -0xb7b5: "ryag" -0xb7b6: "ryagg" -0xb7b7: "ryags" -0xb7b8: "ryan" -0xb7b9: "ryanj" -0xb7ba: "ryanh" -0xb7bb: "ryad" -0xb7bc: "ryal" -0xb7bd: "ryalg" -0xb7be: "ryalm" -0xb7bf: "ryalb" -0xb7c0: "ryals" -0xb7c1: "ryalt" -0xb7c2: "ryalp" -0xb7c3: "ryalh" -0xb7c4: "ryam" -0xb7c5: "ryab" -0xb7c6: "ryabs" -0xb7c7: "ryas" -0xb7c8: "ryass" -0xb7c9: "ryang" -0xb7ca: "ryaj" -0xb7cb: "ryac" -0xb7cc: "ryak" -0xb7cd: "ryat" -0xb7ce: "ryap" -0xb7cf: "ryah" -0xb7d0: "ryae" -0xb7d1: "ryaeg" -0xb7d2: "ryaegg" -0xb7d3: "ryaegs" -0xb7d4: "ryaen" -0xb7d5: "ryaenj" -0xb7d6: "ryaenh" -0xb7d7: "ryaed" -0xb7d8: "ryael" -0xb7d9: "ryaelg" -0xb7da: "ryaelm" -0xb7db: "ryaelb" -0xb7dc: "ryaels" -0xb7dd: "ryaelt" -0xb7de: "ryaelp" -0xb7df: "ryaelh" -0xb7e0: "ryaem" -0xb7e1: "ryaeb" -0xb7e2: "ryaebs" -0xb7e3: "ryaes" -0xb7e4: "ryaess" -0xb7e5: "ryaeng" -0xb7e6: "ryaej" -0xb7e7: "ryaec" -0xb7e8: "ryaek" -0xb7e9: "ryaet" -0xb7ea: "ryaep" -0xb7eb: "ryaeh" -0xb7ec: "reo" -0xb7ed: "reog" -0xb7ee: "reogg" -0xb7ef: "reogs" -0xb7f0: "reon" -0xb7f1: "reonj" -0xb7f2: "reonh" -0xb7f3: "reod" -0xb7f4: "reol" -0xb7f5: "reolg" -0xb7f6: "reolm" -0xb7f7: "reolb" -0xb7f8: "reols" -0xb7f9: "reolt" -0xb7fa: "reolp" -0xb7fb: "reolh" -0xb7fc: "reom" -0xb7fd: "reob" -0xb7fe: "reobs" -0xb7ff: "reos" -/* x0b8 */ -0xb800: "reoss" -0xb801: "reong" -0xb802: "reoj" -0xb803: "reoc" -0xb804: "reok" -0xb805: "reot" -0xb806: "reop" -0xb807: "reoh" -0xb808: "re" -0xb809: "reg" -0xb80a: "regg" -0xb80b: "regs" -0xb80c: "ren" -0xb80d: "renj" -0xb80e: "renh" -0xb80f: "red" -0xb810: "rel" -0xb811: "relg" -0xb812: "relm" -0xb813: "relb" -0xb814: "rels" -0xb815: "relt" -0xb816: "relp" -0xb817: "relh" -0xb818: "rem" -0xb819: "reb" -0xb81a: "rebs" -0xb81b: "res" -0xb81c: "ress" -0xb81d: "reng" -0xb81e: "rej" -0xb81f: "rec" -0xb820: "rek" -0xb821: "ret" -0xb822: "rep" -0xb823: "reh" -0xb824: "ryeo" -0xb825: "ryeog" -0xb826: "ryeogg" -0xb827: "ryeogs" -0xb828: "ryeon" -0xb829: "ryeonj" -0xb82a: "ryeonh" -0xb82b: "ryeod" -0xb82c: "ryeol" -0xb82d: "ryeolg" -0xb82e: "ryeolm" -0xb82f: "ryeolb" -0xb830: "ryeols" -0xb831: "ryeolt" -0xb832: "ryeolp" -0xb833: "ryeolh" -0xb834: "ryeom" -0xb835: "ryeob" -0xb836: "ryeobs" -0xb837: "ryeos" -0xb838: "ryeoss" -0xb839: "ryeong" -0xb83a: "ryeoj" -0xb83b: "ryeoc" -0xb83c: "ryeok" -0xb83d: "ryeot" -0xb83e: "ryeop" -0xb83f: "ryeoh" -0xb840: "rye" -0xb841: "ryeg" -0xb842: "ryegg" -0xb843: "ryegs" -0xb844: "ryen" -0xb845: "ryenj" -0xb846: "ryenh" -0xb847: "ryed" -0xb848: "ryel" -0xb849: "ryelg" -0xb84a: "ryelm" -0xb84b: "ryelb" -0xb84c: "ryels" -0xb84d: "ryelt" -0xb84e: "ryelp" -0xb84f: "ryelh" -0xb850: "ryem" -0xb851: "ryeb" -0xb852: "ryebs" -0xb853: "ryes" -0xb854: "ryess" -0xb855: "ryeng" -0xb856: "ryej" -0xb857: "ryec" -0xb858: "ryek" -0xb859: "ryet" -0xb85a: "ryep" -0xb85b: "ryeh" -0xb85c: "ro" -0xb85d: "rog" -0xb85e: "rogg" -0xb85f: "rogs" -0xb860: "ron" -0xb861: "ronj" -0xb862: "ronh" -0xb863: "rod" -0xb864: "rol" -0xb865: "rolg" -0xb866: "rolm" -0xb867: "rolb" -0xb868: "rols" -0xb869: "rolt" -0xb86a: "rolp" -0xb86b: "rolh" -0xb86c: "rom" -0xb86d: "rob" -0xb86e: "robs" -0xb86f: "ros" -0xb870: "ross" -0xb871: "rong" -0xb872: "roj" -0xb873: "roc" -0xb874: "rok" -0xb875: "rot" -0xb876: "rop" -0xb877: "roh" -0xb878: "rwa" -0xb879: "rwag" -0xb87a: "rwagg" -0xb87b: "rwags" -0xb87c: "rwan" -0xb87d: "rwanj" -0xb87e: "rwanh" -0xb87f: "rwad" -0xb880: "rwal" -0xb881: "rwalg" -0xb882: "rwalm" -0xb883: "rwalb" -0xb884: "rwals" -0xb885: "rwalt" -0xb886: "rwalp" -0xb887: "rwalh" -0xb888: "rwam" -0xb889: "rwab" -0xb88a: "rwabs" -0xb88b: "rwas" -0xb88c: "rwass" -0xb88d: "rwang" -0xb88e: "rwaj" -0xb88f: "rwac" -0xb890: "rwak" -0xb891: "rwat" -0xb892: "rwap" -0xb893: "rwah" -0xb894: "rwae" -0xb895: "rwaeg" -0xb896: "rwaegg" -0xb897: "rwaegs" -0xb898: "rwaen" -0xb899: "rwaenj" -0xb89a: "rwaenh" -0xb89b: "rwaed" -0xb89c: "rwael" -0xb89d: "rwaelg" -0xb89e: "rwaelm" -0xb89f: "rwaelb" -0xb8a0: "rwaels" -0xb8a1: "rwaelt" -0xb8a2: "rwaelp" -0xb8a3: "rwaelh" -0xb8a4: "rwaem" -0xb8a5: "rwaeb" -0xb8a6: "rwaebs" -0xb8a7: "rwaes" -0xb8a8: "rwaess" -0xb8a9: "rwaeng" -0xb8aa: "rwaej" -0xb8ab: "rwaec" -0xb8ac: "rwaek" -0xb8ad: "rwaet" -0xb8ae: "rwaep" -0xb8af: "rwaeh" -0xb8b0: "roe" -0xb8b1: "roeg" -0xb8b2: "roegg" -0xb8b3: "roegs" -0xb8b4: "roen" -0xb8b5: "roenj" -0xb8b6: "roenh" -0xb8b7: "roed" -0xb8b8: "roel" -0xb8b9: "roelg" -0xb8ba: "roelm" -0xb8bb: "roelb" -0xb8bc: "roels" -0xb8bd: "roelt" -0xb8be: "roelp" -0xb8bf: "roelh" -0xb8c0: "roem" -0xb8c1: "roeb" -0xb8c2: "roebs" -0xb8c3: "roes" -0xb8c4: "roess" -0xb8c5: "roeng" -0xb8c6: "roej" -0xb8c7: "roec" -0xb8c8: "roek" -0xb8c9: "roet" -0xb8ca: "roep" -0xb8cb: "roeh" -0xb8cc: "ryo" -0xb8cd: "ryog" -0xb8ce: "ryogg" -0xb8cf: "ryogs" -0xb8d0: "ryon" -0xb8d1: "ryonj" -0xb8d2: "ryonh" -0xb8d3: "ryod" -0xb8d4: "ryol" -0xb8d5: "ryolg" -0xb8d6: "ryolm" -0xb8d7: "ryolb" -0xb8d8: "ryols" -0xb8d9: "ryolt" -0xb8da: "ryolp" -0xb8db: "ryolh" -0xb8dc: "ryom" -0xb8dd: "ryob" -0xb8de: "ryobs" -0xb8df: "ryos" -0xb8e0: "ryoss" -0xb8e1: "ryong" -0xb8e2: "ryoj" -0xb8e3: "ryoc" -0xb8e4: "ryok" -0xb8e5: "ryot" -0xb8e6: "ryop" -0xb8e7: "ryoh" -0xb8e8: "ru" -0xb8e9: "rug" -0xb8ea: "rugg" -0xb8eb: "rugs" -0xb8ec: "run" -0xb8ed: "runj" -0xb8ee: "runh" -0xb8ef: "rud" -0xb8f0: "rul" -0xb8f1: "rulg" -0xb8f2: "rulm" -0xb8f3: "rulb" -0xb8f4: "ruls" -0xb8f5: "rult" -0xb8f6: "rulp" -0xb8f7: "rulh" -0xb8f8: "rum" -0xb8f9: "rub" -0xb8fa: "rubs" -0xb8fb: "rus" -0xb8fc: "russ" -0xb8fd: "rung" -0xb8fe: "ruj" -0xb8ff: "ruc" -/* x0b9 */ -0xb900: "ruk" -0xb901: "rut" -0xb902: "rup" -0xb903: "ruh" -0xb904: "rweo" -0xb905: "rweog" -0xb906: "rweogg" -0xb907: "rweogs" -0xb908: "rweon" -0xb909: "rweonj" -0xb90a: "rweonh" -0xb90b: "rweod" -0xb90c: "rweol" -0xb90d: "rweolg" -0xb90e: "rweolm" -0xb90f: "rweolb" -0xb910: "rweols" -0xb911: "rweolt" -0xb912: "rweolp" -0xb913: "rweolh" -0xb914: "rweom" -0xb915: "rweob" -0xb916: "rweobs" -0xb917: "rweos" -0xb918: "rweoss" -0xb919: "rweong" -0xb91a: "rweoj" -0xb91b: "rweoc" -0xb91c: "rweok" -0xb91d: "rweot" -0xb91e: "rweop" -0xb91f: "rweoh" -0xb920: "rwe" -0xb921: "rweg" -0xb922: "rwegg" -0xb923: "rwegs" -0xb924: "rwen" -0xb925: "rwenj" -0xb926: "rwenh" -0xb927: "rwed" -0xb928: "rwel" -0xb929: "rwelg" -0xb92a: "rwelm" -0xb92b: "rwelb" -0xb92c: "rwels" -0xb92d: "rwelt" -0xb92e: "rwelp" -0xb92f: "rwelh" -0xb930: "rwem" -0xb931: "rweb" -0xb932: "rwebs" -0xb933: "rwes" -0xb934: "rwess" -0xb935: "rweng" -0xb936: "rwej" -0xb937: "rwec" -0xb938: "rwek" -0xb939: "rwet" -0xb93a: "rwep" -0xb93b: "rweh" -0xb93c: "rwi" -0xb93d: "rwig" -0xb93e: "rwigg" -0xb93f: "rwigs" -0xb940: "rwin" -0xb941: "rwinj" -0xb942: "rwinh" -0xb943: "rwid" -0xb944: "rwil" -0xb945: "rwilg" -0xb946: "rwilm" -0xb947: "rwilb" -0xb948: "rwils" -0xb949: "rwilt" -0xb94a: "rwilp" -0xb94b: "rwilh" -0xb94c: "rwim" -0xb94d: "rwib" -0xb94e: "rwibs" -0xb94f: "rwis" -0xb950: "rwiss" -0xb951: "rwing" -0xb952: "rwij" -0xb953: "rwic" -0xb954: "rwik" -0xb955: "rwit" -0xb956: "rwip" -0xb957: "rwih" -0xb958: "ryu" -0xb959: "ryug" -0xb95a: "ryugg" -0xb95b: "ryugs" -0xb95c: "ryun" -0xb95d: "ryunj" -0xb95e: "ryunh" -0xb95f: "ryud" -0xb960: "ryul" -0xb961: "ryulg" -0xb962: "ryulm" -0xb963: "ryulb" -0xb964: "ryuls" -0xb965: "ryult" -0xb966: "ryulp" -0xb967: "ryulh" -0xb968: "ryum" -0xb969: "ryub" -0xb96a: "ryubs" -0xb96b: "ryus" -0xb96c: "ryuss" -0xb96d: "ryung" -0xb96e: "ryuj" -0xb96f: "ryuc" -0xb970: "ryuk" -0xb971: "ryut" -0xb972: "ryup" -0xb973: "ryuh" -0xb974: "reu" -0xb975: "reug" -0xb976: "reugg" -0xb977: "reugs" -0xb978: "reun" -0xb979: "reunj" -0xb97a: "reunh" -0xb97b: "reud" -0xb97c: "reul" -0xb97d: "reulg" -0xb97e: "reulm" -0xb97f: "reulb" -0xb980: "reuls" -0xb981: "reult" -0xb982: "reulp" -0xb983: "reulh" -0xb984: "reum" -0xb985: "reub" -0xb986: "reubs" -0xb987: "reus" -0xb988: "reuss" -0xb989: "reung" -0xb98a: "reuj" -0xb98b: "reuc" -0xb98c: "reuk" -0xb98d: "reut" -0xb98e: "reup" -0xb98f: "reuh" -0xb990: "ryi" -0xb991: "ryig" -0xb992: "ryigg" -0xb993: "ryigs" -0xb994: "ryin" -0xb995: "ryinj" -0xb996: "ryinh" -0xb997: "ryid" -0xb998: "ryil" -0xb999: "ryilg" -0xb99a: "ryilm" -0xb99b: "ryilb" -0xb99c: "ryils" -0xb99d: "ryilt" -0xb99e: "ryilp" -0xb99f: "ryilh" -0xb9a0: "ryim" -0xb9a1: "ryib" -0xb9a2: "ryibs" -0xb9a3: "ryis" -0xb9a4: "ryiss" -0xb9a5: "rying" -0xb9a6: "ryij" -0xb9a7: "ryic" -0xb9a8: "ryik" -0xb9a9: "ryit" -0xb9aa: "ryip" -0xb9ab: "ryih" -0xb9ac: "ri" -0xb9ad: "rig" -0xb9ae: "rigg" -0xb9af: "rigs" -0xb9b0: "rin" -0xb9b1: "rinj" -0xb9b2: "rinh" -0xb9b3: "rid" -0xb9b4: "ril" -0xb9b5: "rilg" -0xb9b6: "rilm" -0xb9b7: "rilb" -0xb9b8: "rils" -0xb9b9: "rilt" -0xb9ba: "rilp" -0xb9bb: "rilh" -0xb9bc: "rim" -0xb9bd: "rib" -0xb9be: "ribs" -0xb9bf: "ris" -0xb9c0: "riss" -0xb9c1: "ring" -0xb9c2: "rij" -0xb9c3: "ric" -0xb9c4: "rik" -0xb9c5: "rit" -0xb9c6: "rip" -0xb9c7: "rih" -0xb9c8: "ma" -0xb9c9: "mag" -0xb9ca: "magg" -0xb9cb: "mags" -0xb9cc: "man" -0xb9cd: "manj" -0xb9ce: "manh" -0xb9cf: "mad" -0xb9d0: "mal" -0xb9d1: "malg" -0xb9d2: "malm" -0xb9d3: "malb" -0xb9d4: "mals" -0xb9d5: "malt" -0xb9d6: "malp" -0xb9d7: "malh" -0xb9d8: "mam" -0xb9d9: "mab" -0xb9da: "mabs" -0xb9db: "mas" -0xb9dc: "mass" -0xb9dd: "mang" -0xb9de: "maj" -0xb9df: "mac" -0xb9e0: "mak" -0xb9e1: "mat" -0xb9e2: "map" -0xb9e3: "mah" -0xb9e4: "mae" -0xb9e5: "maeg" -0xb9e6: "maegg" -0xb9e7: "maegs" -0xb9e8: "maen" -0xb9e9: "maenj" -0xb9ea: "maenh" -0xb9eb: "maed" -0xb9ec: "mael" -0xb9ed: "maelg" -0xb9ee: "maelm" -0xb9ef: "maelb" -0xb9f0: "maels" -0xb9f1: "maelt" -0xb9f2: "maelp" -0xb9f3: "maelh" -0xb9f4: "maem" -0xb9f5: "maeb" -0xb9f6: "maebs" -0xb9f7: "maes" -0xb9f8: "maess" -0xb9f9: "maeng" -0xb9fa: "maej" -0xb9fb: "maec" -0xb9fc: "maek" -0xb9fd: "maet" -0xb9fe: "maep" -0xb9ff: "maeh" -/* x0ba */ -0xba00: "mya" -0xba01: "myag" -0xba02: "myagg" -0xba03: "myags" -0xba04: "myan" -0xba05: "myanj" -0xba06: "myanh" -0xba07: "myad" -0xba08: "myal" -0xba09: "myalg" -0xba0a: "myalm" -0xba0b: "myalb" -0xba0c: "myals" -0xba0d: "myalt" -0xba0e: "myalp" -0xba0f: "myalh" -0xba10: "myam" -0xba11: "myab" -0xba12: "myabs" -0xba13: "myas" -0xba14: "myass" -0xba15: "myang" -0xba16: "myaj" -0xba17: "myac" -0xba18: "myak" -0xba19: "myat" -0xba1a: "myap" -0xba1b: "myah" -0xba1c: "myae" -0xba1d: "myaeg" -0xba1e: "myaegg" -0xba1f: "myaegs" -0xba20: "myaen" -0xba21: "myaenj" -0xba22: "myaenh" -0xba23: "myaed" -0xba24: "myael" -0xba25: "myaelg" -0xba26: "myaelm" -0xba27: "myaelb" -0xba28: "myaels" -0xba29: "myaelt" -0xba2a: "myaelp" -0xba2b: "myaelh" -0xba2c: "myaem" -0xba2d: "myaeb" -0xba2e: "myaebs" -0xba2f: "myaes" -0xba30: "myaess" -0xba31: "myaeng" -0xba32: "myaej" -0xba33: "myaec" -0xba34: "myaek" -0xba35: "myaet" -0xba36: "myaep" -0xba37: "myaeh" -0xba38: "meo" -0xba39: "meog" -0xba3a: "meogg" -0xba3b: "meogs" -0xba3c: "meon" -0xba3d: "meonj" -0xba3e: "meonh" -0xba3f: "meod" -0xba40: "meol" -0xba41: "meolg" -0xba42: "meolm" -0xba43: "meolb" -0xba44: "meols" -0xba45: "meolt" -0xba46: "meolp" -0xba47: "meolh" -0xba48: "meom" -0xba49: "meob" -0xba4a: "meobs" -0xba4b: "meos" -0xba4c: "meoss" -0xba4d: "meong" -0xba4e: "meoj" -0xba4f: "meoc" -0xba50: "meok" -0xba51: "meot" -0xba52: "meop" -0xba53: "meoh" -0xba54: "me" -0xba55: "meg" -0xba56: "megg" -0xba57: "megs" -0xba58: "men" -0xba59: "menj" -0xba5a: "menh" -0xba5b: "med" -0xba5c: "mel" -0xba5d: "melg" -0xba5e: "melm" -0xba5f: "melb" -0xba60: "mels" -0xba61: "melt" -0xba62: "melp" -0xba63: "melh" -0xba64: "mem" -0xba65: "meb" -0xba66: "mebs" -0xba67: "mes" -0xba68: "mess" -0xba69: "meng" -0xba6a: "mej" -0xba6b: "mec" -0xba6c: "mek" -0xba6d: "met" -0xba6e: "mep" -0xba6f: "meh" -0xba70: "myeo" -0xba71: "myeog" -0xba72: "myeogg" -0xba73: "myeogs" -0xba74: "myeon" -0xba75: "myeonj" -0xba76: "myeonh" -0xba77: "myeod" -0xba78: "myeol" -0xba79: "myeolg" -0xba7a: "myeolm" -0xba7b: "myeolb" -0xba7c: "myeols" -0xba7d: "myeolt" -0xba7e: "myeolp" -0xba7f: "myeolh" -0xba80: "myeom" -0xba81: "myeob" -0xba82: "myeobs" -0xba83: "myeos" -0xba84: "myeoss" -0xba85: "myeong" -0xba86: "myeoj" -0xba87: "myeoc" -0xba88: "myeok" -0xba89: "myeot" -0xba8a: "myeop" -0xba8b: "myeoh" -0xba8c: "mye" -0xba8d: "myeg" -0xba8e: "myegg" -0xba8f: "myegs" -0xba90: "myen" -0xba91: "myenj" -0xba92: "myenh" -0xba93: "myed" -0xba94: "myel" -0xba95: "myelg" -0xba96: "myelm" -0xba97: "myelb" -0xba98: "myels" -0xba99: "myelt" -0xba9a: "myelp" -0xba9b: "myelh" -0xba9c: "myem" -0xba9d: "myeb" -0xba9e: "myebs" -0xba9f: "myes" -0xbaa0: "myess" -0xbaa1: "myeng" -0xbaa2: "myej" -0xbaa3: "myec" -0xbaa4: "myek" -0xbaa5: "myet" -0xbaa6: "myep" -0xbaa7: "myeh" -0xbaa8: "mo" -0xbaa9: "mog" -0xbaaa: "mogg" -0xbaab: "mogs" -0xbaac: "mon" -0xbaad: "monj" -0xbaae: "monh" -0xbaaf: "mod" -0xbab0: "mol" -0xbab1: "molg" -0xbab2: "molm" -0xbab3: "molb" -0xbab4: "mols" -0xbab5: "molt" -0xbab6: "molp" -0xbab7: "molh" -0xbab8: "mom" -0xbab9: "mob" -0xbaba: "mobs" -0xbabb: "mos" -0xbabc: "moss" -0xbabd: "mong" -0xbabe: "moj" -0xbabf: "moc" -0xbac0: "mok" -0xbac1: "mot" -0xbac2: "mop" -0xbac3: "moh" -0xbac4: "mwa" -0xbac5: "mwag" -0xbac6: "mwagg" -0xbac7: "mwags" -0xbac8: "mwan" -0xbac9: "mwanj" -0xbaca: "mwanh" -0xbacb: "mwad" -0xbacc: "mwal" -0xbacd: "mwalg" -0xbace: "mwalm" -0xbacf: "mwalb" -0xbad0: "mwals" -0xbad1: "mwalt" -0xbad2: "mwalp" -0xbad3: "mwalh" -0xbad4: "mwam" -0xbad5: "mwab" -0xbad6: "mwabs" -0xbad7: "mwas" -0xbad8: "mwass" -0xbad9: "mwang" -0xbada: "mwaj" -0xbadb: "mwac" -0xbadc: "mwak" -0xbadd: "mwat" -0xbade: "mwap" -0xbadf: "mwah" -0xbae0: "mwae" -0xbae1: "mwaeg" -0xbae2: "mwaegg" -0xbae3: "mwaegs" -0xbae4: "mwaen" -0xbae5: "mwaenj" -0xbae6: "mwaenh" -0xbae7: "mwaed" -0xbae8: "mwael" -0xbae9: "mwaelg" -0xbaea: "mwaelm" -0xbaeb: "mwaelb" -0xbaec: "mwaels" -0xbaed: "mwaelt" -0xbaee: "mwaelp" -0xbaef: "mwaelh" -0xbaf0: "mwaem" -0xbaf1: "mwaeb" -0xbaf2: "mwaebs" -0xbaf3: "mwaes" -0xbaf4: "mwaess" -0xbaf5: "mwaeng" -0xbaf6: "mwaej" -0xbaf7: "mwaec" -0xbaf8: "mwaek" -0xbaf9: "mwaet" -0xbafa: "mwaep" -0xbafb: "mwaeh" -0xbafc: "moe" -0xbafd: "moeg" -0xbafe: "moegg" -0xbaff: "moegs" -/* x0bb */ -0xbb00: "moen" -0xbb01: "moenj" -0xbb02: "moenh" -0xbb03: "moed" -0xbb04: "moel" -0xbb05: "moelg" -0xbb06: "moelm" -0xbb07: "moelb" -0xbb08: "moels" -0xbb09: "moelt" -0xbb0a: "moelp" -0xbb0b: "moelh" -0xbb0c: "moem" -0xbb0d: "moeb" -0xbb0e: "moebs" -0xbb0f: "moes" -0xbb10: "moess" -0xbb11: "moeng" -0xbb12: "moej" -0xbb13: "moec" -0xbb14: "moek" -0xbb15: "moet" -0xbb16: "moep" -0xbb17: "moeh" -0xbb18: "myo" -0xbb19: "myog" -0xbb1a: "myogg" -0xbb1b: "myogs" -0xbb1c: "myon" -0xbb1d: "myonj" -0xbb1e: "myonh" -0xbb1f: "myod" -0xbb20: "myol" -0xbb21: "myolg" -0xbb22: "myolm" -0xbb23: "myolb" -0xbb24: "myols" -0xbb25: "myolt" -0xbb26: "myolp" -0xbb27: "myolh" -0xbb28: "myom" -0xbb29: "myob" -0xbb2a: "myobs" -0xbb2b: "myos" -0xbb2c: "myoss" -0xbb2d: "myong" -0xbb2e: "myoj" -0xbb2f: "myoc" -0xbb30: "myok" -0xbb31: "myot" -0xbb32: "myop" -0xbb33: "myoh" -0xbb34: "mu" -0xbb35: "mug" -0xbb36: "mugg" -0xbb37: "mugs" -0xbb38: "mun" -0xbb39: "munj" -0xbb3a: "munh" -0xbb3b: "mud" -0xbb3c: "mul" -0xbb3d: "mulg" -0xbb3e: "mulm" -0xbb3f: "mulb" -0xbb40: "muls" -0xbb41: "mult" -0xbb42: "mulp" -0xbb43: "mulh" -0xbb44: "mum" -0xbb45: "mub" -0xbb46: "mubs" -0xbb47: "mus" -0xbb48: "muss" -0xbb49: "mung" -0xbb4a: "muj" -0xbb4b: "muc" -0xbb4c: "muk" -0xbb4d: "mut" -0xbb4e: "mup" -0xbb4f: "muh" -0xbb50: "mweo" -0xbb51: "mweog" -0xbb52: "mweogg" -0xbb53: "mweogs" -0xbb54: "mweon" -0xbb55: "mweonj" -0xbb56: "mweonh" -0xbb57: "mweod" -0xbb58: "mweol" -0xbb59: "mweolg" -0xbb5a: "mweolm" -0xbb5b: "mweolb" -0xbb5c: "mweols" -0xbb5d: "mweolt" -0xbb5e: "mweolp" -0xbb5f: "mweolh" -0xbb60: "mweom" -0xbb61: "mweob" -0xbb62: "mweobs" -0xbb63: "mweos" -0xbb64: "mweoss" -0xbb65: "mweong" -0xbb66: "mweoj" -0xbb67: "mweoc" -0xbb68: "mweok" -0xbb69: "mweot" -0xbb6a: "mweop" -0xbb6b: "mweoh" -0xbb6c: "mwe" -0xbb6d: "mweg" -0xbb6e: "mwegg" -0xbb6f: "mwegs" -0xbb70: "mwen" -0xbb71: "mwenj" -0xbb72: "mwenh" -0xbb73: "mwed" -0xbb74: "mwel" -0xbb75: "mwelg" -0xbb76: "mwelm" -0xbb77: "mwelb" -0xbb78: "mwels" -0xbb79: "mwelt" -0xbb7a: "mwelp" -0xbb7b: "mwelh" -0xbb7c: "mwem" -0xbb7d: "mweb" -0xbb7e: "mwebs" -0xbb7f: "mwes" -0xbb80: "mwess" -0xbb81: "mweng" -0xbb82: "mwej" -0xbb83: "mwec" -0xbb84: "mwek" -0xbb85: "mwet" -0xbb86: "mwep" -0xbb87: "mweh" -0xbb88: "mwi" -0xbb89: "mwig" -0xbb8a: "mwigg" -0xbb8b: "mwigs" -0xbb8c: "mwin" -0xbb8d: "mwinj" -0xbb8e: "mwinh" -0xbb8f: "mwid" -0xbb90: "mwil" -0xbb91: "mwilg" -0xbb92: "mwilm" -0xbb93: "mwilb" -0xbb94: "mwils" -0xbb95: "mwilt" -0xbb96: "mwilp" -0xbb97: "mwilh" -0xbb98: "mwim" -0xbb99: "mwib" -0xbb9a: "mwibs" -0xbb9b: "mwis" -0xbb9c: "mwiss" -0xbb9d: "mwing" -0xbb9e: "mwij" -0xbb9f: "mwic" -0xbba0: "mwik" -0xbba1: "mwit" -0xbba2: "mwip" -0xbba3: "mwih" -0xbba4: "myu" -0xbba5: "myug" -0xbba6: "myugg" -0xbba7: "myugs" -0xbba8: "myun" -0xbba9: "myunj" -0xbbaa: "myunh" -0xbbab: "myud" -0xbbac: "myul" -0xbbad: "myulg" -0xbbae: "myulm" -0xbbaf: "myulb" -0xbbb0: "myuls" -0xbbb1: "myult" -0xbbb2: "myulp" -0xbbb3: "myulh" -0xbbb4: "myum" -0xbbb5: "myub" -0xbbb6: "myubs" -0xbbb7: "myus" -0xbbb8: "myuss" -0xbbb9: "myung" -0xbbba: "myuj" -0xbbbb: "myuc" -0xbbbc: "myuk" -0xbbbd: "myut" -0xbbbe: "myup" -0xbbbf: "myuh" -0xbbc0: "meu" -0xbbc1: "meug" -0xbbc2: "meugg" -0xbbc3: "meugs" -0xbbc4: "meun" -0xbbc5: "meunj" -0xbbc6: "meunh" -0xbbc7: "meud" -0xbbc8: "meul" -0xbbc9: "meulg" -0xbbca: "meulm" -0xbbcb: "meulb" -0xbbcc: "meuls" -0xbbcd: "meult" -0xbbce: "meulp" -0xbbcf: "meulh" -0xbbd0: "meum" -0xbbd1: "meub" -0xbbd2: "meubs" -0xbbd3: "meus" -0xbbd4: "meuss" -0xbbd5: "meung" -0xbbd6: "meuj" -0xbbd7: "meuc" -0xbbd8: "meuk" -0xbbd9: "meut" -0xbbda: "meup" -0xbbdb: "meuh" -0xbbdc: "myi" -0xbbdd: "myig" -0xbbde: "myigg" -0xbbdf: "myigs" -0xbbe0: "myin" -0xbbe1: "myinj" -0xbbe2: "myinh" -0xbbe3: "myid" -0xbbe4: "myil" -0xbbe5: "myilg" -0xbbe6: "myilm" -0xbbe7: "myilb" -0xbbe8: "myils" -0xbbe9: "myilt" -0xbbea: "myilp" -0xbbeb: "myilh" -0xbbec: "myim" -0xbbed: "myib" -0xbbee: "myibs" -0xbbef: "myis" -0xbbf0: "myiss" -0xbbf1: "mying" -0xbbf2: "myij" -0xbbf3: "myic" -0xbbf4: "myik" -0xbbf5: "myit" -0xbbf6: "myip" -0xbbf7: "myih" -0xbbf8: "mi" -0xbbf9: "mig" -0xbbfa: "migg" -0xbbfb: "migs" -0xbbfc: "min" -0xbbfd: "minj" -0xbbfe: "minh" -0xbbff: "mid" -/* x0bc */ -0xbc00: "mil" -0xbc01: "milg" -0xbc02: "milm" -0xbc03: "milb" -0xbc04: "mils" -0xbc05: "milt" -0xbc06: "milp" -0xbc07: "milh" -0xbc08: "mim" -0xbc09: "mib" -0xbc0a: "mibs" -0xbc0b: "mis" -0xbc0c: "miss" -0xbc0d: "ming" -0xbc0e: "mij" -0xbc0f: "mic" -0xbc10: "mik" -0xbc11: "mit" -0xbc12: "mip" -0xbc13: "mih" -0xbc14: "ba" -0xbc15: "bag" -0xbc16: "bagg" -0xbc17: "bags" -0xbc18: "ban" -0xbc19: "banj" -0xbc1a: "banh" -0xbc1b: "bad" -0xbc1c: "bal" -0xbc1d: "balg" -0xbc1e: "balm" -0xbc1f: "balb" -0xbc20: "bals" -0xbc21: "balt" -0xbc22: "balp" -0xbc23: "balh" -0xbc24: "bam" -0xbc25: "bab" -0xbc26: "babs" -0xbc27: "bas" -0xbc28: "bass" -0xbc29: "bang" -0xbc2a: "baj" -0xbc2b: "bac" -0xbc2c: "bak" -0xbc2d: "bat" -0xbc2e: "bap" -0xbc2f: "bah" -0xbc30: "bae" -0xbc31: "baeg" -0xbc32: "baegg" -0xbc33: "baegs" -0xbc34: "baen" -0xbc35: "baenj" -0xbc36: "baenh" -0xbc37: "baed" -0xbc38: "bael" -0xbc39: "baelg" -0xbc3a: "baelm" -0xbc3b: "baelb" -0xbc3c: "baels" -0xbc3d: "baelt" -0xbc3e: "baelp" -0xbc3f: "baelh" -0xbc40: "baem" -0xbc41: "baeb" -0xbc42: "baebs" -0xbc43: "baes" -0xbc44: "baess" -0xbc45: "baeng" -0xbc46: "baej" -0xbc47: "baec" -0xbc48: "baek" -0xbc49: "baet" -0xbc4a: "baep" -0xbc4b: "baeh" -0xbc4c: "bya" -0xbc4d: "byag" -0xbc4e: "byagg" -0xbc4f: "byags" -0xbc50: "byan" -0xbc51: "byanj" -0xbc52: "byanh" -0xbc53: "byad" -0xbc54: "byal" -0xbc55: "byalg" -0xbc56: "byalm" -0xbc57: "byalb" -0xbc58: "byals" -0xbc59: "byalt" -0xbc5a: "byalp" -0xbc5b: "byalh" -0xbc5c: "byam" -0xbc5d: "byab" -0xbc5e: "byabs" -0xbc5f: "byas" -0xbc60: "byass" -0xbc61: "byang" -0xbc62: "byaj" -0xbc63: "byac" -0xbc64: "byak" -0xbc65: "byat" -0xbc66: "byap" -0xbc67: "byah" -0xbc68: "byae" -0xbc69: "byaeg" -0xbc6a: "byaegg" -0xbc6b: "byaegs" -0xbc6c: "byaen" -0xbc6d: "byaenj" -0xbc6e: "byaenh" -0xbc6f: "byaed" -0xbc70: "byael" -0xbc71: "byaelg" -0xbc72: "byaelm" -0xbc73: "byaelb" -0xbc74: "byaels" -0xbc75: "byaelt" -0xbc76: "byaelp" -0xbc77: "byaelh" -0xbc78: "byaem" -0xbc79: "byaeb" -0xbc7a: "byaebs" -0xbc7b: "byaes" -0xbc7c: "byaess" -0xbc7d: "byaeng" -0xbc7e: "byaej" -0xbc7f: "byaec" -0xbc80: "byaek" -0xbc81: "byaet" -0xbc82: "byaep" -0xbc83: "byaeh" -0xbc84: "beo" -0xbc85: "beog" -0xbc86: "beogg" -0xbc87: "beogs" -0xbc88: "beon" -0xbc89: "beonj" -0xbc8a: "beonh" -0xbc8b: "beod" -0xbc8c: "beol" -0xbc8d: "beolg" -0xbc8e: "beolm" -0xbc8f: "beolb" -0xbc90: "beols" -0xbc91: "beolt" -0xbc92: "beolp" -0xbc93: "beolh" -0xbc94: "beom" -0xbc95: "beob" -0xbc96: "beobs" -0xbc97: "beos" -0xbc98: "beoss" -0xbc99: "beong" -0xbc9a: "beoj" -0xbc9b: "beoc" -0xbc9c: "beok" -0xbc9d: "beot" -0xbc9e: "beop" -0xbc9f: "beoh" -0xbca0: "be" -0xbca1: "beg" -0xbca2: "begg" -0xbca3: "begs" -0xbca4: "ben" -0xbca5: "benj" -0xbca6: "benh" -0xbca7: "bed" -0xbca8: "bel" -0xbca9: "belg" -0xbcaa: "belm" -0xbcab: "belb" -0xbcac: "bels" -0xbcad: "belt" -0xbcae: "belp" -0xbcaf: "belh" -0xbcb0: "bem" -0xbcb1: "beb" -0xbcb2: "bebs" -0xbcb3: "bes" -0xbcb4: "bess" -0xbcb5: "beng" -0xbcb6: "bej" -0xbcb7: "bec" -0xbcb8: "bek" -0xbcb9: "bet" -0xbcba: "bep" -0xbcbb: "beh" -0xbcbc: "byeo" -0xbcbd: "byeog" -0xbcbe: "byeogg" -0xbcbf: "byeogs" -0xbcc0: "byeon" -0xbcc1: "byeonj" -0xbcc2: "byeonh" -0xbcc3: "byeod" -0xbcc4: "byeol" -0xbcc5: "byeolg" -0xbcc6: "byeolm" -0xbcc7: "byeolb" -0xbcc8: "byeols" -0xbcc9: "byeolt" -0xbcca: "byeolp" -0xbccb: "byeolh" -0xbccc: "byeom" -0xbccd: "byeob" -0xbcce: "byeobs" -0xbccf: "byeos" -0xbcd0: "byeoss" -0xbcd1: "byeong" -0xbcd2: "byeoj" -0xbcd3: "byeoc" -0xbcd4: "byeok" -0xbcd5: "byeot" -0xbcd6: "byeop" -0xbcd7: "byeoh" -0xbcd8: "bye" -0xbcd9: "byeg" -0xbcda: "byegg" -0xbcdb: "byegs" -0xbcdc: "byen" -0xbcdd: "byenj" -0xbcde: "byenh" -0xbcdf: "byed" -0xbce0: "byel" -0xbce1: "byelg" -0xbce2: "byelm" -0xbce3: "byelb" -0xbce4: "byels" -0xbce5: "byelt" -0xbce6: "byelp" -0xbce7: "byelh" -0xbce8: "byem" -0xbce9: "byeb" -0xbcea: "byebs" -0xbceb: "byes" -0xbcec: "byess" -0xbced: "byeng" -0xbcee: "byej" -0xbcef: "byec" -0xbcf0: "byek" -0xbcf1: "byet" -0xbcf2: "byep" -0xbcf3: "byeh" -0xbcf4: "bo" -0xbcf5: "bog" -0xbcf6: "bogg" -0xbcf7: "bogs" -0xbcf8: "bon" -0xbcf9: "bonj" -0xbcfa: "bonh" -0xbcfb: "bod" -0xbcfc: "bol" -0xbcfd: "bolg" -0xbcfe: "bolm" -0xbcff: "bolb" -/* x0bd */ -0xbd00: "bols" -0xbd01: "bolt" -0xbd02: "bolp" -0xbd03: "bolh" -0xbd04: "bom" -0xbd05: "bob" -0xbd06: "bobs" -0xbd07: "bos" -0xbd08: "boss" -0xbd09: "bong" -0xbd0a: "boj" -0xbd0b: "boc" -0xbd0c: "bok" -0xbd0d: "bot" -0xbd0e: "bop" -0xbd0f: "boh" -0xbd10: "bwa" -0xbd11: "bwag" -0xbd12: "bwagg" -0xbd13: "bwags" -0xbd14: "bwan" -0xbd15: "bwanj" -0xbd16: "bwanh" -0xbd17: "bwad" -0xbd18: "bwal" -0xbd19: "bwalg" -0xbd1a: "bwalm" -0xbd1b: "bwalb" -0xbd1c: "bwals" -0xbd1d: "bwalt" -0xbd1e: "bwalp" -0xbd1f: "bwalh" -0xbd20: "bwam" -0xbd21: "bwab" -0xbd22: "bwabs" -0xbd23: "bwas" -0xbd24: "bwass" -0xbd25: "bwang" -0xbd26: "bwaj" -0xbd27: "bwac" -0xbd28: "bwak" -0xbd29: "bwat" -0xbd2a: "bwap" -0xbd2b: "bwah" -0xbd2c: "bwae" -0xbd2d: "bwaeg" -0xbd2e: "bwaegg" -0xbd2f: "bwaegs" -0xbd30: "bwaen" -0xbd31: "bwaenj" -0xbd32: "bwaenh" -0xbd33: "bwaed" -0xbd34: "bwael" -0xbd35: "bwaelg" -0xbd36: "bwaelm" -0xbd37: "bwaelb" -0xbd38: "bwaels" -0xbd39: "bwaelt" -0xbd3a: "bwaelp" -0xbd3b: "bwaelh" -0xbd3c: "bwaem" -0xbd3d: "bwaeb" -0xbd3e: "bwaebs" -0xbd3f: "bwaes" -0xbd40: "bwaess" -0xbd41: "bwaeng" -0xbd42: "bwaej" -0xbd43: "bwaec" -0xbd44: "bwaek" -0xbd45: "bwaet" -0xbd46: "bwaep" -0xbd47: "bwaeh" -0xbd48: "boe" -0xbd49: "boeg" -0xbd4a: "boegg" -0xbd4b: "boegs" -0xbd4c: "boen" -0xbd4d: "boenj" -0xbd4e: "boenh" -0xbd4f: "boed" -0xbd50: "boel" -0xbd51: "boelg" -0xbd52: "boelm" -0xbd53: "boelb" -0xbd54: "boels" -0xbd55: "boelt" -0xbd56: "boelp" -0xbd57: "boelh" -0xbd58: "boem" -0xbd59: "boeb" -0xbd5a: "boebs" -0xbd5b: "boes" -0xbd5c: "boess" -0xbd5d: "boeng" -0xbd5e: "boej" -0xbd5f: "boec" -0xbd60: "boek" -0xbd61: "boet" -0xbd62: "boep" -0xbd63: "boeh" -0xbd64: "byo" -0xbd65: "byog" -0xbd66: "byogg" -0xbd67: "byogs" -0xbd68: "byon" -0xbd69: "byonj" -0xbd6a: "byonh" -0xbd6b: "byod" -0xbd6c: "byol" -0xbd6d: "byolg" -0xbd6e: "byolm" -0xbd6f: "byolb" -0xbd70: "byols" -0xbd71: "byolt" -0xbd72: "byolp" -0xbd73: "byolh" -0xbd74: "byom" -0xbd75: "byob" -0xbd76: "byobs" -0xbd77: "byos" -0xbd78: "byoss" -0xbd79: "byong" -0xbd7a: "byoj" -0xbd7b: "byoc" -0xbd7c: "byok" -0xbd7d: "byot" -0xbd7e: "byop" -0xbd7f: "byoh" -0xbd80: "bu" -0xbd81: "bug" -0xbd82: "bugg" -0xbd83: "bugs" -0xbd84: "bun" -0xbd85: "bunj" -0xbd86: "bunh" -0xbd87: "bud" -0xbd88: "bul" -0xbd89: "bulg" -0xbd8a: "bulm" -0xbd8b: "bulb" -0xbd8c: "buls" -0xbd8d: "bult" -0xbd8e: "bulp" -0xbd8f: "bulh" -0xbd90: "bum" -0xbd91: "bub" -0xbd92: "bubs" -0xbd93: "bus" -0xbd94: "buss" -0xbd95: "bung" -0xbd96: "buj" -0xbd97: "buc" -0xbd98: "buk" -0xbd99: "but" -0xbd9a: "bup" -0xbd9b: "buh" -0xbd9c: "bweo" -0xbd9d: "bweog" -0xbd9e: "bweogg" -0xbd9f: "bweogs" -0xbda0: "bweon" -0xbda1: "bweonj" -0xbda2: "bweonh" -0xbda3: "bweod" -0xbda4: "bweol" -0xbda5: "bweolg" -0xbda6: "bweolm" -0xbda7: "bweolb" -0xbda8: "bweols" -0xbda9: "bweolt" -0xbdaa: "bweolp" -0xbdab: "bweolh" -0xbdac: "bweom" -0xbdad: "bweob" -0xbdae: "bweobs" -0xbdaf: "bweos" -0xbdb0: "bweoss" -0xbdb1: "bweong" -0xbdb2: "bweoj" -0xbdb3: "bweoc" -0xbdb4: "bweok" -0xbdb5: "bweot" -0xbdb6: "bweop" -0xbdb7: "bweoh" -0xbdb8: "bwe" -0xbdb9: "bweg" -0xbdba: "bwegg" -0xbdbb: "bwegs" -0xbdbc: "bwen" -0xbdbd: "bwenj" -0xbdbe: "bwenh" -0xbdbf: "bwed" -0xbdc0: "bwel" -0xbdc1: "bwelg" -0xbdc2: "bwelm" -0xbdc3: "bwelb" -0xbdc4: "bwels" -0xbdc5: "bwelt" -0xbdc6: "bwelp" -0xbdc7: "bwelh" -0xbdc8: "bwem" -0xbdc9: "bweb" -0xbdca: "bwebs" -0xbdcb: "bwes" -0xbdcc: "bwess" -0xbdcd: "bweng" -0xbdce: "bwej" -0xbdcf: "bwec" -0xbdd0: "bwek" -0xbdd1: "bwet" -0xbdd2: "bwep" -0xbdd3: "bweh" -0xbdd4: "bwi" -0xbdd5: "bwig" -0xbdd6: "bwigg" -0xbdd7: "bwigs" -0xbdd8: "bwin" -0xbdd9: "bwinj" -0xbdda: "bwinh" -0xbddb: "bwid" -0xbddc: "bwil" -0xbddd: "bwilg" -0xbdde: "bwilm" -0xbddf: "bwilb" -0xbde0: "bwils" -0xbde1: "bwilt" -0xbde2: "bwilp" -0xbde3: "bwilh" -0xbde4: "bwim" -0xbde5: "bwib" -0xbde6: "bwibs" -0xbde7: "bwis" -0xbde8: "bwiss" -0xbde9: "bwing" -0xbdea: "bwij" -0xbdeb: "bwic" -0xbdec: "bwik" -0xbded: "bwit" -0xbdee: "bwip" -0xbdef: "bwih" -0xbdf0: "byu" -0xbdf1: "byug" -0xbdf2: "byugg" -0xbdf3: "byugs" -0xbdf4: "byun" -0xbdf5: "byunj" -0xbdf6: "byunh" -0xbdf7: "byud" -0xbdf8: "byul" -0xbdf9: "byulg" -0xbdfa: "byulm" -0xbdfb: "byulb" -0xbdfc: "byuls" -0xbdfd: "byult" -0xbdfe: "byulp" -0xbdff: "byulh" -/* x0be */ -0xbe00: "byum" -0xbe01: "byub" -0xbe02: "byubs" -0xbe03: "byus" -0xbe04: "byuss" -0xbe05: "byung" -0xbe06: "byuj" -0xbe07: "byuc" -0xbe08: "byuk" -0xbe09: "byut" -0xbe0a: "byup" -0xbe0b: "byuh" -0xbe0c: "beu" -0xbe0d: "beug" -0xbe0e: "beugg" -0xbe0f: "beugs" -0xbe10: "beun" -0xbe11: "beunj" -0xbe12: "beunh" -0xbe13: "beud" -0xbe14: "beul" -0xbe15: "beulg" -0xbe16: "beulm" -0xbe17: "beulb" -0xbe18: "beuls" -0xbe19: "beult" -0xbe1a: "beulp" -0xbe1b: "beulh" -0xbe1c: "beum" -0xbe1d: "beub" -0xbe1e: "beubs" -0xbe1f: "beus" -0xbe20: "beuss" -0xbe21: "beung" -0xbe22: "beuj" -0xbe23: "beuc" -0xbe24: "beuk" -0xbe25: "beut" -0xbe26: "beup" -0xbe27: "beuh" -0xbe28: "byi" -0xbe29: "byig" -0xbe2a: "byigg" -0xbe2b: "byigs" -0xbe2c: "byin" -0xbe2d: "byinj" -0xbe2e: "byinh" -0xbe2f: "byid" -0xbe30: "byil" -0xbe31: "byilg" -0xbe32: "byilm" -0xbe33: "byilb" -0xbe34: "byils" -0xbe35: "byilt" -0xbe36: "byilp" -0xbe37: "byilh" -0xbe38: "byim" -0xbe39: "byib" -0xbe3a: "byibs" -0xbe3b: "byis" -0xbe3c: "byiss" -0xbe3d: "bying" -0xbe3e: "byij" -0xbe3f: "byic" -0xbe40: "byik" -0xbe41: "byit" -0xbe42: "byip" -0xbe43: "byih" -0xbe44: "bi" -0xbe45: "big" -0xbe46: "bigg" -0xbe47: "bigs" -0xbe48: "bin" -0xbe49: "binj" -0xbe4a: "binh" -0xbe4b: "bid" -0xbe4c: "bil" -0xbe4d: "bilg" -0xbe4e: "bilm" -0xbe4f: "bilb" -0xbe50: "bils" -0xbe51: "bilt" -0xbe52: "bilp" -0xbe53: "bilh" -0xbe54: "bim" -0xbe55: "bib" -0xbe56: "bibs" -0xbe57: "bis" -0xbe58: "biss" -0xbe59: "bing" -0xbe5a: "bij" -0xbe5b: "bic" -0xbe5c: "bik" -0xbe5d: "bit" -0xbe5e: "bip" -0xbe5f: "bih" -0xbe60: "bba" -0xbe61: "bbag" -0xbe62: "bbagg" -0xbe63: "bbags" -0xbe64: "bban" -0xbe65: "bbanj" -0xbe66: "bbanh" -0xbe67: "bbad" -0xbe68: "bbal" -0xbe69: "bbalg" -0xbe6a: "bbalm" -0xbe6b: "bbalb" -0xbe6c: "bbals" -0xbe6d: "bbalt" -0xbe6e: "bbalp" -0xbe6f: "bbalh" -0xbe70: "bbam" -0xbe71: "bbab" -0xbe72: "bbabs" -0xbe73: "bbas" -0xbe74: "bbass" -0xbe75: "bbang" -0xbe76: "bbaj" -0xbe77: "bbac" -0xbe78: "bbak" -0xbe79: "bbat" -0xbe7a: "bbap" -0xbe7b: "bbah" -0xbe7c: "bbae" -0xbe7d: "bbaeg" -0xbe7e: "bbaegg" -0xbe7f: "bbaegs" -0xbe80: "bbaen" -0xbe81: "bbaenj" -0xbe82: "bbaenh" -0xbe83: "bbaed" -0xbe84: "bbael" -0xbe85: "bbaelg" -0xbe86: "bbaelm" -0xbe87: "bbaelb" -0xbe88: "bbaels" -0xbe89: "bbaelt" -0xbe8a: "bbaelp" -0xbe8b: "bbaelh" -0xbe8c: "bbaem" -0xbe8d: "bbaeb" -0xbe8e: "bbaebs" -0xbe8f: "bbaes" -0xbe90: "bbaess" -0xbe91: "bbaeng" -0xbe92: "bbaej" -0xbe93: "bbaec" -0xbe94: "bbaek" -0xbe95: "bbaet" -0xbe96: "bbaep" -0xbe97: "bbaeh" -0xbe98: "bbya" -0xbe99: "bbyag" -0xbe9a: "bbyagg" -0xbe9b: "bbyags" -0xbe9c: "bbyan" -0xbe9d: "bbyanj" -0xbe9e: "bbyanh" -0xbe9f: "bbyad" -0xbea0: "bbyal" -0xbea1: "bbyalg" -0xbea2: "bbyalm" -0xbea3: "bbyalb" -0xbea4: "bbyals" -0xbea5: "bbyalt" -0xbea6: "bbyalp" -0xbea7: "bbyalh" -0xbea8: "bbyam" -0xbea9: "bbyab" -0xbeaa: "bbyabs" -0xbeab: "bbyas" -0xbeac: "bbyass" -0xbead: "bbyang" -0xbeae: "bbyaj" -0xbeaf: "bbyac" -0xbeb0: "bbyak" -0xbeb1: "bbyat" -0xbeb2: "bbyap" -0xbeb3: "bbyah" -0xbeb4: "bbyae" -0xbeb5: "bbyaeg" -0xbeb6: "bbyaegg" -0xbeb7: "bbyaegs" -0xbeb8: "bbyaen" -0xbeb9: "bbyaenj" -0xbeba: "bbyaenh" -0xbebb: "bbyaed" -0xbebc: "bbyael" -0xbebd: "bbyaelg" -0xbebe: "bbyaelm" -0xbebf: "bbyaelb" -0xbec0: "bbyaels" -0xbec1: "bbyaelt" -0xbec2: "bbyaelp" -0xbec3: "bbyaelh" -0xbec4: "bbyaem" -0xbec5: "bbyaeb" -0xbec6: "bbyaebs" -0xbec7: "bbyaes" -0xbec8: "bbyaess" -0xbec9: "bbyaeng" -0xbeca: "bbyaej" -0xbecb: "bbyaec" -0xbecc: "bbyaek" -0xbecd: "bbyaet" -0xbece: "bbyaep" -0xbecf: "bbyaeh" -0xbed0: "bbeo" -0xbed1: "bbeog" -0xbed2: "bbeogg" -0xbed3: "bbeogs" -0xbed4: "bbeon" -0xbed5: "bbeonj" -0xbed6: "bbeonh" -0xbed7: "bbeod" -0xbed8: "bbeol" -0xbed9: "bbeolg" -0xbeda: "bbeolm" -0xbedb: "bbeolb" -0xbedc: "bbeols" -0xbedd: "bbeolt" -0xbede: "bbeolp" -0xbedf: "bbeolh" -0xbee0: "bbeom" -0xbee1: "bbeob" -0xbee2: "bbeobs" -0xbee3: "bbeos" -0xbee4: "bbeoss" -0xbee5: "bbeong" -0xbee6: "bbeoj" -0xbee7: "bbeoc" -0xbee8: "bbeok" -0xbee9: "bbeot" -0xbeea: "bbeop" -0xbeeb: "bbeoh" -0xbeec: "bbe" -0xbeed: "bbeg" -0xbeee: "bbegg" -0xbeef: "bbegs" -0xbef0: "bben" -0xbef1: "bbenj" -0xbef2: "bbenh" -0xbef3: "bbed" -0xbef4: "bbel" -0xbef5: "bbelg" -0xbef6: "bbelm" -0xbef7: "bbelb" -0xbef8: "bbels" -0xbef9: "bbelt" -0xbefa: "bbelp" -0xbefb: "bbelh" -0xbefc: "bbem" -0xbefd: "bbeb" -0xbefe: "bbebs" -0xbeff: "bbes" -/* x0bf */ -0xbf00: "bbess" -0xbf01: "bbeng" -0xbf02: "bbej" -0xbf03: "bbec" -0xbf04: "bbek" -0xbf05: "bbet" -0xbf06: "bbep" -0xbf07: "bbeh" -0xbf08: "bbyeo" -0xbf09: "bbyeog" -0xbf0a: "bbyeogg" -0xbf0b: "bbyeogs" -0xbf0c: "bbyeon" -0xbf0d: "bbyeonj" -0xbf0e: "bbyeonh" -0xbf0f: "bbyeod" -0xbf10: "bbyeol" -0xbf11: "bbyeolg" -0xbf12: "bbyeolm" -0xbf13: "bbyeolb" -0xbf14: "bbyeols" -0xbf15: "bbyeolt" -0xbf16: "bbyeolp" -0xbf17: "bbyeolh" -0xbf18: "bbyeom" -0xbf19: "bbyeob" -0xbf1a: "bbyeobs" -0xbf1b: "bbyeos" -0xbf1c: "bbyeoss" -0xbf1d: "bbyeong" -0xbf1e: "bbyeoj" -0xbf1f: "bbyeoc" -0xbf20: "bbyeok" -0xbf21: "bbyeot" -0xbf22: "bbyeop" -0xbf23: "bbyeoh" -0xbf24: "bbye" -0xbf25: "bbyeg" -0xbf26: "bbyegg" -0xbf27: "bbyegs" -0xbf28: "bbyen" -0xbf29: "bbyenj" -0xbf2a: "bbyenh" -0xbf2b: "bbyed" -0xbf2c: "bbyel" -0xbf2d: "bbyelg" -0xbf2e: "bbyelm" -0xbf2f: "bbyelb" -0xbf30: "bbyels" -0xbf31: "bbyelt" -0xbf32: "bbyelp" -0xbf33: "bbyelh" -0xbf34: "bbyem" -0xbf35: "bbyeb" -0xbf36: "bbyebs" -0xbf37: "bbyes" -0xbf38: "bbyess" -0xbf39: "bbyeng" -0xbf3a: "bbyej" -0xbf3b: "bbyec" -0xbf3c: "bbyek" -0xbf3d: "bbyet" -0xbf3e: "bbyep" -0xbf3f: "bbyeh" -0xbf40: "bbo" -0xbf41: "bbog" -0xbf42: "bbogg" -0xbf43: "bbogs" -0xbf44: "bbon" -0xbf45: "bbonj" -0xbf46: "bbonh" -0xbf47: "bbod" -0xbf48: "bbol" -0xbf49: "bbolg" -0xbf4a: "bbolm" -0xbf4b: "bbolb" -0xbf4c: "bbols" -0xbf4d: "bbolt" -0xbf4e: "bbolp" -0xbf4f: "bbolh" -0xbf50: "bbom" -0xbf51: "bbob" -0xbf52: "bbobs" -0xbf53: "bbos" -0xbf54: "bboss" -0xbf55: "bbong" -0xbf56: "bboj" -0xbf57: "bboc" -0xbf58: "bbok" -0xbf59: "bbot" -0xbf5a: "bbop" -0xbf5b: "bboh" -0xbf5c: "bbwa" -0xbf5d: "bbwag" -0xbf5e: "bbwagg" -0xbf5f: "bbwags" -0xbf60: "bbwan" -0xbf61: "bbwanj" -0xbf62: "bbwanh" -0xbf63: "bbwad" -0xbf64: "bbwal" -0xbf65: "bbwalg" -0xbf66: "bbwalm" -0xbf67: "bbwalb" -0xbf68: "bbwals" -0xbf69: "bbwalt" -0xbf6a: "bbwalp" -0xbf6b: "bbwalh" -0xbf6c: "bbwam" -0xbf6d: "bbwab" -0xbf6e: "bbwabs" -0xbf6f: "bbwas" -0xbf70: "bbwass" -0xbf71: "bbwang" -0xbf72: "bbwaj" -0xbf73: "bbwac" -0xbf74: "bbwak" -0xbf75: "bbwat" -0xbf76: "bbwap" -0xbf77: "bbwah" -0xbf78: "bbwae" -0xbf79: "bbwaeg" -0xbf7a: "bbwaegg" -0xbf7b: "bbwaegs" -0xbf7c: "bbwaen" -0xbf7d: "bbwaenj" -0xbf7e: "bbwaenh" -0xbf7f: "bbwaed" -0xbf80: "bbwael" -0xbf81: "bbwaelg" -0xbf82: "bbwaelm" -0xbf83: "bbwaelb" -0xbf84: "bbwaels" -0xbf85: "bbwaelt" -0xbf86: "bbwaelp" -0xbf87: "bbwaelh" -0xbf88: "bbwaem" -0xbf89: "bbwaeb" -0xbf8a: "bbwaebs" -0xbf8b: "bbwaes" -0xbf8c: "bbwaess" -0xbf8d: "bbwaeng" -0xbf8e: "bbwaej" -0xbf8f: "bbwaec" -0xbf90: "bbwaek" -0xbf91: "bbwaet" -0xbf92: "bbwaep" -0xbf93: "bbwaeh" -0xbf94: "bboe" -0xbf95: "bboeg" -0xbf96: "bboegg" -0xbf97: "bboegs" -0xbf98: "bboen" -0xbf99: "bboenj" -0xbf9a: "bboenh" -0xbf9b: "bboed" -0xbf9c: "bboel" -0xbf9d: "bboelg" -0xbf9e: "bboelm" -0xbf9f: "bboelb" -0xbfa0: "bboels" -0xbfa1: "bboelt" -0xbfa2: "bboelp" -0xbfa3: "bboelh" -0xbfa4: "bboem" -0xbfa5: "bboeb" -0xbfa6: "bboebs" -0xbfa7: "bboes" -0xbfa8: "bboess" -0xbfa9: "bboeng" -0xbfaa: "bboej" -0xbfab: "bboec" -0xbfac: "bboek" -0xbfad: "bboet" -0xbfae: "bboep" -0xbfaf: "bboeh" -0xbfb0: "bbyo" -0xbfb1: "bbyog" -0xbfb2: "bbyogg" -0xbfb3: "bbyogs" -0xbfb4: "bbyon" -0xbfb5: "bbyonj" -0xbfb6: "bbyonh" -0xbfb7: "bbyod" -0xbfb8: "bbyol" -0xbfb9: "bbyolg" -0xbfba: "bbyolm" -0xbfbb: "bbyolb" -0xbfbc: "bbyols" -0xbfbd: "bbyolt" -0xbfbe: "bbyolp" -0xbfbf: "bbyolh" -0xbfc0: "bbyom" -0xbfc1: "bbyob" -0xbfc2: "bbyobs" -0xbfc3: "bbyos" -0xbfc4: "bbyoss" -0xbfc5: "bbyong" -0xbfc6: "bbyoj" -0xbfc7: "bbyoc" -0xbfc8: "bbyok" -0xbfc9: "bbyot" -0xbfca: "bbyop" -0xbfcb: "bbyoh" -0xbfcc: "bbu" -0xbfcd: "bbug" -0xbfce: "bbugg" -0xbfcf: "bbugs" -0xbfd0: "bbun" -0xbfd1: "bbunj" -0xbfd2: "bbunh" -0xbfd3: "bbud" -0xbfd4: "bbul" -0xbfd5: "bbulg" -0xbfd6: "bbulm" -0xbfd7: "bbulb" -0xbfd8: "bbuls" -0xbfd9: "bbult" -0xbfda: "bbulp" -0xbfdb: "bbulh" -0xbfdc: "bbum" -0xbfdd: "bbub" -0xbfde: "bbubs" -0xbfdf: "bbus" -0xbfe0: "bbuss" -0xbfe1: "bbung" -0xbfe2: "bbuj" -0xbfe3: "bbuc" -0xbfe4: "bbuk" -0xbfe5: "bbut" -0xbfe6: "bbup" -0xbfe7: "bbuh" -0xbfe8: "bbweo" -0xbfe9: "bbweog" -0xbfea: "bbweogg" -0xbfeb: "bbweogs" -0xbfec: "bbweon" -0xbfed: "bbweonj" -0xbfee: "bbweonh" -0xbfef: "bbweod" -0xbff0: "bbweol" -0xbff1: "bbweolg" -0xbff2: "bbweolm" -0xbff3: "bbweolb" -0xbff4: "bbweols" -0xbff5: "bbweolt" -0xbff6: "bbweolp" -0xbff7: "bbweolh" -0xbff8: "bbweom" -0xbff9: "bbweob" -0xbffa: "bbweobs" -0xbffb: "bbweos" -0xbffc: "bbweoss" -0xbffd: "bbweong" -0xbffe: "bbweoj" -0xbfff: "bbweoc" -/* x0c0 */ -0xc000: "bbweok" -0xc001: "bbweot" -0xc002: "bbweop" -0xc003: "bbweoh" -0xc004: "bbwe" -0xc005: "bbweg" -0xc006: "bbwegg" -0xc007: "bbwegs" -0xc008: "bbwen" -0xc009: "bbwenj" -0xc00a: "bbwenh" -0xc00b: "bbwed" -0xc00c: "bbwel" -0xc00d: "bbwelg" -0xc00e: "bbwelm" -0xc00f: "bbwelb" -0xc010: "bbwels" -0xc011: "bbwelt" -0xc012: "bbwelp" -0xc013: "bbwelh" -0xc014: "bbwem" -0xc015: "bbweb" -0xc016: "bbwebs" -0xc017: "bbwes" -0xc018: "bbwess" -0xc019: "bbweng" -0xc01a: "bbwej" -0xc01b: "bbwec" -0xc01c: "bbwek" -0xc01d: "bbwet" -0xc01e: "bbwep" -0xc01f: "bbweh" -0xc020: "bbwi" -0xc021: "bbwig" -0xc022: "bbwigg" -0xc023: "bbwigs" -0xc024: "bbwin" -0xc025: "bbwinj" -0xc026: "bbwinh" -0xc027: "bbwid" -0xc028: "bbwil" -0xc029: "bbwilg" -0xc02a: "bbwilm" -0xc02b: "bbwilb" -0xc02c: "bbwils" -0xc02d: "bbwilt" -0xc02e: "bbwilp" -0xc02f: "bbwilh" -0xc030: "bbwim" -0xc031: "bbwib" -0xc032: "bbwibs" -0xc033: "bbwis" -0xc034: "bbwiss" -0xc035: "bbwing" -0xc036: "bbwij" -0xc037: "bbwic" -0xc038: "bbwik" -0xc039: "bbwit" -0xc03a: "bbwip" -0xc03b: "bbwih" -0xc03c: "bbyu" -0xc03d: "bbyug" -0xc03e: "bbyugg" -0xc03f: "bbyugs" -0xc040: "bbyun" -0xc041: "bbyunj" -0xc042: "bbyunh" -0xc043: "bbyud" -0xc044: "bbyul" -0xc045: "bbyulg" -0xc046: "bbyulm" -0xc047: "bbyulb" -0xc048: "bbyuls" -0xc049: "bbyult" -0xc04a: "bbyulp" -0xc04b: "bbyulh" -0xc04c: "bbyum" -0xc04d: "bbyub" -0xc04e: "bbyubs" -0xc04f: "bbyus" -0xc050: "bbyuss" -0xc051: "bbyung" -0xc052: "bbyuj" -0xc053: "bbyuc" -0xc054: "bbyuk" -0xc055: "bbyut" -0xc056: "bbyup" -0xc057: "bbyuh" -0xc058: "bbeu" -0xc059: "bbeug" -0xc05a: "bbeugg" -0xc05b: "bbeugs" -0xc05c: "bbeun" -0xc05d: "bbeunj" -0xc05e: "bbeunh" -0xc05f: "bbeud" -0xc060: "bbeul" -0xc061: "bbeulg" -0xc062: "bbeulm" -0xc063: "bbeulb" -0xc064: "bbeuls" -0xc065: "bbeult" -0xc066: "bbeulp" -0xc067: "bbeulh" -0xc068: "bbeum" -0xc069: "bbeub" -0xc06a: "bbeubs" -0xc06b: "bbeus" -0xc06c: "bbeuss" -0xc06d: "bbeung" -0xc06e: "bbeuj" -0xc06f: "bbeuc" -0xc070: "bbeuk" -0xc071: "bbeut" -0xc072: "bbeup" -0xc073: "bbeuh" -0xc074: "bbyi" -0xc075: "bbyig" -0xc076: "bbyigg" -0xc077: "bbyigs" -0xc078: "bbyin" -0xc079: "bbyinj" -0xc07a: "bbyinh" -0xc07b: "bbyid" -0xc07c: "bbyil" -0xc07d: "bbyilg" -0xc07e: "bbyilm" -0xc07f: "bbyilb" -0xc080: "bbyils" -0xc081: "bbyilt" -0xc082: "bbyilp" -0xc083: "bbyilh" -0xc084: "bbyim" -0xc085: "bbyib" -0xc086: "bbyibs" -0xc087: "bbyis" -0xc088: "bbyiss" -0xc089: "bbying" -0xc08a: "bbyij" -0xc08b: "bbyic" -0xc08c: "bbyik" -0xc08d: "bbyit" -0xc08e: "bbyip" -0xc08f: "bbyih" -0xc090: "bbi" -0xc091: "bbig" -0xc092: "bbigg" -0xc093: "bbigs" -0xc094: "bbin" -0xc095: "bbinj" -0xc096: "bbinh" -0xc097: "bbid" -0xc098: "bbil" -0xc099: "bbilg" -0xc09a: "bbilm" -0xc09b: "bbilb" -0xc09c: "bbils" -0xc09d: "bbilt" -0xc09e: "bbilp" -0xc09f: "bbilh" -0xc0a0: "bbim" -0xc0a1: "bbib" -0xc0a2: "bbibs" -0xc0a3: "bbis" -0xc0a4: "bbiss" -0xc0a5: "bbing" -0xc0a6: "bbij" -0xc0a7: "bbic" -0xc0a8: "bbik" -0xc0a9: "bbit" -0xc0aa: "bbip" -0xc0ab: "bbih" -0xc0ac: "sa" -0xc0ad: "sag" -0xc0ae: "sagg" -0xc0af: "sags" -0xc0b0: "san" -0xc0b1: "sanj" -0xc0b2: "sanh" -0xc0b3: "sad" -0xc0b4: "sal" -0xc0b5: "salg" -0xc0b6: "salm" -0xc0b7: "salb" -0xc0b8: "sals" -0xc0b9: "salt" -0xc0ba: "salp" -0xc0bb: "salh" -0xc0bc: "sam" -0xc0bd: "sab" -0xc0be: "sabs" -0xc0bf: "sas" -0xc0c0: "sass" -0xc0c1: "sang" -0xc0c2: "saj" -0xc0c3: "sac" -0xc0c4: "sak" -0xc0c5: "sat" -0xc0c6: "sap" -0xc0c7: "sah" -0xc0c8: "sae" -0xc0c9: "saeg" -0xc0ca: "saegg" -0xc0cb: "saegs" -0xc0cc: "saen" -0xc0cd: "saenj" -0xc0ce: "saenh" -0xc0cf: "saed" -0xc0d0: "sael" -0xc0d1: "saelg" -0xc0d2: "saelm" -0xc0d3: "saelb" -0xc0d4: "saels" -0xc0d5: "saelt" -0xc0d6: "saelp" -0xc0d7: "saelh" -0xc0d8: "saem" -0xc0d9: "saeb" -0xc0da: "saebs" -0xc0db: "saes" -0xc0dc: "saess" -0xc0dd: "saeng" -0xc0de: "saej" -0xc0df: "saec" -0xc0e0: "saek" -0xc0e1: "saet" -0xc0e2: "saep" -0xc0e3: "saeh" -0xc0e4: "sya" -0xc0e5: "syag" -0xc0e6: "syagg" -0xc0e7: "syags" -0xc0e8: "syan" -0xc0e9: "syanj" -0xc0ea: "syanh" -0xc0eb: "syad" -0xc0ec: "syal" -0xc0ed: "syalg" -0xc0ee: "syalm" -0xc0ef: "syalb" -0xc0f0: "syals" -0xc0f1: "syalt" -0xc0f2: "syalp" -0xc0f3: "syalh" -0xc0f4: "syam" -0xc0f5: "syab" -0xc0f6: "syabs" -0xc0f7: "syas" -0xc0f8: "syass" -0xc0f9: "syang" -0xc0fa: "syaj" -0xc0fb: "syac" -0xc0fc: "syak" -0xc0fd: "syat" -0xc0fe: "syap" -0xc0ff: "syah" -/* x0c1 */ -0xc100: "syae" -0xc101: "syaeg" -0xc102: "syaegg" -0xc103: "syaegs" -0xc104: "syaen" -0xc105: "syaenj" -0xc106: "syaenh" -0xc107: "syaed" -0xc108: "syael" -0xc109: "syaelg" -0xc10a: "syaelm" -0xc10b: "syaelb" -0xc10c: "syaels" -0xc10d: "syaelt" -0xc10e: "syaelp" -0xc10f: "syaelh" -0xc110: "syaem" -0xc111: "syaeb" -0xc112: "syaebs" -0xc113: "syaes" -0xc114: "syaess" -0xc115: "syaeng" -0xc116: "syaej" -0xc117: "syaec" -0xc118: "syaek" -0xc119: "syaet" -0xc11a: "syaep" -0xc11b: "syaeh" -0xc11c: "seo" -0xc11d: "seog" -0xc11e: "seogg" -0xc11f: "seogs" -0xc120: "seon" -0xc121: "seonj" -0xc122: "seonh" -0xc123: "seod" -0xc124: "seol" -0xc125: "seolg" -0xc126: "seolm" -0xc127: "seolb" -0xc128: "seols" -0xc129: "seolt" -0xc12a: "seolp" -0xc12b: "seolh" -0xc12c: "seom" -0xc12d: "seob" -0xc12e: "seobs" -0xc12f: "seos" -0xc130: "seoss" -0xc131: "seong" -0xc132: "seoj" -0xc133: "seoc" -0xc134: "seok" -0xc135: "seot" -0xc136: "seop" -0xc137: "seoh" -0xc138: "se" -0xc139: "seg" -0xc13a: "segg" -0xc13b: "segs" -0xc13c: "sen" -0xc13d: "senj" -0xc13e: "senh" -0xc13f: "sed" -0xc140: "sel" -0xc141: "selg" -0xc142: "selm" -0xc143: "selb" -0xc144: "sels" -0xc145: "selt" -0xc146: "selp" -0xc147: "selh" -0xc148: "sem" -0xc149: "seb" -0xc14a: "sebs" -0xc14b: "ses" -0xc14c: "sess" -0xc14d: "seng" -0xc14e: "sej" -0xc14f: "sec" -0xc150: "sek" -0xc151: "set" -0xc152: "sep" -0xc153: "seh" -0xc154: "syeo" -0xc155: "syeog" -0xc156: "syeogg" -0xc157: "syeogs" -0xc158: "syeon" -0xc159: "syeonj" -0xc15a: "syeonh" -0xc15b: "syeod" -0xc15c: "syeol" -0xc15d: "syeolg" -0xc15e: "syeolm" -0xc15f: "syeolb" -0xc160: "syeols" -0xc161: "syeolt" -0xc162: "syeolp" -0xc163: "syeolh" -0xc164: "syeom" -0xc165: "syeob" -0xc166: "syeobs" -0xc167: "syeos" -0xc168: "syeoss" -0xc169: "syeong" -0xc16a: "syeoj" -0xc16b: "syeoc" -0xc16c: "syeok" -0xc16d: "syeot" -0xc16e: "syeop" -0xc16f: "syeoh" -0xc170: "sye" -0xc171: "syeg" -0xc172: "syegg" -0xc173: "syegs" -0xc174: "syen" -0xc175: "syenj" -0xc176: "syenh" -0xc177: "syed" -0xc178: "syel" -0xc179: "syelg" -0xc17a: "syelm" -0xc17b: "syelb" -0xc17c: "syels" -0xc17d: "syelt" -0xc17e: "syelp" -0xc17f: "syelh" -0xc180: "syem" -0xc181: "syeb" -0xc182: "syebs" -0xc183: "syes" -0xc184: "syess" -0xc185: "syeng" -0xc186: "syej" -0xc187: "syec" -0xc188: "syek" -0xc189: "syet" -0xc18a: "syep" -0xc18b: "syeh" -0xc18c: "so" -0xc18d: "sog" -0xc18e: "sogg" -0xc18f: "sogs" -0xc190: "son" -0xc191: "sonj" -0xc192: "sonh" -0xc193: "sod" -0xc194: "sol" -0xc195: "solg" -0xc196: "solm" -0xc197: "solb" -0xc198: "sols" -0xc199: "solt" -0xc19a: "solp" -0xc19b: "solh" -0xc19c: "som" -0xc19d: "sob" -0xc19e: "sobs" -0xc19f: "sos" -0xc1a0: "soss" -0xc1a1: "song" -0xc1a2: "soj" -0xc1a3: "soc" -0xc1a4: "sok" -0xc1a5: "sot" -0xc1a6: "sop" -0xc1a7: "soh" -0xc1a8: "swa" -0xc1a9: "swag" -0xc1aa: "swagg" -0xc1ab: "swags" -0xc1ac: "swan" -0xc1ad: "swanj" -0xc1ae: "swanh" -0xc1af: "swad" -0xc1b0: "swal" -0xc1b1: "swalg" -0xc1b2: "swalm" -0xc1b3: "swalb" -0xc1b4: "swals" -0xc1b5: "swalt" -0xc1b6: "swalp" -0xc1b7: "swalh" -0xc1b8: "swam" -0xc1b9: "swab" -0xc1ba: "swabs" -0xc1bb: "swas" -0xc1bc: "swass" -0xc1bd: "swang" -0xc1be: "swaj" -0xc1bf: "swac" -0xc1c0: "swak" -0xc1c1: "swat" -0xc1c2: "swap" -0xc1c3: "swah" -0xc1c4: "swae" -0xc1c5: "swaeg" -0xc1c6: "swaegg" -0xc1c7: "swaegs" -0xc1c8: "swaen" -0xc1c9: "swaenj" -0xc1ca: "swaenh" -0xc1cb: "swaed" -0xc1cc: "swael" -0xc1cd: "swaelg" -0xc1ce: "swaelm" -0xc1cf: "swaelb" -0xc1d0: "swaels" -0xc1d1: "swaelt" -0xc1d2: "swaelp" -0xc1d3: "swaelh" -0xc1d4: "swaem" -0xc1d5: "swaeb" -0xc1d6: "swaebs" -0xc1d7: "swaes" -0xc1d8: "swaess" -0xc1d9: "swaeng" -0xc1da: "swaej" -0xc1db: "swaec" -0xc1dc: "swaek" -0xc1dd: "swaet" -0xc1de: "swaep" -0xc1df: "swaeh" -0xc1e0: "soe" -0xc1e1: "soeg" -0xc1e2: "soegg" -0xc1e3: "soegs" -0xc1e4: "soen" -0xc1e5: "soenj" -0xc1e6: "soenh" -0xc1e7: "soed" -0xc1e8: "soel" -0xc1e9: "soelg" -0xc1ea: "soelm" -0xc1eb: "soelb" -0xc1ec: "soels" -0xc1ed: "soelt" -0xc1ee: "soelp" -0xc1ef: "soelh" -0xc1f0: "soem" -0xc1f1: "soeb" -0xc1f2: "soebs" -0xc1f3: "soes" -0xc1f4: "soess" -0xc1f5: "soeng" -0xc1f6: "soej" -0xc1f7: "soec" -0xc1f8: "soek" -0xc1f9: "soet" -0xc1fa: "soep" -0xc1fb: "soeh" -0xc1fc: "syo" -0xc1fd: "syog" -0xc1fe: "syogg" -0xc1ff: "syogs" -/* x0c2 */ -0xc200: "syon" -0xc201: "syonj" -0xc202: "syonh" -0xc203: "syod" -0xc204: "syol" -0xc205: "syolg" -0xc206: "syolm" -0xc207: "syolb" -0xc208: "syols" -0xc209: "syolt" -0xc20a: "syolp" -0xc20b: "syolh" -0xc20c: "syom" -0xc20d: "syob" -0xc20e: "syobs" -0xc20f: "syos" -0xc210: "syoss" -0xc211: "syong" -0xc212: "syoj" -0xc213: "syoc" -0xc214: "syok" -0xc215: "syot" -0xc216: "syop" -0xc217: "syoh" -0xc218: "su" -0xc219: "sug" -0xc21a: "sugg" -0xc21b: "sugs" -0xc21c: "sun" -0xc21d: "sunj" -0xc21e: "sunh" -0xc21f: "sud" -0xc220: "sul" -0xc221: "sulg" -0xc222: "sulm" -0xc223: "sulb" -0xc224: "suls" -0xc225: "sult" -0xc226: "sulp" -0xc227: "sulh" -0xc228: "sum" -0xc229: "sub" -0xc22a: "subs" -0xc22b: "sus" -0xc22c: "suss" -0xc22d: "sung" -0xc22e: "suj" -0xc22f: "suc" -0xc230: "suk" -0xc231: "sut" -0xc232: "sup" -0xc233: "suh" -0xc234: "sweo" -0xc235: "sweog" -0xc236: "sweogg" -0xc237: "sweogs" -0xc238: "sweon" -0xc239: "sweonj" -0xc23a: "sweonh" -0xc23b: "sweod" -0xc23c: "sweol" -0xc23d: "sweolg" -0xc23e: "sweolm" -0xc23f: "sweolb" -0xc240: "sweols" -0xc241: "sweolt" -0xc242: "sweolp" -0xc243: "sweolh" -0xc244: "sweom" -0xc245: "sweob" -0xc246: "sweobs" -0xc247: "sweos" -0xc248: "sweoss" -0xc249: "sweong" -0xc24a: "sweoj" -0xc24b: "sweoc" -0xc24c: "sweok" -0xc24d: "sweot" -0xc24e: "sweop" -0xc24f: "sweoh" -0xc250: "swe" -0xc251: "sweg" -0xc252: "swegg" -0xc253: "swegs" -0xc254: "swen" -0xc255: "swenj" -0xc256: "swenh" -0xc257: "swed" -0xc258: "swel" -0xc259: "swelg" -0xc25a: "swelm" -0xc25b: "swelb" -0xc25c: "swels" -0xc25d: "swelt" -0xc25e: "swelp" -0xc25f: "swelh" -0xc260: "swem" -0xc261: "sweb" -0xc262: "swebs" -0xc263: "swes" -0xc264: "swess" -0xc265: "sweng" -0xc266: "swej" -0xc267: "swec" -0xc268: "swek" -0xc269: "swet" -0xc26a: "swep" -0xc26b: "sweh" -0xc26c: "swi" -0xc26d: "swig" -0xc26e: "swigg" -0xc26f: "swigs" -0xc270: "swin" -0xc271: "swinj" -0xc272: "swinh" -0xc273: "swid" -0xc274: "swil" -0xc275: "swilg" -0xc276: "swilm" -0xc277: "swilb" -0xc278: "swils" -0xc279: "swilt" -0xc27a: "swilp" -0xc27b: "swilh" -0xc27c: "swim" -0xc27d: "swib" -0xc27e: "swibs" -0xc27f: "swis" -0xc280: "swiss" -0xc281: "swing" -0xc282: "swij" -0xc283: "swic" -0xc284: "swik" -0xc285: "swit" -0xc286: "swip" -0xc287: "swih" -0xc288: "syu" -0xc289: "syug" -0xc28a: "syugg" -0xc28b: "syugs" -0xc28c: "syun" -0xc28d: "syunj" -0xc28e: "syunh" -0xc28f: "syud" -0xc290: "syul" -0xc291: "syulg" -0xc292: "syulm" -0xc293: "syulb" -0xc294: "syuls" -0xc295: "syult" -0xc296: "syulp" -0xc297: "syulh" -0xc298: "syum" -0xc299: "syub" -0xc29a: "syubs" -0xc29b: "syus" -0xc29c: "syuss" -0xc29d: "syung" -0xc29e: "syuj" -0xc29f: "syuc" -0xc2a0: "syuk" -0xc2a1: "syut" -0xc2a2: "syup" -0xc2a3: "syuh" -0xc2a4: "seu" -0xc2a5: "seug" -0xc2a6: "seugg" -0xc2a7: "seugs" -0xc2a8: "seun" -0xc2a9: "seunj" -0xc2aa: "seunh" -0xc2ab: "seud" -0xc2ac: "seul" -0xc2ad: "seulg" -0xc2ae: "seulm" -0xc2af: "seulb" -0xc2b0: "seuls" -0xc2b1: "seult" -0xc2b2: "seulp" -0xc2b3: "seulh" -0xc2b4: "seum" -0xc2b5: "seub" -0xc2b6: "seubs" -0xc2b7: "seus" -0xc2b8: "seuss" -0xc2b9: "seung" -0xc2ba: "seuj" -0xc2bb: "seuc" -0xc2bc: "seuk" -0xc2bd: "seut" -0xc2be: "seup" -0xc2bf: "seuh" -0xc2c0: "syi" -0xc2c1: "syig" -0xc2c2: "syigg" -0xc2c3: "syigs" -0xc2c4: "syin" -0xc2c5: "syinj" -0xc2c6: "syinh" -0xc2c7: "syid" -0xc2c8: "syil" -0xc2c9: "syilg" -0xc2ca: "syilm" -0xc2cb: "syilb" -0xc2cc: "syils" -0xc2cd: "syilt" -0xc2ce: "syilp" -0xc2cf: "syilh" -0xc2d0: "syim" -0xc2d1: "syib" -0xc2d2: "syibs" -0xc2d3: "syis" -0xc2d4: "syiss" -0xc2d5: "sying" -0xc2d6: "syij" -0xc2d7: "syic" -0xc2d8: "syik" -0xc2d9: "syit" -0xc2da: "syip" -0xc2db: "syih" -0xc2dc: "si" -0xc2dd: "sig" -0xc2de: "sigg" -0xc2df: "sigs" -0xc2e0: "sin" -0xc2e1: "sinj" -0xc2e2: "sinh" -0xc2e3: "sid" -0xc2e4: "sil" -0xc2e5: "silg" -0xc2e6: "silm" -0xc2e7: "silb" -0xc2e8: "sils" -0xc2e9: "silt" -0xc2ea: "silp" -0xc2eb: "silh" -0xc2ec: "sim" -0xc2ed: "sib" -0xc2ee: "sibs" -0xc2ef: "sis" -0xc2f0: "siss" -0xc2f1: "sing" -0xc2f2: "sij" -0xc2f3: "sic" -0xc2f4: "sik" -0xc2f5: "sit" -0xc2f6: "sip" -0xc2f7: "sih" -0xc2f8: "ssa" -0xc2f9: "ssag" -0xc2fa: "ssagg" -0xc2fb: "ssags" -0xc2fc: "ssan" -0xc2fd: "ssanj" -0xc2fe: "ssanh" -0xc2ff: "ssad" -/* x0c3 */ -0xc300: "ssal" -0xc301: "ssalg" -0xc302: "ssalm" -0xc303: "ssalb" -0xc304: "ssals" -0xc305: "ssalt" -0xc306: "ssalp" -0xc307: "ssalh" -0xc308: "ssam" -0xc309: "ssab" -0xc30a: "ssabs" -0xc30b: "ssas" -0xc30c: "ssass" -0xc30d: "ssang" -0xc30e: "ssaj" -0xc30f: "ssac" -0xc310: "ssak" -0xc311: "ssat" -0xc312: "ssap" -0xc313: "ssah" -0xc314: "ssae" -0xc315: "ssaeg" -0xc316: "ssaegg" -0xc317: "ssaegs" -0xc318: "ssaen" -0xc319: "ssaenj" -0xc31a: "ssaenh" -0xc31b: "ssaed" -0xc31c: "ssael" -0xc31d: "ssaelg" -0xc31e: "ssaelm" -0xc31f: "ssaelb" -0xc320: "ssaels" -0xc321: "ssaelt" -0xc322: "ssaelp" -0xc323: "ssaelh" -0xc324: "ssaem" -0xc325: "ssaeb" -0xc326: "ssaebs" -0xc327: "ssaes" -0xc328: "ssaess" -0xc329: "ssaeng" -0xc32a: "ssaej" -0xc32b: "ssaec" -0xc32c: "ssaek" -0xc32d: "ssaet" -0xc32e: "ssaep" -0xc32f: "ssaeh" -0xc330: "ssya" -0xc331: "ssyag" -0xc332: "ssyagg" -0xc333: "ssyags" -0xc334: "ssyan" -0xc335: "ssyanj" -0xc336: "ssyanh" -0xc337: "ssyad" -0xc338: "ssyal" -0xc339: "ssyalg" -0xc33a: "ssyalm" -0xc33b: "ssyalb" -0xc33c: "ssyals" -0xc33d: "ssyalt" -0xc33e: "ssyalp" -0xc33f: "ssyalh" -0xc340: "ssyam" -0xc341: "ssyab" -0xc342: "ssyabs" -0xc343: "ssyas" -0xc344: "ssyass" -0xc345: "ssyang" -0xc346: "ssyaj" -0xc347: "ssyac" -0xc348: "ssyak" -0xc349: "ssyat" -0xc34a: "ssyap" -0xc34b: "ssyah" -0xc34c: "ssyae" -0xc34d: "ssyaeg" -0xc34e: "ssyaegg" -0xc34f: "ssyaegs" -0xc350: "ssyaen" -0xc351: "ssyaenj" -0xc352: "ssyaenh" -0xc353: "ssyaed" -0xc354: "ssyael" -0xc355: "ssyaelg" -0xc356: "ssyaelm" -0xc357: "ssyaelb" -0xc358: "ssyaels" -0xc359: "ssyaelt" -0xc35a: "ssyaelp" -0xc35b: "ssyaelh" -0xc35c: "ssyaem" -0xc35d: "ssyaeb" -0xc35e: "ssyaebs" -0xc35f: "ssyaes" -0xc360: "ssyaess" -0xc361: "ssyaeng" -0xc362: "ssyaej" -0xc363: "ssyaec" -0xc364: "ssyaek" -0xc365: "ssyaet" -0xc366: "ssyaep" -0xc367: "ssyaeh" -0xc368: "sseo" -0xc369: "sseog" -0xc36a: "sseogg" -0xc36b: "sseogs" -0xc36c: "sseon" -0xc36d: "sseonj" -0xc36e: "sseonh" -0xc36f: "sseod" -0xc370: "sseol" -0xc371: "sseolg" -0xc372: "sseolm" -0xc373: "sseolb" -0xc374: "sseols" -0xc375: "sseolt" -0xc376: "sseolp" -0xc377: "sseolh" -0xc378: "sseom" -0xc379: "sseob" -0xc37a: "sseobs" -0xc37b: "sseos" -0xc37c: "sseoss" -0xc37d: "sseong" -0xc37e: "sseoj" -0xc37f: "sseoc" -0xc380: "sseok" -0xc381: "sseot" -0xc382: "sseop" -0xc383: "sseoh" -0xc384: "sse" -0xc385: "sseg" -0xc386: "ssegg" -0xc387: "ssegs" -0xc388: "ssen" -0xc389: "ssenj" -0xc38a: "ssenh" -0xc38b: "ssed" -0xc38c: "ssel" -0xc38d: "sselg" -0xc38e: "sselm" -0xc38f: "sselb" -0xc390: "ssels" -0xc391: "sselt" -0xc392: "sselp" -0xc393: "sselh" -0xc394: "ssem" -0xc395: "sseb" -0xc396: "ssebs" -0xc397: "sses" -0xc398: "ssess" -0xc399: "sseng" -0xc39a: "ssej" -0xc39b: "ssec" -0xc39c: "ssek" -0xc39d: "sset" -0xc39e: "ssep" -0xc39f: "sseh" -0xc3a0: "ssyeo" -0xc3a1: "ssyeog" -0xc3a2: "ssyeogg" -0xc3a3: "ssyeogs" -0xc3a4: "ssyeon" -0xc3a5: "ssyeonj" -0xc3a6: "ssyeonh" -0xc3a7: "ssyeod" -0xc3a8: "ssyeol" -0xc3a9: "ssyeolg" -0xc3aa: "ssyeolm" -0xc3ab: "ssyeolb" -0xc3ac: "ssyeols" -0xc3ad: "ssyeolt" -0xc3ae: "ssyeolp" -0xc3af: "ssyeolh" -0xc3b0: "ssyeom" -0xc3b1: "ssyeob" -0xc3b2: "ssyeobs" -0xc3b3: "ssyeos" -0xc3b4: "ssyeoss" -0xc3b5: "ssyeong" -0xc3b6: "ssyeoj" -0xc3b7: "ssyeoc" -0xc3b8: "ssyeok" -0xc3b9: "ssyeot" -0xc3ba: "ssyeop" -0xc3bb: "ssyeoh" -0xc3bc: "ssye" -0xc3bd: "ssyeg" -0xc3be: "ssyegg" -0xc3bf: "ssyegs" -0xc3c0: "ssyen" -0xc3c1: "ssyenj" -0xc3c2: "ssyenh" -0xc3c3: "ssyed" -0xc3c4: "ssyel" -0xc3c5: "ssyelg" -0xc3c6: "ssyelm" -0xc3c7: "ssyelb" -0xc3c8: "ssyels" -0xc3c9: "ssyelt" -0xc3ca: "ssyelp" -0xc3cb: "ssyelh" -0xc3cc: "ssyem" -0xc3cd: "ssyeb" -0xc3ce: "ssyebs" -0xc3cf: "ssyes" -0xc3d0: "ssyess" -0xc3d1: "ssyeng" -0xc3d2: "ssyej" -0xc3d3: "ssyec" -0xc3d4: "ssyek" -0xc3d5: "ssyet" -0xc3d6: "ssyep" -0xc3d7: "ssyeh" -0xc3d8: "sso" -0xc3d9: "ssog" -0xc3da: "ssogg" -0xc3db: "ssogs" -0xc3dc: "sson" -0xc3dd: "ssonj" -0xc3de: "ssonh" -0xc3df: "ssod" -0xc3e0: "ssol" -0xc3e1: "ssolg" -0xc3e2: "ssolm" -0xc3e3: "ssolb" -0xc3e4: "ssols" -0xc3e5: "ssolt" -0xc3e6: "ssolp" -0xc3e7: "ssolh" -0xc3e8: "ssom" -0xc3e9: "ssob" -0xc3ea: "ssobs" -0xc3eb: "ssos" -0xc3ec: "ssoss" -0xc3ed: "ssong" -0xc3ee: "ssoj" -0xc3ef: "ssoc" -0xc3f0: "ssok" -0xc3f1: "ssot" -0xc3f2: "ssop" -0xc3f3: "ssoh" -0xc3f4: "sswa" -0xc3f5: "sswag" -0xc3f6: "sswagg" -0xc3f7: "sswags" -0xc3f8: "sswan" -0xc3f9: "sswanj" -0xc3fa: "sswanh" -0xc3fb: "sswad" -0xc3fc: "sswal" -0xc3fd: "sswalg" -0xc3fe: "sswalm" -0xc3ff: "sswalb" -/* x0c4 */ -0xc400: "sswals" -0xc401: "sswalt" -0xc402: "sswalp" -0xc403: "sswalh" -0xc404: "sswam" -0xc405: "sswab" -0xc406: "sswabs" -0xc407: "sswas" -0xc408: "sswass" -0xc409: "sswang" -0xc40a: "sswaj" -0xc40b: "sswac" -0xc40c: "sswak" -0xc40d: "sswat" -0xc40e: "sswap" -0xc40f: "sswah" -0xc410: "sswae" -0xc411: "sswaeg" -0xc412: "sswaegg" -0xc413: "sswaegs" -0xc414: "sswaen" -0xc415: "sswaenj" -0xc416: "sswaenh" -0xc417: "sswaed" -0xc418: "sswael" -0xc419: "sswaelg" -0xc41a: "sswaelm" -0xc41b: "sswaelb" -0xc41c: "sswaels" -0xc41d: "sswaelt" -0xc41e: "sswaelp" -0xc41f: "sswaelh" -0xc420: "sswaem" -0xc421: "sswaeb" -0xc422: "sswaebs" -0xc423: "sswaes" -0xc424: "sswaess" -0xc425: "sswaeng" -0xc426: "sswaej" -0xc427: "sswaec" -0xc428: "sswaek" -0xc429: "sswaet" -0xc42a: "sswaep" -0xc42b: "sswaeh" -0xc42c: "ssoe" -0xc42d: "ssoeg" -0xc42e: "ssoegg" -0xc42f: "ssoegs" -0xc430: "ssoen" -0xc431: "ssoenj" -0xc432: "ssoenh" -0xc433: "ssoed" -0xc434: "ssoel" -0xc435: "ssoelg" -0xc436: "ssoelm" -0xc437: "ssoelb" -0xc438: "ssoels" -0xc439: "ssoelt" -0xc43a: "ssoelp" -0xc43b: "ssoelh" -0xc43c: "ssoem" -0xc43d: "ssoeb" -0xc43e: "ssoebs" -0xc43f: "ssoes" -0xc440: "ssoess" -0xc441: "ssoeng" -0xc442: "ssoej" -0xc443: "ssoec" -0xc444: "ssoek" -0xc445: "ssoet" -0xc446: "ssoep" -0xc447: "ssoeh" -0xc448: "ssyo" -0xc449: "ssyog" -0xc44a: "ssyogg" -0xc44b: "ssyogs" -0xc44c: "ssyon" -0xc44d: "ssyonj" -0xc44e: "ssyonh" -0xc44f: "ssyod" -0xc450: "ssyol" -0xc451: "ssyolg" -0xc452: "ssyolm" -0xc453: "ssyolb" -0xc454: "ssyols" -0xc455: "ssyolt" -0xc456: "ssyolp" -0xc457: "ssyolh" -0xc458: "ssyom" -0xc459: "ssyob" -0xc45a: "ssyobs" -0xc45b: "ssyos" -0xc45c: "ssyoss" -0xc45d: "ssyong" -0xc45e: "ssyoj" -0xc45f: "ssyoc" -0xc460: "ssyok" -0xc461: "ssyot" -0xc462: "ssyop" -0xc463: "ssyoh" -0xc464: "ssu" -0xc465: "ssug" -0xc466: "ssugg" -0xc467: "ssugs" -0xc468: "ssun" -0xc469: "ssunj" -0xc46a: "ssunh" -0xc46b: "ssud" -0xc46c: "ssul" -0xc46d: "ssulg" -0xc46e: "ssulm" -0xc46f: "ssulb" -0xc470: "ssuls" -0xc471: "ssult" -0xc472: "ssulp" -0xc473: "ssulh" -0xc474: "ssum" -0xc475: "ssub" -0xc476: "ssubs" -0xc477: "ssus" -0xc478: "ssuss" -0xc479: "ssung" -0xc47a: "ssuj" -0xc47b: "ssuc" -0xc47c: "ssuk" -0xc47d: "ssut" -0xc47e: "ssup" -0xc47f: "ssuh" -0xc480: "ssweo" -0xc481: "ssweog" -0xc482: "ssweogg" -0xc483: "ssweogs" -0xc484: "ssweon" -0xc485: "ssweonj" -0xc486: "ssweonh" -0xc487: "ssweod" -0xc488: "ssweol" -0xc489: "ssweolg" -0xc48a: "ssweolm" -0xc48b: "ssweolb" -0xc48c: "ssweols" -0xc48d: "ssweolt" -0xc48e: "ssweolp" -0xc48f: "ssweolh" -0xc490: "ssweom" -0xc491: "ssweob" -0xc492: "ssweobs" -0xc493: "ssweos" -0xc494: "ssweoss" -0xc495: "ssweong" -0xc496: "ssweoj" -0xc497: "ssweoc" -0xc498: "ssweok" -0xc499: "ssweot" -0xc49a: "ssweop" -0xc49b: "ssweoh" -0xc49c: "sswe" -0xc49d: "ssweg" -0xc49e: "sswegg" -0xc49f: "sswegs" -0xc4a0: "sswen" -0xc4a1: "sswenj" -0xc4a2: "sswenh" -0xc4a3: "sswed" -0xc4a4: "sswel" -0xc4a5: "sswelg" -0xc4a6: "sswelm" -0xc4a7: "sswelb" -0xc4a8: "sswels" -0xc4a9: "sswelt" -0xc4aa: "sswelp" -0xc4ab: "sswelh" -0xc4ac: "sswem" -0xc4ad: "ssweb" -0xc4ae: "sswebs" -0xc4af: "sswes" -0xc4b0: "sswess" -0xc4b1: "ssweng" -0xc4b2: "sswej" -0xc4b3: "sswec" -0xc4b4: "sswek" -0xc4b5: "sswet" -0xc4b6: "sswep" -0xc4b7: "ssweh" -0xc4b8: "sswi" -0xc4b9: "sswig" -0xc4ba: "sswigg" -0xc4bb: "sswigs" -0xc4bc: "sswin" -0xc4bd: "sswinj" -0xc4be: "sswinh" -0xc4bf: "sswid" -0xc4c0: "sswil" -0xc4c1: "sswilg" -0xc4c2: "sswilm" -0xc4c3: "sswilb" -0xc4c4: "sswils" -0xc4c5: "sswilt" -0xc4c6: "sswilp" -0xc4c7: "sswilh" -0xc4c8: "sswim" -0xc4c9: "sswib" -0xc4ca: "sswibs" -0xc4cb: "sswis" -0xc4cc: "sswiss" -0xc4cd: "sswing" -0xc4ce: "sswij" -0xc4cf: "sswic" -0xc4d0: "sswik" -0xc4d1: "sswit" -0xc4d2: "sswip" -0xc4d3: "sswih" -0xc4d4: "ssyu" -0xc4d5: "ssyug" -0xc4d6: "ssyugg" -0xc4d7: "ssyugs" -0xc4d8: "ssyun" -0xc4d9: "ssyunj" -0xc4da: "ssyunh" -0xc4db: "ssyud" -0xc4dc: "ssyul" -0xc4dd: "ssyulg" -0xc4de: "ssyulm" -0xc4df: "ssyulb" -0xc4e0: "ssyuls" -0xc4e1: "ssyult" -0xc4e2: "ssyulp" -0xc4e3: "ssyulh" -0xc4e4: "ssyum" -0xc4e5: "ssyub" -0xc4e6: "ssyubs" -0xc4e7: "ssyus" -0xc4e8: "ssyuss" -0xc4e9: "ssyung" -0xc4ea: "ssyuj" -0xc4eb: "ssyuc" -0xc4ec: "ssyuk" -0xc4ed: "ssyut" -0xc4ee: "ssyup" -0xc4ef: "ssyuh" -0xc4f0: "sseu" -0xc4f1: "sseug" -0xc4f2: "sseugg" -0xc4f3: "sseugs" -0xc4f4: "sseun" -0xc4f5: "sseunj" -0xc4f6: "sseunh" -0xc4f7: "sseud" -0xc4f8: "sseul" -0xc4f9: "sseulg" -0xc4fa: "sseulm" -0xc4fb: "sseulb" -0xc4fc: "sseuls" -0xc4fd: "sseult" -0xc4fe: "sseulp" -0xc4ff: "sseulh" -/* x0c5 */ -0xc500: "sseum" -0xc501: "sseub" -0xc502: "sseubs" -0xc503: "sseus" -0xc504: "sseuss" -0xc505: "sseung" -0xc506: "sseuj" -0xc507: "sseuc" -0xc508: "sseuk" -0xc509: "sseut" -0xc50a: "sseup" -0xc50b: "sseuh" -0xc50c: "ssyi" -0xc50d: "ssyig" -0xc50e: "ssyigg" -0xc50f: "ssyigs" -0xc510: "ssyin" -0xc511: "ssyinj" -0xc512: "ssyinh" -0xc513: "ssyid" -0xc514: "ssyil" -0xc515: "ssyilg" -0xc516: "ssyilm" -0xc517: "ssyilb" -0xc518: "ssyils" -0xc519: "ssyilt" -0xc51a: "ssyilp" -0xc51b: "ssyilh" -0xc51c: "ssyim" -0xc51d: "ssyib" -0xc51e: "ssyibs" -0xc51f: "ssyis" -0xc520: "ssyiss" -0xc521: "ssying" -0xc522: "ssyij" -0xc523: "ssyic" -0xc524: "ssyik" -0xc525: "ssyit" -0xc526: "ssyip" -0xc527: "ssyih" -0xc528: "ssi" -0xc529: "ssig" -0xc52a: "ssigg" -0xc52b: "ssigs" -0xc52c: "ssin" -0xc52d: "ssinj" -0xc52e: "ssinh" -0xc52f: "ssid" -0xc530: "ssil" -0xc531: "ssilg" -0xc532: "ssilm" -0xc533: "ssilb" -0xc534: "ssils" -0xc535: "ssilt" -0xc536: "ssilp" -0xc537: "ssilh" -0xc538: "ssim" -0xc539: "ssib" -0xc53a: "ssibs" -0xc53b: "ssis" -0xc53c: "ssiss" -0xc53d: "ssing" -0xc53e: "ssij" -0xc53f: "ssic" -0xc540: "ssik" -0xc541: "ssit" -0xc542: "ssip" -0xc543: "ssih" -0xc544: "a" -0xc545: "ag" -0xc546: "agg" -0xc547: "ags" -0xc548: "an" -0xc549: "anj" -0xc54a: "anh" -0xc54b: "ad" -0xc54c: "al" -0xc54d: "alg" -0xc54e: "alm" -0xc54f: "alb" -0xc550: "als" -0xc551: "alt" -0xc552: "alp" -0xc553: "alh" -0xc554: "am" -0xc555: "ab" -0xc556: "abs" -0xc557: "as" -0xc558: "ass" -0xc559: "ang" -0xc55a: "aj" -0xc55b: "ac" -0xc55c: "ak" -0xc55d: "at" -0xc55e: "ap" -0xc55f: "ah" -0xc560: "ae" -0xc561: "aeg" -0xc562: "aegg" -0xc563: "aegs" -0xc564: "aen" -0xc565: "aenj" -0xc566: "aenh" -0xc567: "aed" -0xc568: "ael" -0xc569: "aelg" -0xc56a: "aelm" -0xc56b: "aelb" -0xc56c: "aels" -0xc56d: "aelt" -0xc56e: "aelp" -0xc56f: "aelh" -0xc570: "aem" -0xc571: "aeb" -0xc572: "aebs" -0xc573: "aes" -0xc574: "aess" -0xc575: "aeng" -0xc576: "aej" -0xc577: "aec" -0xc578: "aek" -0xc579: "aet" -0xc57a: "aep" -0xc57b: "aeh" -0xc57c: "ya" -0xc57d: "yag" -0xc57e: "yagg" -0xc57f: "yags" -0xc580: "yan" -0xc581: "yanj" -0xc582: "yanh" -0xc583: "yad" -0xc584: "yal" -0xc585: "yalg" -0xc586: "yalm" -0xc587: "yalb" -0xc588: "yals" -0xc589: "yalt" -0xc58a: "yalp" -0xc58b: "yalh" -0xc58c: "yam" -0xc58d: "yab" -0xc58e: "yabs" -0xc58f: "yas" -0xc590: "yass" -0xc591: "yang" -0xc592: "yaj" -0xc593: "yac" -0xc594: "yak" -0xc595: "yat" -0xc596: "yap" -0xc597: "yah" -0xc598: "yae" -0xc599: "yaeg" -0xc59a: "yaegg" -0xc59b: "yaegs" -0xc59c: "yaen" -0xc59d: "yaenj" -0xc59e: "yaenh" -0xc59f: "yaed" -0xc5a0: "yael" -0xc5a1: "yaelg" -0xc5a2: "yaelm" -0xc5a3: "yaelb" -0xc5a4: "yaels" -0xc5a5: "yaelt" -0xc5a6: "yaelp" -0xc5a7: "yaelh" -0xc5a8: "yaem" -0xc5a9: "yaeb" -0xc5aa: "yaebs" -0xc5ab: "yaes" -0xc5ac: "yaess" -0xc5ad: "yaeng" -0xc5ae: "yaej" -0xc5af: "yaec" -0xc5b0: "yaek" -0xc5b1: "yaet" -0xc5b2: "yaep" -0xc5b3: "yaeh" -0xc5b4: "eo" -0xc5b5: "eog" -0xc5b6: "eogg" -0xc5b7: "eogs" -0xc5b8: "eon" -0xc5b9: "eonj" -0xc5ba: "eonh" -0xc5bb: "eod" -0xc5bc: "eol" -0xc5bd: "eolg" -0xc5be: "eolm" -0xc5bf: "eolb" -0xc5c0: "eols" -0xc5c1: "eolt" -0xc5c2: "eolp" -0xc5c3: "eolh" -0xc5c4: "eom" -0xc5c5: "eob" -0xc5c6: "eobs" -0xc5c7: "eos" -0xc5c8: "eoss" -0xc5c9: "eong" -0xc5ca: "eoj" -0xc5cb: "eoc" -0xc5cc: "eok" -0xc5cd: "eot" -0xc5ce: "eop" -0xc5cf: "eoh" -0xc5d0: "e" -0xc5d1: "eg" -0xc5d2: "egg" -0xc5d3: "egs" -0xc5d4: "en" -0xc5d5: "enj" -0xc5d6: "enh" -0xc5d7: "ed" -0xc5d8: "el" -0xc5d9: "elg" -0xc5da: "elm" -0xc5db: "elb" -0xc5dc: "els" -0xc5dd: "elt" -0xc5de: "elp" -0xc5df: "elh" -0xc5e0: "em" -0xc5e1: "eb" -0xc5e2: "ebs" -0xc5e3: "es" -0xc5e4: "ess" -0xc5e5: "eng" -0xc5e6: "ej" -0xc5e7: "ec" -0xc5e8: "ek" -0xc5e9: "et" -0xc5ea: "ep" -0xc5eb: "eh" -0xc5ec: "yeo" -0xc5ed: "yeog" -0xc5ee: "yeogg" -0xc5ef: "yeogs" -0xc5f0: "yeon" -0xc5f1: "yeonj" -0xc5f2: "yeonh" -0xc5f3: "yeod" -0xc5f4: "yeol" -0xc5f5: "yeolg" -0xc5f6: "yeolm" -0xc5f7: "yeolb" -0xc5f8: "yeols" -0xc5f9: "yeolt" -0xc5fa: "yeolp" -0xc5fb: "yeolh" -0xc5fc: "yeom" -0xc5fd: "yeob" -0xc5fe: "yeobs" -0xc5ff: "yeos" -/* x0c6 */ -0xc600: "yeoss" -0xc601: "yeong" -0xc602: "yeoj" -0xc603: "yeoc" -0xc604: "yeok" -0xc605: "yeot" -0xc606: "yeop" -0xc607: "yeoh" -0xc608: "ye" -0xc609: "yeg" -0xc60a: "yegg" -0xc60b: "yegs" -0xc60c: "yen" -0xc60d: "yenj" -0xc60e: "yenh" -0xc60f: "yed" -0xc610: "yel" -0xc611: "yelg" -0xc612: "yelm" -0xc613: "yelb" -0xc614: "yels" -0xc615: "yelt" -0xc616: "yelp" -0xc617: "yelh" -0xc618: "yem" -0xc619: "yeb" -0xc61a: "yebs" -0xc61b: "yes" -0xc61c: "yess" -0xc61d: "yeng" -0xc61e: "yej" -0xc61f: "yec" -0xc620: "yek" -0xc621: "yet" -0xc622: "yep" -0xc623: "yeh" -0xc624: "o" -0xc625: "og" -0xc626: "ogg" -0xc627: "ogs" -0xc628: "on" -0xc629: "onj" -0xc62a: "onh" -0xc62b: "od" -0xc62c: "ol" -0xc62d: "olg" -0xc62e: "olm" -0xc62f: "olb" -0xc630: "ols" -0xc631: "olt" -0xc632: "olp" -0xc633: "olh" -0xc634: "om" -0xc635: "ob" -0xc636: "obs" -0xc637: "os" -0xc638: "oss" -0xc639: "ong" -0xc63a: "oj" -0xc63b: "oc" -0xc63c: "ok" -0xc63d: "ot" -0xc63e: "op" -0xc63f: "oh" -0xc640: "wa" -0xc641: "wag" -0xc642: "wagg" -0xc643: "wags" -0xc644: "wan" -0xc645: "wanj" -0xc646: "wanh" -0xc647: "wad" -0xc648: "wal" -0xc649: "walg" -0xc64a: "walm" -0xc64b: "walb" -0xc64c: "wals" -0xc64d: "walt" -0xc64e: "walp" -0xc64f: "walh" -0xc650: "wam" -0xc651: "wab" -0xc652: "wabs" -0xc653: "was" -0xc654: "wass" -0xc655: "wang" -0xc656: "waj" -0xc657: "wac" -0xc658: "wak" -0xc659: "wat" -0xc65a: "wap" -0xc65b: "wah" -0xc65c: "wae" -0xc65d: "waeg" -0xc65e: "waegg" -0xc65f: "waegs" -0xc660: "waen" -0xc661: "waenj" -0xc662: "waenh" -0xc663: "waed" -0xc664: "wael" -0xc665: "waelg" -0xc666: "waelm" -0xc667: "waelb" -0xc668: "waels" -0xc669: "waelt" -0xc66a: "waelp" -0xc66b: "waelh" -0xc66c: "waem" -0xc66d: "waeb" -0xc66e: "waebs" -0xc66f: "waes" -0xc670: "waess" -0xc671: "waeng" -0xc672: "waej" -0xc673: "waec" -0xc674: "waek" -0xc675: "waet" -0xc676: "waep" -0xc677: "waeh" -0xc678: "oe" -0xc679: "oeg" -0xc67a: "oegg" -0xc67b: "oegs" -0xc67c: "oen" -0xc67d: "oenj" -0xc67e: "oenh" -0xc67f: "oed" -0xc680: "oel" -0xc681: "oelg" -0xc682: "oelm" -0xc683: "oelb" -0xc684: "oels" -0xc685: "oelt" -0xc686: "oelp" -0xc687: "oelh" -0xc688: "oem" -0xc689: "oeb" -0xc68a: "oebs" -0xc68b: "oes" -0xc68c: "oess" -0xc68d: "oeng" -0xc68e: "oej" -0xc68f: "oec" -0xc690: "oek" -0xc691: "oet" -0xc692: "oep" -0xc693: "oeh" -0xc694: "yo" -0xc695: "yog" -0xc696: "yogg" -0xc697: "yogs" -0xc698: "yon" -0xc699: "yonj" -0xc69a: "yonh" -0xc69b: "yod" -0xc69c: "yol" -0xc69d: "yolg" -0xc69e: "yolm" -0xc69f: "yolb" -0xc6a0: "yols" -0xc6a1: "yolt" -0xc6a2: "yolp" -0xc6a3: "yolh" -0xc6a4: "yom" -0xc6a5: "yob" -0xc6a6: "yobs" -0xc6a7: "yos" -0xc6a8: "yoss" -0xc6a9: "yong" -0xc6aa: "yoj" -0xc6ab: "yoc" -0xc6ac: "yok" -0xc6ad: "yot" -0xc6ae: "yop" -0xc6af: "yoh" -0xc6b0: "u" -0xc6b1: "ug" -0xc6b2: "ugg" -0xc6b3: "ugs" -0xc6b4: "un" -0xc6b5: "unj" -0xc6b6: "unh" -0xc6b7: "ud" -0xc6b8: "ul" -0xc6b9: "ulg" -0xc6ba: "ulm" -0xc6bb: "ulb" -0xc6bc: "uls" -0xc6bd: "ult" -0xc6be: "ulp" -0xc6bf: "ulh" -0xc6c0: "um" -0xc6c1: "ub" -0xc6c2: "ubs" -0xc6c3: "us" -0xc6c4: "uss" -0xc6c5: "ung" -0xc6c6: "uj" -0xc6c7: "uc" -0xc6c8: "uk" -0xc6c9: "ut" -0xc6ca: "up" -0xc6cb: "uh" -0xc6cc: "weo" -0xc6cd: "weog" -0xc6ce: "weogg" -0xc6cf: "weogs" -0xc6d0: "weon" -0xc6d1: "weonj" -0xc6d2: "weonh" -0xc6d3: "weod" -0xc6d4: "weol" -0xc6d5: "weolg" -0xc6d6: "weolm" -0xc6d7: "weolb" -0xc6d8: "weols" -0xc6d9: "weolt" -0xc6da: "weolp" -0xc6db: "weolh" -0xc6dc: "weom" -0xc6dd: "weob" -0xc6de: "weobs" -0xc6df: "weos" -0xc6e0: "weoss" -0xc6e1: "weong" -0xc6e2: "weoj" -0xc6e3: "weoc" -0xc6e4: "weok" -0xc6e5: "weot" -0xc6e6: "weop" -0xc6e7: "weoh" -0xc6e8: "we" -0xc6e9: "weg" -0xc6ea: "wegg" -0xc6eb: "wegs" -0xc6ec: "wen" -0xc6ed: "wenj" -0xc6ee: "wenh" -0xc6ef: "wed" -0xc6f0: "wel" -0xc6f1: "welg" -0xc6f2: "welm" -0xc6f3: "welb" -0xc6f4: "wels" -0xc6f5: "welt" -0xc6f6: "welp" -0xc6f7: "welh" -0xc6f8: "wem" -0xc6f9: "web" -0xc6fa: "webs" -0xc6fb: "wes" -0xc6fc: "wess" -0xc6fd: "weng" -0xc6fe: "wej" -0xc6ff: "wec" -/* x0c7 */ -0xc700: "wek" -0xc701: "wet" -0xc702: "wep" -0xc703: "weh" -0xc704: "wi" -0xc705: "wig" -0xc706: "wigg" -0xc707: "wigs" -0xc708: "win" -0xc709: "winj" -0xc70a: "winh" -0xc70b: "wid" -0xc70c: "wil" -0xc70d: "wilg" -0xc70e: "wilm" -0xc70f: "wilb" -0xc710: "wils" -0xc711: "wilt" -0xc712: "wilp" -0xc713: "wilh" -0xc714: "wim" -0xc715: "wib" -0xc716: "wibs" -0xc717: "wis" -0xc718: "wiss" -0xc719: "wing" -0xc71a: "wij" -0xc71b: "wic" -0xc71c: "wik" -0xc71d: "wit" -0xc71e: "wip" -0xc71f: "wih" -0xc720: "yu" -0xc721: "yug" -0xc722: "yugg" -0xc723: "yugs" -0xc724: "yun" -0xc725: "yunj" -0xc726: "yunh" -0xc727: "yud" -0xc728: "yul" -0xc729: "yulg" -0xc72a: "yulm" -0xc72b: "yulb" -0xc72c: "yuls" -0xc72d: "yult" -0xc72e: "yulp" -0xc72f: "yulh" -0xc730: "yum" -0xc731: "yub" -0xc732: "yubs" -0xc733: "yus" -0xc734: "yuss" -0xc735: "yung" -0xc736: "yuj" -0xc737: "yuc" -0xc738: "yuk" -0xc739: "yut" -0xc73a: "yup" -0xc73b: "yuh" -0xc73c: "eu" -0xc73d: "eug" -0xc73e: "eugg" -0xc73f: "eugs" -0xc740: "eun" -0xc741: "eunj" -0xc742: "eunh" -0xc743: "eud" -0xc744: "eul" -0xc745: "eulg" -0xc746: "eulm" -0xc747: "eulb" -0xc748: "euls" -0xc749: "eult" -0xc74a: "eulp" -0xc74b: "eulh" -0xc74c: "eum" -0xc74d: "eub" -0xc74e: "eubs" -0xc74f: "eus" -0xc750: "euss" -0xc751: "eung" -0xc752: "euj" -0xc753: "euc" -0xc754: "euk" -0xc755: "eut" -0xc756: "eup" -0xc757: "euh" -0xc758: "yi" -0xc759: "yig" -0xc75a: "yigg" -0xc75b: "yigs" -0xc75c: "yin" -0xc75d: "yinj" -0xc75e: "yinh" -0xc75f: "yid" -0xc760: "yil" -0xc761: "yilg" -0xc762: "yilm" -0xc763: "yilb" -0xc764: "yils" -0xc765: "yilt" -0xc766: "yilp" -0xc767: "yilh" -0xc768: "yim" -0xc769: "yib" -0xc76a: "yibs" -0xc76b: "yis" -0xc76c: "yiss" -0xc76d: "ying" -0xc76e: "yij" -0xc76f: "yic" -0xc770: "yik" -0xc771: "yit" -0xc772: "yip" -0xc773: "yih" -0xc774: "i" -0xc775: "ig" -0xc776: "igg" -0xc777: "igs" -0xc778: "in" -0xc779: "inj" -0xc77a: "inh" -0xc77b: "id" -0xc77c: "il" -0xc77d: "ilg" -0xc77e: "ilm" -0xc77f: "ilb" -0xc780: "ils" -0xc781: "ilt" -0xc782: "ilp" -0xc783: "ilh" -0xc784: "im" -0xc785: "ib" -0xc786: "ibs" -0xc787: "is" -0xc788: "iss" -0xc789: "ing" -0xc78a: "ij" -0xc78b: "ic" -0xc78c: "ik" -0xc78d: "it" -0xc78e: "ip" -0xc78f: "ih" -0xc790: "ja" -0xc791: "jag" -0xc792: "jagg" -0xc793: "jags" -0xc794: "jan" -0xc795: "janj" -0xc796: "janh" -0xc797: "jad" -0xc798: "jal" -0xc799: "jalg" -0xc79a: "jalm" -0xc79b: "jalb" -0xc79c: "jals" -0xc79d: "jalt" -0xc79e: "jalp" -0xc79f: "jalh" -0xc7a0: "jam" -0xc7a1: "jab" -0xc7a2: "jabs" -0xc7a3: "jas" -0xc7a4: "jass" -0xc7a5: "jang" -0xc7a6: "jaj" -0xc7a7: "jac" -0xc7a8: "jak" -0xc7a9: "jat" -0xc7aa: "jap" -0xc7ab: "jah" -0xc7ac: "jae" -0xc7ad: "jaeg" -0xc7ae: "jaegg" -0xc7af: "jaegs" -0xc7b0: "jaen" -0xc7b1: "jaenj" -0xc7b2: "jaenh" -0xc7b3: "jaed" -0xc7b4: "jael" -0xc7b5: "jaelg" -0xc7b6: "jaelm" -0xc7b7: "jaelb" -0xc7b8: "jaels" -0xc7b9: "jaelt" -0xc7ba: "jaelp" -0xc7bb: "jaelh" -0xc7bc: "jaem" -0xc7bd: "jaeb" -0xc7be: "jaebs" -0xc7bf: "jaes" -0xc7c0: "jaess" -0xc7c1: "jaeng" -0xc7c2: "jaej" -0xc7c3: "jaec" -0xc7c4: "jaek" -0xc7c5: "jaet" -0xc7c6: "jaep" -0xc7c7: "jaeh" -0xc7c8: "jya" -0xc7c9: "jyag" -0xc7ca: "jyagg" -0xc7cb: "jyags" -0xc7cc: "jyan" -0xc7cd: "jyanj" -0xc7ce: "jyanh" -0xc7cf: "jyad" -0xc7d0: "jyal" -0xc7d1: "jyalg" -0xc7d2: "jyalm" -0xc7d3: "jyalb" -0xc7d4: "jyals" -0xc7d5: "jyalt" -0xc7d6: "jyalp" -0xc7d7: "jyalh" -0xc7d8: "jyam" -0xc7d9: "jyab" -0xc7da: "jyabs" -0xc7db: "jyas" -0xc7dc: "jyass" -0xc7dd: "jyang" -0xc7de: "jyaj" -0xc7df: "jyac" -0xc7e0: "jyak" -0xc7e1: "jyat" -0xc7e2: "jyap" -0xc7e3: "jyah" -0xc7e4: "jyae" -0xc7e5: "jyaeg" -0xc7e6: "jyaegg" -0xc7e7: "jyaegs" -0xc7e8: "jyaen" -0xc7e9: "jyaenj" -0xc7ea: "jyaenh" -0xc7eb: "jyaed" -0xc7ec: "jyael" -0xc7ed: "jyaelg" -0xc7ee: "jyaelm" -0xc7ef: "jyaelb" -0xc7f0: "jyaels" -0xc7f1: "jyaelt" -0xc7f2: "jyaelp" -0xc7f3: "jyaelh" -0xc7f4: "jyaem" -0xc7f5: "jyaeb" -0xc7f6: "jyaebs" -0xc7f7: "jyaes" -0xc7f8: "jyaess" -0xc7f9: "jyaeng" -0xc7fa: "jyaej" -0xc7fb: "jyaec" -0xc7fc: "jyaek" -0xc7fd: "jyaet" -0xc7fe: "jyaep" -0xc7ff: "jyaeh" -/* x0c8 */ -0xc800: "jeo" -0xc801: "jeog" -0xc802: "jeogg" -0xc803: "jeogs" -0xc804: "jeon" -0xc805: "jeonj" -0xc806: "jeonh" -0xc807: "jeod" -0xc808: "jeol" -0xc809: "jeolg" -0xc80a: "jeolm" -0xc80b: "jeolb" -0xc80c: "jeols" -0xc80d: "jeolt" -0xc80e: "jeolp" -0xc80f: "jeolh" -0xc810: "jeom" -0xc811: "jeob" -0xc812: "jeobs" -0xc813: "jeos" -0xc814: "jeoss" -0xc815: "jeong" -0xc816: "jeoj" -0xc817: "jeoc" -0xc818: "jeok" -0xc819: "jeot" -0xc81a: "jeop" -0xc81b: "jeoh" -0xc81c: "je" -0xc81d: "jeg" -0xc81e: "jegg" -0xc81f: "jegs" -0xc820: "jen" -0xc821: "jenj" -0xc822: "jenh" -0xc823: "jed" -0xc824: "jel" -0xc825: "jelg" -0xc826: "jelm" -0xc827: "jelb" -0xc828: "jels" -0xc829: "jelt" -0xc82a: "jelp" -0xc82b: "jelh" -0xc82c: "jem" -0xc82d: "jeb" -0xc82e: "jebs" -0xc82f: "jes" -0xc830: "jess" -0xc831: "jeng" -0xc832: "jej" -0xc833: "jec" -0xc834: "jek" -0xc835: "jet" -0xc836: "jep" -0xc837: "jeh" -0xc838: "jyeo" -0xc839: "jyeog" -0xc83a: "jyeogg" -0xc83b: "jyeogs" -0xc83c: "jyeon" -0xc83d: "jyeonj" -0xc83e: "jyeonh" -0xc83f: "jyeod" -0xc840: "jyeol" -0xc841: "jyeolg" -0xc842: "jyeolm" -0xc843: "jyeolb" -0xc844: "jyeols" -0xc845: "jyeolt" -0xc846: "jyeolp" -0xc847: "jyeolh" -0xc848: "jyeom" -0xc849: "jyeob" -0xc84a: "jyeobs" -0xc84b: "jyeos" -0xc84c: "jyeoss" -0xc84d: "jyeong" -0xc84e: "jyeoj" -0xc84f: "jyeoc" -0xc850: "jyeok" -0xc851: "jyeot" -0xc852: "jyeop" -0xc853: "jyeoh" -0xc854: "jye" -0xc855: "jyeg" -0xc856: "jyegg" -0xc857: "jyegs" -0xc858: "jyen" -0xc859: "jyenj" -0xc85a: "jyenh" -0xc85b: "jyed" -0xc85c: "jyel" -0xc85d: "jyelg" -0xc85e: "jyelm" -0xc85f: "jyelb" -0xc860: "jyels" -0xc861: "jyelt" -0xc862: "jyelp" -0xc863: "jyelh" -0xc864: "jyem" -0xc865: "jyeb" -0xc866: "jyebs" -0xc867: "jyes" -0xc868: "jyess" -0xc869: "jyeng" -0xc86a: "jyej" -0xc86b: "jyec" -0xc86c: "jyek" -0xc86d: "jyet" -0xc86e: "jyep" -0xc86f: "jyeh" -0xc870: "jo" -0xc871: "jog" -0xc872: "jogg" -0xc873: "jogs" -0xc874: "jon" -0xc875: "jonj" -0xc876: "jonh" -0xc877: "jod" -0xc878: "jol" -0xc879: "jolg" -0xc87a: "jolm" -0xc87b: "jolb" -0xc87c: "jols" -0xc87d: "jolt" -0xc87e: "jolp" -0xc87f: "jolh" -0xc880: "jom" -0xc881: "job" -0xc882: "jobs" -0xc883: "jos" -0xc884: "joss" -0xc885: "jong" -0xc886: "joj" -0xc887: "joc" -0xc888: "jok" -0xc889: "jot" -0xc88a: "jop" -0xc88b: "joh" -0xc88c: "jwa" -0xc88d: "jwag" -0xc88e: "jwagg" -0xc88f: "jwags" -0xc890: "jwan" -0xc891: "jwanj" -0xc892: "jwanh" -0xc893: "jwad" -0xc894: "jwal" -0xc895: "jwalg" -0xc896: "jwalm" -0xc897: "jwalb" -0xc898: "jwals" -0xc899: "jwalt" -0xc89a: "jwalp" -0xc89b: "jwalh" -0xc89c: "jwam" -0xc89d: "jwab" -0xc89e: "jwabs" -0xc89f: "jwas" -0xc8a0: "jwass" -0xc8a1: "jwang" -0xc8a2: "jwaj" -0xc8a3: "jwac" -0xc8a4: "jwak" -0xc8a5: "jwat" -0xc8a6: "jwap" -0xc8a7: "jwah" -0xc8a8: "jwae" -0xc8a9: "jwaeg" -0xc8aa: "jwaegg" -0xc8ab: "jwaegs" -0xc8ac: "jwaen" -0xc8ad: "jwaenj" -0xc8ae: "jwaenh" -0xc8af: "jwaed" -0xc8b0: "jwael" -0xc8b1: "jwaelg" -0xc8b2: "jwaelm" -0xc8b3: "jwaelb" -0xc8b4: "jwaels" -0xc8b5: "jwaelt" -0xc8b6: "jwaelp" -0xc8b7: "jwaelh" -0xc8b8: "jwaem" -0xc8b9: "jwaeb" -0xc8ba: "jwaebs" -0xc8bb: "jwaes" -0xc8bc: "jwaess" -0xc8bd: "jwaeng" -0xc8be: "jwaej" -0xc8bf: "jwaec" -0xc8c0: "jwaek" -0xc8c1: "jwaet" -0xc8c2: "jwaep" -0xc8c3: "jwaeh" -0xc8c4: "joe" -0xc8c5: "joeg" -0xc8c6: "joegg" -0xc8c7: "joegs" -0xc8c8: "joen" -0xc8c9: "joenj" -0xc8ca: "joenh" -0xc8cb: "joed" -0xc8cc: "joel" -0xc8cd: "joelg" -0xc8ce: "joelm" -0xc8cf: "joelb" -0xc8d0: "joels" -0xc8d1: "joelt" -0xc8d2: "joelp" -0xc8d3: "joelh" -0xc8d4: "joem" -0xc8d5: "joeb" -0xc8d6: "joebs" -0xc8d7: "joes" -0xc8d8: "joess" -0xc8d9: "joeng" -0xc8da: "joej" -0xc8db: "joec" -0xc8dc: "joek" -0xc8dd: "joet" -0xc8de: "joep" -0xc8df: "joeh" -0xc8e0: "jyo" -0xc8e1: "jyog" -0xc8e2: "jyogg" -0xc8e3: "jyogs" -0xc8e4: "jyon" -0xc8e5: "jyonj" -0xc8e6: "jyonh" -0xc8e7: "jyod" -0xc8e8: "jyol" -0xc8e9: "jyolg" -0xc8ea: "jyolm" -0xc8eb: "jyolb" -0xc8ec: "jyols" -0xc8ed: "jyolt" -0xc8ee: "jyolp" -0xc8ef: "jyolh" -0xc8f0: "jyom" -0xc8f1: "jyob" -0xc8f2: "jyobs" -0xc8f3: "jyos" -0xc8f4: "jyoss" -0xc8f5: "jyong" -0xc8f6: "jyoj" -0xc8f7: "jyoc" -0xc8f8: "jyok" -0xc8f9: "jyot" -0xc8fa: "jyop" -0xc8fb: "jyoh" -0xc8fc: "ju" -0xc8fd: "jug" -0xc8fe: "jugg" -0xc8ff: "jugs" -/* x0c9 */ -0xc900: "jun" -0xc901: "junj" -0xc902: "junh" -0xc903: "jud" -0xc904: "jul" -0xc905: "julg" -0xc906: "julm" -0xc907: "julb" -0xc908: "juls" -0xc909: "jult" -0xc90a: "julp" -0xc90b: "julh" -0xc90c: "jum" -0xc90d: "jub" -0xc90e: "jubs" -0xc90f: "jus" -0xc910: "juss" -0xc911: "jung" -0xc912: "juj" -0xc913: "juc" -0xc914: "juk" -0xc915: "jut" -0xc916: "jup" -0xc917: "juh" -0xc918: "jweo" -0xc919: "jweog" -0xc91a: "jweogg" -0xc91b: "jweogs" -0xc91c: "jweon" -0xc91d: "jweonj" -0xc91e: "jweonh" -0xc91f: "jweod" -0xc920: "jweol" -0xc921: "jweolg" -0xc922: "jweolm" -0xc923: "jweolb" -0xc924: "jweols" -0xc925: "jweolt" -0xc926: "jweolp" -0xc927: "jweolh" -0xc928: "jweom" -0xc929: "jweob" -0xc92a: "jweobs" -0xc92b: "jweos" -0xc92c: "jweoss" -0xc92d: "jweong" -0xc92e: "jweoj" -0xc92f: "jweoc" -0xc930: "jweok" -0xc931: "jweot" -0xc932: "jweop" -0xc933: "jweoh" -0xc934: "jwe" -0xc935: "jweg" -0xc936: "jwegg" -0xc937: "jwegs" -0xc938: "jwen" -0xc939: "jwenj" -0xc93a: "jwenh" -0xc93b: "jwed" -0xc93c: "jwel" -0xc93d: "jwelg" -0xc93e: "jwelm" -0xc93f: "jwelb" -0xc940: "jwels" -0xc941: "jwelt" -0xc942: "jwelp" -0xc943: "jwelh" -0xc944: "jwem" -0xc945: "jweb" -0xc946: "jwebs" -0xc947: "jwes" -0xc948: "jwess" -0xc949: "jweng" -0xc94a: "jwej" -0xc94b: "jwec" -0xc94c: "jwek" -0xc94d: "jwet" -0xc94e: "jwep" -0xc94f: "jweh" -0xc950: "jwi" -0xc951: "jwig" -0xc952: "jwigg" -0xc953: "jwigs" -0xc954: "jwin" -0xc955: "jwinj" -0xc956: "jwinh" -0xc957: "jwid" -0xc958: "jwil" -0xc959: "jwilg" -0xc95a: "jwilm" -0xc95b: "jwilb" -0xc95c: "jwils" -0xc95d: "jwilt" -0xc95e: "jwilp" -0xc95f: "jwilh" -0xc960: "jwim" -0xc961: "jwib" -0xc962: "jwibs" -0xc963: "jwis" -0xc964: "jwiss" -0xc965: "jwing" -0xc966: "jwij" -0xc967: "jwic" -0xc968: "jwik" -0xc969: "jwit" -0xc96a: "jwip" -0xc96b: "jwih" -0xc96c: "jyu" -0xc96d: "jyug" -0xc96e: "jyugg" -0xc96f: "jyugs" -0xc970: "jyun" -0xc971: "jyunj" -0xc972: "jyunh" -0xc973: "jyud" -0xc974: "jyul" -0xc975: "jyulg" -0xc976: "jyulm" -0xc977: "jyulb" -0xc978: "jyuls" -0xc979: "jyult" -0xc97a: "jyulp" -0xc97b: "jyulh" -0xc97c: "jyum" -0xc97d: "jyub" -0xc97e: "jyubs" -0xc97f: "jyus" -0xc980: "jyuss" -0xc981: "jyung" -0xc982: "jyuj" -0xc983: "jyuc" -0xc984: "jyuk" -0xc985: "jyut" -0xc986: "jyup" -0xc987: "jyuh" -0xc988: "jeu" -0xc989: "jeug" -0xc98a: "jeugg" -0xc98b: "jeugs" -0xc98c: "jeun" -0xc98d: "jeunj" -0xc98e: "jeunh" -0xc98f: "jeud" -0xc990: "jeul" -0xc991: "jeulg" -0xc992: "jeulm" -0xc993: "jeulb" -0xc994: "jeuls" -0xc995: "jeult" -0xc996: "jeulp" -0xc997: "jeulh" -0xc998: "jeum" -0xc999: "jeub" -0xc99a: "jeubs" -0xc99b: "jeus" -0xc99c: "jeuss" -0xc99d: "jeung" -0xc99e: "jeuj" -0xc99f: "jeuc" -0xc9a0: "jeuk" -0xc9a1: "jeut" -0xc9a2: "jeup" -0xc9a3: "jeuh" -0xc9a4: "jyi" -0xc9a5: "jyig" -0xc9a6: "jyigg" -0xc9a7: "jyigs" -0xc9a8: "jyin" -0xc9a9: "jyinj" -0xc9aa: "jyinh" -0xc9ab: "jyid" -0xc9ac: "jyil" -0xc9ad: "jyilg" -0xc9ae: "jyilm" -0xc9af: "jyilb" -0xc9b0: "jyils" -0xc9b1: "jyilt" -0xc9b2: "jyilp" -0xc9b3: "jyilh" -0xc9b4: "jyim" -0xc9b5: "jyib" -0xc9b6: "jyibs" -0xc9b7: "jyis" -0xc9b8: "jyiss" -0xc9b9: "jying" -0xc9ba: "jyij" -0xc9bb: "jyic" -0xc9bc: "jyik" -0xc9bd: "jyit" -0xc9be: "jyip" -0xc9bf: "jyih" -0xc9c0: "ji" -0xc9c1: "jig" -0xc9c2: "jigg" -0xc9c3: "jigs" -0xc9c4: "jin" -0xc9c5: "jinj" -0xc9c6: "jinh" -0xc9c7: "jid" -0xc9c8: "jil" -0xc9c9: "jilg" -0xc9ca: "jilm" -0xc9cb: "jilb" -0xc9cc: "jils" -0xc9cd: "jilt" -0xc9ce: "jilp" -0xc9cf: "jilh" -0xc9d0: "jim" -0xc9d1: "jib" -0xc9d2: "jibs" -0xc9d3: "jis" -0xc9d4: "jiss" -0xc9d5: "jing" -0xc9d6: "jij" -0xc9d7: "jic" -0xc9d8: "jik" -0xc9d9: "jit" -0xc9da: "jip" -0xc9db: "jih" -0xc9dc: "jja" -0xc9dd: "jjag" -0xc9de: "jjagg" -0xc9df: "jjags" -0xc9e0: "jjan" -0xc9e1: "jjanj" -0xc9e2: "jjanh" -0xc9e3: "jjad" -0xc9e4: "jjal" -0xc9e5: "jjalg" -0xc9e6: "jjalm" -0xc9e7: "jjalb" -0xc9e8: "jjals" -0xc9e9: "jjalt" -0xc9ea: "jjalp" -0xc9eb: "jjalh" -0xc9ec: "jjam" -0xc9ed: "jjab" -0xc9ee: "jjabs" -0xc9ef: "jjas" -0xc9f0: "jjass" -0xc9f1: "jjang" -0xc9f2: "jjaj" -0xc9f3: "jjac" -0xc9f4: "jjak" -0xc9f5: "jjat" -0xc9f6: "jjap" -0xc9f7: "jjah" -0xc9f8: "jjae" -0xc9f9: "jjaeg" -0xc9fa: "jjaegg" -0xc9fb: "jjaegs" -0xc9fc: "jjaen" -0xc9fd: "jjaenj" -0xc9fe: "jjaenh" -0xc9ff: "jjaed" -/* x0ca */ -0xca00: "jjael" -0xca01: "jjaelg" -0xca02: "jjaelm" -0xca03: "jjaelb" -0xca04: "jjaels" -0xca05: "jjaelt" -0xca06: "jjaelp" -0xca07: "jjaelh" -0xca08: "jjaem" -0xca09: "jjaeb" -0xca0a: "jjaebs" -0xca0b: "jjaes" -0xca0c: "jjaess" -0xca0d: "jjaeng" -0xca0e: "jjaej" -0xca0f: "jjaec" -0xca10: "jjaek" -0xca11: "jjaet" -0xca12: "jjaep" -0xca13: "jjaeh" -0xca14: "jjya" -0xca15: "jjyag" -0xca16: "jjyagg" -0xca17: "jjyags" -0xca18: "jjyan" -0xca19: "jjyanj" -0xca1a: "jjyanh" -0xca1b: "jjyad" -0xca1c: "jjyal" -0xca1d: "jjyalg" -0xca1e: "jjyalm" -0xca1f: "jjyalb" -0xca20: "jjyals" -0xca21: "jjyalt" -0xca22: "jjyalp" -0xca23: "jjyalh" -0xca24: "jjyam" -0xca25: "jjyab" -0xca26: "jjyabs" -0xca27: "jjyas" -0xca28: "jjyass" -0xca29: "jjyang" -0xca2a: "jjyaj" -0xca2b: "jjyac" -0xca2c: "jjyak" -0xca2d: "jjyat" -0xca2e: "jjyap" -0xca2f: "jjyah" -0xca30: "jjyae" -0xca31: "jjyaeg" -0xca32: "jjyaegg" -0xca33: "jjyaegs" -0xca34: "jjyaen" -0xca35: "jjyaenj" -0xca36: "jjyaenh" -0xca37: "jjyaed" -0xca38: "jjyael" -0xca39: "jjyaelg" -0xca3a: "jjyaelm" -0xca3b: "jjyaelb" -0xca3c: "jjyaels" -0xca3d: "jjyaelt" -0xca3e: "jjyaelp" -0xca3f: "jjyaelh" -0xca40: "jjyaem" -0xca41: "jjyaeb" -0xca42: "jjyaebs" -0xca43: "jjyaes" -0xca44: "jjyaess" -0xca45: "jjyaeng" -0xca46: "jjyaej" -0xca47: "jjyaec" -0xca48: "jjyaek" -0xca49: "jjyaet" -0xca4a: "jjyaep" -0xca4b: "jjyaeh" -0xca4c: "jjeo" -0xca4d: "jjeog" -0xca4e: "jjeogg" -0xca4f: "jjeogs" -0xca50: "jjeon" -0xca51: "jjeonj" -0xca52: "jjeonh" -0xca53: "jjeod" -0xca54: "jjeol" -0xca55: "jjeolg" -0xca56: "jjeolm" -0xca57: "jjeolb" -0xca58: "jjeols" -0xca59: "jjeolt" -0xca5a: "jjeolp" -0xca5b: "jjeolh" -0xca5c: "jjeom" -0xca5d: "jjeob" -0xca5e: "jjeobs" -0xca5f: "jjeos" -0xca60: "jjeoss" -0xca61: "jjeong" -0xca62: "jjeoj" -0xca63: "jjeoc" -0xca64: "jjeok" -0xca65: "jjeot" -0xca66: "jjeop" -0xca67: "jjeoh" -0xca68: "jje" -0xca69: "jjeg" -0xca6a: "jjegg" -0xca6b: "jjegs" -0xca6c: "jjen" -0xca6d: "jjenj" -0xca6e: "jjenh" -0xca6f: "jjed" -0xca70: "jjel" -0xca71: "jjelg" -0xca72: "jjelm" -0xca73: "jjelb" -0xca74: "jjels" -0xca75: "jjelt" -0xca76: "jjelp" -0xca77: "jjelh" -0xca78: "jjem" -0xca79: "jjeb" -0xca7a: "jjebs" -0xca7b: "jjes" -0xca7c: "jjess" -0xca7d: "jjeng" -0xca7e: "jjej" -0xca7f: "jjec" -0xca80: "jjek" -0xca81: "jjet" -0xca82: "jjep" -0xca83: "jjeh" -0xca84: "jjyeo" -0xca85: "jjyeog" -0xca86: "jjyeogg" -0xca87: "jjyeogs" -0xca88: "jjyeon" -0xca89: "jjyeonj" -0xca8a: "jjyeonh" -0xca8b: "jjyeod" -0xca8c: "jjyeol" -0xca8d: "jjyeolg" -0xca8e: "jjyeolm" -0xca8f: "jjyeolb" -0xca90: "jjyeols" -0xca91: "jjyeolt" -0xca92: "jjyeolp" -0xca93: "jjyeolh" -0xca94: "jjyeom" -0xca95: "jjyeob" -0xca96: "jjyeobs" -0xca97: "jjyeos" -0xca98: "jjyeoss" -0xca99: "jjyeong" -0xca9a: "jjyeoj" -0xca9b: "jjyeoc" -0xca9c: "jjyeok" -0xca9d: "jjyeot" -0xca9e: "jjyeop" -0xca9f: "jjyeoh" -0xcaa0: "jjye" -0xcaa1: "jjyeg" -0xcaa2: "jjyegg" -0xcaa3: "jjyegs" -0xcaa4: "jjyen" -0xcaa5: "jjyenj" -0xcaa6: "jjyenh" -0xcaa7: "jjyed" -0xcaa8: "jjyel" -0xcaa9: "jjyelg" -0xcaaa: "jjyelm" -0xcaab: "jjyelb" -0xcaac: "jjyels" -0xcaad: "jjyelt" -0xcaae: "jjyelp" -0xcaaf: "jjyelh" -0xcab0: "jjyem" -0xcab1: "jjyeb" -0xcab2: "jjyebs" -0xcab3: "jjyes" -0xcab4: "jjyess" -0xcab5: "jjyeng" -0xcab6: "jjyej" -0xcab7: "jjyec" -0xcab8: "jjyek" -0xcab9: "jjyet" -0xcaba: "jjyep" -0xcabb: "jjyeh" -0xcabc: "jjo" -0xcabd: "jjog" -0xcabe: "jjogg" -0xcabf: "jjogs" -0xcac0: "jjon" -0xcac1: "jjonj" -0xcac2: "jjonh" -0xcac3: "jjod" -0xcac4: "jjol" -0xcac5: "jjolg" -0xcac6: "jjolm" -0xcac7: "jjolb" -0xcac8: "jjols" -0xcac9: "jjolt" -0xcaca: "jjolp" -0xcacb: "jjolh" -0xcacc: "jjom" -0xcacd: "jjob" -0xcace: "jjobs" -0xcacf: "jjos" -0xcad0: "jjoss" -0xcad1: "jjong" -0xcad2: "jjoj" -0xcad3: "jjoc" -0xcad4: "jjok" -0xcad5: "jjot" -0xcad6: "jjop" -0xcad7: "jjoh" -0xcad8: "jjwa" -0xcad9: "jjwag" -0xcada: "jjwagg" -0xcadb: "jjwags" -0xcadc: "jjwan" -0xcadd: "jjwanj" -0xcade: "jjwanh" -0xcadf: "jjwad" -0xcae0: "jjwal" -0xcae1: "jjwalg" -0xcae2: "jjwalm" -0xcae3: "jjwalb" -0xcae4: "jjwals" -0xcae5: "jjwalt" -0xcae6: "jjwalp" -0xcae7: "jjwalh" -0xcae8: "jjwam" -0xcae9: "jjwab" -0xcaea: "jjwabs" -0xcaeb: "jjwas" -0xcaec: "jjwass" -0xcaed: "jjwang" -0xcaee: "jjwaj" -0xcaef: "jjwac" -0xcaf0: "jjwak" -0xcaf1: "jjwat" -0xcaf2: "jjwap" -0xcaf3: "jjwah" -0xcaf4: "jjwae" -0xcaf5: "jjwaeg" -0xcaf6: "jjwaegg" -0xcaf7: "jjwaegs" -0xcaf8: "jjwaen" -0xcaf9: "jjwaenj" -0xcafa: "jjwaenh" -0xcafb: "jjwaed" -0xcafc: "jjwael" -0xcafd: "jjwaelg" -0xcafe: "jjwaelm" -0xcaff: "jjwaelb" -/* x0cb */ -0xcb00: "jjwaels" -0xcb01: "jjwaelt" -0xcb02: "jjwaelp" -0xcb03: "jjwaelh" -0xcb04: "jjwaem" -0xcb05: "jjwaeb" -0xcb06: "jjwaebs" -0xcb07: "jjwaes" -0xcb08: "jjwaess" -0xcb09: "jjwaeng" -0xcb0a: "jjwaej" -0xcb0b: "jjwaec" -0xcb0c: "jjwaek" -0xcb0d: "jjwaet" -0xcb0e: "jjwaep" -0xcb0f: "jjwaeh" -0xcb10: "jjoe" -0xcb11: "jjoeg" -0xcb12: "jjoegg" -0xcb13: "jjoegs" -0xcb14: "jjoen" -0xcb15: "jjoenj" -0xcb16: "jjoenh" -0xcb17: "jjoed" -0xcb18: "jjoel" -0xcb19: "jjoelg" -0xcb1a: "jjoelm" -0xcb1b: "jjoelb" -0xcb1c: "jjoels" -0xcb1d: "jjoelt" -0xcb1e: "jjoelp" -0xcb1f: "jjoelh" -0xcb20: "jjoem" -0xcb21: "jjoeb" -0xcb22: "jjoebs" -0xcb23: "jjoes" -0xcb24: "jjoess" -0xcb25: "jjoeng" -0xcb26: "jjoej" -0xcb27: "jjoec" -0xcb28: "jjoek" -0xcb29: "jjoet" -0xcb2a: "jjoep" -0xcb2b: "jjoeh" -0xcb2c: "jjyo" -0xcb2d: "jjyog" -0xcb2e: "jjyogg" -0xcb2f: "jjyogs" -0xcb30: "jjyon" -0xcb31: "jjyonj" -0xcb32: "jjyonh" -0xcb33: "jjyod" -0xcb34: "jjyol" -0xcb35: "jjyolg" -0xcb36: "jjyolm" -0xcb37: "jjyolb" -0xcb38: "jjyols" -0xcb39: "jjyolt" -0xcb3a: "jjyolp" -0xcb3b: "jjyolh" -0xcb3c: "jjyom" -0xcb3d: "jjyob" -0xcb3e: "jjyobs" -0xcb3f: "jjyos" -0xcb40: "jjyoss" -0xcb41: "jjyong" -0xcb42: "jjyoj" -0xcb43: "jjyoc" -0xcb44: "jjyok" -0xcb45: "jjyot" -0xcb46: "jjyop" -0xcb47: "jjyoh" -0xcb48: "jju" -0xcb49: "jjug" -0xcb4a: "jjugg" -0xcb4b: "jjugs" -0xcb4c: "jjun" -0xcb4d: "jjunj" -0xcb4e: "jjunh" -0xcb4f: "jjud" -0xcb50: "jjul" -0xcb51: "jjulg" -0xcb52: "jjulm" -0xcb53: "jjulb" -0xcb54: "jjuls" -0xcb55: "jjult" -0xcb56: "jjulp" -0xcb57: "jjulh" -0xcb58: "jjum" -0xcb59: "jjub" -0xcb5a: "jjubs" -0xcb5b: "jjus" -0xcb5c: "jjuss" -0xcb5d: "jjung" -0xcb5e: "jjuj" -0xcb5f: "jjuc" -0xcb60: "jjuk" -0xcb61: "jjut" -0xcb62: "jjup" -0xcb63: "jjuh" -0xcb64: "jjweo" -0xcb65: "jjweog" -0xcb66: "jjweogg" -0xcb67: "jjweogs" -0xcb68: "jjweon" -0xcb69: "jjweonj" -0xcb6a: "jjweonh" -0xcb6b: "jjweod" -0xcb6c: "jjweol" -0xcb6d: "jjweolg" -0xcb6e: "jjweolm" -0xcb6f: "jjweolb" -0xcb70: "jjweols" -0xcb71: "jjweolt" -0xcb72: "jjweolp" -0xcb73: "jjweolh" -0xcb74: "jjweom" -0xcb75: "jjweob" -0xcb76: "jjweobs" -0xcb77: "jjweos" -0xcb78: "jjweoss" -0xcb79: "jjweong" -0xcb7a: "jjweoj" -0xcb7b: "jjweoc" -0xcb7c: "jjweok" -0xcb7d: "jjweot" -0xcb7e: "jjweop" -0xcb7f: "jjweoh" -0xcb80: "jjwe" -0xcb81: "jjweg" -0xcb82: "jjwegg" -0xcb83: "jjwegs" -0xcb84: "jjwen" -0xcb85: "jjwenj" -0xcb86: "jjwenh" -0xcb87: "jjwed" -0xcb88: "jjwel" -0xcb89: "jjwelg" -0xcb8a: "jjwelm" -0xcb8b: "jjwelb" -0xcb8c: "jjwels" -0xcb8d: "jjwelt" -0xcb8e: "jjwelp" -0xcb8f: "jjwelh" -0xcb90: "jjwem" -0xcb91: "jjweb" -0xcb92: "jjwebs" -0xcb93: "jjwes" -0xcb94: "jjwess" -0xcb95: "jjweng" -0xcb96: "jjwej" -0xcb97: "jjwec" -0xcb98: "jjwek" -0xcb99: "jjwet" -0xcb9a: "jjwep" -0xcb9b: "jjweh" -0xcb9c: "jjwi" -0xcb9d: "jjwig" -0xcb9e: "jjwigg" -0xcb9f: "jjwigs" -0xcba0: "jjwin" -0xcba1: "jjwinj" -0xcba2: "jjwinh" -0xcba3: "jjwid" -0xcba4: "jjwil" -0xcba5: "jjwilg" -0xcba6: "jjwilm" -0xcba7: "jjwilb" -0xcba8: "jjwils" -0xcba9: "jjwilt" -0xcbaa: "jjwilp" -0xcbab: "jjwilh" -0xcbac: "jjwim" -0xcbad: "jjwib" -0xcbae: "jjwibs" -0xcbaf: "jjwis" -0xcbb0: "jjwiss" -0xcbb1: "jjwing" -0xcbb2: "jjwij" -0xcbb3: "jjwic" -0xcbb4: "jjwik" -0xcbb5: "jjwit" -0xcbb6: "jjwip" -0xcbb7: "jjwih" -0xcbb8: "jjyu" -0xcbb9: "jjyug" -0xcbba: "jjyugg" -0xcbbb: "jjyugs" -0xcbbc: "jjyun" -0xcbbd: "jjyunj" -0xcbbe: "jjyunh" -0xcbbf: "jjyud" -0xcbc0: "jjyul" -0xcbc1: "jjyulg" -0xcbc2: "jjyulm" -0xcbc3: "jjyulb" -0xcbc4: "jjyuls" -0xcbc5: "jjyult" -0xcbc6: "jjyulp" -0xcbc7: "jjyulh" -0xcbc8: "jjyum" -0xcbc9: "jjyub" -0xcbca: "jjyubs" -0xcbcb: "jjyus" -0xcbcc: "jjyuss" -0xcbcd: "jjyung" -0xcbce: "jjyuj" -0xcbcf: "jjyuc" -0xcbd0: "jjyuk" -0xcbd1: "jjyut" -0xcbd2: "jjyup" -0xcbd3: "jjyuh" -0xcbd4: "jjeu" -0xcbd5: "jjeug" -0xcbd6: "jjeugg" -0xcbd7: "jjeugs" -0xcbd8: "jjeun" -0xcbd9: "jjeunj" -0xcbda: "jjeunh" -0xcbdb: "jjeud" -0xcbdc: "jjeul" -0xcbdd: "jjeulg" -0xcbde: "jjeulm" -0xcbdf: "jjeulb" -0xcbe0: "jjeuls" -0xcbe1: "jjeult" -0xcbe2: "jjeulp" -0xcbe3: "jjeulh" -0xcbe4: "jjeum" -0xcbe5: "jjeub" -0xcbe6: "jjeubs" -0xcbe7: "jjeus" -0xcbe8: "jjeuss" -0xcbe9: "jjeung" -0xcbea: "jjeuj" -0xcbeb: "jjeuc" -0xcbec: "jjeuk" -0xcbed: "jjeut" -0xcbee: "jjeup" -0xcbef: "jjeuh" -0xcbf0: "jjyi" -0xcbf1: "jjyig" -0xcbf2: "jjyigg" -0xcbf3: "jjyigs" -0xcbf4: "jjyin" -0xcbf5: "jjyinj" -0xcbf6: "jjyinh" -0xcbf7: "jjyid" -0xcbf8: "jjyil" -0xcbf9: "jjyilg" -0xcbfa: "jjyilm" -0xcbfb: "jjyilb" -0xcbfc: "jjyils" -0xcbfd: "jjyilt" -0xcbfe: "jjyilp" -0xcbff: "jjyilh" -/* x0cc */ -0xcc00: "jjyim" -0xcc01: "jjyib" -0xcc02: "jjyibs" -0xcc03: "jjyis" -0xcc04: "jjyiss" -0xcc05: "jjying" -0xcc06: "jjyij" -0xcc07: "jjyic" -0xcc08: "jjyik" -0xcc09: "jjyit" -0xcc0a: "jjyip" -0xcc0b: "jjyih" -0xcc0c: "jji" -0xcc0d: "jjig" -0xcc0e: "jjigg" -0xcc0f: "jjigs" -0xcc10: "jjin" -0xcc11: "jjinj" -0xcc12: "jjinh" -0xcc13: "jjid" -0xcc14: "jjil" -0xcc15: "jjilg" -0xcc16: "jjilm" -0xcc17: "jjilb" -0xcc18: "jjils" -0xcc19: "jjilt" -0xcc1a: "jjilp" -0xcc1b: "jjilh" -0xcc1c: "jjim" -0xcc1d: "jjib" -0xcc1e: "jjibs" -0xcc1f: "jjis" -0xcc20: "jjiss" -0xcc21: "jjing" -0xcc22: "jjij" -0xcc23: "jjic" -0xcc24: "jjik" -0xcc25: "jjit" -0xcc26: "jjip" -0xcc27: "jjih" -0xcc28: "ca" -0xcc29: "cag" -0xcc2a: "cagg" -0xcc2b: "cags" -0xcc2c: "can" -0xcc2d: "canj" -0xcc2e: "canh" -0xcc2f: "cad" -0xcc30: "cal" -0xcc31: "calg" -0xcc32: "calm" -0xcc33: "calb" -0xcc34: "cals" -0xcc35: "calt" -0xcc36: "calp" -0xcc37: "calh" -0xcc38: "cam" -0xcc39: "cab" -0xcc3a: "cabs" -0xcc3b: "cas" -0xcc3c: "cass" -0xcc3d: "cang" -0xcc3e: "caj" -0xcc3f: "cac" -0xcc40: "cak" -0xcc41: "cat" -0xcc42: "cap" -0xcc43: "cah" -0xcc44: "cae" -0xcc45: "caeg" -0xcc46: "caegg" -0xcc47: "caegs" -0xcc48: "caen" -0xcc49: "caenj" -0xcc4a: "caenh" -0xcc4b: "caed" -0xcc4c: "cael" -0xcc4d: "caelg" -0xcc4e: "caelm" -0xcc4f: "caelb" -0xcc50: "caels" -0xcc51: "caelt" -0xcc52: "caelp" -0xcc53: "caelh" -0xcc54: "caem" -0xcc55: "caeb" -0xcc56: "caebs" -0xcc57: "caes" -0xcc58: "caess" -0xcc59: "caeng" -0xcc5a: "caej" -0xcc5b: "caec" -0xcc5c: "caek" -0xcc5d: "caet" -0xcc5e: "caep" -0xcc5f: "caeh" -0xcc60: "cya" -0xcc61: "cyag" -0xcc62: "cyagg" -0xcc63: "cyags" -0xcc64: "cyan" -0xcc65: "cyanj" -0xcc66: "cyanh" -0xcc67: "cyad" -0xcc68: "cyal" -0xcc69: "cyalg" -0xcc6a: "cyalm" -0xcc6b: "cyalb" -0xcc6c: "cyals" -0xcc6d: "cyalt" -0xcc6e: "cyalp" -0xcc6f: "cyalh" -0xcc70: "cyam" -0xcc71: "cyab" -0xcc72: "cyabs" -0xcc73: "cyas" -0xcc74: "cyass" -0xcc75: "cyang" -0xcc76: "cyaj" -0xcc77: "cyac" -0xcc78: "cyak" -0xcc79: "cyat" -0xcc7a: "cyap" -0xcc7b: "cyah" -0xcc7c: "cyae" -0xcc7d: "cyaeg" -0xcc7e: "cyaegg" -0xcc7f: "cyaegs" -0xcc80: "cyaen" -0xcc81: "cyaenj" -0xcc82: "cyaenh" -0xcc83: "cyaed" -0xcc84: "cyael" -0xcc85: "cyaelg" -0xcc86: "cyaelm" -0xcc87: "cyaelb" -0xcc88: "cyaels" -0xcc89: "cyaelt" -0xcc8a: "cyaelp" -0xcc8b: "cyaelh" -0xcc8c: "cyaem" -0xcc8d: "cyaeb" -0xcc8e: "cyaebs" -0xcc8f: "cyaes" -0xcc90: "cyaess" -0xcc91: "cyaeng" -0xcc92: "cyaej" -0xcc93: "cyaec" -0xcc94: "cyaek" -0xcc95: "cyaet" -0xcc96: "cyaep" -0xcc97: "cyaeh" -0xcc98: "ceo" -0xcc99: "ceog" -0xcc9a: "ceogg" -0xcc9b: "ceogs" -0xcc9c: "ceon" -0xcc9d: "ceonj" -0xcc9e: "ceonh" -0xcc9f: "ceod" -0xcca0: "ceol" -0xcca1: "ceolg" -0xcca2: "ceolm" -0xcca3: "ceolb" -0xcca4: "ceols" -0xcca5: "ceolt" -0xcca6: "ceolp" -0xcca7: "ceolh" -0xcca8: "ceom" -0xcca9: "ceob" -0xccaa: "ceobs" -0xccab: "ceos" -0xccac: "ceoss" -0xccad: "ceong" -0xccae: "ceoj" -0xccaf: "ceoc" -0xccb0: "ceok" -0xccb1: "ceot" -0xccb2: "ceop" -0xccb3: "ceoh" -0xccb4: "ce" -0xccb5: "ceg" -0xccb6: "cegg" -0xccb7: "cegs" -0xccb8: "cen" -0xccb9: "cenj" -0xccba: "cenh" -0xccbb: "ced" -0xccbc: "cel" -0xccbd: "celg" -0xccbe: "celm" -0xccbf: "celb" -0xccc0: "cels" -0xccc1: "celt" -0xccc2: "celp" -0xccc3: "celh" -0xccc4: "cem" -0xccc5: "ceb" -0xccc6: "cebs" -0xccc7: "ces" -0xccc8: "cess" -0xccc9: "ceng" -0xccca: "cej" -0xcccb: "cec" -0xcccc: "cek" -0xcccd: "cet" -0xccce: "cep" -0xcccf: "ceh" -0xccd0: "cyeo" -0xccd1: "cyeog" -0xccd2: "cyeogg" -0xccd3: "cyeogs" -0xccd4: "cyeon" -0xccd5: "cyeonj" -0xccd6: "cyeonh" -0xccd7: "cyeod" -0xccd8: "cyeol" -0xccd9: "cyeolg" -0xccda: "cyeolm" -0xccdb: "cyeolb" -0xccdc: "cyeols" -0xccdd: "cyeolt" -0xccde: "cyeolp" -0xccdf: "cyeolh" -0xcce0: "cyeom" -0xcce1: "cyeob" -0xcce2: "cyeobs" -0xcce3: "cyeos" -0xcce4: "cyeoss" -0xcce5: "cyeong" -0xcce6: "cyeoj" -0xcce7: "cyeoc" -0xcce8: "cyeok" -0xcce9: "cyeot" -0xccea: "cyeop" -0xcceb: "cyeoh" -0xccec: "cye" -0xcced: "cyeg" -0xccee: "cyegg" -0xccef: "cyegs" -0xccf0: "cyen" -0xccf1: "cyenj" -0xccf2: "cyenh" -0xccf3: "cyed" -0xccf4: "cyel" -0xccf5: "cyelg" -0xccf6: "cyelm" -0xccf7: "cyelb" -0xccf8: "cyels" -0xccf9: "cyelt" -0xccfa: "cyelp" -0xccfb: "cyelh" -0xccfc: "cyem" -0xccfd: "cyeb" -0xccfe: "cyebs" -0xccff: "cyes" -/* x0cd */ -0xcd00: "cyess" -0xcd01: "cyeng" -0xcd02: "cyej" -0xcd03: "cyec" -0xcd04: "cyek" -0xcd05: "cyet" -0xcd06: "cyep" -0xcd07: "cyeh" -0xcd08: "co" -0xcd09: "cog" -0xcd0a: "cogg" -0xcd0b: "cogs" -0xcd0c: "con" -0xcd0d: "conj" -0xcd0e: "conh" -0xcd0f: "cod" -0xcd10: "col" -0xcd11: "colg" -0xcd12: "colm" -0xcd13: "colb" -0xcd14: "cols" -0xcd15: "colt" -0xcd16: "colp" -0xcd17: "colh" -0xcd18: "com" -0xcd19: "cob" -0xcd1a: "cobs" -0xcd1b: "cos" -0xcd1c: "coss" -0xcd1d: "cong" -0xcd1e: "coj" -0xcd1f: "coc" -0xcd20: "cok" -0xcd21: "cot" -0xcd22: "cop" -0xcd23: "coh" -0xcd24: "cwa" -0xcd25: "cwag" -0xcd26: "cwagg" -0xcd27: "cwags" -0xcd28: "cwan" -0xcd29: "cwanj" -0xcd2a: "cwanh" -0xcd2b: "cwad" -0xcd2c: "cwal" -0xcd2d: "cwalg" -0xcd2e: "cwalm" -0xcd2f: "cwalb" -0xcd30: "cwals" -0xcd31: "cwalt" -0xcd32: "cwalp" -0xcd33: "cwalh" -0xcd34: "cwam" -0xcd35: "cwab" -0xcd36: "cwabs" -0xcd37: "cwas" -0xcd38: "cwass" -0xcd39: "cwang" -0xcd3a: "cwaj" -0xcd3b: "cwac" -0xcd3c: "cwak" -0xcd3d: "cwat" -0xcd3e: "cwap" -0xcd3f: "cwah" -0xcd40: "cwae" -0xcd41: "cwaeg" -0xcd42: "cwaegg" -0xcd43: "cwaegs" -0xcd44: "cwaen" -0xcd45: "cwaenj" -0xcd46: "cwaenh" -0xcd47: "cwaed" -0xcd48: "cwael" -0xcd49: "cwaelg" -0xcd4a: "cwaelm" -0xcd4b: "cwaelb" -0xcd4c: "cwaels" -0xcd4d: "cwaelt" -0xcd4e: "cwaelp" -0xcd4f: "cwaelh" -0xcd50: "cwaem" -0xcd51: "cwaeb" -0xcd52: "cwaebs" -0xcd53: "cwaes" -0xcd54: "cwaess" -0xcd55: "cwaeng" -0xcd56: "cwaej" -0xcd57: "cwaec" -0xcd58: "cwaek" -0xcd59: "cwaet" -0xcd5a: "cwaep" -0xcd5b: "cwaeh" -0xcd5c: "coe" -0xcd5d: "coeg" -0xcd5e: "coegg" -0xcd5f: "coegs" -0xcd60: "coen" -0xcd61: "coenj" -0xcd62: "coenh" -0xcd63: "coed" -0xcd64: "coel" -0xcd65: "coelg" -0xcd66: "coelm" -0xcd67: "coelb" -0xcd68: "coels" -0xcd69: "coelt" -0xcd6a: "coelp" -0xcd6b: "coelh" -0xcd6c: "coem" -0xcd6d: "coeb" -0xcd6e: "coebs" -0xcd6f: "coes" -0xcd70: "coess" -0xcd71: "coeng" -0xcd72: "coej" -0xcd73: "coec" -0xcd74: "coek" -0xcd75: "coet" -0xcd76: "coep" -0xcd77: "coeh" -0xcd78: "cyo" -0xcd79: "cyog" -0xcd7a: "cyogg" -0xcd7b: "cyogs" -0xcd7c: "cyon" -0xcd7d: "cyonj" -0xcd7e: "cyonh" -0xcd7f: "cyod" -0xcd80: "cyol" -0xcd81: "cyolg" -0xcd82: "cyolm" -0xcd83: "cyolb" -0xcd84: "cyols" -0xcd85: "cyolt" -0xcd86: "cyolp" -0xcd87: "cyolh" -0xcd88: "cyom" -0xcd89: "cyob" -0xcd8a: "cyobs" -0xcd8b: "cyos" -0xcd8c: "cyoss" -0xcd8d: "cyong" -0xcd8e: "cyoj" -0xcd8f: "cyoc" -0xcd90: "cyok" -0xcd91: "cyot" -0xcd92: "cyop" -0xcd93: "cyoh" -0xcd94: "cu" -0xcd95: "cug" -0xcd96: "cugg" -0xcd97: "cugs" -0xcd98: "cun" -0xcd99: "cunj" -0xcd9a: "cunh" -0xcd9b: "cud" -0xcd9c: "cul" -0xcd9d: "culg" -0xcd9e: "culm" -0xcd9f: "culb" -0xcda0: "culs" -0xcda1: "cult" -0xcda2: "culp" -0xcda3: "culh" -0xcda4: "cum" -0xcda5: "cub" -0xcda6: "cubs" -0xcda7: "cus" -0xcda8: "cuss" -0xcda9: "cung" -0xcdaa: "cuj" -0xcdab: "cuc" -0xcdac: "cuk" -0xcdad: "cut" -0xcdae: "cup" -0xcdaf: "cuh" -0xcdb0: "cweo" -0xcdb1: "cweog" -0xcdb2: "cweogg" -0xcdb3: "cweogs" -0xcdb4: "cweon" -0xcdb5: "cweonj" -0xcdb6: "cweonh" -0xcdb7: "cweod" -0xcdb8: "cweol" -0xcdb9: "cweolg" -0xcdba: "cweolm" -0xcdbb: "cweolb" -0xcdbc: "cweols" -0xcdbd: "cweolt" -0xcdbe: "cweolp" -0xcdbf: "cweolh" -0xcdc0: "cweom" -0xcdc1: "cweob" -0xcdc2: "cweobs" -0xcdc3: "cweos" -0xcdc4: "cweoss" -0xcdc5: "cweong" -0xcdc6: "cweoj" -0xcdc7: "cweoc" -0xcdc8: "cweok" -0xcdc9: "cweot" -0xcdca: "cweop" -0xcdcb: "cweoh" -0xcdcc: "cwe" -0xcdcd: "cweg" -0xcdce: "cwegg" -0xcdcf: "cwegs" -0xcdd0: "cwen" -0xcdd1: "cwenj" -0xcdd2: "cwenh" -0xcdd3: "cwed" -0xcdd4: "cwel" -0xcdd5: "cwelg" -0xcdd6: "cwelm" -0xcdd7: "cwelb" -0xcdd8: "cwels" -0xcdd9: "cwelt" -0xcdda: "cwelp" -0xcddb: "cwelh" -0xcddc: "cwem" -0xcddd: "cweb" -0xcdde: "cwebs" -0xcddf: "cwes" -0xcde0: "cwess" -0xcde1: "cweng" -0xcde2: "cwej" -0xcde3: "cwec" -0xcde4: "cwek" -0xcde5: "cwet" -0xcde6: "cwep" -0xcde7: "cweh" -0xcde8: "cwi" -0xcde9: "cwig" -0xcdea: "cwigg" -0xcdeb: "cwigs" -0xcdec: "cwin" -0xcded: "cwinj" -0xcdee: "cwinh" -0xcdef: "cwid" -0xcdf0: "cwil" -0xcdf1: "cwilg" -0xcdf2: "cwilm" -0xcdf3: "cwilb" -0xcdf4: "cwils" -0xcdf5: "cwilt" -0xcdf6: "cwilp" -0xcdf7: "cwilh" -0xcdf8: "cwim" -0xcdf9: "cwib" -0xcdfa: "cwibs" -0xcdfb: "cwis" -0xcdfc: "cwiss" -0xcdfd: "cwing" -0xcdfe: "cwij" -0xcdff: "cwic" -/* x0ce */ -0xce00: "cwik" -0xce01: "cwit" -0xce02: "cwip" -0xce03: "cwih" -0xce04: "cyu" -0xce05: "cyug" -0xce06: "cyugg" -0xce07: "cyugs" -0xce08: "cyun" -0xce09: "cyunj" -0xce0a: "cyunh" -0xce0b: "cyud" -0xce0c: "cyul" -0xce0d: "cyulg" -0xce0e: "cyulm" -0xce0f: "cyulb" -0xce10: "cyuls" -0xce11: "cyult" -0xce12: "cyulp" -0xce13: "cyulh" -0xce14: "cyum" -0xce15: "cyub" -0xce16: "cyubs" -0xce17: "cyus" -0xce18: "cyuss" -0xce19: "cyung" -0xce1a: "cyuj" -0xce1b: "cyuc" -0xce1c: "cyuk" -0xce1d: "cyut" -0xce1e: "cyup" -0xce1f: "cyuh" -0xce20: "ceu" -0xce21: "ceug" -0xce22: "ceugg" -0xce23: "ceugs" -0xce24: "ceun" -0xce25: "ceunj" -0xce26: "ceunh" -0xce27: "ceud" -0xce28: "ceul" -0xce29: "ceulg" -0xce2a: "ceulm" -0xce2b: "ceulb" -0xce2c: "ceuls" -0xce2d: "ceult" -0xce2e: "ceulp" -0xce2f: "ceulh" -0xce30: "ceum" -0xce31: "ceub" -0xce32: "ceubs" -0xce33: "ceus" -0xce34: "ceuss" -0xce35: "ceung" -0xce36: "ceuj" -0xce37: "ceuc" -0xce38: "ceuk" -0xce39: "ceut" -0xce3a: "ceup" -0xce3b: "ceuh" -0xce3c: "cyi" -0xce3d: "cyig" -0xce3e: "cyigg" -0xce3f: "cyigs" -0xce40: "cyin" -0xce41: "cyinj" -0xce42: "cyinh" -0xce43: "cyid" -0xce44: "cyil" -0xce45: "cyilg" -0xce46: "cyilm" -0xce47: "cyilb" -0xce48: "cyils" -0xce49: "cyilt" -0xce4a: "cyilp" -0xce4b: "cyilh" -0xce4c: "cyim" -0xce4d: "cyib" -0xce4e: "cyibs" -0xce4f: "cyis" -0xce50: "cyiss" -0xce51: "cying" -0xce52: "cyij" -0xce53: "cyic" -0xce54: "cyik" -0xce55: "cyit" -0xce56: "cyip" -0xce57: "cyih" -0xce58: "ci" -0xce59: "cig" -0xce5a: "cigg" -0xce5b: "cigs" -0xce5c: "cin" -0xce5d: "cinj" -0xce5e: "cinh" -0xce5f: "cid" -0xce60: "cil" -0xce61: "cilg" -0xce62: "cilm" -0xce63: "cilb" -0xce64: "cils" -0xce65: "cilt" -0xce66: "cilp" -0xce67: "cilh" -0xce68: "cim" -0xce69: "cib" -0xce6a: "cibs" -0xce6b: "cis" -0xce6c: "ciss" -0xce6d: "cing" -0xce6e: "cij" -0xce6f: "cic" -0xce70: "cik" -0xce71: "cit" -0xce72: "cip" -0xce73: "cih" -0xce74: "ka" -0xce75: "kag" -0xce76: "kagg" -0xce77: "kags" -0xce78: "kan" -0xce79: "kanj" -0xce7a: "kanh" -0xce7b: "kad" -0xce7c: "kal" -0xce7d: "kalg" -0xce7e: "kalm" -0xce7f: "kalb" -0xce80: "kals" -0xce81: "kalt" -0xce82: "kalp" -0xce83: "kalh" -0xce84: "kam" -0xce85: "kab" -0xce86: "kabs" -0xce87: "kas" -0xce88: "kass" -0xce89: "kang" -0xce8a: "kaj" -0xce8b: "kac" -0xce8c: "kak" -0xce8d: "kat" -0xce8e: "kap" -0xce8f: "kah" -0xce90: "kae" -0xce91: "kaeg" -0xce92: "kaegg" -0xce93: "kaegs" -0xce94: "kaen" -0xce95: "kaenj" -0xce96: "kaenh" -0xce97: "kaed" -0xce98: "kael" -0xce99: "kaelg" -0xce9a: "kaelm" -0xce9b: "kaelb" -0xce9c: "kaels" -0xce9d: "kaelt" -0xce9e: "kaelp" -0xce9f: "kaelh" -0xcea0: "kaem" -0xcea1: "kaeb" -0xcea2: "kaebs" -0xcea3: "kaes" -0xcea4: "kaess" -0xcea5: "kaeng" -0xcea6: "kaej" -0xcea7: "kaec" -0xcea8: "kaek" -0xcea9: "kaet" -0xceaa: "kaep" -0xceab: "kaeh" -0xceac: "kya" -0xcead: "kyag" -0xceae: "kyagg" -0xceaf: "kyags" -0xceb0: "kyan" -0xceb1: "kyanj" -0xceb2: "kyanh" -0xceb3: "kyad" -0xceb4: "kyal" -0xceb5: "kyalg" -0xceb6: "kyalm" -0xceb7: "kyalb" -0xceb8: "kyals" -0xceb9: "kyalt" -0xceba: "kyalp" -0xcebb: "kyalh" -0xcebc: "kyam" -0xcebd: "kyab" -0xcebe: "kyabs" -0xcebf: "kyas" -0xcec0: "kyass" -0xcec1: "kyang" -0xcec2: "kyaj" -0xcec3: "kyac" -0xcec4: "kyak" -0xcec5: "kyat" -0xcec6: "kyap" -0xcec7: "kyah" -0xcec8: "kyae" -0xcec9: "kyaeg" -0xceca: "kyaegg" -0xcecb: "kyaegs" -0xcecc: "kyaen" -0xcecd: "kyaenj" -0xcece: "kyaenh" -0xcecf: "kyaed" -0xced0: "kyael" -0xced1: "kyaelg" -0xced2: "kyaelm" -0xced3: "kyaelb" -0xced4: "kyaels" -0xced5: "kyaelt" -0xced6: "kyaelp" -0xced7: "kyaelh" -0xced8: "kyaem" -0xced9: "kyaeb" -0xceda: "kyaebs" -0xcedb: "kyaes" -0xcedc: "kyaess" -0xcedd: "kyaeng" -0xcede: "kyaej" -0xcedf: "kyaec" -0xcee0: "kyaek" -0xcee1: "kyaet" -0xcee2: "kyaep" -0xcee3: "kyaeh" -0xcee4: "keo" -0xcee5: "keog" -0xcee6: "keogg" -0xcee7: "keogs" -0xcee8: "keon" -0xcee9: "keonj" -0xceea: "keonh" -0xceeb: "keod" -0xceec: "keol" -0xceed: "keolg" -0xceee: "keolm" -0xceef: "keolb" -0xcef0: "keols" -0xcef1: "keolt" -0xcef2: "keolp" -0xcef3: "keolh" -0xcef4: "keom" -0xcef5: "keob" -0xcef6: "keobs" -0xcef7: "keos" -0xcef8: "keoss" -0xcef9: "keong" -0xcefa: "keoj" -0xcefb: "keoc" -0xcefc: "keok" -0xcefd: "keot" -0xcefe: "keop" -0xceff: "keoh" -/* x0cf */ -0xcf00: "ke" -0xcf01: "keg" -0xcf02: "kegg" -0xcf03: "kegs" -0xcf04: "ken" -0xcf05: "kenj" -0xcf06: "kenh" -0xcf07: "ked" -0xcf08: "kel" -0xcf09: "kelg" -0xcf0a: "kelm" -0xcf0b: "kelb" -0xcf0c: "kels" -0xcf0d: "kelt" -0xcf0e: "kelp" -0xcf0f: "kelh" -0xcf10: "kem" -0xcf11: "keb" -0xcf12: "kebs" -0xcf13: "kes" -0xcf14: "kess" -0xcf15: "keng" -0xcf16: "kej" -0xcf17: "kec" -0xcf18: "kek" -0xcf19: "ket" -0xcf1a: "kep" -0xcf1b: "keh" -0xcf1c: "kyeo" -0xcf1d: "kyeog" -0xcf1e: "kyeogg" -0xcf1f: "kyeogs" -0xcf20: "kyeon" -0xcf21: "kyeonj" -0xcf22: "kyeonh" -0xcf23: "kyeod" -0xcf24: "kyeol" -0xcf25: "kyeolg" -0xcf26: "kyeolm" -0xcf27: "kyeolb" -0xcf28: "kyeols" -0xcf29: "kyeolt" -0xcf2a: "kyeolp" -0xcf2b: "kyeolh" -0xcf2c: "kyeom" -0xcf2d: "kyeob" -0xcf2e: "kyeobs" -0xcf2f: "kyeos" -0xcf30: "kyeoss" -0xcf31: "kyeong" -0xcf32: "kyeoj" -0xcf33: "kyeoc" -0xcf34: "kyeok" -0xcf35: "kyeot" -0xcf36: "kyeop" -0xcf37: "kyeoh" -0xcf38: "kye" -0xcf39: "kyeg" -0xcf3a: "kyegg" -0xcf3b: "kyegs" -0xcf3c: "kyen" -0xcf3d: "kyenj" -0xcf3e: "kyenh" -0xcf3f: "kyed" -0xcf40: "kyel" -0xcf41: "kyelg" -0xcf42: "kyelm" -0xcf43: "kyelb" -0xcf44: "kyels" -0xcf45: "kyelt" -0xcf46: "kyelp" -0xcf47: "kyelh" -0xcf48: "kyem" -0xcf49: "kyeb" -0xcf4a: "kyebs" -0xcf4b: "kyes" -0xcf4c: "kyess" -0xcf4d: "kyeng" -0xcf4e: "kyej" -0xcf4f: "kyec" -0xcf50: "kyek" -0xcf51: "kyet" -0xcf52: "kyep" -0xcf53: "kyeh" -0xcf54: "ko" -0xcf55: "kog" -0xcf56: "kogg" -0xcf57: "kogs" -0xcf58: "kon" -0xcf59: "konj" -0xcf5a: "konh" -0xcf5b: "kod" -0xcf5c: "kol" -0xcf5d: "kolg" -0xcf5e: "kolm" -0xcf5f: "kolb" -0xcf60: "kols" -0xcf61: "kolt" -0xcf62: "kolp" -0xcf63: "kolh" -0xcf64: "kom" -0xcf65: "kob" -0xcf66: "kobs" -0xcf67: "kos" -0xcf68: "koss" -0xcf69: "kong" -0xcf6a: "koj" -0xcf6b: "koc" -0xcf6c: "kok" -0xcf6d: "kot" -0xcf6e: "kop" -0xcf6f: "koh" -0xcf70: "kwa" -0xcf71: "kwag" -0xcf72: "kwagg" -0xcf73: "kwags" -0xcf74: "kwan" -0xcf75: "kwanj" -0xcf76: "kwanh" -0xcf77: "kwad" -0xcf78: "kwal" -0xcf79: "kwalg" -0xcf7a: "kwalm" -0xcf7b: "kwalb" -0xcf7c: "kwals" -0xcf7d: "kwalt" -0xcf7e: "kwalp" -0xcf7f: "kwalh" -0xcf80: "kwam" -0xcf81: "kwab" -0xcf82: "kwabs" -0xcf83: "kwas" -0xcf84: "kwass" -0xcf85: "kwang" -0xcf86: "kwaj" -0xcf87: "kwac" -0xcf88: "kwak" -0xcf89: "kwat" -0xcf8a: "kwap" -0xcf8b: "kwah" -0xcf8c: "kwae" -0xcf8d: "kwaeg" -0xcf8e: "kwaegg" -0xcf8f: "kwaegs" -0xcf90: "kwaen" -0xcf91: "kwaenj" -0xcf92: "kwaenh" -0xcf93: "kwaed" -0xcf94: "kwael" -0xcf95: "kwaelg" -0xcf96: "kwaelm" -0xcf97: "kwaelb" -0xcf98: "kwaels" -0xcf99: "kwaelt" -0xcf9a: "kwaelp" -0xcf9b: "kwaelh" -0xcf9c: "kwaem" -0xcf9d: "kwaeb" -0xcf9e: "kwaebs" -0xcf9f: "kwaes" -0xcfa0: "kwaess" -0xcfa1: "kwaeng" -0xcfa2: "kwaej" -0xcfa3: "kwaec" -0xcfa4: "kwaek" -0xcfa5: "kwaet" -0xcfa6: "kwaep" -0xcfa7: "kwaeh" -0xcfa8: "koe" -0xcfa9: "koeg" -0xcfaa: "koegg" -0xcfab: "koegs" -0xcfac: "koen" -0xcfad: "koenj" -0xcfae: "koenh" -0xcfaf: "koed" -0xcfb0: "koel" -0xcfb1: "koelg" -0xcfb2: "koelm" -0xcfb3: "koelb" -0xcfb4: "koels" -0xcfb5: "koelt" -0xcfb6: "koelp" -0xcfb7: "koelh" -0xcfb8: "koem" -0xcfb9: "koeb" -0xcfba: "koebs" -0xcfbb: "koes" -0xcfbc: "koess" -0xcfbd: "koeng" -0xcfbe: "koej" -0xcfbf: "koec" -0xcfc0: "koek" -0xcfc1: "koet" -0xcfc2: "koep" -0xcfc3: "koeh" -0xcfc4: "kyo" -0xcfc5: "kyog" -0xcfc6: "kyogg" -0xcfc7: "kyogs" -0xcfc8: "kyon" -0xcfc9: "kyonj" -0xcfca: "kyonh" -0xcfcb: "kyod" -0xcfcc: "kyol" -0xcfcd: "kyolg" -0xcfce: "kyolm" -0xcfcf: "kyolb" -0xcfd0: "kyols" -0xcfd1: "kyolt" -0xcfd2: "kyolp" -0xcfd3: "kyolh" -0xcfd4: "kyom" -0xcfd5: "kyob" -0xcfd6: "kyobs" -0xcfd7: "kyos" -0xcfd8: "kyoss" -0xcfd9: "kyong" -0xcfda: "kyoj" -0xcfdb: "kyoc" -0xcfdc: "kyok" -0xcfdd: "kyot" -0xcfde: "kyop" -0xcfdf: "kyoh" -0xcfe0: "ku" -0xcfe1: "kug" -0xcfe2: "kugg" -0xcfe3: "kugs" -0xcfe4: "kun" -0xcfe5: "kunj" -0xcfe6: "kunh" -0xcfe7: "kud" -0xcfe8: "kul" -0xcfe9: "kulg" -0xcfea: "kulm" -0xcfeb: "kulb" -0xcfec: "kuls" -0xcfed: "kult" -0xcfee: "kulp" -0xcfef: "kulh" -0xcff0: "kum" -0xcff1: "kub" -0xcff2: "kubs" -0xcff3: "kus" -0xcff4: "kuss" -0xcff5: "kung" -0xcff6: "kuj" -0xcff7: "kuc" -0xcff8: "kuk" -0xcff9: "kut" -0xcffa: "kup" -0xcffb: "kuh" -0xcffc: "kweo" -0xcffd: "kweog" -0xcffe: "kweogg" -0xcfff: "kweogs" -/* x0d0 */ -0xd000: "kweon" -0xd001: "kweonj" -0xd002: "kweonh" -0xd003: "kweod" -0xd004: "kweol" -0xd005: "kweolg" -0xd006: "kweolm" -0xd007: "kweolb" -0xd008: "kweols" -0xd009: "kweolt" -0xd00a: "kweolp" -0xd00b: "kweolh" -0xd00c: "kweom" -0xd00d: "kweob" -0xd00e: "kweobs" -0xd00f: "kweos" -0xd010: "kweoss" -0xd011: "kweong" -0xd012: "kweoj" -0xd013: "kweoc" -0xd014: "kweok" -0xd015: "kweot" -0xd016: "kweop" -0xd017: "kweoh" -0xd018: "kwe" -0xd019: "kweg" -0xd01a: "kwegg" -0xd01b: "kwegs" -0xd01c: "kwen" -0xd01d: "kwenj" -0xd01e: "kwenh" -0xd01f: "kwed" -0xd020: "kwel" -0xd021: "kwelg" -0xd022: "kwelm" -0xd023: "kwelb" -0xd024: "kwels" -0xd025: "kwelt" -0xd026: "kwelp" -0xd027: "kwelh" -0xd028: "kwem" -0xd029: "kweb" -0xd02a: "kwebs" -0xd02b: "kwes" -0xd02c: "kwess" -0xd02d: "kweng" -0xd02e: "kwej" -0xd02f: "kwec" -0xd030: "kwek" -0xd031: "kwet" -0xd032: "kwep" -0xd033: "kweh" -0xd034: "kwi" -0xd035: "kwig" -0xd036: "kwigg" -0xd037: "kwigs" -0xd038: "kwin" -0xd039: "kwinj" -0xd03a: "kwinh" -0xd03b: "kwid" -0xd03c: "kwil" -0xd03d: "kwilg" -0xd03e: "kwilm" -0xd03f: "kwilb" -0xd040: "kwils" -0xd041: "kwilt" -0xd042: "kwilp" -0xd043: "kwilh" -0xd044: "kwim" -0xd045: "kwib" -0xd046: "kwibs" -0xd047: "kwis" -0xd048: "kwiss" -0xd049: "kwing" -0xd04a: "kwij" -0xd04b: "kwic" -0xd04c: "kwik" -0xd04d: "kwit" -0xd04e: "kwip" -0xd04f: "kwih" -0xd050: "kyu" -0xd051: "kyug" -0xd052: "kyugg" -0xd053: "kyugs" -0xd054: "kyun" -0xd055: "kyunj" -0xd056: "kyunh" -0xd057: "kyud" -0xd058: "kyul" -0xd059: "kyulg" -0xd05a: "kyulm" -0xd05b: "kyulb" -0xd05c: "kyuls" -0xd05d: "kyult" -0xd05e: "kyulp" -0xd05f: "kyulh" -0xd060: "kyum" -0xd061: "kyub" -0xd062: "kyubs" -0xd063: "kyus" -0xd064: "kyuss" -0xd065: "kyung" -0xd066: "kyuj" -0xd067: "kyuc" -0xd068: "kyuk" -0xd069: "kyut" -0xd06a: "kyup" -0xd06b: "kyuh" -0xd06c: "keu" -0xd06d: "keug" -0xd06e: "keugg" -0xd06f: "keugs" -0xd070: "keun" -0xd071: "keunj" -0xd072: "keunh" -0xd073: "keud" -0xd074: "keul" -0xd075: "keulg" -0xd076: "keulm" -0xd077: "keulb" -0xd078: "keuls" -0xd079: "keult" -0xd07a: "keulp" -0xd07b: "keulh" -0xd07c: "keum" -0xd07d: "keub" -0xd07e: "keubs" -0xd07f: "keus" -0xd080: "keuss" -0xd081: "keung" -0xd082: "keuj" -0xd083: "keuc" -0xd084: "keuk" -0xd085: "keut" -0xd086: "keup" -0xd087: "keuh" -0xd088: "kyi" -0xd089: "kyig" -0xd08a: "kyigg" -0xd08b: "kyigs" -0xd08c: "kyin" -0xd08d: "kyinj" -0xd08e: "kyinh" -0xd08f: "kyid" -0xd090: "kyil" -0xd091: "kyilg" -0xd092: "kyilm" -0xd093: "kyilb" -0xd094: "kyils" -0xd095: "kyilt" -0xd096: "kyilp" -0xd097: "kyilh" -0xd098: "kyim" -0xd099: "kyib" -0xd09a: "kyibs" -0xd09b: "kyis" -0xd09c: "kyiss" -0xd09d: "kying" -0xd09e: "kyij" -0xd09f: "kyic" -0xd0a0: "kyik" -0xd0a1: "kyit" -0xd0a2: "kyip" -0xd0a3: "kyih" -0xd0a4: "ki" -0xd0a5: "kig" -0xd0a6: "kigg" -0xd0a7: "kigs" -0xd0a8: "kin" -0xd0a9: "kinj" -0xd0aa: "kinh" -0xd0ab: "kid" -0xd0ac: "kil" -0xd0ad: "kilg" -0xd0ae: "kilm" -0xd0af: "kilb" -0xd0b0: "kils" -0xd0b1: "kilt" -0xd0b2: "kilp" -0xd0b3: "kilh" -0xd0b4: "kim" -0xd0b5: "kib" -0xd0b6: "kibs" -0xd0b7: "kis" -0xd0b8: "kiss" -0xd0b9: "king" -0xd0ba: "kij" -0xd0bb: "kic" -0xd0bc: "kik" -0xd0bd: "kit" -0xd0be: "kip" -0xd0bf: "kih" -0xd0c0: "ta" -0xd0c1: "tag" -0xd0c2: "tagg" -0xd0c3: "tags" -0xd0c4: "tan" -0xd0c5: "tanj" -0xd0c6: "tanh" -0xd0c7: "tad" -0xd0c8: "tal" -0xd0c9: "talg" -0xd0ca: "talm" -0xd0cb: "talb" -0xd0cc: "tals" -0xd0cd: "talt" -0xd0ce: "talp" -0xd0cf: "talh" -0xd0d0: "tam" -0xd0d1: "tab" -0xd0d2: "tabs" -0xd0d3: "tas" -0xd0d4: "tass" -0xd0d5: "tang" -0xd0d6: "taj" -0xd0d7: "tac" -0xd0d8: "tak" -0xd0d9: "tat" -0xd0da: "tap" -0xd0db: "tah" -0xd0dc: "tae" -0xd0dd: "taeg" -0xd0de: "taegg" -0xd0df: "taegs" -0xd0e0: "taen" -0xd0e1: "taenj" -0xd0e2: "taenh" -0xd0e3: "taed" -0xd0e4: "tael" -0xd0e5: "taelg" -0xd0e6: "taelm" -0xd0e7: "taelb" -0xd0e8: "taels" -0xd0e9: "taelt" -0xd0ea: "taelp" -0xd0eb: "taelh" -0xd0ec: "taem" -0xd0ed: "taeb" -0xd0ee: "taebs" -0xd0ef: "taes" -0xd0f0: "taess" -0xd0f1: "taeng" -0xd0f2: "taej" -0xd0f3: "taec" -0xd0f4: "taek" -0xd0f5: "taet" -0xd0f6: "taep" -0xd0f7: "taeh" -0xd0f8: "tya" -0xd0f9: "tyag" -0xd0fa: "tyagg" -0xd0fb: "tyags" -0xd0fc: "tyan" -0xd0fd: "tyanj" -0xd0fe: "tyanh" -0xd0ff: "tyad" -/* x0d1 */ -0xd100: "tyal" -0xd101: "tyalg" -0xd102: "tyalm" -0xd103: "tyalb" -0xd104: "tyals" -0xd105: "tyalt" -0xd106: "tyalp" -0xd107: "tyalh" -0xd108: "tyam" -0xd109: "tyab" -0xd10a: "tyabs" -0xd10b: "tyas" -0xd10c: "tyass" -0xd10d: "tyang" -0xd10e: "tyaj" -0xd10f: "tyac" -0xd110: "tyak" -0xd111: "tyat" -0xd112: "tyap" -0xd113: "tyah" -0xd114: "tyae" -0xd115: "tyaeg" -0xd116: "tyaegg" -0xd117: "tyaegs" -0xd118: "tyaen" -0xd119: "tyaenj" -0xd11a: "tyaenh" -0xd11b: "tyaed" -0xd11c: "tyael" -0xd11d: "tyaelg" -0xd11e: "tyaelm" -0xd11f: "tyaelb" -0xd120: "tyaels" -0xd121: "tyaelt" -0xd122: "tyaelp" -0xd123: "tyaelh" -0xd124: "tyaem" -0xd125: "tyaeb" -0xd126: "tyaebs" -0xd127: "tyaes" -0xd128: "tyaess" -0xd129: "tyaeng" -0xd12a: "tyaej" -0xd12b: "tyaec" -0xd12c: "tyaek" -0xd12d: "tyaet" -0xd12e: "tyaep" -0xd12f: "tyaeh" -0xd130: "teo" -0xd131: "teog" -0xd132: "teogg" -0xd133: "teogs" -0xd134: "teon" -0xd135: "teonj" -0xd136: "teonh" -0xd137: "teod" -0xd138: "teol" -0xd139: "teolg" -0xd13a: "teolm" -0xd13b: "teolb" -0xd13c: "teols" -0xd13d: "teolt" -0xd13e: "teolp" -0xd13f: "teolh" -0xd140: "teom" -0xd141: "teob" -0xd142: "teobs" -0xd143: "teos" -0xd144: "teoss" -0xd145: "teong" -0xd146: "teoj" -0xd147: "teoc" -0xd148: "teok" -0xd149: "teot" -0xd14a: "teop" -0xd14b: "teoh" -0xd14c: "te" -0xd14d: "teg" -0xd14e: "tegg" -0xd14f: "tegs" -0xd150: "ten" -0xd151: "tenj" -0xd152: "tenh" -0xd153: "ted" -0xd154: "tel" -0xd155: "telg" -0xd156: "telm" -0xd157: "telb" -0xd158: "tels" -0xd159: "telt" -0xd15a: "telp" -0xd15b: "telh" -0xd15c: "tem" -0xd15d: "teb" -0xd15e: "tebs" -0xd15f: "tes" -0xd160: "tess" -0xd161: "teng" -0xd162: "tej" -0xd163: "tec" -0xd164: "tek" -0xd165: "tet" -0xd166: "tep" -0xd167: "teh" -0xd168: "tyeo" -0xd169: "tyeog" -0xd16a: "tyeogg" -0xd16b: "tyeogs" -0xd16c: "tyeon" -0xd16d: "tyeonj" -0xd16e: "tyeonh" -0xd16f: "tyeod" -0xd170: "tyeol" -0xd171: "tyeolg" -0xd172: "tyeolm" -0xd173: "tyeolb" -0xd174: "tyeols" -0xd175: "tyeolt" -0xd176: "tyeolp" -0xd177: "tyeolh" -0xd178: "tyeom" -0xd179: "tyeob" -0xd17a: "tyeobs" -0xd17b: "tyeos" -0xd17c: "tyeoss" -0xd17d: "tyeong" -0xd17e: "tyeoj" -0xd17f: "tyeoc" -0xd180: "tyeok" -0xd181: "tyeot" -0xd182: "tyeop" -0xd183: "tyeoh" -0xd184: "tye" -0xd185: "tyeg" -0xd186: "tyegg" -0xd187: "tyegs" -0xd188: "tyen" -0xd189: "tyenj" -0xd18a: "tyenh" -0xd18b: "tyed" -0xd18c: "tyel" -0xd18d: "tyelg" -0xd18e: "tyelm" -0xd18f: "tyelb" -0xd190: "tyels" -0xd191: "tyelt" -0xd192: "tyelp" -0xd193: "tyelh" -0xd194: "tyem" -0xd195: "tyeb" -0xd196: "tyebs" -0xd197: "tyes" -0xd198: "tyess" -0xd199: "tyeng" -0xd19a: "tyej" -0xd19b: "tyec" -0xd19c: "tyek" -0xd19d: "tyet" -0xd19e: "tyep" -0xd19f: "tyeh" -0xd1a0: "to" -0xd1a1: "tog" -0xd1a2: "togg" -0xd1a3: "togs" -0xd1a4: "ton" -0xd1a5: "tonj" -0xd1a6: "tonh" -0xd1a7: "tod" -0xd1a8: "tol" -0xd1a9: "tolg" -0xd1aa: "tolm" -0xd1ab: "tolb" -0xd1ac: "tols" -0xd1ad: "tolt" -0xd1ae: "tolp" -0xd1af: "tolh" -0xd1b0: "tom" -0xd1b1: "tob" -0xd1b2: "tobs" -0xd1b3: "tos" -0xd1b4: "toss" -0xd1b5: "tong" -0xd1b6: "toj" -0xd1b7: "toc" -0xd1b8: "tok" -0xd1b9: "tot" -0xd1ba: "top" -0xd1bb: "toh" -0xd1bc: "twa" -0xd1bd: "twag" -0xd1be: "twagg" -0xd1bf: "twags" -0xd1c0: "twan" -0xd1c1: "twanj" -0xd1c2: "twanh" -0xd1c3: "twad" -0xd1c4: "twal" -0xd1c5: "twalg" -0xd1c6: "twalm" -0xd1c7: "twalb" -0xd1c8: "twals" -0xd1c9: "twalt" -0xd1ca: "twalp" -0xd1cb: "twalh" -0xd1cc: "twam" -0xd1cd: "twab" -0xd1ce: "twabs" -0xd1cf: "twas" -0xd1d0: "twass" -0xd1d1: "twang" -0xd1d2: "twaj" -0xd1d3: "twac" -0xd1d4: "twak" -0xd1d5: "twat" -0xd1d6: "twap" -0xd1d7: "twah" -0xd1d8: "twae" -0xd1d9: "twaeg" -0xd1da: "twaegg" -0xd1db: "twaegs" -0xd1dc: "twaen" -0xd1dd: "twaenj" -0xd1de: "twaenh" -0xd1df: "twaed" -0xd1e0: "twael" -0xd1e1: "twaelg" -0xd1e2: "twaelm" -0xd1e3: "twaelb" -0xd1e4: "twaels" -0xd1e5: "twaelt" -0xd1e6: "twaelp" -0xd1e7: "twaelh" -0xd1e8: "twaem" -0xd1e9: "twaeb" -0xd1ea: "twaebs" -0xd1eb: "twaes" -0xd1ec: "twaess" -0xd1ed: "twaeng" -0xd1ee: "twaej" -0xd1ef: "twaec" -0xd1f0: "twaek" -0xd1f1: "twaet" -0xd1f2: "twaep" -0xd1f3: "twaeh" -0xd1f4: "toe" -0xd1f5: "toeg" -0xd1f6: "toegg" -0xd1f7: "toegs" -0xd1f8: "toen" -0xd1f9: "toenj" -0xd1fa: "toenh" -0xd1fb: "toed" -0xd1fc: "toel" -0xd1fd: "toelg" -0xd1fe: "toelm" -0xd1ff: "toelb" -/* x0d2 */ -0xd200: "toels" -0xd201: "toelt" -0xd202: "toelp" -0xd203: "toelh" -0xd204: "toem" -0xd205: "toeb" -0xd206: "toebs" -0xd207: "toes" -0xd208: "toess" -0xd209: "toeng" -0xd20a: "toej" -0xd20b: "toec" -0xd20c: "toek" -0xd20d: "toet" -0xd20e: "toep" -0xd20f: "toeh" -0xd210: "tyo" -0xd211: "tyog" -0xd212: "tyogg" -0xd213: "tyogs" -0xd214: "tyon" -0xd215: "tyonj" -0xd216: "tyonh" -0xd217: "tyod" -0xd218: "tyol" -0xd219: "tyolg" -0xd21a: "tyolm" -0xd21b: "tyolb" -0xd21c: "tyols" -0xd21d: "tyolt" -0xd21e: "tyolp" -0xd21f: "tyolh" -0xd220: "tyom" -0xd221: "tyob" -0xd222: "tyobs" -0xd223: "tyos" -0xd224: "tyoss" -0xd225: "tyong" -0xd226: "tyoj" -0xd227: "tyoc" -0xd228: "tyok" -0xd229: "tyot" -0xd22a: "tyop" -0xd22b: "tyoh" -0xd22c: "tu" -0xd22d: "tug" -0xd22e: "tugg" -0xd22f: "tugs" -0xd230: "tun" -0xd231: "tunj" -0xd232: "tunh" -0xd233: "tud" -0xd234: "tul" -0xd235: "tulg" -0xd236: "tulm" -0xd237: "tulb" -0xd238: "tuls" -0xd239: "tult" -0xd23a: "tulp" -0xd23b: "tulh" -0xd23c: "tum" -0xd23d: "tub" -0xd23e: "tubs" -0xd23f: "tus" -0xd240: "tuss" -0xd241: "tung" -0xd242: "tuj" -0xd243: "tuc" -0xd244: "tuk" -0xd245: "tut" -0xd246: "tup" -0xd247: "tuh" -0xd248: "tweo" -0xd249: "tweog" -0xd24a: "tweogg" -0xd24b: "tweogs" -0xd24c: "tweon" -0xd24d: "tweonj" -0xd24e: "tweonh" -0xd24f: "tweod" -0xd250: "tweol" -0xd251: "tweolg" -0xd252: "tweolm" -0xd253: "tweolb" -0xd254: "tweols" -0xd255: "tweolt" -0xd256: "tweolp" -0xd257: "tweolh" -0xd258: "tweom" -0xd259: "tweob" -0xd25a: "tweobs" -0xd25b: "tweos" -0xd25c: "tweoss" -0xd25d: "tweong" -0xd25e: "tweoj" -0xd25f: "tweoc" -0xd260: "tweok" -0xd261: "tweot" -0xd262: "tweop" -0xd263: "tweoh" -0xd264: "twe" -0xd265: "tweg" -0xd266: "twegg" -0xd267: "twegs" -0xd268: "twen" -0xd269: "twenj" -0xd26a: "twenh" -0xd26b: "twed" -0xd26c: "twel" -0xd26d: "twelg" -0xd26e: "twelm" -0xd26f: "twelb" -0xd270: "twels" -0xd271: "twelt" -0xd272: "twelp" -0xd273: "twelh" -0xd274: "twem" -0xd275: "tweb" -0xd276: "twebs" -0xd277: "twes" -0xd278: "twess" -0xd279: "tweng" -0xd27a: "twej" -0xd27b: "twec" -0xd27c: "twek" -0xd27d: "twet" -0xd27e: "twep" -0xd27f: "tweh" -0xd280: "twi" -0xd281: "twig" -0xd282: "twigg" -0xd283: "twigs" -0xd284: "twin" -0xd285: "twinj" -0xd286: "twinh" -0xd287: "twid" -0xd288: "twil" -0xd289: "twilg" -0xd28a: "twilm" -0xd28b: "twilb" -0xd28c: "twils" -0xd28d: "twilt" -0xd28e: "twilp" -0xd28f: "twilh" -0xd290: "twim" -0xd291: "twib" -0xd292: "twibs" -0xd293: "twis" -0xd294: "twiss" -0xd295: "twing" -0xd296: "twij" -0xd297: "twic" -0xd298: "twik" -0xd299: "twit" -0xd29a: "twip" -0xd29b: "twih" -0xd29c: "tyu" -0xd29d: "tyug" -0xd29e: "tyugg" -0xd29f: "tyugs" -0xd2a0: "tyun" -0xd2a1: "tyunj" -0xd2a2: "tyunh" -0xd2a3: "tyud" -0xd2a4: "tyul" -0xd2a5: "tyulg" -0xd2a6: "tyulm" -0xd2a7: "tyulb" -0xd2a8: "tyuls" -0xd2a9: "tyult" -0xd2aa: "tyulp" -0xd2ab: "tyulh" -0xd2ac: "tyum" -0xd2ad: "tyub" -0xd2ae: "tyubs" -0xd2af: "tyus" -0xd2b0: "tyuss" -0xd2b1: "tyung" -0xd2b2: "tyuj" -0xd2b3: "tyuc" -0xd2b4: "tyuk" -0xd2b5: "tyut" -0xd2b6: "tyup" -0xd2b7: "tyuh" -0xd2b8: "teu" -0xd2b9: "teug" -0xd2ba: "teugg" -0xd2bb: "teugs" -0xd2bc: "teun" -0xd2bd: "teunj" -0xd2be: "teunh" -0xd2bf: "teud" -0xd2c0: "teul" -0xd2c1: "teulg" -0xd2c2: "teulm" -0xd2c3: "teulb" -0xd2c4: "teuls" -0xd2c5: "teult" -0xd2c6: "teulp" -0xd2c7: "teulh" -0xd2c8: "teum" -0xd2c9: "teub" -0xd2ca: "teubs" -0xd2cb: "teus" -0xd2cc: "teuss" -0xd2cd: "teung" -0xd2ce: "teuj" -0xd2cf: "teuc" -0xd2d0: "teuk" -0xd2d1: "teut" -0xd2d2: "teup" -0xd2d3: "teuh" -0xd2d4: "tyi" -0xd2d5: "tyig" -0xd2d6: "tyigg" -0xd2d7: "tyigs" -0xd2d8: "tyin" -0xd2d9: "tyinj" -0xd2da: "tyinh" -0xd2db: "tyid" -0xd2dc: "tyil" -0xd2dd: "tyilg" -0xd2de: "tyilm" -0xd2df: "tyilb" -0xd2e0: "tyils" -0xd2e1: "tyilt" -0xd2e2: "tyilp" -0xd2e3: "tyilh" -0xd2e4: "tyim" -0xd2e5: "tyib" -0xd2e6: "tyibs" -0xd2e7: "tyis" -0xd2e8: "tyiss" -0xd2e9: "tying" -0xd2ea: "tyij" -0xd2eb: "tyic" -0xd2ec: "tyik" -0xd2ed: "tyit" -0xd2ee: "tyip" -0xd2ef: "tyih" -0xd2f0: "ti" -0xd2f1: "tig" -0xd2f2: "tigg" -0xd2f3: "tigs" -0xd2f4: "tin" -0xd2f5: "tinj" -0xd2f6: "tinh" -0xd2f7: "tid" -0xd2f8: "til" -0xd2f9: "tilg" -0xd2fa: "tilm" -0xd2fb: "tilb" -0xd2fc: "tils" -0xd2fd: "tilt" -0xd2fe: "tilp" -0xd2ff: "tilh" -/* x0d3 */ -0xd300: "tim" -0xd301: "tib" -0xd302: "tibs" -0xd303: "tis" -0xd304: "tiss" -0xd305: "ting" -0xd306: "tij" -0xd307: "tic" -0xd308: "tik" -0xd309: "tit" -0xd30a: "tip" -0xd30b: "tih" -0xd30c: "pa" -0xd30d: "pag" -0xd30e: "pagg" -0xd30f: "pags" -0xd310: "pan" -0xd311: "panj" -0xd312: "panh" -0xd313: "pad" -0xd314: "pal" -0xd315: "palg" -0xd316: "palm" -0xd317: "palb" -0xd318: "pals" -0xd319: "palt" -0xd31a: "palp" -0xd31b: "palh" -0xd31c: "pam" -0xd31d: "pab" -0xd31e: "pabs" -0xd31f: "pas" -0xd320: "pass" -0xd321: "pang" -0xd322: "paj" -0xd323: "pac" -0xd324: "pak" -0xd325: "pat" -0xd326: "pap" -0xd327: "pah" -0xd328: "pae" -0xd329: "paeg" -0xd32a: "paegg" -0xd32b: "paegs" -0xd32c: "paen" -0xd32d: "paenj" -0xd32e: "paenh" -0xd32f: "paed" -0xd330: "pael" -0xd331: "paelg" -0xd332: "paelm" -0xd333: "paelb" -0xd334: "paels" -0xd335: "paelt" -0xd336: "paelp" -0xd337: "paelh" -0xd338: "paem" -0xd339: "paeb" -0xd33a: "paebs" -0xd33b: "paes" -0xd33c: "paess" -0xd33d: "paeng" -0xd33e: "paej" -0xd33f: "paec" -0xd340: "paek" -0xd341: "paet" -0xd342: "paep" -0xd343: "paeh" -0xd344: "pya" -0xd345: "pyag" -0xd346: "pyagg" -0xd347: "pyags" -0xd348: "pyan" -0xd349: "pyanj" -0xd34a: "pyanh" -0xd34b: "pyad" -0xd34c: "pyal" -0xd34d: "pyalg" -0xd34e: "pyalm" -0xd34f: "pyalb" -0xd350: "pyals" -0xd351: "pyalt" -0xd352: "pyalp" -0xd353: "pyalh" -0xd354: "pyam" -0xd355: "pyab" -0xd356: "pyabs" -0xd357: "pyas" -0xd358: "pyass" -0xd359: "pyang" -0xd35a: "pyaj" -0xd35b: "pyac" -0xd35c: "pyak" -0xd35d: "pyat" -0xd35e: "pyap" -0xd35f: "pyah" -0xd360: "pyae" -0xd361: "pyaeg" -0xd362: "pyaegg" -0xd363: "pyaegs" -0xd364: "pyaen" -0xd365: "pyaenj" -0xd366: "pyaenh" -0xd367: "pyaed" -0xd368: "pyael" -0xd369: "pyaelg" -0xd36a: "pyaelm" -0xd36b: "pyaelb" -0xd36c: "pyaels" -0xd36d: "pyaelt" -0xd36e: "pyaelp" -0xd36f: "pyaelh" -0xd370: "pyaem" -0xd371: "pyaeb" -0xd372: "pyaebs" -0xd373: "pyaes" -0xd374: "pyaess" -0xd375: "pyaeng" -0xd376: "pyaej" -0xd377: "pyaec" -0xd378: "pyaek" -0xd379: "pyaet" -0xd37a: "pyaep" -0xd37b: "pyaeh" -0xd37c: "peo" -0xd37d: "peog" -0xd37e: "peogg" -0xd37f: "peogs" -0xd380: "peon" -0xd381: "peonj" -0xd382: "peonh" -0xd383: "peod" -0xd384: "peol" -0xd385: "peolg" -0xd386: "peolm" -0xd387: "peolb" -0xd388: "peols" -0xd389: "peolt" -0xd38a: "peolp" -0xd38b: "peolh" -0xd38c: "peom" -0xd38d: "peob" -0xd38e: "peobs" -0xd38f: "peos" -0xd390: "peoss" -0xd391: "peong" -0xd392: "peoj" -0xd393: "peoc" -0xd394: "peok" -0xd395: "peot" -0xd396: "peop" -0xd397: "peoh" -0xd398: "pe" -0xd399: "peg" -0xd39a: "pegg" -0xd39b: "pegs" -0xd39c: "pen" -0xd39d: "penj" -0xd39e: "penh" -0xd39f: "ped" -0xd3a0: "pel" -0xd3a1: "pelg" -0xd3a2: "pelm" -0xd3a3: "pelb" -0xd3a4: "pels" -0xd3a5: "pelt" -0xd3a6: "pelp" -0xd3a7: "pelh" -0xd3a8: "pem" -0xd3a9: "peb" -0xd3aa: "pebs" -0xd3ab: "pes" -0xd3ac: "pess" -0xd3ad: "peng" -0xd3ae: "pej" -0xd3af: "pec" -0xd3b0: "pek" -0xd3b1: "pet" -0xd3b2: "pep" -0xd3b3: "peh" -0xd3b4: "pyeo" -0xd3b5: "pyeog" -0xd3b6: "pyeogg" -0xd3b7: "pyeogs" -0xd3b8: "pyeon" -0xd3b9: "pyeonj" -0xd3ba: "pyeonh" -0xd3bb: "pyeod" -0xd3bc: "pyeol" -0xd3bd: "pyeolg" -0xd3be: "pyeolm" -0xd3bf: "pyeolb" -0xd3c0: "pyeols" -0xd3c1: "pyeolt" -0xd3c2: "pyeolp" -0xd3c3: "pyeolh" -0xd3c4: "pyeom" -0xd3c5: "pyeob" -0xd3c6: "pyeobs" -0xd3c7: "pyeos" -0xd3c8: "pyeoss" -0xd3c9: "pyeong" -0xd3ca: "pyeoj" -0xd3cb: "pyeoc" -0xd3cc: "pyeok" -0xd3cd: "pyeot" -0xd3ce: "pyeop" -0xd3cf: "pyeoh" -0xd3d0: "pye" -0xd3d1: "pyeg" -0xd3d2: "pyegg" -0xd3d3: "pyegs" -0xd3d4: "pyen" -0xd3d5: "pyenj" -0xd3d6: "pyenh" -0xd3d7: "pyed" -0xd3d8: "pyel" -0xd3d9: "pyelg" -0xd3da: "pyelm" -0xd3db: "pyelb" -0xd3dc: "pyels" -0xd3dd: "pyelt" -0xd3de: "pyelp" -0xd3df: "pyelh" -0xd3e0: "pyem" -0xd3e1: "pyeb" -0xd3e2: "pyebs" -0xd3e3: "pyes" -0xd3e4: "pyess" -0xd3e5: "pyeng" -0xd3e6: "pyej" -0xd3e7: "pyec" -0xd3e8: "pyek" -0xd3e9: "pyet" -0xd3ea: "pyep" -0xd3eb: "pyeh" -0xd3ec: "po" -0xd3ed: "pog" -0xd3ee: "pogg" -0xd3ef: "pogs" -0xd3f0: "pon" -0xd3f1: "ponj" -0xd3f2: "ponh" -0xd3f3: "pod" -0xd3f4: "pol" -0xd3f5: "polg" -0xd3f6: "polm" -0xd3f7: "polb" -0xd3f8: "pols" -0xd3f9: "polt" -0xd3fa: "polp" -0xd3fb: "polh" -0xd3fc: "pom" -0xd3fd: "pob" -0xd3fe: "pobs" -0xd3ff: "pos" -/* x0d4 */ -0xd400: "poss" -0xd401: "pong" -0xd402: "poj" -0xd403: "poc" -0xd404: "pok" -0xd405: "pot" -0xd406: "pop" -0xd407: "poh" -0xd408: "pwa" -0xd409: "pwag" -0xd40a: "pwagg" -0xd40b: "pwags" -0xd40c: "pwan" -0xd40d: "pwanj" -0xd40e: "pwanh" -0xd40f: "pwad" -0xd410: "pwal" -0xd411: "pwalg" -0xd412: "pwalm" -0xd413: "pwalb" -0xd414: "pwals" -0xd415: "pwalt" -0xd416: "pwalp" -0xd417: "pwalh" -0xd418: "pwam" -0xd419: "pwab" -0xd41a: "pwabs" -0xd41b: "pwas" -0xd41c: "pwass" -0xd41d: "pwang" -0xd41e: "pwaj" -0xd41f: "pwac" -0xd420: "pwak" -0xd421: "pwat" -0xd422: "pwap" -0xd423: "pwah" -0xd424: "pwae" -0xd425: "pwaeg" -0xd426: "pwaegg" -0xd427: "pwaegs" -0xd428: "pwaen" -0xd429: "pwaenj" -0xd42a: "pwaenh" -0xd42b: "pwaed" -0xd42c: "pwael" -0xd42d: "pwaelg" -0xd42e: "pwaelm" -0xd42f: "pwaelb" -0xd430: "pwaels" -0xd431: "pwaelt" -0xd432: "pwaelp" -0xd433: "pwaelh" -0xd434: "pwaem" -0xd435: "pwaeb" -0xd436: "pwaebs" -0xd437: "pwaes" -0xd438: "pwaess" -0xd439: "pwaeng" -0xd43a: "pwaej" -0xd43b: "pwaec" -0xd43c: "pwaek" -0xd43d: "pwaet" -0xd43e: "pwaep" -0xd43f: "pwaeh" -0xd440: "poe" -0xd441: "poeg" -0xd442: "poegg" -0xd443: "poegs" -0xd444: "poen" -0xd445: "poenj" -0xd446: "poenh" -0xd447: "poed" -0xd448: "poel" -0xd449: "poelg" -0xd44a: "poelm" -0xd44b: "poelb" -0xd44c: "poels" -0xd44d: "poelt" -0xd44e: "poelp" -0xd44f: "poelh" -0xd450: "poem" -0xd451: "poeb" -0xd452: "poebs" -0xd453: "poes" -0xd454: "poess" -0xd455: "poeng" -0xd456: "poej" -0xd457: "poec" -0xd458: "poek" -0xd459: "poet" -0xd45a: "poep" -0xd45b: "poeh" -0xd45c: "pyo" -0xd45d: "pyog" -0xd45e: "pyogg" -0xd45f: "pyogs" -0xd460: "pyon" -0xd461: "pyonj" -0xd462: "pyonh" -0xd463: "pyod" -0xd464: "pyol" -0xd465: "pyolg" -0xd466: "pyolm" -0xd467: "pyolb" -0xd468: "pyols" -0xd469: "pyolt" -0xd46a: "pyolp" -0xd46b: "pyolh" -0xd46c: "pyom" -0xd46d: "pyob" -0xd46e: "pyobs" -0xd46f: "pyos" -0xd470: "pyoss" -0xd471: "pyong" -0xd472: "pyoj" -0xd473: "pyoc" -0xd474: "pyok" -0xd475: "pyot" -0xd476: "pyop" -0xd477: "pyoh" -0xd478: "pu" -0xd479: "pug" -0xd47a: "pugg" -0xd47b: "pugs" -0xd47c: "pun" -0xd47d: "punj" -0xd47e: "punh" -0xd47f: "pud" -0xd480: "pul" -0xd481: "pulg" -0xd482: "pulm" -0xd483: "pulb" -0xd484: "puls" -0xd485: "pult" -0xd486: "pulp" -0xd487: "pulh" -0xd488: "pum" -0xd489: "pub" -0xd48a: "pubs" -0xd48b: "pus" -0xd48c: "puss" -0xd48d: "pung" -0xd48e: "puj" -0xd48f: "puc" -0xd490: "puk" -0xd491: "put" -0xd492: "pup" -0xd493: "puh" -0xd494: "pweo" -0xd495: "pweog" -0xd496: "pweogg" -0xd497: "pweogs" -0xd498: "pweon" -0xd499: "pweonj" -0xd49a: "pweonh" -0xd49b: "pweod" -0xd49c: "pweol" -0xd49d: "pweolg" -0xd49e: "pweolm" -0xd49f: "pweolb" -0xd4a0: "pweols" -0xd4a1: "pweolt" -0xd4a2: "pweolp" -0xd4a3: "pweolh" -0xd4a4: "pweom" -0xd4a5: "pweob" -0xd4a6: "pweobs" -0xd4a7: "pweos" -0xd4a8: "pweoss" -0xd4a9: "pweong" -0xd4aa: "pweoj" -0xd4ab: "pweoc" -0xd4ac: "pweok" -0xd4ad: "pweot" -0xd4ae: "pweop" -0xd4af: "pweoh" -0xd4b0: "pwe" -0xd4b1: "pweg" -0xd4b2: "pwegg" -0xd4b3: "pwegs" -0xd4b4: "pwen" -0xd4b5: "pwenj" -0xd4b6: "pwenh" -0xd4b7: "pwed" -0xd4b8: "pwel" -0xd4b9: "pwelg" -0xd4ba: "pwelm" -0xd4bb: "pwelb" -0xd4bc: "pwels" -0xd4bd: "pwelt" -0xd4be: "pwelp" -0xd4bf: "pwelh" -0xd4c0: "pwem" -0xd4c1: "pweb" -0xd4c2: "pwebs" -0xd4c3: "pwes" -0xd4c4: "pwess" -0xd4c5: "pweng" -0xd4c6: "pwej" -0xd4c7: "pwec" -0xd4c8: "pwek" -0xd4c9: "pwet" -0xd4ca: "pwep" -0xd4cb: "pweh" -0xd4cc: "pwi" -0xd4cd: "pwig" -0xd4ce: "pwigg" -0xd4cf: "pwigs" -0xd4d0: "pwin" -0xd4d1: "pwinj" -0xd4d2: "pwinh" -0xd4d3: "pwid" -0xd4d4: "pwil" -0xd4d5: "pwilg" -0xd4d6: "pwilm" -0xd4d7: "pwilb" -0xd4d8: "pwils" -0xd4d9: "pwilt" -0xd4da: "pwilp" -0xd4db: "pwilh" -0xd4dc: "pwim" -0xd4dd: "pwib" -0xd4de: "pwibs" -0xd4df: "pwis" -0xd4e0: "pwiss" -0xd4e1: "pwing" -0xd4e2: "pwij" -0xd4e3: "pwic" -0xd4e4: "pwik" -0xd4e5: "pwit" -0xd4e6: "pwip" -0xd4e7: "pwih" -0xd4e8: "pyu" -0xd4e9: "pyug" -0xd4ea: "pyugg" -0xd4eb: "pyugs" -0xd4ec: "pyun" -0xd4ed: "pyunj" -0xd4ee: "pyunh" -0xd4ef: "pyud" -0xd4f0: "pyul" -0xd4f1: "pyulg" -0xd4f2: "pyulm" -0xd4f3: "pyulb" -0xd4f4: "pyuls" -0xd4f5: "pyult" -0xd4f6: "pyulp" -0xd4f7: "pyulh" -0xd4f8: "pyum" -0xd4f9: "pyub" -0xd4fa: "pyubs" -0xd4fb: "pyus" -0xd4fc: "pyuss" -0xd4fd: "pyung" -0xd4fe: "pyuj" -0xd4ff: "pyuc" -/* x0d5 */ -0xd500: "pyuk" -0xd501: "pyut" -0xd502: "pyup" -0xd503: "pyuh" -0xd504: "peu" -0xd505: "peug" -0xd506: "peugg" -0xd507: "peugs" -0xd508: "peun" -0xd509: "peunj" -0xd50a: "peunh" -0xd50b: "peud" -0xd50c: "peul" -0xd50d: "peulg" -0xd50e: "peulm" -0xd50f: "peulb" -0xd510: "peuls" -0xd511: "peult" -0xd512: "peulp" -0xd513: "peulh" -0xd514: "peum" -0xd515: "peub" -0xd516: "peubs" -0xd517: "peus" -0xd518: "peuss" -0xd519: "peung" -0xd51a: "peuj" -0xd51b: "peuc" -0xd51c: "peuk" -0xd51d: "peut" -0xd51e: "peup" -0xd51f: "peuh" -0xd520: "pyi" -0xd521: "pyig" -0xd522: "pyigg" -0xd523: "pyigs" -0xd524: "pyin" -0xd525: "pyinj" -0xd526: "pyinh" -0xd527: "pyid" -0xd528: "pyil" -0xd529: "pyilg" -0xd52a: "pyilm" -0xd52b: "pyilb" -0xd52c: "pyils" -0xd52d: "pyilt" -0xd52e: "pyilp" -0xd52f: "pyilh" -0xd530: "pyim" -0xd531: "pyib" -0xd532: "pyibs" -0xd533: "pyis" -0xd534: "pyiss" -0xd535: "pying" -0xd536: "pyij" -0xd537: "pyic" -0xd538: "pyik" -0xd539: "pyit" -0xd53a: "pyip" -0xd53b: "pyih" -0xd53c: "pi" -0xd53d: "pig" -0xd53e: "pigg" -0xd53f: "pigs" -0xd540: "pin" -0xd541: "pinj" -0xd542: "pinh" -0xd543: "pid" -0xd544: "pil" -0xd545: "pilg" -0xd546: "pilm" -0xd547: "pilb" -0xd548: "pils" -0xd549: "pilt" -0xd54a: "pilp" -0xd54b: "pilh" -0xd54c: "pim" -0xd54d: "pib" -0xd54e: "pibs" -0xd54f: "pis" -0xd550: "piss" -0xd551: "ping" -0xd552: "pij" -0xd553: "pic" -0xd554: "pik" -0xd555: "pit" -0xd556: "pip" -0xd557: "pih" -0xd558: "ha" -0xd559: "hag" -0xd55a: "hagg" -0xd55b: "hags" -0xd55c: "han" -0xd55d: "hanj" -0xd55e: "hanh" -0xd55f: "had" -0xd560: "hal" -0xd561: "halg" -0xd562: "halm" -0xd563: "halb" -0xd564: "hals" -0xd565: "halt" -0xd566: "halp" -0xd567: "halh" -0xd568: "ham" -0xd569: "hab" -0xd56a: "habs" -0xd56b: "has" -0xd56c: "hass" -0xd56d: "hang" -0xd56e: "haj" -0xd56f: "hac" -0xd570: "hak" -0xd571: "hat" -0xd572: "hap" -0xd573: "hah" -0xd574: "hae" -0xd575: "haeg" -0xd576: "haegg" -0xd577: "haegs" -0xd578: "haen" -0xd579: "haenj" -0xd57a: "haenh" -0xd57b: "haed" -0xd57c: "hael" -0xd57d: "haelg" -0xd57e: "haelm" -0xd57f: "haelb" -0xd580: "haels" -0xd581: "haelt" -0xd582: "haelp" -0xd583: "haelh" -0xd584: "haem" -0xd585: "haeb" -0xd586: "haebs" -0xd587: "haes" -0xd588: "haess" -0xd589: "haeng" -0xd58a: "haej" -0xd58b: "haec" -0xd58c: "haek" -0xd58d: "haet" -0xd58e: "haep" -0xd58f: "haeh" -0xd590: "hya" -0xd591: "hyag" -0xd592: "hyagg" -0xd593: "hyags" -0xd594: "hyan" -0xd595: "hyanj" -0xd596: "hyanh" -0xd597: "hyad" -0xd598: "hyal" -0xd599: "hyalg" -0xd59a: "hyalm" -0xd59b: "hyalb" -0xd59c: "hyals" -0xd59d: "hyalt" -0xd59e: "hyalp" -0xd59f: "hyalh" -0xd5a0: "hyam" -0xd5a1: "hyab" -0xd5a2: "hyabs" -0xd5a3: "hyas" -0xd5a4: "hyass" -0xd5a5: "hyang" -0xd5a6: "hyaj" -0xd5a7: "hyac" -0xd5a8: "hyak" -0xd5a9: "hyat" -0xd5aa: "hyap" -0xd5ab: "hyah" -0xd5ac: "hyae" -0xd5ad: "hyaeg" -0xd5ae: "hyaegg" -0xd5af: "hyaegs" -0xd5b0: "hyaen" -0xd5b1: "hyaenj" -0xd5b2: "hyaenh" -0xd5b3: "hyaed" -0xd5b4: "hyael" -0xd5b5: "hyaelg" -0xd5b6: "hyaelm" -0xd5b7: "hyaelb" -0xd5b8: "hyaels" -0xd5b9: "hyaelt" -0xd5ba: "hyaelp" -0xd5bb: "hyaelh" -0xd5bc: "hyaem" -0xd5bd: "hyaeb" -0xd5be: "hyaebs" -0xd5bf: "hyaes" -0xd5c0: "hyaess" -0xd5c1: "hyaeng" -0xd5c2: "hyaej" -0xd5c3: "hyaec" -0xd5c4: "hyaek" -0xd5c5: "hyaet" -0xd5c6: "hyaep" -0xd5c7: "hyaeh" -0xd5c8: "heo" -0xd5c9: "heog" -0xd5ca: "heogg" -0xd5cb: "heogs" -0xd5cc: "heon" -0xd5cd: "heonj" -0xd5ce: "heonh" -0xd5cf: "heod" -0xd5d0: "heol" -0xd5d1: "heolg" -0xd5d2: "heolm" -0xd5d3: "heolb" -0xd5d4: "heols" -0xd5d5: "heolt" -0xd5d6: "heolp" -0xd5d7: "heolh" -0xd5d8: "heom" -0xd5d9: "heob" -0xd5da: "heobs" -0xd5db: "heos" -0xd5dc: "heoss" -0xd5dd: "heong" -0xd5de: "heoj" -0xd5df: "heoc" -0xd5e0: "heok" -0xd5e1: "heot" -0xd5e2: "heop" -0xd5e3: "heoh" -0xd5e4: "he" -0xd5e5: "heg" -0xd5e6: "hegg" -0xd5e7: "hegs" -0xd5e8: "hen" -0xd5e9: "henj" -0xd5ea: "henh" -0xd5eb: "hed" -0xd5ec: "hel" -0xd5ed: "helg" -0xd5ee: "helm" -0xd5ef: "helb" -0xd5f0: "hels" -0xd5f1: "helt" -0xd5f2: "help" -0xd5f3: "helh" -0xd5f4: "hem" -0xd5f5: "heb" -0xd5f6: "hebs" -0xd5f7: "hes" -0xd5f8: "hess" -0xd5f9: "heng" -0xd5fa: "hej" -0xd5fb: "hec" -0xd5fc: "hek" -0xd5fd: "het" -0xd5fe: "hep" -0xd5ff: "heh" -/* x0d6 */ -0xd600: "hyeo" -0xd601: "hyeog" -0xd602: "hyeogg" -0xd603: "hyeogs" -0xd604: "hyeon" -0xd605: "hyeonj" -0xd606: "hyeonh" -0xd607: "hyeod" -0xd608: "hyeol" -0xd609: "hyeolg" -0xd60a: "hyeolm" -0xd60b: "hyeolb" -0xd60c: "hyeols" -0xd60d: "hyeolt" -0xd60e: "hyeolp" -0xd60f: "hyeolh" -0xd610: "hyeom" -0xd611: "hyeob" -0xd612: "hyeobs" -0xd613: "hyeos" -0xd614: "hyeoss" -0xd615: "hyeong" -0xd616: "hyeoj" -0xd617: "hyeoc" -0xd618: "hyeok" -0xd619: "hyeot" -0xd61a: "hyeop" -0xd61b: "hyeoh" -0xd61c: "hye" -0xd61d: "hyeg" -0xd61e: "hyegg" -0xd61f: "hyegs" -0xd620: "hyen" -0xd621: "hyenj" -0xd622: "hyenh" -0xd623: "hyed" -0xd624: "hyel" -0xd625: "hyelg" -0xd626: "hyelm" -0xd627: "hyelb" -0xd628: "hyels" -0xd629: "hyelt" -0xd62a: "hyelp" -0xd62b: "hyelh" -0xd62c: "hyem" -0xd62d: "hyeb" -0xd62e: "hyebs" -0xd62f: "hyes" -0xd630: "hyess" -0xd631: "hyeng" -0xd632: "hyej" -0xd633: "hyec" -0xd634: "hyek" -0xd635: "hyet" -0xd636: "hyep" -0xd637: "hyeh" -0xd638: "ho" -0xd639: "hog" -0xd63a: "hogg" -0xd63b: "hogs" -0xd63c: "hon" -0xd63d: "honj" -0xd63e: "honh" -0xd63f: "hod" -0xd640: "hol" -0xd641: "holg" -0xd642: "holm" -0xd643: "holb" -0xd644: "hols" -0xd645: "holt" -0xd646: "holp" -0xd647: "holh" -0xd648: "hom" -0xd649: "hob" -0xd64a: "hobs" -0xd64b: "hos" -0xd64c: "hoss" -0xd64d: "hong" -0xd64e: "hoj" -0xd64f: "hoc" -0xd650: "hok" -0xd651: "hot" -0xd652: "hop" -0xd653: "hoh" -0xd654: "hwa" -0xd655: "hwag" -0xd656: "hwagg" -0xd657: "hwags" -0xd658: "hwan" -0xd659: "hwanj" -0xd65a: "hwanh" -0xd65b: "hwad" -0xd65c: "hwal" -0xd65d: "hwalg" -0xd65e: "hwalm" -0xd65f: "hwalb" -0xd660: "hwals" -0xd661: "hwalt" -0xd662: "hwalp" -0xd663: "hwalh" -0xd664: "hwam" -0xd665: "hwab" -0xd666: "hwabs" -0xd667: "hwas" -0xd668: "hwass" -0xd669: "hwang" -0xd66a: "hwaj" -0xd66b: "hwac" -0xd66c: "hwak" -0xd66d: "hwat" -0xd66e: "hwap" -0xd66f: "hwah" -0xd670: "hwae" -0xd671: "hwaeg" -0xd672: "hwaegg" -0xd673: "hwaegs" -0xd674: "hwaen" -0xd675: "hwaenj" -0xd676: "hwaenh" -0xd677: "hwaed" -0xd678: "hwael" -0xd679: "hwaelg" -0xd67a: "hwaelm" -0xd67b: "hwaelb" -0xd67c: "hwaels" -0xd67d: "hwaelt" -0xd67e: "hwaelp" -0xd67f: "hwaelh" -0xd680: "hwaem" -0xd681: "hwaeb" -0xd682: "hwaebs" -0xd683: "hwaes" -0xd684: "hwaess" -0xd685: "hwaeng" -0xd686: "hwaej" -0xd687: "hwaec" -0xd688: "hwaek" -0xd689: "hwaet" -0xd68a: "hwaep" -0xd68b: "hwaeh" -0xd68c: "hoe" -0xd68d: "hoeg" -0xd68e: "hoegg" -0xd68f: "hoegs" -0xd690: "hoen" -0xd691: "hoenj" -0xd692: "hoenh" -0xd693: "hoed" -0xd694: "hoel" -0xd695: "hoelg" -0xd696: "hoelm" -0xd697: "hoelb" -0xd698: "hoels" -0xd699: "hoelt" -0xd69a: "hoelp" -0xd69b: "hoelh" -0xd69c: "hoem" -0xd69d: "hoeb" -0xd69e: "hoebs" -0xd69f: "hoes" -0xd6a0: "hoess" -0xd6a1: "hoeng" -0xd6a2: "hoej" -0xd6a3: "hoec" -0xd6a4: "hoek" -0xd6a5: "hoet" -0xd6a6: "hoep" -0xd6a7: "hoeh" -0xd6a8: "hyo" -0xd6a9: "hyog" -0xd6aa: "hyogg" -0xd6ab: "hyogs" -0xd6ac: "hyon" -0xd6ad: "hyonj" -0xd6ae: "hyonh" -0xd6af: "hyod" -0xd6b0: "hyol" -0xd6b1: "hyolg" -0xd6b2: "hyolm" -0xd6b3: "hyolb" -0xd6b4: "hyols" -0xd6b5: "hyolt" -0xd6b6: "hyolp" -0xd6b7: "hyolh" -0xd6b8: "hyom" -0xd6b9: "hyob" -0xd6ba: "hyobs" -0xd6bb: "hyos" -0xd6bc: "hyoss" -0xd6bd: "hyong" -0xd6be: "hyoj" -0xd6bf: "hyoc" -0xd6c0: "hyok" -0xd6c1: "hyot" -0xd6c2: "hyop" -0xd6c3: "hyoh" -0xd6c4: "hu" -0xd6c5: "hug" -0xd6c6: "hugg" -0xd6c7: "hugs" -0xd6c8: "hun" -0xd6c9: "hunj" -0xd6ca: "hunh" -0xd6cb: "hud" -0xd6cc: "hul" -0xd6cd: "hulg" -0xd6ce: "hulm" -0xd6cf: "hulb" -0xd6d0: "huls" -0xd6d1: "hult" -0xd6d2: "hulp" -0xd6d3: "hulh" -0xd6d4: "hum" -0xd6d5: "hub" -0xd6d6: "hubs" -0xd6d7: "hus" -0xd6d8: "huss" -0xd6d9: "hung" -0xd6da: "huj" -0xd6db: "huc" -0xd6dc: "huk" -0xd6dd: "hut" -0xd6de: "hup" -0xd6df: "huh" -0xd6e0: "hweo" -0xd6e1: "hweog" -0xd6e2: "hweogg" -0xd6e3: "hweogs" -0xd6e4: "hweon" -0xd6e5: "hweonj" -0xd6e6: "hweonh" -0xd6e7: "hweod" -0xd6e8: "hweol" -0xd6e9: "hweolg" -0xd6ea: "hweolm" -0xd6eb: "hweolb" -0xd6ec: "hweols" -0xd6ed: "hweolt" -0xd6ee: "hweolp" -0xd6ef: "hweolh" -0xd6f0: "hweom" -0xd6f1: "hweob" -0xd6f2: "hweobs" -0xd6f3: "hweos" -0xd6f4: "hweoss" -0xd6f5: "hweong" -0xd6f6: "hweoj" -0xd6f7: "hweoc" -0xd6f8: "hweok" -0xd6f9: "hweot" -0xd6fa: "hweop" -0xd6fb: "hweoh" -0xd6fc: "hwe" -0xd6fd: "hweg" -0xd6fe: "hwegg" -0xd6ff: "hwegs" -/* x0d7 */ -0xd700: "hwen" -0xd701: "hwenj" -0xd702: "hwenh" -0xd703: "hwed" -0xd704: "hwel" -0xd705: "hwelg" -0xd706: "hwelm" -0xd707: "hwelb" -0xd708: "hwels" -0xd709: "hwelt" -0xd70a: "hwelp" -0xd70b: "hwelh" -0xd70c: "hwem" -0xd70d: "hweb" -0xd70e: "hwebs" -0xd70f: "hwes" -0xd710: "hwess" -0xd711: "hweng" -0xd712: "hwej" -0xd713: "hwec" -0xd714: "hwek" -0xd715: "hwet" -0xd716: "hwep" -0xd717: "hweh" -0xd718: "hwi" -0xd719: "hwig" -0xd71a: "hwigg" -0xd71b: "hwigs" -0xd71c: "hwin" -0xd71d: "hwinj" -0xd71e: "hwinh" -0xd71f: "hwid" -0xd720: "hwil" -0xd721: "hwilg" -0xd722: "hwilm" -0xd723: "hwilb" -0xd724: "hwils" -0xd725: "hwilt" -0xd726: "hwilp" -0xd727: "hwilh" -0xd728: "hwim" -0xd729: "hwib" -0xd72a: "hwibs" -0xd72b: "hwis" -0xd72c: "hwiss" -0xd72d: "hwing" -0xd72e: "hwij" -0xd72f: "hwic" -0xd730: "hwik" -0xd731: "hwit" -0xd732: "hwip" -0xd733: "hwih" -0xd734: "hyu" -0xd735: "hyug" -0xd736: "hyugg" -0xd737: "hyugs" -0xd738: "hyun" -0xd739: "hyunj" -0xd73a: "hyunh" -0xd73b: "hyud" -0xd73c: "hyul" -0xd73d: "hyulg" -0xd73e: "hyulm" -0xd73f: "hyulb" -0xd740: "hyuls" -0xd741: "hyult" -0xd742: "hyulp" -0xd743: "hyulh" -0xd744: "hyum" -0xd745: "hyub" -0xd746: "hyubs" -0xd747: "hyus" -0xd748: "hyuss" -0xd749: "hyung" -0xd74a: "hyuj" -0xd74b: "hyuc" -0xd74c: "hyuk" -0xd74d: "hyut" -0xd74e: "hyup" -0xd74f: "hyuh" -0xd750: "heu" -0xd751: "heug" -0xd752: "heugg" -0xd753: "heugs" -0xd754: "heun" -0xd755: "heunj" -0xd756: "heunh" -0xd757: "heud" -0xd758: "heul" -0xd759: "heulg" -0xd75a: "heulm" -0xd75b: "heulb" -0xd75c: "heuls" -0xd75d: "heult" -0xd75e: "heulp" -0xd75f: "heulh" -0xd760: "heum" -0xd761: "heub" -0xd762: "heubs" -0xd763: "heus" -0xd764: "heuss" -0xd765: "heung" -0xd766: "heuj" -0xd767: "heuc" -0xd768: "heuk" -0xd769: "heut" -0xd76a: "heup" -0xd76b: "heuh" -0xd76c: "hyi" -0xd76d: "hyig" -0xd76e: "hyigg" -0xd76f: "hyigs" -0xd770: "hyin" -0xd771: "hyinj" -0xd772: "hyinh" -0xd773: "hyid" -0xd774: "hyil" -0xd775: "hyilg" -0xd776: "hyilm" -0xd777: "hyilb" -0xd778: "hyils" -0xd779: "hyilt" -0xd77a: "hyilp" -0xd77b: "hyilh" -0xd77c: "hyim" -0xd77d: "hyib" -0xd77e: "hyibs" -0xd77f: "hyis" -0xd780: "hyiss" -0xd781: "hying" -0xd782: "hyij" -0xd783: "hyic" -0xd784: "hyik" -0xd785: "hyit" -0xd786: "hyip" -0xd787: "hyih" -0xd788: "hi" -0xd789: "hig" -0xd78a: "higg" -0xd78b: "higs" -0xd78c: "hin" -0xd78d: "hinj" -0xd78e: "hinh" -0xd78f: "hid" -0xd790: "hil" -0xd791: "hilg" -0xd792: "hilm" -0xd793: "hilb" -0xd794: "hils" -0xd795: "hilt" -0xd796: "hilp" -0xd797: "hilh" -0xd798: "him" -0xd799: "hib" -0xd79a: "hibs" -0xd79b: "his" -0xd79c: "hiss" -0xd79d: "hing" -0xd79e: "hij" -0xd79f: "hic" -0xd7a0: "hik" -0xd7a1: "hit" -0xd7a2: "hip" -0xd7a3: "hih" -0xd7a4: "[?]" -0xd7a5: "[?]" -0xd7a6: "[?]" -0xd7a7: "[?]" -0xd7a8: "[?]" -0xd7a9: "[?]" -0xd7aa: "[?]" -0xd7ab: "[?]" -0xd7ac: "[?]" -0xd7ad: "[?]" -0xd7ae: "[?]" -0xd7af: "[?]" -0xd7b0: "[?]" -0xd7b1: "[?]" -0xd7b2: "[?]" -0xd7b3: "[?]" -0xd7b4: "[?]" -0xd7b5: "[?]" -0xd7b6: "[?]" -0xd7b7: "[?]" -0xd7b8: "[?]" -0xd7b9: "[?]" -0xd7ba: "[?]" -0xd7bb: "[?]" -0xd7bc: "[?]" -0xd7bd: "[?]" -0xd7be: "[?]" -0xd7bf: "[?]" -0xd7c0: "[?]" -0xd7c1: "[?]" -0xd7c2: "[?]" -0xd7c3: "[?]" -0xd7c4: "[?]" -0xd7c5: "[?]" -0xd7c6: "[?]" -0xd7c7: "[?]" -0xd7c8: "[?]" -0xd7c9: "[?]" -0xd7ca: "[?]" -0xd7cb: "[?]" -0xd7cc: "[?]" -0xd7cd: "[?]" -0xd7ce: "[?]" -0xd7cf: "[?]" -0xd7d0: "[?]" -0xd7d1: "[?]" -0xd7d2: "[?]" -0xd7d3: "[?]" -0xd7d4: "[?]" -0xd7d5: "[?]" -0xd7d6: "[?]" -0xd7d7: "[?]" -0xd7d8: "[?]" -0xd7d9: "[?]" -0xd7da: "[?]" -0xd7db: "[?]" -0xd7dc: "[?]" -0xd7dd: "[?]" -0xd7de: "[?]" -0xd7df: "[?]" -0xd7e0: "[?]" -0xd7e1: "[?]" -0xd7e2: "[?]" -0xd7e3: "[?]" -0xd7e4: "[?]" -0xd7e5: "[?]" -0xd7e6: "[?]" -0xd7e7: "[?]" -0xd7e8: "[?]" -0xd7e9: "[?]" -0xd7ea: "[?]" -0xd7eb: "[?]" -0xd7ec: "[?]" -0xd7ed: "[?]" -0xd7ee: "[?]" -0xd7ef: "[?]" -0xd7f0: "[?]" -0xd7f1: "[?]" -0xd7f2: "[?]" -0xd7f3: "[?]" -0xd7f4: "[?]" -0xd7f5: "[?]" -0xd7f6: "[?]" -0xd7f7: "[?]" -0xd7f8: "[?]" -0xd7f9: "[?]" -0xd7fa: "[?]" -0xd7fb: "[?]" -0xd7fc: "[?]" -0xd7fd: "[?]" -0xd7fe: "[?]" -/* x0f9 */ -0xf900: "Kay " -0xf901: "Kayng " -0xf902: "Ke " -0xf903: "Ko " -0xf904: "Kol " -0xf905: "Koc " -0xf906: "Kwi " -0xf907: "Kwi " -0xf908: "Kyun " -0xf909: "Kul " -0xf90a: "Kum " -0xf90b: "Na " -0xf90c: "Na " -0xf90d: "Na " -0xf90e: "La " -0xf90f: "Na " -0xf910: "Na " -0xf911: "Na " -0xf912: "Na " -0xf913: "Na " -0xf914: "Nak " -0xf915: "Nak " -0xf916: "Nak " -0xf917: "Nak " -0xf918: "Nak " -0xf919: "Nak " -0xf91a: "Nak " -0xf91b: "Nan " -0xf91c: "Nan " -0xf91d: "Nan " -0xf91e: "Nan " -0xf91f: "Nan " -0xf920: "Nan " -0xf921: "Nam " -0xf922: "Nam " -0xf923: "Nam " -0xf924: "Nam " -0xf925: "Nap " -0xf926: "Nap " -0xf927: "Nap " -0xf928: "Nang " -0xf929: "Nang " -0xf92a: "Nang " -0xf92b: "Nang " -0xf92c: "Nang " -0xf92d: "Nay " -0xf92e: "Nayng " -0xf92f: "No " -0xf930: "No " -0xf931: "No " -0xf932: "No " -0xf933: "No " -0xf934: "No " -0xf935: "No " -0xf936: "No " -0xf937: "No " -0xf938: "No " -0xf939: "No " -0xf93a: "No " -0xf93b: "Nok " -0xf93c: "Nok " -0xf93d: "Nok " -0xf93e: "Nok " -0xf93f: "Nok " -0xf940: "Nok " -0xf941: "Non " -0xf942: "Nong " -0xf943: "Nong " -0xf944: "Nong " -0xf945: "Nong " -0xf946: "Noy " -0xf947: "Noy " -0xf948: "Noy " -0xf949: "Noy " -0xf94a: "Nwu " -0xf94b: "Nwu " -0xf94c: "Nwu " -0xf94d: "Nwu " -0xf94e: "Nwu " -0xf94f: "Nwu " -0xf950: "Nwu " -0xf951: "Nwu " -0xf952: "Nuk " -0xf953: "Nuk " -0xf954: "Num " -0xf955: "Nung " -0xf956: "Nung " -0xf957: "Nung " -0xf958: "Nung " -0xf959: "Nung " -0xf95a: "Twu " -0xf95b: "La " -0xf95c: "Lak " -0xf95d: "Lak " -0xf95e: "Lan " -0xf95f: "Lyeng " -0xf960: "Lo " -0xf961: "Lyul " -0xf962: "Li " -0xf963: "Pey " -0xf964: "Pen " -0xf965: "Pyen " -0xf966: "Pwu " -0xf967: "Pwul " -0xf968: "Pi " -0xf969: "Sak " -0xf96a: "Sak " -0xf96b: "Sam " -0xf96c: "Sayk " -0xf96d: "Sayng " -0xf96e: "Sep " -0xf96f: "Sey " -0xf970: "Sway " -0xf971: "Sin " -0xf972: "Sim " -0xf973: "Sip " -0xf974: "Ya " -0xf975: "Yak " -0xf976: "Yak " -0xf977: "Yang " -0xf978: "Yang " -0xf979: "Yang " -0xf97a: "Yang " -0xf97b: "Yang " -0xf97c: "Yang " -0xf97d: "Yang " -0xf97e: "Yang " -0xf97f: "Ye " -0xf980: "Ye " -0xf981: "Ye " -0xf982: "Ye " -0xf983: "Ye " -0xf984: "Ye " -0xf985: "Ye " -0xf986: "Ye " -0xf987: "Ye " -0xf988: "Ye " -0xf989: "Ye " -0xf98a: "Yek " -0xf98b: "Yek " -0xf98c: "Yek " -0xf98d: "Yek " -0xf98e: "Yen " -0xf98f: "Yen " -0xf990: "Yen " -0xf991: "Yen " -0xf992: "Yen " -0xf993: "Yen " -0xf994: "Yen " -0xf995: "Yen " -0xf996: "Yen " -0xf997: "Yen " -0xf998: "Yen " -0xf999: "Yen " -0xf99a: "Yen " -0xf99b: "Yen " -0xf99c: "Yel " -0xf99d: "Yel " -0xf99e: "Yel " -0xf99f: "Yel " -0xf9a0: "Yel " -0xf9a1: "Yel " -0xf9a2: "Yem " -0xf9a3: "Yem " -0xf9a4: "Yem " -0xf9a5: "Yem " -0xf9a6: "Yem " -0xf9a7: "Yep " -0xf9a8: "Yeng " -0xf9a9: "Yeng " -0xf9aa: "Yeng " -0xf9ab: "Yeng " -0xf9ac: "Yeng " -0xf9ad: "Yeng " -0xf9ae: "Yeng " -0xf9af: "Yeng " -0xf9b0: "Yeng " -0xf9b1: "Yeng " -0xf9b2: "Yeng " -0xf9b3: "Yeng " -0xf9b4: "Yeng " -0xf9b5: "Yey " -0xf9b6: "Yey " -0xf9b7: "Yey " -0xf9b8: "Yey " -0xf9b9: "O " -0xf9ba: "Yo " -0xf9bb: "Yo " -0xf9bc: "Yo " -0xf9bd: "Yo " -0xf9be: "Yo " -0xf9bf: "Yo " -0xf9c0: "Yo " -0xf9c1: "Yo " -0xf9c2: "Yo " -0xf9c3: "Yo " -0xf9c4: "Yong " -0xf9c5: "Wun " -0xf9c6: "Wen " -0xf9c7: "Yu " -0xf9c8: "Yu " -0xf9c9: "Yu " -0xf9ca: "Yu " -0xf9cb: "Yu " -0xf9cc: "Yu " -0xf9cd: "Yu " -0xf9ce: "Yu " -0xf9cf: "Yu " -0xf9d0: "Yu " -0xf9d1: "Yuk " -0xf9d2: "Yuk " -0xf9d3: "Yuk " -0xf9d4: "Yun " -0xf9d5: "Yun " -0xf9d6: "Yun " -0xf9d7: "Yun " -0xf9d8: "Yul " -0xf9d9: "Yul " -0xf9da: "Yul " -0xf9db: "Yul " -0xf9dc: "Yung " -0xf9dd: "I " -0xf9de: "I " -0xf9df: "I " -0xf9e0: "I " -0xf9e1: "I " -0xf9e2: "I " -0xf9e3: "I " -0xf9e4: "I " -0xf9e5: "I " -0xf9e6: "I " -0xf9e7: "I " -0xf9e8: "I " -0xf9e9: "I " -0xf9ea: "I " -0xf9eb: "Ik " -0xf9ec: "Ik " -0xf9ed: "In " -0xf9ee: "In " -0xf9ef: "In " -0xf9f0: "In " -0xf9f1: "In " -0xf9f2: "In " -0xf9f3: "In " -0xf9f4: "Im " -0xf9f5: "Im " -0xf9f6: "Im " -0xf9f7: "Ip " -0xf9f8: "Ip " -0xf9f9: "Ip " -0xf9fa: "Cang " -0xf9fb: "Cek " -0xf9fc: "Ci " -0xf9fd: "Cip " -0xf9fe: "Cha " -0xf9ff: "Chek " -/* x0fa */ -0xfa00: "Chey " -0xfa01: "Thak " -0xfa02: "Thak " -0xfa03: "Thang " -0xfa04: "Thayk " -0xfa05: "Thong " -0xfa06: "Pho " -0xfa07: "Phok " -0xfa08: "Hang " -0xfa09: "Hang " -0xfa0a: "Hyen " -0xfa0b: "Hwak " -0xfa0c: "Wu " -0xfa0d: "Huo " -0xfa0e: "[?] " -0xfa0f: "[?] " -0xfa10: "Zhong " -0xfa11: "[?] " -0xfa12: "Qing " -0xfa13: "[?] " -0xfa14: "[?] " -0xfa15: "Xi " -0xfa16: "Zhu " -0xfa17: "Yi " -0xfa18: "Li " -0xfa19: "Shen " -0xfa1a: "Xiang " -0xfa1b: "Fu " -0xfa1c: "Jing " -0xfa1d: "Jing " -0xfa1e: "Yu " -0xfa1f: "[?] " -0xfa20: "Hagi " -0xfa21: "[?] " -0xfa22: "Zhu " -0xfa23: "[?] " -0xfa24: "[?] " -0xfa25: "Yi " -0xfa26: "Du " -0xfa27: "[?] " -0xfa28: "[?] " -0xfa29: "[?] " -0xfa2a: "Fan " -0xfa2b: "Si " -0xfa2c: "Guan " -0xfa2d: "[?]" -0xfa2e: "[?]" -0xfa2f: "[?]" -0xfa30: "[?]" -0xfa31: "[?]" -0xfa32: "[?]" -0xfa33: "[?]" -0xfa34: "[?]" -0xfa35: "[?]" -0xfa36: "[?]" -0xfa37: "[?]" -0xfa38: "[?]" -0xfa39: "[?]" -0xfa3a: "[?]" -0xfa3b: "[?]" -0xfa3c: "[?]" -0xfa3d: "[?]" -0xfa3e: "[?]" -0xfa3f: "[?]" -0xfa40: "[?]" -0xfa41: "[?]" -0xfa42: "[?]" -0xfa43: "[?]" -0xfa44: "[?]" -0xfa45: "[?]" -0xfa46: "[?]" -0xfa47: "[?]" -0xfa48: "[?]" -0xfa49: "[?]" -0xfa4a: "[?]" -0xfa4b: "[?]" -0xfa4c: "[?]" -0xfa4d: "[?]" -0xfa4e: "[?]" -0xfa4f: "[?]" -0xfa50: "[?]" -0xfa51: "[?]" -0xfa52: "[?]" -0xfa53: "[?]" -0xfa54: "[?]" -0xfa55: "[?]" -0xfa56: "[?]" -0xfa57: "[?]" -0xfa58: "[?]" -0xfa59: "[?]" -0xfa5a: "[?]" -0xfa5b: "[?]" -0xfa5c: "[?]" -0xfa5d: "[?]" -0xfa5e: "[?]" -0xfa5f: "[?]" -0xfa60: "[?]" -0xfa61: "[?]" -0xfa62: "[?]" -0xfa63: "[?]" -0xfa64: "[?]" -0xfa65: "[?]" -0xfa66: "[?]" -0xfa67: "[?]" -0xfa68: "[?]" -0xfa69: "[?]" -0xfa6a: "[?]" -0xfa6b: "[?]" -0xfa6c: "[?]" -0xfa6d: "[?]" -0xfa6e: "[?]" -0xfa6f: "[?]" -0xfa70: "[?]" -0xfa71: "[?]" -0xfa72: "[?]" -0xfa73: "[?]" -0xfa74: "[?]" -0xfa75: "[?]" -0xfa76: "[?]" -0xfa77: "[?]" -0xfa78: "[?]" -0xfa79: "[?]" -0xfa7a: "[?]" -0xfa7b: "[?]" -0xfa7c: "[?]" -0xfa7d: "[?]" -0xfa7e: "[?]" -0xfa7f: "[?]" -0xfa80: "[?]" -0xfa81: "[?]" -0xfa82: "[?]" -0xfa83: "[?]" -0xfa84: "[?]" -0xfa85: "[?]" -0xfa86: "[?]" -0xfa87: "[?]" -0xfa88: "[?]" -0xfa89: "[?]" -0xfa8a: "[?]" -0xfa8b: "[?]" -0xfa8c: "[?]" -0xfa8d: "[?]" -0xfa8e: "[?]" -0xfa8f: "[?]" -0xfa90: "[?]" -0xfa91: "[?]" -0xfa92: "[?]" -0xfa93: "[?]" -0xfa94: "[?]" -0xfa95: "[?]" -0xfa96: "[?]" -0xfa97: "[?]" -0xfa98: "[?]" -0xfa99: "[?]" -0xfa9a: "[?]" -0xfa9b: "[?]" -0xfa9c: "[?]" -0xfa9d: "[?]" -0xfa9e: "[?]" -0xfa9f: "[?]" -0xfaa0: "[?]" -0xfaa1: "[?]" -0xfaa2: "[?]" -0xfaa3: "[?]" -0xfaa4: "[?]" -0xfaa5: "[?]" -0xfaa6: "[?]" -0xfaa7: "[?]" -0xfaa8: "[?]" -0xfaa9: "[?]" -0xfaaa: "[?]" -0xfaab: "[?]" -0xfaac: "[?]" -0xfaad: "[?]" -0xfaae: "[?]" -0xfaaf: "[?]" -0xfab0: "[?]" -0xfab1: "[?]" -0xfab2: "[?]" -0xfab3: "[?]" -0xfab4: "[?]" -0xfab5: "[?]" -0xfab6: "[?]" -0xfab7: "[?]" -0xfab8: "[?]" -0xfab9: "[?]" -0xfaba: "[?]" -0xfabb: "[?]" -0xfabc: "[?]" -0xfabd: "[?]" -0xfabe: "[?]" -0xfabf: "[?]" -0xfac0: "[?]" -0xfac1: "[?]" -0xfac2: "[?]" -0xfac3: "[?]" -0xfac4: "[?]" -0xfac5: "[?]" -0xfac6: "[?]" -0xfac7: "[?]" -0xfac8: "[?]" -0xfac9: "[?]" -0xfaca: "[?]" -0xfacb: "[?]" -0xfacc: "[?]" -0xfacd: "[?]" -0xface: "[?]" -0xfacf: "[?]" -0xfad0: "[?]" -0xfad1: "[?]" -0xfad2: "[?]" -0xfad3: "[?]" -0xfad4: "[?]" -0xfad5: "[?]" -0xfad6: "[?]" -0xfad7: "[?]" -0xfad8: "[?]" -0xfad9: "[?]" -0xfada: "[?]" -0xfadb: "[?]" -0xfadc: "[?]" -0xfadd: "[?]" -0xfade: "[?]" -0xfadf: "[?]" -0xfae0: "[?]" -0xfae1: "[?]" -0xfae2: "[?]" -0xfae3: "[?]" -0xfae4: "[?]" -0xfae5: "[?]" -0xfae6: "[?]" -0xfae7: "[?]" -0xfae8: "[?]" -0xfae9: "[?]" -0xfaea: "[?]" -0xfaeb: "[?]" -0xfaec: "[?]" -0xfaed: "[?]" -0xfaee: "[?]" -0xfaef: "[?]" -0xfaf0: "[?]" -0xfaf1: "[?]" -0xfaf2: "[?]" -0xfaf3: "[?]" -0xfaf4: "[?]" -0xfaf5: "[?]" -0xfaf6: "[?]" -0xfaf7: "[?]" -0xfaf8: "[?]" -0xfaf9: "[?]" -0xfafa: "[?]" -0xfafb: "[?]" -0xfafc: "[?]" -0xfafd: "[?]" -0xfafe: "[?]" -/* x0fb */ -0xfb00: "ff" -0xfb01: "fi" -0xfb02: "fl" -0xfb03: "ffi" -0xfb04: "ffl" -0xfb05: "st" -0xfb06: "st" -0xfb07: "[?]" -0xfb08: "[?]" -0xfb09: "[?]" -0xfb0a: "[?]" -0xfb0b: "[?]" -0xfb0c: "[?]" -0xfb0d: "[?]" -0xfb0e: "[?]" -0xfb0f: "[?]" -0xfb10: "[?]" -0xfb11: "[?]" -0xfb12: "[?]" -0xfb13: "mn" -0xfb14: "me" -0xfb15: "mi" -0xfb16: "vn" -0xfb17: "mkh" -0xfb18: "[?]" -0xfb19: "[?]" -0xfb1a: "[?]" -0xfb1b: "[?]" -0xfb1c: "[?]" -0xfb1d: "yi" -0xfb1e: "" -0xfb1f: "ay" -0xfb20: "`" -0xfb21: "" -0xfb22: "d" -0xfb23: "h" -0xfb24: "k" -0xfb25: "l" -0xfb26: "m" -0xfb27: "m" -0xfb28: "t" -0xfb29: "+" -0xfb2a: "sh" -0xfb2b: "s" -0xfb2c: "sh" -0xfb2d: "s" -0xfb2e: "a" -0xfb2f: "a" -0xfb30: "" -0xfb31: "b" -0xfb32: "g" -0xfb33: "d" -0xfb34: "h" -0xfb35: "v" -0xfb36: "z" -0xfb37: "[?]" -0xfb38: "t" -0xfb39: "y" -0xfb3a: "k" -0xfb3b: "k" -0xfb3c: "l" -0xfb3d: "[?]" -0xfb3e: "l" -0xfb3f: "[?]" -0xfb40: "n" -0xfb41: "n" -0xfb42: "[?]" -0xfb43: "p" -0xfb44: "p" -0xfb45: "[?]" -0xfb46: "ts" -0xfb47: "ts" -0xfb48: "r" -0xfb49: "sh" -0xfb4a: "t" -0xfb4b: "vo" -0xfb4c: "b" -0xfb4d: "k" -0xfb4e: "p" -0xfb4f: "l" -0xfb50: "" -0xfb51: "" -0xfb52: "" -0xfb53: "" -0xfb54: "" -0xfb55: "" -0xfb56: "" -0xfb57: "" -0xfb58: "" -0xfb59: "" -0xfb5a: "" -0xfb5b: "" -0xfb5c: "" -0xfb5d: "" -0xfb5e: "" -0xfb5f: "" -0xfb60: "" -0xfb61: "" -0xfb62: "" -0xfb63: "" -0xfb64: "" -0xfb65: "" -0xfb66: "" -0xfb67: "" -0xfb68: "" -0xfb69: "" -0xfb6a: "" -0xfb6b: "" -0xfb6c: "" -0xfb6d: "" -0xfb6e: "" -0xfb6f: "" -0xfb70: "" -0xfb71: "" -0xfb72: "" -0xfb73: "" -0xfb74: "" -0xfb75: "" -0xfb76: "" -0xfb77: "" -0xfb78: "" -0xfb79: "" -0xfb7a: "" -0xfb7b: "" -0xfb7c: "" -0xfb7d: "" -0xfb7e: "" -0xfb7f: "" -0xfb80: "" -0xfb81: "" -0xfb82: "" -0xfb83: "" -0xfb84: "" -0xfb85: "" -0xfb86: "" -0xfb87: "" -0xfb88: "" -0xfb89: "" -0xfb8a: "" -0xfb8b: "" -0xfb8c: "" -0xfb8d: "" -0xfb8e: "" -0xfb8f: "" -0xfb90: "" -0xfb91: "" -0xfb92: "" -0xfb93: "" -0xfb94: "" -0xfb95: "" -0xfb96: "" -0xfb97: "" -0xfb98: "" -0xfb99: "" -0xfb9a: "" -0xfb9b: "" -0xfb9c: "" -0xfb9d: "" -0xfb9e: "" -0xfb9f: "" -0xfba0: "" -0xfba1: "" -0xfba2: "" -0xfba3: "" -0xfba4: "" -0xfba5: "" -0xfba6: "" -0xfba7: "" -0xfba8: "" -0xfba9: "" -0xfbaa: "" -0xfbab: "" -0xfbac: "" -0xfbad: "" -0xfbae: "" -0xfbaf: "" -0xfbb0: "" -0xfbb1: "" -0xfbb2: "[?]" -0xfbb3: "[?]" -0xfbb4: "[?]" -0xfbb5: "[?]" -0xfbb6: "[?]" -0xfbb7: "[?]" -0xfbb8: "[?]" -0xfbb9: "[?]" -0xfbba: "[?]" -0xfbbb: "[?]" -0xfbbc: "[?]" -0xfbbd: "[?]" -0xfbbe: "[?]" -0xfbbf: "[?]" -0xfbc0: "[?]" -0xfbc1: "[?]" -0xfbc2: "[?]" -0xfbc3: "[?]" -0xfbc4: "[?]" -0xfbc5: "[?]" -0xfbc6: "[?]" -0xfbc7: "[?]" -0xfbc8: "[?]" -0xfbc9: "[?]" -0xfbca: "[?]" -0xfbcb: "[?]" -0xfbcc: "[?]" -0xfbcd: "[?]" -0xfbce: "[?]" -0xfbcf: "[?]" -0xfbd0: "[?]" -0xfbd1: "[?]" -0xfbd2: "[?]" -0xfbd3: "" -0xfbd4: "" -0xfbd5: "" -0xfbd6: "" -0xfbd7: "" -0xfbd8: "" -0xfbd9: "" -0xfbda: "" -0xfbdb: "" -0xfbdc: "" -0xfbdd: "" -0xfbde: "" -0xfbdf: "" -0xfbe0: "" -0xfbe1: "" -0xfbe2: "" -0xfbe3: "" -0xfbe4: "" -0xfbe5: "" -0xfbe6: "" -0xfbe7: "" -0xfbe8: "" -0xfbe9: "" -0xfbea: "" -0xfbeb: "" -0xfbec: "" -0xfbed: "" -0xfbee: "" -0xfbef: "" -0xfbf0: "" -0xfbf1: "" -0xfbf2: "" -0xfbf3: "" -0xfbf4: "" -0xfbf5: "" -0xfbf6: "" -0xfbf7: "" -0xfbf8: "" -0xfbf9: "" -0xfbfa: "" -0xfbfb: "" -0xfbfc: "" -0xfbfd: "" -0xfbfe: "" -0xfbff: "" -/* x0fc */ -0xfc00: "" -0xfc01: "" -0xfc02: "" -0xfc03: "" -0xfc04: "" -0xfc05: "" -0xfc06: "" -0xfc07: "" -0xfc08: "" -0xfc09: "" -0xfc0a: "" -0xfc0b: "" -0xfc0c: "" -0xfc0d: "" -0xfc0e: "" -0xfc0f: "" -0xfc10: "" -0xfc11: "" -0xfc12: "" -0xfc13: "" -0xfc14: "" -0xfc15: "" -0xfc16: "" -0xfc17: "" -0xfc18: "" -0xfc19: "" -0xfc1a: "" -0xfc1b: "" -0xfc1c: "" -0xfc1d: "" -0xfc1e: "" -0xfc1f: "" -0xfc20: "" -0xfc21: "" -0xfc22: "" -0xfc23: "" -0xfc24: "" -0xfc25: "" -0xfc26: "" -0xfc27: "" -0xfc28: "" -0xfc29: "" -0xfc2a: "" -0xfc2b: "" -0xfc2c: "" -0xfc2d: "" -0xfc2e: "" -0xfc2f: "" -0xfc30: "" -0xfc31: "" -0xfc32: "" -0xfc33: "" -0xfc34: "" -0xfc35: "" -0xfc36: "" -0xfc37: "" -0xfc38: "" -0xfc39: "" -0xfc3a: "" -0xfc3b: "" -0xfc3c: "" -0xfc3d: "" -0xfc3e: "" -0xfc3f: "" -0xfc40: "" -0xfc41: "" -0xfc42: "" -0xfc43: "" -0xfc44: "" -0xfc45: "" -0xfc46: "" -0xfc47: "" -0xfc48: "" -0xfc49: "" -0xfc4a: "" -0xfc4b: "" -0xfc4c: "" -0xfc4d: "" -0xfc4e: "" -0xfc4f: "" -0xfc50: "" -0xfc51: "" -0xfc52: "" -0xfc53: "" -0xfc54: "" -0xfc55: "" -0xfc56: "" -0xfc57: "" -0xfc58: "" -0xfc59: "" -0xfc5a: "" -0xfc5b: "" -0xfc5c: "" -0xfc5d: "" -0xfc5e: "" -0xfc5f: "" -0xfc60: "" -0xfc61: "" -0xfc62: "" -0xfc63: "" -0xfc64: "" -0xfc65: "" -0xfc66: "" -0xfc67: "" -0xfc68: "" -0xfc69: "" -0xfc6a: "" -0xfc6b: "" -0xfc6c: "" -0xfc6d: "" -0xfc6e: "" -0xfc6f: "" -0xfc70: "" -0xfc71: "" -0xfc72: "" -0xfc73: "" -0xfc74: "" -0xfc75: "" -0xfc76: "" -0xfc77: "" -0xfc78: "" -0xfc79: "" -0xfc7a: "" -0xfc7b: "" -0xfc7c: "" -0xfc7d: "" -0xfc7e: "" -0xfc7f: "" -0xfc80: "" -0xfc81: "" -0xfc82: "" -0xfc83: "" -0xfc84: "" -0xfc85: "" -0xfc86: "" -0xfc87: "" -0xfc88: "" -0xfc89: "" -0xfc8a: "" -0xfc8b: "" -0xfc8c: "" -0xfc8d: "" -0xfc8e: "" -0xfc8f: "" -0xfc90: "" -0xfc91: "" -0xfc92: "" -0xfc93: "" -0xfc94: "" -0xfc95: "" -0xfc96: "" -0xfc97: "" -0xfc98: "" -0xfc99: "" -0xfc9a: "" -0xfc9b: "" -0xfc9c: "" -0xfc9d: "" -0xfc9e: "" -0xfc9f: "" -0xfca0: "" -0xfca1: "" -0xfca2: "" -0xfca3: "" -0xfca4: "" -0xfca5: "" -0xfca6: "" -0xfca7: "" -0xfca8: "" -0xfca9: "" -0xfcaa: "" -0xfcab: "" -0xfcac: "" -0xfcad: "" -0xfcae: "" -0xfcaf: "" -0xfcb0: "" -0xfcb1: "" -0xfcb2: "" -0xfcb3: "" -0xfcb4: "" -0xfcb5: "" -0xfcb6: "" -0xfcb7: "" -0xfcb8: "" -0xfcb9: "" -0xfcba: "" -0xfcbb: "" -0xfcbc: "" -0xfcbd: "" -0xfcbe: "" -0xfcbf: "" -0xfcc0: "" -0xfcc1: "" -0xfcc2: "" -0xfcc3: "" -0xfcc4: "" -0xfcc5: "" -0xfcc6: "" -0xfcc7: "" -0xfcc8: "" -0xfcc9: "" -0xfcca: "" -0xfccb: "" -0xfccc: "" -0xfccd: "" -0xfcce: "" -0xfccf: "" -0xfcd0: "" -0xfcd1: "" -0xfcd2: "" -0xfcd3: "" -0xfcd4: "" -0xfcd5: "" -0xfcd6: "" -0xfcd7: "" -0xfcd8: "" -0xfcd9: "" -0xfcda: "" -0xfcdb: "" -0xfcdc: "" -0xfcdd: "" -0xfcde: "" -0xfcdf: "" -0xfce0: "" -0xfce1: "" -0xfce2: "" -0xfce3: "" -0xfce4: "" -0xfce5: "" -0xfce6: "" -0xfce7: "" -0xfce8: "" -0xfce9: "" -0xfcea: "" -0xfceb: "" -0xfcec: "" -0xfced: "" -0xfcee: "" -0xfcef: "" -0xfcf0: "" -0xfcf1: "" -0xfcf2: "" -0xfcf3: "" -0xfcf4: "" -0xfcf5: "" -0xfcf6: "" -0xfcf7: "" -0xfcf8: "" -0xfcf9: "" -0xfcfa: "" -0xfcfb: "" -0xfcfc: "" -0xfcfd: "" -0xfcfe: "" -0xfcff: "" -/* x0fd */ -0xfd00: "" -0xfd01: "" -0xfd02: "" -0xfd03: "" -0xfd04: "" -0xfd05: "" -0xfd06: "" -0xfd07: "" -0xfd08: "" -0xfd09: "" -0xfd0a: "" -0xfd0b: "" -0xfd0c: "" -0xfd0d: "" -0xfd0e: "" -0xfd0f: "" -0xfd10: "" -0xfd11: "" -0xfd12: "" -0xfd13: "" -0xfd14: "" -0xfd15: "" -0xfd16: "" -0xfd17: "" -0xfd18: "" -0xfd19: "" -0xfd1a: "" -0xfd1b: "" -0xfd1c: "" -0xfd1d: "" -0xfd1e: "" -0xfd1f: "" -0xfd20: "" -0xfd21: "" -0xfd22: "" -0xfd23: "" -0xfd24: "" -0xfd25: "" -0xfd26: "" -0xfd27: "" -0xfd28: "" -0xfd29: "" -0xfd2a: "" -0xfd2b: "" -0xfd2c: "" -0xfd2d: "" -0xfd2e: "" -0xfd2f: "" -0xfd30: "" -0xfd31: "" -0xfd32: "" -0xfd33: "" -0xfd34: "" -0xfd35: "" -0xfd36: "" -0xfd37: "" -0xfd38: "" -0xfd39: "" -0xfd3a: "" -0xfd3b: "" -0xfd3c: "" -0xfd3d: "" -0xfd3e: "" -0xfd3f: "" -0xfd40: "[?]" -0xfd41: "[?]" -0xfd42: "[?]" -0xfd43: "[?]" -0xfd44: "[?]" -0xfd45: "[?]" -0xfd46: "[?]" -0xfd47: "[?]" -0xfd48: "[?]" -0xfd49: "[?]" -0xfd4a: "[?]" -0xfd4b: "[?]" -0xfd4c: "[?]" -0xfd4d: "[?]" -0xfd4e: "[?]" -0xfd4f: "[?]" -0xfd50: "" -0xfd51: "" -0xfd52: "" -0xfd53: "" -0xfd54: "" -0xfd55: "" -0xfd56: "" -0xfd57: "" -0xfd58: "" -0xfd59: "" -0xfd5a: "" -0xfd5b: "" -0xfd5c: "" -0xfd5d: "" -0xfd5e: "" -0xfd5f: "" -0xfd60: "" -0xfd61: "" -0xfd62: "" -0xfd63: "" -0xfd64: "" -0xfd65: "" -0xfd66: "" -0xfd67: "" -0xfd68: "" -0xfd69: "" -0xfd6a: "" -0xfd6b: "" -0xfd6c: "" -0xfd6d: "" -0xfd6e: "" -0xfd6f: "" -0xfd70: "" -0xfd71: "" -0xfd72: "" -0xfd73: "" -0xfd74: "" -0xfd75: "" -0xfd76: "" -0xfd77: "" -0xfd78: "" -0xfd79: "" -0xfd7a: "" -0xfd7b: "" -0xfd7c: "" -0xfd7d: "" -0xfd7e: "" -0xfd7f: "" -0xfd80: "" -0xfd81: "" -0xfd82: "" -0xfd83: "" -0xfd84: "" -0xfd85: "" -0xfd86: "" -0xfd87: "" -0xfd88: "" -0xfd89: "" -0xfd8a: "" -0xfd8b: "" -0xfd8c: "" -0xfd8d: "" -0xfd8e: "" -0xfd8f: "" -0xfd90: "[?]" -0xfd91: "[?]" -0xfd92: "" -0xfd93: "" -0xfd94: "" -0xfd95: "" -0xfd96: "" -0xfd97: "" -0xfd98: "" -0xfd99: "" -0xfd9a: "" -0xfd9b: "" -0xfd9c: "" -0xfd9d: "" -0xfd9e: "" -0xfd9f: "" -0xfda0: "" -0xfda1: "" -0xfda2: "" -0xfda3: "" -0xfda4: "" -0xfda5: "" -0xfda6: "" -0xfda7: "" -0xfda8: "" -0xfda9: "" -0xfdaa: "" -0xfdab: "" -0xfdac: "" -0xfdad: "" -0xfdae: "" -0xfdaf: "" -0xfdb0: "" -0xfdb1: "" -0xfdb2: "" -0xfdb3: "" -0xfdb4: "" -0xfdb5: "" -0xfdb6: "" -0xfdb7: "" -0xfdb8: "" -0xfdb9: "" -0xfdba: "" -0xfdbb: "" -0xfdbc: "" -0xfdbd: "" -0xfdbe: "" -0xfdbf: "" -0xfdc0: "" -0xfdc1: "" -0xfdc2: "" -0xfdc3: "" -0xfdc4: "" -0xfdc5: "" -0xfdc6: "" -0xfdc7: "" -0xfdc8: "[?]" -0xfdc9: "[?]" -0xfdca: "[?]" -0xfdcb: "[?]" -0xfdcc: "[?]" -0xfdcd: "[?]" -0xfdce: "[?]" -0xfdcf: "[?]" -0xfdd0: "[?]" -0xfdd1: "[?]" -0xfdd2: "[?]" -0xfdd3: "[?]" -0xfdd4: "[?]" -0xfdd5: "[?]" -0xfdd6: "[?]" -0xfdd7: "[?]" -0xfdd8: "[?]" -0xfdd9: "[?]" -0xfdda: "[?]" -0xfddb: "[?]" -0xfddc: "[?]" -0xfddd: "[?]" -0xfdde: "[?]" -0xfddf: "[?]" -0xfde0: "[?]" -0xfde1: "[?]" -0xfde2: "[?]" -0xfde3: "[?]" -0xfde4: "[?]" -0xfde5: "[?]" -0xfde6: "[?]" -0xfde7: "[?]" -0xfde8: "[?]" -0xfde9: "[?]" -0xfdea: "[?]" -0xfdeb: "[?]" -0xfdec: "[?]" -0xfded: "[?]" -0xfdee: "[?]" -0xfdef: "[?]" -0xfdf0: "" -0xfdf1: "" -0xfdf2: "" -0xfdf3: "" -0xfdf4: "" -0xfdf5: "" -0xfdf6: "" -0xfdf7: "" -0xfdf8: "" -0xfdf9: "" -0xfdfa: "" -0xfdfb: "" -0xfdfc: "[?]" -0xfdfd: "[?]" -0xfdfe: "[?]" -/* x0fe */ -0xfe00: "[?]" -0xfe01: "[?]" -0xfe02: "[?]" -0xfe03: "[?]" -0xfe04: "[?]" -0xfe05: "[?]" -0xfe06: "[?]" -0xfe07: "[?]" -0xfe08: "[?]" -0xfe09: "[?]" -0xfe0a: "[?]" -0xfe0b: "[?]" -0xfe0c: "[?]" -0xfe0d: "[?]" -0xfe0e: "[?]" -0xfe0f: "[?]" -0xfe10: "[?]" -0xfe11: "[?]" -0xfe12: "[?]" -0xfe13: "[?]" -0xfe14: "[?]" -0xfe15: "[?]" -0xfe16: "[?]" -0xfe17: "[?]" -0xfe18: "[?]" -0xfe19: "[?]" -0xfe1a: "[?]" -0xfe1b: "[?]" -0xfe1c: "[?]" -0xfe1d: "[?]" -0xfe1e: "[?]" -0xfe1f: "[?]" -0xfe20: "" -0xfe21: "" -0xfe22: "" -0xfe23: "~" -0xfe24: "[?]" -0xfe25: "[?]" -0xfe26: "[?]" -0xfe27: "[?]" -0xfe28: "[?]" -0xfe29: "[?]" -0xfe2a: "[?]" -0xfe2b: "[?]" -0xfe2c: "[?]" -0xfe2d: "[?]" -0xfe2e: "[?]" -0xfe2f: "[?]" -0xfe30: ".." -0xfe31: "--" -0xfe32: "-" -0xfe33: "_" -0xfe34: "_" -0xfe35: "(" -0xfe36: ") " -0xfe37: "{" -0xfe38: "} " -0xfe39: "[" -0xfe3a: "] " -0xfe3b: "[(" -0xfe3c: ")] " -0xfe3d: "<<" -0xfe3e: ">> " -0xfe3f: "<" -0xfe40: "> " -0xfe41: "[" -0xfe42: "] " -0xfe43: "{" -0xfe44: "}" -0xfe45: "[?]" -0xfe46: "[?]" -0xfe47: "[?]" -0xfe48: "[?]" -0xfe49: "" -0xfe4a: "" -0xfe4b: "" -0xfe4c: "" -0xfe4d: "" -0xfe4e: "" -0xfe4f: "" -0xfe50: "," -0xfe51: "," -0xfe52: "." -0xfe53: "" -0xfe54: ";" -0xfe55: ":" -0xfe56: "?" -0xfe57: "!" -0xfe58: "-" -0xfe59: "(" -0xfe5a: ")" -0xfe5b: "{" -0xfe5c: "}" -0xfe5d: "{" -0xfe5e: "}" -0xfe5f: "#" -0xfe60: "&" -0xfe61: "*" -0xfe62: "+" -0xfe63: "-" -0xfe64: "<" -0xfe65: ">" -0xfe66: "=" -0xfe67: "" -0xfe68: "\\" -0xfe69: "$" -0xfe6a: "%" -0xfe6b: "@" -0xfe6c: "[?]" -0xfe6d: "[?]" -0xfe6e: "[?]" -0xfe6f: "[?]" -0xfe70: "" -0xfe71: "" -0xfe72: "" -0xfe73: "[?]" -0xfe74: "" -0xfe75: "[?]" -0xfe76: "" -0xfe77: "" -0xfe78: "" -0xfe79: "" -0xfe7a: "" -0xfe7b: "" -0xfe7c: "" -0xfe7d: "" -0xfe7e: "" -0xfe7f: "" -0xfe80: "" -0xfe81: "" -0xfe82: "" -0xfe83: "" -0xfe84: "" -0xfe85: "" -0xfe86: "" -0xfe87: "" -0xfe88: "" -0xfe89: "" -0xfe8a: "" -0xfe8b: "" -0xfe8c: "" -0xfe8d: "" -0xfe8e: "" -0xfe8f: "" -0xfe90: "" -0xfe91: "" -0xfe92: "" -0xfe93: "" -0xfe94: "" -0xfe95: "" -0xfe96: "" -0xfe97: "" -0xfe98: "" -0xfe99: "" -0xfe9a: "" -0xfe9b: "" -0xfe9c: "" -0xfe9d: "" -0xfe9e: "" -0xfe9f: "" -0xfea0: "" -0xfea1: "" -0xfea2: "" -0xfea3: "" -0xfea4: "" -0xfea5: "" -0xfea6: "" -0xfea7: "" -0xfea8: "" -0xfea9: "" -0xfeaa: "" -0xfeab: "" -0xfeac: "" -0xfead: "" -0xfeae: "" -0xfeaf: "" -0xfeb0: "" -0xfeb1: "" -0xfeb2: "" -0xfeb3: "" -0xfeb4: "" -0xfeb5: "" -0xfeb6: "" -0xfeb7: "" -0xfeb8: "" -0xfeb9: "" -0xfeba: "" -0xfebb: "" -0xfebc: "" -0xfebd: "" -0xfebe: "" -0xfebf: "" -0xfec0: "" -0xfec1: "" -0xfec2: "" -0xfec3: "" -0xfec4: "" -0xfec5: "" -0xfec6: "" -0xfec7: "" -0xfec8: "" -0xfec9: "" -0xfeca: "" -0xfecb: "" -0xfecc: "" -0xfecd: "" -0xfece: "" -0xfecf: "" -0xfed0: "" -0xfed1: "" -0xfed2: "" -0xfed3: "" -0xfed4: "" -0xfed5: "" -0xfed6: "" -0xfed7: "" -0xfed8: "" -0xfed9: "" -0xfeda: "" -0xfedb: "" -0xfedc: "" -0xfedd: "" -0xfede: "" -0xfedf: "" -0xfee0: "" -0xfee1: "" -0xfee2: "" -0xfee3: "" -0xfee4: "" -0xfee5: "" -0xfee6: "" -0xfee7: "" -0xfee8: "" -0xfee9: "" -0xfeea: "" -0xfeeb: "" -0xfeec: "" -0xfeed: "" -0xfeee: "" -0xfeef: "" -0xfef0: "" -0xfef1: "" -0xfef2: "" -0xfef3: "" -0xfef4: "" -0xfef5: "" -0xfef6: "" -0xfef7: "" -0xfef8: "" -0xfef9: "" -0xfefa: "" -0xfefb: "" -0xfefc: "" -0xfefd: "[?]" -0xfefe: "[?]" -0xfeff: "" -/* x0ff */ -0xff00: "[?]" -0xff01: "!" -0xff02: "\"" -0xff03: "#" -0xff04: "$" -0xff05: "%" -0xff06: "&" -0xff07: "'" -0xff08: "(" -0xff09: ")" -0xff0a: "*" -0xff0b: "+" -0xff0c: "," -0xff0d: "-" -0xff0e: "." -0xff0f: "/" -0xff10: "0" -0xff11: "1" -0xff12: "2" -0xff13: "3" -0xff14: "4" -0xff15: "5" -0xff16: "6" -0xff17: "7" -0xff18: "8" -0xff19: "9" -0xff1a: ":" -0xff1b: ";" -0xff1c: "<" -0xff1d: "=" -0xff1e: ">" -0xff1f: "?" -0xff20: "@" -0xff21: "A" -0xff22: "B" -0xff23: "C" -0xff24: "D" -0xff25: "E" -0xff26: "F" -0xff27: "G" -0xff28: "H" -0xff29: "I" -0xff2a: "J" -0xff2b: "K" -0xff2c: "L" -0xff2d: "M" -0xff2e: "N" -0xff2f: "O" -0xff30: "P" -0xff31: "Q" -0xff32: "R" -0xff33: "S" -0xff34: "T" -0xff35: "U" -0xff36: "V" -0xff37: "W" -0xff38: "X" -0xff39: "Y" -0xff3a: "Z" -0xff3b: "[" -0xff3c: "\\" -0xff3d: "]" -0xff3e: "^" -0xff3f: "_" -0xff40: "`" -0xff41: "a" -0xff42: "b" -0xff43: "c" -0xff44: "d" -0xff45: "e" -0xff46: "f" -0xff47: "g" -0xff48: "h" -0xff49: "i" -0xff4a: "j" -0xff4b: "k" -0xff4c: "l" -0xff4d: "m" -0xff4e: "n" -0xff4f: "o" -0xff50: "p" -0xff51: "q" -0xff52: "r" -0xff53: "s" -0xff54: "t" -0xff55: "u" -0xff56: "v" -0xff57: "w" -0xff58: "x" -0xff59: "y" -0xff5a: "z" -0xff5b: "{" -0xff5c: "|" -0xff5d: "}" -0xff5e: "~" -0xff5f: "[?]" -0xff60: "[?]" -0xff61: "." -0xff62: "[" -0xff63: "]" -0xff64: "," -0xff65: "*" -0xff66: "wo" -0xff67: "a" -0xff68: "i" -0xff69: "u" -0xff6a: "e" -0xff6b: "o" -0xff6c: "ya" -0xff6d: "yu" -0xff6e: "yo" -0xff6f: "tu" -0xff70: "+" -0xff71: "a" -0xff72: "i" -0xff73: "u" -0xff74: "e" -0xff75: "o" -0xff76: "ka" -0xff77: "ki" -0xff78: "ku" -0xff79: "ke" -0xff7a: "ko" -0xff7b: "sa" -0xff7c: "si" -0xff7d: "su" -0xff7e: "se" -0xff7f: "so" -0xff80: "ta" -0xff81: "ti" -0xff82: "tu" -0xff83: "te" -0xff84: "to" -0xff85: "na" -0xff86: "ni" -0xff87: "nu" -0xff88: "ne" -0xff89: "no" -0xff8a: "ha" -0xff8b: "hi" -0xff8c: "hu" -0xff8d: "he" -0xff8e: "ho" -0xff8f: "ma" -0xff90: "mi" -0xff91: "mu" -0xff92: "me" -0xff93: "mo" -0xff94: "ya" -0xff95: "yu" -0xff96: "yo" -0xff97: "ra" -0xff98: "ri" -0xff99: "ru" -0xff9a: "re" -0xff9b: "ro" -0xff9c: "wa" -0xff9d: "n" -0xff9e: ":" -0xff9f: ";" -0xffa0: "" -0xffa1: "g" -0xffa2: "gg" -0xffa3: "gs" -0xffa4: "n" -0xffa5: "nj" -0xffa6: "nh" -0xffa7: "d" -0xffa8: "dd" -0xffa9: "r" -0xffaa: "lg" -0xffab: "lm" -0xffac: "lb" -0xffad: "ls" -0xffae: "lt" -0xffaf: "lp" -0xffb0: "rh" -0xffb1: "m" -0xffb2: "b" -0xffb3: "bb" -0xffb4: "bs" -0xffb5: "s" -0xffb6: "ss" -0xffb7: "" -0xffb8: "j" -0xffb9: "jj" -0xffba: "c" -0xffbb: "k" -0xffbc: "t" -0xffbd: "p" -0xffbe: "h" -0xffbf: "[?]" -0xffc0: "[?]" -0xffc1: "[?]" -0xffc2: "a" -0xffc3: "ae" -0xffc4: "ya" -0xffc5: "yae" -0xffc6: "eo" -0xffc7: "e" -0xffc8: "[?]" -0xffc9: "[?]" -0xffca: "yeo" -0xffcb: "ye" -0xffcc: "o" -0xffcd: "wa" -0xffce: "wae" -0xffcf: "oe" -0xffd0: "[?]" -0xffd1: "[?]" -0xffd2: "yo" -0xffd3: "u" -0xffd4: "weo" -0xffd5: "we" -0xffd6: "wi" -0xffd7: "yu" -0xffd8: "[?]" -0xffd9: "[?]" -0xffda: "eu" -0xffdb: "yi" -0xffdc: "i" -0xffdd: "[?]" -0xffde: "[?]" -0xffdf: "[?]" -0xffe0: "/C" -0xffe1: "PS" -0xffe2: "!" -0xffe3: "-" -0xffe4: "|" -0xffe5: "Y=" -0xffe6: "W=" -0xffe7: "[?]" -0xffe8: "|" -0xffe9: "-" -0xffea: "|" -0xffeb: "-" -0xffec: "|" -0xffed: "#" -0xffee: "O" -0xffef: "[?]" -0xfff0: "[?]" -0xfff1: "[?]" -0xfff2: "[?]" -0xfff3: "[?]" -0xfff4: "[?]" -0xfff5: "[?]" -0xfff6: "[?]" -0xfff7: "[?]" -0xfff8: "[?]" -0xfff9: "{" -0xfffa: "|" -0xfffb: "}" -0xfffc: "" -0xfffd: "" -0xfffe: "" -0xffff: "" diff --git a/vendor/github.com/rainycape/unidecode/unidecode.go b/vendor/github.com/rainycape/unidecode/unidecode.go index f9d2d49d418..16281da4bb9 100644 --- a/vendor/github.com/rainycape/unidecode/unidecode.go +++ b/vendor/github.com/rainycape/unidecode/unidecode.go @@ -3,6 +3,8 @@ // approximations. package unidecode +//go:generate go run make_table.go + import ( "sync" "unicode" diff --git a/vendor/github.com/rainycape/unidecode/unidecode_test.go b/vendor/github.com/rainycape/unidecode/unidecode_test.go deleted file mode 100644 index 7ef0de9f2fc..00000000000 --- a/vendor/github.com/rainycape/unidecode/unidecode_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package unidecode - -import ( - "testing" -) - -func testTransliteration(original string, decoded string, t *testing.T) { - if r := Unidecode(original); r != decoded { - t.Errorf("Expected '%s', got '%s'\n", decoded, r) - } -} - -func TestASCII(t *testing.T) { - s := "ABCDEF" - testTransliteration(s, s, t) -} - -func TestKnosos(t *testing.T) { - o := "Κνωσός" - d := "Knosos" - testTransliteration(o, d, t) -} - -func TestBeiJing(t *testing.T) { - o := "\u5317\u4EB0" - d := "Bei Jing " - testTransliteration(o, d, t) -} - -func TestEmoji(t *testing.T) { - o := "Hey Luna t belle 😵😂" - d := "Hey Luna t belle " - testTransliteration(o, d, t) -} - -func BenchmarkUnidecode(b *testing.B) { - cases := []string{ - "ABCDEF", - "Κνωσός", - "\u5317\u4EB0", - } - for ii := 0; ii < b.N; ii++ { - for _, v := range cases { - _ = Unidecode(v) - } - } -} - -func BenchmarkDecodeTable(b *testing.B) { - for ii := 0; ii < b.N; ii++ { - decodeTransliterations() - } -} - -func init() { - decodeTransliterations() -} diff --git a/vendor/github.com/sergi/go-diff/AUTHORS b/vendor/github.com/sergi/go-diff/AUTHORS new file mode 100644 index 00000000000..2d7bb2bf572 --- /dev/null +++ b/vendor/github.com/sergi/go-diff/AUTHORS @@ -0,0 +1,25 @@ +# This is the official list of go-diff authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Danny Yoo +James Kolb +Jonathan Amsterdam +Markus Zimmermann +Matt Kovars +Örjan Persson +Osman Masood +Robert Carlsen +Rory Flynn +Sergi Mansilla +Shatrugna Sadhu +Shawn Smith +Stas Maksimov +Tor Arvid Lund +Zac Bergquist diff --git a/vendor/github.com/sergi/go-diff/CONTRIBUTORS b/vendor/github.com/sergi/go-diff/CONTRIBUTORS new file mode 100644 index 00000000000..369e3d55190 --- /dev/null +++ b/vendor/github.com/sergi/go-diff/CONTRIBUTORS @@ -0,0 +1,32 @@ +# This is the official list of people who can contribute +# (and typically have contributed) code to the go-diff +# repository. +# +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, ACME Inc. employees would be listed here +# but not in AUTHORS, because ACME Inc. would hold the copyright. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Danny Yoo +James Kolb +Jonathan Amsterdam +Markus Zimmermann +Matt Kovars +Örjan Persson +Osman Masood +Robert Carlsen +Rory Flynn +Sergi Mansilla +Shatrugna Sadhu +Shawn Smith +Stas Maksimov +Tor Arvid Lund +Zac Bergquist diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go index 59b8851683f..82ad7bc8f1c 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go @@ -1285,6 +1285,7 @@ func (dmp *DiffMatchPatch) DiffToDelta(diffs []Diff) string { // DiffFromDelta given the original text1, and an encoded string which describes the operations required to transform text1 into text2, comAdde the full diff. func (dmp *DiffMatchPatch) DiffFromDelta(text1 string, delta string) (diffs []Diff, err error) { i := 0 + runes := []rune(text1) for _, token := range strings.Split(delta, "\t") { if len(token) == 0 { @@ -1316,9 +1317,13 @@ func (dmp *DiffMatchPatch) DiffFromDelta(text1 string, delta string) (diffs []Di return nil, errors.New("Negative number in DiffFromDelta: " + param) } - // Remember that string slicing is by byte - we want by rune here. - text := string([]rune(text1)[i : i+int(n)]) i += int(n) + // Break out if we are out of bounds, go1.6 can't handle this very well + if i > len(runes) { + break + } + // Remember that string slicing is by byte - we want by rune here. + text := string(runes[i-int(n) : i]) if op == '=' { diffs = append(diffs, Diff{DiffEqual, text}) @@ -1331,8 +1336,8 @@ func (dmp *DiffMatchPatch) DiffFromDelta(text1 string, delta string) (diffs []Di } } - if i != len([]rune(text1)) { - return nil, fmt.Errorf("Delta length (%v) smaller than source text length (%v)", i, len(text1)) + if i != len(runes) { + return nil, fmt.Errorf("Delta length (%v) is different from source text length (%v)", i, len(text1)) } return diffs, nil diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go index 116c0434811..223c43c4268 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go @@ -21,32 +21,32 @@ import ( // Patch represents one patch operation. type Patch struct { diffs []Diff - start1 int - start2 int - length1 int - length2 int + Start1 int + Start2 int + Length1 int + Length2 int } // String emulates GNU diff's format. // Header: @@ -382,8 +481,9 @@ -// Indicies are printed as 1-based, not 0-based. +// Indices are printed as 1-based, not 0-based. func (p *Patch) String() string { var coords1, coords2 string - if p.length1 == 0 { - coords1 = strconv.Itoa(p.start1) + ",0" - } else if p.length1 == 1 { - coords1 = strconv.Itoa(p.start1 + 1) + if p.Length1 == 0 { + coords1 = strconv.Itoa(p.Start1) + ",0" + } else if p.Length1 == 1 { + coords1 = strconv.Itoa(p.Start1 + 1) } else { - coords1 = strconv.Itoa(p.start1+1) + "," + strconv.Itoa(p.length1) + coords1 = strconv.Itoa(p.Start1+1) + "," + strconv.Itoa(p.Length1) } - if p.length2 == 0 { - coords2 = strconv.Itoa(p.start2) + ",0" - } else if p.length2 == 1 { - coords2 = strconv.Itoa(p.start2 + 1) + if p.Length2 == 0 { + coords2 = strconv.Itoa(p.Start2) + ",0" + } else if p.Length2 == 1 { + coords2 = strconv.Itoa(p.Start2 + 1) } else { - coords2 = strconv.Itoa(p.start2+1) + "," + strconv.Itoa(p.length2) + coords2 = strconv.Itoa(p.Start2+1) + "," + strconv.Itoa(p.Length2) } var text bytes.Buffer @@ -76,37 +76,37 @@ func (dmp *DiffMatchPatch) PatchAddContext(patch Patch, text string) Patch { return patch } - pattern := text[patch.start2 : patch.start2+patch.length1] + pattern := text[patch.Start2 : patch.Start2+patch.Length1] padding := 0 // Look for the first and last matches of pattern in text. If two different matches are found, increase the pattern length. for strings.Index(text, pattern) != strings.LastIndex(text, pattern) && len(pattern) < dmp.MatchMaxBits-2*dmp.PatchMargin { padding += dmp.PatchMargin - maxStart := max(0, patch.start2-padding) - minEnd := min(len(text), patch.start2+patch.length1+padding) + maxStart := max(0, patch.Start2-padding) + minEnd := min(len(text), patch.Start2+patch.Length1+padding) pattern = text[maxStart:minEnd] } // Add one chunk for good luck. padding += dmp.PatchMargin // Add the prefix. - prefix := text[max(0, patch.start2-padding):patch.start2] + prefix := text[max(0, patch.Start2-padding):patch.Start2] if len(prefix) != 0 { patch.diffs = append([]Diff{Diff{DiffEqual, prefix}}, patch.diffs...) } // Add the suffix. - suffix := text[patch.start2+patch.length1 : min(len(text), patch.start2+patch.length1+padding)] + suffix := text[patch.Start2+patch.Length1 : min(len(text), patch.Start2+patch.Length1+padding)] if len(suffix) != 0 { patch.diffs = append(patch.diffs, Diff{DiffEqual, suffix}) } // Roll back the start points. - patch.start1 -= len(prefix) - patch.start2 -= len(prefix) + patch.Start1 -= len(prefix) + patch.Start2 -= len(prefix) // Extend the lengths. - patch.length1 += len(prefix) + len(suffix) - patch.length2 += len(prefix) + len(suffix) + patch.Length1 += len(prefix) + len(suffix) + patch.Length2 += len(prefix) + len(suffix) return patch } @@ -155,18 +155,18 @@ func (dmp *DiffMatchPatch) patchMake2(text1 string, diffs []Diff) []Patch { for i, aDiff := range diffs { if len(patch.diffs) == 0 && aDiff.Type != DiffEqual { // A new patch starts here. - patch.start1 = charCount1 - patch.start2 = charCount2 + patch.Start1 = charCount1 + patch.Start2 = charCount2 } switch aDiff.Type { case DiffInsert: patch.diffs = append(patch.diffs, aDiff) - patch.length2 += len(aDiff.Text) + patch.Length2 += len(aDiff.Text) postpatchText = postpatchText[:charCount2] + aDiff.Text + postpatchText[charCount2:] case DiffDelete: - patch.length1 += len(aDiff.Text) + patch.Length1 += len(aDiff.Text) patch.diffs = append(patch.diffs, aDiff) postpatchText = postpatchText[:charCount2] + postpatchText[charCount2+len(aDiff.Text):] case DiffEqual: @@ -174,8 +174,8 @@ func (dmp *DiffMatchPatch) patchMake2(text1 string, diffs []Diff) []Patch { len(patch.diffs) != 0 && i != len(diffs)-1 { // Small equality inside a patch. patch.diffs = append(patch.diffs, aDiff) - patch.length1 += len(aDiff.Text) - patch.length2 += len(aDiff.Text) + patch.Length1 += len(aDiff.Text) + patch.Length2 += len(aDiff.Text) } if len(aDiff.Text) >= 2*dmp.PatchMargin { // Time for a new patch. @@ -219,10 +219,10 @@ func (dmp *DiffMatchPatch) PatchDeepCopy(patches []Patch) []Patch { aDiff.Text, }) } - patchCopy.start1 = aPatch.start1 - patchCopy.start2 = aPatch.start2 - patchCopy.length1 = aPatch.length1 - patchCopy.length2 = aPatch.length2 + patchCopy.Start1 = aPatch.Start1 + patchCopy.Start2 = aPatch.Start2 + patchCopy.Length1 = aPatch.Length1 + patchCopy.Length2 = aPatch.Length2 patchesCopy = append(patchesCopy, patchCopy) } return patchesCopy @@ -246,7 +246,7 @@ func (dmp *DiffMatchPatch) PatchApply(patches []Patch, text string) (string, []b delta := 0 results := make([]bool, len(patches)) for _, aPatch := range patches { - expectedLoc := aPatch.start2 + delta + expectedLoc := aPatch.Start2 + delta text1 := dmp.DiffText1(aPatch.diffs) var startLoc int endLoc := -1 @@ -268,7 +268,7 @@ func (dmp *DiffMatchPatch) PatchApply(patches []Patch, text string) (string, []b // No match found. :( results[x] = false // Subtract the delta for this failed patch from subsequent patches. - delta -= aPatch.length2 - aPatch.length1 + delta -= aPatch.Length2 - aPatch.Length1 } else { // Found a match. :) results[x] = true @@ -329,26 +329,26 @@ func (dmp *DiffMatchPatch) PatchAddPadding(patches []Patch) string { // Bump all the patches forward. for i := range patches { - patches[i].start1 += paddingLength - patches[i].start2 += paddingLength + patches[i].Start1 += paddingLength + patches[i].Start2 += paddingLength } // Add some padding on start of first diff. if len(patches[0].diffs) == 0 || patches[0].diffs[0].Type != DiffEqual { // Add nullPadding equality. patches[0].diffs = append([]Diff{Diff{DiffEqual, nullPadding}}, patches[0].diffs...) - patches[0].start1 -= paddingLength // Should be 0. - patches[0].start2 -= paddingLength // Should be 0. - patches[0].length1 += paddingLength - patches[0].length2 += paddingLength + patches[0].Start1 -= paddingLength // Should be 0. + patches[0].Start2 -= paddingLength // Should be 0. + patches[0].Length1 += paddingLength + patches[0].Length2 += paddingLength } else if paddingLength > len(patches[0].diffs[0].Text) { // Grow first equality. extraLength := paddingLength - len(patches[0].diffs[0].Text) patches[0].diffs[0].Text = nullPadding[len(patches[0].diffs[0].Text):] + patches[0].diffs[0].Text - patches[0].start1 -= extraLength - patches[0].start2 -= extraLength - patches[0].length1 += extraLength - patches[0].length2 += extraLength + patches[0].Start1 -= extraLength + patches[0].Start2 -= extraLength + patches[0].Length1 += extraLength + patches[0].Length2 += extraLength } // Add some padding on end of last diff. @@ -356,15 +356,15 @@ func (dmp *DiffMatchPatch) PatchAddPadding(patches []Patch) string { if len(patches[last].diffs) == 0 || patches[last].diffs[len(patches[last].diffs)-1].Type != DiffEqual { // Add nullPadding equality. patches[last].diffs = append(patches[last].diffs, Diff{DiffEqual, nullPadding}) - patches[last].length1 += paddingLength - patches[last].length2 += paddingLength + patches[last].Length1 += paddingLength + patches[last].Length2 += paddingLength } else if paddingLength > len(patches[last].diffs[len(patches[last].diffs)-1].Text) { // Grow last equality. lastDiff := patches[last].diffs[len(patches[last].diffs)-1] extraLength := paddingLength - len(lastDiff.Text) patches[last].diffs[len(patches[last].diffs)-1].Text += nullPadding[:extraLength] - patches[last].length1 += extraLength - patches[last].length2 += extraLength + patches[last].Length1 += extraLength + patches[last].Length2 += extraLength } return nullPadding @@ -375,7 +375,7 @@ func (dmp *DiffMatchPatch) PatchAddPadding(patches []Patch) string { func (dmp *DiffMatchPatch) PatchSplitMax(patches []Patch) []Patch { patchSize := dmp.MatchMaxBits for x := 0; x < len(patches); x++ { - if patches[x].length1 <= patchSize { + if patches[x].Length1 <= patchSize { continue } bigpatch := patches[x] @@ -383,46 +383,46 @@ func (dmp *DiffMatchPatch) PatchSplitMax(patches []Patch) []Patch { patches = append(patches[:x], patches[x+1:]...) x-- - start1 := bigpatch.start1 - start2 := bigpatch.start2 + Start1 := bigpatch.Start1 + Start2 := bigpatch.Start2 precontext := "" for len(bigpatch.diffs) != 0 { // Create one of several smaller patches. patch := Patch{} empty := true - patch.start1 = start1 - len(precontext) - patch.start2 = start2 - len(precontext) + patch.Start1 = Start1 - len(precontext) + patch.Start2 = Start2 - len(precontext) if len(precontext) != 0 { - patch.length1 = len(precontext) - patch.length2 = len(precontext) + patch.Length1 = len(precontext) + patch.Length2 = len(precontext) patch.diffs = append(patch.diffs, Diff{DiffEqual, precontext}) } - for len(bigpatch.diffs) != 0 && patch.length1 < patchSize-dmp.PatchMargin { + for len(bigpatch.diffs) != 0 && patch.Length1 < patchSize-dmp.PatchMargin { diffType := bigpatch.diffs[0].Type diffText := bigpatch.diffs[0].Text if diffType == DiffInsert { // Insertions are harmless. - patch.length2 += len(diffText) - start2 += len(diffText) + patch.Length2 += len(diffText) + Start2 += len(diffText) patch.diffs = append(patch.diffs, bigpatch.diffs[0]) bigpatch.diffs = bigpatch.diffs[1:] empty = false } else if diffType == DiffDelete && len(patch.diffs) == 1 && patch.diffs[0].Type == DiffEqual && len(diffText) > 2*patchSize { // This is a large deletion. Let it pass in one chunk. - patch.length1 += len(diffText) - start1 += len(diffText) + patch.Length1 += len(diffText) + Start1 += len(diffText) empty = false patch.diffs = append(patch.diffs, Diff{diffType, diffText}) bigpatch.diffs = bigpatch.diffs[1:] } else { // Deletion or equality. Only take as much as we can stomach. - diffText = diffText[:min(len(diffText), patchSize-patch.length1-dmp.PatchMargin)] + diffText = diffText[:min(len(diffText), patchSize-patch.Length1-dmp.PatchMargin)] - patch.length1 += len(diffText) - start1 += len(diffText) + patch.Length1 += len(diffText) + Start1 += len(diffText) if diffType == DiffEqual { - patch.length2 += len(diffText) - start2 += len(diffText) + patch.Length2 += len(diffText) + Start2 += len(diffText) } else { empty = false } @@ -448,8 +448,8 @@ func (dmp *DiffMatchPatch) PatchSplitMax(patches []Patch) []Patch { } if len(postcontext) != 0 { - patch.length1 += len(postcontext) - patch.length2 += len(postcontext) + patch.Length1 += len(postcontext) + patch.Length2 += len(postcontext) if len(patch.diffs) != 0 && patch.diffs[len(patch.diffs)-1].Type == DiffEqual { patch.diffs[len(patch.diffs)-1].Text += postcontext } else { @@ -496,27 +496,27 @@ func (dmp *DiffMatchPatch) PatchFromText(textline string) ([]Patch, error) { patch = Patch{} m := patchHeader.FindStringSubmatch(text[textPointer]) - patch.start1, _ = strconv.Atoi(m[1]) + patch.Start1, _ = strconv.Atoi(m[1]) if len(m[2]) == 0 { - patch.start1-- - patch.length1 = 1 + patch.Start1-- + patch.Length1 = 1 } else if m[2] == "0" { - patch.length1 = 0 + patch.Length1 = 0 } else { - patch.start1-- - patch.length1, _ = strconv.Atoi(m[2]) + patch.Start1-- + patch.Length1, _ = strconv.Atoi(m[2]) } - patch.start2, _ = strconv.Atoi(m[3]) + patch.Start2, _ = strconv.Atoi(m[3]) if len(m[4]) == 0 { - patch.start2-- - patch.length2 = 1 + patch.Start2-- + patch.Length2 = 1 } else if m[4] == "0" { - patch.length2 = 0 + patch.Length2 = 0 } else { - patch.start2-- - patch.length2, _ = strconv.Atoi(m[4]) + patch.Start2-- + patch.Length2, _ = strconv.Atoi(m[4]) } textPointer++ diff --git a/vendor/github.com/smartystreets/assertions/CONTRIBUTING.md b/vendor/github.com/smartystreets/assertions/CONTRIBUTING.md deleted file mode 100644 index 1820ecb3310..00000000000 --- a/vendor/github.com/smartystreets/assertions/CONTRIBUTING.md +++ /dev/null @@ -1,12 +0,0 @@ -# Contributing - -In general, the code posted to the [SmartyStreets github organization](https://github.com/smartystreets) is created to solve specific problems at SmartyStreets that are ancillary to our core products in the address verification industry and may or may not be useful to other organizations or developers. Our reason for posting said code isn't necessarily to solicit feedback or contributions from the community but more as a showcase of some of the approaches to solving problems we have adopted. - -Having stated that, we do consider issues raised by other githubbers as well as contributions submitted via pull requests. When submitting such a pull request, please follow these guidelines: - -- _Look before you leap:_ If the changes you plan to make are significant, it's in everyone's best interest for you to discuss them with a SmartyStreets team member prior to opening a pull request. -- _License and ownership:_ If modifying the `LICENSE.md` file, limit your changes to fixing typographical mistakes. Do NOT modify the actual terms in the license or the copyright by **SmartyStreets, LLC**. Code submitted to SmartyStreets projects becomes property of SmartyStreets and must be compatible with the associated license. -- _Testing:_ If the code you are submitting resides in packages/modules covered by automated tests, be sure to add passing tests that cover your changes and assert expected behavior and state. Submit the additional test cases as part of your change set. -- _Style:_ Match your approach to **naming** and **formatting** with the surrounding code. Basically, the code you submit shouldn't stand out. - - "Naming" refers to such constructs as variables, methods, functions, classes, structs, interfaces, packages, modules, directories, files, etc... - - "Formatting" refers to such constructs as whitespace, horizontal line length, vertical function length, vertical file length, indentation, curly braces, etc... diff --git a/vendor/github.com/smartystreets/assertions/README.md b/vendor/github.com/smartystreets/assertions/README.md deleted file mode 100644 index 58383bb00af..00000000000 --- a/vendor/github.com/smartystreets/assertions/README.md +++ /dev/null @@ -1,575 +0,0 @@ -# assertions --- - import "github.com/smartystreets/assertions" - -Package assertions contains the implementations for all assertions which are -referenced in goconvey's `convey` package -(github.com/smartystreets/goconvey/convey) and gunit -(github.com/smartystreets/gunit) for use with the So(...) method. They can also -be used in traditional Go test functions and even in applications. - -Many of the assertions lean heavily on work done by Aaron Jacobs in his -excellent oglematchers library. (https://github.com/jacobsa/oglematchers) The -ShouldResemble assertion leans heavily on work done by Daniel Jacques in his -very helpful go-render library. (https://github.com/luci/go-render) - -## Usage - -#### func GoConveyMode - -```go -func GoConveyMode(yes bool) -``` -GoConveyMode provides control over JSON serialization of failures. When using -the assertions in this package from the convey package JSON results are very -helpful and can be rendered in a DIFF view. In that case, this function will be -called with a true value to enable the JSON serialization. By default, the -assertions in this package will not serializer a JSON result, making standalone -ussage more convenient. - -#### func ShouldAlmostEqual - -```go -func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string -``` -ShouldAlmostEqual makes sure that two parameters are close enough to being -equal. The acceptable delta may be specified with a third argument, or a very -small default delta will be used. - -#### func ShouldBeBetween - -```go -func ShouldBeBetween(actual interface{}, expected ...interface{}) string -``` -ShouldBeBetween receives exactly three parameters: an actual value, a lower -bound, and an upper bound. It ensures that the actual value is between both -bounds (but not equal to either of them). - -#### func ShouldBeBetweenOrEqual - -```go -func ShouldBeBetweenOrEqual(actual interface{}, expected ...interface{}) string -``` -ShouldBeBetweenOrEqual receives exactly three parameters: an actual value, a -lower bound, and an upper bound. It ensures that the actual value is between -both bounds or equal to one of them. - -#### func ShouldBeBlank - -```go -func ShouldBeBlank(actual interface{}, expected ...interface{}) string -``` -ShouldBeBlank receives exactly 1 string parameter and ensures that it is equal -to "". - -#### func ShouldBeChronological - -```go -func ShouldBeChronological(actual interface{}, expected ...interface{}) string -``` -ShouldBeChronological receives a []time.Time slice and asserts that the are in -chronological order starting with the first time.Time as the earliest. - -#### func ShouldBeEmpty - -```go -func ShouldBeEmpty(actual interface{}, expected ...interface{}) string -``` -ShouldBeEmpty receives a single parameter (actual) and determines whether or not -calling len(actual) would return `0`. It obeys the rules specified by the len -function for determining length: http://golang.org/pkg/builtin/#len - -#### func ShouldBeFalse - -```go -func ShouldBeFalse(actual interface{}, expected ...interface{}) string -``` -ShouldBeFalse receives a single parameter and ensures that it is false. - -#### func ShouldBeGreaterThan - -```go -func ShouldBeGreaterThan(actual interface{}, expected ...interface{}) string -``` -ShouldBeGreaterThan receives exactly two parameters and ensures that the first -is greater than the second. - -#### func ShouldBeGreaterThanOrEqualTo - -```go -func ShouldBeGreaterThanOrEqualTo(actual interface{}, expected ...interface{}) string -``` -ShouldBeGreaterThanOrEqualTo receives exactly two parameters and ensures that -the first is greater than or equal to the second. - -#### func ShouldBeIn - -```go -func ShouldBeIn(actual interface{}, expected ...interface{}) string -``` -ShouldBeIn receives at least 2 parameters. The first is a proposed member of the -collection that is passed in either as the second parameter, or of the -collection that is comprised of all the remaining parameters. This assertion -ensures that the proposed member is in the collection (using ShouldEqual). - -#### func ShouldBeLessThan - -```go -func ShouldBeLessThan(actual interface{}, expected ...interface{}) string -``` -ShouldBeLessThan receives exactly two parameters and ensures that the first is -less than the second. - -#### func ShouldBeLessThanOrEqualTo - -```go -func ShouldBeLessThanOrEqualTo(actual interface{}, expected ...interface{}) string -``` -ShouldBeLessThan receives exactly two parameters and ensures that the first is -less than or equal to the second. - -#### func ShouldBeNil - -```go -func ShouldBeNil(actual interface{}, expected ...interface{}) string -``` -ShouldBeNil receives a single parameter and ensures that it is nil. - -#### func ShouldBeTrue - -```go -func ShouldBeTrue(actual interface{}, expected ...interface{}) string -``` -ShouldBeTrue receives a single parameter and ensures that it is true. - -#### func ShouldBeZeroValue - -```go -func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string -``` -ShouldBeZeroValue receives a single parameter and ensures that it is the Go -equivalent of the default value, or "zero" value. - -#### func ShouldContain - -```go -func ShouldContain(actual interface{}, expected ...interface{}) string -``` -ShouldContain receives exactly two parameters. The first is a slice and the -second is a proposed member. Membership is determined using ShouldEqual. - -#### func ShouldContainKey - -```go -func ShouldContainKey(actual interface{}, expected ...interface{}) string -``` -ShouldContainKey receives exactly two parameters. The first is a map and the -second is a proposed key. Keys are compared with a simple '=='. - -#### func ShouldContainSubstring - -```go -func ShouldContainSubstring(actual interface{}, expected ...interface{}) string -``` -ShouldContainSubstring receives exactly 2 string parameters and ensures that the -first contains the second as a substring. - -#### func ShouldEndWith - -```go -func ShouldEndWith(actual interface{}, expected ...interface{}) string -``` -ShouldEndWith receives exactly 2 string parameters and ensures that the first -ends with the second. - -#### func ShouldEqual - -```go -func ShouldEqual(actual interface{}, expected ...interface{}) string -``` -ShouldEqual receives exactly two parameters and does an equality check. - -#### func ShouldEqualTrimSpace - -```go -func ShouldEqualTrimSpace(actual interface{}, expected ...interface{}) string -``` -ShouldEqualTrimSpace receives exactly 2 string parameters and ensures that the -first is equal to the second after removing all leading and trailing whitespace -using strings.TrimSpace(first). - -#### func ShouldEqualWithout - -```go -func ShouldEqualWithout(actual interface{}, expected ...interface{}) string -``` -ShouldEqualWithout receives exactly 3 string parameters and ensures that the -first is equal to the second after removing all instances of the third from the -first using strings.Replace(first, third, "", -1). - -#### func ShouldHappenAfter - -```go -func ShouldHappenAfter(actual interface{}, expected ...interface{}) string -``` -ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the -first happens after the second. - -#### func ShouldHappenBefore - -```go -func ShouldHappenBefore(actual interface{}, expected ...interface{}) string -``` -ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the -first happens before the second. - -#### func ShouldHappenBetween - -```go -func ShouldHappenBetween(actual interface{}, expected ...interface{}) string -``` -ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the -first happens between (not on) the second and third. - -#### func ShouldHappenOnOrAfter - -```go -func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string -``` -ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that -the first happens on or after the second. - -#### func ShouldHappenOnOrBefore - -```go -func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string -``` -ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that -the first happens on or before the second. - -#### func ShouldHappenOnOrBetween - -```go -func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string -``` -ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that -the first happens between or on the second and third. - -#### func ShouldHappenWithin - -```go -func ShouldHappenWithin(actual interface{}, expected ...interface{}) string -``` -ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 -arguments) and asserts that the first time.Time happens within or on the -duration specified relative to the other time.Time. - -#### func ShouldHaveLength - -```go -func ShouldHaveLength(actual interface{}, expected ...interface{}) string -``` -ShouldHaveLength receives 2 parameters. The first is a collection to check the -length of, the second being the expected length. It obeys the rules specified by -the len function for determining length: http://golang.org/pkg/builtin/#len - -#### func ShouldHaveSameTypeAs - -```go -func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string -``` -ShouldHaveSameTypeAs receives exactly two parameters and compares their -underlying types for equality. - -#### func ShouldImplement - -```go -func ShouldImplement(actual interface{}, expectedList ...interface{}) string -``` -ShouldImplement receives exactly two parameters and ensures that the first -implements the interface type of the second. - -#### func ShouldNotAlmostEqual - -```go -func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string -``` -ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual - -#### func ShouldNotBeBetween - -```go -func ShouldNotBeBetween(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeBetween receives exactly three parameters: an actual value, a lower -bound, and an upper bound. It ensures that the actual value is NOT between both -bounds. - -#### func ShouldNotBeBetweenOrEqual - -```go -func ShouldNotBeBetweenOrEqual(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeBetweenOrEqual receives exactly three parameters: an actual value, a -lower bound, and an upper bound. It ensures that the actual value is nopt -between the bounds nor equal to either of them. - -#### func ShouldNotBeBlank - -```go -func ShouldNotBeBlank(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeBlank receives exactly 1 string parameter and ensures that it is -equal to "". - -#### func ShouldNotBeEmpty - -```go -func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeEmpty receives a single parameter (actual) and determines whether or -not calling len(actual) would return a value greater than zero. It obeys the -rules specified by the `len` function for determining length: -http://golang.org/pkg/builtin/#len - -#### func ShouldNotBeIn - -```go -func ShouldNotBeIn(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of -the collection that is passed in either as the second parameter, or of the -collection that is comprised of all the remaining parameters. This assertion -ensures that the proposed member is NOT in the collection (using ShouldEqual). - -#### func ShouldNotBeNil - -```go -func ShouldNotBeNil(actual interface{}, expected ...interface{}) string -``` -ShouldNotBeNil receives a single parameter and ensures that it is not nil. - -#### func ShouldNotContain - -```go -func ShouldNotContain(actual interface{}, expected ...interface{}) string -``` -ShouldNotContain receives exactly two parameters. The first is a slice and the -second is a proposed member. Membership is determinied using ShouldEqual. - -#### func ShouldNotContainKey - -```go -func ShouldNotContainKey(actual interface{}, expected ...interface{}) string -``` -ShouldNotContainKey receives exactly two parameters. The first is a map and the -second is a proposed absent key. Keys are compared with a simple '=='. - -#### func ShouldNotContainSubstring - -```go -func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string -``` -ShouldNotContainSubstring receives exactly 2 string parameters and ensures that -the first does NOT contain the second as a substring. - -#### func ShouldNotEndWith - -```go -func ShouldNotEndWith(actual interface{}, expected ...interface{}) string -``` -ShouldEndWith receives exactly 2 string parameters and ensures that the first -does not end with the second. - -#### func ShouldNotEqual - -```go -func ShouldNotEqual(actual interface{}, expected ...interface{}) string -``` -ShouldNotEqual receives exactly two parameters and does an inequality check. - -#### func ShouldNotHappenOnOrBetween - -```go -func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string -``` -ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts -that the first does NOT happen between or on the second or third. - -#### func ShouldNotHappenWithin - -```go -func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string -``` -ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 -arguments) and asserts that the first time.Time does NOT happen within or on the -duration specified relative to the other time.Time. - -#### func ShouldNotHaveSameTypeAs - -```go -func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string -``` -ShouldNotHaveSameTypeAs receives exactly two parameters and compares their -underlying types for inequality. - -#### func ShouldNotImplement - -```go -func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string -``` -ShouldNotImplement receives exactly two parameters and ensures that the first -does NOT implement the interface type of the second. - -#### func ShouldNotPanic - -```go -func ShouldNotPanic(actual interface{}, expected ...interface{}) (message string) -``` -ShouldNotPanic receives a void, niladic function and expects to execute the -function without any panic. - -#### func ShouldNotPanicWith - -```go -func ShouldNotPanicWith(actual interface{}, expected ...interface{}) (message string) -``` -ShouldNotPanicWith receives a void, niladic function and expects to recover a -panic whose content differs from the second argument. - -#### func ShouldNotPointTo - -```go -func ShouldNotPointTo(actual interface{}, expected ...interface{}) string -``` -ShouldNotPointTo receives exactly two parameters and checks to see that they -point to different addresess. - -#### func ShouldNotResemble - -```go -func ShouldNotResemble(actual interface{}, expected ...interface{}) string -``` -ShouldNotResemble receives exactly two parameters and does an inverse deep equal -check (see reflect.DeepEqual) - -#### func ShouldNotStartWith - -```go -func ShouldNotStartWith(actual interface{}, expected ...interface{}) string -``` -ShouldNotStartWith receives exactly 2 string parameters and ensures that the -first does not start with the second. - -#### func ShouldPanic - -```go -func ShouldPanic(actual interface{}, expected ...interface{}) (message string) -``` -ShouldPanic receives a void, niladic function and expects to recover a panic. - -#### func ShouldPanicWith - -```go -func ShouldPanicWith(actual interface{}, expected ...interface{}) (message string) -``` -ShouldPanicWith receives a void, niladic function and expects to recover a panic -with the second argument as the content. - -#### func ShouldPointTo - -```go -func ShouldPointTo(actual interface{}, expected ...interface{}) string -``` -ShouldPointTo receives exactly two parameters and checks to see that they point -to the same address. - -#### func ShouldResemble - -```go -func ShouldResemble(actual interface{}, expected ...interface{}) string -``` -ShouldResemble receives exactly two parameters and does a deep equal check (see -reflect.DeepEqual) - -#### func ShouldStartWith - -```go -func ShouldStartWith(actual interface{}, expected ...interface{}) string -``` -ShouldStartWith receives exactly 2 string parameters and ensures that the first -starts with the second. - -#### func So - -```go -func So(actual interface{}, assert assertion, expected ...interface{}) (bool, string) -``` -So is a convenience function (as opposed to an inconvenience function?) for -running assertions on arbitrary arguments in any context, be it for testing or -even application logging. It allows you to perform assertion-like behavior (and -get nicely formatted messages detailing discrepancies) but without the program -blowing up or panicking. All that is required is to import this package and call -`So` with one of the assertions exported by this package as the second -parameter. The first return parameter is a boolean indicating if the assertion -was true. The second return parameter is the well-formatted message showing why -an assertion was incorrect, or blank if the assertion was correct. - -Example: - - if ok, message := So(x, ShouldBeGreaterThan, y); !ok { - log.Println(message) - } - -#### type Assertion - -```go -type Assertion struct { -} -``` - - -#### func New - -```go -func New(t testingT) *Assertion -``` -New swallows the *testing.T struct and prints failed assertions using t.Error. -Example: assertions.New(t).So(1, should.Equal, 1) - -#### func (*Assertion) Failed - -```go -func (this *Assertion) Failed() bool -``` -Failed reports whether any calls to So (on this Assertion instance) have failed. - -#### func (*Assertion) So - -```go -func (this *Assertion) So(actual interface{}, assert assertion, expected ...interface{}) bool -``` -So calls the standalone So function and additionally, calls t.Error in failure -scenarios. - -#### type FailureView - -```go -type FailureView struct { - Message string `json:"Message"` - Expected string `json:"Expected"` - Actual string `json:"Actual"` -} -``` - -This struct is also declared in -github.com/smartystreets/goconvey/convey/reporting. The json struct tags should -be equal in both declarations. - -#### type Serializer - -```go -type Serializer interface { - // contains filtered or unexported methods -} -``` diff --git a/vendor/github.com/smartystreets/assertions/assertions.goconvey b/vendor/github.com/smartystreets/assertions/assertions.goconvey deleted file mode 100644 index e76cf275d47..00000000000 --- a/vendor/github.com/smartystreets/assertions/assertions.goconvey +++ /dev/null @@ -1,3 +0,0 @@ -#ignore --timeout=1s --coverpkg=github.com/smartystreets/assertions,github.com/smartystreets/assertions/internal/oglematchers \ No newline at end of file diff --git a/vendor/github.com/smartystreets/assertions/doc.go b/vendor/github.com/smartystreets/assertions/doc.go index 5720fc298c6..50572325373 100644 --- a/vendor/github.com/smartystreets/assertions/doc.go +++ b/vendor/github.com/smartystreets/assertions/doc.go @@ -26,7 +26,7 @@ var serializer Serializer = new(noopSerializer) // are very helpful and can be rendered in a DIFF view. In that case, this function // will be called with a true value to enable the JSON serialization. By default, // the assertions in this package will not serializer a JSON result, making -// standalone ussage more convenient. +// standalone usage more convenient. func GoConveyMode(yes bool) { if yes { serializer = newSerializer() @@ -82,6 +82,8 @@ func (this *Assertion) So(actual interface{}, assert assertion, expected ...inte // log.Println(message) // } // +// For an alternative implementation of So (that provides more flexible return options) +// see the `So` function in the package at github.com/smartystreets/assertions/assert. func So(actual interface{}, assert assertion, expected ...interface{}) (bool, string) { if result := so(actual, assert, expected...); len(result) == 0 { return true, result diff --git a/vendor/github.com/smartystreets/assertions/equal_method.go b/vendor/github.com/smartystreets/assertions/equal_method.go new file mode 100644 index 00000000000..c4fc38fab5e --- /dev/null +++ b/vendor/github.com/smartystreets/assertions/equal_method.go @@ -0,0 +1,75 @@ +package assertions + +import "reflect" + +type equalityMethodSpecification struct { + a interface{} + b interface{} + + aType reflect.Type + bType reflect.Type + + equalMethod reflect.Value +} + +func newEqualityMethodSpecification(a, b interface{}) *equalityMethodSpecification { + return &equalityMethodSpecification{ + a: a, + b: b, + } +} + +func (this *equalityMethodSpecification) IsSatisfied() bool { + if !this.bothAreSameType() { + return false + } + if !this.typeHasEqualMethod() { + return false + } + if !this.equalMethodReceivesSameTypeForComparison() { + return false + } + if !this.equalMethodReturnsBool() { + return false + } + return true +} + +func (this *equalityMethodSpecification) bothAreSameType() bool { + this.aType = reflect.TypeOf(this.a) + if this.aType == nil { + return false + } + if this.aType.Kind() == reflect.Ptr { + this.aType = this.aType.Elem() + } + this.bType = reflect.TypeOf(this.b) + return this.aType == this.bType +} +func (this *equalityMethodSpecification) typeHasEqualMethod() bool { + aInstance := reflect.ValueOf(this.a) + this.equalMethod = aInstance.MethodByName("Equal") + return this.equalMethod != reflect.Value{} +} + +func (this *equalityMethodSpecification) equalMethodReceivesSameTypeForComparison() bool { + signature := this.equalMethod.Type() + return signature.NumIn() == 1 && signature.In(0) == this.aType +} + +func (this *equalityMethodSpecification) equalMethodReturnsBool() bool { + signature := this.equalMethod.Type() + return signature.NumOut() == 1 && signature.Out(0) == reflect.TypeOf(true) +} + +func (this *equalityMethodSpecification) AreEqual() bool { + a := reflect.ValueOf(this.a) + b := reflect.ValueOf(this.b) + return areEqual(a, b) && areEqual(b, a) +} +func areEqual(receiver reflect.Value, argument reflect.Value) bool { + equalMethod := receiver.MethodByName("Equal") + argumentList := []reflect.Value{argument} + result := equalMethod.Call(argumentList) + return result[0].Bool() +} diff --git a/vendor/github.com/smartystreets/assertions/equality.go b/vendor/github.com/smartystreets/assertions/equality.go index 2b6049c37d9..0a4b1f3dd03 100644 --- a/vendor/github.com/smartystreets/assertions/equality.go +++ b/vendor/github.com/smartystreets/assertions/equality.go @@ -7,14 +7,15 @@ import ( "reflect" "strings" - "github.com/smartystreets/assertions/internal/oglematchers" "github.com/smartystreets/assertions/internal/go-render/render" + "github.com/smartystreets/assertions/internal/oglematchers" ) -// default acceptable delta for ShouldAlmostEqual -const defaultDelta = 0.0000000001 - -// ShouldEqual receives exactly two parameters and does an equality check. +// ShouldEqual receives exactly two parameters and does an equality check +// using the following semantics: +// 1. If the expected and actual values implement an Equal method in the form +// `func (this T) Equal(that T) bool` then call the method. If true, they are equal. +// 2. The expected and actual values are judged equal or not by oglematchers.Equals. func ShouldEqual(actual interface{}, expected ...interface{}) string { if message := need(1, expected); message != success { return message @@ -25,10 +26,17 @@ func shouldEqual(actual, expected interface{}) (message string) { defer func() { if r := recover(); r != nil { message = serializer.serialize(expected, actual, fmt.Sprintf(shouldHaveBeenEqual, expected, actual)) - return } }() + if specification := newEqualityMethodSpecification(expected, actual); specification.IsSatisfied() { + if specification.AreEqual() { + return success + } else { + message = fmt.Sprintf(shouldHaveBeenEqual, expected, actual) + return serializer.serialize(expected, actual, message) + } + } if matchError := oglematchers.Equals(expected).Matches(actual); matchError != nil { expectedSyntax := fmt.Sprintf("%v", expected) actualSyntax := fmt.Sprintf("%v", actual) @@ -37,14 +45,14 @@ func shouldEqual(actual, expected interface{}) (message string) { } else { message = fmt.Sprintf(shouldHaveBeenEqual, expected, actual) } - message = serializer.serialize(expected, actual, message) - return + return serializer.serialize(expected, actual, message) } return success } // ShouldNotEqual receives exactly two parameters and does an inequality check. +// See ShouldEqual for details on how equality is determined. func ShouldNotEqual(actual interface{}, expected ...interface{}) string { if fail := need(1, expected); fail != success { return fail @@ -95,7 +103,7 @@ func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64 delta, err := getFloat(expected[1]) if err != nil { - return 0.0, 0.0, 0.0, "delta must be a numerical type" + return 0.0, 0.0, 0.0, "The delta value " + err.Error() } deltaFloat = delta @@ -104,15 +112,13 @@ func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64 } actualFloat, err := getFloat(actual) - if err != nil { - return 0.0, 0.0, 0.0, err.Error() + return 0.0, 0.0, 0.0, "The actual value " + err.Error() } expectedFloat, err := getFloat(expected[0]) - if err != nil { - return 0.0, 0.0, 0.0, err.Error() + return 0.0, 0.0, 0.0, "The comparison value " + err.Error() } return actualFloat, expectedFloat, deltaFloat, "" @@ -139,7 +145,7 @@ func getFloat(num interface{}) (float64, error) { numKind == reflect.Float64 { return numValue.Float(), nil } else { - return 0.0, errors.New("must be a numerical type, but was " + numKind.String()) + return 0.0, errors.New("must be a numerical type, but was: " + numKind.String()) } } diff --git a/vendor/github.com/smartystreets/assertions/filter.go b/vendor/github.com/smartystreets/assertions/filter.go index ee368a97ed7..7c46ab8e35c 100644 --- a/vendor/github.com/smartystreets/assertions/filter.go +++ b/vendor/github.com/smartystreets/assertions/filter.go @@ -6,6 +6,7 @@ const ( success = "" needExactValues = "This assertion requires exactly %d comparison values (you provided %d)." needNonEmptyCollection = "This assertion requires at least 1 comparison value (you provided 0)." + needFewerValues = "This assertion allows %d or fewer comparison values (you provided %d)." ) func need(needed int, expected []interface{}) string { @@ -21,3 +22,10 @@ func atLeast(minimum int, expected []interface{}) string { } return success } + +func atMost(max int, expected []interface{}) string { + if len(expected) > max { + return fmt.Sprintf(needFewerValues, max, len(expected)) + } + return success +} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md b/vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md deleted file mode 100644 index 215a2bb7a8b..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/README.md +++ /dev/null @@ -1,58 +0,0 @@ -[![GoDoc](https://godoc.org/github.com/smartystreets/assertions/internal/oglematchers?status.svg)](https://godoc.org/github.com/smartystreets/assertions/internal/oglematchers) - -`oglematchers` is a package for the Go programming language containing a set of -matchers, useful in a testing or mocking framework, inspired by and mostly -compatible with [Google Test][googletest] for C++ and -[Google JS Test][google-js-test]. The package is used by the -[ogletest][ogletest] testing framework and [oglemock][oglemock] mocking -framework, which may be more directly useful to you, but can be generically used -elsewhere as well. - -A "matcher" is simply an object with a `Matches` method defining a set of golang -values matched by the matcher, and a `Description` method describing that set. -For example, here are some matchers: - -```go -// Numbers -Equals(17.13) -LessThan(19) - -// Strings -Equals("taco") -HasSubstr("burrito") -MatchesRegex("t.*o") - -// Combining matchers -AnyOf(LessThan(17), GreaterThan(19)) -``` - -There are lots more; see [here][reference] for a reference. You can also add -your own simply by implementing the `oglematchers.Matcher` interface. - - -Installation ------------- - -First, make sure you have installed Go 1.0.2 or newer. See -[here][golang-install] for instructions. - -Use the following command to install `oglematchers` and keep it up to date: - - go get -u github.com/smartystreets/assertions/internal/oglematchers - - -Documentation -------------- - -See [here][reference] for documentation. Alternatively, you can install the -package and then use `godoc`: - - godoc github.com/smartystreets/assertions/internal/oglematchers - - -[reference]: http://godoc.org/github.com/smartystreets/assertions/internal/oglematchers -[golang-install]: http://golang.org/doc/install.html -[googletest]: http://code.google.com/p/googletest/ -[google-js-test]: http://code.google.com/p/google-js-test/ -[ogletest]: http://github.com/smartystreets/assertions/internal/ogletest -[oglemock]: http://github.com/smartystreets/assertions/internal/oglemock diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go deleted file mode 100644 index d93a9740443..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/all_of.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "strings" -) - -// AllOf accepts a set of matchers S and returns a matcher that follows the -// algorithm below when considering a candidate c: -// -// 1. Return true if for every Matcher m in S, m matches c. -// -// 2. Otherwise, if there is a matcher m in S such that m returns a fatal -// error for c, return that matcher's error message. -// -// 3. Otherwise, return false with the error from some wrapped matcher. -// -// This is akin to a logical AND operation for matchers. -func AllOf(matchers ...Matcher) Matcher { - return &allOfMatcher{matchers} -} - -type allOfMatcher struct { - wrappedMatchers []Matcher -} - -func (m *allOfMatcher) Description() string { - // Special case: the empty set. - if len(m.wrappedMatchers) == 0 { - return "is anything" - } - - // Join the descriptions for the wrapped matchers. - wrappedDescs := make([]string, len(m.wrappedMatchers)) - for i, wrappedMatcher := range m.wrappedMatchers { - wrappedDescs[i] = wrappedMatcher.Description() - } - - return strings.Join(wrappedDescs, ", and ") -} - -func (m *allOfMatcher) Matches(c interface{}) (err error) { - for _, wrappedMatcher := range m.wrappedMatchers { - if wrappedErr := wrappedMatcher.Matches(c); wrappedErr != nil { - err = wrappedErr - - // If the error is fatal, return immediately with this error. - _, ok := wrappedErr.(*FatalError) - if ok { - return - } - } - } - - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go deleted file mode 100644 index f6991ec1020..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/any.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -// Any returns a matcher that matches any value. -func Any() Matcher { - return &anyMatcher{} -} - -type anyMatcher struct { -} - -func (m *anyMatcher) Description() string { - return "is anything" -} - -func (m *anyMatcher) Matches(c interface{}) error { - return nil -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go deleted file mode 100644 index 2941847c705..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/elements_are.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -// Given a list of arguments M, ElementsAre returns a matcher that matches -// arrays and slices A where all of the following hold: -// -// * A is the same length as M. -// -// * For each i < len(A) where M[i] is a matcher, A[i] matches M[i]. -// -// * For each i < len(A) where M[i] is not a matcher, A[i] matches -// Equals(M[i]). -// -func ElementsAre(M ...interface{}) Matcher { - // Copy over matchers, or convert to Equals(x) for non-matcher x. - subMatchers := make([]Matcher, len(M)) - for i, x := range M { - if matcher, ok := x.(Matcher); ok { - subMatchers[i] = matcher - continue - } - - subMatchers[i] = Equals(x) - } - - return &elementsAreMatcher{subMatchers} -} - -type elementsAreMatcher struct { - subMatchers []Matcher -} - -func (m *elementsAreMatcher) Description() string { - subDescs := make([]string, len(m.subMatchers)) - for i, sm := range m.subMatchers { - subDescs[i] = sm.Description() - } - - return fmt.Sprintf("elements are: [%s]", strings.Join(subDescs, ", ")) -} - -func (m *elementsAreMatcher) Matches(candidates interface{}) error { - // The candidate must be a slice or an array. - v := reflect.ValueOf(candidates) - if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { - return NewFatalError("which is not a slice or array") - } - - // The length must be correct. - if v.Len() != len(m.subMatchers) { - return errors.New(fmt.Sprintf("which is of length %d", v.Len())) - } - - // Check each element. - for i, subMatcher := range m.subMatchers { - c := v.Index(i) - if matchErr := subMatcher.Matches(c.Interface()); matchErr != nil { - // Return an errors indicating which element doesn't match. If the - // matcher error was fatal, make this one fatal too. - err := errors.New(fmt.Sprintf("whose element %d doesn't match", i)) - if _, isFatal := matchErr.(*FatalError); isFatal { - err = NewFatalError(err.Error()) - } - - return err - } - } - - return nil -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go deleted file mode 100644 index 8a078e36d86..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/error.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -// Error returns a matcher that matches non-nil values implementing the -// built-in error interface for whom the return value of Error() matches the -// supplied matcher. -// -// For example: -// -// err := errors.New("taco burrito") -// -// Error(Equals("taco burrito")) // matches err -// Error(HasSubstr("taco")) // matches err -// Error(HasSubstr("enchilada")) // doesn't match err -// -func Error(m Matcher) Matcher { - return &errorMatcher{m} -} - -type errorMatcher struct { - wrappedMatcher Matcher -} - -func (m *errorMatcher) Description() string { - return "error " + m.wrappedMatcher.Description() -} - -func (m *errorMatcher) Matches(c interface{}) error { - // Make sure that c is an error. - e, ok := c.(error) - if !ok { - return NewFatalError("which is not an error") - } - - // Pass on the error text to the wrapped matcher. - return m.wrappedMatcher.Matches(e.Error()) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go deleted file mode 100644 index 3b286f73218..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_same_type_as.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "fmt" - "reflect" -) - -// HasSameTypeAs returns a matcher that matches values with exactly the same -// type as the supplied prototype. -func HasSameTypeAs(p interface{}) Matcher { - expected := reflect.TypeOf(p) - pred := func(c interface{}) error { - actual := reflect.TypeOf(c) - if actual != expected { - return fmt.Errorf("which has type %v", actual) - } - - return nil - } - - return NewMatcher(pred, fmt.Sprintf("has type %v", expected)) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go deleted file mode 100644 index bf5bd6ae6d3..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/has_substr.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -// HasSubstr returns a matcher that matches strings containing s as a -// substring. -func HasSubstr(s string) Matcher { - return NewMatcher( - func(c interface{}) error { return hasSubstr(s, c) }, - fmt.Sprintf("has substring \"%s\"", s)) -} - -func hasSubstr(needle string, c interface{}) error { - v := reflect.ValueOf(c) - if v.Kind() != reflect.String { - return NewFatalError("which is not a string") - } - - // Perform the substring search. - haystack := v.String() - if strings.Contains(haystack, needle) { - return nil - } - - return errors.New("") -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go deleted file mode 100644 index ae6460ed966..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/identical_to.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "errors" - "fmt" - "reflect" -) - -// Is the type comparable according to the definition here? -// -// http://weekly.golang.org/doc/go_spec.html#Comparison_operators -// -func isComparable(t reflect.Type) bool { - switch t.Kind() { - case reflect.Array: - return isComparable(t.Elem()) - - case reflect.Struct: - for i := 0; i < t.NumField(); i++ { - if !isComparable(t.Field(i).Type) { - return false - } - } - - return true - - case reflect.Slice, reflect.Map, reflect.Func: - return false - } - - return true -} - -// Should the supplied type be allowed as an argument to IdenticalTo? -func isLegalForIdenticalTo(t reflect.Type) (bool, error) { - // Allow the zero type. - if t == nil { - return true, nil - } - - // Reference types are always okay; we compare pointers. - switch t.Kind() { - case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: - return true, nil - } - - // Reject other non-comparable types. - if !isComparable(t) { - return false, errors.New(fmt.Sprintf("%v is not comparable", t)) - } - - return true, nil -} - -// IdenticalTo(x) returns a matcher that matches values v with type identical -// to x such that: -// -// 1. If v and x are of a reference type (slice, map, function, channel), then -// they are either both nil or are references to the same object. -// -// 2. Otherwise, if v and x are not of a reference type but have a valid type, -// then v == x. -// -// If v and x are both the invalid type (which results from the predeclared nil -// value, or from nil interface variables), then the matcher is satisfied. -// -// This function will panic if x is of a value type that is not comparable. For -// example, x cannot be an array of functions. -func IdenticalTo(x interface{}) Matcher { - t := reflect.TypeOf(x) - - // Reject illegal arguments. - if ok, err := isLegalForIdenticalTo(t); !ok { - panic("IdenticalTo: " + err.Error()) - } - - return &identicalToMatcher{x} -} - -type identicalToMatcher struct { - x interface{} -} - -func (m *identicalToMatcher) Description() string { - t := reflect.TypeOf(m.x) - return fmt.Sprintf("identical to <%v> %v", t, m.x) -} - -func (m *identicalToMatcher) Matches(c interface{}) error { - // Make sure the candidate's type is correct. - t := reflect.TypeOf(m.x) - if ct := reflect.TypeOf(c); t != ct { - return NewFatalError(fmt.Sprintf("which is of type %v", ct)) - } - - // Special case: two values of the invalid type are always identical. - if t == nil { - return nil - } - - // Handle reference types. - switch t.Kind() { - case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: - xv := reflect.ValueOf(m.x) - cv := reflect.ValueOf(c) - if xv.Pointer() == cv.Pointer() { - return nil - } - - return errors.New("which is not an identical reference") - } - - // Are the values equal? - if m.x == c { - return nil - } - - return errors.New("") -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go deleted file mode 100644 index 1ed63f30c4e..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/matches_regexp.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "errors" - "fmt" - "reflect" - "regexp" -) - -// MatchesRegexp returns a matcher that matches strings and byte slices whose -// contents match the supplied regular expression. The semantics are those of -// regexp.Match. In particular, that means the match is not implicitly anchored -// to the ends of the string: MatchesRegexp("bar") will match "foo bar baz". -func MatchesRegexp(pattern string) Matcher { - re, err := regexp.Compile(pattern) - if err != nil { - panic("MatchesRegexp: " + err.Error()) - } - - return &matchesRegexpMatcher{re} -} - -type matchesRegexpMatcher struct { - re *regexp.Regexp -} - -func (m *matchesRegexpMatcher) Description() string { - return fmt.Sprintf("matches regexp \"%s\"", m.re.String()) -} - -func (m *matchesRegexpMatcher) Matches(c interface{}) (err error) { - v := reflect.ValueOf(c) - isString := v.Kind() == reflect.String - isByteSlice := v.Kind() == reflect.Slice && v.Elem().Kind() == reflect.Uint8 - - err = errors.New("") - - switch { - case isString: - if m.re.MatchString(v.String()) { - err = nil - } - - case isByteSlice: - if m.re.Match(v.Bytes()) { - err = nil - } - - default: - err = NewFatalError("which is not a string or []byte") - } - - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go deleted file mode 100644 index c9d8398ee63..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/new_matcher.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -// Create a matcher with the given description and predicate function, which -// will be invoked to handle calls to Matchers. -// -// Using this constructor may be a convenience over defining your own type that -// implements Matcher if you do not need any logic in your Description method. -func NewMatcher( - predicate func(interface{}) error, - description string) Matcher { - return &predicateMatcher{ - predicate: predicate, - description: description, - } -} - -type predicateMatcher struct { - predicate func(interface{}) error - description string -} - -func (pm *predicateMatcher) Matches(c interface{}) error { - return pm.predicate(c) -} - -func (pm *predicateMatcher) Description() string { - return pm.description -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go deleted file mode 100644 index d2cfc97869b..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/panics.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2011 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "errors" - "fmt" - "reflect" -) - -// Panics matches zero-arg functions which, when invoked, panic with an error -// that matches the supplied matcher. -// -// NOTE(jacobsa): This matcher cannot detect the case where the function panics -// using panic(nil), by design of the language. See here for more info: -// -// http://goo.gl/9aIQL -// -func Panics(m Matcher) Matcher { - return &panicsMatcher{m} -} - -type panicsMatcher struct { - wrappedMatcher Matcher -} - -func (m *panicsMatcher) Description() string { - return "panics with: " + m.wrappedMatcher.Description() -} - -func (m *panicsMatcher) Matches(c interface{}) (err error) { - // Make sure c is a zero-arg function. - v := reflect.ValueOf(c) - if v.Kind() != reflect.Func || v.Type().NumIn() != 0 { - err = NewFatalError("which is not a zero-arg function") - return - } - - // Call the function and check its panic error. - defer func() { - if e := recover(); e != nil { - err = m.wrappedMatcher.Matches(e) - - // Set a clearer error message if the matcher said no. - if err != nil { - wrappedClause := "" - if err.Error() != "" { - wrappedClause = ", " + err.Error() - } - - err = errors.New(fmt.Sprintf("which panicked with: %v%s", e, wrappedClause)) - } - } - }() - - v.Call([]reflect.Value{}) - - // If we get here, the function didn't panic. - err = errors.New("which didn't panic") - return -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go deleted file mode 100644 index c5383f2402f..00000000000 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/pointee.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2012 Aaron Jacobs. All Rights Reserved. -// Author: aaronjjacobs@gmail.com (Aaron Jacobs) -// -// 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 oglematchers - -import ( - "errors" - "fmt" - "reflect" -) - -// Return a matcher that matches non-nil pointers whose pointee matches the -// wrapped matcher. -func Pointee(m Matcher) Matcher { - return &pointeeMatcher{m} -} - -type pointeeMatcher struct { - wrapped Matcher -} - -func (m *pointeeMatcher) Matches(c interface{}) (err error) { - // Make sure the candidate is of the appropriate type. - cv := reflect.ValueOf(c) - if !cv.IsValid() || cv.Kind() != reflect.Ptr { - return NewFatalError("which is not a pointer") - } - - // Make sure the candidate is non-nil. - if cv.IsNil() { - return NewFatalError("") - } - - // Defer to the wrapped matcher. Fix up empty errors so that failure messages - // are more helpful than just printing a pointer for "Actual". - pointee := cv.Elem().Interface() - err = m.wrapped.Matches(pointee) - if err != nil && err.Error() == "" { - s := fmt.Sprintf("whose pointee is %v", pointee) - - if _, ok := err.(*FatalError); ok { - err = NewFatalError(s) - } else { - err = errors.New(s) - } - } - - return err -} - -func (m *pointeeMatcher) Description() string { - return fmt.Sprintf("pointee(%s)", m.wrapped.Description()) -} diff --git a/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go b/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go index f79d0c03db1..8ea2807c6f4 100644 --- a/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go +++ b/vendor/github.com/smartystreets/assertions/internal/oglematchers/transform_description.go @@ -23,7 +23,7 @@ func transformDescription(m Matcher, newDesc string) Matcher { } type transformDescriptionMatcher struct { - desc string + desc string wrappedMatcher Matcher } diff --git a/vendor/github.com/smartystreets/assertions/messages.go b/vendor/github.com/smartystreets/assertions/messages.go index 9c57ab2b8b9..2756fb0ec3d 100644 --- a/vendor/github.com/smartystreets/assertions/messages.go +++ b/vendor/github.com/smartystreets/assertions/messages.go @@ -77,6 +77,9 @@ const ( // type checking shouldNotHaveImplemented = "Expected '%v'\nto NOT implement '%v'\n(but it did)!" shouldCompareWithInterfacePointer = "The expected value must be a pointer to an interface type (eg. *fmt.Stringer)" shouldNotBeNilActual = "The actual value was 'nil' and should be a value or a pointer to a value!" + + shouldBeError = "Expected an error value (but was '%v' instead)!" + shouldBeErrorInvalidComparisonValue = "The final argument to this assertion must be a string or an error value (you provided: '%v')." ) const ( // time comparisons diff --git a/vendor/github.com/smartystreets/assertions/serializer.go b/vendor/github.com/smartystreets/assertions/serializer.go index 90ae3e3b692..fa32f9403fa 100644 --- a/vendor/github.com/smartystreets/assertions/serializer.go +++ b/vendor/github.com/smartystreets/assertions/serializer.go @@ -20,10 +20,7 @@ func (self *failureSerializer) serializeDetailed(expected, actual interface{}, m Expected: render.Render(expected), Actual: render.Render(actual), } - serialized, err := json.Marshal(view) - if err != nil { - return message - } + serialized, _ := json.Marshal(view) return string(serialized) } @@ -33,10 +30,7 @@ func (self *failureSerializer) serialize(expected, actual interface{}, message s Expected: fmt.Sprintf("%+v", expected), Actual: fmt.Sprintf("%+v", actual), } - serialized, err := json.Marshal(view) - if err != nil { - return message - } + serialized, _ := json.Marshal(view) return string(serialized) } @@ -57,8 +51,8 @@ type FailureView struct { /////////////////////////////////////////////////////// // noopSerializer just gives back the original message. This is useful when we are using -// the assertions from a context other than the web UI, that requires the JSON structure -// provided by the failureSerializer. +// the assertions from a context other than the GoConvey Web UI, that requires the JSON +// structure provided by the failureSerializer. type noopSerializer struct{} func (self *noopSerializer) serialize(expected, actual interface{}, message string) string { diff --git a/vendor/github.com/smartystreets/assertions/type.go b/vendor/github.com/smartystreets/assertions/type.go index 3fc00f68cd0..d2d1dc864b2 100644 --- a/vendor/github.com/smartystreets/assertions/type.go +++ b/vendor/github.com/smartystreets/assertions/type.go @@ -14,9 +14,10 @@ func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string { first := reflect.TypeOf(actual) second := reflect.TypeOf(expected[0]) - if equal := ShouldEqual(first, second); equal != success { + if first != second { return serializer.serialize(second, first, fmt.Sprintf(shouldHaveBeenA, actual, second, first)) } + return success } @@ -29,7 +30,7 @@ func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string first := reflect.TypeOf(actual) second := reflect.TypeOf(expected[0]) - if equal := ShouldEqual(first, second); equal == success { + if (actual == nil && expected[0] == nil) || first == second { return fmt.Sprintf(shouldNotHaveBeenA, actual, second) } return success @@ -65,10 +66,6 @@ func ShouldImplement(actual interface{}, expectedList ...interface{}) string { expectedInterface := expectedType.Elem() - if actualType == nil { - return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actual) - } - if !actualType.Implements(expectedInterface) { return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actualType) } @@ -110,3 +107,28 @@ func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string } return success } + +// ShouldBeError asserts that the first argument implements the error interface. +// It also compares the first argument against the second argument if provided +// (which must be an error message string or another error value). +func ShouldBeError(actual interface{}, expected ...interface{}) string { + if fail := atMost(1, expected); fail != success { + return fail + } + + if !isError(actual) { + return fmt.Sprintf(shouldBeError, reflect.TypeOf(actual)) + } + + if len(expected) == 0 { + return success + } + + if expected := expected[0]; !isString(expected) && !isError(expected) { + return fmt.Sprintf(shouldBeErrorInvalidComparisonValue, reflect.TypeOf(expected)) + } + return ShouldEqual(fmt.Sprint(actual), fmt.Sprint(expected[0])) +} + +func isString(value interface{}) bool { _, ok := value.(string); return ok } +func isError(value interface{}) bool { _, ok := value.(error); return ok } diff --git a/vendor/github.com/smartystreets/goconvey/convey/assertions.go b/vendor/github.com/smartystreets/goconvey/convey/assertions.go index 1e87b826dff..b37f6b43a65 100644 --- a/vendor/github.com/smartystreets/goconvey/convey/assertions.go +++ b/vendor/github.com/smartystreets/goconvey/convey/assertions.go @@ -65,4 +65,6 @@ var ( ShouldHappenWithin = assertions.ShouldHappenWithin ShouldNotHappenWithin = assertions.ShouldNotHappenWithin ShouldBeChronological = assertions.ShouldBeChronological + + ShouldBeError = assertions.ShouldBeError ) diff --git a/vendor/github.com/smartystreets/goconvey/convey/convey.goconvey b/vendor/github.com/smartystreets/goconvey/convey/convey.goconvey deleted file mode 100644 index a2d9327dc91..00000000000 --- a/vendor/github.com/smartystreets/goconvey/convey/convey.goconvey +++ /dev/null @@ -1,4 +0,0 @@ -#ignore --timeout=1s -#-covermode=count -#-coverpkg=github.com/smartystreets/goconvey/convey,github.com/smartystreets/goconvey/convey/gotest,github.com/smartystreets/goconvey/convey/reporting \ No newline at end of file diff --git a/vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey b/vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey deleted file mode 100644 index 79982854b53..00000000000 --- a/vendor/github.com/smartystreets/goconvey/convey/reporting/reporting.goconvey +++ /dev/null @@ -1,2 +0,0 @@ -#ignore --timeout=1s diff --git a/vendor/github.com/smartystreets/goconvey/web/client/resources/fonts/Open_Sans/LICENSE.txt b/vendor/github.com/smartystreets/goconvey/web/client/resources/fonts/Open_Sans/LICENSE.txt new file mode 100755 index 00000000000..75b52484ea4 --- /dev/null +++ b/vendor/github.com/smartystreets/goconvey/web/client/resources/fonts/Open_Sans/LICENSE.txt @@ -0,0 +1,202 @@ + + 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. diff --git a/vendor/github.com/teris-io/shortid/LICENSE b/vendor/github.com/teris-io/shortid/LICENSE new file mode 100644 index 00000000000..fc737ef1ce8 --- /dev/null +++ b/vendor/github.com/teris-io/shortid/LICENSE @@ -0,0 +1,18 @@ +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/teris-io/shortid/shortid.go b/vendor/github.com/teris-io/shortid/shortid.go new file mode 100644 index 00000000000..c9461c29168 --- /dev/null +++ b/vendor/github.com/teris-io/shortid/shortid.go @@ -0,0 +1,362 @@ +// Copyright (c) 2016-2017. Oleg Sklyar & teris.io. All rights reserved. +// See the LICENSE file in the project root for licensing information. + +// Original algorithm: +// Copyright (c) 2015 Dylan Greene, contributors: https://github.com/dylang/shortid. +// MIT-license as found in the LICENSE file. + +// Seed computation: based on The Central Randomizer 1.3 +// Copyright (c) 1997 Paul Houle (houle@msc.cornell.edu) + +// Package shortid enables the generation of short, unique, non-sequential and by default URL friendly +// Ids. The package is heavily inspired by the node.js https://github.com/dylang/shortid library. +// +// Id Length +// +// The standard Id length is 9 symbols when generated at a rate of 1 Id per millisecond, +// occasionally it reaches 11 (at the rate of a few thousand Ids per millisecond) and very-very +// rarely it can go beyond that during continuous generation at full throttle on high-performant +// hardware. A test generating 500k Ids at full throttle on conventional hardware generated the +// following Ids at the head and the tail (length > 9 is expected for this test): +// +// -NDveu-9Q +// iNove6iQ9J +// NVDve6-9Q +// VVDvc6i99J +// NVovc6-QQy +// VVoveui9QC +// ... +// tFmGc6iQQs +// KpTvcui99k +// KFTGcuiQ9p +// KFmGeu-Q9O +// tFTvcu-QQt +// tpTveu-99u +// +// Life span +// +// The package guarantees the generation of unique Ids with zero collisions for 34 years +// (1/1/2016-1/1/2050) using the same worker Id within a single (although concurrent) application if +// application restarts take longer than 1 millisecond. The package supports up to 32 works, all +// providing unique sequences. +// +// Implementation details +// +// Although heavily inspired by the node.js shortid library this is +// not a simple Go port. In addition it +// +// - is safe to concurrency; +// - does not require any yearly version/epoch resets; +// - provides stable Id size over a long period at the rate of 1ms; +// - guarantees no collisions (due to guaranteed fixed size of Ids between milliseconds and because +// multiple requests within the same ms lead to longer Ids with the prefix unique to the ms); +// - supports 32 over 16 workers. +// +// The algorithm uses less randomness than the original node.js implementation, which permits to +// extend the life span as well as reduce and guarantee the length. In general terms, each Id +// has the following 3 pieces of information encoded: the millisecond (first 8 symbols), the worker +// Id (9th symbol), running concurrent counter within the same millisecond, only if required, over +// all remaining symbols. The element of randomness per symbol is 1/2 for the worker and the +// millisecond and 0 for the counter. Here 0 means no randomness, i.e. every value is encoded using +// a 64-base alphabet; 1/2 means one of two matching symbols of the supplied alphabet, 1/4 one of +// four matching symbols. The original algorithm of the node.js module uses 1/4 throughout. +// +// All methods accepting the parameters that govern the randomness are exported and can be used +// to directly implement an algorithm with e.g. more randomness, but with longer Ids and shorter +// life spans. +package shortid + +import ( + randc "crypto/rand" + "errors" + "fmt" + "math" + randm "math/rand" + "sync" + "sync/atomic" + "time" + "unsafe" +) + +// Version defined the library version. +const Version = 1.1 + +// DefaultABC is the default URL-friendly alphabet. +const DefaultABC = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-" + +// Abc represents a shuffled alphabet used to generate the Ids and provides methods to +// encode data. +type Abc struct { + alphabet []rune +} + +// Shortid type represents a short Id generator working with a given alphabet. +type Shortid struct { + abc Abc + worker uint + epoch time.Time // ids can be generated for 34 years since this date + ms uint // ms since epoch for the last id + count uint // request count within the same ms + mx sync.Mutex // locks access to ms and count +} + +var shortid *Shortid + +func init() { + shortid = MustNew(0, DefaultABC, 1) +} + +// GetDefault retrieves the default short Id generator initialised with the default alphabet, +// worker=0 and seed=1. The default can be overwritten using SetDefault. +func GetDefault() *Shortid { + return (*Shortid)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&shortid)))) +} + +// SetDefault overwrites the default generator. +func SetDefault(sid *Shortid) { + target := (*unsafe.Pointer)(unsafe.Pointer(&shortid)) + source := unsafe.Pointer(sid) + atomic.SwapPointer(target, source) +} + +// Generate generates an Id using the default generator. +func Generate() (string, error) { + return shortid.Generate() +} + +// MustGenerate acts just like Generate, but panics instead of returning errors. +func MustGenerate() string { + id, err := Generate() + if err == nil { + return id + } + panic(err) +} + +// New constructs an instance of the short Id generator for the given worker number [0,31], alphabet +// (64 unique symbols) and seed value (to shuffle the alphabet). The worker number should be +// different for multiple or distributed processes generating Ids into the same data space. The +// seed, on contrary, should be identical. +func New(worker uint8, alphabet string, seed uint64) (*Shortid, error) { + if worker > 31 { + return nil, errors.New("expected worker in the range [0,31]") + } + abc, err := NewAbc(alphabet, seed) + if err == nil { + sid := &Shortid{ + abc: abc, + worker: uint(worker), + epoch: time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC), + ms: 0, + count: 0, + } + return sid, nil + } + return nil, err +} + +// MustNew acts just like New, but panics instead of returning errors. +func MustNew(worker uint8, alphabet string, seed uint64) *Shortid { + sid, err := New(worker, alphabet, seed) + if err == nil { + return sid + } + panic(err) +} + +// Generate generates a new short Id. +func (sid *Shortid) Generate() (string, error) { + return sid.GenerateInternal(nil, sid.epoch) +} + +// MustGenerate acts just like Generate, but panics instead of returning errors. +func (sid *Shortid) MustGenerate() string { + id, err := sid.Generate() + if err == nil { + return id + } + panic(err) +} + +// GenerateInternal should only be used for testing purposes. +func (sid *Shortid) GenerateInternal(tm *time.Time, epoch time.Time) (string, error) { + ms, count := sid.getMsAndCounter(tm, epoch) + idrunes := make([]rune, 9) + if tmp, err := sid.abc.Encode(ms, 8, 5); err == nil { + copy(idrunes, tmp) // first 8 symbols + } else { + return "", err + } + if tmp, err := sid.abc.Encode(sid.worker, 1, 5); err == nil { + idrunes[8] = tmp[0] + } else { + return "", err + } + if count > 0 { + if countrunes, err := sid.abc.Encode(count, 0, 6); err == nil { + // only extend if really need it + idrunes = append(idrunes, countrunes...) + } else { + return "", err + } + } + return string(idrunes), nil +} + +func (sid *Shortid) getMsAndCounter(tm *time.Time, epoch time.Time) (uint, uint) { + sid.mx.Lock() + defer sid.mx.Unlock() + var ms uint + if tm != nil { + ms = uint(tm.Sub(epoch).Nanoseconds() / 1000000) + } else { + ms = uint(time.Now().Sub(epoch).Nanoseconds() / 1000000) + } + if ms == sid.ms { + sid.count++ + } else { + sid.count = 0 + sid.ms = ms + } + return sid.ms, sid.count +} + +// String returns a string representation of the short Id generator. +func (sid *Shortid) String() string { + return fmt.Sprintf("Shortid(worker=%v, epoch=%v, abc=%v)", sid.worker, sid.epoch, sid.abc) +} + +// Abc returns the instance of alphabet used for representing the Ids. +func (sid *Shortid) Abc() Abc { + return sid.abc +} + +// Epoch returns the value of epoch used as the beginning of millisecond counting (normally +// 2016-01-01 00:00:00 local time) +func (sid *Shortid) Epoch() time.Time { + return sid.epoch +} + +// Worker returns the value of worker for this short Id generator. +func (sid *Shortid) Worker() uint { + return sid.worker +} + +// NewAbc constructs a new instance of shuffled alphabet to be used for Id representation. +func NewAbc(alphabet string, seed uint64) (Abc, error) { + runes := []rune(alphabet) + if len(runes) != len(DefaultABC) { + return Abc{}, fmt.Errorf("alphabet must contain %v unique characters", len(DefaultABC)) + } + if nonUnique(runes) { + return Abc{}, errors.New("alphabet must contain unique characters only") + } + abc := Abc{alphabet: nil} + abc.shuffle(alphabet, seed) + return abc, nil +} + +// MustNewAbc acts just like NewAbc, but panics instead of returning errors. +func MustNewAbc(alphabet string, seed uint64) Abc { + res, err := NewAbc(alphabet, seed) + if err == nil { + return res + } + panic(err) +} + +func nonUnique(runes []rune) bool { + found := make(map[rune]struct{}) + for _, r := range runes { + if _, seen := found[r]; !seen { + found[r] = struct{}{} + } + } + return len(found) < len(runes) +} + +func (abc *Abc) shuffle(alphabet string, seed uint64) { + source := []rune(alphabet) + for len(source) > 1 { + seed = (seed*9301 + 49297) % 233280 + i := int(seed * uint64(len(source)) / 233280) + + abc.alphabet = append(abc.alphabet, source[i]) + source = append(source[:i], source[i+1:]...) + } + abc.alphabet = append(abc.alphabet, source[0]) +} + +// Encode encodes a given value into a slice of runes of length nsymbols. In case nsymbols==0, the +// length of the result is automatically computed from data. Even if fewer symbols is required to +// encode the data than nsymbols, all positions are used encoding 0 where required to guarantee +// uniqueness in case further data is added to the sequence. The value of digits [4,6] represents +// represents n in 2^n, which defines how much randomness flows into the algorithm: 4 -- every value +// can be represented by 4 symbols in the alphabet (permitting at most 16 values), 5 -- every value +// can be represented by 2 symbols in the alphabet (permitting at most 32 values), 6 -- every value +// is represented by exactly 1 symbol with no randomness (permitting 64 values). +func (abc *Abc) Encode(val, nsymbols, digits uint) ([]rune, error) { + if digits < 4 || 6 < digits { + return nil, fmt.Errorf("allowed digits range [4,6], found %v", digits) + } + + var computedSize uint = 1 + if val >= 1 { + computedSize = uint(math.Log2(float64(val)))/digits + 1 + } + if nsymbols == 0 { + nsymbols = computedSize + } else if nsymbols < computedSize { + return nil, fmt.Errorf("cannot accommodate data, need %v digits, got %v", computedSize, nsymbols) + } + + mask := 1<>shift) & mask) | random[i] + res[i] = abc.alphabet[index] + } + return res, nil +} + +// MustEncode acts just like Encode, but panics instead of returning errors. +func (abc *Abc) MustEncode(val, size, digits uint) []rune { + res, err := abc.Encode(val, size, digits) + if err == nil { + return res + } + panic(err) +} + +func maskedRandomInts(size, mask int) []int { + ints := make([]int, size) + bytes := make([]byte, size) + if _, err := randc.Read(bytes); err == nil { + for i, b := range bytes { + ints[i] = int(b) & mask + } + } else { + for i := range ints { + ints[i] = randm.Intn(0xff) & mask + } + } + return ints +} + +// String returns a string representation of the Abc instance. +func (abc Abc) String() string { + return fmt.Sprintf("Abc{alphabet='%v')", abc.Alphabet()) +} + +// Alphabet returns the alphabet used as an immutable string. +func (abc Abc) Alphabet() string { + return string(abc.alphabet) +} diff --git a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md deleted file mode 100644 index 17014701f4d..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md +++ /dev/null @@ -1,131 +0,0 @@ -Changes by Version -================== - -2.9.1 (unreleased) ------------------- - -- nothing yet - - -2.9.0 (2017-07-29) ------------------- - -- Pin thrift <= 0.10 (#179) -- Introduce a parallel interface ContribObserver (#159) - - -2.8.0 (2017-07-05) ------------------- - -- Drop `jaeger.` prefix from `jaeger.hostname` process-level tag -- Add options to set tracer tags - - -2.7.0 (2017-06-21) ------------------- - -- Fix rate limiter balance [#135](https://github.com/uber/jaeger-client-go/pull/135) [#140](https://github.com/uber/jaeger-client-go/pull/140) -- Default client to send Jaeger.thrift [#147](https://github.com/uber/jaeger-client-go/pull/147) -- Save baggage in span [#153](https://github.com/uber/jaeger-client-go/pull/153) -- Move reporter.queueLength to the top of the struct to guarantee 64bit alignment [#158](https://github.com/uber/jaeger-client-go/pull/158) -- Support HTTP transport with jaeger.thrift [#161](https://github.com/uber/jaeger-client-go/pull/161) - - -2.6.0 (2017-03-28) ------------------- - -- Add config option to initialize RPC Metrics feature - - -2.5.0 (2017-03-23) ------------------- - -- Split request latency metric by success/failure [#123](https://github.com/uber/jaeger-client-go/pull/123) -- Add mutex to adaptive sampler and fix race condition [#124](https://github.com/uber/jaeger-client-go/pull/124) -- Fix rate limiter panic [#125](https://github.com/uber/jaeger-client-go/pull/125) - - -2.4.0 (2017-03-21) ------------------- - -- Remove `_ms` suffix from request latency metric name [#121](https://github.com/uber/jaeger-client-go/pull/121) -- Rename all metrics to "request" and "http_request" and use tags for other dimensions [#121](https://github.com/uber/jaeger-client-go/pull/121) - - -2.3.0 (2017-03-20) ------------------- - -- Make Span type public to allow access to non-std methods for testing [#117](https://github.com/uber/jaeger-client-go/pull/117) -- Add a structured way to extract traces for logging with zap [#118](https://github.com/uber/jaeger-client-go/pull/118) - - -2.2.1 (2017-03-14) ------------------- - -- Fix panic caused by updating the remote sampler from adaptive sampler to any other sampler type (https://github.com/uber/jaeger-client-go/pull/111) - - -2.2.0 (2017-03-10) ------------------- - -- Introduce Observer and SpanObserver (https://github.com/uber/jaeger-client-go/pull/94) -- Add RPC metrics emitter as Observer/SpanObserver (https://github.com/uber/jaeger-client-go/pull/103) - - -2.1.2 (2017-02-27) -------------------- - -- Fix leaky bucket bug (https://github.com/uber/jaeger-client-go/pull/99) -- Fix zap logger Infof (https://github.com/uber/jaeger-client-go/pull/100) -- Add tracer initialization godoc examples - - -2.1.1 (2017-02-21) -------------------- - -- Fix inefficient usage of zap.Logger - - -2.1.0 (2017-02-17) -------------------- - -- Add adapter for zap.Logger (https://github.com/uber-go/zap) -- Move logging API to ./log/ package - - -2.0.0 (2017-02-08) -------------------- - -- Support Adaptive Sampling -- Support 128bit Trace IDs -- Change trace/span IDs from uint64 to strong types TraceID and SpanID -- Add Zipkin HTTP B3 Propagation format support #72 -- Rip out existing metrics and use github.com/uber/jaeger-lib/metrics -- Change API for tracer, reporter, sampler initialization - - -1.6.0 (2016-10-14) -------------------- - -- Add Zipkin HTTP transport -- Support external baggage via jaeger-baggage header -- Unpin Thrift version, keep to master - - -1.5.1 (2016-09-27) -------------------- - -- Relax dependency on opentracing to ^1 - - -1.5.0 (2016-09-27) -------------------- - -- Upgrade to opentracing-go 1.0 -- Support KV logging for Spans - - -1.4.0 (2016-09-14) -------------------- - -- Support debug traces via HTTP header "jaeger-debug-id" diff --git a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md b/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md deleted file mode 100644 index ba4d24f4738..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/CONTRIBUTING.md +++ /dev/null @@ -1,67 +0,0 @@ -# Contributing to `jaeger-client-go` - -We'd love your help! If you would like to contribute code you can do so through GitHub -by forking the repository and sending a pull request into the `master` branch. - -## Getting Started - -This library uses [glide](https://github.com/Masterminds/glide) to manage dependencies. - -To get started: - -```bash -git submodule update --init --recursive -glide install -make test -``` - -## Making A Change - -*Before making any significant changes, please [open an -issue](https://github.com/uber/jaeger-client-go/issues).* Discussing your proposed -changes ahead of time will make the contribution process smooth for everyone. - -Once we've discussed your changes and you've got your code ready, make sure -that tests are passing (`make test` or `make cover`) and open your PR! Your -pull request is most likely to be accepted if it: - -* Includes tests for new functionality. -* Follows the guidelines in [Effective - Go](https://golang.org/doc/effective_go.html) and the [Go team's common code - review comments](https://github.com/golang/go/wiki/CodeReviewComments). -* Has a [good commit - message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). - -## Cutting a Release - -See [RELEASE.md](./RELEASE.md) - -## License - -By contributing your code, you agree to license your contribution under the terms -of the MIT License: https://github.com/uber/jaeger-client-go/blob/master/LICENSE - -If you are adding a new file it should have a header like below. - -``` -// Copyright (c) 2017 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -``` - diff --git a/vendor/github.com/uber/jaeger-client-go/LICENSE b/vendor/github.com/uber/jaeger-client-go/LICENSE index 1fe81959773..261eeb9e9f8 100644 --- a/vendor/github.com/uber/jaeger-client-go/LICENSE +++ b/vendor/github.com/uber/jaeger-client-go/LICENSE @@ -1,21 +1,201 @@ -The MIT License (MIT) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2017 Uber Technologies, Inc. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + 1. Definitions. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + "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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. diff --git a/vendor/github.com/uber/jaeger-client-go/Makefile b/vendor/github.com/uber/jaeger-client-go/Makefile deleted file mode 100644 index c8b0925b606..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/Makefile +++ /dev/null @@ -1,104 +0,0 @@ -PROJECT_ROOT=github.com/uber/jaeger-client-go -PACKAGES := $(shell glide novendor | grep -v ./thrift-gen/...) -# all .go files that don't exist in hidden directories -ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen \ - -e ".*/\..*" \ - -e ".*/_.*" \ - -e ".*/mocks.*") - --include crossdock/rules.mk - -export GO15VENDOREXPERIMENT=1 - -RACE=-race -GOTEST=go test -v $(RACE) -GOLINT=golint -GOVET=go vet -GOFMT=gofmt -FMT_LOG=fmt.log -LINT_LOG=lint.log - -THRIFT_VER=0.9.3 -THRIFT_IMG=thrift:$(THRIFT_VER) -THRIFT=docker run -v "${PWD}:/data" $(THRIFT_IMG) thrift -THRIFT_GO_ARGS=thrift_import="github.com/apache/thrift/lib/go/thrift" -THRIFT_GEN_DIR=thrift-gen - -PASS=$(shell printf "\033[32mPASS\033[0m") -FAIL=$(shell printf "\033[31mFAIL\033[0m") -COLORIZE=sed ''/PASS/s//$(PASS)/'' | sed ''/FAIL/s//$(FAIL)/'' - -.DEFAULT_GOAL := test-and-lint - -.PHONY: test-and-lint -test-and-lint: test fmt lint - -.PHONY: test -test: - bash -c "set -e; set -o pipefail; $(GOTEST) $(PACKAGES) | $(COLORIZE)" - -.PHONY: fmt -fmt: - $(GOFMT) -e -s -l -w $(ALL_SRC) - ./scripts/updateLicenses.sh - -.PHONY: lint -lint: - $(GOVET) $(PACKAGES) - @cat /dev/null > $(LINT_LOG) - @$(foreach pkg, $(PACKAGES), $(GOLINT) $(pkg) | grep -v crossdock/thrift >> $(LINT_LOG) || true;) - @[ ! -s "$(LINT_LOG)" ] || (echo "Lint Failures" | cat - $(LINT_LOG) && false) - @$(GOFMT) -e -s -l $(ALL_SRC) > $(FMT_LOG) - @[ ! -s "$(FMT_LOG)" ] || (echo "Go Fmt Failures, run 'make fmt'" | cat - $(FMT_LOG) && false) - - -.PHONY: install -install: - glide --version || go get github.com/Masterminds/glide - glide install - - -.PHONY: cover -cover: - ./scripts/cover.sh $(shell go list $(PACKAGES)) - go tool cover -html=cover.out -o cover.html - - -# This is not part of the regular test target because we don't want to slow it -# down. -.PHONY: test-examples -test-examples: - make -C examples - -# TODO at the moment we're not generating tchan_*.go files -thrift: idl-submodule thrift-image - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/agent.thrift - sed -i '' 's|"zipkincore"|"$(PROJECT_ROOT)/thrift-gen/zipkincore"|g' $(THRIFT_GEN_DIR)/agent/*.go - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/sampling.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/jaeger.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/zipkincore.thrift - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/baggage.thrift - rm -rf thrift-gen/*/*-remote - $(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/crossdock/thrift/ /data/idl/thrift/crossdock/tracetest.thrift - rm -rf crossdock/thrift/*/*-remote - -idl-submodule: - git submodule init - git submodule update - -thrift-image: - $(THRIFT) -version - -.PHONY: install_ci -install_ci: install - go get github.com/wadey/gocovmerge - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover - go get github.com/golang/lint/golint - - -.PHONY: test_ci -test_ci: - @./scripts/cover.sh $(shell go list $(PACKAGES)) - make lint - diff --git a/vendor/github.com/uber/jaeger-client-go/README.md b/vendor/github.com/uber/jaeger-client-go/README.md deleted file mode 100644 index d08f0927271..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/README.md +++ /dev/null @@ -1,222 +0,0 @@ -[![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![OpenTracing 1.0 Enabled][ot-img]][ot-url] - -# Jaeger Bindings for Go OpenTracing API - -This is a client side library that implements an -[OpenTracing](http://opentracing.io) Tracer, -with Zipkin-compatible data model. - -## Installation - -We recommended using a dependency manager like [glide](https://github.com/Masterminds/glide) -and [semantic versioning](http://semver.org/) when including this library into an application. -For example, Jaeger backend imports this library like this: - -```yaml -- package: github.com/uber/jaeger-client-go - version: ^2.7.0 -``` - -If you instead want to use the latest version in `master`, you can pull it via `go get`. -Note that during `go get` you may see build errors due to incompatible dependencies, which is why -we recommend using semantic versions for dependencioes. The error may be fixed by running -`make install` (it will install `glide` if you don't have it): - -```shell -go get -u github.com/uber/jaeger-client-go/ -cd $GOPATH/src/github.com/uber/jaeger-client-go/ -git submodule update --init --recursive -make install -``` - -## Initialization - -See tracer initialization examples in [godoc](https://godoc.org/github.com/uber/jaeger-client-go/config#pkg-examples) -and [config/example_test.go](./config/example_test.go). - -### Closing the tracer via `io.Closer` - -The constructor functions for Jaeger Tracer return the tracer itself and an `io.Closer` instance. -It is recommended to structure your `main()` so that it calls the `Close()` function on the closer -before exiting, e.g. - -```go -tracer, closer, err := cfg.New(...) -defer closer.Close() -``` - -This is especially useful for command-line tools that enable tracing, as well as -for the long-running apps that support graceful shutdown. For example, if your deployment -system sends SIGTERM instead of killing the process and you trap that signal to do a graceful -exit, then having `defer closer.Closer()` ensures that all buffered spans are flushed. - -### Metrics & Monitoring - -The tracer emits a number of different metrics, defined in -[metrics.go](metrics.go). The monitoring backend is expected to support -tag-based metric names, e.g. instead of `statsd`-style string names -like `counters.my-service.jaeger.spans.started.sampled`, the metrics -are defined by a short name and a collection of key/value tags, for -example: `name:traces, state:started, sampled:true`. - -The monitoring backend is represented by the -[StatsReporter](stats_reporter.go) interface. An implementation -of that interface should be passed to the `New` method during -tracer initialization: - -```go - stats := // create StatsReporter implementation - tracer := config.Tracing.New("your-service-name", stats) -``` - -By default, a no-op `NullStatsReporter` is used. - -### Logging - -The tracer can be configured with an optional logger, which will be -used to log communication errors, or log spans if a logging reporter -option is specified in the configuration. The logging API is abstracted -by the [Logger](logger.go) interface. A logger instance implementing -this interface can be set on the `Config` object before calling the -`New` method. - -## Instrumentation for Tracing - -Since this tracer is fully compliant with OpenTracing API 1.0, -all code instrumentation should only use the API itself, as described -in the [opentracing-go] -(https://github.com/opentracing/opentracing-go) documentation. - -## Features - -### Reporters - -A "reporter" is a component receives the finished spans and reports -them to somewhere. Under normal circumstances, the Tracer -should use the default `RemoteReporter`, which sends the spans out of -process via configurable "transport". For testing purposes, one can -use an `InMemoryReporter` that accumulates spans in a buffer and -allows to retrieve them for later verification. Also available are -`NullReporter`, a no-op reporter that does nothing, a `LoggingReporter` -which logs all finished spans using their `String()` method, and a -`CompositeReporter` that can be used to combine more than one reporter -into one, e.g. to attach a logging reporter to the main remote reporter. - -### Span Reporting Transports - -The remote reporter uses "transports" to actually send the spans out -of process. Currently two supported transports are Thrift over UDP -and Thrift over TChannel. More transports will be added in the future. - -The only data format currently used is Zipkin Thrift 1.x span format, -which allows easy integration of the tracer with Zipkin backend. - -### Sampling - -The tracer does not record all spans, but only those that have the -sampling bit set in the `flags`. When a new trace is started and a new -unique ID is generated, a sampling decision is made whether this trace -should be sampled. The sampling decision is propagated to all downstream -calls via the `flags` field of the trace context. The following samplers -are available: - 1. `RemotelyControlledSampler` uses one of the other simpler samplers - and periodically updates it by polling an external server. This - allows dynamic control of the sampling strategies. - 1. `ConstSampler` always makes the same sampling decision for all - trace IDs. it can be configured to either sample all traces, or - to sample none. - 1. `ProbabilisticSampler` uses a fixed sampling rate as a probability - for a given trace to be sampled. The actual decision is made by - comparing the trace ID with a random number multiplied by the - sampling rate. - 1. `RateLimitingSampler` can be used to allow only a certain fixed - number of traces to be sampled per second. - -### Baggage Injection - -The OpenTracing spec allows for [baggage](https://github.com/opentracing/specification/blob/master/specification.md#set-a-baggage-item), -which are key value pairs that are added to the span context and propagated -throughout the trace. -An external process can inject baggage by setting the special -HTTP Header `jaeger-baggage` on a request - -```sh -curl -H "jaeger-baggage: key1=value1, key2=value2" http://myhost.com -``` - -Baggage can also be programatically set inside your service by doing -the following - -```go -if span := opentracing.SpanFromContext(ctx); span != nil { - span.SetBaggageItem("key", "value") -} -``` - -Another service downstream of that can retrieve the baggage in a similar way: - -```go -if span := opentracing.SpanFromContext(ctx); span != nil { - val := span.BaggageItem("key") - println(val) -} -``` - -### Debug Traces (Forced Sampling) - -#### Programmatically - -The OpenTracing API defines a `sampling.priority` standard tag that -can be used to affect the sampling of a span and its children: - -```go -import ( - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" -) - -span := opentracing.SpanFromContext(ctx) -ext.SamplingPriority.Set(span, 1) -``` - -#### Via HTTP Headers - -Jaeger Tracer also understands a special HTTP Header `jaeger-debug-id`, -which can be set in the incoming request, e.g. - -```sh -curl -H "jaeger-debug-id: some-correlation-id" http://myhost.com -``` - -When Jaeger sees this header in the request that otherwise has no -tracing context, it ensures that the new trace started for this -request will be sampled in the "debug" mode (meaning it should survive -all downsampling that might happen in the collection pipeline), and the -root span will have a tag as if this statement was executed: - -```go -span.SetTag("jaeger-debug-id", "some-correlation-id") -``` - -This allows using Jaeger UI to find the trace by this tag. - -### Zipkin HTTP B3 compatible header propagation - -Jaeger Tracer supports Zipkin B3 Propagation HTTP headers, which are used -by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction with e.g. [these OpenZipkin tracers](https://github.com/openzipkin). - -However it is not the default propagation format, see [here](zipkin/README.md#NewZipkinB3HTTPHeaderPropagator) how to set it up. - -## License - - [The MIT License](LICENSE). - - -[doc-img]: https://godoc.org/github.com/uber/jaeger-client-go?status.svg -[doc]: https://godoc.org/github.com/uber/jaeger-client-go -[ci-img]: https://travis-ci.org/uber/jaeger-client-go.svg?branch=master -[ci]: https://travis-ci.org/uber/jaeger-client-go -[cov-img]: https://coveralls.io/repos/uber/jaeger-client-go/badge.svg?branch=master&service=github -[cov]: https://coveralls.io/github/uber/jaeger-client-go?branch=master -[ot-img]: https://img.shields.io/badge/OpenTracing--1.0-enabled-blue.svg -[ot-url]: http://opentracing.io diff --git a/vendor/github.com/uber/jaeger-client-go/RELEASE.md b/vendor/github.com/uber/jaeger-client-go/RELEASE.md deleted file mode 100644 index 115e49ab8ad..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/RELEASE.md +++ /dev/null @@ -1,11 +0,0 @@ -# Release Process - -1. Create a PR "Preparing for release X.Y.Z" against master branch - * Alter CHANGELOG.md from ` (unreleased)` to ` (YYYY-MM-DD)` - * Update `JaegerClientVersion` in constants.go to `Go-X.Y.Z` -2. Create a release "Release X.Y.Z" on Github - * Create Tag `vX.Y.Z` - * Copy CHANGELOG.md into the release notes -3. Create a PR "Back to development" against master branch - * Add ` (unreleased)` to CHANGELOG.md - * Update `JaegerClientVersion` in constants.go to `Go-dev` diff --git a/vendor/github.com/uber/jaeger-client-go/baggage_setter.go b/vendor/github.com/uber/jaeger-client-go/baggage_setter.go index dd72ea5d5fe..1037ca0e861 100644 --- a/vendor/github.com/uber/jaeger-client-go/baggage_setter.go +++ b/vendor/github.com/uber/jaeger-client-go/baggage_setter.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger @@ -44,7 +38,7 @@ func newBaggageSetter(restrictionManager baggage.RestrictionManager, metrics *Me func (s *baggageSetter) setBaggage(span *Span, key, value string) { var truncated bool var prevItem string - restriction := s.restrictionManager.GetRestriction(key) + restriction := s.restrictionManager.GetRestriction(span.serviceName(), key) if !restriction.KeyAllowed() { s.logFields(span, key, value, prevItem, truncated, restriction.KeyAllowed()) s.metrics.BaggageUpdateFailure.Inc(1) diff --git a/vendor/github.com/uber/jaeger-client-go/config/config.go b/vendor/github.com/uber/jaeger-client-go/config/config.go index 26ee44b99d3..306b92fa2ab 100644 --- a/vendor/github.com/uber/jaeger-client-go/config/config.go +++ b/vendor/github.com/uber/jaeger-client-go/config/config.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 config @@ -165,6 +159,7 @@ func (c Configuration) New( jaeger.TracerOptions.Metrics(tracerMetrics), jaeger.TracerOptions.Logger(opts.logger), jaeger.TracerOptions.CustomHeaderKeys(c.Headers), + jaeger.TracerOptions.Gen128Bit(opts.gen128Bit), jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan), } @@ -216,7 +211,7 @@ func (c Configuration) InitGlobalTracer( if err != nil { return nil, err } - opentracing.InitGlobalTracer(tracer) + opentracing.SetGlobalTracer(tracer) return closer, nil } diff --git a/vendor/github.com/uber/jaeger-client-go/config/options.go b/vendor/github.com/uber/jaeger-client-go/config/options.go index 99f3ca6bda5..76486440ac1 100644 --- a/vendor/github.com/uber/jaeger-client-go/config/options.go +++ b/vendor/github.com/uber/jaeger-client-go/config/options.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 config @@ -37,6 +31,7 @@ type Options struct { reporter jaeger.Reporter contribObservers []jaeger.ContribObserver observers []jaeger.Observer + gen128Bit bool zipkinSharedRPCSpan bool tags []opentracing.Tag } @@ -80,6 +75,13 @@ func ContribObserver(observer jaeger.ContribObserver) Option { } } +// Gen128Bit specifies whether to generate 128bit trace IDs. +func Gen128Bit(gen128Bit bool) Option { + return func(c *Options) { + c.gen128Bit = gen128Bit + } +} + // ZipkinSharedRPCSpan creates an option that enables sharing span ID between client // and server spans a la zipkin. If false, client and server spans will be assigned // different IDs. diff --git a/vendor/github.com/uber/jaeger-client-go/constants.go b/vendor/github.com/uber/jaeger-client-go/constants.go index 65978b8be9e..1f00d1c0b1e 100644 --- a/vendor/github.com/uber/jaeger-client-go/constants.go +++ b/vendor/github.com/uber/jaeger-client-go/constants.go @@ -1,28 +1,22 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger const ( // JaegerClientVersion is the version of the client library reported as Span tag. - JaegerClientVersion = "Go-2.9.1dev" + JaegerClientVersion = "Go-2.11.2" // JaegerClientVersionTagKey is the name of the tag used to report client version. JaegerClientVersionTagKey = "jaeger.version" @@ -77,6 +71,6 @@ const ( SamplerTypeRateLimiting = "ratelimiting" // SamplerTypeLowerBound is the type of sampler that samples - // only up to a fixed number of traces per second. + // at least a fixed number of traces per second. SamplerTypeLowerBound = "lowerbound" ) diff --git a/vendor/github.com/uber/jaeger-client-go/context.go b/vendor/github.com/uber/jaeger-client-go/context.go index d3dcf9b542f..8b06173d983 100644 --- a/vendor/github.com/uber/jaeger-client-go/context.go +++ b/vendor/github.com/uber/jaeger-client-go/context.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/contrib_observer.go b/vendor/github.com/uber/jaeger-client-go/contrib_observer.go index 2fe28d26130..4ce1881f3b8 100644 --- a/vendor/github.com/uber/jaeger-client-go/contrib_observer.go +++ b/vendor/github.com/uber/jaeger-client-go/contrib_observer.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/doc.go b/vendor/github.com/uber/jaeger-client-go/doc.go index 6a0ad6ad36e..4f5549033d5 100644 --- a/vendor/github.com/uber/jaeger-client-go/doc.go +++ b/vendor/github.com/uber/jaeger-client-go/doc.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger implements an OpenTracing (http://opentracing.io) Tracer. diff --git a/vendor/github.com/uber/jaeger-client-go/glide.lock b/vendor/github.com/uber/jaeger-client-go/glide.lock deleted file mode 100644 index 84a832e05d7..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/glide.lock +++ /dev/null @@ -1,75 +0,0 @@ -hash: 50e5f204fc6ee9ff66efb1275c7d12f78f8f21a2de98ed38c947d01eb2064b0f -updated: 2017-07-28T19:53:12.495163139-04:00 -imports: -- name: github.com/apache/thrift - version: b2a4d4ae21c789b689dd162deb819665567f481c - subpackages: - - lib/go/thrift -- name: github.com/codahale/hdrhistogram - version: 3a0bb77429bd3a61596f5e8a3172445844342120 -- name: github.com/crossdock/crossdock-go - version: 049aabb0122b03bc9bd30cab8f3f91fb60166361 - subpackages: - - assert - - require -- name: github.com/davecgh/go-spew - version: adab96458c51a58dc1783b3335dcce5461522e75 - subpackages: - - spew -- name: github.com/opentracing/opentracing-go - version: 1949ddbfd147afd4d964a9f00b24eb291e0e7c38 - subpackages: - - ext - - log -- name: github.com/pmezard/go-difflib - version: 792786c7400a136282c1664665ae0a8db921c6c2 - subpackages: - - difflib -- name: github.com/stretchr/testify - version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 - subpackages: - - assert - - require - - suite -- name: github.com/uber-go/atomic - version: 4e336646b2ef9fc6e47be8e21594178f98e5ebcf -- name: github.com/uber/jaeger-lib - version: e3c1d3b562900c6ac0a7ded654cb95d88e72b63e - subpackages: - - metrics - - metrics/testutils -- name: github.com/uber/tchannel-go - version: b99c1d7cecb0fdc882bed0098e7cae6ec7459059 - subpackages: - - atomic - - internal/argreader - - relay - - thrift - - thrift/gen-go/meta - - tnet - - tos - - trace/thrift/gen-go/tcollector - - trand - - typed -- name: go.uber.org/atomic - version: 4e336646b2ef9fc6e47be8e21594178f98e5ebcf -- name: go.uber.org/zap - version: 6a4e056f2cc954cfec3581729e758909604b3f76 - subpackages: - - buffer - - internal/bufferpool - - internal/color - - internal/exit - - internal/multierror - - zapcore -- name: golang.org/x/net - version: f5079bd7f6f74e23c4d65efa0f4ce14cbd6a3c0f - subpackages: - - bpf - - context - - context/ctxhttp - - internal/iana - - internal/socket - - ipv4 - - ipv6 -testImports: [] diff --git a/vendor/github.com/uber/jaeger-client-go/glide.yaml b/vendor/github.com/uber/jaeger-client-go/glide.yaml deleted file mode 100644 index fd93b2473e6..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/glide.yaml +++ /dev/null @@ -1,33 +0,0 @@ -package: github.com/uber/jaeger-client-go -import: -- package: github.com/apache/thrift - version: ">=0.9.3, <0.11.0" - subpackages: - - lib/go/thrift -- package: github.com/opentracing/opentracing-go - version: ^1 - subpackages: - - ext - - log -- package: golang.org/x/net - subpackages: - - context -- package: github.com/uber/tchannel-go - version: ^1.1.0 - subpackages: - - atomic - - thrift - - thrift/gen-go/meta - - tnet - - trace/thrift/gen-go/tcollector - - typed -- package: github.com/stretchr/testify - version: ^1.1.3 - subpackages: - - assert - - require - - suite -- package: github.com/crossdock/crossdock-go -- package: github.com/uber/jaeger-lib - subpackages: - - metrics diff --git a/vendor/github.com/uber/jaeger-client-go/header.go b/vendor/github.com/uber/jaeger-client-go/header.go index 0044186d2ed..19c2c055b81 100644 --- a/vendor/github.com/uber/jaeger-client-go/header.go +++ b/vendor/github.com/uber/jaeger-client-go/header.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go index 52e2c7b4f9e..745729319ff 100644 --- a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go +++ b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/options.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 remote diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go index d17ca671f87..a56515acab8 100644 --- a/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go +++ b/vendor/github.com/uber/jaeger-client-go/internal/baggage/remote/restriction_manager.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 remote @@ -96,7 +90,7 @@ func (m *RestrictionManager) isReady() bool { } // GetRestriction implements RestrictionManager#GetRestriction. -func (m *RestrictionManager) GetRestriction(key string) *baggage.Restriction { +func (m *RestrictionManager) GetRestriction(service, key string) *baggage.Restriction { m.mux.RLock() defer m.mux.RUnlock() if !m.initialized { diff --git a/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go b/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go index a3be272c31a..c16a5c56629 100644 --- a/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go +++ b/vendor/github.com/uber/jaeger-client-go/internal/baggage/restriction_manager.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 baggage @@ -48,9 +42,12 @@ func (r *Restriction) MaxValueLength() int { return r.maxValueLength } -// RestrictionManager keeps track of valid baggage keys and their restrictions. +// RestrictionManager keeps track of valid baggage keys and their restrictions. The manager +// will return a Restriction for a specific baggage key which will determine whether the baggage +// key is allowed for the current service and any other applicable restrictions on the baggage +// value. type RestrictionManager interface { - GetRestriction(key string) *Restriction + GetRestriction(service, key string) *Restriction } // DefaultRestrictionManager allows any baggage key. @@ -69,6 +66,6 @@ func NewDefaultRestrictionManager(maxValueLength int) *DefaultRestrictionManager } // GetRestriction implements RestrictionManager#GetRestriction. -func (m *DefaultRestrictionManager) GetRestriction(key string) *Restriction { +func (m *DefaultRestrictionManager) GetRestriction(service, key string) *Restriction { return m.defaultRestriction } diff --git a/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go b/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go index 283deb1ab5d..0e10b8a5aa8 100644 --- a/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go +++ b/vendor/github.com/uber/jaeger-client-go/internal/spanlog/json.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 spanlog diff --git a/vendor/github.com/uber/jaeger-client-go/interop.go b/vendor/github.com/uber/jaeger-client-go/interop.go index 23becc2c7ba..8402d087c29 100644 --- a/vendor/github.com/uber/jaeger-client-go/interop.go +++ b/vendor/github.com/uber/jaeger-client-go/interop.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go b/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go index 63a7db7b582..868b2a5b546 100644 --- a/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go +++ b/vendor/github.com/uber/jaeger-client-go/jaeger_tag.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go index 3335b5c89c9..338a3458221 100644 --- a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go +++ b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/log/logger.go b/vendor/github.com/uber/jaeger-client-go/log/logger.go index 3ac1bac488f..b002cda5531 100644 --- a/vendor/github.com/uber/jaeger-client-go/log/logger.go +++ b/vendor/github.com/uber/jaeger-client-go/log/logger.go @@ -1,26 +1,25 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 log -import "log" +import ( + "bytes" + "fmt" + "log" + "sync" +) // Logger provides an abstract interface for logging from Reporters. // Applications can provide their own implementation of this interface to adapt @@ -55,3 +54,30 @@ type nullLogger struct{} func (l *nullLogger) Error(msg string) {} func (l *nullLogger) Infof(msg string, args ...interface{}) {} + +// BytesBufferLogger implements Logger backed by a bytes.Buffer. +type BytesBufferLogger struct { + mux sync.Mutex + buf bytes.Buffer +} + +// Error implements Logger. +func (l *BytesBufferLogger) Error(msg string) { + l.mux.Lock() + l.buf.WriteString(fmt.Sprintf("ERROR: %s\n", msg)) + l.mux.Unlock() +} + +// Infof implements Logger. +func (l *BytesBufferLogger) Infof(msg string, args ...interface{}) { + l.mux.Lock() + l.buf.WriteString("INFO: " + fmt.Sprintf(msg, args...) + "\n") + l.mux.Unlock() +} + +// String returns string representation of the underlying buffer. +func (l *BytesBufferLogger) String() string { + l.mux.Lock() + defer l.mux.Unlock() + return l.buf.String() +} diff --git a/vendor/github.com/uber/jaeger-client-go/logger.go b/vendor/github.com/uber/jaeger-client-go/logger.go index 52b5dffd335..d4f0b501923 100644 --- a/vendor/github.com/uber/jaeger-client-go/logger.go +++ b/vendor/github.com/uber/jaeger-client-go/logger.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/metrics.go b/vendor/github.com/uber/jaeger-client-go/metrics.go index 7a976c6ad0c..8c0e63213fe 100644 --- a/vendor/github.com/uber/jaeger-client-go/metrics.go +++ b/vendor/github.com/uber/jaeger-client-go/metrics.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger @@ -39,63 +33,61 @@ type Metrics struct { TracesJoinedNotSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=n"` // Number of sampled spans started by this tracer - SpansStarted metrics.Counter `metric:"spans" tags:"group=lifecycle,state=started"` + SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y"` - // Number of sampled spans finished by this tracer - SpansFinished metrics.Counter `metric:"spans" tags:"group=lifecycle,state=finished"` + // Number of unsampled spans started by this tracer + SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n"` - // Number of sampled spans started by this tracer - SpansSampled metrics.Counter `metric:"spans" tags:"group=sampling,sampled=y"` - - // Number of not-sampled spans started by this tracer - SpansNotSampled metrics.Counter `metric:"spans" tags:"group=sampling,sampled=n"` + // Number of spans finished by this tracer + SpansFinished metrics.Counter `metric:"finished_spans"` // Number of errors decoding tracing context - DecodingErrors metrics.Counter `metric:"decoding-errors"` + DecodingErrors metrics.Counter `metric:"span_context_decoding_errors"` // Number of spans successfully reported - ReporterSuccess metrics.Counter `metric:"reporter-spans" tags:"state=success"` + ReporterSuccess metrics.Counter `metric:"reporter_spans" tags:"result=ok"` - // Number of spans in failed attempts to report - ReporterFailure metrics.Counter `metric:"reporter-spans" tags:"state=failure"` + // Number of spans not reported due to a Sender failure + ReporterFailure metrics.Counter `metric:"reporter_spans" tags:"result=err"` // Number of spans dropped due to internal queue overflow - ReporterDropped metrics.Counter `metric:"reporter-spans" tags:"state=dropped"` + ReporterDropped metrics.Counter `metric:"reporter_spans" tags:"result=dropped"` // Current number of spans in the reporter queue - ReporterQueueLength metrics.Gauge `metric:"reporter-queue"` + ReporterQueueLength metrics.Gauge `metric:"reporter_queue_length"` // Number of times the Sampler succeeded to retrieve sampling strategy - SamplerRetrieved metrics.Counter `metric:"sampler" tags:"state=retrieved"` - - // Number of times the Sampler succeeded to retrieve and update sampling strategy - SamplerUpdated metrics.Counter `metric:"sampler" tags:"state=updated"` - - // Number of times the Sampler failed to update sampling strategy - SamplerUpdateFailure metrics.Counter `metric:"sampler" tags:"state=failure,phase=updating"` + SamplerRetrieved metrics.Counter `metric:"sampler_queries" tags:"result=ok"` // Number of times the Sampler failed to retrieve sampling strategy - SamplerQueryFailure metrics.Counter `metric:"sampler" tags:"state=failure,phase=query"` + SamplerQueryFailure metrics.Counter `metric:"sampler_queries" tags:"result=err"` + + // Number of times the Sampler succeeded to retrieve and update sampling strategy + SamplerUpdated metrics.Counter `metric:"sampler_updates" tags:"result=ok"` + + // Number of times the Sampler failed to update sampling strategy + SamplerUpdateFailure metrics.Counter `metric:"sampler_updates" tags:"result=err"` // Number of times baggage was successfully written or updated on spans. - BaggageUpdateSuccess metrics.Counter `metric:"baggage-update" tags:"result=ok"` + BaggageUpdateSuccess metrics.Counter `metric:"baggage_updates" tags:"result=ok"` // Number of times baggage failed to write or update on spans. - BaggageUpdateFailure metrics.Counter `metric:"baggage-update" tags:"result=err"` + BaggageUpdateFailure metrics.Counter `metric:"baggage_updates" tags:"result=err"` // Number of times baggage was truncated as per baggage restrictions. - BaggageTruncate metrics.Counter `metric:"baggage-truncate"` + BaggageTruncate metrics.Counter `metric:"baggage_truncations"` // Number of times baggage restrictions were successfully updated. - BaggageRestrictionsUpdateSuccess metrics.Counter `metric:"baggage-restrictions-update" tags:"result=ok"` + BaggageRestrictionsUpdateSuccess metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=ok"` // Number of times baggage restrictions failed to update. - BaggageRestrictionsUpdateFailure metrics.Counter `metric:"baggage-restrictions-update" tags:"result=err"` + BaggageRestrictionsUpdateFailure metrics.Counter `metric:"baggage_restrictions_updates" tags:"result=err"` } // NewMetrics creates a new Metrics struct and initializes it. func NewMetrics(factory metrics.Factory, globalTags map[string]string) *Metrics { m := &Metrics{} + // TODO the namespace "jaeger" should be configurable (e.g. in all-in-one "jaeger-client" would make more sense) metrics.Init(m, factory.Namespace("jaeger", nil), globalTags) return m } diff --git a/vendor/github.com/uber/jaeger-client-go/observer.go b/vendor/github.com/uber/jaeger-client-go/observer.go index 7eeac5369d3..7bbd028897a 100644 --- a/vendor/github.com/uber/jaeger-client-go/observer.go +++ b/vendor/github.com/uber/jaeger-client-go/observer.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/propagation.go b/vendor/github.com/uber/jaeger-client-go/propagation.go index 30ddc845126..abca67a3c9b 100644 --- a/vendor/github.com/uber/jaeger-client-go/propagation.go +++ b/vendor/github.com/uber/jaeger-client-go/propagation.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/reference.go b/vendor/github.com/uber/jaeger-client-go/reference.go index f4c9f7c39b6..5646e78bb2a 100644 --- a/vendor/github.com/uber/jaeger-client-go/reference.go +++ b/vendor/github.com/uber/jaeger-client-go/reference.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/reporter.go b/vendor/github.com/uber/jaeger-client-go/reporter.go index 0bff9197977..fe6288c4b9e 100644 --- a/vendor/github.com/uber/jaeger-client-go/reporter.go +++ b/vendor/github.com/uber/jaeger-client-go/reporter.go @@ -1,26 +1,21 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger import ( + "fmt" "sync" "sync/atomic" "time" @@ -155,26 +150,40 @@ func (r *compositeReporter) Close() { } } -// ------------------------------ +// ------------- REMOTE REPORTER ----------------- + +type reporterQueueItemType int const ( defaultQueueSize = 100 - defaultBufferFlushInterval = 10 * time.Second + defaultBufferFlushInterval = 1 * time.Second + + reporterQueueItemSpan reporterQueueItemType = iota + reporterQueueItemClose ) -type remoteReporter struct { - // must be first in the struct because `sync/atomic` expects 64-bit alignment. - // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq - queueLength int64 - - reporterOptions - sender Transport - queue chan *Span - queueDrained sync.WaitGroup - flushSignal chan *sync.WaitGroup +type reporterQueueItem struct { + itemType reporterQueueItemType + span *Span + close *sync.WaitGroup } -// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender +type remoteReporter struct { + // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment. + // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq + queueLength int64 + closed int64 // 0 - not closed, 1 - closed + + reporterOptions + + sender Transport + queue chan reporterQueueItem +} + +// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender. +// Calls to Report(Span) return immediately (side effect: if internal buffer is full the span is dropped). +// Periodically the transport buffer is flushed even if it hasn't reached max packet size. +// Calls to Close() block until all spans reported prior to the call to Close are flushed. func NewRemoteReporter(sender Transport, opts ...ReporterOption) Reporter { options := reporterOptions{} for _, option := range opts { @@ -195,18 +204,21 @@ func NewRemoteReporter(sender Transport, opts ...ReporterOption) Reporter { reporter := &remoteReporter{ reporterOptions: options, sender: sender, - flushSignal: make(chan *sync.WaitGroup), - queue: make(chan *Span, options.queueSize), + queue: make(chan reporterQueueItem, options.queueSize), } go reporter.processQueue() return reporter } // Report implements Report() method of Reporter. -// It passes the span to a background go-routine for submission to Jaeger. +// It passes the span to a background go-routine for submission to Jaeger backend. +// If the internal queue is full, the span is dropped and metrics.ReporterDropped counter is incremented. +// If Report() is called after the reporter has been Close()-ed, the additional spans will not be +// sent to the backend, but the metrics.ReporterDropped counter may not reflect them correctly, +// because some of them may still be successfully added to the queue. func (r *remoteReporter) Report(span *Span) { select { - case r.queue <- span: + case r.queue <- reporterQueueItem{itemType: reporterQueueItemSpan, span: span}: atomic.AddInt64(&r.queueLength, 1) default: r.metrics.ReporterDropped.Inc(1) @@ -215,53 +227,63 @@ func (r *remoteReporter) Report(span *Span) { // Close implements Close() method of Reporter by waiting for the queue to be drained. func (r *remoteReporter) Close() { - r.queueDrained.Add(1) - close(r.queue) - r.queueDrained.Wait() + if swapped := atomic.CompareAndSwapInt64(&r.closed, 0, 1); !swapped { + r.logger.Error("Repeated attempt to close the reporter is ignored") + return + } + r.sendCloseEvent() r.sender.Close() } +func (r *remoteReporter) sendCloseEvent() { + wg := &sync.WaitGroup{} + wg.Add(1) + item := reporterQueueItem{itemType: reporterQueueItemClose, close: wg} + + r.queue <- item // if the queue is full we will block until there is space + atomic.AddInt64(&r.queueLength, 1) + wg.Wait() +} + // processQueue reads spans from the queue, converts them to Thrift, and stores them in an internal buffer. // When the buffer length reaches batchSize, it is flushed by submitting the accumulated spans to Jaeger. // Buffer also gets flushed automatically every batchFlushInterval seconds, just in case the tracer stopped // reporting new spans. func (r *remoteReporter) processQueue() { + // flush causes the Sender to flush its accumulated spans and clear the buffer + flush := func() { + if flushed, err := r.sender.Flush(); err != nil { + r.metrics.ReporterFailure.Inc(int64(flushed)) + r.logger.Error(fmt.Sprintf("error when flushing the buffer: %s", err.Error())) + } else if flushed > 0 { + r.metrics.ReporterSuccess.Inc(int64(flushed)) + } + } + timer := time.NewTicker(r.bufferFlushInterval) for { select { - case span, ok := <-r.queue: - if ok { - atomic.AddInt64(&r.queueLength, -1) + case <-timer.C: + flush() + case item := <-r.queue: + atomic.AddInt64(&r.queueLength, -1) + switch item.itemType { + case reporterQueueItemSpan: + span := item.span if flushed, err := r.sender.Append(span); err != nil { r.metrics.ReporterFailure.Inc(int64(flushed)) - r.logger.Error(err.Error()) + r.logger.Error(fmt.Sprintf("error reporting span %q: %s", span.OperationName(), err.Error())) } else if flushed > 0 { r.metrics.ReporterSuccess.Inc(int64(flushed)) // to reduce the number of gauge stats, we only emit queue length on flush r.metrics.ReporterQueueLength.Update(atomic.LoadInt64(&r.queueLength)) } - } else { - // queue closed + case reporterQueueItemClose: timer.Stop() - r.flush() - r.queueDrained.Done() + flush() + item.close.Done() return } - case <-timer.C: - r.flush() - case wg := <-r.flushSignal: // for testing - r.flush() - wg.Done() } } } - -// flush causes the Sender to flush its accumulated spans and clear the buffer -func (r *remoteReporter) flush() { - if flushed, err := r.sender.Flush(); err != nil { - r.metrics.ReporterFailure.Inc(int64(flushed)) - r.logger.Error(err.Error()) - } else if flushed > 0 { - r.metrics.ReporterSuccess.Inc(int64(flushed)) - } -} diff --git a/vendor/github.com/uber/jaeger-client-go/reporter_options.go b/vendor/github.com/uber/jaeger-client-go/reporter_options.go index 891d1bb6470..65012d7015d 100644 --- a/vendor/github.com/uber/jaeger-client-go/reporter_options.go +++ b/vendor/github.com/uber/jaeger-client-go/reporter_options.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md deleted file mode 100644 index 879948e9c9c..00000000000 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/README.md +++ /dev/null @@ -1,5 +0,0 @@ -An Observer that can be used to emit RPC metrics -================================================ - -It can be attached to the tracer during tracer construction. -See `ExampleObserver` function in [observer_test.go](./observer_test.go). diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go index 5b73b14071e..51aa11b350e 100644 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/doc.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 rpcmetrics implements an Observer that can be used to emit RPC metrics. package rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go index 79ec1c8ef9f..30555243d0c 100644 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/endpoints.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go index d01387fa406..ab8d74c2918 100644 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/metrics.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go index ac0f79b0fe3..148d84b3a1a 100644 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/normalizer.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go index c10624d78e9..eca5ff6f3b9 100644 --- a/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go +++ b/vendor/github.com/uber/jaeger-client-go/rpcmetrics/observer.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 rpcmetrics diff --git a/vendor/github.com/uber/jaeger-client-go/sampler.go b/vendor/github.com/uber/jaeger-client-go/sampler.go index f7eeee7e941..f2e8c994e2b 100644 --- a/vendor/github.com/uber/jaeger-client-go/sampler.go +++ b/vendor/github.com/uber/jaeger-client-go/sampler.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger @@ -338,6 +332,7 @@ func (s *adaptiveSampler) Close() { for _, sampler := range s.samplers { sampler.Close() } + s.defaultSampler.Close() } func (s *adaptiveSampler) Equal(other Sampler) bool { diff --git a/vendor/github.com/uber/jaeger-client-go/sampler_options.go b/vendor/github.com/uber/jaeger-client-go/sampler_options.go index 8d9c5bf9ee1..75d28a56119 100644 --- a/vendor/github.com/uber/jaeger-client-go/sampler_options.go +++ b/vendor/github.com/uber/jaeger-client-go/sampler_options.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/span.go b/vendor/github.com/uber/jaeger-client-go/span.go index 96d36c6ac6e..132fb721751 100644 --- a/vendor/github.com/uber/jaeger-client-go/span.go +++ b/vendor/github.com/uber/jaeger-client-go/span.go @@ -1,27 +1,20 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger import ( - "strings" "sync" "time" @@ -167,7 +160,6 @@ func (s *Span) appendLog(lr opentracing.LogRecord) { // SetBaggageItem implements SetBaggageItem() of opentracing.SpanContext func (s *Span) SetBaggageItem(key, value string) opentracing.Span { - key = normalizeBaggageKey(key) s.Lock() defer s.Unlock() s.tracer.setBaggage(s, key, value) @@ -176,7 +168,6 @@ func (s *Span) SetBaggageItem(key, value string) opentracing.Span { // BaggageItem implements BaggageItem() of opentracing.SpanContext func (s *Span) BaggageItem(key string) string { - key = normalizeBaggageKey(key) s.RLock() defer s.RUnlock() return s.context.baggage[key] @@ -232,6 +223,10 @@ func (s *Span) OperationName() string { return s.operationName } +func (s *Span) serviceName() string { + return s.tracer.serviceName +} + func setSamplingPriority(s *Span, value interface{}) bool { s.Lock() defer s.Unlock() @@ -245,10 +240,3 @@ func setSamplingPriority(s *Span, value interface{}) bool { } return false } - -// Converts end-user baggage key into internal representation. -// Used for both read and write access to baggage items. -func normalizeBaggageKey(key string) string { - // TODO(yurishkuro) normalizeBaggageKey: cache the results in some bounded LRU cache - return strings.Replace(strings.ToLower(key), "_", "-", -1) -} diff --git a/vendor/github.com/uber/jaeger-client-go/tracer.go b/vendor/github.com/uber/jaeger-client-go/tracer.go index 2fdd5ee4397..49fb099e367 100644 --- a/vendor/github.com/uber/jaeger-client-go/tracer.go +++ b/vendor/github.com/uber/jaeger-client-go/tracer.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger @@ -50,9 +44,10 @@ type Tracer struct { randomNumber func() uint64 options struct { - poolSpans bool - gen128Bit bool // whether to generate 128bit trace IDs - zipkinSharedRPCSpan bool + poolSpans bool + gen128Bit bool // whether to generate 128bit trace IDs + zipkinSharedRPCSpan bool + highTraceIDGenerator func() uint64 // custom high trace ID generator // more options to come } // pool for Span objects @@ -140,6 +135,15 @@ func NewTracer( t.logger.Error("Unable to determine this host's IP address: " + err.Error()) } + if t.options.gen128Bit { + if t.options.highTraceIDGenerator == nil { + t.options.highTraceIDGenerator = t.randomNumber + } + } else if t.options.highTraceIDGenerator != nil { + t.logger.Error("Overriding high trace ID generator but not generating " + + "128 bit trace IDs, consider enabling the \"Gen128Bit\" option") + } + return t, t } @@ -211,7 +215,7 @@ func (t *Tracer) startSpanWithOptions( newTrace = true ctx.traceID.Low = t.randomID() if t.options.gen128Bit { - ctx.traceID.High = t.randomID() + ctx.traceID.High = t.options.highTraceIDGenerator() } ctx.spanID = SpanID(ctx.traceID.Low) ctx.parentID = 0 @@ -344,9 +348,8 @@ func (t *Tracer) startSpanInternal( } } // emit metrics - t.metrics.SpansStarted.Inc(1) if sp.context.IsSampled() { - t.metrics.SpansSampled.Inc(1) + t.metrics.SpansStartedSampled.Inc(1) if newTrace { // We cannot simply check for parentID==0 because in Zipkin model the // server-side RPC span has the exact same trace/span/parent IDs as the @@ -357,7 +360,7 @@ func (t *Tracer) startSpanInternal( t.metrics.TracesJoinedSampled.Inc(1) } } else { - t.metrics.SpansNotSampled.Inc(1) + t.metrics.SpansStartedNotSampled.Inc(1) if newTrace { t.metrics.TracesStartedNotSampled.Inc(1) } else if sp.firstInProcess { diff --git a/vendor/github.com/uber/jaeger-client-go/tracer_options.go b/vendor/github.com/uber/jaeger-client-go/tracer_options.go index 2c8931e3057..72edf6dbbe2 100644 --- a/vendor/github.com/uber/jaeger-client-go/tracer_options.go +++ b/vendor/github.com/uber/jaeger-client-go/tracer_options.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger @@ -121,6 +115,18 @@ func (tracerOptions) ContribObserver(observer ContribObserver) TracerOption { } } +func (tracerOptions) Gen128Bit(gen128Bit bool) TracerOption { + return func(tracer *Tracer) { + tracer.options.gen128Bit = gen128Bit + } +} + +func (tracerOptions) HighTraceIDGenerator(highTraceIDGenerator func() uint64) TracerOption { + return func(tracer *Tracer) { + tracer.options.highTraceIDGenerator = highTraceIDGenerator + } +} + func (tracerOptions) ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) TracerOption { return func(tracer *Tracer) { tracer.options.zipkinSharedRPCSpan = zipkinSharedRPCSpan diff --git a/vendor/github.com/uber/jaeger-client-go/transport.go b/vendor/github.com/uber/jaeger-client-go/transport.go index f02c6f3b58d..c5f5b19551f 100644 --- a/vendor/github.com/uber/jaeger-client-go/transport.go +++ b/vendor/github.com/uber/jaeger-client-go/transport.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/transport_udp.go b/vendor/github.com/uber/jaeger-client-go/transport_udp.go index af87a9382e0..cb83cdf9b4c 100644 --- a/vendor/github.com/uber/jaeger-client-go/transport_udp.go +++ b/vendor/github.com/uber/jaeger-client-go/transport_udp.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/utils/http_json.go b/vendor/github.com/uber/jaeger-client-go/utils/http_json.go index c534315005c..237211f8224 100644 --- a/vendor/github.com/uber/jaeger-client-go/utils/http_json.go +++ b/vendor/github.com/uber/jaeger-client-go/utils/http_json.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 utils diff --git a/vendor/github.com/uber/jaeger-client-go/utils/localip.go b/vendor/github.com/uber/jaeger-client-go/utils/localip.go index 5dac5ee2a58..b51af7713f7 100644 --- a/vendor/github.com/uber/jaeger-client-go/utils/localip.go +++ b/vendor/github.com/uber/jaeger-client-go/utils/localip.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 utils diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rand.go b/vendor/github.com/uber/jaeger-client-go/utils/rand.go index ad67634bc7d..9875f7f55cb 100644 --- a/vendor/github.com/uber/jaeger-client-go/utils/rand.go +++ b/vendor/github.com/uber/jaeger-client-go/utils/rand.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 utils diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go index 58927586b00..1b8db975848 100644 --- a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go +++ b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 utils diff --git a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go index b1de37bef31..2374686e55a 100644 --- a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go +++ b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 utils diff --git a/vendor/github.com/uber/jaeger-client-go/utils/utils.go b/vendor/github.com/uber/jaeger-client-go/utils/utils.go index 79eaa4e21c3..ac3c325d1ed 100644 --- a/vendor/github.com/uber/jaeger-client-go/utils/utils.go +++ b/vendor/github.com/uber/jaeger-client-go/utils/utils.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Copyright (c) 2017 Uber Technologies, Inc. // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// 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 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 utils diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin.go b/vendor/github.com/uber/jaeger-client-go/zipkin.go index 3667c9fbc60..636952b7f1d 100644 --- a/vendor/github.com/uber/jaeger-client-go/zipkin.go +++ b/vendor/github.com/uber/jaeger-client-go/zipkin.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go index c85b608e1c5..b2e9a3e6476 100644 --- a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go +++ b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go @@ -1,22 +1,16 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 jaeger diff --git a/vendor/github.com/uber/jaeger-lib/LICENSE b/vendor/github.com/uber/jaeger-lib/LICENSE index 546ac3c9e50..261eeb9e9f8 100644 --- a/vendor/github.com/uber/jaeger-lib/LICENSE +++ b/vendor/github.com/uber/jaeger-lib/LICENSE @@ -1,21 +1,201 @@ -The MIT License (MIT) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2016 Uber Technologies, Inc. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + 1. Definitions. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + "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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. diff --git a/vendor/github.com/uber/jaeger-lib/metrics/counter.go b/vendor/github.com/uber/jaeger-lib/metrics/counter.go index 4ba21fe21cd..2a6a43efdb4 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/counter.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/counter.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/uber/jaeger-lib/metrics/factory.go b/vendor/github.com/uber/jaeger-lib/metrics/factory.go index f59d9d2a55d..a744a890df3 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/factory.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/factory.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/uber/jaeger-lib/metrics/gauge.go b/vendor/github.com/uber/jaeger-lib/metrics/gauge.go index 4a2c1fdbe84..3c606391a09 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/gauge.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/gauge.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/uber/jaeger-lib/metrics/local.go b/vendor/github.com/uber/jaeger-lib/metrics/local.go index 1843186ad88..8c3624849cc 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/local.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/local.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/uber/jaeger-lib/metrics/metrics.go b/vendor/github.com/uber/jaeger-lib/metrics/metrics.go index d29d72f2046..0b97707b075 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/metrics.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/metrics.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go b/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go index 1db8aaa68f6..4a8abdb539f 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/stopwatch.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/uber/jaeger-lib/metrics/timer.go b/vendor/github.com/uber/jaeger-lib/metrics/timer.go index bed6d609e0d..e18d222abb4 100644 --- a/vendor/github.com/uber/jaeger-lib/metrics/timer.go +++ b/vendor/github.com/uber/jaeger-lib/metrics/timer.go @@ -1,22 +1,16 @@ // Copyright (c) 2017 Uber Technologies, Inc. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// 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 // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://www.apache.org/licenses/LICENSE-2.0 // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 metrics diff --git a/vendor/github.com/yudai/gojsondiff/LICENSE b/vendor/github.com/yudai/gojsondiff/LICENSE index 445f43cdf11..b778ed8c337 100644 --- a/vendor/github.com/yudai/gojsondiff/LICENSE +++ b/vendor/github.com/yudai/gojsondiff/LICENSE @@ -72,7 +72,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## cli.go - https://github.com/urfave/cli +## cli.go - https://github.com/codegangsta/cli Copyright (C) 2013 Jeremy Saenz All Rights Reserved. diff --git a/vendor/github.com/yudai/gojsondiff/Makefile b/vendor/github.com/yudai/gojsondiff/Makefile deleted file mode 100644 index 50ed3d601d0..00000000000 --- a/vendor/github.com/yudai/gojsondiff/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: - if [ `go fmt $(go list ./... | grep -v /vendor/) | wc -l` -gt 0 ]; then echo "go fmt error"; exit 1; fi diff --git a/vendor/github.com/yudai/gojsondiff/README.md b/vendor/github.com/yudai/gojsondiff/README.md deleted file mode 100644 index 2f0f6f8c5d2..00000000000 --- a/vendor/github.com/yudai/gojsondiff/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# Go JSON Diff (and Patch) - -[![Wercker](https://app.wercker.com/status/00d70daaf40ce277fd4f10290f097b9d/s/master)][wercker] -[![GoDoc](https://godoc.org/github.com/yudai/gojsondiff?status.svg)][godoc] -[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg)][license] - -[wercker]: https://app.wercker.com/project/bykey/00d70daaf40ce277fd4f10290f097b9d -[godoc]: https://godoc.org/github.com/yudai/gojsondiff -[license]: https://github.com/yudai/gojsondiff/blob/master/LICENSE - -## How to use - -### Installation - -```sh -go get github.com/yudai/gojsondiff -``` - -### Comparing two JSON strings - -See `jd/main.go` for how to use this library. - - -## CLI tool - -This repository contains a package that you can use as a CLI tool. - -### Installation - -```sh -go get github.com/yudai/gojsondiff/jd -``` - -### Usage - -#### Diff - -Just give two json files to the `jd` command: - -```sh -jd one.json another.json -``` - -Outputs would be something like: - -```diff - { - "arr": [ - 0: "arr0", - 1: 21, - 2: { - "num": 1, -- "str": "pek3f" -+ "str": "changed" - }, - 3: [ - 0: 0, -- 1: "1" -+ 1: "changed" - ] - ], - "bool": true, - "num_float": 39.39, - "num_int": 13, - "obj": { - "arr": [ - 0: 17, - 1: "str", - 2: { -- "str": "eafeb" -+ "str": "changed" - } - ], -+ "new": "added", -- "num": 19, - "obj": { -- "num": 14, -+ "num": 9999 -- "str": "efj3" -+ "str": "changed" - }, - "str": "bcded" - }, - "str": "abcde" - } -``` - -When you prefer the delta foramt of [jsondiffpatch](https://github.com/benjamine/jsondiffpatch), add the `-f delta` option. - -```sh -jd -f delta one.json another.json -``` - -This command shows: - -```json -{ - "arr": { - "2": { - "str": [ - "pek3f", - "changed" - ] - }, - "3": { - "1": [ - "1", - "changed" - ], - "_t": "a" - }, - "_t": "a" - }, - "obj": { - "arr": { - "2": { - "str": [ - "eafeb", - "changed" - ] - }, - "_t": "a" - }, - "new": [ - "added" - ], - "num": [ - 19, - 0, - 0 - ], - "obj": { - "num": [ - 14, - 9999 - ], - "str": [ - "efj3", - "changed" - ] - } - } -} -``` - -#### Patch - -Give a diff file in the delta format and the JSON file to the `jp` command. - -```sh -jp diff.delta one.json -``` - - -## License - -MIT License (see `LICENSE` for detail) diff --git a/vendor/github.com/yudai/gojsondiff/wercker.yml b/vendor/github.com/yudai/gojsondiff/wercker.yml deleted file mode 100644 index 1a401f87bf3..00000000000 --- a/vendor/github.com/yudai/gojsondiff/wercker.yml +++ /dev/null @@ -1,8 +0,0 @@ -box: golang:1.6.3 - -build: - steps: - - setup-go-workspace - - script: - name: test - code: make test diff --git a/vendor/github.com/yudai/golcs/LICENSE b/vendor/github.com/yudai/golcs/LICENSE index 6e61196b44b..ab7d2e0fba2 100644 --- a/vendor/github.com/yudai/golcs/LICENSE +++ b/vendor/github.com/yudai/golcs/LICENSE @@ -19,55 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -============================================================================ - -This repository is build with following third party libraries. Thank you! - - -## ginkgo - https://github.com/onsi/ginkgo - -Copyright (c) 2013-2014 Onsi Fakhouri - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -# gomega - https://github.com/onsi/gomega - -Copyright (c) 2013-2014 Onsi Fakhouri - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/yudai/golcs/README.md b/vendor/github.com/yudai/golcs/README.md deleted file mode 100644 index 8af24e9e895..00000000000 --- a/vendor/github.com/yudai/golcs/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Go Longest Common Subsequence (LCS) - -A package to calculate [LCS](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem) of slices. - -## Usage - -```sh -go get github.com/yudai/golcs -``` - -```go -import " github.com/yudai/golcs" - -left = []interface{}{1, 2, 5, 3, 1, 1, 5, 8, 3} -right = []interface{}{1, 2, 3, 3, 4, 4, 5, 1, 6} - -lcs := golcs.New(left, right) - -lcs.Values() // LCS values => []interface{}{1, 2, 5, 1} -lcs.IndexPairs() // Matched indices => [{Left: 0, Right: 0}, {Left: 1, Right: 1}, {Left: 2, Right: 6}, {Left: 4, Right: 7}] -lcs.Length() // Matched length => 4 - -lcs.Table() // Memo table -``` - -All the methods of `Lcs` cache their return values. For example, the memo table is calculated only once and reused when `Values()`, `Length()` and other methods are called. - - -## FAQ - -### How can I give `[]byte` values to `Lcs()` as its arguments? - -As `[]interface{}` is incompatible with `[]othertype` like `[]byte`, you need to create a `[]interface{}` slice and copy the values in your `[]byte` slice into it. Unfortunately, Go doesn't provide any mesure to cast a slice into `[]interface{}` with zero cost. Your copy costs O(n). - -```go -leftBytes := []byte("TGAGTA") -left = make([]interface{}, len(leftBytes)) -for i, v := range leftBytes { - left[i] = v -} - -rightBytes := []byte("GATA") -right = make([]interface{}, len(rightBytes)) -for i, v := range rightBytes { - right[i] = v -} - -lcs.New(left, right) -``` - - -## LICENSE - -The MIT license (See `LICENSE` for detail) diff --git a/vendor/github.com/yudai/golcs/golcs.go b/vendor/github.com/yudai/golcs/golcs.go index cd653d16695..1dd2d568cfa 100644 --- a/vendor/github.com/yudai/golcs/golcs.go +++ b/vendor/github.com/yudai/golcs/golcs.go @@ -1,17 +1,33 @@ +// package lcs provides functions to calculate Longest Common Subsequence (LCS) +// values from two arbitrary arrays. package lcs import ( + "context" "reflect" ) +// Lcs is the interface to calculate the LCS of two arrays. type Lcs interface { + // Values calculates the LCS value of the two arrays. Values() (values []interface{}) + // ValueContext is a context aware version of Values() + ValuesContext(ctx context.Context) (values []interface{}, err error) + // IndexPairs calculates paris of indices which have the same value in LCS. IndexPairs() (pairs []IndexPair) + // IndexPairsContext is a context aware version of IndexPairs() + IndexPairsContext(ctx context.Context) (pairs []IndexPair, err error) + // Length calculates the length of the LCS. Length() (length int) + // LengthContext is a context aware version of Length() + LengthContext(ctx context.Context) (length int, err error) + // Left returns one of the two arrays to be compared. Left() (leftValues []interface{}) + // Right returns the other of the two arrays to be compared. Right() (righttValues []interface{}) } +// IndexPair represents an pair of indeices in the Left and Right arrays found in the LCS value. type IndexPair struct { Left int Right int @@ -26,6 +42,7 @@ type lcs struct { values []interface{} } +// New creates a new LCS calculator from two arrays. func New(left, right []interface{}) Lcs { return &lcs{ left: left, @@ -36,9 +53,16 @@ func New(left, right []interface{}) Lcs { } } +// Table implements Lcs.Table() func (lcs *lcs) Table() (table [][]int) { + table, _ = lcs.TableContext(context.Background()) + return table +} + +// Table implements Lcs.TableContext() +func (lcs *lcs) TableContext(ctx context.Context) (table [][]int, err error) { if lcs.table != nil { - return lcs.table + return lcs.table, nil } sizeX := len(lcs.left) + 1 @@ -50,6 +74,12 @@ func (lcs *lcs) Table() (table [][]int) { } for y := 1; y < sizeY; y++ { + select { // check in each y to save some time + case <-ctx.Done(): + return nil, ctx.Err() + default: + // nop + } for x := 1; x < sizeX; x++ { increment := 0 if reflect.DeepEqual(lcs.left[x-1], lcs.right[y-1]) { @@ -60,20 +90,41 @@ func (lcs *lcs) Table() (table [][]int) { } lcs.table = table - return + return table, nil } +// Table implements Lcs.Length() func (lcs *lcs) Length() (length int) { - length = lcs.Table()[len(lcs.left)][len(lcs.right)] - return + length, _ = lcs.LengthContext(context.Background()) + return length } +// Table implements Lcs.LengthContext() +func (lcs *lcs) LengthContext(ctx context.Context) (length int, err error) { + table, err := lcs.TableContext(ctx) + if err != nil { + return 0, err + } + return table[len(lcs.left)][len(lcs.right)], nil +} + +// Table implements Lcs.IndexPairs() func (lcs *lcs) IndexPairs() (pairs []IndexPair) { + pairs, _ = lcs.IndexPairsContext(context.Background()) + return pairs +} + +// Table implements Lcs.IndexPairsContext() +func (lcs *lcs) IndexPairsContext(ctx context.Context) (pairs []IndexPair, err error) { if lcs.indexPairs != nil { - return lcs.indexPairs + return lcs.indexPairs, nil + } + + table, err := lcs.TableContext(ctx) + if err != nil { + return nil, err } - table := lcs.Table() pairs = make([]IndexPair, table[len(table)-1][len(table[0])-1]) for x, y := len(lcs.left), len(lcs.right); x > 0 && y > 0; { @@ -92,28 +143,42 @@ func (lcs *lcs) IndexPairs() (pairs []IndexPair) { lcs.indexPairs = pairs - return + return pairs, nil } +// Table implements Lcs.Values() func (lcs *lcs) Values() (values []interface{}) { + values, _ = lcs.ValuesContext(context.Background()) + return values +} + +// Table implements Lcs.ValuesContext() +func (lcs *lcs) ValuesContext(ctx context.Context) (values []interface{}, err error) { if lcs.values != nil { - return lcs.values + return lcs.values, nil + } + + pairs, err := lcs.IndexPairsContext(ctx) + if err != nil { + return nil, err } - pairs := lcs.IndexPairs() values = make([]interface{}, len(pairs)) for i, pair := range pairs { values[i] = lcs.left[pair.Left] } lcs.values = values - return + + return values, nil } +// Table implements Lcs.Left() func (lcs *lcs) Left() (leftValues []interface{}) { leftValues = lcs.left return } +// Table implements Lcs.Right() func (lcs *lcs) Right() (rightValues []interface{}) { rightValues = lcs.right return diff --git a/vendor/golang.org/x/crypto/AUTHORS b/vendor/golang.org/x/crypto/AUTHORS new file mode 100644 index 00000000000..2b00ddba0df --- /dev/null +++ b/vendor/golang.org/x/crypto/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at https://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/crypto/CONTRIBUTORS b/vendor/golang.org/x/crypto/CONTRIBUTORS new file mode 100644 index 00000000000..1fbd3e976fa --- /dev/null +++ b/vendor/golang.org/x/crypto/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at https://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/net/AUTHORS b/vendor/golang.org/x/net/AUTHORS new file mode 100644 index 00000000000..15167cd746c --- /dev/null +++ b/vendor/golang.org/x/net/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/net/CONTRIBUTORS b/vendor/golang.org/x/net/CONTRIBUTORS new file mode 100644 index 00000000000..1c4577e9680 --- /dev/null +++ b/vendor/golang.org/x/net/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go index 66aff7cb4a0..a3c021d3f88 100644 --- a/vendor/golang.org/x/net/context/context.go +++ b/vendor/golang.org/x/net/context/context.go @@ -5,9 +5,11 @@ // Package context defines the Context type, which carries deadlines, // cancelation signals, and other request-scoped values across API boundaries // and between processes. +// As of Go 1.7 this package is available in the standard library under the +// name context. https://golang.org/pkg/context. // // Incoming requests to a server should create a Context, and outgoing calls to -// servers should accept a Context. The chain of function calls between must +// servers should accept a Context. The chain of function calls between must // propagate the Context, optionally replacing it with a modified copy created // using WithDeadline, WithTimeout, WithCancel, or WithValue. // @@ -16,14 +18,14 @@ // propagation: // // Do not store Contexts inside a struct type; instead, pass a Context -// explicitly to each function that needs it. The Context should be the first +// explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // // func DoSomething(ctx context.Context, arg Arg) error { // // ... use ctx ... // } // -// Do not pass a nil Context, even if a function permits it. Pass context.TODO +// Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. // // Use context Values only for request-scoped data that transits processes and @@ -34,399 +36,21 @@ // // See http://blog.golang.org/context for example code for a server that uses // Contexts. -package context - -import ( - "errors" - "fmt" - "sync" - "time" -) - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - // - // WithCancel arranges for Done to be closed when cancel is called; - // WithDeadline arranges for Done to be closed when the deadline - // expires; WithTimeout arranges for Done to be closed when the timeout - // elapses. - // - // Done is provided for use in select statements: - // - // // DoSomething calls DoSomethingSlow and returns as soon as - // // it returns or ctx.Done is closed. - // func DoSomething(ctx context.Context) (Result, error) { - // c := make(chan Result, 1) - // go func() { c <- DoSomethingSlow(ctx) }() - // select { - // case res := <-c: - // return res, nil - // case <-ctx.Done(): - // return nil, ctx.Err() - // } - // } - // - // See http://blog.golang.org/pipelines for more examples of how to use - // a Done channel for cancelation. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - // - // A key identifies a specific value in a Context. Functions that wish - // to store values in Context typically allocate a key in a global - // variable then use that key as the argument to context.WithValue and - // Context.Value. A key can be any type that supports equality; - // packages should define keys as an unexported type to avoid - // collisions. - // - // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: - // - // // Package user defines a User type that's stored in Contexts. - // package user - // - // import "golang.org/x/net/context" - // - // // User is the type of value stored in the Contexts. - // type User struct {...} - // - // // key is an unexported type for keys defined in this package. - // // This prevents collisions with keys defined in other packages. - // type key int - // - // // userKey is the key for user.User values in Contexts. It is - // // unexported; clients use user.NewContext and user.FromContext - // // instead of using this key directly. - // var userKey key = 0 - // - // // NewContext returns a new Context that carries value u. - // func NewContext(ctx context.Context, u *User) context.Context { - // return context.WithValue(ctx, userKey, u) - // } - // - // // FromContext returns the User value stored in ctx, if any. - // func FromContext(ctx context.Context) (*User, bool) { - // u, ok := ctx.Value(userKey).(*User) - // return u, ok - // } - Value(key interface{}) interface{} -} - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = errors.New("context canceled") - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = errors.New("context deadline exceeded") - -// An emptyCtx is never canceled, has no values, and has no deadline. It is not -// struct{}, since vars of this type must have distinct addresses. -type emptyCtx int - -func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { - return -} - -func (*emptyCtx) Done() <-chan struct{} { - return nil -} - -func (*emptyCtx) Err() error { - return nil -} - -func (*emptyCtx) Value(key interface{}) interface{} { - return nil -} - -func (e *emptyCtx) String() string { - switch e { - case background: - return "context.Background" - case todo: - return "context.TODO" - } - return "unknown empty Context" -} - -var ( - background = new(emptyCtx) - todo = new(emptyCtx) -) +package context // import "golang.org/x/net/context" // Background returns a non-nil, empty Context. It is never canceled, has no -// values, and has no deadline. It is typically used by the main function, +// values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming // requests. func Background() Context { return background } -// TODO returns a non-nil, empty Context. Code should use context.TODO when -// it's unclear which Context to use or it's is not yet available (because the +// TODO returns a non-nil, empty Context. Code should use context.TODO when +// it's unclear which Context to use or it is not yet available (because the // surrounding function has not yet been extended to accept a Context // parameter). TODO is recognized by static analysis tools that determine // whether Contexts are propagated correctly in a program. func TODO() Context { return todo } - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc func() - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - c := newCancelCtx(parent) - propagateCancel(parent, &c) - return &c, func() { c.cancel(true, Canceled) } -} - -// newCancelCtx returns an initialized cancelCtx. -func newCancelCtx(parent Context) cancelCtx { - return cancelCtx{ - Context: parent, - done: make(chan struct{}), - } -} - -// propagateCancel arranges for child to be canceled when parent is. -func propagateCancel(parent Context, child canceler) { - if parent.Done() == nil { - return // parent is never canceled - } - if p, ok := parentCancelCtx(parent); ok { - p.mu.Lock() - if p.err != nil { - // parent has already been canceled - child.cancel(false, p.err) - } else { - if p.children == nil { - p.children = make(map[canceler]bool) - } - p.children[child] = true - } - p.mu.Unlock() - } else { - go func() { - select { - case <-parent.Done(): - child.cancel(false, parent.Err()) - case <-child.Done(): - } - }() - } -} - -// parentCancelCtx follows a chain of parent references until it finds a -// *cancelCtx. This function understands how each of the concrete types in this -// package represents its parent. -func parentCancelCtx(parent Context) (*cancelCtx, bool) { - for { - switch c := parent.(type) { - case *cancelCtx: - return c, true - case *timerCtx: - return &c.cancelCtx, true - case *valueCtx: - parent = c.Context - default: - return nil, false - } - } -} - -// A canceler is a context type that can be canceled directly. The -// implementations are *cancelCtx and *timerCtx. -type canceler interface { - cancel(removeFromParent bool, err error) - Done() <-chan struct{} -} - -// A cancelCtx can be canceled. When canceled, it also cancels any children -// that implement canceler. -type cancelCtx struct { - Context - - done chan struct{} // closed by the first cancel call. - - mu sync.Mutex - children map[canceler]bool // set to nil by the first cancel call - err error // set to non-nil by the first cancel call -} - -func (c *cancelCtx) Done() <-chan struct{} { - return c.done -} - -func (c *cancelCtx) Err() error { - c.mu.Lock() - defer c.mu.Unlock() - return c.err -} - -func (c *cancelCtx) String() string { - return fmt.Sprintf("%v.WithCancel", c.Context) -} - -// cancel closes c.done, cancels each of c's children, and, if -// removeFromParent is true, removes c from its parent's children. -func (c *cancelCtx) cancel(removeFromParent bool, err error) { - if err == nil { - panic("context: internal error: missing cancel error") - } - c.mu.Lock() - if c.err != nil { - c.mu.Unlock() - return // already canceled - } - c.err = err - close(c.done) - for child := range c.children { - // NOTE: acquiring the child's lock while holding parent's lock. - child.cancel(false, err) - } - c.children = nil - c.mu.Unlock() - - if removeFromParent { - if p, ok := parentCancelCtx(c.Context); ok { - p.mu.Lock() - if p.children != nil { - delete(p.children, c) - } - p.mu.Unlock() - } - } -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with the deadline -// timer, so code should call cancel as soon as the operations running in this -// Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { - // The current deadline is already sooner than the new one. - return WithCancel(parent) - } - c := &timerCtx{ - cancelCtx: newCancelCtx(parent), - deadline: deadline, - } - propagateCancel(parent, c) - d := deadline.Sub(time.Now()) - if d <= 0 { - c.cancel(true, DeadlineExceeded) // deadline has already passed - return c, func() { c.cancel(true, Canceled) } - } - c.mu.Lock() - defer c.mu.Unlock() - if c.err == nil { - c.timer = time.AfterFunc(d, func() { - c.cancel(true, DeadlineExceeded) - }) - } - return c, func() { c.cancel(true, Canceled) } -} - -// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to -// implement Done and Err. It implements cancel by stopping its timer then -// delegating to cancelCtx.cancel. -type timerCtx struct { - cancelCtx - timer *time.Timer // Under cancelCtx.mu. - - deadline time.Time -} - -func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { - return c.deadline, true -} - -func (c *timerCtx) String() string { - return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) -} - -func (c *timerCtx) cancel(removeFromParent bool, err error) { - c.cancelCtx.cancel(removeFromParent, err) - c.mu.Lock() - if c.timer != nil { - c.timer.Stop() - c.timer = nil - } - c.mu.Unlock() -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with the deadline -// timer, so code should call cancel as soon as the operations running in this -// Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return &valueCtx{parent, key, val} -} - -// A valueCtx carries a key-value pair. It implements Value for that key and -// delegates all other calls to the embedded Context. -type valueCtx struct { - Context - key, val interface{} -} - -func (c *valueCtx) String() string { - return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) -} - -func (c *valueCtx) Value(key interface{}) interface{} { - if c.key == key { - return c.val - } - return c.Context.Value(key) -} diff --git a/vendor/golang.org/x/net/context/context_test.go b/vendor/golang.org/x/net/context/context_test.go deleted file mode 100644 index 82d2494a492..00000000000 --- a/vendor/golang.org/x/net/context/context_test.go +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright 2014 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 context - -import ( - "fmt" - "math/rand" - "runtime" - "strings" - "sync" - "testing" - "time" -) - -// otherContext is a Context that's not one of the types defined in context.go. -// This lets us test code paths that differ based on the underlying type of the -// Context. -type otherContext struct { - Context -} - -func TestBackground(t *testing.T) { - c := Background() - if c == nil { - t.Fatalf("Background returned nil") - } - select { - case x := <-c.Done(): - t.Errorf("<-c.Done() == %v want nothing (it should block)", x) - default: - } - if got, want := fmt.Sprint(c), "context.Background"; got != want { - t.Errorf("Background().String() = %q want %q", got, want) - } -} - -func TestTODO(t *testing.T) { - c := TODO() - if c == nil { - t.Fatalf("TODO returned nil") - } - select { - case x := <-c.Done(): - t.Errorf("<-c.Done() == %v want nothing (it should block)", x) - default: - } - if got, want := fmt.Sprint(c), "context.TODO"; got != want { - t.Errorf("TODO().String() = %q want %q", got, want) - } -} - -func TestWithCancel(t *testing.T) { - c1, cancel := WithCancel(Background()) - - if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want { - t.Errorf("c1.String() = %q want %q", got, want) - } - - o := otherContext{c1} - c2, _ := WithCancel(o) - contexts := []Context{c1, o, c2} - - for i, c := range contexts { - if d := c.Done(); d == nil { - t.Errorf("c[%d].Done() == %v want non-nil", i, d) - } - if e := c.Err(); e != nil { - t.Errorf("c[%d].Err() == %v want nil", i, e) - } - - select { - case x := <-c.Done(): - t.Errorf("<-c.Done() == %v want nothing (it should block)", x) - default: - } - } - - cancel() - time.Sleep(100 * time.Millisecond) // let cancelation propagate - - for i, c := range contexts { - select { - case <-c.Done(): - default: - t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i) - } - if e := c.Err(); e != Canceled { - t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled) - } - } -} - -func TestParentFinishesChild(t *testing.T) { - // Context tree: - // parent -> cancelChild - // parent -> valueChild -> timerChild - parent, cancel := WithCancel(Background()) - cancelChild, stop := WithCancel(parent) - defer stop() - valueChild := WithValue(parent, "key", "value") - timerChild, stop := WithTimeout(valueChild, 10000*time.Hour) - defer stop() - - select { - case x := <-parent.Done(): - t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) - case x := <-cancelChild.Done(): - t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x) - case x := <-timerChild.Done(): - t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x) - case x := <-valueChild.Done(): - t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x) - default: - } - - // The parent's children should contain the two cancelable children. - pc := parent.(*cancelCtx) - cc := cancelChild.(*cancelCtx) - tc := timerChild.(*timerCtx) - pc.mu.Lock() - if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] { - t.Errorf("bad linkage: pc.children = %v, want %v and %v", - pc.children, cc, tc) - } - pc.mu.Unlock() - - if p, ok := parentCancelCtx(cc.Context); !ok || p != pc { - t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc) - } - if p, ok := parentCancelCtx(tc.Context); !ok || p != pc { - t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc) - } - - cancel() - - pc.mu.Lock() - if len(pc.children) != 0 { - t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children) - } - pc.mu.Unlock() - - // parent and children should all be finished. - check := func(ctx Context, name string) { - select { - case <-ctx.Done(): - default: - t.Errorf("<-%s.Done() blocked, but shouldn't have", name) - } - if e := ctx.Err(); e != Canceled { - t.Errorf("%s.Err() == %v want %v", name, e, Canceled) - } - } - check(parent, "parent") - check(cancelChild, "cancelChild") - check(valueChild, "valueChild") - check(timerChild, "timerChild") - - // WithCancel should return a canceled context on a canceled parent. - precanceledChild := WithValue(parent, "key", "value") - select { - case <-precanceledChild.Done(): - default: - t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have") - } - if e := precanceledChild.Err(); e != Canceled { - t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled) - } -} - -func TestChildFinishesFirst(t *testing.T) { - cancelable, stop := WithCancel(Background()) - defer stop() - for _, parent := range []Context{Background(), cancelable} { - child, cancel := WithCancel(parent) - - select { - case x := <-parent.Done(): - t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) - case x := <-child.Done(): - t.Errorf("<-child.Done() == %v want nothing (it should block)", x) - default: - } - - cc := child.(*cancelCtx) - pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background() - if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) { - t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok) - } - - if pcok { - pc.mu.Lock() - if len(pc.children) != 1 || !pc.children[cc] { - t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc) - } - pc.mu.Unlock() - } - - cancel() - - if pcok { - pc.mu.Lock() - if len(pc.children) != 0 { - t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children) - } - pc.mu.Unlock() - } - - // child should be finished. - select { - case <-child.Done(): - default: - t.Errorf("<-child.Done() blocked, but shouldn't have") - } - if e := child.Err(); e != Canceled { - t.Errorf("child.Err() == %v want %v", e, Canceled) - } - - // parent should not be finished. - select { - case x := <-parent.Done(): - t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) - default: - } - if e := parent.Err(); e != nil { - t.Errorf("parent.Err() == %v want nil", e) - } - } -} - -func testDeadline(c Context, wait time.Duration, t *testing.T) { - select { - case <-time.After(wait): - t.Fatalf("context should have timed out") - case <-c.Done(): - } - if e := c.Err(); e != DeadlineExceeded { - t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded) - } -} - -func TestDeadline(t *testing.T) { - c, _ := WithDeadline(Background(), time.Now().Add(100*time.Millisecond)) - if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { - t.Errorf("c.String() = %q want prefix %q", got, prefix) - } - testDeadline(c, 200*time.Millisecond, t) - - c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond)) - o := otherContext{c} - testDeadline(o, 200*time.Millisecond, t) - - c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond)) - o = otherContext{c} - c, _ = WithDeadline(o, time.Now().Add(300*time.Millisecond)) - testDeadline(c, 200*time.Millisecond, t) -} - -func TestTimeout(t *testing.T) { - c, _ := WithTimeout(Background(), 100*time.Millisecond) - if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { - t.Errorf("c.String() = %q want prefix %q", got, prefix) - } - testDeadline(c, 200*time.Millisecond, t) - - c, _ = WithTimeout(Background(), 100*time.Millisecond) - o := otherContext{c} - testDeadline(o, 200*time.Millisecond, t) - - c, _ = WithTimeout(Background(), 100*time.Millisecond) - o = otherContext{c} - c, _ = WithTimeout(o, 300*time.Millisecond) - testDeadline(c, 200*time.Millisecond, t) -} - -func TestCanceledTimeout(t *testing.T) { - c, _ := WithTimeout(Background(), 200*time.Millisecond) - o := otherContext{c} - c, cancel := WithTimeout(o, 400*time.Millisecond) - cancel() - time.Sleep(100 * time.Millisecond) // let cancelation propagate - select { - case <-c.Done(): - default: - t.Errorf("<-c.Done() blocked, but shouldn't have") - } - if e := c.Err(); e != Canceled { - t.Errorf("c.Err() == %v want %v", e, Canceled) - } -} - -type key1 int -type key2 int - -var k1 = key1(1) -var k2 = key2(1) // same int as k1, different type -var k3 = key2(3) // same type as k2, different int - -func TestValues(t *testing.T) { - check := func(c Context, nm, v1, v2, v3 string) { - if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 { - t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0) - } - if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 { - t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0) - } - if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 { - t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0) - } - } - - c0 := Background() - check(c0, "c0", "", "", "") - - c1 := WithValue(Background(), k1, "c1k1") - check(c1, "c1", "c1k1", "", "") - - if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want { - t.Errorf("c.String() = %q want %q", got, want) - } - - c2 := WithValue(c1, k2, "c2k2") - check(c2, "c2", "c1k1", "c2k2", "") - - c3 := WithValue(c2, k3, "c3k3") - check(c3, "c2", "c1k1", "c2k2", "c3k3") - - c4 := WithValue(c3, k1, nil) - check(c4, "c4", "", "c2k2", "c3k3") - - o0 := otherContext{Background()} - check(o0, "o0", "", "", "") - - o1 := otherContext{WithValue(Background(), k1, "c1k1")} - check(o1, "o1", "c1k1", "", "") - - o2 := WithValue(o1, k2, "o2k2") - check(o2, "o2", "c1k1", "o2k2", "") - - o3 := otherContext{c4} - check(o3, "o3", "", "c2k2", "c3k3") - - o4 := WithValue(o3, k3, nil) - check(o4, "o4", "", "c2k2", "") -} - -func TestAllocs(t *testing.T) { - bg := Background() - for _, test := range []struct { - desc string - f func() - limit float64 - gccgoLimit float64 - }{ - { - desc: "Background()", - f: func() { Background() }, - limit: 0, - gccgoLimit: 0, - }, - { - desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1), - f: func() { - c := WithValue(bg, k1, nil) - c.Value(k1) - }, - limit: 3, - gccgoLimit: 3, - }, - { - desc: "WithTimeout(bg, 15*time.Millisecond)", - f: func() { - c, _ := WithTimeout(bg, 15*time.Millisecond) - <-c.Done() - }, - limit: 8, - gccgoLimit: 13, - }, - { - desc: "WithCancel(bg)", - f: func() { - c, cancel := WithCancel(bg) - cancel() - <-c.Done() - }, - limit: 5, - gccgoLimit: 8, - }, - { - desc: "WithTimeout(bg, 100*time.Millisecond)", - f: func() { - c, cancel := WithTimeout(bg, 100*time.Millisecond) - cancel() - <-c.Done() - }, - limit: 8, - gccgoLimit: 25, - }, - } { - limit := test.limit - if runtime.Compiler == "gccgo" { - // gccgo does not yet do escape analysis. - // TOOD(iant): Remove this when gccgo does do escape analysis. - limit = test.gccgoLimit - } - if n := testing.AllocsPerRun(100, test.f); n > limit { - t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit)) - } - } -} - -func TestSimultaneousCancels(t *testing.T) { - root, cancel := WithCancel(Background()) - m := map[Context]CancelFunc{root: cancel} - q := []Context{root} - // Create a tree of contexts. - for len(q) != 0 && len(m) < 100 { - parent := q[0] - q = q[1:] - for i := 0; i < 4; i++ { - ctx, cancel := WithCancel(parent) - m[ctx] = cancel - q = append(q, ctx) - } - } - // Start all the cancels in a random order. - var wg sync.WaitGroup - wg.Add(len(m)) - for _, cancel := range m { - go func(cancel CancelFunc) { - cancel() - wg.Done() - }(cancel) - } - // Wait on all the contexts in a random order. - for ctx := range m { - select { - case <-ctx.Done(): - case <-time.After(1 * time.Second): - buf := make([]byte, 10<<10) - n := runtime.Stack(buf, true) - t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n]) - } - } - // Wait for all the cancel functions to return. - done := make(chan struct{}) - go func() { - wg.Wait() - close(done) - }() - select { - case <-done: - case <-time.After(1 * time.Second): - buf := make([]byte, 10<<10) - n := runtime.Stack(buf, true) - t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n]) - } -} - -func TestInterlockedCancels(t *testing.T) { - parent, cancelParent := WithCancel(Background()) - child, cancelChild := WithCancel(parent) - go func() { - parent.Done() - cancelChild() - }() - cancelParent() - select { - case <-child.Done(): - case <-time.After(1 * time.Second): - buf := make([]byte, 10<<10) - n := runtime.Stack(buf, true) - t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n]) - } -} - -func TestLayersCancel(t *testing.T) { - testLayers(t, time.Now().UnixNano(), false) -} - -func TestLayersTimeout(t *testing.T) { - testLayers(t, time.Now().UnixNano(), true) -} - -func testLayers(t *testing.T, seed int64, testTimeout bool) { - rand.Seed(seed) - errorf := func(format string, a ...interface{}) { - t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...) - } - const ( - timeout = 200 * time.Millisecond - minLayers = 30 - ) - type value int - var ( - vals []*value - cancels []CancelFunc - numTimers int - ctx = Background() - ) - for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ { - switch rand.Intn(3) { - case 0: - v := new(value) - ctx = WithValue(ctx, v, v) - vals = append(vals, v) - case 1: - var cancel CancelFunc - ctx, cancel = WithCancel(ctx) - cancels = append(cancels, cancel) - case 2: - var cancel CancelFunc - ctx, cancel = WithTimeout(ctx, timeout) - cancels = append(cancels, cancel) - numTimers++ - } - } - checkValues := func(when string) { - for _, key := range vals { - if val := ctx.Value(key).(*value); key != val { - errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key) - } - } - } - select { - case <-ctx.Done(): - errorf("ctx should not be canceled yet") - default: - } - if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) { - t.Errorf("ctx.String() = %q want prefix %q", s, prefix) - } - t.Log(ctx) - checkValues("before cancel") - if testTimeout { - select { - case <-ctx.Done(): - case <-time.After(timeout + timeout/10): - errorf("ctx should have timed out") - } - checkValues("after timeout") - } else { - cancel := cancels[rand.Intn(len(cancels))] - cancel() - select { - case <-ctx.Done(): - default: - errorf("ctx should be canceled") - } - checkValues("after cancel") - } -} diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go new file mode 100644 index 00000000000..d20f52b7de9 --- /dev/null +++ b/vendor/golang.org/x/net/context/go17.go @@ -0,0 +1,72 @@ +// Copyright 2016 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. + +// +build go1.7 + +package context + +import ( + "context" // standard library's context, as of Go 1.7 + "time" +) + +var ( + todo = context.TODO() + background = context.Background() +) + +// Canceled is the error returned by Context.Err when the context is canceled. +var Canceled = context.Canceled + +// DeadlineExceeded is the error returned by Context.Err when the context's +// deadline passes. +var DeadlineExceeded = context.DeadlineExceeded + +// WithCancel returns a copy of parent with a new Done channel. The returned +// context's Done channel is closed when the returned cancel function is called +// or when the parent context's Done channel is closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { + ctx, f := context.WithCancel(parent) + return ctx, CancelFunc(f) +} + +// WithDeadline returns a copy of the parent context with the deadline adjusted +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// context's Done channel is closed when the deadline expires, when the returned +// cancel function is called, or when the parent context's Done channel is +// closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { + ctx, f := context.WithDeadline(parent, deadline) + return ctx, CancelFunc(f) +} + +// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete: +// +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } +func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { + return WithDeadline(parent, time.Now().Add(timeout)) +} + +// WithValue returns a copy of parent in which the value associated with key is +// val. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +func WithValue(parent Context, key interface{}, val interface{}) Context { + return context.WithValue(parent, key, val) +} diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go new file mode 100644 index 00000000000..d88bd1db127 --- /dev/null +++ b/vendor/golang.org/x/net/context/go19.go @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +// +build go1.9 + +package context + +import "context" // standard library's context, as of Go 1.7 + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context = context.Context + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc = context.CancelFunc diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go new file mode 100644 index 00000000000..0f35592df51 --- /dev/null +++ b/vendor/golang.org/x/net/context/pre_go17.go @@ -0,0 +1,300 @@ +// Copyright 2014 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. + +// +build !go1.7 + +package context + +import ( + "errors" + "fmt" + "sync" + "time" +) + +// An emptyCtx is never canceled, has no values, and has no deadline. It is not +// struct{}, since vars of this type must have distinct addresses. +type emptyCtx int + +func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { + return +} + +func (*emptyCtx) Done() <-chan struct{} { + return nil +} + +func (*emptyCtx) Err() error { + return nil +} + +func (*emptyCtx) Value(key interface{}) interface{} { + return nil +} + +func (e *emptyCtx) String() string { + switch e { + case background: + return "context.Background" + case todo: + return "context.TODO" + } + return "unknown empty Context" +} + +var ( + background = new(emptyCtx) + todo = new(emptyCtx) +) + +// Canceled is the error returned by Context.Err when the context is canceled. +var Canceled = errors.New("context canceled") + +// DeadlineExceeded is the error returned by Context.Err when the context's +// deadline passes. +var DeadlineExceeded = errors.New("context deadline exceeded") + +// WithCancel returns a copy of parent with a new Done channel. The returned +// context's Done channel is closed when the returned cancel function is called +// or when the parent context's Done channel is closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { + c := newCancelCtx(parent) + propagateCancel(parent, c) + return c, func() { c.cancel(true, Canceled) } +} + +// newCancelCtx returns an initialized cancelCtx. +func newCancelCtx(parent Context) *cancelCtx { + return &cancelCtx{ + Context: parent, + done: make(chan struct{}), + } +} + +// propagateCancel arranges for child to be canceled when parent is. +func propagateCancel(parent Context, child canceler) { + if parent.Done() == nil { + return // parent is never canceled + } + if p, ok := parentCancelCtx(parent); ok { + p.mu.Lock() + if p.err != nil { + // parent has already been canceled + child.cancel(false, p.err) + } else { + if p.children == nil { + p.children = make(map[canceler]bool) + } + p.children[child] = true + } + p.mu.Unlock() + } else { + go func() { + select { + case <-parent.Done(): + child.cancel(false, parent.Err()) + case <-child.Done(): + } + }() + } +} + +// parentCancelCtx follows a chain of parent references until it finds a +// *cancelCtx. This function understands how each of the concrete types in this +// package represents its parent. +func parentCancelCtx(parent Context) (*cancelCtx, bool) { + for { + switch c := parent.(type) { + case *cancelCtx: + return c, true + case *timerCtx: + return c.cancelCtx, true + case *valueCtx: + parent = c.Context + default: + return nil, false + } + } +} + +// removeChild removes a context from its parent. +func removeChild(parent Context, child canceler) { + p, ok := parentCancelCtx(parent) + if !ok { + return + } + p.mu.Lock() + if p.children != nil { + delete(p.children, child) + } + p.mu.Unlock() +} + +// A canceler is a context type that can be canceled directly. The +// implementations are *cancelCtx and *timerCtx. +type canceler interface { + cancel(removeFromParent bool, err error) + Done() <-chan struct{} +} + +// A cancelCtx can be canceled. When canceled, it also cancels any children +// that implement canceler. +type cancelCtx struct { + Context + + done chan struct{} // closed by the first cancel call. + + mu sync.Mutex + children map[canceler]bool // set to nil by the first cancel call + err error // set to non-nil by the first cancel call +} + +func (c *cancelCtx) Done() <-chan struct{} { + return c.done +} + +func (c *cancelCtx) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *cancelCtx) String() string { + return fmt.Sprintf("%v.WithCancel", c.Context) +} + +// cancel closes c.done, cancels each of c's children, and, if +// removeFromParent is true, removes c from its parent's children. +func (c *cancelCtx) cancel(removeFromParent bool, err error) { + if err == nil { + panic("context: internal error: missing cancel error") + } + c.mu.Lock() + if c.err != nil { + c.mu.Unlock() + return // already canceled + } + c.err = err + close(c.done) + for child := range c.children { + // NOTE: acquiring the child's lock while holding parent's lock. + child.cancel(false, err) + } + c.children = nil + c.mu.Unlock() + + if removeFromParent { + removeChild(c.Context, c) + } +} + +// WithDeadline returns a copy of the parent context with the deadline adjusted +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// context's Done channel is closed when the deadline expires, when the returned +// cancel function is called, or when the parent context's Done channel is +// closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { + if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { + // The current deadline is already sooner than the new one. + return WithCancel(parent) + } + c := &timerCtx{ + cancelCtx: newCancelCtx(parent), + deadline: deadline, + } + propagateCancel(parent, c) + d := deadline.Sub(time.Now()) + if d <= 0 { + c.cancel(true, DeadlineExceeded) // deadline has already passed + return c, func() { c.cancel(true, Canceled) } + } + c.mu.Lock() + defer c.mu.Unlock() + if c.err == nil { + c.timer = time.AfterFunc(d, func() { + c.cancel(true, DeadlineExceeded) + }) + } + return c, func() { c.cancel(true, Canceled) } +} + +// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to +// implement Done and Err. It implements cancel by stopping its timer then +// delegating to cancelCtx.cancel. +type timerCtx struct { + *cancelCtx + timer *time.Timer // Under cancelCtx.mu. + + deadline time.Time +} + +func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { + return c.deadline, true +} + +func (c *timerCtx) String() string { + return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) +} + +func (c *timerCtx) cancel(removeFromParent bool, err error) { + c.cancelCtx.cancel(false, err) + if removeFromParent { + // Remove this timerCtx from its parent cancelCtx's children. + removeChild(c.cancelCtx.Context, c) + } + c.mu.Lock() + if c.timer != nil { + c.timer.Stop() + c.timer = nil + } + c.mu.Unlock() +} + +// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete: +// +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } +func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { + return WithDeadline(parent, time.Now().Add(timeout)) +} + +// WithValue returns a copy of parent in which the value associated with key is +// val. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +func WithValue(parent Context, key interface{}, val interface{}) Context { + return &valueCtx{parent, key, val} +} + +// A valueCtx carries a key-value pair. It implements Value for that key and +// delegates all other calls to the embedded Context. +type valueCtx struct { + Context + key, val interface{} +} + +func (c *valueCtx) String() string { + return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) +} + +func (c *valueCtx) Value(key interface{}) interface{} { + if c.key == key { + return c.val + } + return c.Context.Value(key) +} diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go new file mode 100644 index 00000000000..b105f80be4f --- /dev/null +++ b/vendor/golang.org/x/net/context/pre_go19.go @@ -0,0 +1,109 @@ +// Copyright 2014 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. + +// +build !go1.9 + +package context + +import "time" + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context interface { + // Deadline returns the time when work done on behalf of this context + // should be canceled. Deadline returns ok==false when no deadline is + // set. Successive calls to Deadline return the same results. + Deadline() (deadline time.Time, ok bool) + + // Done returns a channel that's closed when work done on behalf of this + // context should be canceled. Done may return nil if this context can + // never be canceled. Successive calls to Done return the same value. + // + // WithCancel arranges for Done to be closed when cancel is called; + // WithDeadline arranges for Done to be closed when the deadline + // expires; WithTimeout arranges for Done to be closed when the timeout + // elapses. + // + // Done is provided for use in select statements: + // + // // Stream generates values with DoSomething and sends them to out + // // until DoSomething returns an error or ctx.Done is closed. + // func Stream(ctx context.Context, out chan<- Value) error { + // for { + // v, err := DoSomething(ctx) + // if err != nil { + // return err + // } + // select { + // case <-ctx.Done(): + // return ctx.Err() + // case out <- v: + // } + // } + // } + // + // See http://blog.golang.org/pipelines for more examples of how to use + // a Done channel for cancelation. + Done() <-chan struct{} + + // Err returns a non-nil error value after Done is closed. Err returns + // Canceled if the context was canceled or DeadlineExceeded if the + // context's deadline passed. No other values for Err are defined. + // After Done is closed, successive calls to Err return the same value. + Err() error + + // Value returns the value associated with this context for key, or nil + // if no value is associated with key. Successive calls to Value with + // the same key returns the same result. + // + // Use context values only for request-scoped data that transits + // processes and API boundaries, not for passing optional parameters to + // functions. + // + // A key identifies a specific value in a Context. Functions that wish + // to store values in Context typically allocate a key in a global + // variable then use that key as the argument to context.WithValue and + // Context.Value. A key can be any type that supports equality; + // packages should define keys as an unexported type to avoid + // collisions. + // + // Packages that define a Context key should provide type-safe accessors + // for the values stores using that key: + // + // // Package user defines a User type that's stored in Contexts. + // package user + // + // import "golang.org/x/net/context" + // + // // User is the type of value stored in the Contexts. + // type User struct {...} + // + // // key is an unexported type for keys defined in this package. + // // This prevents collisions with keys defined in other packages. + // type key int + // + // // userKey is the key for user.User values in Contexts. It is + // // unexported; clients use user.NewContext and user.FromContext + // // instead of using this key directly. + // var userKey key = 0 + // + // // NewContext returns a new Context that carries value u. + // func NewContext(ctx context.Context, u *User) context.Context { + // return context.WithValue(ctx, userKey, u) + // } + // + // // FromContext returns the User value stored in ctx, if any. + // func FromContext(ctx context.Context) (*User, bool) { + // u, ok := ctx.Value(userKey).(*User) + // return u, ok + // } + Value(key interface{}) interface{} +} + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc func() diff --git a/vendor/golang.org/x/net/context/withtimeout_test.go b/vendor/golang.org/x/net/context/withtimeout_test.go deleted file mode 100644 index a6754dc3689..00000000000 --- a/vendor/golang.org/x/net/context/withtimeout_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2014 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 context_test - -import ( - "fmt" - "time" - - "golang.org/x/net/context" -) - -func ExampleWithTimeout() { - // Pass a context with a timeout to tell a blocking function that it - // should abandon its work after the timeout elapses. - ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond) - select { - case <-time.After(200 * time.Millisecond): - fmt.Println("overslept") - case <-ctx.Done(): - fmt.Println(ctx.Err()) // prints "context deadline exceeded" - } - // Output: - // context deadline exceeded -} diff --git a/vendor/golang.org/x/net/html/atom/atom.go b/vendor/golang.org/x/net/html/atom/atom.go deleted file mode 100644 index cd0a8ac1545..00000000000 --- a/vendor/golang.org/x/net/html/atom/atom.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2012 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 atom provides integer codes (also known as atoms) for a fixed set of -// frequently occurring HTML strings: tag names and attribute keys such as "p" -// and "id". -// -// Sharing an atom's name between all elements with the same tag can result in -// fewer string allocations when tokenizing and parsing HTML. Integer -// comparisons are also generally faster than string comparisons. -// -// The value of an atom's particular code is not guaranteed to stay the same -// between versions of this package. Neither is any ordering guaranteed: -// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to -// be dense. The only guarantees are that e.g. looking up "div" will yield -// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0. -package atom // import "golang.org/x/net/html/atom" - -// Atom is an integer code for a string. The zero value maps to "". -type Atom uint32 - -// String returns the atom's name. -func (a Atom) String() string { - start := uint32(a >> 8) - n := uint32(a & 0xff) - if start+n > uint32(len(atomText)) { - return "" - } - return atomText[start : start+n] -} - -func (a Atom) string() string { - return atomText[a>>8 : a>>8+a&0xff] -} - -// fnv computes the FNV hash with an arbitrary starting value h. -func fnv(h uint32, s []byte) uint32 { - for i := range s { - h ^= uint32(s[i]) - h *= 16777619 - } - return h -} - -func match(s string, t []byte) bool { - for i, c := range t { - if s[i] != c { - return false - } - } - return true -} - -// Lookup returns the atom whose name is s. It returns zero if there is no -// such atom. The lookup is case sensitive. -func Lookup(s []byte) Atom { - if len(s) == 0 || len(s) > maxAtomLen { - return 0 - } - h := fnv(hash0, s) - if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { - return a - } - if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { - return a - } - return 0 -} - -// String returns a string whose contents are equal to s. In that sense, it is -// equivalent to string(s) but may be more efficient. -func String(s []byte) string { - if a := Lookup(s); a != 0 { - return a.String() - } - return string(s) -} diff --git a/vendor/golang.org/x/net/html/atom/gen.go b/vendor/golang.org/x/net/html/atom/gen.go deleted file mode 100644 index 6bfa8660198..00000000000 --- a/vendor/golang.org/x/net/html/atom/gen.go +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright 2012 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. - -// +build ignore - -package main - -// This program generates table.go and table_test.go. -// Invoke as -// -// go run gen.go |gofmt >table.go -// go run gen.go -test |gofmt >table_test.go - -import ( - "flag" - "fmt" - "math/rand" - "os" - "sort" - "strings" -) - -// identifier converts s to a Go exported identifier. -// It converts "div" to "Div" and "accept-charset" to "AcceptCharset". -func identifier(s string) string { - b := make([]byte, 0, len(s)) - cap := true - for _, c := range s { - if c == '-' { - cap = true - continue - } - if cap && 'a' <= c && c <= 'z' { - c -= 'a' - 'A' - } - cap = false - b = append(b, byte(c)) - } - return string(b) -} - -var test = flag.Bool("test", false, "generate table_test.go") - -func main() { - flag.Parse() - - var all []string - all = append(all, elements...) - all = append(all, attributes...) - all = append(all, eventHandlers...) - all = append(all, extra...) - sort.Strings(all) - - if *test { - fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n") - fmt.Printf("package atom\n\n") - fmt.Printf("var testAtomList = []string{\n") - for _, s := range all { - fmt.Printf("\t%q,\n", s) - } - fmt.Printf("}\n") - return - } - - // uniq - lists have dups - // compute max len too - maxLen := 0 - w := 0 - for _, s := range all { - if w == 0 || all[w-1] != s { - if maxLen < len(s) { - maxLen = len(s) - } - all[w] = s - w++ - } - } - all = all[:w] - - // Find hash that minimizes table size. - var best *table - for i := 0; i < 1000000; i++ { - if best != nil && 1<<(best.k-1) < len(all) { - break - } - h := rand.Uint32() - for k := uint(0); k <= 16; k++ { - if best != nil && k >= best.k { - break - } - var t table - if t.init(h, k, all) { - best = &t - break - } - } - } - if best == nil { - fmt.Fprintf(os.Stderr, "failed to construct string table\n") - os.Exit(1) - } - - // Lay out strings, using overlaps when possible. - layout := append([]string{}, all...) - - // Remove strings that are substrings of other strings - for changed := true; changed; { - changed = false - for i, s := range layout { - if s == "" { - continue - } - for j, t := range layout { - if i != j && t != "" && strings.Contains(s, t) { - changed = true - layout[j] = "" - } - } - } - } - - // Join strings where one suffix matches another prefix. - for { - // Find best i, j, k such that layout[i][len-k:] == layout[j][:k], - // maximizing overlap length k. - besti := -1 - bestj := -1 - bestk := 0 - for i, s := range layout { - if s == "" { - continue - } - for j, t := range layout { - if i == j { - continue - } - for k := bestk + 1; k <= len(s) && k <= len(t); k++ { - if s[len(s)-k:] == t[:k] { - besti = i - bestj = j - bestk = k - } - } - } - } - if bestk > 0 { - layout[besti] += layout[bestj][bestk:] - layout[bestj] = "" - continue - } - break - } - - text := strings.Join(layout, "") - - atom := map[string]uint32{} - for _, s := range all { - off := strings.Index(text, s) - if off < 0 { - panic("lost string " + s) - } - atom[s] = uint32(off<<8 | len(s)) - } - - // Generate the Go code. - fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n") - fmt.Printf("package atom\n\nconst (\n") - for _, s := range all { - fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s]) - } - fmt.Printf(")\n\n") - - fmt.Printf("const hash0 = %#x\n\n", best.h0) - fmt.Printf("const maxAtomLen = %d\n\n", maxLen) - - fmt.Printf("var table = [1<<%d]Atom{\n", best.k) - for i, s := range best.tab { - if s == "" { - continue - } - fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s) - } - fmt.Printf("}\n") - datasize := (1 << best.k) * 4 - - fmt.Printf("const atomText =\n") - textsize := len(text) - for len(text) > 60 { - fmt.Printf("\t%q +\n", text[:60]) - text = text[60:] - } - fmt.Printf("\t%q\n\n", text) - - fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize) -} - -type byLen []string - -func (x byLen) Less(i, j int) bool { return len(x[i]) > len(x[j]) } -func (x byLen) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byLen) Len() int { return len(x) } - -// fnv computes the FNV hash with an arbitrary starting value h. -func fnv(h uint32, s string) uint32 { - for i := 0; i < len(s); i++ { - h ^= uint32(s[i]) - h *= 16777619 - } - return h -} - -// A table represents an attempt at constructing the lookup table. -// The lookup table uses cuckoo hashing, meaning that each string -// can be found in one of two positions. -type table struct { - h0 uint32 - k uint - mask uint32 - tab []string -} - -// hash returns the two hashes for s. -func (t *table) hash(s string) (h1, h2 uint32) { - h := fnv(t.h0, s) - h1 = h & t.mask - h2 = (h >> 16) & t.mask - return -} - -// init initializes the table with the given parameters. -// h0 is the initial hash value, -// k is the number of bits of hash value to use, and -// x is the list of strings to store in the table. -// init returns false if the table cannot be constructed. -func (t *table) init(h0 uint32, k uint, x []string) bool { - t.h0 = h0 - t.k = k - t.tab = make([]string, 1< len(t.tab) { - return false - } - s := t.tab[i] - h1, h2 := t.hash(s) - j := h1 + h2 - i - if t.tab[j] != "" && !t.push(j, depth+1) { - return false - } - t.tab[j] = s - return true -} - -// The lists of element names and attribute keys were taken from -// https://html.spec.whatwg.org/multipage/indices.html#index -// as of the "HTML Living Standard - Last Updated 21 February 2015" version. - -var elements = []string{ - "a", - "abbr", - "address", - "area", - "article", - "aside", - "audio", - "b", - "base", - "bdi", - "bdo", - "blockquote", - "body", - "br", - "button", - "canvas", - "caption", - "cite", - "code", - "col", - "colgroup", - "command", - "data", - "datalist", - "dd", - "del", - "details", - "dfn", - "dialog", - "div", - "dl", - "dt", - "em", - "embed", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hgroup", - "hr", - "html", - "i", - "iframe", - "img", - "input", - "ins", - "kbd", - "keygen", - "label", - "legend", - "li", - "link", - "map", - "mark", - "menu", - "menuitem", - "meta", - "meter", - "nav", - "noscript", - "object", - "ol", - "optgroup", - "option", - "output", - "p", - "param", - "pre", - "progress", - "q", - "rp", - "rt", - "ruby", - "s", - "samp", - "script", - "section", - "select", - "small", - "source", - "span", - "strong", - "style", - "sub", - "summary", - "sup", - "table", - "tbody", - "td", - "template", - "textarea", - "tfoot", - "th", - "thead", - "time", - "title", - "tr", - "track", - "u", - "ul", - "var", - "video", - "wbr", -} - -// https://html.spec.whatwg.org/multipage/indices.html#attributes-3 - -var attributes = []string{ - "abbr", - "accept", - "accept-charset", - "accesskey", - "action", - "alt", - "async", - "autocomplete", - "autofocus", - "autoplay", - "challenge", - "charset", - "checked", - "cite", - "class", - "cols", - "colspan", - "command", - "content", - "contenteditable", - "contextmenu", - "controls", - "coords", - "crossorigin", - "data", - "datetime", - "default", - "defer", - "dir", - "dirname", - "disabled", - "download", - "draggable", - "dropzone", - "enctype", - "for", - "form", - "formaction", - "formenctype", - "formmethod", - "formnovalidate", - "formtarget", - "headers", - "height", - "hidden", - "high", - "href", - "hreflang", - "http-equiv", - "icon", - "id", - "inputmode", - "ismap", - "itemid", - "itemprop", - "itemref", - "itemscope", - "itemtype", - "keytype", - "kind", - "label", - "lang", - "list", - "loop", - "low", - "manifest", - "max", - "maxlength", - "media", - "mediagroup", - "method", - "min", - "minlength", - "multiple", - "muted", - "name", - "novalidate", - "open", - "optimum", - "pattern", - "ping", - "placeholder", - "poster", - "preload", - "radiogroup", - "readonly", - "rel", - "required", - "reversed", - "rows", - "rowspan", - "sandbox", - "spellcheck", - "scope", - "scoped", - "seamless", - "selected", - "shape", - "size", - "sizes", - "sortable", - "sorted", - "span", - "src", - "srcdoc", - "srclang", - "start", - "step", - "style", - "tabindex", - "target", - "title", - "translate", - "type", - "typemustmatch", - "usemap", - "value", - "width", - "wrap", -} - -var eventHandlers = []string{ - "onabort", - "onautocomplete", - "onautocompleteerror", - "onafterprint", - "onbeforeprint", - "onbeforeunload", - "onblur", - "oncancel", - "oncanplay", - "oncanplaythrough", - "onchange", - "onclick", - "onclose", - "oncontextmenu", - "oncuechange", - "ondblclick", - "ondrag", - "ondragend", - "ondragenter", - "ondragleave", - "ondragover", - "ondragstart", - "ondrop", - "ondurationchange", - "onemptied", - "onended", - "onerror", - "onfocus", - "onhashchange", - "oninput", - "oninvalid", - "onkeydown", - "onkeypress", - "onkeyup", - "onlanguagechange", - "onload", - "onloadeddata", - "onloadedmetadata", - "onloadstart", - "onmessage", - "onmousedown", - "onmousemove", - "onmouseout", - "onmouseover", - "onmouseup", - "onmousewheel", - "onoffline", - "ononline", - "onpagehide", - "onpageshow", - "onpause", - "onplay", - "onplaying", - "onpopstate", - "onprogress", - "onratechange", - "onreset", - "onresize", - "onscroll", - "onseeked", - "onseeking", - "onselect", - "onshow", - "onsort", - "onstalled", - "onstorage", - "onsubmit", - "onsuspend", - "ontimeupdate", - "ontoggle", - "onunload", - "onvolumechange", - "onwaiting", -} - -// extra are ad-hoc values not covered by any of the lists above. -var extra = []string{ - "align", - "annotation", - "annotation-xml", - "applet", - "basefont", - "bgsound", - "big", - "blink", - "center", - "color", - "desc", - "face", - "font", - "foreignObject", // HTML is case-insensitive, but SVG-embedded-in-HTML is case-sensitive. - "foreignobject", - "frame", - "frameset", - "image", - "isindex", - "listing", - "malignmark", - "marquee", - "math", - "mglyph", - "mi", - "mn", - "mo", - "ms", - "mtext", - "nobr", - "noembed", - "noframes", - "plaintext", - "prompt", - "public", - "spacer", - "strike", - "svg", - "system", - "tt", - "xmp", -} diff --git a/vendor/golang.org/x/net/html/atom/table.go b/vendor/golang.org/x/net/html/atom/table.go deleted file mode 100644 index 2605ba3102f..00000000000 --- a/vendor/golang.org/x/net/html/atom/table.go +++ /dev/null @@ -1,713 +0,0 @@ -// generated by go run gen.go; DO NOT EDIT - -package atom - -const ( - A Atom = 0x1 - Abbr Atom = 0x4 - Accept Atom = 0x2106 - AcceptCharset Atom = 0x210e - Accesskey Atom = 0x3309 - Action Atom = 0x1f606 - Address Atom = 0x4f307 - Align Atom = 0x1105 - Alt Atom = 0x4503 - Annotation Atom = 0x1670a - AnnotationXml Atom = 0x1670e - Applet Atom = 0x2b306 - Area Atom = 0x2fa04 - Article Atom = 0x38807 - Aside Atom = 0x8305 - Async Atom = 0x7b05 - Audio Atom = 0xa605 - Autocomplete Atom = 0x1fc0c - Autofocus Atom = 0xb309 - Autoplay Atom = 0xce08 - B Atom = 0x101 - Base Atom = 0xd604 - Basefont Atom = 0xd608 - Bdi Atom = 0x1a03 - Bdo Atom = 0xe703 - Bgsound Atom = 0x11807 - Big Atom = 0x12403 - Blink Atom = 0x12705 - Blockquote Atom = 0x12c0a - Body Atom = 0x2f04 - Br Atom = 0x202 - Button Atom = 0x13606 - Canvas Atom = 0x7f06 - Caption Atom = 0x1bb07 - Center Atom = 0x5b506 - Challenge Atom = 0x21f09 - Charset Atom = 0x2807 - Checked Atom = 0x32807 - Cite Atom = 0x3c804 - Class Atom = 0x4de05 - Code Atom = 0x14904 - Col Atom = 0x15003 - Colgroup Atom = 0x15008 - Color Atom = 0x15d05 - Cols Atom = 0x16204 - Colspan Atom = 0x16207 - Command Atom = 0x17507 - Content Atom = 0x42307 - Contenteditable Atom = 0x4230f - Contextmenu Atom = 0x3310b - Controls Atom = 0x18808 - Coords Atom = 0x19406 - Crossorigin Atom = 0x19f0b - Data Atom = 0x44a04 - Datalist Atom = 0x44a08 - Datetime Atom = 0x23c08 - Dd Atom = 0x26702 - Default Atom = 0x8607 - Defer Atom = 0x14b05 - Del Atom = 0x3ef03 - Desc Atom = 0x4db04 - Details Atom = 0x4807 - Dfn Atom = 0x6103 - Dialog Atom = 0x1b06 - Dir Atom = 0x6903 - Dirname Atom = 0x6907 - Disabled Atom = 0x10c08 - Div Atom = 0x11303 - Dl Atom = 0x11e02 - Download Atom = 0x40008 - Draggable Atom = 0x17b09 - Dropzone Atom = 0x39108 - Dt Atom = 0x50902 - Em Atom = 0x6502 - Embed Atom = 0x6505 - Enctype Atom = 0x21107 - Face Atom = 0x5b304 - Fieldset Atom = 0x1b008 - Figcaption Atom = 0x1b80a - Figure Atom = 0x1cc06 - Font Atom = 0xda04 - Footer Atom = 0x8d06 - For Atom = 0x1d803 - ForeignObject Atom = 0x1d80d - Foreignobject Atom = 0x1e50d - Form Atom = 0x1f204 - Formaction Atom = 0x1f20a - Formenctype Atom = 0x20d0b - Formmethod Atom = 0x2280a - Formnovalidate Atom = 0x2320e - Formtarget Atom = 0x2470a - Frame Atom = 0x9a05 - Frameset Atom = 0x9a08 - H1 Atom = 0x26e02 - H2 Atom = 0x29402 - H3 Atom = 0x2a702 - H4 Atom = 0x2e902 - H5 Atom = 0x2f302 - H6 Atom = 0x50b02 - Head Atom = 0x2d504 - Header Atom = 0x2d506 - Headers Atom = 0x2d507 - Height Atom = 0x25106 - Hgroup Atom = 0x25906 - Hidden Atom = 0x26506 - High Atom = 0x26b04 - Hr Atom = 0x27002 - Href Atom = 0x27004 - Hreflang Atom = 0x27008 - Html Atom = 0x25504 - HttpEquiv Atom = 0x2780a - I Atom = 0x601 - Icon Atom = 0x42204 - Id Atom = 0x8502 - Iframe Atom = 0x29606 - Image Atom = 0x29c05 - Img Atom = 0x2a103 - Input Atom = 0x3e805 - Inputmode Atom = 0x3e809 - Ins Atom = 0x1a803 - Isindex Atom = 0x2a907 - Ismap Atom = 0x2b005 - Itemid Atom = 0x33c06 - Itemprop Atom = 0x3c908 - Itemref Atom = 0x5ad07 - Itemscope Atom = 0x2b909 - Itemtype Atom = 0x2c308 - Kbd Atom = 0x1903 - Keygen Atom = 0x3906 - Keytype Atom = 0x53707 - Kind Atom = 0x10904 - Label Atom = 0xf005 - Lang Atom = 0x27404 - Legend Atom = 0x18206 - Li Atom = 0x1202 - Link Atom = 0x12804 - List Atom = 0x44e04 - Listing Atom = 0x44e07 - Loop Atom = 0xf404 - Low Atom = 0x11f03 - Malignmark Atom = 0x100a - Manifest Atom = 0x5f108 - Map Atom = 0x2b203 - Mark Atom = 0x1604 - Marquee Atom = 0x2cb07 - Math Atom = 0x2d204 - Max Atom = 0x2e103 - Maxlength Atom = 0x2e109 - Media Atom = 0x6e05 - Mediagroup Atom = 0x6e0a - Menu Atom = 0x33804 - Menuitem Atom = 0x33808 - Meta Atom = 0x45d04 - Meter Atom = 0x24205 - Method Atom = 0x22c06 - Mglyph Atom = 0x2a206 - Mi Atom = 0x2eb02 - Min Atom = 0x2eb03 - Minlength Atom = 0x2eb09 - Mn Atom = 0x23502 - Mo Atom = 0x3ed02 - Ms Atom = 0x2bc02 - Mtext Atom = 0x2f505 - Multiple Atom = 0x30308 - Muted Atom = 0x30b05 - Name Atom = 0x6c04 - Nav Atom = 0x3e03 - Nobr Atom = 0x5704 - Noembed Atom = 0x6307 - Noframes Atom = 0x9808 - Noscript Atom = 0x3d208 - Novalidate Atom = 0x2360a - Object Atom = 0x1ec06 - Ol Atom = 0xc902 - Onabort Atom = 0x13a07 - Onafterprint Atom = 0x1c00c - Onautocomplete Atom = 0x1fa0e - Onautocompleteerror Atom = 0x1fa13 - Onbeforeprint Atom = 0x6040d - Onbeforeunload Atom = 0x4e70e - Onblur Atom = 0xaa06 - Oncancel Atom = 0xe908 - Oncanplay Atom = 0x28509 - Oncanplaythrough Atom = 0x28510 - Onchange Atom = 0x3a708 - Onclick Atom = 0x31007 - Onclose Atom = 0x31707 - Oncontextmenu Atom = 0x32f0d - Oncuechange Atom = 0x3420b - Ondblclick Atom = 0x34d0a - Ondrag Atom = 0x35706 - Ondragend Atom = 0x35709 - Ondragenter Atom = 0x3600b - Ondragleave Atom = 0x36b0b - Ondragover Atom = 0x3760a - Ondragstart Atom = 0x3800b - Ondrop Atom = 0x38f06 - Ondurationchange Atom = 0x39f10 - Onemptied Atom = 0x39609 - Onended Atom = 0x3af07 - Onerror Atom = 0x3b607 - Onfocus Atom = 0x3bd07 - Onhashchange Atom = 0x3da0c - Oninput Atom = 0x3e607 - Oninvalid Atom = 0x3f209 - Onkeydown Atom = 0x3fb09 - Onkeypress Atom = 0x4080a - Onkeyup Atom = 0x41807 - Onlanguagechange Atom = 0x43210 - Onload Atom = 0x44206 - Onloadeddata Atom = 0x4420c - Onloadedmetadata Atom = 0x45510 - Onloadstart Atom = 0x46b0b - Onmessage Atom = 0x47609 - Onmousedown Atom = 0x47f0b - Onmousemove Atom = 0x48a0b - Onmouseout Atom = 0x4950a - Onmouseover Atom = 0x4a20b - Onmouseup Atom = 0x4ad09 - Onmousewheel Atom = 0x4b60c - Onoffline Atom = 0x4c209 - Ononline Atom = 0x4cb08 - Onpagehide Atom = 0x4d30a - Onpageshow Atom = 0x4fe0a - Onpause Atom = 0x50d07 - Onplay Atom = 0x51706 - Onplaying Atom = 0x51709 - Onpopstate Atom = 0x5200a - Onprogress Atom = 0x52a0a - Onratechange Atom = 0x53e0c - Onreset Atom = 0x54a07 - Onresize Atom = 0x55108 - Onscroll Atom = 0x55f08 - Onseeked Atom = 0x56708 - Onseeking Atom = 0x56f09 - Onselect Atom = 0x57808 - Onshow Atom = 0x58206 - Onsort Atom = 0x58b06 - Onstalled Atom = 0x59509 - Onstorage Atom = 0x59e09 - Onsubmit Atom = 0x5a708 - Onsuspend Atom = 0x5bb09 - Ontimeupdate Atom = 0xdb0c - Ontoggle Atom = 0x5c408 - Onunload Atom = 0x5cc08 - Onvolumechange Atom = 0x5d40e - Onwaiting Atom = 0x5e209 - Open Atom = 0x3cf04 - Optgroup Atom = 0xf608 - Optimum Atom = 0x5eb07 - Option Atom = 0x60006 - Output Atom = 0x49c06 - P Atom = 0xc01 - Param Atom = 0xc05 - Pattern Atom = 0x5107 - Ping Atom = 0x7704 - Placeholder Atom = 0xc30b - Plaintext Atom = 0xfd09 - Poster Atom = 0x15706 - Pre Atom = 0x25e03 - Preload Atom = 0x25e07 - Progress Atom = 0x52c08 - Prompt Atom = 0x5fa06 - Public Atom = 0x41e06 - Q Atom = 0x13101 - Radiogroup Atom = 0x30a - Readonly Atom = 0x2fb08 - Rel Atom = 0x25f03 - Required Atom = 0x1d008 - Reversed Atom = 0x5a08 - Rows Atom = 0x9204 - Rowspan Atom = 0x9207 - Rp Atom = 0x1c602 - Rt Atom = 0x13f02 - Ruby Atom = 0xaf04 - S Atom = 0x2c01 - Samp Atom = 0x4e04 - Sandbox Atom = 0xbb07 - Scope Atom = 0x2bd05 - Scoped Atom = 0x2bd06 - Script Atom = 0x3d406 - Seamless Atom = 0x31c08 - Section Atom = 0x4e207 - Select Atom = 0x57a06 - Selected Atom = 0x57a08 - Shape Atom = 0x4f905 - Size Atom = 0x55504 - Sizes Atom = 0x55505 - Small Atom = 0x18f05 - Sortable Atom = 0x58d08 - Sorted Atom = 0x19906 - Source Atom = 0x1aa06 - Spacer Atom = 0x2db06 - Span Atom = 0x9504 - Spellcheck Atom = 0x3230a - Src Atom = 0x3c303 - Srcdoc Atom = 0x3c306 - Srclang Atom = 0x41107 - Start Atom = 0x38605 - Step Atom = 0x5f704 - Strike Atom = 0x53306 - Strong Atom = 0x55906 - Style Atom = 0x61105 - Sub Atom = 0x5a903 - Summary Atom = 0x61607 - Sup Atom = 0x61d03 - Svg Atom = 0x62003 - System Atom = 0x62306 - Tabindex Atom = 0x46308 - Table Atom = 0x42d05 - Target Atom = 0x24b06 - Tbody Atom = 0x2e05 - Td Atom = 0x4702 - Template Atom = 0x62608 - Textarea Atom = 0x2f608 - Tfoot Atom = 0x8c05 - Th Atom = 0x22e02 - Thead Atom = 0x2d405 - Time Atom = 0xdd04 - Title Atom = 0xa105 - Tr Atom = 0x10502 - Track Atom = 0x10505 - Translate Atom = 0x14009 - Tt Atom = 0x5302 - Type Atom = 0x21404 - Typemustmatch Atom = 0x2140d - U Atom = 0xb01 - Ul Atom = 0x8a02 - Usemap Atom = 0x51106 - Value Atom = 0x4005 - Var Atom = 0x11503 - Video Atom = 0x28105 - Wbr Atom = 0x12103 - Width Atom = 0x50705 - Wrap Atom = 0x58704 - Xmp Atom = 0xc103 -) - -const hash0 = 0xc17da63e - -const maxAtomLen = 19 - -var table = [1 << 9]Atom{ - 0x1: 0x48a0b, // onmousemove - 0x2: 0x5e209, // onwaiting - 0x3: 0x1fa13, // onautocompleteerror - 0x4: 0x5fa06, // prompt - 0x7: 0x5eb07, // optimum - 0x8: 0x1604, // mark - 0xa: 0x5ad07, // itemref - 0xb: 0x4fe0a, // onpageshow - 0xc: 0x57a06, // select - 0xd: 0x17b09, // draggable - 0xe: 0x3e03, // nav - 0xf: 0x17507, // command - 0x11: 0xb01, // u - 0x14: 0x2d507, // headers - 0x15: 0x44a08, // datalist - 0x17: 0x4e04, // samp - 0x1a: 0x3fb09, // onkeydown - 0x1b: 0x55f08, // onscroll - 0x1c: 0x15003, // col - 0x20: 0x3c908, // itemprop - 0x21: 0x2780a, // http-equiv - 0x22: 0x61d03, // sup - 0x24: 0x1d008, // required - 0x2b: 0x25e07, // preload - 0x2c: 0x6040d, // onbeforeprint - 0x2d: 0x3600b, // ondragenter - 0x2e: 0x50902, // dt - 0x2f: 0x5a708, // onsubmit - 0x30: 0x27002, // hr - 0x31: 0x32f0d, // oncontextmenu - 0x33: 0x29c05, // image - 0x34: 0x50d07, // onpause - 0x35: 0x25906, // hgroup - 0x36: 0x7704, // ping - 0x37: 0x57808, // onselect - 0x3a: 0x11303, // div - 0x3b: 0x1fa0e, // onautocomplete - 0x40: 0x2eb02, // mi - 0x41: 0x31c08, // seamless - 0x42: 0x2807, // charset - 0x43: 0x8502, // id - 0x44: 0x5200a, // onpopstate - 0x45: 0x3ef03, // del - 0x46: 0x2cb07, // marquee - 0x47: 0x3309, // accesskey - 0x49: 0x8d06, // footer - 0x4a: 0x44e04, // list - 0x4b: 0x2b005, // ismap - 0x51: 0x33804, // menu - 0x52: 0x2f04, // body - 0x55: 0x9a08, // frameset - 0x56: 0x54a07, // onreset - 0x57: 0x12705, // blink - 0x58: 0xa105, // title - 0x59: 0x38807, // article - 0x5b: 0x22e02, // th - 0x5d: 0x13101, // q - 0x5e: 0x3cf04, // open - 0x5f: 0x2fa04, // area - 0x61: 0x44206, // onload - 0x62: 0xda04, // font - 0x63: 0xd604, // base - 0x64: 0x16207, // colspan - 0x65: 0x53707, // keytype - 0x66: 0x11e02, // dl - 0x68: 0x1b008, // fieldset - 0x6a: 0x2eb03, // min - 0x6b: 0x11503, // var - 0x6f: 0x2d506, // header - 0x70: 0x13f02, // rt - 0x71: 0x15008, // colgroup - 0x72: 0x23502, // mn - 0x74: 0x13a07, // onabort - 0x75: 0x3906, // keygen - 0x76: 0x4c209, // onoffline - 0x77: 0x21f09, // challenge - 0x78: 0x2b203, // map - 0x7a: 0x2e902, // h4 - 0x7b: 0x3b607, // onerror - 0x7c: 0x2e109, // maxlength - 0x7d: 0x2f505, // mtext - 0x7e: 0xbb07, // sandbox - 0x7f: 0x58b06, // onsort - 0x80: 0x100a, // malignmark - 0x81: 0x45d04, // meta - 0x82: 0x7b05, // async - 0x83: 0x2a702, // h3 - 0x84: 0x26702, // dd - 0x85: 0x27004, // href - 0x86: 0x6e0a, // mediagroup - 0x87: 0x19406, // coords - 0x88: 0x41107, // srclang - 0x89: 0x34d0a, // ondblclick - 0x8a: 0x4005, // value - 0x8c: 0xe908, // oncancel - 0x8e: 0x3230a, // spellcheck - 0x8f: 0x9a05, // frame - 0x91: 0x12403, // big - 0x94: 0x1f606, // action - 0x95: 0x6903, // dir - 0x97: 0x2fb08, // readonly - 0x99: 0x42d05, // table - 0x9a: 0x61607, // summary - 0x9b: 0x12103, // wbr - 0x9c: 0x30a, // radiogroup - 0x9d: 0x6c04, // name - 0x9f: 0x62306, // system - 0xa1: 0x15d05, // color - 0xa2: 0x7f06, // canvas - 0xa3: 0x25504, // html - 0xa5: 0x56f09, // onseeking - 0xac: 0x4f905, // shape - 0xad: 0x25f03, // rel - 0xae: 0x28510, // oncanplaythrough - 0xaf: 0x3760a, // ondragover - 0xb0: 0x62608, // template - 0xb1: 0x1d80d, // foreignObject - 0xb3: 0x9204, // rows - 0xb6: 0x44e07, // listing - 0xb7: 0x49c06, // output - 0xb9: 0x3310b, // contextmenu - 0xbb: 0x11f03, // low - 0xbc: 0x1c602, // rp - 0xbd: 0x5bb09, // onsuspend - 0xbe: 0x13606, // button - 0xbf: 0x4db04, // desc - 0xc1: 0x4e207, // section - 0xc2: 0x52a0a, // onprogress - 0xc3: 0x59e09, // onstorage - 0xc4: 0x2d204, // math - 0xc5: 0x4503, // alt - 0xc7: 0x8a02, // ul - 0xc8: 0x5107, // pattern - 0xc9: 0x4b60c, // onmousewheel - 0xca: 0x35709, // ondragend - 0xcb: 0xaf04, // ruby - 0xcc: 0xc01, // p - 0xcd: 0x31707, // onclose - 0xce: 0x24205, // meter - 0xcf: 0x11807, // bgsound - 0xd2: 0x25106, // height - 0xd4: 0x101, // b - 0xd5: 0x2c308, // itemtype - 0xd8: 0x1bb07, // caption - 0xd9: 0x10c08, // disabled - 0xdb: 0x33808, // menuitem - 0xdc: 0x62003, // svg - 0xdd: 0x18f05, // small - 0xde: 0x44a04, // data - 0xe0: 0x4cb08, // ononline - 0xe1: 0x2a206, // mglyph - 0xe3: 0x6505, // embed - 0xe4: 0x10502, // tr - 0xe5: 0x46b0b, // onloadstart - 0xe7: 0x3c306, // srcdoc - 0xeb: 0x5c408, // ontoggle - 0xed: 0xe703, // bdo - 0xee: 0x4702, // td - 0xef: 0x8305, // aside - 0xf0: 0x29402, // h2 - 0xf1: 0x52c08, // progress - 0xf2: 0x12c0a, // blockquote - 0xf4: 0xf005, // label - 0xf5: 0x601, // i - 0xf7: 0x9207, // rowspan - 0xfb: 0x51709, // onplaying - 0xfd: 0x2a103, // img - 0xfe: 0xf608, // optgroup - 0xff: 0x42307, // content - 0x101: 0x53e0c, // onratechange - 0x103: 0x3da0c, // onhashchange - 0x104: 0x4807, // details - 0x106: 0x40008, // download - 0x109: 0x14009, // translate - 0x10b: 0x4230f, // contenteditable - 0x10d: 0x36b0b, // ondragleave - 0x10e: 0x2106, // accept - 0x10f: 0x57a08, // selected - 0x112: 0x1f20a, // formaction - 0x113: 0x5b506, // center - 0x115: 0x45510, // onloadedmetadata - 0x116: 0x12804, // link - 0x117: 0xdd04, // time - 0x118: 0x19f0b, // crossorigin - 0x119: 0x3bd07, // onfocus - 0x11a: 0x58704, // wrap - 0x11b: 0x42204, // icon - 0x11d: 0x28105, // video - 0x11e: 0x4de05, // class - 0x121: 0x5d40e, // onvolumechange - 0x122: 0xaa06, // onblur - 0x123: 0x2b909, // itemscope - 0x124: 0x61105, // style - 0x127: 0x41e06, // public - 0x129: 0x2320e, // formnovalidate - 0x12a: 0x58206, // onshow - 0x12c: 0x51706, // onplay - 0x12d: 0x3c804, // cite - 0x12e: 0x2bc02, // ms - 0x12f: 0xdb0c, // ontimeupdate - 0x130: 0x10904, // kind - 0x131: 0x2470a, // formtarget - 0x135: 0x3af07, // onended - 0x136: 0x26506, // hidden - 0x137: 0x2c01, // s - 0x139: 0x2280a, // formmethod - 0x13a: 0x3e805, // input - 0x13c: 0x50b02, // h6 - 0x13d: 0xc902, // ol - 0x13e: 0x3420b, // oncuechange - 0x13f: 0x1e50d, // foreignobject - 0x143: 0x4e70e, // onbeforeunload - 0x144: 0x2bd05, // scope - 0x145: 0x39609, // onemptied - 0x146: 0x14b05, // defer - 0x147: 0xc103, // xmp - 0x148: 0x39f10, // ondurationchange - 0x149: 0x1903, // kbd - 0x14c: 0x47609, // onmessage - 0x14d: 0x60006, // option - 0x14e: 0x2eb09, // minlength - 0x14f: 0x32807, // checked - 0x150: 0xce08, // autoplay - 0x152: 0x202, // br - 0x153: 0x2360a, // novalidate - 0x156: 0x6307, // noembed - 0x159: 0x31007, // onclick - 0x15a: 0x47f0b, // onmousedown - 0x15b: 0x3a708, // onchange - 0x15e: 0x3f209, // oninvalid - 0x15f: 0x2bd06, // scoped - 0x160: 0x18808, // controls - 0x161: 0x30b05, // muted - 0x162: 0x58d08, // sortable - 0x163: 0x51106, // usemap - 0x164: 0x1b80a, // figcaption - 0x165: 0x35706, // ondrag - 0x166: 0x26b04, // high - 0x168: 0x3c303, // src - 0x169: 0x15706, // poster - 0x16b: 0x1670e, // annotation-xml - 0x16c: 0x5f704, // step - 0x16d: 0x4, // abbr - 0x16e: 0x1b06, // dialog - 0x170: 0x1202, // li - 0x172: 0x3ed02, // mo - 0x175: 0x1d803, // for - 0x176: 0x1a803, // ins - 0x178: 0x55504, // size - 0x179: 0x43210, // onlanguagechange - 0x17a: 0x8607, // default - 0x17b: 0x1a03, // bdi - 0x17c: 0x4d30a, // onpagehide - 0x17d: 0x6907, // dirname - 0x17e: 0x21404, // type - 0x17f: 0x1f204, // form - 0x181: 0x28509, // oncanplay - 0x182: 0x6103, // dfn - 0x183: 0x46308, // tabindex - 0x186: 0x6502, // em - 0x187: 0x27404, // lang - 0x189: 0x39108, // dropzone - 0x18a: 0x4080a, // onkeypress - 0x18b: 0x23c08, // datetime - 0x18c: 0x16204, // cols - 0x18d: 0x1, // a - 0x18e: 0x4420c, // onloadeddata - 0x190: 0xa605, // audio - 0x192: 0x2e05, // tbody - 0x193: 0x22c06, // method - 0x195: 0xf404, // loop - 0x196: 0x29606, // iframe - 0x198: 0x2d504, // head - 0x19e: 0x5f108, // manifest - 0x19f: 0xb309, // autofocus - 0x1a0: 0x14904, // code - 0x1a1: 0x55906, // strong - 0x1a2: 0x30308, // multiple - 0x1a3: 0xc05, // param - 0x1a6: 0x21107, // enctype - 0x1a7: 0x5b304, // face - 0x1a8: 0xfd09, // plaintext - 0x1a9: 0x26e02, // h1 - 0x1aa: 0x59509, // onstalled - 0x1ad: 0x3d406, // script - 0x1ae: 0x2db06, // spacer - 0x1af: 0x55108, // onresize - 0x1b0: 0x4a20b, // onmouseover - 0x1b1: 0x5cc08, // onunload - 0x1b2: 0x56708, // onseeked - 0x1b4: 0x2140d, // typemustmatch - 0x1b5: 0x1cc06, // figure - 0x1b6: 0x4950a, // onmouseout - 0x1b7: 0x25e03, // pre - 0x1b8: 0x50705, // width - 0x1b9: 0x19906, // sorted - 0x1bb: 0x5704, // nobr - 0x1be: 0x5302, // tt - 0x1bf: 0x1105, // align - 0x1c0: 0x3e607, // oninput - 0x1c3: 0x41807, // onkeyup - 0x1c6: 0x1c00c, // onafterprint - 0x1c7: 0x210e, // accept-charset - 0x1c8: 0x33c06, // itemid - 0x1c9: 0x3e809, // inputmode - 0x1cb: 0x53306, // strike - 0x1cc: 0x5a903, // sub - 0x1cd: 0x10505, // track - 0x1ce: 0x38605, // start - 0x1d0: 0xd608, // basefont - 0x1d6: 0x1aa06, // source - 0x1d7: 0x18206, // legend - 0x1d8: 0x2d405, // thead - 0x1da: 0x8c05, // tfoot - 0x1dd: 0x1ec06, // object - 0x1de: 0x6e05, // media - 0x1df: 0x1670a, // annotation - 0x1e0: 0x20d0b, // formenctype - 0x1e2: 0x3d208, // noscript - 0x1e4: 0x55505, // sizes - 0x1e5: 0x1fc0c, // autocomplete - 0x1e6: 0x9504, // span - 0x1e7: 0x9808, // noframes - 0x1e8: 0x24b06, // target - 0x1e9: 0x38f06, // ondrop - 0x1ea: 0x2b306, // applet - 0x1ec: 0x5a08, // reversed - 0x1f0: 0x2a907, // isindex - 0x1f3: 0x27008, // hreflang - 0x1f5: 0x2f302, // h5 - 0x1f6: 0x4f307, // address - 0x1fa: 0x2e103, // max - 0x1fb: 0xc30b, // placeholder - 0x1fc: 0x2f608, // textarea - 0x1fe: 0x4ad09, // onmouseup - 0x1ff: 0x3800b, // ondragstart -} - -const atomText = "abbradiogrouparamalignmarkbdialogaccept-charsetbodyaccesskey" + - "genavaluealtdetailsampatternobreversedfnoembedirnamediagroup" + - "ingasyncanvasidefaultfooterowspanoframesetitleaudionblurubya" + - "utofocusandboxmplaceholderautoplaybasefontimeupdatebdoncance" + - "labelooptgrouplaintextrackindisabledivarbgsoundlowbrbigblink" + - "blockquotebuttonabortranslatecodefercolgroupostercolorcolspa" + - "nnotation-xmlcommandraggablegendcontrolsmallcoordsortedcross" + - "originsourcefieldsetfigcaptionafterprintfigurequiredforeignO" + - "bjectforeignobjectformactionautocompleteerrorformenctypemust" + - "matchallengeformmethodformnovalidatetimeterformtargetheightm" + - "lhgroupreloadhiddenhigh1hreflanghttp-equivideoncanplaythroug" + - "h2iframeimageimglyph3isindexismappletitemscopeditemtypemarqu" + - "eematheaderspacermaxlength4minlength5mtextareadonlymultiplem" + - "utedonclickoncloseamlesspellcheckedoncontextmenuitemidoncuec" + - "hangeondblclickondragendondragenterondragleaveondragoverondr" + - "agstarticleondropzonemptiedondurationchangeonendedonerroronf" + - "ocusrcdocitempropenoscriptonhashchangeoninputmodeloninvalido" + - "nkeydownloadonkeypressrclangonkeyupublicontenteditableonlang" + - "uagechangeonloadeddatalistingonloadedmetadatabindexonloadsta" + - "rtonmessageonmousedownonmousemoveonmouseoutputonmouseoveronm" + - "ouseuponmousewheelonofflineononlineonpagehidesclassectionbef" + - "oreunloaddresshapeonpageshowidth6onpausemaponplayingonpopsta" + - "teonprogresstrikeytypeonratechangeonresetonresizestrongonscr" + - "ollonseekedonseekingonselectedonshowraponsortableonstalledon" + - "storageonsubmitemrefacenteronsuspendontoggleonunloadonvolume" + - "changeonwaitingoptimumanifestepromptoptionbeforeprintstylesu" + - "mmarysupsvgsystemplate" diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go deleted file mode 100644 index 52f651ff6db..00000000000 --- a/vendor/golang.org/x/net/html/const.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2011 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 html - -// Section 12.2.3.2 of the HTML5 specification says "The following elements -// have varying levels of special parsing rules". -// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements -var isSpecialElementMap = map[string]bool{ - "address": true, - "applet": true, - "area": true, - "article": true, - "aside": true, - "base": true, - "basefont": true, - "bgsound": true, - "blockquote": true, - "body": true, - "br": true, - "button": true, - "caption": true, - "center": true, - "col": true, - "colgroup": true, - "dd": true, - "details": true, - "dir": true, - "div": true, - "dl": true, - "dt": true, - "embed": true, - "fieldset": true, - "figcaption": true, - "figure": true, - "footer": true, - "form": true, - "frame": true, - "frameset": true, - "h1": true, - "h2": true, - "h3": true, - "h4": true, - "h5": true, - "h6": true, - "head": true, - "header": true, - "hgroup": true, - "hr": true, - "html": true, - "iframe": true, - "img": true, - "input": true, - "isindex": true, - "li": true, - "link": true, - "listing": true, - "marquee": true, - "menu": true, - "meta": true, - "nav": true, - "noembed": true, - "noframes": true, - "noscript": true, - "object": true, - "ol": true, - "p": true, - "param": true, - "plaintext": true, - "pre": true, - "script": true, - "section": true, - "select": true, - "source": true, - "style": true, - "summary": true, - "table": true, - "tbody": true, - "td": true, - "template": true, - "textarea": true, - "tfoot": true, - "th": true, - "thead": true, - "title": true, - "tr": true, - "track": true, - "ul": true, - "wbr": true, - "xmp": true, -} - -func isSpecialElement(element *Node) bool { - switch element.Namespace { - case "", "html": - return isSpecialElementMap[element.Data] - case "svg": - return element.Data == "foreignObject" - } - return false -} diff --git a/vendor/golang.org/x/net/html/doc.go b/vendor/golang.org/x/net/html/doc.go deleted file mode 100644 index 94f496874ab..00000000000 --- a/vendor/golang.org/x/net/html/doc.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2010 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 html implements an HTML5-compliant tokenizer and parser. - -Tokenization is done by creating a Tokenizer for an io.Reader r. It is the -caller's responsibility to ensure that r provides UTF-8 encoded HTML. - - z := html.NewTokenizer(r) - -Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), -which parses the next token and returns its type, or an error: - - for { - tt := z.Next() - if tt == html.ErrorToken { - // ... - return ... - } - // Process the current token. - } - -There are two APIs for retrieving the current token. The high-level API is to -call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs -allow optionally calling Raw after Next but before Token, Text, TagName, or -TagAttr. In EBNF notation, the valid call sequence per token is: - - Next {Raw} [ Token | Text | TagName {TagAttr} ] - -Token returns an independent data structure that completely describes a token. -Entities (such as "<") are unescaped, tag names and attribute keys are -lower-cased, and attributes are collected into a []Attribute. For example: - - for { - if z.Next() == html.ErrorToken { - // Returning io.EOF indicates success. - return z.Err() - } - emitToken(z.Token()) - } - -The low-level API performs fewer allocations and copies, but the contents of -the []byte values returned by Text, TagName and TagAttr may change on the next -call to Next. For example, to extract an HTML page's anchor text: - - depth := 0 - for { - tt := z.Next() - switch tt { - case ErrorToken: - return z.Err() - case TextToken: - if depth > 0 { - // emitBytes should copy the []byte it receives, - // if it doesn't process it immediately. - emitBytes(z.Text()) - } - case StartTagToken, EndTagToken: - tn, _ := z.TagName() - if len(tn) == 1 && tn[0] == 'a' { - if tt == StartTagToken { - depth++ - } else { - depth-- - } - } - } - } - -Parsing is done by calling Parse with an io.Reader, which returns the root of -the parse tree (the document element) as a *Node. It is the caller's -responsibility to ensure that the Reader provides UTF-8 encoded HTML. For -example, to process each anchor node in depth-first order: - - doc, err := html.Parse(r) - if err != nil { - // ... - } - var f func(*html.Node) - f = func(n *html.Node) { - if n.Type == html.ElementNode && n.Data == "a" { - // Do something with n... - } - for c := n.FirstChild; c != nil; c = c.NextSibling { - f(c) - } - } - f(doc) - -The relevant specifications include: -https://html.spec.whatwg.org/multipage/syntax.html and -https://html.spec.whatwg.org/multipage/syntax.html#tokenization -*/ -package html // import "golang.org/x/net/html" - -// The tokenization algorithm implemented by this package is not a line-by-line -// transliteration of the relatively verbose state-machine in the WHATWG -// specification. A more direct approach is used instead, where the program -// counter implies the state, such as whether it is tokenizing a tag or a text -// node. Specification compliance is verified by checking expected and actual -// outputs over a test suite rather than aiming for algorithmic fidelity. - -// TODO(nigeltao): Does a DOM API belong in this package or a separate one? -// TODO(nigeltao): How does parsing interact with a JavaScript engine? diff --git a/vendor/golang.org/x/net/html/doctype.go b/vendor/golang.org/x/net/html/doctype.go deleted file mode 100644 index c484e5a94fb..00000000000 --- a/vendor/golang.org/x/net/html/doctype.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2011 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 html - -import ( - "strings" -) - -// parseDoctype parses the data from a DoctypeToken into a name, -// public identifier, and system identifier. It returns a Node whose Type -// is DoctypeNode, whose Data is the name, and which has attributes -// named "system" and "public" for the two identifiers if they were present. -// quirks is whether the document should be parsed in "quirks mode". -func parseDoctype(s string) (n *Node, quirks bool) { - n = &Node{Type: DoctypeNode} - - // Find the name. - space := strings.IndexAny(s, whitespace) - if space == -1 { - space = len(s) - } - n.Data = s[:space] - // The comparison to "html" is case-sensitive. - if n.Data != "html" { - quirks = true - } - n.Data = strings.ToLower(n.Data) - s = strings.TrimLeft(s[space:], whitespace) - - if len(s) < 6 { - // It can't start with "PUBLIC" or "SYSTEM". - // Ignore the rest of the string. - return n, quirks || s != "" - } - - key := strings.ToLower(s[:6]) - s = s[6:] - for key == "public" || key == "system" { - s = strings.TrimLeft(s, whitespace) - if s == "" { - break - } - quote := s[0] - if quote != '"' && quote != '\'' { - break - } - s = s[1:] - q := strings.IndexRune(s, rune(quote)) - var id string - if q == -1 { - id = s - s = "" - } else { - id = s[:q] - s = s[q+1:] - } - n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) - if key == "public" { - key = "system" - } else { - key = "" - } - } - - if key != "" || s != "" { - quirks = true - } else if len(n.Attr) > 0 { - if n.Attr[0].Key == "public" { - public := strings.ToLower(n.Attr[0].Val) - switch public { - case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": - quirks = true - default: - for _, q := range quirkyIDs { - if strings.HasPrefix(public, q) { - quirks = true - break - } - } - } - // The following two public IDs only cause quirks mode if there is no system ID. - if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || - strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { - quirks = true - } - } - if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && - strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { - quirks = true - } - } - - return n, quirks -} - -// quirkyIDs is a list of public doctype identifiers that cause a document -// to be interpreted in quirks mode. The identifiers should be in lower case. -var quirkyIDs = []string{ - "+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", - "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//", -} diff --git a/vendor/golang.org/x/net/html/entity.go b/vendor/golang.org/x/net/html/entity.go deleted file mode 100644 index a50c04c60e9..00000000000 --- a/vendor/golang.org/x/net/html/entity.go +++ /dev/null @@ -1,2253 +0,0 @@ -// Copyright 2010 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 html - -// All entities that do not end with ';' are 6 or fewer bytes long. -const longestEntityWithoutSemicolon = 6 - -// entity is a map from HTML entity names to their values. The semicolon matters: -// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references -// lists both "amp" and "amp;" as two separate entries. -// -// Note that the HTML5 list is larger than the HTML4 list at -// http://www.w3.org/TR/html4/sgml/entities.html -var entity = map[string]rune{ - "AElig;": '\U000000C6', - "AMP;": '\U00000026', - "Aacute;": '\U000000C1', - "Abreve;": '\U00000102', - "Acirc;": '\U000000C2', - "Acy;": '\U00000410', - "Afr;": '\U0001D504', - "Agrave;": '\U000000C0', - "Alpha;": '\U00000391', - "Amacr;": '\U00000100', - "And;": '\U00002A53', - "Aogon;": '\U00000104', - "Aopf;": '\U0001D538', - "ApplyFunction;": '\U00002061', - "Aring;": '\U000000C5', - "Ascr;": '\U0001D49C', - "Assign;": '\U00002254', - "Atilde;": '\U000000C3', - "Auml;": '\U000000C4', - "Backslash;": '\U00002216', - "Barv;": '\U00002AE7', - "Barwed;": '\U00002306', - "Bcy;": '\U00000411', - "Because;": '\U00002235', - "Bernoullis;": '\U0000212C', - "Beta;": '\U00000392', - "Bfr;": '\U0001D505', - "Bopf;": '\U0001D539', - "Breve;": '\U000002D8', - "Bscr;": '\U0000212C', - "Bumpeq;": '\U0000224E', - "CHcy;": '\U00000427', - "COPY;": '\U000000A9', - "Cacute;": '\U00000106', - "Cap;": '\U000022D2', - "CapitalDifferentialD;": '\U00002145', - "Cayleys;": '\U0000212D', - "Ccaron;": '\U0000010C', - "Ccedil;": '\U000000C7', - "Ccirc;": '\U00000108', - "Cconint;": '\U00002230', - "Cdot;": '\U0000010A', - "Cedilla;": '\U000000B8', - "CenterDot;": '\U000000B7', - "Cfr;": '\U0000212D', - "Chi;": '\U000003A7', - "CircleDot;": '\U00002299', - "CircleMinus;": '\U00002296', - "CirclePlus;": '\U00002295', - "CircleTimes;": '\U00002297', - "ClockwiseContourIntegral;": '\U00002232', - "CloseCurlyDoubleQuote;": '\U0000201D', - "CloseCurlyQuote;": '\U00002019', - "Colon;": '\U00002237', - "Colone;": '\U00002A74', - "Congruent;": '\U00002261', - "Conint;": '\U0000222F', - "ContourIntegral;": '\U0000222E', - "Copf;": '\U00002102', - "Coproduct;": '\U00002210', - "CounterClockwiseContourIntegral;": '\U00002233', - "Cross;": '\U00002A2F', - "Cscr;": '\U0001D49E', - "Cup;": '\U000022D3', - "CupCap;": '\U0000224D', - "DD;": '\U00002145', - "DDotrahd;": '\U00002911', - "DJcy;": '\U00000402', - "DScy;": '\U00000405', - "DZcy;": '\U0000040F', - "Dagger;": '\U00002021', - "Darr;": '\U000021A1', - "Dashv;": '\U00002AE4', - "Dcaron;": '\U0000010E', - "Dcy;": '\U00000414', - "Del;": '\U00002207', - "Delta;": '\U00000394', - "Dfr;": '\U0001D507', - "DiacriticalAcute;": '\U000000B4', - "DiacriticalDot;": '\U000002D9', - "DiacriticalDoubleAcute;": '\U000002DD', - "DiacriticalGrave;": '\U00000060', - "DiacriticalTilde;": '\U000002DC', - "Diamond;": '\U000022C4', - "DifferentialD;": '\U00002146', - "Dopf;": '\U0001D53B', - "Dot;": '\U000000A8', - "DotDot;": '\U000020DC', - "DotEqual;": '\U00002250', - "DoubleContourIntegral;": '\U0000222F', - "DoubleDot;": '\U000000A8', - "DoubleDownArrow;": '\U000021D3', - "DoubleLeftArrow;": '\U000021D0', - "DoubleLeftRightArrow;": '\U000021D4', - "DoubleLeftTee;": '\U00002AE4', - "DoubleLongLeftArrow;": '\U000027F8', - "DoubleLongLeftRightArrow;": '\U000027FA', - "DoubleLongRightArrow;": '\U000027F9', - "DoubleRightArrow;": '\U000021D2', - "DoubleRightTee;": '\U000022A8', - "DoubleUpArrow;": '\U000021D1', - "DoubleUpDownArrow;": '\U000021D5', - "DoubleVerticalBar;": '\U00002225', - "DownArrow;": '\U00002193', - "DownArrowBar;": '\U00002913', - "DownArrowUpArrow;": '\U000021F5', - "DownBreve;": '\U00000311', - "DownLeftRightVector;": '\U00002950', - "DownLeftTeeVector;": '\U0000295E', - "DownLeftVector;": '\U000021BD', - "DownLeftVectorBar;": '\U00002956', - "DownRightTeeVector;": '\U0000295F', - "DownRightVector;": '\U000021C1', - "DownRightVectorBar;": '\U00002957', - "DownTee;": '\U000022A4', - "DownTeeArrow;": '\U000021A7', - "Downarrow;": '\U000021D3', - "Dscr;": '\U0001D49F', - "Dstrok;": '\U00000110', - "ENG;": '\U0000014A', - "ETH;": '\U000000D0', - "Eacute;": '\U000000C9', - "Ecaron;": '\U0000011A', - "Ecirc;": '\U000000CA', - "Ecy;": '\U0000042D', - "Edot;": '\U00000116', - "Efr;": '\U0001D508', - "Egrave;": '\U000000C8', - "Element;": '\U00002208', - "Emacr;": '\U00000112', - "EmptySmallSquare;": '\U000025FB', - "EmptyVerySmallSquare;": '\U000025AB', - "Eogon;": '\U00000118', - "Eopf;": '\U0001D53C', - "Epsilon;": '\U00000395', - "Equal;": '\U00002A75', - "EqualTilde;": '\U00002242', - "Equilibrium;": '\U000021CC', - "Escr;": '\U00002130', - "Esim;": '\U00002A73', - "Eta;": '\U00000397', - "Euml;": '\U000000CB', - "Exists;": '\U00002203', - "ExponentialE;": '\U00002147', - "Fcy;": '\U00000424', - "Ffr;": '\U0001D509', - "FilledSmallSquare;": '\U000025FC', - "FilledVerySmallSquare;": '\U000025AA', - "Fopf;": '\U0001D53D', - "ForAll;": '\U00002200', - "Fouriertrf;": '\U00002131', - "Fscr;": '\U00002131', - "GJcy;": '\U00000403', - "GT;": '\U0000003E', - "Gamma;": '\U00000393', - "Gammad;": '\U000003DC', - "Gbreve;": '\U0000011E', - "Gcedil;": '\U00000122', - "Gcirc;": '\U0000011C', - "Gcy;": '\U00000413', - "Gdot;": '\U00000120', - "Gfr;": '\U0001D50A', - "Gg;": '\U000022D9', - "Gopf;": '\U0001D53E', - "GreaterEqual;": '\U00002265', - "GreaterEqualLess;": '\U000022DB', - "GreaterFullEqual;": '\U00002267', - "GreaterGreater;": '\U00002AA2', - "GreaterLess;": '\U00002277', - "GreaterSlantEqual;": '\U00002A7E', - "GreaterTilde;": '\U00002273', - "Gscr;": '\U0001D4A2', - "Gt;": '\U0000226B', - "HARDcy;": '\U0000042A', - "Hacek;": '\U000002C7', - "Hat;": '\U0000005E', - "Hcirc;": '\U00000124', - "Hfr;": '\U0000210C', - "HilbertSpace;": '\U0000210B', - "Hopf;": '\U0000210D', - "HorizontalLine;": '\U00002500', - "Hscr;": '\U0000210B', - "Hstrok;": '\U00000126', - "HumpDownHump;": '\U0000224E', - "HumpEqual;": '\U0000224F', - "IEcy;": '\U00000415', - "IJlig;": '\U00000132', - "IOcy;": '\U00000401', - "Iacute;": '\U000000CD', - "Icirc;": '\U000000CE', - "Icy;": '\U00000418', - "Idot;": '\U00000130', - "Ifr;": '\U00002111', - "Igrave;": '\U000000CC', - "Im;": '\U00002111', - "Imacr;": '\U0000012A', - "ImaginaryI;": '\U00002148', - "Implies;": '\U000021D2', - "Int;": '\U0000222C', - "Integral;": '\U0000222B', - "Intersection;": '\U000022C2', - "InvisibleComma;": '\U00002063', - "InvisibleTimes;": '\U00002062', - "Iogon;": '\U0000012E', - "Iopf;": '\U0001D540', - "Iota;": '\U00000399', - "Iscr;": '\U00002110', - "Itilde;": '\U00000128', - "Iukcy;": '\U00000406', - "Iuml;": '\U000000CF', - "Jcirc;": '\U00000134', - "Jcy;": '\U00000419', - "Jfr;": '\U0001D50D', - "Jopf;": '\U0001D541', - "Jscr;": '\U0001D4A5', - "Jsercy;": '\U00000408', - "Jukcy;": '\U00000404', - "KHcy;": '\U00000425', - "KJcy;": '\U0000040C', - "Kappa;": '\U0000039A', - "Kcedil;": '\U00000136', - "Kcy;": '\U0000041A', - "Kfr;": '\U0001D50E', - "Kopf;": '\U0001D542', - "Kscr;": '\U0001D4A6', - "LJcy;": '\U00000409', - "LT;": '\U0000003C', - "Lacute;": '\U00000139', - "Lambda;": '\U0000039B', - "Lang;": '\U000027EA', - "Laplacetrf;": '\U00002112', - "Larr;": '\U0000219E', - "Lcaron;": '\U0000013D', - "Lcedil;": '\U0000013B', - "Lcy;": '\U0000041B', - "LeftAngleBracket;": '\U000027E8', - "LeftArrow;": '\U00002190', - "LeftArrowBar;": '\U000021E4', - "LeftArrowRightArrow;": '\U000021C6', - "LeftCeiling;": '\U00002308', - "LeftDoubleBracket;": '\U000027E6', - "LeftDownTeeVector;": '\U00002961', - "LeftDownVector;": '\U000021C3', - "LeftDownVectorBar;": '\U00002959', - "LeftFloor;": '\U0000230A', - "LeftRightArrow;": '\U00002194', - "LeftRightVector;": '\U0000294E', - "LeftTee;": '\U000022A3', - "LeftTeeArrow;": '\U000021A4', - "LeftTeeVector;": '\U0000295A', - "LeftTriangle;": '\U000022B2', - "LeftTriangleBar;": '\U000029CF', - "LeftTriangleEqual;": '\U000022B4', - "LeftUpDownVector;": '\U00002951', - "LeftUpTeeVector;": '\U00002960', - "LeftUpVector;": '\U000021BF', - "LeftUpVectorBar;": '\U00002958', - "LeftVector;": '\U000021BC', - "LeftVectorBar;": '\U00002952', - "Leftarrow;": '\U000021D0', - "Leftrightarrow;": '\U000021D4', - "LessEqualGreater;": '\U000022DA', - "LessFullEqual;": '\U00002266', - "LessGreater;": '\U00002276', - "LessLess;": '\U00002AA1', - "LessSlantEqual;": '\U00002A7D', - "LessTilde;": '\U00002272', - "Lfr;": '\U0001D50F', - "Ll;": '\U000022D8', - "Lleftarrow;": '\U000021DA', - "Lmidot;": '\U0000013F', - "LongLeftArrow;": '\U000027F5', - "LongLeftRightArrow;": '\U000027F7', - "LongRightArrow;": '\U000027F6', - "Longleftarrow;": '\U000027F8', - "Longleftrightarrow;": '\U000027FA', - "Longrightarrow;": '\U000027F9', - "Lopf;": '\U0001D543', - "LowerLeftArrow;": '\U00002199', - "LowerRightArrow;": '\U00002198', - "Lscr;": '\U00002112', - "Lsh;": '\U000021B0', - "Lstrok;": '\U00000141', - "Lt;": '\U0000226A', - "Map;": '\U00002905', - "Mcy;": '\U0000041C', - "MediumSpace;": '\U0000205F', - "Mellintrf;": '\U00002133', - "Mfr;": '\U0001D510', - "MinusPlus;": '\U00002213', - "Mopf;": '\U0001D544', - "Mscr;": '\U00002133', - "Mu;": '\U0000039C', - "NJcy;": '\U0000040A', - "Nacute;": '\U00000143', - "Ncaron;": '\U00000147', - "Ncedil;": '\U00000145', - "Ncy;": '\U0000041D', - "NegativeMediumSpace;": '\U0000200B', - "NegativeThickSpace;": '\U0000200B', - "NegativeThinSpace;": '\U0000200B', - "NegativeVeryThinSpace;": '\U0000200B', - "NestedGreaterGreater;": '\U0000226B', - "NestedLessLess;": '\U0000226A', - "NewLine;": '\U0000000A', - "Nfr;": '\U0001D511', - "NoBreak;": '\U00002060', - "NonBreakingSpace;": '\U000000A0', - "Nopf;": '\U00002115', - "Not;": '\U00002AEC', - "NotCongruent;": '\U00002262', - "NotCupCap;": '\U0000226D', - "NotDoubleVerticalBar;": '\U00002226', - "NotElement;": '\U00002209', - "NotEqual;": '\U00002260', - "NotExists;": '\U00002204', - "NotGreater;": '\U0000226F', - "NotGreaterEqual;": '\U00002271', - "NotGreaterLess;": '\U00002279', - "NotGreaterTilde;": '\U00002275', - "NotLeftTriangle;": '\U000022EA', - "NotLeftTriangleEqual;": '\U000022EC', - "NotLess;": '\U0000226E', - "NotLessEqual;": '\U00002270', - "NotLessGreater;": '\U00002278', - "NotLessTilde;": '\U00002274', - "NotPrecedes;": '\U00002280', - "NotPrecedesSlantEqual;": '\U000022E0', - "NotReverseElement;": '\U0000220C', - "NotRightTriangle;": '\U000022EB', - "NotRightTriangleEqual;": '\U000022ED', - "NotSquareSubsetEqual;": '\U000022E2', - "NotSquareSupersetEqual;": '\U000022E3', - "NotSubsetEqual;": '\U00002288', - "NotSucceeds;": '\U00002281', - "NotSucceedsSlantEqual;": '\U000022E1', - "NotSupersetEqual;": '\U00002289', - "NotTilde;": '\U00002241', - "NotTildeEqual;": '\U00002244', - "NotTildeFullEqual;": '\U00002247', - "NotTildeTilde;": '\U00002249', - "NotVerticalBar;": '\U00002224', - "Nscr;": '\U0001D4A9', - "Ntilde;": '\U000000D1', - "Nu;": '\U0000039D', - "OElig;": '\U00000152', - "Oacute;": '\U000000D3', - "Ocirc;": '\U000000D4', - "Ocy;": '\U0000041E', - "Odblac;": '\U00000150', - "Ofr;": '\U0001D512', - "Ograve;": '\U000000D2', - "Omacr;": '\U0000014C', - "Omega;": '\U000003A9', - "Omicron;": '\U0000039F', - "Oopf;": '\U0001D546', - "OpenCurlyDoubleQuote;": '\U0000201C', - "OpenCurlyQuote;": '\U00002018', - "Or;": '\U00002A54', - "Oscr;": '\U0001D4AA', - "Oslash;": '\U000000D8', - "Otilde;": '\U000000D5', - "Otimes;": '\U00002A37', - "Ouml;": '\U000000D6', - "OverBar;": '\U0000203E', - "OverBrace;": '\U000023DE', - "OverBracket;": '\U000023B4', - "OverParenthesis;": '\U000023DC', - "PartialD;": '\U00002202', - "Pcy;": '\U0000041F', - "Pfr;": '\U0001D513', - "Phi;": '\U000003A6', - "Pi;": '\U000003A0', - "PlusMinus;": '\U000000B1', - "Poincareplane;": '\U0000210C', - "Popf;": '\U00002119', - "Pr;": '\U00002ABB', - "Precedes;": '\U0000227A', - "PrecedesEqual;": '\U00002AAF', - "PrecedesSlantEqual;": '\U0000227C', - "PrecedesTilde;": '\U0000227E', - "Prime;": '\U00002033', - "Product;": '\U0000220F', - "Proportion;": '\U00002237', - "Proportional;": '\U0000221D', - "Pscr;": '\U0001D4AB', - "Psi;": '\U000003A8', - "QUOT;": '\U00000022', - "Qfr;": '\U0001D514', - "Qopf;": '\U0000211A', - "Qscr;": '\U0001D4AC', - "RBarr;": '\U00002910', - "REG;": '\U000000AE', - "Racute;": '\U00000154', - "Rang;": '\U000027EB', - "Rarr;": '\U000021A0', - "Rarrtl;": '\U00002916', - "Rcaron;": '\U00000158', - "Rcedil;": '\U00000156', - "Rcy;": '\U00000420', - "Re;": '\U0000211C', - "ReverseElement;": '\U0000220B', - "ReverseEquilibrium;": '\U000021CB', - "ReverseUpEquilibrium;": '\U0000296F', - "Rfr;": '\U0000211C', - "Rho;": '\U000003A1', - "RightAngleBracket;": '\U000027E9', - "RightArrow;": '\U00002192', - "RightArrowBar;": '\U000021E5', - "RightArrowLeftArrow;": '\U000021C4', - "RightCeiling;": '\U00002309', - "RightDoubleBracket;": '\U000027E7', - "RightDownTeeVector;": '\U0000295D', - "RightDownVector;": '\U000021C2', - "RightDownVectorBar;": '\U00002955', - "RightFloor;": '\U0000230B', - "RightTee;": '\U000022A2', - "RightTeeArrow;": '\U000021A6', - "RightTeeVector;": '\U0000295B', - "RightTriangle;": '\U000022B3', - "RightTriangleBar;": '\U000029D0', - "RightTriangleEqual;": '\U000022B5', - "RightUpDownVector;": '\U0000294F', - "RightUpTeeVector;": '\U0000295C', - "RightUpVector;": '\U000021BE', - "RightUpVectorBar;": '\U00002954', - "RightVector;": '\U000021C0', - "RightVectorBar;": '\U00002953', - "Rightarrow;": '\U000021D2', - "Ropf;": '\U0000211D', - "RoundImplies;": '\U00002970', - "Rrightarrow;": '\U000021DB', - "Rscr;": '\U0000211B', - "Rsh;": '\U000021B1', - "RuleDelayed;": '\U000029F4', - "SHCHcy;": '\U00000429', - "SHcy;": '\U00000428', - "SOFTcy;": '\U0000042C', - "Sacute;": '\U0000015A', - "Sc;": '\U00002ABC', - "Scaron;": '\U00000160', - "Scedil;": '\U0000015E', - "Scirc;": '\U0000015C', - "Scy;": '\U00000421', - "Sfr;": '\U0001D516', - "ShortDownArrow;": '\U00002193', - "ShortLeftArrow;": '\U00002190', - "ShortRightArrow;": '\U00002192', - "ShortUpArrow;": '\U00002191', - "Sigma;": '\U000003A3', - "SmallCircle;": '\U00002218', - "Sopf;": '\U0001D54A', - "Sqrt;": '\U0000221A', - "Square;": '\U000025A1', - "SquareIntersection;": '\U00002293', - "SquareSubset;": '\U0000228F', - "SquareSubsetEqual;": '\U00002291', - "SquareSuperset;": '\U00002290', - "SquareSupersetEqual;": '\U00002292', - "SquareUnion;": '\U00002294', - "Sscr;": '\U0001D4AE', - "Star;": '\U000022C6', - "Sub;": '\U000022D0', - "Subset;": '\U000022D0', - "SubsetEqual;": '\U00002286', - "Succeeds;": '\U0000227B', - "SucceedsEqual;": '\U00002AB0', - "SucceedsSlantEqual;": '\U0000227D', - "SucceedsTilde;": '\U0000227F', - "SuchThat;": '\U0000220B', - "Sum;": '\U00002211', - "Sup;": '\U000022D1', - "Superset;": '\U00002283', - "SupersetEqual;": '\U00002287', - "Supset;": '\U000022D1', - "THORN;": '\U000000DE', - "TRADE;": '\U00002122', - "TSHcy;": '\U0000040B', - "TScy;": '\U00000426', - "Tab;": '\U00000009', - "Tau;": '\U000003A4', - "Tcaron;": '\U00000164', - "Tcedil;": '\U00000162', - "Tcy;": '\U00000422', - "Tfr;": '\U0001D517', - "Therefore;": '\U00002234', - "Theta;": '\U00000398', - "ThinSpace;": '\U00002009', - "Tilde;": '\U0000223C', - "TildeEqual;": '\U00002243', - "TildeFullEqual;": '\U00002245', - "TildeTilde;": '\U00002248', - "Topf;": '\U0001D54B', - "TripleDot;": '\U000020DB', - "Tscr;": '\U0001D4AF', - "Tstrok;": '\U00000166', - "Uacute;": '\U000000DA', - "Uarr;": '\U0000219F', - "Uarrocir;": '\U00002949', - "Ubrcy;": '\U0000040E', - "Ubreve;": '\U0000016C', - "Ucirc;": '\U000000DB', - "Ucy;": '\U00000423', - "Udblac;": '\U00000170', - "Ufr;": '\U0001D518', - "Ugrave;": '\U000000D9', - "Umacr;": '\U0000016A', - "UnderBar;": '\U0000005F', - "UnderBrace;": '\U000023DF', - "UnderBracket;": '\U000023B5', - "UnderParenthesis;": '\U000023DD', - "Union;": '\U000022C3', - "UnionPlus;": '\U0000228E', - "Uogon;": '\U00000172', - "Uopf;": '\U0001D54C', - "UpArrow;": '\U00002191', - "UpArrowBar;": '\U00002912', - "UpArrowDownArrow;": '\U000021C5', - "UpDownArrow;": '\U00002195', - "UpEquilibrium;": '\U0000296E', - "UpTee;": '\U000022A5', - "UpTeeArrow;": '\U000021A5', - "Uparrow;": '\U000021D1', - "Updownarrow;": '\U000021D5', - "UpperLeftArrow;": '\U00002196', - "UpperRightArrow;": '\U00002197', - "Upsi;": '\U000003D2', - "Upsilon;": '\U000003A5', - "Uring;": '\U0000016E', - "Uscr;": '\U0001D4B0', - "Utilde;": '\U00000168', - "Uuml;": '\U000000DC', - "VDash;": '\U000022AB', - "Vbar;": '\U00002AEB', - "Vcy;": '\U00000412', - "Vdash;": '\U000022A9', - "Vdashl;": '\U00002AE6', - "Vee;": '\U000022C1', - "Verbar;": '\U00002016', - "Vert;": '\U00002016', - "VerticalBar;": '\U00002223', - "VerticalLine;": '\U0000007C', - "VerticalSeparator;": '\U00002758', - "VerticalTilde;": '\U00002240', - "VeryThinSpace;": '\U0000200A', - "Vfr;": '\U0001D519', - "Vopf;": '\U0001D54D', - "Vscr;": '\U0001D4B1', - "Vvdash;": '\U000022AA', - "Wcirc;": '\U00000174', - "Wedge;": '\U000022C0', - "Wfr;": '\U0001D51A', - "Wopf;": '\U0001D54E', - "Wscr;": '\U0001D4B2', - "Xfr;": '\U0001D51B', - "Xi;": '\U0000039E', - "Xopf;": '\U0001D54F', - "Xscr;": '\U0001D4B3', - "YAcy;": '\U0000042F', - "YIcy;": '\U00000407', - "YUcy;": '\U0000042E', - "Yacute;": '\U000000DD', - "Ycirc;": '\U00000176', - "Ycy;": '\U0000042B', - "Yfr;": '\U0001D51C', - "Yopf;": '\U0001D550', - "Yscr;": '\U0001D4B4', - "Yuml;": '\U00000178', - "ZHcy;": '\U00000416', - "Zacute;": '\U00000179', - "Zcaron;": '\U0000017D', - "Zcy;": '\U00000417', - "Zdot;": '\U0000017B', - "ZeroWidthSpace;": '\U0000200B', - "Zeta;": '\U00000396', - "Zfr;": '\U00002128', - "Zopf;": '\U00002124', - "Zscr;": '\U0001D4B5', - "aacute;": '\U000000E1', - "abreve;": '\U00000103', - "ac;": '\U0000223E', - "acd;": '\U0000223F', - "acirc;": '\U000000E2', - "acute;": '\U000000B4', - "acy;": '\U00000430', - "aelig;": '\U000000E6', - "af;": '\U00002061', - "afr;": '\U0001D51E', - "agrave;": '\U000000E0', - "alefsym;": '\U00002135', - "aleph;": '\U00002135', - "alpha;": '\U000003B1', - "amacr;": '\U00000101', - "amalg;": '\U00002A3F', - "amp;": '\U00000026', - "and;": '\U00002227', - "andand;": '\U00002A55', - "andd;": '\U00002A5C', - "andslope;": '\U00002A58', - "andv;": '\U00002A5A', - "ang;": '\U00002220', - "ange;": '\U000029A4', - "angle;": '\U00002220', - "angmsd;": '\U00002221', - "angmsdaa;": '\U000029A8', - "angmsdab;": '\U000029A9', - "angmsdac;": '\U000029AA', - "angmsdad;": '\U000029AB', - "angmsdae;": '\U000029AC', - "angmsdaf;": '\U000029AD', - "angmsdag;": '\U000029AE', - "angmsdah;": '\U000029AF', - "angrt;": '\U0000221F', - "angrtvb;": '\U000022BE', - "angrtvbd;": '\U0000299D', - "angsph;": '\U00002222', - "angst;": '\U000000C5', - "angzarr;": '\U0000237C', - "aogon;": '\U00000105', - "aopf;": '\U0001D552', - "ap;": '\U00002248', - "apE;": '\U00002A70', - "apacir;": '\U00002A6F', - "ape;": '\U0000224A', - "apid;": '\U0000224B', - "apos;": '\U00000027', - "approx;": '\U00002248', - "approxeq;": '\U0000224A', - "aring;": '\U000000E5', - "ascr;": '\U0001D4B6', - "ast;": '\U0000002A', - "asymp;": '\U00002248', - "asympeq;": '\U0000224D', - "atilde;": '\U000000E3', - "auml;": '\U000000E4', - "awconint;": '\U00002233', - "awint;": '\U00002A11', - "bNot;": '\U00002AED', - "backcong;": '\U0000224C', - "backepsilon;": '\U000003F6', - "backprime;": '\U00002035', - "backsim;": '\U0000223D', - "backsimeq;": '\U000022CD', - "barvee;": '\U000022BD', - "barwed;": '\U00002305', - "barwedge;": '\U00002305', - "bbrk;": '\U000023B5', - "bbrktbrk;": '\U000023B6', - "bcong;": '\U0000224C', - "bcy;": '\U00000431', - "bdquo;": '\U0000201E', - "becaus;": '\U00002235', - "because;": '\U00002235', - "bemptyv;": '\U000029B0', - "bepsi;": '\U000003F6', - "bernou;": '\U0000212C', - "beta;": '\U000003B2', - "beth;": '\U00002136', - "between;": '\U0000226C', - "bfr;": '\U0001D51F', - "bigcap;": '\U000022C2', - "bigcirc;": '\U000025EF', - "bigcup;": '\U000022C3', - "bigodot;": '\U00002A00', - "bigoplus;": '\U00002A01', - "bigotimes;": '\U00002A02', - "bigsqcup;": '\U00002A06', - "bigstar;": '\U00002605', - "bigtriangledown;": '\U000025BD', - "bigtriangleup;": '\U000025B3', - "biguplus;": '\U00002A04', - "bigvee;": '\U000022C1', - "bigwedge;": '\U000022C0', - "bkarow;": '\U0000290D', - "blacklozenge;": '\U000029EB', - "blacksquare;": '\U000025AA', - "blacktriangle;": '\U000025B4', - "blacktriangledown;": '\U000025BE', - "blacktriangleleft;": '\U000025C2', - "blacktriangleright;": '\U000025B8', - "blank;": '\U00002423', - "blk12;": '\U00002592', - "blk14;": '\U00002591', - "blk34;": '\U00002593', - "block;": '\U00002588', - "bnot;": '\U00002310', - "bopf;": '\U0001D553', - "bot;": '\U000022A5', - "bottom;": '\U000022A5', - "bowtie;": '\U000022C8', - "boxDL;": '\U00002557', - "boxDR;": '\U00002554', - "boxDl;": '\U00002556', - "boxDr;": '\U00002553', - "boxH;": '\U00002550', - "boxHD;": '\U00002566', - "boxHU;": '\U00002569', - "boxHd;": '\U00002564', - "boxHu;": '\U00002567', - "boxUL;": '\U0000255D', - "boxUR;": '\U0000255A', - "boxUl;": '\U0000255C', - "boxUr;": '\U00002559', - "boxV;": '\U00002551', - "boxVH;": '\U0000256C', - "boxVL;": '\U00002563', - "boxVR;": '\U00002560', - "boxVh;": '\U0000256B', - "boxVl;": '\U00002562', - "boxVr;": '\U0000255F', - "boxbox;": '\U000029C9', - "boxdL;": '\U00002555', - "boxdR;": '\U00002552', - "boxdl;": '\U00002510', - "boxdr;": '\U0000250C', - "boxh;": '\U00002500', - "boxhD;": '\U00002565', - "boxhU;": '\U00002568', - "boxhd;": '\U0000252C', - "boxhu;": '\U00002534', - "boxminus;": '\U0000229F', - "boxplus;": '\U0000229E', - "boxtimes;": '\U000022A0', - "boxuL;": '\U0000255B', - "boxuR;": '\U00002558', - "boxul;": '\U00002518', - "boxur;": '\U00002514', - "boxv;": '\U00002502', - "boxvH;": '\U0000256A', - "boxvL;": '\U00002561', - "boxvR;": '\U0000255E', - "boxvh;": '\U0000253C', - "boxvl;": '\U00002524', - "boxvr;": '\U0000251C', - "bprime;": '\U00002035', - "breve;": '\U000002D8', - "brvbar;": '\U000000A6', - "bscr;": '\U0001D4B7', - "bsemi;": '\U0000204F', - "bsim;": '\U0000223D', - "bsime;": '\U000022CD', - "bsol;": '\U0000005C', - "bsolb;": '\U000029C5', - "bsolhsub;": '\U000027C8', - "bull;": '\U00002022', - "bullet;": '\U00002022', - "bump;": '\U0000224E', - "bumpE;": '\U00002AAE', - "bumpe;": '\U0000224F', - "bumpeq;": '\U0000224F', - "cacute;": '\U00000107', - "cap;": '\U00002229', - "capand;": '\U00002A44', - "capbrcup;": '\U00002A49', - "capcap;": '\U00002A4B', - "capcup;": '\U00002A47', - "capdot;": '\U00002A40', - "caret;": '\U00002041', - "caron;": '\U000002C7', - "ccaps;": '\U00002A4D', - "ccaron;": '\U0000010D', - "ccedil;": '\U000000E7', - "ccirc;": '\U00000109', - "ccups;": '\U00002A4C', - "ccupssm;": '\U00002A50', - "cdot;": '\U0000010B', - "cedil;": '\U000000B8', - "cemptyv;": '\U000029B2', - "cent;": '\U000000A2', - "centerdot;": '\U000000B7', - "cfr;": '\U0001D520', - "chcy;": '\U00000447', - "check;": '\U00002713', - "checkmark;": '\U00002713', - "chi;": '\U000003C7', - "cir;": '\U000025CB', - "cirE;": '\U000029C3', - "circ;": '\U000002C6', - "circeq;": '\U00002257', - "circlearrowleft;": '\U000021BA', - "circlearrowright;": '\U000021BB', - "circledR;": '\U000000AE', - "circledS;": '\U000024C8', - "circledast;": '\U0000229B', - "circledcirc;": '\U0000229A', - "circleddash;": '\U0000229D', - "cire;": '\U00002257', - "cirfnint;": '\U00002A10', - "cirmid;": '\U00002AEF', - "cirscir;": '\U000029C2', - "clubs;": '\U00002663', - "clubsuit;": '\U00002663', - "colon;": '\U0000003A', - "colone;": '\U00002254', - "coloneq;": '\U00002254', - "comma;": '\U0000002C', - "commat;": '\U00000040', - "comp;": '\U00002201', - "compfn;": '\U00002218', - "complement;": '\U00002201', - "complexes;": '\U00002102', - "cong;": '\U00002245', - "congdot;": '\U00002A6D', - "conint;": '\U0000222E', - "copf;": '\U0001D554', - "coprod;": '\U00002210', - "copy;": '\U000000A9', - "copysr;": '\U00002117', - "crarr;": '\U000021B5', - "cross;": '\U00002717', - "cscr;": '\U0001D4B8', - "csub;": '\U00002ACF', - "csube;": '\U00002AD1', - "csup;": '\U00002AD0', - "csupe;": '\U00002AD2', - "ctdot;": '\U000022EF', - "cudarrl;": '\U00002938', - "cudarrr;": '\U00002935', - "cuepr;": '\U000022DE', - "cuesc;": '\U000022DF', - "cularr;": '\U000021B6', - "cularrp;": '\U0000293D', - "cup;": '\U0000222A', - "cupbrcap;": '\U00002A48', - "cupcap;": '\U00002A46', - "cupcup;": '\U00002A4A', - "cupdot;": '\U0000228D', - "cupor;": '\U00002A45', - "curarr;": '\U000021B7', - "curarrm;": '\U0000293C', - "curlyeqprec;": '\U000022DE', - "curlyeqsucc;": '\U000022DF', - "curlyvee;": '\U000022CE', - "curlywedge;": '\U000022CF', - "curren;": '\U000000A4', - "curvearrowleft;": '\U000021B6', - "curvearrowright;": '\U000021B7', - "cuvee;": '\U000022CE', - "cuwed;": '\U000022CF', - "cwconint;": '\U00002232', - "cwint;": '\U00002231', - "cylcty;": '\U0000232D', - "dArr;": '\U000021D3', - "dHar;": '\U00002965', - "dagger;": '\U00002020', - "daleth;": '\U00002138', - "darr;": '\U00002193', - "dash;": '\U00002010', - "dashv;": '\U000022A3', - "dbkarow;": '\U0000290F', - "dblac;": '\U000002DD', - "dcaron;": '\U0000010F', - "dcy;": '\U00000434', - "dd;": '\U00002146', - "ddagger;": '\U00002021', - "ddarr;": '\U000021CA', - "ddotseq;": '\U00002A77', - "deg;": '\U000000B0', - "delta;": '\U000003B4', - "demptyv;": '\U000029B1', - "dfisht;": '\U0000297F', - "dfr;": '\U0001D521', - "dharl;": '\U000021C3', - "dharr;": '\U000021C2', - "diam;": '\U000022C4', - "diamond;": '\U000022C4', - "diamondsuit;": '\U00002666', - "diams;": '\U00002666', - "die;": '\U000000A8', - "digamma;": '\U000003DD', - "disin;": '\U000022F2', - "div;": '\U000000F7', - "divide;": '\U000000F7', - "divideontimes;": '\U000022C7', - "divonx;": '\U000022C7', - "djcy;": '\U00000452', - "dlcorn;": '\U0000231E', - "dlcrop;": '\U0000230D', - "dollar;": '\U00000024', - "dopf;": '\U0001D555', - "dot;": '\U000002D9', - "doteq;": '\U00002250', - "doteqdot;": '\U00002251', - "dotminus;": '\U00002238', - "dotplus;": '\U00002214', - "dotsquare;": '\U000022A1', - "doublebarwedge;": '\U00002306', - "downarrow;": '\U00002193', - "downdownarrows;": '\U000021CA', - "downharpoonleft;": '\U000021C3', - "downharpoonright;": '\U000021C2', - "drbkarow;": '\U00002910', - "drcorn;": '\U0000231F', - "drcrop;": '\U0000230C', - "dscr;": '\U0001D4B9', - "dscy;": '\U00000455', - "dsol;": '\U000029F6', - "dstrok;": '\U00000111', - "dtdot;": '\U000022F1', - "dtri;": '\U000025BF', - "dtrif;": '\U000025BE', - "duarr;": '\U000021F5', - "duhar;": '\U0000296F', - "dwangle;": '\U000029A6', - "dzcy;": '\U0000045F', - "dzigrarr;": '\U000027FF', - "eDDot;": '\U00002A77', - "eDot;": '\U00002251', - "eacute;": '\U000000E9', - "easter;": '\U00002A6E', - "ecaron;": '\U0000011B', - "ecir;": '\U00002256', - "ecirc;": '\U000000EA', - "ecolon;": '\U00002255', - "ecy;": '\U0000044D', - "edot;": '\U00000117', - "ee;": '\U00002147', - "efDot;": '\U00002252', - "efr;": '\U0001D522', - "eg;": '\U00002A9A', - "egrave;": '\U000000E8', - "egs;": '\U00002A96', - "egsdot;": '\U00002A98', - "el;": '\U00002A99', - "elinters;": '\U000023E7', - "ell;": '\U00002113', - "els;": '\U00002A95', - "elsdot;": '\U00002A97', - "emacr;": '\U00000113', - "empty;": '\U00002205', - "emptyset;": '\U00002205', - "emptyv;": '\U00002205', - "emsp;": '\U00002003', - "emsp13;": '\U00002004', - "emsp14;": '\U00002005', - "eng;": '\U0000014B', - "ensp;": '\U00002002', - "eogon;": '\U00000119', - "eopf;": '\U0001D556', - "epar;": '\U000022D5', - "eparsl;": '\U000029E3', - "eplus;": '\U00002A71', - "epsi;": '\U000003B5', - "epsilon;": '\U000003B5', - "epsiv;": '\U000003F5', - "eqcirc;": '\U00002256', - "eqcolon;": '\U00002255', - "eqsim;": '\U00002242', - "eqslantgtr;": '\U00002A96', - "eqslantless;": '\U00002A95', - "equals;": '\U0000003D', - "equest;": '\U0000225F', - "equiv;": '\U00002261', - "equivDD;": '\U00002A78', - "eqvparsl;": '\U000029E5', - "erDot;": '\U00002253', - "erarr;": '\U00002971', - "escr;": '\U0000212F', - "esdot;": '\U00002250', - "esim;": '\U00002242', - "eta;": '\U000003B7', - "eth;": '\U000000F0', - "euml;": '\U000000EB', - "euro;": '\U000020AC', - "excl;": '\U00000021', - "exist;": '\U00002203', - "expectation;": '\U00002130', - "exponentiale;": '\U00002147', - "fallingdotseq;": '\U00002252', - "fcy;": '\U00000444', - "female;": '\U00002640', - "ffilig;": '\U0000FB03', - "fflig;": '\U0000FB00', - "ffllig;": '\U0000FB04', - "ffr;": '\U0001D523', - "filig;": '\U0000FB01', - "flat;": '\U0000266D', - "fllig;": '\U0000FB02', - "fltns;": '\U000025B1', - "fnof;": '\U00000192', - "fopf;": '\U0001D557', - "forall;": '\U00002200', - "fork;": '\U000022D4', - "forkv;": '\U00002AD9', - "fpartint;": '\U00002A0D', - "frac12;": '\U000000BD', - "frac13;": '\U00002153', - "frac14;": '\U000000BC', - "frac15;": '\U00002155', - "frac16;": '\U00002159', - "frac18;": '\U0000215B', - "frac23;": '\U00002154', - "frac25;": '\U00002156', - "frac34;": '\U000000BE', - "frac35;": '\U00002157', - "frac38;": '\U0000215C', - "frac45;": '\U00002158', - "frac56;": '\U0000215A', - "frac58;": '\U0000215D', - "frac78;": '\U0000215E', - "frasl;": '\U00002044', - "frown;": '\U00002322', - "fscr;": '\U0001D4BB', - "gE;": '\U00002267', - "gEl;": '\U00002A8C', - "gacute;": '\U000001F5', - "gamma;": '\U000003B3', - "gammad;": '\U000003DD', - "gap;": '\U00002A86', - "gbreve;": '\U0000011F', - "gcirc;": '\U0000011D', - "gcy;": '\U00000433', - "gdot;": '\U00000121', - "ge;": '\U00002265', - "gel;": '\U000022DB', - "geq;": '\U00002265', - "geqq;": '\U00002267', - "geqslant;": '\U00002A7E', - "ges;": '\U00002A7E', - "gescc;": '\U00002AA9', - "gesdot;": '\U00002A80', - "gesdoto;": '\U00002A82', - "gesdotol;": '\U00002A84', - "gesles;": '\U00002A94', - "gfr;": '\U0001D524', - "gg;": '\U0000226B', - "ggg;": '\U000022D9', - "gimel;": '\U00002137', - "gjcy;": '\U00000453', - "gl;": '\U00002277', - "glE;": '\U00002A92', - "gla;": '\U00002AA5', - "glj;": '\U00002AA4', - "gnE;": '\U00002269', - "gnap;": '\U00002A8A', - "gnapprox;": '\U00002A8A', - "gne;": '\U00002A88', - "gneq;": '\U00002A88', - "gneqq;": '\U00002269', - "gnsim;": '\U000022E7', - "gopf;": '\U0001D558', - "grave;": '\U00000060', - "gscr;": '\U0000210A', - "gsim;": '\U00002273', - "gsime;": '\U00002A8E', - "gsiml;": '\U00002A90', - "gt;": '\U0000003E', - "gtcc;": '\U00002AA7', - "gtcir;": '\U00002A7A', - "gtdot;": '\U000022D7', - "gtlPar;": '\U00002995', - "gtquest;": '\U00002A7C', - "gtrapprox;": '\U00002A86', - "gtrarr;": '\U00002978', - "gtrdot;": '\U000022D7', - "gtreqless;": '\U000022DB', - "gtreqqless;": '\U00002A8C', - "gtrless;": '\U00002277', - "gtrsim;": '\U00002273', - "hArr;": '\U000021D4', - "hairsp;": '\U0000200A', - "half;": '\U000000BD', - "hamilt;": '\U0000210B', - "hardcy;": '\U0000044A', - "harr;": '\U00002194', - "harrcir;": '\U00002948', - "harrw;": '\U000021AD', - "hbar;": '\U0000210F', - "hcirc;": '\U00000125', - "hearts;": '\U00002665', - "heartsuit;": '\U00002665', - "hellip;": '\U00002026', - "hercon;": '\U000022B9', - "hfr;": '\U0001D525', - "hksearow;": '\U00002925', - "hkswarow;": '\U00002926', - "hoarr;": '\U000021FF', - "homtht;": '\U0000223B', - "hookleftarrow;": '\U000021A9', - "hookrightarrow;": '\U000021AA', - "hopf;": '\U0001D559', - "horbar;": '\U00002015', - "hscr;": '\U0001D4BD', - "hslash;": '\U0000210F', - "hstrok;": '\U00000127', - "hybull;": '\U00002043', - "hyphen;": '\U00002010', - "iacute;": '\U000000ED', - "ic;": '\U00002063', - "icirc;": '\U000000EE', - "icy;": '\U00000438', - "iecy;": '\U00000435', - "iexcl;": '\U000000A1', - "iff;": '\U000021D4', - "ifr;": '\U0001D526', - "igrave;": '\U000000EC', - "ii;": '\U00002148', - "iiiint;": '\U00002A0C', - "iiint;": '\U0000222D', - "iinfin;": '\U000029DC', - "iiota;": '\U00002129', - "ijlig;": '\U00000133', - "imacr;": '\U0000012B', - "image;": '\U00002111', - "imagline;": '\U00002110', - "imagpart;": '\U00002111', - "imath;": '\U00000131', - "imof;": '\U000022B7', - "imped;": '\U000001B5', - "in;": '\U00002208', - "incare;": '\U00002105', - "infin;": '\U0000221E', - "infintie;": '\U000029DD', - "inodot;": '\U00000131', - "int;": '\U0000222B', - "intcal;": '\U000022BA', - "integers;": '\U00002124', - "intercal;": '\U000022BA', - "intlarhk;": '\U00002A17', - "intprod;": '\U00002A3C', - "iocy;": '\U00000451', - "iogon;": '\U0000012F', - "iopf;": '\U0001D55A', - "iota;": '\U000003B9', - "iprod;": '\U00002A3C', - "iquest;": '\U000000BF', - "iscr;": '\U0001D4BE', - "isin;": '\U00002208', - "isinE;": '\U000022F9', - "isindot;": '\U000022F5', - "isins;": '\U000022F4', - "isinsv;": '\U000022F3', - "isinv;": '\U00002208', - "it;": '\U00002062', - "itilde;": '\U00000129', - "iukcy;": '\U00000456', - "iuml;": '\U000000EF', - "jcirc;": '\U00000135', - "jcy;": '\U00000439', - "jfr;": '\U0001D527', - "jmath;": '\U00000237', - "jopf;": '\U0001D55B', - "jscr;": '\U0001D4BF', - "jsercy;": '\U00000458', - "jukcy;": '\U00000454', - "kappa;": '\U000003BA', - "kappav;": '\U000003F0', - "kcedil;": '\U00000137', - "kcy;": '\U0000043A', - "kfr;": '\U0001D528', - "kgreen;": '\U00000138', - "khcy;": '\U00000445', - "kjcy;": '\U0000045C', - "kopf;": '\U0001D55C', - "kscr;": '\U0001D4C0', - "lAarr;": '\U000021DA', - "lArr;": '\U000021D0', - "lAtail;": '\U0000291B', - "lBarr;": '\U0000290E', - "lE;": '\U00002266', - "lEg;": '\U00002A8B', - "lHar;": '\U00002962', - "lacute;": '\U0000013A', - "laemptyv;": '\U000029B4', - "lagran;": '\U00002112', - "lambda;": '\U000003BB', - "lang;": '\U000027E8', - "langd;": '\U00002991', - "langle;": '\U000027E8', - "lap;": '\U00002A85', - "laquo;": '\U000000AB', - "larr;": '\U00002190', - "larrb;": '\U000021E4', - "larrbfs;": '\U0000291F', - "larrfs;": '\U0000291D', - "larrhk;": '\U000021A9', - "larrlp;": '\U000021AB', - "larrpl;": '\U00002939', - "larrsim;": '\U00002973', - "larrtl;": '\U000021A2', - "lat;": '\U00002AAB', - "latail;": '\U00002919', - "late;": '\U00002AAD', - "lbarr;": '\U0000290C', - "lbbrk;": '\U00002772', - "lbrace;": '\U0000007B', - "lbrack;": '\U0000005B', - "lbrke;": '\U0000298B', - "lbrksld;": '\U0000298F', - "lbrkslu;": '\U0000298D', - "lcaron;": '\U0000013E', - "lcedil;": '\U0000013C', - "lceil;": '\U00002308', - "lcub;": '\U0000007B', - "lcy;": '\U0000043B', - "ldca;": '\U00002936', - "ldquo;": '\U0000201C', - "ldquor;": '\U0000201E', - "ldrdhar;": '\U00002967', - "ldrushar;": '\U0000294B', - "ldsh;": '\U000021B2', - "le;": '\U00002264', - "leftarrow;": '\U00002190', - "leftarrowtail;": '\U000021A2', - "leftharpoondown;": '\U000021BD', - "leftharpoonup;": '\U000021BC', - "leftleftarrows;": '\U000021C7', - "leftrightarrow;": '\U00002194', - "leftrightarrows;": '\U000021C6', - "leftrightharpoons;": '\U000021CB', - "leftrightsquigarrow;": '\U000021AD', - "leftthreetimes;": '\U000022CB', - "leg;": '\U000022DA', - "leq;": '\U00002264', - "leqq;": '\U00002266', - "leqslant;": '\U00002A7D', - "les;": '\U00002A7D', - "lescc;": '\U00002AA8', - "lesdot;": '\U00002A7F', - "lesdoto;": '\U00002A81', - "lesdotor;": '\U00002A83', - "lesges;": '\U00002A93', - "lessapprox;": '\U00002A85', - "lessdot;": '\U000022D6', - "lesseqgtr;": '\U000022DA', - "lesseqqgtr;": '\U00002A8B', - "lessgtr;": '\U00002276', - "lesssim;": '\U00002272', - "lfisht;": '\U0000297C', - "lfloor;": '\U0000230A', - "lfr;": '\U0001D529', - "lg;": '\U00002276', - "lgE;": '\U00002A91', - "lhard;": '\U000021BD', - "lharu;": '\U000021BC', - "lharul;": '\U0000296A', - "lhblk;": '\U00002584', - "ljcy;": '\U00000459', - "ll;": '\U0000226A', - "llarr;": '\U000021C7', - "llcorner;": '\U0000231E', - "llhard;": '\U0000296B', - "lltri;": '\U000025FA', - "lmidot;": '\U00000140', - "lmoust;": '\U000023B0', - "lmoustache;": '\U000023B0', - "lnE;": '\U00002268', - "lnap;": '\U00002A89', - "lnapprox;": '\U00002A89', - "lne;": '\U00002A87', - "lneq;": '\U00002A87', - "lneqq;": '\U00002268', - "lnsim;": '\U000022E6', - "loang;": '\U000027EC', - "loarr;": '\U000021FD', - "lobrk;": '\U000027E6', - "longleftarrow;": '\U000027F5', - "longleftrightarrow;": '\U000027F7', - "longmapsto;": '\U000027FC', - "longrightarrow;": '\U000027F6', - "looparrowleft;": '\U000021AB', - "looparrowright;": '\U000021AC', - "lopar;": '\U00002985', - "lopf;": '\U0001D55D', - "loplus;": '\U00002A2D', - "lotimes;": '\U00002A34', - "lowast;": '\U00002217', - "lowbar;": '\U0000005F', - "loz;": '\U000025CA', - "lozenge;": '\U000025CA', - "lozf;": '\U000029EB', - "lpar;": '\U00000028', - "lparlt;": '\U00002993', - "lrarr;": '\U000021C6', - "lrcorner;": '\U0000231F', - "lrhar;": '\U000021CB', - "lrhard;": '\U0000296D', - "lrm;": '\U0000200E', - "lrtri;": '\U000022BF', - "lsaquo;": '\U00002039', - "lscr;": '\U0001D4C1', - "lsh;": '\U000021B0', - "lsim;": '\U00002272', - "lsime;": '\U00002A8D', - "lsimg;": '\U00002A8F', - "lsqb;": '\U0000005B', - "lsquo;": '\U00002018', - "lsquor;": '\U0000201A', - "lstrok;": '\U00000142', - "lt;": '\U0000003C', - "ltcc;": '\U00002AA6', - "ltcir;": '\U00002A79', - "ltdot;": '\U000022D6', - "lthree;": '\U000022CB', - "ltimes;": '\U000022C9', - "ltlarr;": '\U00002976', - "ltquest;": '\U00002A7B', - "ltrPar;": '\U00002996', - "ltri;": '\U000025C3', - "ltrie;": '\U000022B4', - "ltrif;": '\U000025C2', - "lurdshar;": '\U0000294A', - "luruhar;": '\U00002966', - "mDDot;": '\U0000223A', - "macr;": '\U000000AF', - "male;": '\U00002642', - "malt;": '\U00002720', - "maltese;": '\U00002720', - "map;": '\U000021A6', - "mapsto;": '\U000021A6', - "mapstodown;": '\U000021A7', - "mapstoleft;": '\U000021A4', - "mapstoup;": '\U000021A5', - "marker;": '\U000025AE', - "mcomma;": '\U00002A29', - "mcy;": '\U0000043C', - "mdash;": '\U00002014', - "measuredangle;": '\U00002221', - "mfr;": '\U0001D52A', - "mho;": '\U00002127', - "micro;": '\U000000B5', - "mid;": '\U00002223', - "midast;": '\U0000002A', - "midcir;": '\U00002AF0', - "middot;": '\U000000B7', - "minus;": '\U00002212', - "minusb;": '\U0000229F', - "minusd;": '\U00002238', - "minusdu;": '\U00002A2A', - "mlcp;": '\U00002ADB', - "mldr;": '\U00002026', - "mnplus;": '\U00002213', - "models;": '\U000022A7', - "mopf;": '\U0001D55E', - "mp;": '\U00002213', - "mscr;": '\U0001D4C2', - "mstpos;": '\U0000223E', - "mu;": '\U000003BC', - "multimap;": '\U000022B8', - "mumap;": '\U000022B8', - "nLeftarrow;": '\U000021CD', - "nLeftrightarrow;": '\U000021CE', - "nRightarrow;": '\U000021CF', - "nVDash;": '\U000022AF', - "nVdash;": '\U000022AE', - "nabla;": '\U00002207', - "nacute;": '\U00000144', - "nap;": '\U00002249', - "napos;": '\U00000149', - "napprox;": '\U00002249', - "natur;": '\U0000266E', - "natural;": '\U0000266E', - "naturals;": '\U00002115', - "nbsp;": '\U000000A0', - "ncap;": '\U00002A43', - "ncaron;": '\U00000148', - "ncedil;": '\U00000146', - "ncong;": '\U00002247', - "ncup;": '\U00002A42', - "ncy;": '\U0000043D', - "ndash;": '\U00002013', - "ne;": '\U00002260', - "neArr;": '\U000021D7', - "nearhk;": '\U00002924', - "nearr;": '\U00002197', - "nearrow;": '\U00002197', - "nequiv;": '\U00002262', - "nesear;": '\U00002928', - "nexist;": '\U00002204', - "nexists;": '\U00002204', - "nfr;": '\U0001D52B', - "nge;": '\U00002271', - "ngeq;": '\U00002271', - "ngsim;": '\U00002275', - "ngt;": '\U0000226F', - "ngtr;": '\U0000226F', - "nhArr;": '\U000021CE', - "nharr;": '\U000021AE', - "nhpar;": '\U00002AF2', - "ni;": '\U0000220B', - "nis;": '\U000022FC', - "nisd;": '\U000022FA', - "niv;": '\U0000220B', - "njcy;": '\U0000045A', - "nlArr;": '\U000021CD', - "nlarr;": '\U0000219A', - "nldr;": '\U00002025', - "nle;": '\U00002270', - "nleftarrow;": '\U0000219A', - "nleftrightarrow;": '\U000021AE', - "nleq;": '\U00002270', - "nless;": '\U0000226E', - "nlsim;": '\U00002274', - "nlt;": '\U0000226E', - "nltri;": '\U000022EA', - "nltrie;": '\U000022EC', - "nmid;": '\U00002224', - "nopf;": '\U0001D55F', - "not;": '\U000000AC', - "notin;": '\U00002209', - "notinva;": '\U00002209', - "notinvb;": '\U000022F7', - "notinvc;": '\U000022F6', - "notni;": '\U0000220C', - "notniva;": '\U0000220C', - "notnivb;": '\U000022FE', - "notnivc;": '\U000022FD', - "npar;": '\U00002226', - "nparallel;": '\U00002226', - "npolint;": '\U00002A14', - "npr;": '\U00002280', - "nprcue;": '\U000022E0', - "nprec;": '\U00002280', - "nrArr;": '\U000021CF', - "nrarr;": '\U0000219B', - "nrightarrow;": '\U0000219B', - "nrtri;": '\U000022EB', - "nrtrie;": '\U000022ED', - "nsc;": '\U00002281', - "nsccue;": '\U000022E1', - "nscr;": '\U0001D4C3', - "nshortmid;": '\U00002224', - "nshortparallel;": '\U00002226', - "nsim;": '\U00002241', - "nsime;": '\U00002244', - "nsimeq;": '\U00002244', - "nsmid;": '\U00002224', - "nspar;": '\U00002226', - "nsqsube;": '\U000022E2', - "nsqsupe;": '\U000022E3', - "nsub;": '\U00002284', - "nsube;": '\U00002288', - "nsubseteq;": '\U00002288', - "nsucc;": '\U00002281', - "nsup;": '\U00002285', - "nsupe;": '\U00002289', - "nsupseteq;": '\U00002289', - "ntgl;": '\U00002279', - "ntilde;": '\U000000F1', - "ntlg;": '\U00002278', - "ntriangleleft;": '\U000022EA', - "ntrianglelefteq;": '\U000022EC', - "ntriangleright;": '\U000022EB', - "ntrianglerighteq;": '\U000022ED', - "nu;": '\U000003BD', - "num;": '\U00000023', - "numero;": '\U00002116', - "numsp;": '\U00002007', - "nvDash;": '\U000022AD', - "nvHarr;": '\U00002904', - "nvdash;": '\U000022AC', - "nvinfin;": '\U000029DE', - "nvlArr;": '\U00002902', - "nvrArr;": '\U00002903', - "nwArr;": '\U000021D6', - "nwarhk;": '\U00002923', - "nwarr;": '\U00002196', - "nwarrow;": '\U00002196', - "nwnear;": '\U00002927', - "oS;": '\U000024C8', - "oacute;": '\U000000F3', - "oast;": '\U0000229B', - "ocir;": '\U0000229A', - "ocirc;": '\U000000F4', - "ocy;": '\U0000043E', - "odash;": '\U0000229D', - "odblac;": '\U00000151', - "odiv;": '\U00002A38', - "odot;": '\U00002299', - "odsold;": '\U000029BC', - "oelig;": '\U00000153', - "ofcir;": '\U000029BF', - "ofr;": '\U0001D52C', - "ogon;": '\U000002DB', - "ograve;": '\U000000F2', - "ogt;": '\U000029C1', - "ohbar;": '\U000029B5', - "ohm;": '\U000003A9', - "oint;": '\U0000222E', - "olarr;": '\U000021BA', - "olcir;": '\U000029BE', - "olcross;": '\U000029BB', - "oline;": '\U0000203E', - "olt;": '\U000029C0', - "omacr;": '\U0000014D', - "omega;": '\U000003C9', - "omicron;": '\U000003BF', - "omid;": '\U000029B6', - "ominus;": '\U00002296', - "oopf;": '\U0001D560', - "opar;": '\U000029B7', - "operp;": '\U000029B9', - "oplus;": '\U00002295', - "or;": '\U00002228', - "orarr;": '\U000021BB', - "ord;": '\U00002A5D', - "order;": '\U00002134', - "orderof;": '\U00002134', - "ordf;": '\U000000AA', - "ordm;": '\U000000BA', - "origof;": '\U000022B6', - "oror;": '\U00002A56', - "orslope;": '\U00002A57', - "orv;": '\U00002A5B', - "oscr;": '\U00002134', - "oslash;": '\U000000F8', - "osol;": '\U00002298', - "otilde;": '\U000000F5', - "otimes;": '\U00002297', - "otimesas;": '\U00002A36', - "ouml;": '\U000000F6', - "ovbar;": '\U0000233D', - "par;": '\U00002225', - "para;": '\U000000B6', - "parallel;": '\U00002225', - "parsim;": '\U00002AF3', - "parsl;": '\U00002AFD', - "part;": '\U00002202', - "pcy;": '\U0000043F', - "percnt;": '\U00000025', - "period;": '\U0000002E', - "permil;": '\U00002030', - "perp;": '\U000022A5', - "pertenk;": '\U00002031', - "pfr;": '\U0001D52D', - "phi;": '\U000003C6', - "phiv;": '\U000003D5', - "phmmat;": '\U00002133', - "phone;": '\U0000260E', - "pi;": '\U000003C0', - "pitchfork;": '\U000022D4', - "piv;": '\U000003D6', - "planck;": '\U0000210F', - "planckh;": '\U0000210E', - "plankv;": '\U0000210F', - "plus;": '\U0000002B', - "plusacir;": '\U00002A23', - "plusb;": '\U0000229E', - "pluscir;": '\U00002A22', - "plusdo;": '\U00002214', - "plusdu;": '\U00002A25', - "pluse;": '\U00002A72', - "plusmn;": '\U000000B1', - "plussim;": '\U00002A26', - "plustwo;": '\U00002A27', - "pm;": '\U000000B1', - "pointint;": '\U00002A15', - "popf;": '\U0001D561', - "pound;": '\U000000A3', - "pr;": '\U0000227A', - "prE;": '\U00002AB3', - "prap;": '\U00002AB7', - "prcue;": '\U0000227C', - "pre;": '\U00002AAF', - "prec;": '\U0000227A', - "precapprox;": '\U00002AB7', - "preccurlyeq;": '\U0000227C', - "preceq;": '\U00002AAF', - "precnapprox;": '\U00002AB9', - "precneqq;": '\U00002AB5', - "precnsim;": '\U000022E8', - "precsim;": '\U0000227E', - "prime;": '\U00002032', - "primes;": '\U00002119', - "prnE;": '\U00002AB5', - "prnap;": '\U00002AB9', - "prnsim;": '\U000022E8', - "prod;": '\U0000220F', - "profalar;": '\U0000232E', - "profline;": '\U00002312', - "profsurf;": '\U00002313', - "prop;": '\U0000221D', - "propto;": '\U0000221D', - "prsim;": '\U0000227E', - "prurel;": '\U000022B0', - "pscr;": '\U0001D4C5', - "psi;": '\U000003C8', - "puncsp;": '\U00002008', - "qfr;": '\U0001D52E', - "qint;": '\U00002A0C', - "qopf;": '\U0001D562', - "qprime;": '\U00002057', - "qscr;": '\U0001D4C6', - "quaternions;": '\U0000210D', - "quatint;": '\U00002A16', - "quest;": '\U0000003F', - "questeq;": '\U0000225F', - "quot;": '\U00000022', - "rAarr;": '\U000021DB', - "rArr;": '\U000021D2', - "rAtail;": '\U0000291C', - "rBarr;": '\U0000290F', - "rHar;": '\U00002964', - "racute;": '\U00000155', - "radic;": '\U0000221A', - "raemptyv;": '\U000029B3', - "rang;": '\U000027E9', - "rangd;": '\U00002992', - "range;": '\U000029A5', - "rangle;": '\U000027E9', - "raquo;": '\U000000BB', - "rarr;": '\U00002192', - "rarrap;": '\U00002975', - "rarrb;": '\U000021E5', - "rarrbfs;": '\U00002920', - "rarrc;": '\U00002933', - "rarrfs;": '\U0000291E', - "rarrhk;": '\U000021AA', - "rarrlp;": '\U000021AC', - "rarrpl;": '\U00002945', - "rarrsim;": '\U00002974', - "rarrtl;": '\U000021A3', - "rarrw;": '\U0000219D', - "ratail;": '\U0000291A', - "ratio;": '\U00002236', - "rationals;": '\U0000211A', - "rbarr;": '\U0000290D', - "rbbrk;": '\U00002773', - "rbrace;": '\U0000007D', - "rbrack;": '\U0000005D', - "rbrke;": '\U0000298C', - "rbrksld;": '\U0000298E', - "rbrkslu;": '\U00002990', - "rcaron;": '\U00000159', - "rcedil;": '\U00000157', - "rceil;": '\U00002309', - "rcub;": '\U0000007D', - "rcy;": '\U00000440', - "rdca;": '\U00002937', - "rdldhar;": '\U00002969', - "rdquo;": '\U0000201D', - "rdquor;": '\U0000201D', - "rdsh;": '\U000021B3', - "real;": '\U0000211C', - "realine;": '\U0000211B', - "realpart;": '\U0000211C', - "reals;": '\U0000211D', - "rect;": '\U000025AD', - "reg;": '\U000000AE', - "rfisht;": '\U0000297D', - "rfloor;": '\U0000230B', - "rfr;": '\U0001D52F', - "rhard;": '\U000021C1', - "rharu;": '\U000021C0', - "rharul;": '\U0000296C', - "rho;": '\U000003C1', - "rhov;": '\U000003F1', - "rightarrow;": '\U00002192', - "rightarrowtail;": '\U000021A3', - "rightharpoondown;": '\U000021C1', - "rightharpoonup;": '\U000021C0', - "rightleftarrows;": '\U000021C4', - "rightleftharpoons;": '\U000021CC', - "rightrightarrows;": '\U000021C9', - "rightsquigarrow;": '\U0000219D', - "rightthreetimes;": '\U000022CC', - "ring;": '\U000002DA', - "risingdotseq;": '\U00002253', - "rlarr;": '\U000021C4', - "rlhar;": '\U000021CC', - "rlm;": '\U0000200F', - "rmoust;": '\U000023B1', - "rmoustache;": '\U000023B1', - "rnmid;": '\U00002AEE', - "roang;": '\U000027ED', - "roarr;": '\U000021FE', - "robrk;": '\U000027E7', - "ropar;": '\U00002986', - "ropf;": '\U0001D563', - "roplus;": '\U00002A2E', - "rotimes;": '\U00002A35', - "rpar;": '\U00000029', - "rpargt;": '\U00002994', - "rppolint;": '\U00002A12', - "rrarr;": '\U000021C9', - "rsaquo;": '\U0000203A', - "rscr;": '\U0001D4C7', - "rsh;": '\U000021B1', - "rsqb;": '\U0000005D', - "rsquo;": '\U00002019', - "rsquor;": '\U00002019', - "rthree;": '\U000022CC', - "rtimes;": '\U000022CA', - "rtri;": '\U000025B9', - "rtrie;": '\U000022B5', - "rtrif;": '\U000025B8', - "rtriltri;": '\U000029CE', - "ruluhar;": '\U00002968', - "rx;": '\U0000211E', - "sacute;": '\U0000015B', - "sbquo;": '\U0000201A', - "sc;": '\U0000227B', - "scE;": '\U00002AB4', - "scap;": '\U00002AB8', - "scaron;": '\U00000161', - "sccue;": '\U0000227D', - "sce;": '\U00002AB0', - "scedil;": '\U0000015F', - "scirc;": '\U0000015D', - "scnE;": '\U00002AB6', - "scnap;": '\U00002ABA', - "scnsim;": '\U000022E9', - "scpolint;": '\U00002A13', - "scsim;": '\U0000227F', - "scy;": '\U00000441', - "sdot;": '\U000022C5', - "sdotb;": '\U000022A1', - "sdote;": '\U00002A66', - "seArr;": '\U000021D8', - "searhk;": '\U00002925', - "searr;": '\U00002198', - "searrow;": '\U00002198', - "sect;": '\U000000A7', - "semi;": '\U0000003B', - "seswar;": '\U00002929', - "setminus;": '\U00002216', - "setmn;": '\U00002216', - "sext;": '\U00002736', - "sfr;": '\U0001D530', - "sfrown;": '\U00002322', - "sharp;": '\U0000266F', - "shchcy;": '\U00000449', - "shcy;": '\U00000448', - "shortmid;": '\U00002223', - "shortparallel;": '\U00002225', - "shy;": '\U000000AD', - "sigma;": '\U000003C3', - "sigmaf;": '\U000003C2', - "sigmav;": '\U000003C2', - "sim;": '\U0000223C', - "simdot;": '\U00002A6A', - "sime;": '\U00002243', - "simeq;": '\U00002243', - "simg;": '\U00002A9E', - "simgE;": '\U00002AA0', - "siml;": '\U00002A9D', - "simlE;": '\U00002A9F', - "simne;": '\U00002246', - "simplus;": '\U00002A24', - "simrarr;": '\U00002972', - "slarr;": '\U00002190', - "smallsetminus;": '\U00002216', - "smashp;": '\U00002A33', - "smeparsl;": '\U000029E4', - "smid;": '\U00002223', - "smile;": '\U00002323', - "smt;": '\U00002AAA', - "smte;": '\U00002AAC', - "softcy;": '\U0000044C', - "sol;": '\U0000002F', - "solb;": '\U000029C4', - "solbar;": '\U0000233F', - "sopf;": '\U0001D564', - "spades;": '\U00002660', - "spadesuit;": '\U00002660', - "spar;": '\U00002225', - "sqcap;": '\U00002293', - "sqcup;": '\U00002294', - "sqsub;": '\U0000228F', - "sqsube;": '\U00002291', - "sqsubset;": '\U0000228F', - "sqsubseteq;": '\U00002291', - "sqsup;": '\U00002290', - "sqsupe;": '\U00002292', - "sqsupset;": '\U00002290', - "sqsupseteq;": '\U00002292', - "squ;": '\U000025A1', - "square;": '\U000025A1', - "squarf;": '\U000025AA', - "squf;": '\U000025AA', - "srarr;": '\U00002192', - "sscr;": '\U0001D4C8', - "ssetmn;": '\U00002216', - "ssmile;": '\U00002323', - "sstarf;": '\U000022C6', - "star;": '\U00002606', - "starf;": '\U00002605', - "straightepsilon;": '\U000003F5', - "straightphi;": '\U000003D5', - "strns;": '\U000000AF', - "sub;": '\U00002282', - "subE;": '\U00002AC5', - "subdot;": '\U00002ABD', - "sube;": '\U00002286', - "subedot;": '\U00002AC3', - "submult;": '\U00002AC1', - "subnE;": '\U00002ACB', - "subne;": '\U0000228A', - "subplus;": '\U00002ABF', - "subrarr;": '\U00002979', - "subset;": '\U00002282', - "subseteq;": '\U00002286', - "subseteqq;": '\U00002AC5', - "subsetneq;": '\U0000228A', - "subsetneqq;": '\U00002ACB', - "subsim;": '\U00002AC7', - "subsub;": '\U00002AD5', - "subsup;": '\U00002AD3', - "succ;": '\U0000227B', - "succapprox;": '\U00002AB8', - "succcurlyeq;": '\U0000227D', - "succeq;": '\U00002AB0', - "succnapprox;": '\U00002ABA', - "succneqq;": '\U00002AB6', - "succnsim;": '\U000022E9', - "succsim;": '\U0000227F', - "sum;": '\U00002211', - "sung;": '\U0000266A', - "sup;": '\U00002283', - "sup1;": '\U000000B9', - "sup2;": '\U000000B2', - "sup3;": '\U000000B3', - "supE;": '\U00002AC6', - "supdot;": '\U00002ABE', - "supdsub;": '\U00002AD8', - "supe;": '\U00002287', - "supedot;": '\U00002AC4', - "suphsol;": '\U000027C9', - "suphsub;": '\U00002AD7', - "suplarr;": '\U0000297B', - "supmult;": '\U00002AC2', - "supnE;": '\U00002ACC', - "supne;": '\U0000228B', - "supplus;": '\U00002AC0', - "supset;": '\U00002283', - "supseteq;": '\U00002287', - "supseteqq;": '\U00002AC6', - "supsetneq;": '\U0000228B', - "supsetneqq;": '\U00002ACC', - "supsim;": '\U00002AC8', - "supsub;": '\U00002AD4', - "supsup;": '\U00002AD6', - "swArr;": '\U000021D9', - "swarhk;": '\U00002926', - "swarr;": '\U00002199', - "swarrow;": '\U00002199', - "swnwar;": '\U0000292A', - "szlig;": '\U000000DF', - "target;": '\U00002316', - "tau;": '\U000003C4', - "tbrk;": '\U000023B4', - "tcaron;": '\U00000165', - "tcedil;": '\U00000163', - "tcy;": '\U00000442', - "tdot;": '\U000020DB', - "telrec;": '\U00002315', - "tfr;": '\U0001D531', - "there4;": '\U00002234', - "therefore;": '\U00002234', - "theta;": '\U000003B8', - "thetasym;": '\U000003D1', - "thetav;": '\U000003D1', - "thickapprox;": '\U00002248', - "thicksim;": '\U0000223C', - "thinsp;": '\U00002009', - "thkap;": '\U00002248', - "thksim;": '\U0000223C', - "thorn;": '\U000000FE', - "tilde;": '\U000002DC', - "times;": '\U000000D7', - "timesb;": '\U000022A0', - "timesbar;": '\U00002A31', - "timesd;": '\U00002A30', - "tint;": '\U0000222D', - "toea;": '\U00002928', - "top;": '\U000022A4', - "topbot;": '\U00002336', - "topcir;": '\U00002AF1', - "topf;": '\U0001D565', - "topfork;": '\U00002ADA', - "tosa;": '\U00002929', - "tprime;": '\U00002034', - "trade;": '\U00002122', - "triangle;": '\U000025B5', - "triangledown;": '\U000025BF', - "triangleleft;": '\U000025C3', - "trianglelefteq;": '\U000022B4', - "triangleq;": '\U0000225C', - "triangleright;": '\U000025B9', - "trianglerighteq;": '\U000022B5', - "tridot;": '\U000025EC', - "trie;": '\U0000225C', - "triminus;": '\U00002A3A', - "triplus;": '\U00002A39', - "trisb;": '\U000029CD', - "tritime;": '\U00002A3B', - "trpezium;": '\U000023E2', - "tscr;": '\U0001D4C9', - "tscy;": '\U00000446', - "tshcy;": '\U0000045B', - "tstrok;": '\U00000167', - "twixt;": '\U0000226C', - "twoheadleftarrow;": '\U0000219E', - "twoheadrightarrow;": '\U000021A0', - "uArr;": '\U000021D1', - "uHar;": '\U00002963', - "uacute;": '\U000000FA', - "uarr;": '\U00002191', - "ubrcy;": '\U0000045E', - "ubreve;": '\U0000016D', - "ucirc;": '\U000000FB', - "ucy;": '\U00000443', - "udarr;": '\U000021C5', - "udblac;": '\U00000171', - "udhar;": '\U0000296E', - "ufisht;": '\U0000297E', - "ufr;": '\U0001D532', - "ugrave;": '\U000000F9', - "uharl;": '\U000021BF', - "uharr;": '\U000021BE', - "uhblk;": '\U00002580', - "ulcorn;": '\U0000231C', - "ulcorner;": '\U0000231C', - "ulcrop;": '\U0000230F', - "ultri;": '\U000025F8', - "umacr;": '\U0000016B', - "uml;": '\U000000A8', - "uogon;": '\U00000173', - "uopf;": '\U0001D566', - "uparrow;": '\U00002191', - "updownarrow;": '\U00002195', - "upharpoonleft;": '\U000021BF', - "upharpoonright;": '\U000021BE', - "uplus;": '\U0000228E', - "upsi;": '\U000003C5', - "upsih;": '\U000003D2', - "upsilon;": '\U000003C5', - "upuparrows;": '\U000021C8', - "urcorn;": '\U0000231D', - "urcorner;": '\U0000231D', - "urcrop;": '\U0000230E', - "uring;": '\U0000016F', - "urtri;": '\U000025F9', - "uscr;": '\U0001D4CA', - "utdot;": '\U000022F0', - "utilde;": '\U00000169', - "utri;": '\U000025B5', - "utrif;": '\U000025B4', - "uuarr;": '\U000021C8', - "uuml;": '\U000000FC', - "uwangle;": '\U000029A7', - "vArr;": '\U000021D5', - "vBar;": '\U00002AE8', - "vBarv;": '\U00002AE9', - "vDash;": '\U000022A8', - "vangrt;": '\U0000299C', - "varepsilon;": '\U000003F5', - "varkappa;": '\U000003F0', - "varnothing;": '\U00002205', - "varphi;": '\U000003D5', - "varpi;": '\U000003D6', - "varpropto;": '\U0000221D', - "varr;": '\U00002195', - "varrho;": '\U000003F1', - "varsigma;": '\U000003C2', - "vartheta;": '\U000003D1', - "vartriangleleft;": '\U000022B2', - "vartriangleright;": '\U000022B3', - "vcy;": '\U00000432', - "vdash;": '\U000022A2', - "vee;": '\U00002228', - "veebar;": '\U000022BB', - "veeeq;": '\U0000225A', - "vellip;": '\U000022EE', - "verbar;": '\U0000007C', - "vert;": '\U0000007C', - "vfr;": '\U0001D533', - "vltri;": '\U000022B2', - "vopf;": '\U0001D567', - "vprop;": '\U0000221D', - "vrtri;": '\U000022B3', - "vscr;": '\U0001D4CB', - "vzigzag;": '\U0000299A', - "wcirc;": '\U00000175', - "wedbar;": '\U00002A5F', - "wedge;": '\U00002227', - "wedgeq;": '\U00002259', - "weierp;": '\U00002118', - "wfr;": '\U0001D534', - "wopf;": '\U0001D568', - "wp;": '\U00002118', - "wr;": '\U00002240', - "wreath;": '\U00002240', - "wscr;": '\U0001D4CC', - "xcap;": '\U000022C2', - "xcirc;": '\U000025EF', - "xcup;": '\U000022C3', - "xdtri;": '\U000025BD', - "xfr;": '\U0001D535', - "xhArr;": '\U000027FA', - "xharr;": '\U000027F7', - "xi;": '\U000003BE', - "xlArr;": '\U000027F8', - "xlarr;": '\U000027F5', - "xmap;": '\U000027FC', - "xnis;": '\U000022FB', - "xodot;": '\U00002A00', - "xopf;": '\U0001D569', - "xoplus;": '\U00002A01', - "xotime;": '\U00002A02', - "xrArr;": '\U000027F9', - "xrarr;": '\U000027F6', - "xscr;": '\U0001D4CD', - "xsqcup;": '\U00002A06', - "xuplus;": '\U00002A04', - "xutri;": '\U000025B3', - "xvee;": '\U000022C1', - "xwedge;": '\U000022C0', - "yacute;": '\U000000FD', - "yacy;": '\U0000044F', - "ycirc;": '\U00000177', - "ycy;": '\U0000044B', - "yen;": '\U000000A5', - "yfr;": '\U0001D536', - "yicy;": '\U00000457', - "yopf;": '\U0001D56A', - "yscr;": '\U0001D4CE', - "yucy;": '\U0000044E', - "yuml;": '\U000000FF', - "zacute;": '\U0000017A', - "zcaron;": '\U0000017E', - "zcy;": '\U00000437', - "zdot;": '\U0000017C', - "zeetrf;": '\U00002128', - "zeta;": '\U000003B6', - "zfr;": '\U0001D537', - "zhcy;": '\U00000436', - "zigrarr;": '\U000021DD', - "zopf;": '\U0001D56B', - "zscr;": '\U0001D4CF', - "zwj;": '\U0000200D', - "zwnj;": '\U0000200C', - "AElig": '\U000000C6', - "AMP": '\U00000026', - "Aacute": '\U000000C1', - "Acirc": '\U000000C2', - "Agrave": '\U000000C0', - "Aring": '\U000000C5', - "Atilde": '\U000000C3', - "Auml": '\U000000C4', - "COPY": '\U000000A9', - "Ccedil": '\U000000C7', - "ETH": '\U000000D0', - "Eacute": '\U000000C9', - "Ecirc": '\U000000CA', - "Egrave": '\U000000C8', - "Euml": '\U000000CB', - "GT": '\U0000003E', - "Iacute": '\U000000CD', - "Icirc": '\U000000CE', - "Igrave": '\U000000CC', - "Iuml": '\U000000CF', - "LT": '\U0000003C', - "Ntilde": '\U000000D1', - "Oacute": '\U000000D3', - "Ocirc": '\U000000D4', - "Ograve": '\U000000D2', - "Oslash": '\U000000D8', - "Otilde": '\U000000D5', - "Ouml": '\U000000D6', - "QUOT": '\U00000022', - "REG": '\U000000AE', - "THORN": '\U000000DE', - "Uacute": '\U000000DA', - "Ucirc": '\U000000DB', - "Ugrave": '\U000000D9', - "Uuml": '\U000000DC', - "Yacute": '\U000000DD', - "aacute": '\U000000E1', - "acirc": '\U000000E2', - "acute": '\U000000B4', - "aelig": '\U000000E6', - "agrave": '\U000000E0', - "amp": '\U00000026', - "aring": '\U000000E5', - "atilde": '\U000000E3', - "auml": '\U000000E4', - "brvbar": '\U000000A6', - "ccedil": '\U000000E7', - "cedil": '\U000000B8', - "cent": '\U000000A2', - "copy": '\U000000A9', - "curren": '\U000000A4', - "deg": '\U000000B0', - "divide": '\U000000F7', - "eacute": '\U000000E9', - "ecirc": '\U000000EA', - "egrave": '\U000000E8', - "eth": '\U000000F0', - "euml": '\U000000EB', - "frac12": '\U000000BD', - "frac14": '\U000000BC', - "frac34": '\U000000BE', - "gt": '\U0000003E', - "iacute": '\U000000ED', - "icirc": '\U000000EE', - "iexcl": '\U000000A1', - "igrave": '\U000000EC', - "iquest": '\U000000BF', - "iuml": '\U000000EF', - "laquo": '\U000000AB', - "lt": '\U0000003C', - "macr": '\U000000AF', - "micro": '\U000000B5', - "middot": '\U000000B7', - "nbsp": '\U000000A0', - "not": '\U000000AC', - "ntilde": '\U000000F1', - "oacute": '\U000000F3', - "ocirc": '\U000000F4', - "ograve": '\U000000F2', - "ordf": '\U000000AA', - "ordm": '\U000000BA', - "oslash": '\U000000F8', - "otilde": '\U000000F5', - "ouml": '\U000000F6', - "para": '\U000000B6', - "plusmn": '\U000000B1', - "pound": '\U000000A3', - "quot": '\U00000022', - "raquo": '\U000000BB', - "reg": '\U000000AE', - "sect": '\U000000A7', - "shy": '\U000000AD', - "sup1": '\U000000B9', - "sup2": '\U000000B2', - "sup3": '\U000000B3', - "szlig": '\U000000DF', - "thorn": '\U000000FE', - "times": '\U000000D7', - "uacute": '\U000000FA', - "ucirc": '\U000000FB', - "ugrave": '\U000000F9', - "uml": '\U000000A8', - "uuml": '\U000000FC', - "yacute": '\U000000FD', - "yen": '\U000000A5', - "yuml": '\U000000FF', -} - -// HTML entities that are two unicode codepoints. -var entity2 = map[string][2]rune{ - // TODO(nigeltao): Handle replacements that are wider than their names. - // "nLt;": {'\u226A', '\u20D2'}, - // "nGt;": {'\u226B', '\u20D2'}, - "NotEqualTilde;": {'\u2242', '\u0338'}, - "NotGreaterFullEqual;": {'\u2267', '\u0338'}, - "NotGreaterGreater;": {'\u226B', '\u0338'}, - "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, - "NotHumpDownHump;": {'\u224E', '\u0338'}, - "NotHumpEqual;": {'\u224F', '\u0338'}, - "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, - "NotLessLess;": {'\u226A', '\u0338'}, - "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, - "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, - "NotNestedLessLess;": {'\u2AA1', '\u0338'}, - "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, - "NotRightTriangleBar;": {'\u29D0', '\u0338'}, - "NotSquareSubset;": {'\u228F', '\u0338'}, - "NotSquareSuperset;": {'\u2290', '\u0338'}, - "NotSubset;": {'\u2282', '\u20D2'}, - "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, - "NotSucceedsTilde;": {'\u227F', '\u0338'}, - "NotSuperset;": {'\u2283', '\u20D2'}, - "ThickSpace;": {'\u205F', '\u200A'}, - "acE;": {'\u223E', '\u0333'}, - "bne;": {'\u003D', '\u20E5'}, - "bnequiv;": {'\u2261', '\u20E5'}, - "caps;": {'\u2229', '\uFE00'}, - "cups;": {'\u222A', '\uFE00'}, - "fjlig;": {'\u0066', '\u006A'}, - "gesl;": {'\u22DB', '\uFE00'}, - "gvertneqq;": {'\u2269', '\uFE00'}, - "gvnE;": {'\u2269', '\uFE00'}, - "lates;": {'\u2AAD', '\uFE00'}, - "lesg;": {'\u22DA', '\uFE00'}, - "lvertneqq;": {'\u2268', '\uFE00'}, - "lvnE;": {'\u2268', '\uFE00'}, - "nGg;": {'\u22D9', '\u0338'}, - "nGtv;": {'\u226B', '\u0338'}, - "nLl;": {'\u22D8', '\u0338'}, - "nLtv;": {'\u226A', '\u0338'}, - "nang;": {'\u2220', '\u20D2'}, - "napE;": {'\u2A70', '\u0338'}, - "napid;": {'\u224B', '\u0338'}, - "nbump;": {'\u224E', '\u0338'}, - "nbumpe;": {'\u224F', '\u0338'}, - "ncongdot;": {'\u2A6D', '\u0338'}, - "nedot;": {'\u2250', '\u0338'}, - "nesim;": {'\u2242', '\u0338'}, - "ngE;": {'\u2267', '\u0338'}, - "ngeqq;": {'\u2267', '\u0338'}, - "ngeqslant;": {'\u2A7E', '\u0338'}, - "nges;": {'\u2A7E', '\u0338'}, - "nlE;": {'\u2266', '\u0338'}, - "nleqq;": {'\u2266', '\u0338'}, - "nleqslant;": {'\u2A7D', '\u0338'}, - "nles;": {'\u2A7D', '\u0338'}, - "notinE;": {'\u22F9', '\u0338'}, - "notindot;": {'\u22F5', '\u0338'}, - "nparsl;": {'\u2AFD', '\u20E5'}, - "npart;": {'\u2202', '\u0338'}, - "npre;": {'\u2AAF', '\u0338'}, - "npreceq;": {'\u2AAF', '\u0338'}, - "nrarrc;": {'\u2933', '\u0338'}, - "nrarrw;": {'\u219D', '\u0338'}, - "nsce;": {'\u2AB0', '\u0338'}, - "nsubE;": {'\u2AC5', '\u0338'}, - "nsubset;": {'\u2282', '\u20D2'}, - "nsubseteqq;": {'\u2AC5', '\u0338'}, - "nsucceq;": {'\u2AB0', '\u0338'}, - "nsupE;": {'\u2AC6', '\u0338'}, - "nsupset;": {'\u2283', '\u20D2'}, - "nsupseteqq;": {'\u2AC6', '\u0338'}, - "nvap;": {'\u224D', '\u20D2'}, - "nvge;": {'\u2265', '\u20D2'}, - "nvgt;": {'\u003E', '\u20D2'}, - "nvle;": {'\u2264', '\u20D2'}, - "nvlt;": {'\u003C', '\u20D2'}, - "nvltrie;": {'\u22B4', '\u20D2'}, - "nvrtrie;": {'\u22B5', '\u20D2'}, - "nvsim;": {'\u223C', '\u20D2'}, - "race;": {'\u223D', '\u0331'}, - "smtes;": {'\u2AAC', '\uFE00'}, - "sqcaps;": {'\u2293', '\uFE00'}, - "sqcups;": {'\u2294', '\uFE00'}, - "varsubsetneq;": {'\u228A', '\uFE00'}, - "varsubsetneqq;": {'\u2ACB', '\uFE00'}, - "varsupsetneq;": {'\u228B', '\uFE00'}, - "varsupsetneqq;": {'\u2ACC', '\uFE00'}, - "vnsub;": {'\u2282', '\u20D2'}, - "vnsup;": {'\u2283', '\u20D2'}, - "vsubnE;": {'\u2ACB', '\uFE00'}, - "vsubne;": {'\u228A', '\uFE00'}, - "vsupnE;": {'\u2ACC', '\uFE00'}, - "vsupne;": {'\u228B', '\uFE00'}, -} diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go deleted file mode 100644 index d8561396200..00000000000 --- a/vendor/golang.org/x/net/html/escape.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2010 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 html - -import ( - "bytes" - "strings" - "unicode/utf8" -) - -// These replacements permit compatibility with old numeric entities that -// assumed Windows-1252 encoding. -// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference -var replacementTable = [...]rune{ - '\u20AC', // First entry is what 0x80 should be replaced with. - '\u0081', - '\u201A', - '\u0192', - '\u201E', - '\u2026', - '\u2020', - '\u2021', - '\u02C6', - '\u2030', - '\u0160', - '\u2039', - '\u0152', - '\u008D', - '\u017D', - '\u008F', - '\u0090', - '\u2018', - '\u2019', - '\u201C', - '\u201D', - '\u2022', - '\u2013', - '\u2014', - '\u02DC', - '\u2122', - '\u0161', - '\u203A', - '\u0153', - '\u009D', - '\u017E', - '\u0178', // Last entry is 0x9F. - // 0x00->'\uFFFD' is handled programmatically. - // 0x0D->'\u000D' is a no-op. -} - -// unescapeEntity reads an entity like "<" from b[src:] and writes the -// corresponding "<" to b[dst:], returning the incremented dst and src cursors. -// Precondition: b[src] == '&' && dst <= src. -// attribute should be true if parsing an attribute value. -func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { - // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference - - // i starts at 1 because we already know that s[0] == '&'. - i, s := 1, b[src:] - - if len(s) <= 1 { - b[dst] = b[src] - return dst + 1, src + 1 - } - - if s[i] == '#' { - if len(s) <= 3 { // We need to have at least "&#.". - b[dst] = b[src] - return dst + 1, src + 1 - } - i++ - c := s[i] - hex := false - if c == 'x' || c == 'X' { - hex = true - i++ - } - - x := '\x00' - for i < len(s) { - c = s[i] - i++ - if hex { - if '0' <= c && c <= '9' { - x = 16*x + rune(c) - '0' - continue - } else if 'a' <= c && c <= 'f' { - x = 16*x + rune(c) - 'a' + 10 - continue - } else if 'A' <= c && c <= 'F' { - x = 16*x + rune(c) - 'A' + 10 - continue - } - } else if '0' <= c && c <= '9' { - x = 10*x + rune(c) - '0' - continue - } - if c != ';' { - i-- - } - break - } - - if i <= 3 { // No characters matched. - b[dst] = b[src] - return dst + 1, src + 1 - } - - if 0x80 <= x && x <= 0x9F { - // Replace characters from Windows-1252 with UTF-8 equivalents. - x = replacementTable[x-0x80] - } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { - // Replace invalid characters with the replacement character. - x = '\uFFFD' - } - - return dst + utf8.EncodeRune(b[dst:], x), src + i - } - - // Consume the maximum number of characters possible, with the - // consumed characters matching one of the named references. - - for i < len(s) { - c := s[i] - i++ - // Lower-cased characters are more common in entities, so we check for them first. - if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { - continue - } - if c != ';' { - i-- - } - break - } - - entityName := string(s[1:i]) - if entityName == "" { - // No-op. - } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { - // No-op. - } else if x := entity[entityName]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + i - } else if x := entity2[entityName]; x[0] != 0 { - dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) - return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i - } else if !attribute { - maxLen := len(entityName) - 1 - if maxLen > longestEntityWithoutSemicolon { - maxLen = longestEntityWithoutSemicolon - } - for j := maxLen; j > 1; j-- { - if x := entity[entityName[:j]]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 - } - } - } - - dst1, src1 = dst+i, src+i - copy(b[dst:dst1], b[src:src1]) - return dst1, src1 -} - -// unescape unescapes b's entities in-place, so that "a<b" becomes "a': - esc = ">" - case '"': - // """ is shorter than """. - esc = """ - case '\r': - esc = " " - default: - panic("unrecognized escape character") - } - s = s[i+1:] - if _, err := w.WriteString(esc); err != nil { - return err - } - i = strings.IndexAny(s, escapedChars) - } - _, err := w.WriteString(s) - return err -} - -// EscapeString escapes special characters like "<" to become "<". It -// escapes only five such characters: <, >, &, ' and ". -// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't -// always true. -func EscapeString(s string) string { - if strings.IndexAny(s, escapedChars) == -1 { - return s - } - var buf bytes.Buffer - escape(&buf, s) - return buf.String() -} - -// UnescapeString unescapes entities like "<" to become "<". It unescapes a -// larger range of entities than EscapeString escapes. For example, "á" -// unescapes to "á", as does "á" and "&xE1;". -// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't -// always true. -func UnescapeString(s string) string { - for _, c := range s { - if c == '&' { - return string(unescape([]byte(s), false)) - } - } - return s -} diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go deleted file mode 100644 index d3b3844099b..00000000000 --- a/vendor/golang.org/x/net/html/foreign.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2011 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 html - -import ( - "strings" -) - -func adjustAttributeNames(aa []Attribute, nameMap map[string]string) { - for i := range aa { - if newName, ok := nameMap[aa[i].Key]; ok { - aa[i].Key = newName - } - } -} - -func adjustForeignAttributes(aa []Attribute) { - for i, a := range aa { - if a.Key == "" || a.Key[0] != 'x' { - continue - } - switch a.Key { - case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", - "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": - j := strings.Index(a.Key, ":") - aa[i].Namespace = a.Key[:j] - aa[i].Key = a.Key[j+1:] - } - } -} - -func htmlIntegrationPoint(n *Node) bool { - if n.Type != ElementNode { - return false - } - switch n.Namespace { - case "math": - if n.Data == "annotation-xml" { - for _, a := range n.Attr { - if a.Key == "encoding" { - val := strings.ToLower(a.Val) - if val == "text/html" || val == "application/xhtml+xml" { - return true - } - } - } - } - case "svg": - switch n.Data { - case "desc", "foreignObject", "title": - return true - } - } - return false -} - -func mathMLTextIntegrationPoint(n *Node) bool { - if n.Namespace != "math" { - return false - } - switch n.Data { - case "mi", "mo", "mn", "ms", "mtext": - return true - } - return false -} - -// Section 12.2.5.5. -var breakout = map[string]bool{ - "b": true, - "big": true, - "blockquote": true, - "body": true, - "br": true, - "center": true, - "code": true, - "dd": true, - "div": true, - "dl": true, - "dt": true, - "em": true, - "embed": true, - "h1": true, - "h2": true, - "h3": true, - "h4": true, - "h5": true, - "h6": true, - "head": true, - "hr": true, - "i": true, - "img": true, - "li": true, - "listing": true, - "menu": true, - "meta": true, - "nobr": true, - "ol": true, - "p": true, - "pre": true, - "ruby": true, - "s": true, - "small": true, - "span": true, - "strong": true, - "strike": true, - "sub": true, - "sup": true, - "table": true, - "tt": true, - "u": true, - "ul": true, - "var": true, -} - -// Section 12.2.5.5. -var svgTagNameAdjustments = map[string]string{ - "altglyph": "altGlyph", - "altglyphdef": "altGlyphDef", - "altglyphitem": "altGlyphItem", - "animatecolor": "animateColor", - "animatemotion": "animateMotion", - "animatetransform": "animateTransform", - "clippath": "clipPath", - "feblend": "feBlend", - "fecolormatrix": "feColorMatrix", - "fecomponenttransfer": "feComponentTransfer", - "fecomposite": "feComposite", - "feconvolvematrix": "feConvolveMatrix", - "fediffuselighting": "feDiffuseLighting", - "fedisplacementmap": "feDisplacementMap", - "fedistantlight": "feDistantLight", - "feflood": "feFlood", - "fefunca": "feFuncA", - "fefuncb": "feFuncB", - "fefuncg": "feFuncG", - "fefuncr": "feFuncR", - "fegaussianblur": "feGaussianBlur", - "feimage": "feImage", - "femerge": "feMerge", - "femergenode": "feMergeNode", - "femorphology": "feMorphology", - "feoffset": "feOffset", - "fepointlight": "fePointLight", - "fespecularlighting": "feSpecularLighting", - "fespotlight": "feSpotLight", - "fetile": "feTile", - "feturbulence": "feTurbulence", - "foreignobject": "foreignObject", - "glyphref": "glyphRef", - "lineargradient": "linearGradient", - "radialgradient": "radialGradient", - "textpath": "textPath", -} - -// Section 12.2.5.1 -var mathMLAttributeAdjustments = map[string]string{ - "definitionurl": "definitionURL", -} - -var svgAttributeAdjustments = map[string]string{ - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterres": "filterRes", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan", -} diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go deleted file mode 100644 index 26b657aec83..00000000000 --- a/vendor/golang.org/x/net/html/node.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2011 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 html - -import ( - "golang.org/x/net/html/atom" -) - -// A NodeType is the type of a Node. -type NodeType uint32 - -const ( - ErrorNode NodeType = iota - TextNode - DocumentNode - ElementNode - CommentNode - DoctypeNode - scopeMarkerNode -) - -// Section 12.2.3.3 says "scope markers are inserted when entering applet -// elements, buttons, object elements, marquees, table cells, and table -// captions, and are used to prevent formatting from 'leaking'". -var scopeMarker = Node{Type: scopeMarkerNode} - -// A Node consists of a NodeType and some Data (tag name for element nodes, -// content for text) and are part of a tree of Nodes. Element nodes may also -// have a Namespace and contain a slice of Attributes. Data is unescaped, so -// that it looks like "a 0 { - return (*s)[i-1] - } - return nil -} - -// index returns the index of the top-most occurrence of n in the stack, or -1 -// if n is not present. -func (s *nodeStack) index(n *Node) int { - for i := len(*s) - 1; i >= 0; i-- { - if (*s)[i] == n { - return i - } - } - return -1 -} - -// insert inserts a node at the given index. -func (s *nodeStack) insert(i int, n *Node) { - (*s) = append(*s, nil) - copy((*s)[i+1:], (*s)[i:]) - (*s)[i] = n -} - -// remove removes a node from the stack. It is a no-op if n is not present. -func (s *nodeStack) remove(n *Node) { - i := s.index(n) - if i == -1 { - return - } - copy((*s)[i:], (*s)[i+1:]) - j := len(*s) - 1 - (*s)[j] = nil - *s = (*s)[:j] -} diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go deleted file mode 100644 index be4b2bf5aa9..00000000000 --- a/vendor/golang.org/x/net/html/parse.go +++ /dev/null @@ -1,2094 +0,0 @@ -// Copyright 2010 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 html - -import ( - "errors" - "fmt" - "io" - "strings" - - a "golang.org/x/net/html/atom" -) - -// A parser implements the HTML5 parsing algorithm: -// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction -type parser struct { - // tokenizer provides the tokens for the parser. - tokenizer *Tokenizer - // tok is the most recently read token. - tok Token - // Self-closing tags like
    are treated as start tags, except that - // hasSelfClosingToken is set while they are being processed. - hasSelfClosingToken bool - // doc is the document root element. - doc *Node - // The stack of open elements (section 12.2.3.2) and active formatting - // elements (section 12.2.3.3). - oe, afe nodeStack - // Element pointers (section 12.2.3.4). - head, form *Node - // Other parsing state flags (section 12.2.3.5). - scripting, framesetOK bool - // im is the current insertion mode. - im insertionMode - // originalIM is the insertion mode to go back to after completing a text - // or inTableText insertion mode. - originalIM insertionMode - // fosterParenting is whether new elements should be inserted according to - // the foster parenting rules (section 12.2.5.3). - fosterParenting bool - // quirks is whether the parser is operating in "quirks mode." - quirks bool - // fragment is whether the parser is parsing an HTML fragment. - fragment bool - // context is the context element when parsing an HTML fragment - // (section 12.4). - context *Node -} - -func (p *parser) top() *Node { - if n := p.oe.top(); n != nil { - return n - } - return p.doc -} - -// Stop tags for use in popUntil. These come from section 12.2.3.2. -var ( - defaultScopeStopTags = map[string][]a.Atom{ - "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, - "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, - "svg": {a.Desc, a.ForeignObject, a.Title}, - } -) - -type scope int - -const ( - defaultScope scope = iota - listItemScope - buttonScope - tableScope - tableRowScope - tableBodyScope - selectScope -) - -// popUntil pops the stack of open elements at the highest element whose tag -// is in matchTags, provided there is no higher element in the scope's stop -// tags (as defined in section 12.2.3.2). It returns whether or not there was -// such an element. If there was not, popUntil leaves the stack unchanged. -// -// For example, the set of stop tags for table scope is: "html", "table". If -// the stack was: -// ["html", "body", "font", "table", "b", "i", "u"] -// then popUntil(tableScope, "font") would return false, but -// popUntil(tableScope, "i") would return true and the stack would become: -// ["html", "body", "font", "table", "b"] -// -// If an element's tag is in both the stop tags and matchTags, then the stack -// will be popped and the function returns true (provided, of course, there was -// no higher element in the stack that was also in the stop tags). For example, -// popUntil(tableScope, "table") returns true and leaves: -// ["html", "body", "font"] -func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool { - if i := p.indexOfElementInScope(s, matchTags...); i != -1 { - p.oe = p.oe[:i] - return true - } - return false -} - -// indexOfElementInScope returns the index in p.oe of the highest element whose -// tag is in matchTags that is in scope. If no matching element is in scope, it -// returns -1. -func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { - for i := len(p.oe) - 1; i >= 0; i-- { - tagAtom := p.oe[i].DataAtom - if p.oe[i].Namespace == "" { - for _, t := range matchTags { - if t == tagAtom { - return i - } - } - switch s { - case defaultScope: - // No-op. - case listItemScope: - if tagAtom == a.Ol || tagAtom == a.Ul { - return -1 - } - case buttonScope: - if tagAtom == a.Button { - return -1 - } - case tableScope: - if tagAtom == a.Html || tagAtom == a.Table { - return -1 - } - case selectScope: - if tagAtom != a.Optgroup && tagAtom != a.Option { - return -1 - } - default: - panic("unreachable") - } - } - switch s { - case defaultScope, listItemScope, buttonScope: - for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { - if t == tagAtom { - return -1 - } - } - } - } - return -1 -} - -// elementInScope is like popUntil, except that it doesn't modify the stack of -// open elements. -func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool { - return p.indexOfElementInScope(s, matchTags...) != -1 -} - -// clearStackToContext pops elements off the stack of open elements until a -// scope-defined element is found. -func (p *parser) clearStackToContext(s scope) { - for i := len(p.oe) - 1; i >= 0; i-- { - tagAtom := p.oe[i].DataAtom - switch s { - case tableScope: - if tagAtom == a.Html || tagAtom == a.Table { - p.oe = p.oe[:i+1] - return - } - case tableRowScope: - if tagAtom == a.Html || tagAtom == a.Tr { - p.oe = p.oe[:i+1] - return - } - case tableBodyScope: - if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead { - p.oe = p.oe[:i+1] - return - } - default: - panic("unreachable") - } - } -} - -// generateImpliedEndTags pops nodes off the stack of open elements as long as -// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt. -// If exceptions are specified, nodes with that name will not be popped off. -func (p *parser) generateImpliedEndTags(exceptions ...string) { - var i int -loop: - for i = len(p.oe) - 1; i >= 0; i-- { - n := p.oe[i] - if n.Type == ElementNode { - switch n.DataAtom { - case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt: - for _, except := range exceptions { - if n.Data == except { - break loop - } - } - continue - } - } - break - } - - p.oe = p.oe[:i+1] -} - -// addChild adds a child node n to the top element, and pushes n onto the stack -// of open elements if it is an element node. -func (p *parser) addChild(n *Node) { - if p.shouldFosterParent() { - p.fosterParent(n) - } else { - p.top().AppendChild(n) - } - - if n.Type == ElementNode { - p.oe = append(p.oe, n) - } -} - -// shouldFosterParent returns whether the next node to be added should be -// foster parented. -func (p *parser) shouldFosterParent() bool { - if p.fosterParenting { - switch p.top().DataAtom { - case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: - return true - } - } - return false -} - -// fosterParent adds a child node according to the foster parenting rules. -// Section 12.2.5.3, "foster parenting". -func (p *parser) fosterParent(n *Node) { - var table, parent, prev *Node - var i int - for i = len(p.oe) - 1; i >= 0; i-- { - if p.oe[i].DataAtom == a.Table { - table = p.oe[i] - break - } - } - - if table == nil { - // The foster parent is the html element. - parent = p.oe[0] - } else { - parent = table.Parent - } - if parent == nil { - parent = p.oe[i-1] - } - - if table != nil { - prev = table.PrevSibling - } else { - prev = parent.LastChild - } - if prev != nil && prev.Type == TextNode && n.Type == TextNode { - prev.Data += n.Data - return - } - - parent.InsertBefore(n, table) -} - -// addText adds text to the preceding node if it is a text node, or else it -// calls addChild with a new text node. -func (p *parser) addText(text string) { - if text == "" { - return - } - - if p.shouldFosterParent() { - p.fosterParent(&Node{ - Type: TextNode, - Data: text, - }) - return - } - - t := p.top() - if n := t.LastChild; n != nil && n.Type == TextNode { - n.Data += text - return - } - p.addChild(&Node{ - Type: TextNode, - Data: text, - }) -} - -// addElement adds a child element based on the current token. -func (p *parser) addElement() { - p.addChild(&Node{ - Type: ElementNode, - DataAtom: p.tok.DataAtom, - Data: p.tok.Data, - Attr: p.tok.Attr, - }) -} - -// Section 12.2.3.3. -func (p *parser) addFormattingElement() { - tagAtom, attr := p.tok.DataAtom, p.tok.Attr - p.addElement() - - // Implement the Noah's Ark clause, but with three per family instead of two. - identicalElements := 0 -findIdenticalElements: - for i := len(p.afe) - 1; i >= 0; i-- { - n := p.afe[i] - if n.Type == scopeMarkerNode { - break - } - if n.Type != ElementNode { - continue - } - if n.Namespace != "" { - continue - } - if n.DataAtom != tagAtom { - continue - } - if len(n.Attr) != len(attr) { - continue - } - compareAttributes: - for _, t0 := range n.Attr { - for _, t1 := range attr { - if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { - // Found a match for this attribute, continue with the next attribute. - continue compareAttributes - } - } - // If we get here, there is no attribute that matches a. - // Therefore the element is not identical to the new one. - continue findIdenticalElements - } - - identicalElements++ - if identicalElements >= 3 { - p.afe.remove(n) - } - } - - p.afe = append(p.afe, p.top()) -} - -// Section 12.2.3.3. -func (p *parser) clearActiveFormattingElements() { - for { - n := p.afe.pop() - if len(p.afe) == 0 || n.Type == scopeMarkerNode { - return - } - } -} - -// Section 12.2.3.3. -func (p *parser) reconstructActiveFormattingElements() { - n := p.afe.top() - if n == nil { - return - } - if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { - return - } - i := len(p.afe) - 1 - for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { - if i == 0 { - i = -1 - break - } - i-- - n = p.afe[i] - } - for { - i++ - clone := p.afe[i].clone() - p.addChild(clone) - p.afe[i] = clone - if i == len(p.afe)-1 { - break - } - } -} - -// Section 12.2.4. -func (p *parser) acknowledgeSelfClosingTag() { - p.hasSelfClosingToken = false -} - -// An insertion mode (section 12.2.3.1) is the state transition function from -// a particular state in the HTML5 parser's state machine. It updates the -// parser's fields depending on parser.tok (where ErrorToken means EOF). -// It returns whether the token was consumed. -type insertionMode func(*parser) bool - -// setOriginalIM sets the insertion mode to return to after completing a text or -// inTableText insertion mode. -// Section 12.2.3.1, "using the rules for". -func (p *parser) setOriginalIM() { - if p.originalIM != nil { - panic("html: bad parser state: originalIM was set twice") - } - p.originalIM = p.im -} - -// Section 12.2.3.1, "reset the insertion mode". -func (p *parser) resetInsertionMode() { - for i := len(p.oe) - 1; i >= 0; i-- { - n := p.oe[i] - if i == 0 && p.context != nil { - n = p.context - } - - switch n.DataAtom { - case a.Select: - p.im = inSelectIM - case a.Td, a.Th: - p.im = inCellIM - case a.Tr: - p.im = inRowIM - case a.Tbody, a.Thead, a.Tfoot: - p.im = inTableBodyIM - case a.Caption: - p.im = inCaptionIM - case a.Colgroup: - p.im = inColumnGroupIM - case a.Table: - p.im = inTableIM - case a.Head: - p.im = inBodyIM - case a.Body: - p.im = inBodyIM - case a.Frameset: - p.im = inFramesetIM - case a.Html: - p.im = beforeHeadIM - default: - continue - } - return - } - p.im = inBodyIM -} - -const whitespace = " \t\r\n\f" - -// Section 12.2.5.4.1. -func initialIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) - if len(p.tok.Data) == 0 { - // It was all whitespace, so ignore it. - return true - } - case CommentToken: - p.doc.AppendChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - n, quirks := parseDoctype(p.tok.Data) - p.doc.AppendChild(n) - p.quirks = quirks - p.im = beforeHTMLIM - return true - } - p.quirks = true - p.im = beforeHTMLIM - return false -} - -// Section 12.2.5.4.2. -func beforeHTMLIM(p *parser) bool { - switch p.tok.Type { - case DoctypeToken: - // Ignore the token. - return true - case TextToken: - p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) - if len(p.tok.Data) == 0 { - // It was all whitespace, so ignore it. - return true - } - case StartTagToken: - if p.tok.DataAtom == a.Html { - p.addElement() - p.im = beforeHeadIM - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Head, a.Body, a.Html, a.Br: - p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) - return false - default: - // Ignore the token. - return true - } - case CommentToken: - p.doc.AppendChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - } - p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) - return false -} - -// Section 12.2.5.4.3. -func beforeHeadIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) - if len(p.tok.Data) == 0 { - // It was all whitespace, so ignore it. - return true - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Head: - p.addElement() - p.head = p.top() - p.im = inHeadIM - return true - case a.Html: - return inBodyIM(p) - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Head, a.Body, a.Html, a.Br: - p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) - return false - default: - // Ignore the token. - return true - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - // Ignore the token. - return true - } - - p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) - return false -} - -// Section 12.2.5.4.4. -func inHeadIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - s := strings.TrimLeft(p.tok.Data, whitespace) - if len(s) < len(p.tok.Data) { - // Add the initial whitespace to the current node. - p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) - if s == "" { - return true - } - p.tok.Data = s - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta: - p.addElement() - p.oe.pop() - p.acknowledgeSelfClosingTag() - return true - case a.Script, a.Title, a.Noscript, a.Noframes, a.Style: - p.addElement() - p.setOriginalIM() - p.im = textIM - return true - case a.Head: - // Ignore the token. - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Head: - n := p.oe.pop() - if n.DataAtom != a.Head { - panic("html: bad parser state: element not found, in the in-head insertion mode") - } - p.im = afterHeadIM - return true - case a.Body, a.Html, a.Br: - p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) - return false - default: - // Ignore the token. - return true - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - // Ignore the token. - return true - } - - p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) - return false -} - -// Section 12.2.5.4.6. -func afterHeadIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - s := strings.TrimLeft(p.tok.Data, whitespace) - if len(s) < len(p.tok.Data) { - // Add the initial whitespace to the current node. - p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) - if s == "" { - return true - } - p.tok.Data = s - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Body: - p.addElement() - p.framesetOK = false - p.im = inBodyIM - return true - case a.Frameset: - p.addElement() - p.im = inFramesetIM - return true - case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: - p.oe = append(p.oe, p.head) - defer p.oe.remove(p.head) - return inHeadIM(p) - case a.Head: - // Ignore the token. - return true - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Body, a.Html, a.Br: - // Drop down to creating an implied tag. - default: - // Ignore the token. - return true - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - return true - case DoctypeToken: - // Ignore the token. - return true - } - - p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) - p.framesetOK = true - return false -} - -// copyAttributes copies attributes of src not found on dst to dst. -func copyAttributes(dst *Node, src Token) { - if len(src.Attr) == 0 { - return - } - attr := map[string]string{} - for _, t := range dst.Attr { - attr[t.Key] = t.Val - } - for _, t := range src.Attr { - if _, ok := attr[t.Key]; !ok { - dst.Attr = append(dst.Attr, t) - attr[t.Key] = t.Val - } - } -} - -// Section 12.2.5.4.7. -func inBodyIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - d := p.tok.Data - switch n := p.oe.top(); n.DataAtom { - case a.Pre, a.Listing: - if n.FirstChild == nil { - // Ignore a newline at the start of a
     block.
    -				if d != "" && d[0] == '\r' {
    -					d = d[1:]
    -				}
    -				if d != "" && d[0] == '\n' {
    -					d = d[1:]
    -				}
    -			}
    -		}
    -		d = strings.Replace(d, "\x00", "", -1)
    -		if d == "" {
    -			return true
    -		}
    -		p.reconstructActiveFormattingElements()
    -		p.addText(d)
    -		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
    -			// There were non-whitespace characters inserted.
    -			p.framesetOK = false
    -		}
    -	case StartTagToken:
    -		switch p.tok.DataAtom {
    -		case a.Html:
    -			copyAttributes(p.oe[0], p.tok)
    -		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
    -			return inHeadIM(p)
    -		case a.Body:
    -			if len(p.oe) >= 2 {
    -				body := p.oe[1]
    -				if body.Type == ElementNode && body.DataAtom == a.Body {
    -					p.framesetOK = false
    -					copyAttributes(body, p.tok)
    -				}
    -			}
    -		case a.Frameset:
    -			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
    -				// Ignore the token.
    -				return true
    -			}
    -			body := p.oe[1]
    -			if body.Parent != nil {
    -				body.Parent.RemoveChild(body)
    -			}
    -			p.oe = p.oe[:1]
    -			p.addElement()
    -			p.im = inFramesetIM
    -			return true
    -		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
    -			p.popUntil(buttonScope, a.P)
    -			p.addElement()
    -		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
    -			p.popUntil(buttonScope, a.P)
    -			switch n := p.top(); n.DataAtom {
    -			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
    -				p.oe.pop()
    -			}
    -			p.addElement()
    -		case a.Pre, a.Listing:
    -			p.popUntil(buttonScope, a.P)
    -			p.addElement()
    -			// The newline, if any, will be dealt with by the TextToken case.
    -			p.framesetOK = false
    -		case a.Form:
    -			if p.form == nil {
    -				p.popUntil(buttonScope, a.P)
    -				p.addElement()
    -				p.form = p.top()
    -			}
    -		case a.Li:
    -			p.framesetOK = false
    -			for i := len(p.oe) - 1; i >= 0; i-- {
    -				node := p.oe[i]
    -				switch node.DataAtom {
    -				case a.Li:
    -					p.oe = p.oe[:i]
    -				case a.Address, a.Div, a.P:
    -					continue
    -				default:
    -					if !isSpecialElement(node) {
    -						continue
    -					}
    -				}
    -				break
    -			}
    -			p.popUntil(buttonScope, a.P)
    -			p.addElement()
    -		case a.Dd, a.Dt:
    -			p.framesetOK = false
    -			for i := len(p.oe) - 1; i >= 0; i-- {
    -				node := p.oe[i]
    -				switch node.DataAtom {
    -				case a.Dd, a.Dt:
    -					p.oe = p.oe[:i]
    -				case a.Address, a.Div, a.P:
    -					continue
    -				default:
    -					if !isSpecialElement(node) {
    -						continue
    -					}
    -				}
    -				break
    -			}
    -			p.popUntil(buttonScope, a.P)
    -			p.addElement()
    -		case a.Plaintext:
    -			p.popUntil(buttonScope, a.P)
    -			p.addElement()
    -		case a.Button:
    -			p.popUntil(defaultScope, a.Button)
    -			p.reconstructActiveFormattingElements()
    -			p.addElement()
    -			p.framesetOK = false
    -		case a.A:
    -			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
    -				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
    -					p.inBodyEndTagFormatting(a.A)
    -					p.oe.remove(n)
    -					p.afe.remove(n)
    -					break
    -				}
    -			}
    -			p.reconstructActiveFormattingElements()
    -			p.addFormattingElement()
    -		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
    -			p.reconstructActiveFormattingElements()
    -			p.addFormattingElement()
    -		case a.Nobr:
    -			p.reconstructActiveFormattingElements()
    -			if p.elementInScope(defaultScope, a.Nobr) {
    -				p.inBodyEndTagFormatting(a.Nobr)
    -				p.reconstructActiveFormattingElements()
    -			}
    -			p.addFormattingElement()
    -		case a.Applet, a.Marquee, a.Object:
    -			p.reconstructActiveFormattingElements()
    -			p.addElement()
    -			p.afe = append(p.afe, &scopeMarker)
    -			p.framesetOK = false
    -		case a.Table:
    -			if !p.quirks {
    -				p.popUntil(buttonScope, a.P)
    -			}
    -			p.addElement()
    -			p.framesetOK = false
    -			p.im = inTableIM
    -			return true
    -		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
    -			p.reconstructActiveFormattingElements()
    -			p.addElement()
    -			p.oe.pop()
    -			p.acknowledgeSelfClosingTag()
    -			if p.tok.DataAtom == a.Input {
    -				for _, t := range p.tok.Attr {
    -					if t.Key == "type" {
    -						if strings.ToLower(t.Val) == "hidden" {
    -							// Skip setting framesetOK = false
    -							return true
    -						}
    -					}
    -				}
    -			}
    -			p.framesetOK = false
    -		case a.Param, a.Source, a.Track:
    -			p.addElement()
    -			p.oe.pop()
    -			p.acknowledgeSelfClosingTag()
    -		case a.Hr:
    -			p.popUntil(buttonScope, a.P)
    -			p.addElement()
    -			p.oe.pop()
    -			p.acknowledgeSelfClosingTag()
    -			p.framesetOK = false
    -		case a.Image:
    -			p.tok.DataAtom = a.Img
    -			p.tok.Data = a.Img.String()
    -			return false
    -		case a.Isindex:
    -			if p.form != nil {
    -				// Ignore the token.
    -				return true
    -			}
    -			action := ""
    -			prompt := "This is a searchable index. Enter search keywords: "
    -			attr := []Attribute{{Key: "name", Val: "isindex"}}
    -			for _, t := range p.tok.Attr {
    -				switch t.Key {
    -				case "action":
    -					action = t.Val
    -				case "name":
    -					// Ignore the attribute.
    -				case "prompt":
    -					prompt = t.Val
    -				default:
    -					attr = append(attr, t)
    -				}
    -			}
    -			p.acknowledgeSelfClosingTag()
    -			p.popUntil(buttonScope, a.P)
    -			p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
    -			if action != "" {
    -				p.form.Attr = []Attribute{{Key: "action", Val: action}}
    -			}
    -			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
    -			p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
    -			p.addText(prompt)
    -			p.addChild(&Node{
    -				Type:     ElementNode,
    -				DataAtom: a.Input,
    -				Data:     a.Input.String(),
    -				Attr:     attr,
    -			})
    -			p.oe.pop()
    -			p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
    -			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
    -			p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
    -		case a.Textarea:
    -			p.addElement()
    -			p.setOriginalIM()
    -			p.framesetOK = false
    -			p.im = textIM
    -		case a.Xmp:
    -			p.popUntil(buttonScope, a.P)
    -			p.reconstructActiveFormattingElements()
    -			p.framesetOK = false
    -			p.addElement()
    -			p.setOriginalIM()
    -			p.im = textIM
    -		case a.Iframe:
    -			p.framesetOK = false
    -			p.addElement()
    -			p.setOriginalIM()
    -			p.im = textIM
    -		case a.Noembed, a.Noscript:
    -			p.addElement()
    -			p.setOriginalIM()
    -			p.im = textIM
    -		case a.Select:
    -			p.reconstructActiveFormattingElements()
    -			p.addElement()
    -			p.framesetOK = false
    -			p.im = inSelectIM
    -			return true
    -		case a.Optgroup, a.Option:
    -			if p.top().DataAtom == a.Option {
    -				p.oe.pop()
    -			}
    -			p.reconstructActiveFormattingElements()
    -			p.addElement()
    -		case a.Rp, a.Rt:
    -			if p.elementInScope(defaultScope, a.Ruby) {
    -				p.generateImpliedEndTags()
    -			}
    -			p.addElement()
    -		case a.Math, a.Svg:
    -			p.reconstructActiveFormattingElements()
    -			if p.tok.DataAtom == a.Math {
    -				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
    -			} else {
    -				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
    -			}
    -			adjustForeignAttributes(p.tok.Attr)
    -			p.addElement()
    -			p.top().Namespace = p.tok.Data
    -			if p.hasSelfClosingToken {
    -				p.oe.pop()
    -				p.acknowledgeSelfClosingTag()
    -			}
    -			return true
    -		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
    -			// Ignore the token.
    -		default:
    -			p.reconstructActiveFormattingElements()
    -			p.addElement()
    -		}
    -	case EndTagToken:
    -		switch p.tok.DataAtom {
    -		case a.Body:
    -			if p.elementInScope(defaultScope, a.Body) {
    -				p.im = afterBodyIM
    -			}
    -		case a.Html:
    -			if p.elementInScope(defaultScope, a.Body) {
    -				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
    -				return false
    -			}
    -			return true
    -		case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
    -			p.popUntil(defaultScope, p.tok.DataAtom)
    -		case a.Form:
    -			node := p.form
    -			p.form = nil
    -			i := p.indexOfElementInScope(defaultScope, a.Form)
    -			if node == nil || i == -1 || p.oe[i] != node {
    -				// Ignore the token.
    -				return true
    -			}
    -			p.generateImpliedEndTags()
    -			p.oe.remove(node)
    -		case a.P:
    -			if !p.elementInScope(buttonScope, a.P) {
    -				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
    -			}
    -			p.popUntil(buttonScope, a.P)
    -		case a.Li:
    -			p.popUntil(listItemScope, a.Li)
    -		case a.Dd, a.Dt:
    -			p.popUntil(defaultScope, p.tok.DataAtom)
    -		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
    -			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
    -		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
    -			p.inBodyEndTagFormatting(p.tok.DataAtom)
    -		case a.Applet, a.Marquee, a.Object:
    -			if p.popUntil(defaultScope, p.tok.DataAtom) {
    -				p.clearActiveFormattingElements()
    -			}
    -		case a.Br:
    -			p.tok.Type = StartTagToken
    -			return false
    -		default:
    -			p.inBodyEndTagOther(p.tok.DataAtom)
    -		}
    -	case CommentToken:
    -		p.addChild(&Node{
    -			Type: CommentNode,
    -			Data: p.tok.Data,
    -		})
    -	}
    -
    -	return true
    -}
    -
    -func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
    -	// This is the "adoption agency" algorithm, described at
    -	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
    -
    -	// TODO: this is a fairly literal line-by-line translation of that algorithm.
    -	// Once the code successfully parses the comprehensive test suite, we should
    -	// refactor this code to be more idiomatic.
    -
    -	// Steps 1-4. The outer loop.
    -	for i := 0; i < 8; i++ {
    -		// Step 5. Find the formatting element.
    -		var formattingElement *Node
    -		for j := len(p.afe) - 1; j >= 0; j-- {
    -			if p.afe[j].Type == scopeMarkerNode {
    -				break
    -			}
    -			if p.afe[j].DataAtom == tagAtom {
    -				formattingElement = p.afe[j]
    -				break
    -			}
    -		}
    -		if formattingElement == nil {
    -			p.inBodyEndTagOther(tagAtom)
    -			return
    -		}
    -		feIndex := p.oe.index(formattingElement)
    -		if feIndex == -1 {
    -			p.afe.remove(formattingElement)
    -			return
    -		}
    -		if !p.elementInScope(defaultScope, tagAtom) {
    -			// Ignore the tag.
    -			return
    -		}
    -
    -		// Steps 9-10. Find the furthest block.
    -		var furthestBlock *Node
    -		for _, e := range p.oe[feIndex:] {
    -			if isSpecialElement(e) {
    -				furthestBlock = e
    -				break
    -			}
    -		}
    -		if furthestBlock == nil {
    -			e := p.oe.pop()
    -			for e != formattingElement {
    -				e = p.oe.pop()
    -			}
    -			p.afe.remove(e)
    -			return
    -		}
    -
    -		// Steps 11-12. Find the common ancestor and bookmark node.
    -		commonAncestor := p.oe[feIndex-1]
    -		bookmark := p.afe.index(formattingElement)
    -
    -		// Step 13. The inner loop. Find the lastNode to reparent.
    -		lastNode := furthestBlock
    -		node := furthestBlock
    -		x := p.oe.index(node)
    -		// Steps 13.1-13.2
    -		for j := 0; j < 3; j++ {
    -			// Step 13.3.
    -			x--
    -			node = p.oe[x]
    -			// Step 13.4 - 13.5.
    -			if p.afe.index(node) == -1 {
    -				p.oe.remove(node)
    -				continue
    -			}
    -			// Step 13.6.
    -			if node == formattingElement {
    -				break
    -			}
    -			// Step 13.7.
    -			clone := node.clone()
    -			p.afe[p.afe.index(node)] = clone
    -			p.oe[p.oe.index(node)] = clone
    -			node = clone
    -			// Step 13.8.
    -			if lastNode == furthestBlock {
    -				bookmark = p.afe.index(node) + 1
    -			}
    -			// Step 13.9.
    -			if lastNode.Parent != nil {
    -				lastNode.Parent.RemoveChild(lastNode)
    -			}
    -			node.AppendChild(lastNode)
    -			// Step 13.10.
    -			lastNode = node
    -		}
    -
    -		// Step 14. Reparent lastNode to the common ancestor,
    -		// or for misnested table nodes, to the foster parent.
    -		if lastNode.Parent != nil {
    -			lastNode.Parent.RemoveChild(lastNode)
    -		}
    -		switch commonAncestor.DataAtom {
    -		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
    -			p.fosterParent(lastNode)
    -		default:
    -			commonAncestor.AppendChild(lastNode)
    -		}
    -
    -		// Steps 15-17. Reparent nodes from the furthest block's children
    -		// to a clone of the formatting element.
    -		clone := formattingElement.clone()
    -		reparentChildren(clone, furthestBlock)
    -		furthestBlock.AppendChild(clone)
    -
    -		// Step 18. Fix up the list of active formatting elements.
    -		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
    -			// Move the bookmark with the rest of the list.
    -			bookmark--
    -		}
    -		p.afe.remove(formattingElement)
    -		p.afe.insert(bookmark, clone)
    -
    -		// Step 19. Fix up the stack of open elements.
    -		p.oe.remove(formattingElement)
    -		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
    -	}
    -}
    -
    -// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
    -// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
    -// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
    -func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
    -	for i := len(p.oe) - 1; i >= 0; i-- {
    -		if p.oe[i].DataAtom == tagAtom {
    -			p.oe = p.oe[:i]
    -			break
    -		}
    -		if isSpecialElement(p.oe[i]) {
    -			break
    -		}
    -	}
    -}
    -
    -// Section 12.2.5.4.8.
    -func textIM(p *parser) bool {
    -	switch p.tok.Type {
    -	case ErrorToken:
    -		p.oe.pop()
    -	case TextToken:
    -		d := p.tok.Data
    -		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
    -			// Ignore a newline at the start of a